summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile3
-rwxr-xr-xSCCP_Test/gen_links.sh48
-rwxr-xr-xSCCP_Test/regen_makefile.sh7
-rw-r--r--bsc-nat/BSC_MS_Simulation.ttcn2
-rw-r--r--bsc-nat/README.md28
-rwxr-xr-xbsc-nat/gen_links.sh2
-rw-r--r--bsc/BSC_Tests.default10
-rw-r--r--bsc/BSC_Tests.ttcn3490
-rw-r--r--bsc/BSC_Tests_CBSP.ttcn436
-rw-r--r--bsc/BSC_Tests_LCLS.ttcn6
-rw-r--r--bsc/MSC_ConnectionHandler.ttcn103
-rw-r--r--bsc/README.md28
-rw-r--r--bsc/expected-results.xml123
-rwxr-xr-xbsc/gen_links.sh3
-rw-r--r--bsc/osmo-bsc.cfg76
-rw-r--r--bsc/osmo-stp.cfg30
-rwxr-xr-xbsc/regen_makefile.sh2
-rw-r--r--bts/BTS_Tests.cfg12
-rw-r--r--bts/BTS_Tests.ttcn1464
-rw-r--r--bts/BTS_Tests_LAPDm.ttcn75
-rw-r--r--bts/BTS_Tests_OML.ttcn4
-rw-r--r--bts/BTS_Tests_SMSCB.ttcn201
-rw-r--r--bts/BTS_Tests_perf.ttcn103
-rw-r--r--bts/README.md4
-rw-r--r--bts/expected-results.xml172
-rwxr-xr-xbts/gen_links.sh2
-rw-r--r--bts/osmo-bsc.cfg (renamed from pcu/osmo-bsc.cfg)73
-rw-r--r--bts/osmo-bts.cfg56
-rw-r--r--cbc/CBC_Tests.cfg18
-rw-r--r--cbc/CBC_Tests.default11
-rw-r--r--cbc/CBC_Tests.ttcn30
-rw-r--r--cbc/SABP_Selftest.ttcn179
-rwxr-xr-xcbc/gen_links.sh6
-rwxr-xr-xcbc/regen_makefile.sh2
-rw-r--r--ccid/CCID_Tests.cfg20
-rw-r--r--ccid/CCID_Tests.default8
-rw-r--r--ccid/CCID_Tests.ttcn621
-rwxr-xr-xccid/gen_links.sh21
-rwxr-xr-xccid/regen_makefile.sh9
-rwxr-xr-xcompare-results.py146
-rwxr-xr-xcompare-results.sh213
-rw-r--r--deps/Makefile118
-rw-r--r--ggsn_tests/GGSN_Tests.ttcn24
-rw-r--r--ggsn_tests/README.md1
-rw-r--r--hlr/HLR_EUSE.ttcn4
-rw-r--r--hlr/HLR_Tests.cfg1
-rw-r--r--hlr/HLR_Tests.default5
-rw-r--r--hlr/HLR_Tests.ttcn667
-rw-r--r--hlr/expected-results.xml9
-rwxr-xr-xhlr/gen_links.sh9
-rwxr-xr-xhlr/regen_makefile.sh2
-rwxr-xr-xlapdm/gen_links.sh2
-rw-r--r--library/BSSAP_CodecPort.ttcn2
-rw-r--r--library/BSSAP_LE_Adapter.ttcn130
-rw-r--r--library/BSSAP_LE_CodecPort.ttcn380
-rw-r--r--library/BSSAP_LE_Emulation.ttcn704
-rw-r--r--library/BSSAP_LE_Types.ttcn594
-rw-r--r--library/BSSGP_Helper.cc4
-rw-r--r--library/BSSGP_Types.ttcn15
-rw-r--r--library/BSSLAP_Types.ttcn530
-rw-r--r--library/BSSMAP_LE_Templates.ttcn434
-rw-r--r--library/BSSMAP_Templates.ttcn110
-rw-r--r--library/CBSP_Adapter.ttcn3
-rw-r--r--library/CBSP_Templates.ttcn69
-rw-r--r--library/DIAMETER_Emulation.ttcn49
-rw-r--r--library/DIAMETER_Templates.ttcn155
-rw-r--r--library/DIAMETER_Types.ttcn2713
-rw-r--r--library/DNS_Helpers.ttcn23
-rw-r--r--library/GSM_RR_Types.ttcn709
-rw-r--r--library/GSM_RestOctets.ttcn831
-rw-r--r--library/GSM_SystemInformation.ttcn83
-rw-r--r--library/GSM_Types.ttcn17
-rw-r--r--library/GSUP_Emulation.ttcn15
-rw-r--r--library/GSUP_Types.ttcn313
-rw-r--r--library/GTPv2_CodecPort.ttcn4
-rw-r--r--library/GTPv2_CodecPort_CtrlFunct.ttcn (renamed from mgw/RTP_CodecPort_CtrlFunct.ttcn)15
-rw-r--r--library/GTPv2_CodecPort_CtrlFunctDef.cc (renamed from mgw/RTP_CodecPort_CtrlFunctDef.cc)17
-rw-r--r--library/GTPv2_Emulation.ttcn606
-rw-r--r--library/GTPv2_Templates.ttcn735
-rw-r--r--library/General_Types.ttcn2
-rw-r--r--library/IPA_Emulation.ttcnpp186
-rw-r--r--library/IPA_Types.ttcn15
-rw-r--r--library/IuUP_EncDec.cc4
-rw-r--r--library/L1CTL_PortType.ttcn42
-rw-r--r--library/L1CTL_Types.ttcn77
-rw-r--r--library/L3_Templates.ttcn259
-rw-r--r--library/LAPDm_RAW_PT.ttcn98
-rw-r--r--library/M3UA_CodecPort.ttcn84
-rw-r--r--library/M3UA_CodecPort_CtrlFunct.ttcn44
-rw-r--r--library/M3UA_CodecPort_CtrlFunctDef.cc56
-rw-r--r--library/M3UA_Templates.ttcn771
-rw-r--r--library/MGCP_Templates.ttcn32
-rw-r--r--library/MNCC_Emulation.ttcn6
-rw-r--r--library/MNCC_EncDec.cc3
-rw-r--r--library/MNCC_Types.ttcn149
-rw-r--r--library/MSLookup_mDNS_Emulation.ttcn45
-rw-r--r--library/MSLookup_mDNS_Templates.ttcn182
-rw-r--r--library/MSLookup_mDNS_Types.ttcn31
-rw-r--r--library/Misc_Helpers.ttcn9
-rw-r--r--library/NS_Emulation.ttcn2
-rw-r--r--library/Native_FunctionDefs.cc30
-rw-r--r--library/Native_Functions.ttcn6
-rw-r--r--library/OSMUX_Emulation.ttcn5
-rw-r--r--library/Osmocom_CTRL_Adapter.ttcn2
-rw-r--r--library/Osmocom_CTRL_Functions.ttcn121
-rw-r--r--library/Osmocom_Gb_Types.ttcn170
-rw-r--r--library/Osmocom_Types.ttcn76
-rw-r--r--library/Osmocom_VTY_Functions.ttcn33
-rw-r--r--library/PCUIF_CodecPort.ttcn10
-rw-r--r--library/PCUIF_Types.ttcn295
-rw-r--r--library/RAN_Adapter.ttcnpp1
-rw-r--r--library/RAN_Emulation.ttcnpp51
-rw-r--r--library/RLCMAC_CSN1_Templates.ttcn267
-rw-r--r--library/RLCMAC_CSN1_Types.ttcn484
-rw-r--r--library/RLCMAC_EncDec.cc1196
-rw-r--r--library/RLCMAC_Templates.ttcn729
-rw-r--r--library/RLCMAC_Types.ttcn311
-rw-r--r--library/RSL_Emulation.ttcn304
-rw-r--r--library/RSL_Types.ttcn88
-rw-r--r--library/RTP_Emulation.ttcn12
-rw-r--r--library/SABP_Adapter.ttcn165
-rw-r--r--library/SABP_CodecPort.ttcn65
-rw-r--r--library/SABP_CodecPort_CtrlFunct.ttcn52
-rw-r--r--library/SABP_CodecPort_CtrlFunctDef.cc66
-rw-r--r--library/SBC_AP_CodecPort.ttcn82
-rw-r--r--library/SBC_AP_CodecPort_CtrlFunct.ttcn44
-rw-r--r--library/SBC_AP_CodecPort_CtrlFunctDef.cc56
-rw-r--r--library/SBC_AP_Templates.ttcn116
-rw-r--r--library/SCCP_Templates.ttcn170
-rw-r--r--library/StatsD_Checker.ttcn272
-rw-r--r--library/StatsD_CodecPort.ttcn57
-rw-r--r--library/StatsD_CodecPort_CtrlFunct.ttcn43
-rw-r--r--library/StatsD_CodecPort_CtrlFunctdef.cc55
-rw-r--r--library/StatsD_Types.ttcn65
-rw-r--r--library/VPCD_Adapter.ttcn73
-rw-r--r--library/VPCD_CodecPort.ttcn64
-rw-r--r--library/VPCD_CodecPort_CtrlFunct.ttcn52
-rw-r--r--library/VPCD_CodecPort_CtrlFunctDef.cc66
-rw-r--r--library/VPCD_Types.ttcn75
-rw-r--r--library/mncc.h4
-rw-r--r--library/ranap/RANAP_Templates.ttcn2
-rw-r--r--library/sabp/SABP_EncDec.cc64
-rw-r--r--library/sabp/SABP_Templates.ttcn682
-rw-r--r--library/sbcap/SBC_AP_CommonDataTypes.asn35
-rw-r--r--library/sbcap/SBC_AP_Constants.asn127
-rw-r--r--library/sbcap/SBC_AP_Containers.asn121
-rw-r--r--library/sbcap/SBC_AP_EncDec.cc64
-rw-r--r--library/sbcap/SBC_AP_IEs.asn650
-rw-r--r--library/sbcap/SBC_AP_PDU_Contents.asn374
-rw-r--r--library/sbcap/SBC_AP_PDU_Descriptions.asn179
-rw-r--r--library/sbcap/SBC_AP_Types.ttcn10
-rw-r--r--mgw/MGCP_Test.default4
-rw-r--r--mgw/MGCP_Test.ttcn435
-rw-r--r--mgw/README.md9
-rw-r--r--mgw/expected-results.xml7
-rwxr-xr-xmgw/gen_links.sh1
-rw-r--r--mgw/osmo-mgw.cfg2
-rw-r--r--mme/MME_Tests.ttcn7
-rwxr-xr-xmme/gen_links.sh2
-rw-r--r--msc/BSC_ConnectionHandler.ttcn790
-rw-r--r--msc/MSC_Tests.ttcn1235
-rw-r--r--msc/MSC_Tests_Iu.ttcn161
-rw-r--r--msc/README.md11
-rw-r--r--msc/expected-results.xml94
-rwxr-xr-xmsc/gen_links.sh2
-rw-r--r--pcu/GPRS_Components.ttcn817
-rw-r--r--pcu/GPRS_TBF.ttcn3
-rw-r--r--pcu/PCUIF_Components.ttcn518
-rw-r--r--pcu/PCU_Tests.cfg5
-rw-r--r--pcu/PCU_Tests.default15
-rw-r--r--pcu/PCU_Tests.ttcn2808
-rw-r--r--pcu/PCU_Tests_NS.ttcn232
-rw-r--r--pcu/PCU_Tests_RAW.ttcn460
-rw-r--r--pcu/PCU_Tests_SNS.cfg4
-rw-r--r--pcu/PCU_Tests_SNS.ttcn (renamed from pcu/PCU_Tests_RAW_SNS.ttcn)10
-rw-r--r--pcu/PCU_selftest.ttcn318
-rw-r--r--pcu/RAW_NS.ttcn229
-rw-r--r--pcu/README.md18
-rw-r--r--pcu/SGSN_Components.ttcn105
-rw-r--r--pcu/expected-results.xml50
-rwxr-xr-xpcu/gen_links.sh5
-rw-r--r--pcu/osmo-bts.cfg83
-rwxr-xr-xpcu/regen_makefile.sh2
-rw-r--r--pgw/PGW_Tests.cfg18
-rw-r--r--pgw/PGW_Tests.default7
-rw-r--r--pgw/PGW_Tests.ttcn553
-rwxr-xr-xpgw/gen_links.sh60
-rwxr-xr-xpgw/regen_makefile.sh7
-rwxr-xr-xregen-makefile.sh6
-rw-r--r--remsim/REMSIM_Tests.cfg13
-rw-r--r--remsim/REMSIM_Tests.default3
-rw-r--r--remsim/REMSIM_Tests.ttcn247
-rw-r--r--remsim/RSPRO.asn362
-rw-r--r--remsim/RSPRO_EncDec.cc26
-rw-r--r--remsim/RSPRO_Server.ttcn190
-rw-r--r--remsim/RSPRO_Types.ttcn398
-rw-r--r--remsim/RSRES.ttcn110
-rw-r--r--remsim/RemsimBankd_Tests.ttcn429
-rw-r--r--remsim/RemsimClient_Tests.ttcn398
-rw-r--r--remsim/RemsimServer_Tests.ttcn572
-rwxr-xr-xremsim/gen_links.sh49
-rwxr-xr-xremsim/regen_makefile.sh10
-rw-r--r--sccp/SCCP_CodecPort.ttcn73
-rw-r--r--sccp/SCCP_Tests.cfg2
-rw-r--r--sccp/SCCP_Tests.default30
-rw-r--r--sccp/SCCP_Tests.ttcn11
-rw-r--r--sccp/SCCP_Tests_RAW.ttcn321
-rw-r--r--selftest/Selftest.ttcn6
-rwxr-xr-xselftest/gen_links.sh2
-rw-r--r--sgsn/README.md8
-rw-r--r--sgsn/SGSN_Tests.ttcn619
-rw-r--r--sgsn/SGSN_Tests_Iu.ttcn93
-rw-r--r--sgsn/expected-results.xml12
-rwxr-xr-xsgsn/gen_links.sh4
-rw-r--r--simtrace/SIMTRACE_CARDEM_Tests.ttcn10
-rw-r--r--simtrace/SIMTRACE_Emulation.ttcn175
-rw-r--r--simtrace/SIMTRACE_Templates.ttcn333
-rw-r--r--simtrace/SIMTRACE_Tests.ttcn162
-rw-r--r--simtrace/SIMTRACE_Types.ttcn356
-rwxr-xr-xsimtrace/gen_links.sh20
-rwxr-xr-xsimtrace/regen_makefile.sh9
-rw-r--r--sip/README.md2
-rw-r--r--sip/SIP_Tests.default1
-rw-r--r--sip/expected-results.xml3
-rw-r--r--sip/osmo-sip-connector.cfg25
-rwxr-xr-xstart-testsuite.sh7
-rw-r--r--stp/README.md18
-rw-r--r--stp/STP_Tests.cfg20
-rw-r--r--stp/STP_Tests.default20
-rw-r--r--stp/STP_Tests.ttcn171
-rw-r--r--stp/STP_Tests_Common.ttcn51
-rw-r--r--stp/STP_Tests_IPA.ttcn274
-rw-r--r--stp/STP_Tests_M3UA.ttcn728
-rwxr-xr-xstp/gen_links.sh57
-rw-r--r--stp/osmo-stp.cfg128
-rwxr-xr-xstp/regen_makefile.sh7
-rwxr-xr-xsysinfo/gen_links.sh6
-rwxr-xr-xttcn3-tcpdump-start.sh27
-rwxr-xr-xttcn3-tcpdump-stop.sh36
240 files changed, 39566 insertions, 4350 deletions
diff --git a/.gitignore b/.gitignore
index 519dc48..5c8caa5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,5 @@ selftest/Selftest
!bin/Makefile
!deps/Makefile
.*.sw?
+*.netcat.stderr
+*.d
diff --git a/Makefile b/Makefile
index 2c8e951..03e7a70 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-SUBDIRS=bsc bsc-nat bts ggsn_tests hlr mgw msc pcu sccp selftest sgsn sip sysinfo
+SUBDIRS=bsc bsc-nat bts ccid ggsn_tests hlr mgw mme msc pcu pgw remsim sccp selftest sgsn \
+ simtrace sip stp sysinfo
NPROC=$(shell nproc 2>/dev/null)
ifeq ($(NPROC),)
diff --git a/SCCP_Test/gen_links.sh b/SCCP_Test/gen_links.sh
new file mode 100755
index 0000000..c980844
--- /dev/null
+++ b/SCCP_Test/gen_links.sh
@@ -0,0 +1,48 @@
+#!/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 SDP_EncDec.cc"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
+FILES="Socket_API_Definitions.ttcn"
+gen_links $DIR $FILES
+
+# required by M3UA_Emulation
+DIR=$BASEDIR/titan.ProtocolModules.M3UA/src
+FILES="M3UA_Types.ttcn"
+gen_links $DIR $FILES
+
+# required by M3UA_Emulation
+DIR=$BASEDIR/titan.TestPorts.SCTPasp/src
+FILES="SCTPasp_PT.cc SCTPasp_PT.hh SCTPasp_PortType.ttcn SCTPasp_Types.ttcn"
+gen_links $DIR $FILES
+
+# required by SCCP Emulation
+DIR=$BASEDIR/titan.ProtocolEmulations.M3UA/src
+FILES="M3UA_Emulation.ttcn"
+gen_links $DIR $FILES
+
+# required by SCCP Emulation
+DIR=$BASEDIR/titan.TestPorts.MTP3asp/src
+FILES="MTP3asp_PortType.ttcn MTP3asp_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.ProtocolEmulations.SCCP/src
+FILES="SCCP_Emulation.ttcn SCCP_Mapping.ttcnpp SCCP_Types.ttcn SCCPasp_Types.ttcn"
+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=../library
+FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn Osmocom_VTY_Functions.ttcn
+Native_Functions.ttcn Native_FunctionDefs.cc SCCP_Templates.ttcn "
+gen_links $DIR $FILES
+
+ignore_pp_results
diff --git a/SCCP_Test/regen_makefile.sh b/SCCP_Test/regen_makefile.sh
new file mode 100755
index 0000000..9472e0c
--- /dev/null
+++ b/SCCP_Test/regen_makefile.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+MAIN=SCCP_Testcases.ttcn
+
+FILES="*.ttcn *.ttcnpp"
+
+../regen-makefile.sh $MAIN $FILES
diff --git a/bsc-nat/BSC_MS_Simulation.ttcn b/bsc-nat/BSC_MS_Simulation.ttcn
index 0582576..0a057a3 100644
--- a/bsc-nat/BSC_MS_Simulation.ttcn
+++ b/bsc-nat/BSC_MS_Simulation.ttcn
@@ -131,7 +131,7 @@ function main(charstring remote_ip, PortNumber remote_port,
/* Initial delay to wait for IPA connection establishment */
T.start;
alt {
- [] SCCPLITE_IPA_CTRL.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { }
+ [] SCCPLITE_IPA_CTRL.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { }
[] T.timeout {
setverdict(fail, "Timeout CTRL waiting for ASP_IPA_EVENT_UP");
mtc.stop;
diff --git a/bsc-nat/README.md b/bsc-nat/README.md
new file mode 100644
index 0000000..63f497b
--- /dev/null
+++ b/bsc-nat/README.md
@@ -0,0 +1,28 @@
+# BSCNAT_Tests.ttcn
+
+* external interfaces
+ * BSSAP/SCCP/IPA (SCCPLite) (emulates BSC-side and MSC-side)
+ * MGCP/UDP (emulates MSC-side MSC+MGW)
+ * MGCP/IPA (emulates BSC-side BSC+MGW)
+ * RTP (emulates BSC-side MGW and MSC-side MGW)
+ * Osmux (emulates BSC-side MGW)
+ * VTY
+ * CTRL
+
+{% dot bscnat_tests.svg
+digraph G {
+ rankdir=LR;
+ BSCNAT [label="IUT\nosmo-bsc_nat",shape="box"];
+ ATS [label="ATS\nBSC_Tests.ttcn"];
+
+ ATS -> BSCNAT [label="SCCPLite BSC-side"];
+ BSCNAT -> ATS [label="SCCPLite MSC-side"];
+ BSCNAT -> ATS [label="MGCP/UDP MSC-side", dir="both"];
+ BSCNAT -> ATS [label="MGCP/IPA BSC-side"];
+ ATS -> BSCNAT [label="CTRL"];
+ ATS -> BSCNAT [label="VTY"];
+ ATS -> BSCNAT [label="RTP BSC-side", dir="both"];
+ ATS -> BSCNAT [label="RTP MSC-side", dir="both"];
+ ATS -> BSCNAT [label="Osmux BSC-side", dir="both"];
+}
+%}
diff --git a/bsc-nat/gen_links.sh b/bsc-nat/gen_links.sh
index 5da9d4e..9bd1faf 100755
--- a/bsc-nat/gen_links.sh
+++ b/bsc-nat/gen_links.sh
@@ -52,7 +52,7 @@ FILES="RTP_EncDec.cc RTP_Types.ttcn"
gen_links $DIR $FILES
DIR=../library
-FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp L3_Templates.ttcn BSSMAP_Templates.ttcn RAN_Emulation.ttcnpp MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc Osmocom_CTRL_Types.ttcn Osmocom_VTY_Functions.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn BSSAP_CodecPort.ttcn"
+FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp L3_Templates.ttcn RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn BSSMAP_Templates.ttcn RAN_Emulation.ttcnpp MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc Osmocom_CTRL_Types.ttcn Osmocom_VTY_Functions.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn BSSAP_CodecPort.ttcn Native_Functions.ttcn Native_FunctionDefs.cc"
gen_links $DIR $FILES
ignore_pp_results
diff --git a/bsc/BSC_Tests.default b/bsc/BSC_Tests.default
index 8818359..c5d1559 100644
--- a/bsc/BSC_Tests.default
+++ b/bsc/BSC_Tests.default
@@ -17,8 +17,18 @@ mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
*.BSCVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
*.BSCVTY.CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT := "yes"
*.BSCVTY.PROMPT1 := "OsmoBSC> "
+*.STATSVTY.CTRL_MODE := "client"
+*.STATSVTY.CTRL_HOSTNAME := "127.0.0.1"
+*.STATSVTY.CTRL_PORTNUM := "4242"
+*.STATSVTY.CTRL_LOGIN_SKIPPED := "yes"
+*.STATSVTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes"
+*.STATSVTY.CTRL_READMODE := "buffered"
+*.STATSVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
+*.STATSVTY.CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT := "yes"
+*.STATSVTY.PROMPT1 := "OsmoBSC> "
[MODULE_PARAMETERS]
Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoBSC";
+StatsD_Checker.mp_enable_stats := true;
[EXECUTE]
diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn
index e25bf7f..540d88f 100644
--- a/bsc/BSC_Tests.ttcn
+++ b/bsc/BSC_Tests.ttcn
@@ -20,6 +20,7 @@ module BSC_Tests {
* level testing.
*/
+import from Misc_Helpers all;
import from General_Types all;
import from Osmocom_Types all;
import from GSM_Types all;
@@ -44,6 +45,11 @@ import from Osmocom_CTRL_Functions all;
import from Osmocom_CTRL_Types all;
import from Osmocom_CTRL_Adapter all;
+import from StatsD_Types all;
+import from StatsD_CodecPort all;
+import from StatsD_CodecPort_CtrlFunct all;
+import from StatsD_Checker all;
+
import from Osmocom_VTY_Functions all;
import from TELNETasp_PortType all;
@@ -58,13 +64,18 @@ import from BSSMAP_Templates all;
import from SCCPasp_Types all;
+import from GSM_SystemInformation all;
+import from GSM_RestOctets all;
+import from TCCConversion_Functions all;
+
const integer NUM_BTS := 3;
+const integer NUM_MSC := 3;
const float T3101_MAX := 12.0;
/* make sure to sync this with the osmo-bts.cfg you're using */
const integer NUM_TCHH_PER_BTS := 2;
const integer NUM_TCHF_PER_BTS := 4;
-const integer NUM_SDCCH_PER_BTS := 4;
+const integer NUM_SDCCH_PER_BTS := 3;
/* per-BTS state which we keep */
@@ -73,6 +84,434 @@ type record BTS_State {
IPA_Client rsl
}
+/* Default list of counters for an 'msc' entity. */
+const CounterNameVals counternames_msc_mscpool := {
+ { "mscpool:subscr:new", 0 },
+ { "mscpool:subscr:known", 0 },
+ { "mscpool:subscr:reattach", 0 },
+ { "mscpool:subscr:attach_lost", 0 },
+ { "mscpool:subscr:paged", 0 }
+};
+
+/* Default list of counters for 'bsc' and 'bts' entities. */
+const CounterNameVals counternames_bsc_bts_handover := {
+ { "assignment:attempted", 0 },
+ { "assignment:completed", 0 },
+ { "assignment:stopped", 0 },
+ { "assignment:no_channel", 0 },
+ { "assignment:timeout", 0 },
+ { "assignment:failed", 0 },
+ { "assignment:error", 0 },
+
+ { "handover:attempted", 0 },
+ { "handover:completed", 0 },
+ { "handover:stopped", 0 },
+ { "handover:no_channel", 0 },
+ { "handover:timeout", 0 },
+ { "handover:failed", 0 },
+ { "handover:error", 0 },
+
+ { "intra_cell_ho:attempted", 0 },
+ { "intra_cell_ho:completed", 0 },
+ { "intra_cell_ho:stopped", 0 },
+ { "intra_cell_ho:no_channel", 0 },
+ { "intra_cell_ho:timeout", 0 },
+ { "intra_cell_ho:failed", 0 },
+ { "intra_cell_ho:error", 0 },
+
+ { "intra_bsc_ho:attempted", 0 },
+ { "intra_bsc_ho:completed", 0 },
+ { "intra_bsc_ho:stopped", 0 },
+ { "intra_bsc_ho:no_channel", 0 },
+ { "intra_bsc_ho:timeout", 0 },
+ { "intra_bsc_ho:failed", 0 },
+ { "intra_bsc_ho:error", 0 },
+
+ { "interbsc_ho_out:attempted", 0 },
+ { "interbsc_ho_out:completed", 0 },
+ { "interbsc_ho_out:stopped", 0 },
+ { "interbsc_ho_out:timeout", 0 },
+ { "interbsc_ho_out:failed", 0 },
+ { "interbsc_ho_out:error", 0 },
+
+ { "interbsc_ho_in:attempted", 0 },
+ { "interbsc_ho_in:completed", 0 },
+ { "interbsc_ho_in:stopped", 0 },
+ { "interbsc_ho_in:no_channel", 0 },
+ { "interbsc_ho_in:timeout", 0 },
+ { "interbsc_ho_in:failed", 0 },
+ { "interbsc_ho_in:error", 0 }
+};
+
+/* Set of all System Information received during one RSL port's startup.
+ * Note that some System Information may be sent on RSL, but lacking actual SI data, to indicate that the BTS should not
+ * broadcast that SI type. That will be reflected as 'omit' here.
+ */
+type record SystemInformationConfig {
+ SystemInformationType1 si1 optional,
+ SystemInformationType2 si2 optional,
+ SystemInformationType2bis si2bis optional,
+ SystemInformationType2ter si2ter optional,
+ SI2quaterRestOctetsList si2quater optional,
+ SystemInformationType3 si3 optional,
+ SystemInformationType4 si4 optional,
+ /* TODO: replace with proper decoding of SI13, implement SI13 in GSM_SystemInformation.ttcn */
+ octetstring si13 optional,
+ SystemInformationType5 si5 optional,
+ SystemInformationType5bis si5bis optional,
+ SystemInformationType5ter si5ter optional,
+ SystemInformationType6 si6 optional
+};
+
+const SystemInformationConfig SystemInformationConfig_omit := {
+ si1 := omit,
+ si2 := omit,
+ si2bis := omit,
+ si2ter := omit,
+ si2quater := omit,
+ si3 := omit,
+ si4 := omit,
+ si13 := omit,
+ si5 := omit,
+ si5bis := omit,
+ si5ter := omit,
+ si6 := omit
+};
+
+/* tr_EUTRAN_CellDesc with defaults used in BSC_Tests.ttcn */
+template EUTRAN_CellDesc tr_EUTRAN_CellDesc_default(template (present) uint16_t e_arfcn := ?,
+ template uint3_t meas_bw := 3)
+:= tr_EUTRAN_CellDesc(e_arfcn := e_arfcn,
+ meas_bw_presence := '1'B,
+ meas_bw := meas_bw);
+
+/* tr_EUTRAN_NeighbourCells with defaults used in BSC_Tests.ttcn */
+template EUTRAN_NeighbourCells tr_EUTRAN_NeighbourCells_default(template (present) EUTRAN_CellDescs cell_desc_list := { tr_EUTRAN_CellDesc_default },
+ template uint3_t prio := 3,
+ template (present) uint5_t thresh_high := 20,
+ template uint5_t thresh_low := 10,
+ template uint5_t qrxlevmin := 22)
+:= tr_EUTRAN_NeighbourCells(
+ cell_desc_list := cell_desc_list,
+ prio_presence := '1'B,
+ prio := prio,
+ thresh_high := thresh_high,
+ thresh_low_presence := '1'B,
+ thresh_low := thresh_low,
+ qrxlevmin_presence := '1'B,
+ qrxlevmin := qrxlevmin);
+
+template SystemInformationConfig SystemInformationConfig_default := {
+ si1 := {
+ cell_chan_desc := '8FB38000000000000000000000000000'O,
+ rach_control := {
+ max_retrans := RACH_MAX_RETRANS_7,
+ tx_integer := '1001'B,
+ cell_barr_access := false,
+ re_not_allowed := true,
+ acc := '0000010000000000'B
+ },
+ rest_octets := ?
+ },
+ si2 := {
+ bcch_freq_list := '00000000000000000000000000000000'O,
+ ncc_permitted := '11111111'B,
+ rach_control := {
+ max_retrans := RACH_MAX_RETRANS_7,
+ tx_integer := '1001'B,
+ cell_barr_access := false,
+ re_not_allowed := true,
+ acc := '0000010000000000'B
+ }
+ },
+ si2bis := omit,
+ si2ter := {
+ extd_bcch_freq_list := '8E320000000000000000000000000800'O,
+ rest_octets := ?
+ },
+ si2quater := {
+ tr_SI2quaterRestOctets_EUTRAN( repeated_neigh_cells := { tr_EUTRAN_NeighbourCells_default } )
+ },
+ si3 := {
+ cell_id := 0,
+ lai := {
+ mcc_mnc := '001F01'H,
+ lac := 1
+ },
+ ctrl_chan_desc := {
+ msc_r99 := true,
+ att := true,
+ bs_ag_blks_res := 1,
+ ccch_conf := CCHAN_DESC_1CCCH_COMBINED,
+ si22ind := false,
+ cbq3 := CBQ3_IU_MODE_NOT_SUPPORTED,
+ spare := '00'B,
+ bs_pa_mfrms := 3,
+ t3212 := 30
+ },
+ cell_options := {
+ dn_ind := false,
+ pwrc := false,
+ dtx := MS_SHALL_USE_UL_DTX,
+ radio_link_tout_div4 := 7
+ },
+ cell_sel_par := {
+ cell_resel_hyst_2dB := 2,
+ ms_txpwr_max_cch := 7,
+ acs := '0'B,
+ neci := true,
+ rxlev_access_min := 0
+ },
+ rach_control := {
+ max_retrans := RACH_MAX_RETRANS_7,
+ tx_integer := '1001'B,
+ cell_barr_access := false,
+ re_not_allowed := true,
+ acc := '0000010000000000'B
+ },
+ rest_octets := {
+ sel_params := {
+ presence := '0'B,
+ params := omit
+ },
+ pwr_offset := {
+ presence := '0'B,
+ offset := omit
+ },
+ si_2ter_ind := '1'B,
+ early_cm_ind := '0'B,
+ sched_where := {
+ presence := '0'B,
+ where := omit
+ },
+ gprs_ind := {
+ presence := '1'B,
+ ind := {
+ ra_colour := 0,
+ si13_pos := '0'B
+ }
+ },
+ umts_early_cm_ind := '1'B,
+ si2_quater_ind := {
+ presence := '1'B,
+ ind := '0'B
+ },
+ iu_mode_ind := omit,
+ si21_ind := {
+ presence := '0'B,
+ pos := omit
+ }
+ }
+ },
+ si4 := {
+ lai := {
+ mcc_mnc := '001F01'H,
+ lac := 1
+ },
+ cell_sel_par := {
+ cell_resel_hyst_2dB := 2,
+ ms_txpwr_max_cch := 7,
+ acs := '0'B,
+ neci := true,
+ rxlev_access_min := 0
+ },
+ rach_control := {
+ max_retrans := RACH_MAX_RETRANS_7,
+ tx_integer := '1001'B,
+ cell_barr_access := false,
+ re_not_allowed := true,
+ acc := '0000010000000000'B
+ },
+ cbch_chan_desc := {
+ iei := '64'O,
+ v := {
+ chan_nr := {
+ u := {
+ sdcch4 := {
+ tag := '001'B,
+ sub_chan := 2
+ }
+ },
+ tn := 0
+ },
+ tsc := 2,
+ h := false,
+ arfcn := 871,
+ maio_hsn := omit
+ }
+ },
+ cbch_mobile_alloc := omit,
+ rest_octets := {
+ sel_params := {
+ presence := '0'B,
+ params := omit
+ },
+ pwr_offset := {
+ presence := '0'B,
+ offset := omit
+ },
+ gprs_ind := {
+ presence := '1'B,
+ ind := {
+ ra_colour := 0,
+ si13_pos := '0'B
+ }
+ },
+ s_presence := '0'B,
+ s := omit
+ }
+ },
+ si13 := '9000185A6FC9E08410AB2B2B2B2B2B2B2B2B2B2B'O,
+ si5 := {
+ bcch_freq_list := '10000000000000000000000000000000'O
+ },
+ si5bis := omit,
+ si5ter := {
+ extd_bcch_freq_list := '9E050020000000000000000000000000'O
+ },
+ si6 := {
+ cell_id := 0,
+ lai := {
+ mcc_mnc := '001F01'H,
+ lac := 1
+ },
+ cell_options := {
+ dtx_ext := '1'B,
+ pwrc := false,
+ dtx := '01'B,
+ radio_link_timeout := '0111'B
+ },
+ ncc_permitted := '11111111'B,
+ rest_octets := ?
+ }
+ };
+
+
+/* List of all the System Information received on all RSL ports */
+type record of SystemInformationConfig SystemInformationConfig_list;
+
+function f_sysinfo_dec_raw(inout SystemInformationConfig si, RSL_Message rsl)
+{
+ var RSL_IE_Body sysinfo_type_ie;
+ var RSL_IE_SysinfoType si_type;
+ var octetstring data;
+
+ if (f_rsl_find_ie(rsl, RSL_IE_SYSINFO_TYPE, sysinfo_type_ie) == false) {
+ setverdict(fail, "Cannot find RSL_IE_SYSINFO_TYPE");
+ mtc.stop;
+ }
+ si_type := sysinfo_type_ie.sysinfo_type;
+
+ if (rsl.msg_type == RSL_MT_BCCH_INFO) {
+ var RSL_IE_Body bcch_ie;
+ if (f_rsl_find_ie(rsl, RSL_IE_FULL_BCCH_INFO, bcch_ie)) {
+ data := bcch_ie.other.payload;
+ }
+ } else if (rsl.msg_type == RSL_MT_SACCH_FILL) {
+ var RSL_IE_Body l3_ie;
+ if (f_rsl_find_ie(rsl, RSL_IE_L3_INFO, l3_ie)) {
+ data := l3_ie.l3_info.payload;
+ }
+ } else {
+ setverdict(fail, "Don't understand this System Information message");
+ mtc.stop;
+ }
+
+ var boolean handled := false;
+
+ if (rsl.msg_type == RSL_MT_BCCH_INFO) {
+ handled := true;
+
+ if (si_type == RSL_SYSTEM_INFO_1) {
+ if (not isbound(data)) {
+ si.si1 := omit;
+ } else {
+ si.si1 := dec_SystemInformation(data).payload.si1;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_2) {
+ if (not isbound(data)) {
+ si.si2 := omit;
+ } else {
+ si.si2 := dec_SystemInformation(data).payload.si2;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_2bis) {
+ if (not isbound(data)) {
+ si.si2bis := omit;
+ } else {
+ si.si2bis := dec_SystemInformation(data).payload.si2bis;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_2ter) {
+ if (not isbound(data)) {
+ si.si2ter := omit;
+ } else {
+ si.si2ter := dec_SystemInformation(data).payload.si2ter;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_2quater) {
+ if (not isbound(data)) {
+ si.si2quater := {};
+ } else {
+ var SystemInformationType2quater decoded := dec_SystemInformation(data).payload.si2quater;
+ /* this is a *record* of SI2quaterRestOctets! (multiplexed) */
+ si.si2quater[decoded.rest_octets.si2quater_index] := decoded.rest_octets;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_3) {
+ if (not isbound(data)) {
+ si.si3 := omit;
+ } else {
+ si.si3 := dec_SystemInformation(data).payload.si3;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_4) {
+ if (not isbound(data)) {
+ si.si4 := omit;
+ } else {
+ si.si4 := dec_SystemInformation(data).payload.si4;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_13) {
+ if (not isbound(data)) {
+ si.si13 := omit;
+ } else {
+ si.si13 := dec_SystemInformation(data).payload.other;
+ }
+ } else {
+ handled := false;
+ }
+ } else if (rsl.msg_type == RSL_MT_SACCH_FILL) {
+ handled := true;
+
+ if (si_type == RSL_SYSTEM_INFO_5) {
+ if (not isbound(data)) {
+ si.si5 := omit;
+ } else {
+ si.si5 := dec_SystemInformation(data).payload.si5;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_5bis) {
+ if (not isbound(data)) {
+ si.si5bis := omit;
+ } else {
+ si.si5bis := dec_SystemInformation(data).payload.si5bis;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_5ter) {
+ if (not isbound(data)) {
+ si.si5ter := omit;
+ } else {
+ si.si5ter := dec_SystemInformation(data).payload.si5ter;
+ }
+ } else if (si_type == RSL_SYSTEM_INFO_6) {
+ if (not isbound(data)) {
+ si.si6 := omit;
+ } else {
+ si.si6 := dec_SystemInformation(data).payload.si6;
+ }
+ } else {
+ handled := false;
+ }
+ }
+
+ if (not handled) {
+ setverdict(fail, "Unexpected SI type in ", rsl.msg_type, " message: ", si_type);
+ }
+}
+
type component test_CT extends CTRL_Adapter_CT {
/* Array of per-BTS state */
var BTS_State bts[NUM_BTS];
@@ -87,7 +526,10 @@ type component test_CT extends CTRL_Adapter_CT {
var MGCP_Emulation_CT vc_MGCP;
port TELNETasp_PT BSCVTY;
- var RAN_Adapter g_bssap;
+ /* StatsD */
+ var StatsD_Checker_CT vc_STATSD;
+
+ var RAN_Adapter g_bssap[NUM_MSC];
/* for old legacy-tests only */
port BSSAP_CODEC_PT BSSAP;
@@ -97,9 +539,20 @@ type component test_CT extends CTRL_Adapter_CT {
/* Osmux is enabled through VTY */
var boolean g_osmux_enabled := false;
- /* global test case guard timer */
+ /*Configure T(tias) over VTY, seconds */
+ var integer g_bsc_sccp_timer_ias := 7 * 60;
+ /*Configure T(tiar) over VTY, seconds */
+ var integer g_bsc_sccp_timer_iar := 15 * 60;
+
+ /* global test case guard timer (actual timeout value is set in f_init()) */
timer T_guard := 30.0;
+ var CounterNameValsList g_ctr_msc;
+ var CounterNameValsList g_ctr_bsc;
+ var CounterNameValsList g_ctr_bts;
+
+ /* System Information bytes as received during RSL startup, for each RSL[idx]. */
+ var SystemInformationConfig_list g_system_information := {};
}
modulepar {
@@ -111,62 +564,214 @@ modulepar {
integer mp_bsc_rsl_port := 3003;
/* port number to which to establish the IPA CTRL connection */
integer mp_bsc_ctrl_port := 4249;
+ /* port number to which to listen for STATSD metrics */
+ integer mp_bsc_statsd_port := 8125;
/* IP address at which the test binds */
charstring mp_test_ip := "127.0.0.1";
- RAN_Configuration mp_bssap_cfg := {
- transport := BSSAP_TRANSPORT_AoIP,
- sccp_service_type := "mtp3_itu",
- sctp_addr := { 23905, "127.0.0.1", 2905, "127.0.0.1" },
- own_pc := 185,
- own_ssn := 254,
- peer_pc := 187,
- peer_ssn := 254,
- sio := '83'O,
- rctx := 0
+ RAN_Configurations mp_bssap_cfg := {
+ {
+ transport := BSSAP_TRANSPORT_AoIP,
+ sccp_service_type := "mtp3_itu",
+ sctp_addr := { 23905, "127.0.0.1", 2905, "127.0.0.1" },
+ own_pc := 185, /* 0.23.1 first MSC emulation */
+ own_ssn := 254,
+ peer_pc := 187, /* 0.23.3 osmo-bsc */
+ peer_ssn := 254,
+ sio := '83'O,
+ rctx := 1
+ },
+ {
+ transport := BSSAP_TRANSPORT_AoIP,
+ sccp_service_type := "mtp3_itu",
+ sctp_addr := { 23906, "127.0.0.1", 2905, "127.0.0.1" },
+ own_pc := 2, /* 0.0.2 second MSC emulation */
+ own_ssn := 254,
+ peer_pc := 187, /* 0.23.3 osmo-bsc */
+ peer_ssn := 254,
+ sio := '83'O,
+ rctx := 2
+ },
+ {
+ transport := BSSAP_TRANSPORT_AoIP,
+ sccp_service_type := "mtp3_itu",
+ sctp_addr := { 23907, "127.0.0.1", 2905, "127.0.0.1" },
+ own_pc := 3, /* 0.0.3 third MSC emulation */
+ own_ssn := 254,
+ peer_pc := 187, /* 0.23.3 osmo-bsc */
+ peer_ssn := 254,
+ sio := '83'O,
+ rctx := 3
+ }
};
/* Whether to enable osmux tests. Can be dropped completely and enable
unconditionally once new version of osmo-bsc is released (current
version: 1.4.1) */
boolean mp_enable_osmux_test := true;
+ /* Value set in osmo-bsc.cfg "ms max power" */
+ uint8_t mp_exp_ms_power_level := 7;
}
-private function f_gen_test_hdlr_pars() return TestHdlrParams {
+private function f_gen_test_hdlr_pars(integer bssap_idx := 0) return TestHdlrParams {
var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
pars.aoip := true;
} else {
pars.aoip := false;
}
+ pars.exp_ms_power_level := mp_exp_ms_power_level;
+ pars.mscpool.bssap_idx := bssap_idx;
return pars;
}
+/* Convenience functions for rate counters using g_ctr_msc. */
+
+private function f_ctrs_msc_init(integer mscs_count := NUM_MSC, CounterNameVals counternames := counternames_msc_mscpool) runs on test_CT {
+ g_ctr_msc := f_counter_name_vals_get_n(IPA_CTRL, "msc", mscs_count, counternames);
+ log("initial msc rate counters: ", g_ctr_msc);
+}
+
+private function f_ctrs_msc_add(integer msc_nr, charstring countername, integer val := 1) runs on test_CT {
+ f_counter_name_vals_list_add(g_ctr_msc, msc_nr, countername, val);
+}
+
+/* f_ctrs_msc_init();
+ * f_do_thing(on_msc := 0);
+ * f_do_thing(on_msc := 0);
+ * f_do_other(on_msc := 1);
+ * f_ctrs_msc_add(0, "thing", 2);
+ * f_ctrs_msc_add(1, "other");
+ * f_ctrs_msc_verify();
+ */
+private function f_ctrs_msc_verify() runs on test_CT {
+ log("verifying msc rate counters: ", g_ctr_msc);
+ f_counter_name_vals_expect_n(IPA_CTRL, "msc", g_ctr_msc);
+}
+
+/* convenience: f_ctrs_msc_add() and f_ctrs_msc_verify() in one call.
+ * f_ctrs_msc_init();
+ * f_do_thing(on_msc := 0);
+ * f_do_thing(on_msc := 0);
+ * f_do_thing(on_msc := 0);
+ * f_ctrs_msc_expect(0, "thing", 3);
+ */
+private function f_ctrs_msc_expect(integer msc_nr, charstring countername, integer val := 1) runs on test_CT {
+ f_ctrs_msc_add(msc_nr, countername, val);
+ f_ctrs_msc_verify();
+}
+
+/* Convenience functions for rate counters using g_ctr_bts, always also including g_ctr_bsc. */
+
+private function f_ctrs_bsc_and_bts_init(integer bts_count := NUM_BTS, CounterNameVals counternames := counternames_bsc_bts_handover) runs on test_CT {
+ g_ctr_bts := f_counter_name_vals_get_n(IPA_CTRL, "bts", bts_count, counternames);
+ log("initial bts rate counters: ", g_ctr_bts);
+ f_ctrs_bsc_init(counternames);
+}
+
+private function f_ctrs_bsc_and_bts_add(integer bts_nr, charstring countername, integer val := 1) runs on test_CT {
+ f_counter_name_vals_list_add(g_ctr_bts, bts_nr, countername, val);
+ f_ctrs_bsc_add(countername, val);
+}
+
+/* f_ctrs_bsc_and_bts_init();
+ * f_do_thing(on_bts := 0);
+ * f_do_thing(on_bts := 0);
+ * f_do_other(on_bts := 1);
+ * f_ctrs_bsc_and_bts_add(0, "thing", 2);
+ * f_ctrs_bsc_and_bts_add(1, "other");
+ * f_ctrs_bsc_and_bts_verify();
+ */
+private function f_ctrs_bsc_and_bts_verify() runs on test_CT {
+ f_counter_name_vals_expect_n(IPA_CTRL, "bts", g_ctr_bts);
+ f_ctrs_bsc_verify();
+}
+
+/* convenience: f_ctrs_bsc_and_bts_add() and f_ctrs_bsc_and_bts_verify() in one call.
+ * f_ctrs_bsc_and_bts_init();
+ * f_do_thing(on_bts := 0);
+ * f_do_thing(on_bts := 0);
+ * f_do_thing(on_bts := 0);
+ * f_ctrs_bsc_and_bts_expect(0, "thing", 3);
+ */
+private function f_ctrs_bsc_and_bts_expect(integer bts_nr, charstring countername, integer val := 1) runs on test_CT {
+ f_ctrs_bsc_and_bts_add(bts_nr, countername, val);
+ f_ctrs_bsc_and_bts_verify();
+}
+
+
+/* Convenience functions for rate counters using g_ctr_bsc. */
+
+private function f_ctrs_bsc_init(CounterNameVals counternames := counternames_bsc_bts_handover) runs on test_CT {
+ g_ctr_bsc := f_counter_name_vals_get_n(IPA_CTRL, "bsc", 1, counternames);
+ log("initial bsc rate counters: ", g_ctr_bsc);
+}
+
+private function f_ctrs_bsc_add(charstring countername, integer val := 1) runs on test_CT {
+ f_counter_name_vals_list_add(g_ctr_bsc, 0, countername, val);
+}
+
+/* f_ctrs_bsc_init();
+ * f_do_thing();
+ * f_do_thing();
+ * f_do_other();
+ * f_ctrs_bsc_add("thing", 2);
+ * f_ctrs_bsc_add("other");
+ * f_ctrs_bsc_verify();
+ */
+private function f_ctrs_bsc_verify() runs on test_CT {
+ f_counter_name_vals_expect_n(IPA_CTRL, "bsc", g_ctr_bsc);
+}
+
+/* convenience: f_ctrs_bsc_add() and f_ctrs_bsc_verify() in one call.
+ * f_ctrs_bsc_init();
+ * f_do_thing();
+ * f_ctrs_bsc_expect("thing", 1);
+ */
+private function f_ctrs_bsc_expect(charstring countername, integer val := 1) runs on test_CT {
+ f_ctrs_bsc_add(countername, val);
+ f_ctrs_bsc_verify();
+}
+
+
private function f_shutdown_helper() runs on test_CT {
all component.stop;
setverdict(pass);
mtc.stop;
}
-private function f_legacy_bssap_reset() runs on test_CT {
+private function f_legacy_bssap_reset(integer bssap_idx := 0) runs on test_CT {
var BSSAP_N_UNITDATA_ind ud_ind;
+ var boolean reset_received := false;
timer T := 5.0;
- BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
+ BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[bssap_idx].sccp_addr_peer, g_bssap[bssap_idx].sccp_addr_own,
+ ts_BSSMAP_Reset(0, g_osmux_enabled)));
T.start;
alt {
- [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) {
+ [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap[bssap_idx].sccp_addr_own, g_bssap[bssap_idx].sccp_addr_peer,
+ tr_BSSMAP_ResetAck(g_osmux_enabled))) {
log("Received RESET-ACK in response to RESET, we're ready to go!");
}
[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled))) -> value ud_ind {
log("Respoding to inbound RESET with RESET-ACK");
BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
ts_BSSMAP_ResetAck(g_osmux_enabled)));
+ reset_received := true;
repeat;
}
[] BSSAP.receive { repeat; }
- [] T.timeout { setverdict(fail, "Waiting for RESET-ACK after sending RESET"); }
+ [] T.timeout {
+ log("Timeout waiting for RESET-ACK after sending RESET");
+ /* If we received a RESET after ours was sent, it
+ may be a race condition where the other peer beacame
+ available after we sent it, but we are in a desired
+ state anyway, so go forward. */
+ if (not reset_received) {
+ setverdict(fail);
+ }
+ }
}
}
@@ -218,9 +823,9 @@ runs on test_CT {
/* wait for IPA RSL link to connect and send ID ACK */
T.start;
alt {
- [] IPA_RSL[i].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) {
+ [] IPA_RSL[i].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) {
T.stop;
- IPA_RSL[i].send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_PAGING_LOAD_IND(23)));
+ IPA_RSL[i].send(ts_ASP_RSL_UD(ts_RSL_PAGING_LOAD_IND(23)));
}
[] IPA_RSL[i].receive(ASP_IPA_Event:?) { repeat }
[] IPA_RSL[i].receive { repeat }
@@ -298,7 +903,7 @@ function f_init_mgcp(charstring id) runs on test_CT {
mgw_udp_port := 2427,
/* Enable it for SCCPlite, since we have 2 MGCP sockets towards MGW (UDP one +
the on with MGCP over IPA forwarded from MSC one) */
- multi_conn_mode := (mp_bssap_cfg.transport == BSSAP_TRANSPORT_SCCPlite_SERVER)
+ multi_conn_mode := (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_SCCPlite_SERVER)
};
vc_MGCP := MGCP_Emulation_CT.create(id);
@@ -329,20 +934,107 @@ function f_init_vty(charstring id := "foo") runs on test_CT {
map(self:BSCVTY, system:BSCVTY);
f_vty_set_prompts(BSCVTY);
f_vty_transceive(BSCVTY, "enable");
+ f_cs7_inst_0_cfg(BSCVTY, {"sccp-timer ias " & int2str(g_bsc_sccp_timer_ias),
+ "sccp-timer iar " & int2str(g_bsc_sccp_timer_iar)});
+}
+
+private function f_logp(charstring log_msg) runs on MSC_ConnHdlr
+{
+ // log on TTCN3 log output
+ log(log_msg);
+ // log in stderr log
+ f_vty_transceive(BSCVTY, "logp lglobal notice " & log_msg);
+}
+
+private function f_sysinfo_seen(integer rsl_idx, RSL_Message rsl) runs on test_CT
+{
+ if (rsl_idx >= lengthof(g_system_information)) {
+ g_system_information[rsl_idx] := SystemInformationConfig_omit
+ }
+ f_sysinfo_dec_raw(g_system_information[rsl_idx], rsl);
+}
+
+altstep as_catch_RSL_sysinfo(integer rsl_idx) runs on test_CT {
+ var ASP_RSL_Unitdata rx_rsl_ud;
+
+ /* For handler_mode := false, receiving the RSL bootstrap messages directly on IPA_RSL */
+ [] IPA_RSL[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_NO_BCCH_INFO)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+ [] IPA_RSL[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_BCCH_INFO)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+ [] IPA_RSL[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_NO_SACCH_FILL)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+ [] IPA_RSL[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_SACCH_FILL)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+
+ /* For handler_mode := true, receiving the RSL bootstrap messages via RSL_Emulation */
+ [] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_NO_BCCH_INFO)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+ [] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_BCCH_INFO)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+ [] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_NO_SACCH_FILL)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+ [] RSL_CCHAN[rsl_idx].receive(tr_ASP_RSL_UD(tr_RSL_SACCH_FILL)) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ repeat;
+ }
+}
+
+/* TODO: use BooleanList from COMMON/src/General_Types.ttcn */
+private type record of boolean my_BooleanList;
+
+private function f_vty_msc_allow_attach(TELNETasp_PT pt, my_BooleanList allow_attach_list)
+{
+ var charstring config := f_vty_transceive_ret(pt, "show running-config");
+
+ for (var integer msc_nr := 0; msc_nr < sizeof(allow_attach_list); msc_nr := msc_nr+1) {
+ if (f_strstr(config, "\nmsc " & int2str(msc_nr) & "\n") < 0) {
+ /* There is no 'msc N' for this msc_nr in the running config, so don't create an empty msc by
+ * stepping into that config node. */
+ log("msc ", msc_nr, " is not configured, skipping");
+ continue;
+ }
+ f_vty_enter_cfg_msc(pt, msc_nr);
+ if (allow_attach_list[msc_nr]) {
+ /* strict := false: ignore if osmo-bsc does not support this config option (latest build) */
+ f_vty_transceive(pt, "allow-attach", strict := false);
+ } else {
+ f_vty_transceive(pt, "no allow-attach", strict := false);
+ }
+ f_vty_transceive(pt, "exit");
+ f_vty_transceive(pt, "exit");
+ }
}
/* global initialization function
* \param nr_bts Number of BTSs we should start/bring up
- * \param handler_mode Start an RSL_Emulation_CT component (true) or not (false) */
-function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false, boolean allow_osmux := false) runs on test_CT {
- var integer i;
+ * \param handler_mode Start an RSL_Emulation_CT component (true) or not (false).
+ * \param nr_msc Number of virtual MSCs to bring up to connect to osmo-bsc.
+ */
+function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false, boolean allow_osmux := false,
+ integer nr_msc := 1, float guard_timeout := 30.0) runs on test_CT {
+ var integer bssap_idx;
if (g_initialized) {
return;
}
g_initialized := true;
- T_guard.start;
+ T_guard.start(guard_timeout);
activate(as_Tguard());
f_init_vty("VirtMSC");
@@ -350,45 +1042,85 @@ function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false, boolea
f_vty_allow_osmux(allow_osmux);
}
- /* Call a function of our 'parent component' RAN_Adapter_CT to start the
- * MSC-side BSSAP emulation */
- if (handler_mode) {
- var RanOps ranops := MSC_RanOps;
- ranops.use_osmux := g_osmux_enabled;
- f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", ranops);
- connect(self:SCCPLITE_IPA_CTRL, g_bssap.vc_RAN:CTRL_CLIENT);
- f_ran_adapter_start(g_bssap);
- } else {
- f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", omit);
- connect(self:BSSAP, g_bssap.vc_SCCP:SCCP_SP_PORT);
- f_ran_adapter_start(g_bssap);
- f_legacy_bssap_reset();
+ var my_BooleanList allow_attach := { false, false, false };
+ f_init_statsd("VirtMSC", vc_STATSD, mp_test_ip, mp_bsc_statsd_port);
+
+ for (bssap_idx := 0; bssap_idx < nr_msc; bssap_idx := bssap_idx+1) {
+ allow_attach[bssap_idx] := true;
+ /* Call a function of our 'parent component' RAN_Adapter_CT to start the
+ * MSC-side BSSAP emulation */
+ if (handler_mode) {
+ var RanOps ranops := MSC_RanOps;
+ ranops.use_osmux := g_osmux_enabled;
+ f_ran_adapter_init(g_bssap[bssap_idx], mp_bssap_cfg[bssap_idx], "VirtMSC", ranops);
+ connect(self:SCCPLITE_IPA_CTRL, g_bssap[bssap_idx].vc_RAN:CTRL_CLIENT);
+ f_ran_adapter_start(g_bssap[bssap_idx]);
+ } else {
+ f_ran_adapter_init(g_bssap[bssap_idx], mp_bssap_cfg[bssap_idx], "VirtMSC", omit);
+ connect(self:BSSAP, g_bssap[bssap_idx].vc_SCCP:SCCP_SP_PORT);
+ f_ran_adapter_start(g_bssap[bssap_idx]);
+ f_legacy_bssap_reset();
+ }
}
+ /* start the test with exactly all enabled MSCs allowed to attach */
+ f_vty_msc_allow_attach(BSCVTY, allow_attach);
+
f_ipa_ctrl_start(mp_bsc_ip, mp_bsc_ctrl_port);
f_init_mgcp("VirtMSC");
- for (i := 0; i < nr_bts; i := i+1) {
- /* wait until osmo-bts-omldummy has respawned */
- f_wait_oml(i, "degraded", 5.0);
- /* start RSL connection */
- f_ipa_rsl_start(bts[i].rsl, mp_bsc_ip, mp_bsc_rsl_port, i, handler_mode);
- /* wait until BSC tells us "connected" */
- f_wait_oml(i, "connected", 5.0);
+ for (var integer i := 0; i < nr_bts; i := i+1) {
+ f_init_bts(i, handler_mode);
}
+}
+function f_init_bts(integer bts_idx := 0, boolean handler_mode := false)
+runs on test_CT {
+ /* wait until osmo-bts-omldummy has respawned */
+ f_wait_oml(bts_idx, "degraded", 5.0);
+
+ /* start RSL connection */
+ f_ipa_rsl_start(bts[bts_idx].rsl, mp_bsc_ip, mp_bsc_rsl_port, bts_idx, handler_mode);
+ /* wait until BSC tells us "connected" */
+ f_wait_oml(bts_idx, "connected", 5.0);
+}
+
+function f_init_bts_and_check_sysinfo(integer bts_idx := 0, boolean handler_mode := false,
+ template SystemInformationConfig expect_si)
+runs on test_CT {
+ var default sysinfo := activate(as_catch_RSL_sysinfo(bts_idx));
+
+ f_init_bts(bts_idx, handler_mode);
+
+ /* Give some time to (hopefully/most likely) collect all system informations from RSL startup.
+ * We could stop as soon as all expected SI are received, but then we might miss SI that we don't expect and
+ * that might be sent afterwards. So rather give a generous timeout and be quite sure to catch all SI.
+ */
+ f_sleep(5.0);
+ log("RSL ", bts_idx, " SYSTEM INFORMATION: ", g_system_information[bts_idx]);
+
+ deactivate(sysinfo);
+
+ if (match(g_system_information[bts_idx], expect_si)) {
+ setverdict(pass);
+ } else {
+ log("RSL ", bts_idx, ": EXPECTED SI: ", expect_si);
+ log("RSL ", bts_idx, ": GOT SI: ", g_system_information[bts_idx]);
+ setverdict(fail, "received SI does not match expectations");
+ return;
+ }
}
/* expect to receive a RSL message matching a specified template on a given BTS / stream */
-function f_exp_ipa_rx(integer bts_nr, template RSL_Message t_rx, float t_secs := 2.0, IpaStreamId sid := IPAC_PROTO_RSL_TRX0)
+function f_exp_ipa_rx(integer bts_nr, template (present) RSL_Message t_rx, float t_secs := 2.0, IpaStreamId sid := IPAC_PROTO_RSL_TRX0)
runs on test_CT return RSL_Message {
var ASP_RSL_Unitdata rx_rsl_ud;
timer T := t_secs;
T.start;
alt {
- [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(sid, t_rx)) -> value rx_rsl_ud {
+ [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(t_rx, sid)) -> value rx_rsl_ud {
T.stop;
}
[] IPA_RSL[bts_nr].receive { repeat; }
@@ -401,9 +1133,9 @@ runs on test_CT return RSL_Message {
}
/* helper function to transmit RSL on a given BTS/stream */
-function f_ipa_tx(integer bts_nr, template RSL_Message t_tx, IpaStreamId sid := IPAC_PROTO_RSL_TRX0)
+function f_ipa_tx(integer bts_nr, template (value) RSL_Message t_tx, IpaStreamId sid := IPAC_PROTO_RSL_TRX0)
runs on test_CT {
- IPA_RSL[bts_nr].send(ts_ASP_RSL_UD(sid, t_tx));
+ IPA_RSL[bts_nr].send(ts_ASP_RSL_UD(t_tx, sid));
}
@@ -414,7 +1146,7 @@ testcase TC_chan_act_noreply() runs on test_CT {
f_init(1);
- IPA_RSL[0].send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_CHAN_RQD('23'O, 23)));
+ IPA_RSL[0].send(ts_ASP_RSL_UD(ts_RSL_CHAN_RQD('23'O, 23)));
rsl_unused := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
setverdict(pass);
}
@@ -428,7 +1160,7 @@ testcase TC_chan_act_counter() runs on test_CT {
f_init(1);
chreq_total := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:total");
- IPA_RSL[0].send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_CHAN_RQD('23'O, 23)));
+ IPA_RSL[0].send(ts_ASP_RSL_UD(ts_RSL_CHAN_RQD('23'O, 23)));
rsl_unused := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:total", chreq_total+1);
@@ -436,13 +1168,11 @@ testcase TC_chan_act_counter() runs on test_CT {
}
/* CHAN RQD -> CHAN ACT -> CHAN ACT ACK -> RF CHAN REL */
-testcase TC_chan_act_ack_noest() runs on test_CT {
+private function f_TC_chan_act_ack_noest(OCT1 ra := '23'O) runs on test_CT {
var RSL_Message rx_rsl;
- f_init(1);
-
/* Send CHAN RQD and wait for allocation; acknowledge it */
- var RslChannelNr chan_nr := f_chreq_act_ack();
+ var RslChannelNr chan_nr := f_chreq_act_ack(ra);
/* expect BSC to disable the channel again if there's no RLL EST IND */
rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), T3101_MAX);
@@ -450,6 +1180,42 @@ testcase TC_chan_act_ack_noest() runs on test_CT {
setverdict(pass);
}
+/* Normal variant */
+testcase TC_chan_act_ack_noest() runs on test_CT {
+ f_init(1);
+ f_TC_chan_act_ack_noest();
+}
+
+/* Emergency call variant */
+testcase TC_chan_act_ack_noest_emerg() runs on test_CT {
+ /* See also: 3GPP TS 04.08, Table 9.9, ra=101xxxxx */
+ f_init(1);
+ f_vty_allow_emerg_bts(true, 0);
+ f_TC_chan_act_ack_noest(ra := 'A5'O);
+}
+
+/* Emergency call variant, but emergency calls are not allowed */
+testcase TC_chan_rqd_emerg_deny() runs on test_CT {
+ /* See also: 3GPP TS 04.08, Table 9.9, ra=101xxxxx */
+
+ var RSL_Message rx_rsl;
+ var GsmRrMessage rr;
+
+ f_init(1);
+ f_vty_allow_emerg_bts(false, 0);
+
+ IPA_RSL[0].clear;
+ f_ipa_tx(0, ts_RSL_CHAN_RQD('A5'O, 23));
+
+ rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeC(RSL_MT_IMMEDIATE_ASSIGN_CMD));
+ rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
+ if (rr.header.message_type == IMMEDIATE_ASSIGNMENT_REJECT) {
+ setverdict(pass);
+ } else {
+ setverdict(fail, "immediate assignment not rejected");
+ }
+}
+
/* Test behavior if MSC never answers to CR */
testcase TC_chan_act_ack_est_ind_noreply() runs on test_CT {
var RslLinkId main_dcch := valueof(ts_RslLinkID_DCCH(0));
@@ -544,11 +1310,10 @@ testcase TC_chan_exhaustion() runs on test_CT {
f_ipa_tx(0, ts_RSL_CHAN_RQD('42'O, 42));
alt {
- [] IPA_RSL[0].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
- tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) {
setverdict(fail, "Received CHAN ACT ACK without resources?!?");
}
- [] IPA_RSL[0].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_IMM_ASSIGN(?))) -> value rsl_ud {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_IMM_ASSIGN(?))) -> value rsl_ud {
var GsmRrMessage rr;
/* match on IMM ASS REJ */
rr := dec_GsmRrMessage(rsl_ud.rsl.ies[1].body.full_imm_ass_info.payload);
@@ -580,13 +1345,11 @@ testcase TC_chan_deact_silence() runs on test_CT {
/* Expect CHANnel RELease */
alt {
- [] IPA_RSL[0].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
- tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL))) {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL))) {
log("Received CHANnel RELease");
setverdict(pass);
}
- [] IPA_RSL[0].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
- tr_RSL_IMM_ASSIGN(?))) {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_IMM_ASSIGN(?))) {
/* See OS#3709, OsmoBSC should not send Immediate
* Assignment Reject since a dedicated channel was
* already allocated, and Immediate Assignment was
@@ -605,16 +1368,17 @@ testcase TC_chan_deact_silence() runs on test_CT {
/* Verify that the BSC refuses any BSSAP connection from the MSC (They are all BSC->MSC direction,
* except for the inter-BSC handover, MT side) */
-testcase TC_outbound_connect() runs on test_CT {
+testcase TC_outbound_connect(integer bssap_idx := 0) runs on test_CT {
f_init(1);
- BSSAP.send(ts_BSSAP_CONNECT_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, 2342, ts_BSSMAP_AssignmentReq));
+ BSSAP.send(ts_BSSAP_CONNECT_req(g_bssap[bssap_idx].sccp_addr_peer, g_bssap[bssap_idx].sccp_addr_own,
+ 2342, ts_BSSMAP_AssignmentReq));
BSSAP.receive(tr_BSSAP_DISC_ind(2342, ?, ?));
setverdict(pass);
}
/* Test behavior if MSC answers with CREF to CR */
-testcase TC_assignment_cic_only() runs on test_CT {
+testcase TC_assignment_cic_only(integer bssap_idx := 0) runs on test_CT {
var BSSAP_N_CONNECT_ind rx_c_ind;
var RSL_Message rx_rsl;
var DchanTuple dt;
@@ -622,7 +1386,7 @@ testcase TC_assignment_cic_only() runs on test_CT {
f_init(1);
dt := f_est_dchan('23'O, 23, '00000000'O);
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
/* send assignment without AoIP IEs */
BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_AssignmentReq(ts_BSSMAP_IE_CIC(0, 1))));
} else {
@@ -644,12 +1408,12 @@ testcase TC_assignment_cic_only() runs on test_CT {
}
/* generate an assignment request for either AoIP or SCCPlite */
-function f_gen_ass_req(boolean osmux_enabled := false) return PDU_BSSAP {
+function f_gen_ass_req(boolean osmux_enabled := false, integer bssap_idx := 0, charstring aoip_tla := "1.2.3.4") return PDU_BSSAP {
var PDU_BSSAP ass_cmd;
var BSSMAP_IE_Osmo_OsmuxCID osmux_cid := valueof(ts_OsmuxCID(0));
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
- valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
+ valueof(f_ts_BSSMAP_IE_AoIP_TLA(aoip_tla, 2342));
if (osmux_enabled) {
ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla, osmux_cid));
} else {
@@ -662,11 +1426,11 @@ function f_gen_ass_req(boolean osmux_enabled := false) return PDU_BSSAP {
return ass_cmd;
}
-function f_gen_handover_req() return PDU_BSSAP {
+function f_gen_handover_req(integer bssap_idx := 0, charstring aoip_tla := "1.2.3.4") return PDU_BSSAP {
var PDU_BSSAP ho_req;
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
- valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
+ valueof(f_ts_BSSMAP_IE_AoIP_TLA(aoip_tla, 2342));
ho_req := valueof(ts_BSSMAP_HandoverRequest(omit, tla));
} else {
var BSSMAP_IE_CircuitIdentityCode cic := valueof(ts_BSSMAP_IE_CIC(0,1));
@@ -676,10 +1440,10 @@ function f_gen_handover_req() return PDU_BSSAP {
}
/* generate an assignment complete template for either AoIP or SCCPlite */
-function f_gen_exp_compl(boolean expect_osmux := false) return template PDU_BSSAP {
+function f_gen_exp_compl(boolean expect_osmux := false, integer bssap_idx := 0) return template PDU_BSSAP {
var template PDU_BSSAP exp_compl;
var BSSMAP_IE_Osmo_OsmuxCID osmux_cid := valueof(ts_OsmuxCID(0));
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
if (expect_osmux) {
exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?, osmux_cid);
} else {
@@ -906,31 +1670,82 @@ function f_expect_chan_rel(integer bts_nr, RslChannelNr rsl_chan_nr,
boolean expect_rr_chan_rel := true,
boolean expect_rll_rel_req := true,
boolean handle_rll_rel := true,
- boolean is_csfb := false
+ boolean is_csfb := false,
+ template CellSelIndValue csfb_expect_cells := omit,
+ template RR_Cause expect_rr_cause := ?
) runs on test_CT {
var RslLinkId main_dcch := valueof(ts_RslLinkID_DCCH(0));
var boolean got_deact_sacch := false;
var boolean got_rr_chan_rel := false;
var boolean got_rll_rel_req := false;
+ var ASP_RSL_Unitdata ud;
+ var RSL_IE_Body l3_ie;
+ var PDU_ML3_NW_MS l3;
+ var RR_Cause got_cause;
log("f_expect_chan_rel() expecting: expect_deact_sacch=", expect_deact_sacch, " expect_rr_chan_rel=", expect_rr_chan_rel,
" expect_rll_rel_req=", expect_rll_rel_req);
alt {
- [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
- tr_RSL_DEACT_SACCH(rsl_chan_nr))) {
+ [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(tr_RSL_DEACT_SACCH(rsl_chan_nr))) {
got_deact_sacch := true;
repeat;
}
- [is_csfb] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_DATA_REQ(rsl_chan_nr, ?, decmatch tr_RRM_RR_RELEASE_CSFB))) {
+ [is_csfb] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(tr_RSL_DATA_REQ(rsl_chan_nr, ?, decmatch tr_RRM_RR_RELEASE_CSFB))) -> value ud {
got_rr_chan_rel := true;
+
+ if (f_rsl_find_ie(ud.rsl, RSL_IE_L3_INFO, l3_ie) == false) {
+ setverdict(fail, "cannot find L3");
+ mtc.stop;
+ }
+ l3 := dec_PDU_ML3_NW_MS(l3_ie.l3_info.payload);
+
+ if (not istemplatekind(csfb_expect_cells, "omit")) {
+ var CellSelIndValue cells := dec_CellSelIndValue(
+ l3.msgs.rrm.channelRelease.cellSelectionIndicator.cellSelectionIndicatorValue);
+
+ log("GOT RR CHANNEL RELEASE CSFB CELLS: ", cells);
+ if (match(cells, csfb_expect_cells)) {
+ setverdict(pass);
+ } else {
+ log("EXPECTED CSFB CELLS: ", csfb_expect_cells);
+ setverdict(fail, "Received CSFB cells list on RR Channel Release does not match expectations");
+ }
+ }
+
+ if (not istemplatekind(expect_rr_cause, "omit")) {
+ int2enum(oct2int(l3.msgs.rrm.channelRelease.rRCause.valuePart), got_cause);
+ log("GOT CAUSE CODE: ", l3.msgs.rrm.channelRelease.rRCause.valuePart, " = ", got_cause);
+ if (match(got_cause, expect_rr_cause)) {
+ setverdict(pass);
+ } else {
+ log("EXPECTED CAUSE CODE: ", expect_rr_cause);
+ setverdict(fail, "Received RR Channel Release Cause code does not match expectations");
+ }
+ }
repeat;
}
- [not is_csfb] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_DATA_REQ(rsl_chan_nr, ?, decmatch tr_RRM_RR_RELEASE))) {
+ [not is_csfb] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(tr_RSL_DATA_REQ(rsl_chan_nr, ?, decmatch tr_RRM_RR_RELEASE))) -> value ud {
got_rr_chan_rel := true;
+
+ if (not istemplatekind(expect_rr_cause, "omit")) {
+ if (f_rsl_find_ie(ud.rsl, RSL_IE_L3_INFO, l3_ie) == false) {
+ setverdict(fail, "cannot find L3");
+ mtc.stop;
+ }
+ l3 := dec_PDU_ML3_NW_MS(l3_ie.l3_info.payload);
+
+ int2enum(oct2int(l3.msgs.rrm.channelRelease.rRCause.valuePart), got_cause);
+ log("GOT CAUSE CODE: ", l3.msgs.rrm.channelRelease.rRCause.valuePart, " = ", got_cause);
+ if (match(got_cause, expect_rr_cause)) {
+ setverdict(pass);
+ } else {
+ log("EXPECTED CAUSE CODE: ", expect_rr_cause);
+ setverdict(fail, "Received RR Channel Release Cause code does not match expectations");
+ }
+ }
repeat;
}
- [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
- tr_RSL_REL_REQ(rsl_chan_nr, ?))) {
+ [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(tr_RSL_REL_REQ(rsl_chan_nr, ?))) {
got_rll_rel_req := true;
/* FIXME: Why are we getting this for LinkID SACCH? */
if (handle_rll_rel) {
@@ -938,13 +1753,12 @@ function f_expect_chan_rel(integer bts_nr, RslChannelNr rsl_chan_nr,
}
repeat;
}
- [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
- tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL))) {
+ [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL))) {
/* respond with CHAN REL ACK */
f_ipa_tx(0, ts_RSL_RF_CHAN_REL_ACK(rsl_chan_nr));
}
/* ignore any user data */
- [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_MsgTypeR(?))) {
+ [] IPA_RSL[bts_nr].receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeR(?))) {
repeat;
}
}
@@ -1051,9 +1865,9 @@ testcase TC_chan_rel_a_reset() runs on test_CT {
IPA_RSL[0].clear;
/* perform BSSAP RESET, expect RESET ACK and DISC.ind on connection */
- BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
+ BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[0].sccp_addr_peer, g_bssap[0].sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
interleave {
- [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) { }
+ [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap[0].sccp_addr_own, g_bssap[0].sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) { }
[] BSSAP.receive(tr_BSSAP_DISC_ind(dt.sccp_conn_id, ?, ?)) { }
}
@@ -1061,6 +1875,51 @@ testcase TC_chan_rel_a_reset() runs on test_CT {
setverdict(pass);
}
+/* Verify T(iar) triggers and releases the channel */
+testcase TC_chan_rel_sccp_tiar_timeout() runs on test_CT {
+ var DchanTuple dt;
+
+ /* Set T(iar) in BSC low enough that it will trigger before other side
+ has time to keep alive with a T(ias). Keep recommended ratio of
+ T(iar) >= T(ias)*2 */
+ g_bsc_sccp_timer_ias := 2;
+ g_bsc_sccp_timer_iar := 5;
+
+ f_init(1);
+
+ dt := f_est_dchan('23'O, 23, '00010203040506'O);
+ f_expect_chan_rel(0, dt.rsl_chan_nr, expect_rll_rel_req := false);
+ setverdict(pass);
+}
+
+private function f_tc_chan_rel_rr_cause(myBSSMAP_Cause clear_cmd_cause, template RR_Cause expect_rr_cause)
+runs on test_CT
+{
+ var DchanTuple dt;
+
+ dt := f_est_dchan('23'O, 23, '00010203040506'O);
+ var BssmapCause cause := 0;
+ BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommand(enum2int(clear_cmd_cause))));
+ BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete)) {
+ BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
+ }
+
+ f_expect_chan_rel(0, dt.rsl_chan_nr, expect_rll_rel_req := false, expect_rr_cause := expect_rr_cause);
+ setverdict(pass);
+}
+
+/* Test that Clear Command cause codes affect the RR Channel Release cause code */
+testcase TC_chan_rel_rr_cause() runs on test_CT {
+ f_init(1);
+
+ f_tc_chan_rel_rr_cause(GSM0808_CAUSE_CALL_CONTROL, GSM48_RR_CAUSE_NORMAL);
+ f_tc_chan_rel_rr_cause(GSM0808_CAUSE_HANDOVER_SUCCESSFUL, GSM48_RR_CAUSE_NORMAL);
+ f_tc_chan_rel_rr_cause(GSM0808_CAUSE_PREEMPTION, GSM48_RR_CAUSE_PREMPTIVE_REL);
+ f_tc_chan_rel_rr_cause(GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+ f_tc_chan_rel_rr_cause(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE, GSM48_RR_CAUSE_ABNORMAL_UNSPEC);
+ f_tc_chan_rel_rr_cause(GSM0808_CAUSE_EQUIPMENT_FAILURE, GSM48_RR_CAUSE_ABNORMAL_UNSPEC);
+}
+
/* Test behavior if RSL EST IND for non-active channel */
testcase TC_rll_est_ind_inact_lchan() runs on test_CT {
timer T := 2.0;
@@ -1157,8 +2016,449 @@ testcase TC_rll_est_ind_inval_sacch() runs on test_CT {
setverdict(pass);
}
+private function f_exp_sapi_n_reject(template (present) GsmSapi sapi := ?,
+ template myBSSMAP_Cause cause := ?,
+ float T_val := 2.0)
+runs on test_CT {
+ var BSSAP_N_DATA_ind rx_di;
+ timer T;
+ var template BSSMAP_IE_Cause tr_cause := tr_BSSMAP_IE_Cause(cause);
+ var template PDU_BSSAP tr_pdu := tr_BSSMAP_SAPInReject(sapi);
+ T.start(T_val);
+ alt {
+ [] BSSAP.receive(tr_BSSAP_DATA_ind(?, tr_pdu)) -> value rx_di {
+ var BSSMAP_IE_Cause rx_cause := rx_di.userData.pdu.bssmap.sAPInReject.cause;
+ if (not match(rx_cause, tr_cause)) {
+ setverdict(fail, "Rx unexpected Cause IE: ",
+ rx_cause, " vs expected ", tr_cause);
+ }
+ setverdict(pass);
+ }
+ [] BSSAP.receive(BSSAP_N_DATA_ind:?) -> value rx_di {
+ setverdict(fail, "Rx unexpected BSSAP PDU: ", rx_di);
+ }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for BSSMAP SAPI N Reject");
+ }
+ }
+}
+
+/* Check if we get SAPI N Reject on receipt of unexpected RLL RELease INDication */
+testcase TC_rll_rel_ind_sapi_n_reject() runs on test_CT {
+ var octetstring rnd_data := f_rnd_octstring(16);
+ var RSL_Message rx_rsl;
+ var DchanTuple dt;
+
+ f_init(1);
+
+ /* MS establishes a SAPI=0 link on DCCH */
+ dt := f_est_dchan(f_rnd_ra_cs(), 23, rnd_data);
+
+ /* MSC sends some data on (not yet established) SAPI=3 link */
+ BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSAP_DTAP(rnd_data, '03'O)));
+ /* BSC attempts to establish a SAPI=3 link on DCCH */
+ rx_rsl := f_exp_ipa_rx(0, tr_RSL_EST_REQ(dt.rsl_chan_nr, tr_RslLinkID_DCCH(3)));
+
+ /* MS sends unexpected RELease INDication on SAPI=3 */
+ f_ipa_tx(0, ts_RSL_REL_IND(dt.rsl_chan_nr, ts_RslLinkID_DCCH(3)));
+ /* We expect to receive BSSMAP SAPI N Reject message from the BSC */
+ f_exp_sapi_n_reject(3, GSM0808_CAUSE_MS_NOT_EQUIPPED);
+
+ /* Clean up the connection */
+ BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
+ f_expect_chan_rel(0, dt.rsl_chan_nr, expect_rll_rel_req := false);
+
+ setverdict(pass);
+}
+
+/* Check if we get SAPI N Reject on receipt of unexpected RLL ERROR INDication */
+testcase TC_rll_err_ind_sapi_n_reject() runs on test_CT {
+ var octetstring rnd_data := f_rnd_octstring(16);
+ var RSL_Message rx_rsl;
+ var DchanTuple dt;
+
+ f_init(1);
+
+ /* MS establishes a SAPI=0 link on DCCH */
+ dt := f_est_dchan(f_rnd_ra_cs(), 23, rnd_data);
+
+ /* MSC sends some data on (not yet established) SAPI=3 link */
+ BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSAP_DTAP(rnd_data, '03'O)));
+ /* BSC attempts to establish a SAPI=3 link on DCCH */
+ rx_rsl := f_exp_ipa_rx(0, tr_RSL_EST_REQ(dt.rsl_chan_nr, tr_RslLinkID_DCCH(3)));
+
+ /* BTS sends unexpected ERROR INDication on SAPI=3 */
+ f_ipa_tx(0, ts_RSL_ERROR_IND(dt.rsl_chan_nr, ts_RslLinkID_DCCH(3), ''O));
+ /* We expect to receive BSSMAP SAPI N Reject message from the BSC */
+ f_exp_sapi_n_reject(3, GSM0808_CAUSE_BSS_NOT_EQUIPPED);
+
+ /* Clean up the connection */
+ BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
+ f_expect_chan_rel(0, dt.rsl_chan_nr, expect_rll_rel_req := false);
+
+ setverdict(pass);
+}
+
+/* Check if we get SAPI N Reject due to a SAPI=3 link establishment timeout */
+testcase TC_rll_timeout_sapi_n_reject() runs on test_CT {
+ var octetstring rnd_data := f_rnd_octstring(16);
+ var RSL_Message rx_rsl;
+ var DchanTuple dt;
+
+ f_init(1);
+
+ /* MS establishes a SAPI=0 link on DCCH */
+ dt := f_est_dchan(f_rnd_ra_cs(), 23, rnd_data);
+
+ /* MSC sends some data on (not yet established) SAPI=3 link */
+ BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSAP_DTAP(rnd_data, '03'O)));
+ /* BSC attempts to establish a SAPI=3 link on DCCH */
+ rx_rsl := f_exp_ipa_rx(0, tr_RSL_EST_REQ(dt.rsl_chan_nr, tr_RslLinkID_DCCH(3)));
+
+ /* MS does not respond, so the link establishment timeout triggers SAPI N Reject */
+ f_exp_sapi_n_reject(3, GSM0808_CAUSE_BSS_NOT_EQUIPPED, T_val := 8.0);
+
+ /* Clean up the connection */
+ BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
+ f_expect_chan_rel(0, dt.rsl_chan_nr, expect_rll_rel_req := false);
+
+ setverdict(pass);
+}
+
+testcase TC_si_default() runs on test_CT {
+ f_init(0);
+ f_init_bts_and_check_sysinfo(0, expect_si := SystemInformationConfig_default);
+}
+
+/* We're testing SI2quater with lists of EARFCNs. Instead of just incrementing EARFCNs, also pick some from the edges of
+ * the entire value range. This function provides the same EARFCN numbers for the same earfcn_index */
+private function f_test_si2quater_earfcn_by_idx(integer earfcn_index) return uint16_t
+{
+ select (earfcn_index) {
+ case (0) {
+ /* E-ARFCN 111 is already added in the osmo-bsc.cfg */
+ return 111;
+ }
+ case (1) {
+ return 1;
+ }
+ case (2) {
+ return 0;
+ }
+ case (3) {
+ return 65535;
+ }
+ case else {
+ return 23 * (earfcn_index - 3);
+ }
+ }
+}
+
+function f_test_si2quater(integer total_earfcns, template SystemInformationConfig expect_si,
+ template CellSelIndValue expect_cells := omit) runs on test_CT {
+
+ f_init(0);
+
+ /* E-ARFCN 111 is already added in the osmo-bsc.cfg, so only add more arfcns if total_earfcns > 1 */
+ for (var integer i := 1; i < total_earfcns; i := i + 1) {
+ f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list add earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))
+ & " thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3"});
+ }
+
+ f_init_bts_and_check_sysinfo(0, expect_si := expect_si);
+
+ f_init(1);
+
+ if (not istemplatekind(expect_cells, "omit")) {
+ /* Also check that RR Channel Release contains these EARFCNs.
+ * (copied code from TC_chan_rel_hard_clear_csfb) */
+ var BSSAP_N_DATA_ind rx_di;
+ var DchanTuple dt;
+
+ dt := f_est_dchan('23'O, 23, '00010203040506'O);
+
+ /* Instruct BSC to clear channel */
+ var BssmapCause cause := 0;
+ BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ts_BSSMAP_ClearCommandCSFB(cause)));
+
+ /* expect Clear Complete from BSC on A */
+ BSSAP.receive(tr_BSSAP_DATA_ind(dt.sccp_conn_id, tr_BSSMAP_ClearComplete)) {
+ /* release the SCCP connection */
+ BSSAP.send(ts_BSSAP_DISC_req(dt.sccp_conn_id, 0));
+ }
+
+ f_expect_chan_rel(0, dt.rsl_chan_nr, expect_rll_rel_req := false, is_csfb := true,
+ csfb_expect_cells := expect_cells);
+ }
+
+ for (var integer i := 1; i < total_earfcns; i := i + 1) {
+ f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list del earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))});
+ }
+}
+
+private function f_tr_si2quater_earfcns(integer count) return template SI2quaterRestOctetsList
+{
+ var template SI2quaterRestOctetsList si2quater := {};
+ var integer si2quater_count := (count + 2) / 3;
+
+ for (var integer i := 0; i < count; i := i + 1) {
+ var integer earfcn := f_test_si2quater_earfcn_by_idx(i);
+ var integer index := i / 3;
+ var integer earfcn_index := i mod 3;
+ if (index >= lengthof(si2quater)) {
+ si2quater[index] := tr_SI2quaterRestOctets_EUTRAN(index := index, count := si2quater_count - 1);
+ }
+ si2quater[index].rel_additions.rel5.rel6.rel7.rel8.prio_eutran_params_desc.desc.eutran_params_desc.desc.repeated_neigh_cells[0].cell_desc_list[earfcn_index] := tr_EUTRAN_CellDesc_default(e_arfcn := earfcn);
+ }
+
+ return si2quater;
+}
+
+private function f_tr_rr_chan_rel_earfcns(integer count) return template CellSelIndValue
+{
+ var template CellSelIndValue_EUTRAN_Descrs cells := {};
+
+ /* the lte neighbors must match the config & vty to pass this test */
+ for (var integer i := 0; i < count; i := i + 1) {
+ var integer earfcn := f_test_si2quater_earfcn_by_idx(i);
+ cells[i] := tr_CellSelIndValue_EUTRAN_Descr(earfcn, '1'B, 3);
+ }
+
+ return tr_CellSelIndValue_EUTRAN(cells);
+}
+
+private function f_tc_si2quater_n_earfcns(integer n) runs on test_CT
+{
+ var template SystemInformationConfig sic := SystemInformationConfig_default;
+ sic.si2quater := f_tr_si2quater_earfcns(n);
+ var template CellSelIndValue cells := f_tr_rr_chan_rel_earfcns(n);
+ f_test_si2quater(n, sic, cells);
+}
+
+testcase TC_si2quater_2_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(2);
+}
+
+testcase TC_si2quater_3_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(3);
+}
+
+testcase TC_si2quater_4_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(4);
+}
+
+testcase TC_si2quater_5_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(5);
+}
+
+testcase TC_si2quater_6_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(6);
+}
+
+testcase TC_si2quater_12_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(12);
+}
+
+testcase TC_si2quater_23_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(23);
+}
+
+testcase TC_si2quater_32_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(32);
+}
+
+testcase TC_si2quater_33_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(33);
+}
+
+testcase TC_si2quater_42_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(42);
+}
+
+testcase TC_si2quater_48_earfcns() runs on test_CT {
+ f_tc_si2quater_n_earfcns(48);
+}
+
+/* verify the VTY error response when adding too many EARFCNs, and showing that osmo-bsc still sends 16 SI2quater with
+ * 48 EARFCNs. */
+testcase TC_si2quater_49_earfcns() runs on test_CT {
+ var template SystemInformationConfig sic := SystemInformationConfig_default;
+ sic.si2quater := f_tr_si2quater_earfcns(48); /* 48, not 49! */
+ f_init(0);
+
+ for (var integer i := 1; i < 48; i := i + 1) {
+ f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list add earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))
+ & " thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3"});
+ }
+
+ /* The 49th EARFCN no longer fits, expect VTY error */
+ f_vty_enter_cfg_bts(BSCVTY, 0);
+ var charstring vty_error;
+ vty_error := f_vty_transceive_ret(BSCVTY,
+ "si2quater neighbor-list add earfcn 70 thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3")
+ f_vty_transceive(BSCVTY, "end");
+
+ if (f_strstr(vty_error, "Unable to add ARFCN 70") >= 0) {
+ log("Got expected VTY error: ", vty_error);
+ setverdict(pass);
+ } else {
+ setverdict(fail, "Expected the 49th EUTRAN ARFCN to be rejected by vty config, got: ", vty_error);
+ }
+
+ f_init_bts_and_check_sysinfo(0, expect_si := sic);
+
+ for (var integer i := 1; i < 48; i := i + 1) {
+ f_bts_0_cfg(BSCVTY, {"si2quater neighbor-list del earfcn " & int2str(f_test_si2quater_earfcn_by_idx(i))});
+ }
+}
+
+private function f_acc09_count_allowed(AccessControlClass acc) return uint8_t
+{
+ var uint8_t count := 0;
+ for (var integer i := 5; i < 16; i := i + 1) {
+ if (acc[i] == '0'B) { /* the list marks barred, we count allowed */
+ count := count + 1;
+ }
+ }
+ return count;
+}
+
+private function f_recv_next_si1(integer rsl_idx := 0) runs on test_CT return SystemInformationType1
+{
+ var ASP_RSL_Unitdata rx_rsl_ud;
+ var SystemInformationType1 last_si1;
+
+ timer T := 30.0;
+ T.start;
+ alt {
+ [] IPA_RSL[rsl_idx].receive(tr_ASP_RSL_UD((tr_RSL_NO_BCCH_INFO,
+ tr_RSL_BCCH_INFO,
+ tr_RSL_NO_SACCH_FILL,
+ tr_RSL_SACCH_FILL))
+ ) -> value rx_rsl_ud {
+ f_sysinfo_seen(rsl_idx, rx_rsl_ud.rsl);
+ if (g_system_information[rsl_idx].si1 == omit) {
+ repeat;
+ }
+ last_si1 := g_system_information[rsl_idx].si1;
+ g_system_information[rsl_idx].si1 := omit;
+ T.stop;
+ }
+ [] T.timeout { setverdict(fail, "Timeout receiving next SI1"); }
+ }
+ return last_si1;
+}
+
+/* verify ACC rotate feature */
+testcase TC_si_acc_rotate() runs on test_CT {
+ var template SystemInformationConfig sic := SystemInformationConfig_default;
+ var SystemInformationType1 last_si1;
+ var AccessControlClass acc;
+ var uint8_t count;
+ var integer times_allowed[10] := { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ f_init(0, guard_timeout := 60.0);
+
+ f_bts_0_cfg(BSCVTY, {"rach access-control-class 5 barred",
+ "access-control-class-rotate 3",
+ "access-control-class-rotate-quantum 1"});
+
+ /* Init and get first sysinfo */
+ f_init_bts_and_check_sysinfo(0, expect_si := ?);
+
+ for (var integer i:= 0; i < 20; i := i + 1) {
+ last_si1 := f_recv_next_si1(0);
+ acc := last_si1.rach_control.acc;
+ count := f_acc09_count_allowed(acc);
+ log("RSL: GOT SI1 ACC len=", count, ": ", acc);
+
+ if (count != 3) {
+ log("RSL: EXPECTED SI ACC len=3");
+ setverdict(fail, "received SI does not match expectations");
+ break;
+ }
+
+ for (var integer j := 0; j < 10; j := j + 1) {
+ if (acc[16 - 1 - j] == '0'B) { /* the list marks barred, we count allowed */
+ times_allowed[j] := times_allowed[j] + 1;
+ }
+ }
+ }
+
+ for (var integer j := 0; j < 10; j := j + 1) {
+ log("ACC", j, " allowed ", times_allowed[j], " times" );
+ if (j != 5 and times_allowed[j] < 3) {
+ setverdict(fail, "ACC", j, " ERROR: allowed ", times_allowed[j], " < 1 times");
+ } else if (j == 5 and times_allowed[j] > 0) {
+ setverdict(fail, "ACC", j, " ERROR: allowed ", times_allowed[j], " > 0 times");
+ }
+ }
+
+ f_bts_0_cfg(BSCVTY, {"access-control-class-rotate 10",
+ "rach access-control-class 5 allowed"});
+}
+
+/* verify ACC startup ramp+rotate feature */
+testcase TC_si_acc_ramp_rotate() runs on test_CT {
+ var template SystemInformationConfig sic := SystemInformationConfig_default;
+ var SystemInformationType1 last_si1;
+ var AccessControlClass acc;
+ var ASP_RSL_Unitdata rx_rsl_ud;
+ var uint8_t count;
+ var uint8_t prev_count;
+ var integer times_allowed[10] := { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ f_init(0, guard_timeout := 80.0);
+
+ f_bts_0_cfg(BSCVTY, {"rach access-control-class 4 barred",
+ "access-control-class-rotate 0",
+ "access-control-class-rotate-quantum 1",
+ "access-control-class-ramping",
+ "access-control-class-ramping-step-interval 5",
+ "access-control-class-ramping-step-size 5"});
+
+ /* Init and get first sysinfo */
+ f_init_bts_and_check_sysinfo(0, expect_si := ?);
+ last_si1 := g_system_information[0].si1;
+ acc := last_si1.rach_control.acc;
+ count := f_acc09_count_allowed(acc);
+ /* Adm subset size was set to 0 above, so wait until all ACC are barred */
+ while (count > 0) {
+ last_si1 := f_recv_next_si1(0);
+ acc := last_si1.rach_control.acc;
+ count := f_acc09_count_allowed(acc);
+ log("RSL: wait len()=0: GOT SI1 ACC len=", count, ": ", acc);
+ }
+
+ /* Increase adm subset size, we should see ramping start up */
+ f_bts_0_cfg(BSCVTY, {"access-control-class-rotate 10"});
+ prev_count := 0;
+ while (true) {
+ last_si1 := f_recv_next_si1(0);
+ acc := last_si1.rach_control.acc;
+ count := f_acc09_count_allowed(acc);
+ log("RSL: GOT SI1 ACC len=", count, ": ", acc);
+
+ if (prev_count > count) {
+ setverdict(fail, "ACC allowed count dropped while expecting grow: ", prev_count, " -> ", count);
+ break;
+ }
+
+ if (count == 9) {
+ break; /* Maximum reached (10 - 1 perm barred), done here */
+ }
+
+ prev_count := count;
+ }
+
+ setverdict(pass);
+
+ f_bts_0_cfg(BSCVTY, {"access-control-class-rotate 10",
+ "rach access-control-class 4 allowed",
+ "no access-control-class-ramping"});
+}
testcase TC_ctrl_msc_connection_status() runs on test_CT {
var charstring ctrl_resp;
@@ -1237,10 +2537,6 @@ testcase TC_ctrl_location() runs on test_CT {
setverdict(pass);
}
-function f_bssap_tx_ud(template PDU_BSSAP bssap) runs on test_CT {
- BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, bssap));
-}
-
/***********************************************************************
* Paging Testing
@@ -1271,11 +2567,10 @@ private function f_pageing_helper(hexstring imsi,
template BSSMAP_FIELD_CellIdentificationList cid_list,
BtsIdList bts_ids := { 0 },
template RSL_ChanNeeded rsl_chneed := omit,
- template OCT4 tmsi := omit) runs on test_CT
+ template (omit) OCT4 tmsi := omit) runs on test_CT
{
var template BSSMAP_IE_ChannelNeeded bssmap_chneed;
- var MobileIdentity mi;
- var template octetstring id_enc; /* FIXME */
+ var template MobileIdentityV mi;
var RSL_Message rx_rsl;
var integer paging_group := hex2int(imsi[lengthof(imsi)-1]);
var integer i;
@@ -1294,19 +2589,17 @@ private function f_pageing_helper(hexstring imsi,
bssmap_chneed := omit;
}
- f_bssap_tx_ud(ts_BSSMAP_Paging(imsi, cid_list, tmsi, bssmap_chneed));
+ BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[0].sccp_addr_peer, g_bssap[0].sccp_addr_own,
+ ts_BSSMAP_Paging(imsi, cid_list, tmsi, bssmap_chneed)));
-/* FIXME: Disabled due to bugs in both GSM_RR_Types and MobileL3_CommonIE_Types IMSI encoder
- if (isvalue(tmsi)) {
- mi := valueof(t_Osmo_MI_TMSI(oct2int(valueof(tmsi))));
+ if (not istemplatekind(tmsi, "omit")) {
+ mi := t_MI_TMSI(tmsi);
} else {
- mi := valueof(ts_Osmo_MI_IMSI(imsi));
+ mi := tr_MI_IMSI(imsi);
}
- id_enc := enc_MobileIdentity(mi);
-*/
- id_enc := ?;
+
for (i := 0; i < sizeof(bts_ids); i := i + 1) {
- rx_rsl := f_exp_ipa_rx(bts_ids[i], tr_RSL_PAGING_CMD(id_enc));
+ rx_rsl := f_exp_ipa_rx(bts_ids[i], tr_RSL_PAGING_CMD(mi));
/* check channel type, paging group */
if (rx_rsl.ies[1].body.paging_group != paging_group) {
setverdict(fail, "Paging for wrong paging group");
@@ -1325,7 +2618,7 @@ private function f_pageing_helper(hexstring imsi,
}
T.start;
alt {
- [] IPA_RSL[i].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(id_enc))) {
+ [] IPA_RSL[i].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(mi))) {
setverdict(fail, "Paging on BTS ", i, " which is not part of ", bts_ids);
}
[] IPA_RSL[i].receive { repeat; }
@@ -1501,7 +2794,7 @@ testcase TC_paging_imsi_load() runs on test_CT {
T.start;
T_retrans.start;
alt {
- [] IPA_RSL[0].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
setverdict(fail, "Received PAGING after LOAD_IND(0)");
mtc.stop;
}
@@ -1566,9 +2859,9 @@ testcase TC_paging_imsi_a_reset() runs on test_CT {
f_pageing_helper('001010123456789'H, cid_list, c_BtsId_all);
/* Perform a BSSMAP Reset and wait for ACK */
- BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
+ BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap[0].sccp_addr_peer, g_bssap[0].sccp_addr_own, ts_BSSMAP_Reset(0, g_osmux_enabled)));
alt {
- [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) { }
+ [] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap[0].sccp_addr_own, g_bssap[0].sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) { }
[] BSSAP.receive { repeat; }
}
@@ -1584,15 +2877,15 @@ testcase TC_paging_imsi_a_reset() runs on test_CT {
/* Wait for 3 seconds if any more PAGING CMD are received on RSL */
T.start;
alt {
- [] IPA_RSL[0].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
setverdict(fail, "Received PAGING after A-RESET");
mtc.stop;
}
- [] IPA_RSL[1].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+ [] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
setverdict(fail, "Received PAGING after A-RESET");
mtc.stop;
}
- [] IPA_RSL[2].receive(tr_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0, tr_RSL_PAGING_CMD(?))) {
+ [] IPA_RSL[2].receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?))) {
setverdict(fail, "Received PAGING after A-RESET");
mtc.stop;
}
@@ -1684,7 +2977,7 @@ function f_ipa_unknown_unit_id(integer mp_bsc_ipa_port) runs on test_CT return b
/* wait for IPA OML link to connect and then disconnect */
T.start;
alt {
- [] IPA_RSL[0].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_DOWN}) {
+ [] IPA_RSL[0].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN)) {
T.stop;
return true;
}
@@ -1727,8 +3020,8 @@ import from MSC_ConnectionHandler all;
type function void_fn(charstring id) runs on MSC_ConnHdlr;
/* helper function to create and connect a MSC_ConnHdlr component */
-private function f_connect_handler(inout MSC_ConnHdlr vc_conn) runs on test_CT {
- connect(vc_conn:RAN, g_bssap.vc_RAN:PROC);
+private function f_connect_handler(inout MSC_ConnHdlr vc_conn, integer bssap_idx := 0) runs on test_CT {
+ connect(vc_conn:RAN, g_bssap[bssap_idx].vc_RAN:PROC);
connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC);
connect(vc_conn:RSL, bts[0].rsl.vc_RSL:CLIENT_PT);
connect(vc_conn:RSL_PROC, bts[0].rsl.vc_RSL:RSL_PROC);
@@ -1740,17 +3033,22 @@ private function f_connect_handler(inout MSC_ConnHdlr vc_conn) runs on test_CT {
connect(vc_conn:RSL2, bts[2].rsl.vc_RSL:CLIENT_PT);
connect(vc_conn:RSL2_PROC, bts[2].rsl.vc_RSL:RSL_PROC);
}
- connect(vc_conn:BSSAP, g_bssap.vc_RAN:CLIENT);
+ connect(vc_conn:BSSAP, g_bssap[bssap_idx].vc_RAN:CLIENT);
connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT);
connect(vc_conn:MGCP_MULTI, vc_MGCP:MGCP_CLIENT_MULTI);
+ connect(vc_conn:STATSD_PROC, vc_STATSD:STATSD_PROC);
}
function f_start_handler(void_fn fn, template (omit) TestHdlrParams pars := omit)
runs on test_CT return MSC_ConnHdlr {
var charstring id := testcasename();
var MSC_ConnHdlr vc_conn;
+ var integer bssap_idx := 0;
+ if (isvalue(pars)) {
+ bssap_idx := valueof(pars).mscpool.bssap_idx;
+ }
vc_conn := MSC_ConnHdlr.create(id);
- f_connect_handler(vc_conn);
+ f_connect_handler(vc_conn, bssap_idx);
vc_conn.start(f_handler_init(fn, id, pars));
return vc_conn;
}
@@ -1807,6 +3105,25 @@ testcase TC_ciph_mode_a5_3() runs on test_CT {
vc_conn.done;
}
+/* establish initial channel, enable ciphering followed by assignment to ciphered channel */
+private function f_tc_assignment_aoip_tla_v6(charstring id) runs on MSC_ConnHdlr {
+ var template PDU_BSSAP exp_compl := f_gen_exp_compl();
+ var PDU_BSSAP ass_cmd := f_gen_ass_req(aoip_tla := "::3");
+ ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelType);
+ ass_cmd.pdu.bssmap.assignmentRequest.codecList := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
+
+ f_establish_fully(ass_cmd, exp_compl);
+}
+testcase TC_assignment_aoip_tla_v6() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+
+ f_init(1, true);
+ f_sleep(1.0);
+ vc_conn := f_start_handler(refers(f_tc_assignment_aoip_tla_v6), pars);
+ vc_conn.done;
+}
+
/* establish initial channel, enable ciphering followed by assignment to ciphered channel */
private function f_tc_assignment_fr_a5(charstring id) runs on MSC_ConnHdlr {
@@ -1900,7 +3217,15 @@ private function f_tc_assignment_sign(charstring id) runs on MSC_ConnHdlr {
var template PDU_BSSAP exp_compl := tr_BSSMAP_AssignmentComplete(omit, omit);
var PDU_BSSAP ass_cmd := f_gen_ass_req();
ass_cmd.pdu.bssmap.assignmentRequest.channelType := valueof(ts_BSSMAP_IE_ChannelTypeSIGNAL);
+
+ f_statsd_reset();
f_establish_fully(ass_cmd, exp_compl);
+
+ var StatsDExpects expect := {
+ { name := "TTCN3.bsc.0.assignment.attempted", mtype := "c", min := 1, max := 1},
+ { name := "TTCN3.bsc.0.assignment.completed", mtype := "c", min := 1, max := 1}
+ };
+ f_statsd_expect(expect);
}
testcase TC_assignment_sign() runs on test_CT {
@@ -2046,7 +3371,7 @@ private function f_TC_assignment_codec(charstring id) runs on MSC_ConnHdlr {
var template PDU_BSSAP exp_compl := f_gen_exp_compl(g_pars.use_osmux);
/* puzzle together the ASSIGNMENT REQ for given codec[s] */
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) {
ass_cmd.pdu.bssmap.assignmentRequest.codecList := g_pars.ass_codec_list;
exp_compl.pdu.bssmap.assignmentComplete.speechCodec.codecElements[0] :=
g_pars.ass_codec_list.codecElements[0];
@@ -2101,7 +3426,7 @@ private function f_TC_assignment_codec_fail(charstring id) runs on MSC_ConnHdlr
var template PDU_BSSAP exp_fail := tr_BSSMAP_AssignmentFail;
/* puzzle together the ASSIGNMENT REQ for given codec[s] */
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) {
ass_cmd.pdu.bssmap.assignmentRequest.codecList := g_pars.ass_codec_list;
}
ass_cmd.pdu.bssmap.assignmentRequest.channelType :=
@@ -2715,6 +4040,33 @@ testcase TC_classmark() runs on test_CT {
vc_conn.done;
}
+/* Send a CommonID from the simulated MSC and verify that the information is used to
+ * fill BSC-internal data structures (specifically, bsc_subscr associated with subscr_conn) */
+private function f_tc_common_id(charstring id) runs on MSC_ConnHdlr {
+ g_pars := f_gen_test_hdlr_pars();
+ f_MscConnHdlr_init_vty();
+
+ f_create_chan_and_exp();
+ /* we should now have a COMPL_L3 at the MSC */
+ BSSAP.receive(tr_BSSMAP_ComplL3);
+
+ /* Send CommonID */
+ BSSAP.send(ts_BSSMAP_CommonId(g_pars.imsi));
+
+ /* Use VTY to verify that the IMSI of the subscr_conn is set */
+ var charstring regex := "*(IMSI: " & hex2str(g_pars.imsi) & ")*";
+ f_vty_transceive_match_regexp_retry(BSCVTY, "show conns", regex, 0, 4, 1.0);
+
+ setverdict(pass);
+}
+testcase TC_common_id() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ f_init(1, true);
+ f_sleep(1.0);
+ vc_conn := f_start_handler(refers(f_tc_common_id));
+ vc_conn.done;
+}
+
private function f_est_single_l3(template PDU_ML3_MS_NW l3) runs on MSC_ConnHdlr {
g_pars := f_gen_test_hdlr_pars();
f_create_chan_and_exp();
@@ -2835,8 +4187,10 @@ runs on test_CT {
}
/* execute a "bts <0-255> trx <0-255> timeslot <0-7> sub-slot <0-7>" command on given Dchan */
-private function f_vty_ss_action(charstring suffix, integer bts_nr, integer trx_nr, RslChannelNr chan_nr)
-runs on MSC_ConnHdlr {
+private function f_vty_ss_action(TELNETasp_PT pt, charstring suffix,
+ uint8_t bts_nr, uint8_t trx_nr,
+ in RslChannelNr chan_nr)
+{
/* FIXME: resolve those from component-global state */
var integer ts_nr := chan_nr.tn;
var integer ss_nr;
@@ -2855,7 +4209,7 @@ runs on MSC_ConnHdlr {
var charstring cmd := "bts "&int2str(bts_nr)&" trx "&int2str(trx_nr)&
" timeslot "&int2str(ts_nr)&" sub-slot "&int2str(ss_nr)&" ";
- f_vty_transceive(BSCVTY, cmd & suffix);
+ f_vty_transceive(pt, cmd & suffix);
}
/* Even though the VTY command to trigger handover takes a new BTS number as argument, behind the scenes osmo-bsc always
@@ -2863,10 +4217,10 @@ runs on MSC_ConnHdlr {
* ident key (ARFCN + BSIC) in the struct passed on to handover_request(). handover_start() then resolves that to a
* viable actual neighbor cell. So from the internal osmo-bsc perspective, we always request handover to an ARFCN + BSIC
* pair, not really to a specific BTS number. */
-private function f_vty_handover(integer bts_nr, integer trx_nr, RslChannelNr chan_nr,
- integer new_bts_nr)
-runs on MSC_ConnHdlr {
- f_vty_ss_action("handover " & int2str(new_bts_nr), bts_nr, trx_nr, chan_nr);
+private function f_vty_handover(TELNETasp_PT pt, uint8_t bts_nr, uint8_t trx_nr,
+ in RslChannelNr chan_nr, uint8_t new_bts_nr)
+{
+ f_vty_ss_action(pt, "handover " & int2str(new_bts_nr), bts_nr, trx_nr, chan_nr);
}
/* intra-BSC hand-over between BTS0 and BTS1 */
@@ -2880,7 +4234,7 @@ private function f_tc_ho_int(charstring id) runs on MSC_ConnHdlr {
ass_cmd.pdu.bssmap.assignmentRequest.codecList := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
f_establish_fully(ass_cmd, exp_compl);
- f_bts_0_cfg({"neighbor bts 1"});
+ f_bts_0_cfg(BSCVTY, {"neighbor bts 1"});
var HandoverState hs := {
rr_ho_cmpl_seen := false,
@@ -2888,7 +4242,7 @@ private function f_tc_ho_int(charstring id) runs on MSC_ConnHdlr {
old_chan_nr := -
};
/* issue hand-over command on VTY */
- f_vty_handover(0, 0, g_chan_nr, 1);
+ f_vty_handover(BSCVTY, 0, 0, g_chan_nr, 1);
/* temporarily suspend DChan processing on BTS1 to avoid race with RSLEM_register */
f_rslem_suspend(RSL1_PROC);
@@ -2915,8 +4269,21 @@ testcase TC_ho_int() runs on test_CT {
var MSC_ConnHdlr vc_conn;
f_init(2, true);
f_sleep(1.0);
+
+ f_ctrs_bsc_and_bts_init();
+
vc_conn := f_start_handler(refers(f_tc_ho_int));
vc_conn.done;
+
+ /* from f_establish_fully() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+ /* from handover */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:completed");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:attempted");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:completed");
+ f_ctrs_bsc_and_bts_verify();
}
/* Expecting MGCP to DLCX the endpoint's two connections: towards BTS and towards MSC */
@@ -2962,7 +4329,7 @@ private function f_tc_ho_out_of_this_bsc(charstring id) runs on MSC_ConnHdlr {
var template PDU_BSSAP exp_compl := f_gen_exp_compl();
f_establish_fully(ass_req, exp_compl);
- f_bts_0_cfg({"neighbor lac 99 arfcn 123 bsic any"});
+ f_bts_0_cfg(BSCVTY, {"neighbor lac 99 arfcn 123 bsic any"});
f_vty_transceive(BSCVTY, "handover any to arfcn 123 bsic any");
BSSAP.receive(tr_BSSMAP_HandoverRequired);
@@ -3014,8 +4381,18 @@ testcase TC_ho_out_of_this_bsc() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+
vc_conn := f_start_handler(refers(f_tc_ho_out_of_this_bsc));
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:completed");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:completed");
+ f_ctrs_bsc_and_bts_verify();
}
/* BSC asks for inter-BSC HO, but the MSC decides that it won't happen and
@@ -3029,7 +4406,7 @@ private function f_tc_ho_out_fail_no_msc_response(charstring id) runs on MSC_Con
var template PDU_BSSAP exp_compl := f_gen_exp_compl();
f_establish_fully(ass_req, exp_compl);
- f_bts_0_cfg({"neighbor lac 99 arfcn 123 bsic any"});
+ f_bts_0_cfg(BSCVTY, {"neighbor lac 99 arfcn 123 bsic any"});
f_vty_transceive(BSCVTY, "handover any to arfcn 123 bsic any");
BSSAP.receive(tr_BSSMAP_HandoverRequired);
@@ -3061,8 +4438,18 @@ testcase TC_ho_out_fail_no_msc_response() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+
vc_conn := f_start_handler(refers(f_tc_ho_out_fail_no_msc_response));
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:timeout");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:timeout");
+ f_ctrs_bsc_and_bts_verify();
}
/* BSC asks for inter-BSC HO, receives BSSMAP Handover Command, but MS reports
@@ -3076,7 +4463,7 @@ private function f_tc_ho_out_fail_rr_ho_failure(charstring id) runs on MSC_ConnH
var template PDU_BSSAP exp_compl := f_gen_exp_compl();
f_establish_fully(ass_req, exp_compl);
- f_bts_0_cfg({"neighbor lac 99 arfcn 123 bsic any"});
+ f_bts_0_cfg(BSCVTY, {"neighbor lac 99 arfcn 123 bsic any"});
f_vty_transceive(BSCVTY, "handover any to arfcn 123 bsic any");
BSSAP.receive(tr_BSSMAP_HandoverRequired);
@@ -3145,8 +4532,18 @@ testcase TC_ho_out_fail_rr_ho_failure() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+
vc_conn := f_start_handler(refers(f_tc_ho_out_fail_rr_ho_failure));
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:failed");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:failed");
+ f_ctrs_bsc_and_bts_verify();
}
/* BSC asks for inter-BSC-out HO, receives BSSMAP Handover Command, but then no reply is received about HO outcome
@@ -3161,7 +4558,7 @@ private function f_tc_ho_out_fail_no_result_after_ho_cmd(charstring id) runs on
var template PDU_BSSAP exp_compl := f_gen_exp_compl();
f_establish_fully(ass_req, exp_compl);
- f_bts_0_cfg({"neighbor lac 99 arfcn 123 bsic any"});
+ f_bts_0_cfg(BSCVTY, {"neighbor lac 99 arfcn 123 bsic any"});
f_vty_transceive(BSCVTY, "handover any to arfcn 123 bsic any");
BSSAP.receive(tr_BSSMAP_HandoverRequired);
@@ -3232,8 +4629,18 @@ testcase TC_ho_out_fail_no_result_after_ho_cmd() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+
vc_conn := f_start_handler(refers(f_tc_ho_out_fail_no_result_after_ho_cmd));
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:timeout");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:timeout");
+ f_ctrs_bsc_and_bts_verify();
}
private function f_tc_ho_into_this_bsc(charstring id) runs on MSC_ConnHdlr {
@@ -3251,8 +4658,8 @@ private function f_tc_ho_into_this_bsc(charstring id) runs on MSC_ConnHdlr {
f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
activate(as_Media());
- BSSAP.send(ts_BSSAP_Conn_Req(g_pars.handover.sccp_addr_bsc, g_pars.handover.sccp_addr_msc,
- f_gen_handover_req()));
+ BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc,
+ f_gen_handover_req(aoip_tla := g_pars.host_aoip_tla)));
BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND);
/* The RSL Emulation magically accepts the Chan Activ behind the scenes. */
@@ -3299,18 +4706,36 @@ private function f_tc_ho_into_this_bsc(charstring id) runs on MSC_ConnHdlr {
BSSAP.receive(tr_BSSMAP_HandoverComplete);
setverdict(pass);
}
-testcase TC_ho_into_this_bsc() runs on test_CT {
+function f_tc_ho_into_this_bsc_main(TestHdlrParams pars) runs on test_CT {
var MSC_ConnHdlr vc_conn;
- var TestHdlrParams pars := f_gen_test_hdlr_pars();
f_init(1, true);
f_sleep(1.0);
- pars.handover.sccp_addr_msc := g_bssap.sccp_addr_own;
- pars.handover.sccp_addr_bsc := g_bssap.sccp_addr_peer;
+ f_ctrs_bsc_and_bts_init();
+
+ pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
+ pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
vc_conn := f_start_handler(refers(f_tc_ho_into_this_bsc), pars);
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:completed");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:completed");
+ f_ctrs_bsc_and_bts_verify();
+}
+
+testcase TC_ho_into_this_bsc() runs on test_CT {
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+ f_tc_ho_into_this_bsc_main(pars);
+}
+
+testcase TC_ho_into_this_bsc_tla_v6() runs on test_CT {
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+ pars.host_aoip_tla := "::6";
+ f_tc_ho_into_this_bsc_main(pars);
}
private function f_tc_ho_in_fail_msc_clears(charstring id) runs on MSC_ConnHdlr {
@@ -3323,7 +4748,7 @@ private function f_tc_ho_in_fail_msc_clears(charstring id) runs on MSC_ConnHdlr
f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
activate(as_Media());
- BSSAP.send(ts_BSSAP_Conn_Req(g_pars.handover.sccp_addr_bsc, g_pars.handover.sccp_addr_msc,
+ BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc,
f_gen_handover_req()));
BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND);
@@ -3379,11 +4804,19 @@ testcase TC_ho_in_fail_msc_clears() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
- pars.handover.sccp_addr_msc := g_bssap.sccp_addr_own;
- pars.handover.sccp_addr_bsc := g_bssap.sccp_addr_peer;
+ f_ctrs_bsc_and_bts_init();
+
+ pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
+ pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
vc_conn := f_start_handler(refers(f_tc_ho_in_fail_msc_clears), pars);
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:stopped");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:stopped");
+ f_ctrs_bsc_and_bts_verify();
}
private function f_tc_ho_in_fail_msc_clears_after_ho_detect(charstring id) runs on MSC_ConnHdlr {
@@ -3401,7 +4834,7 @@ private function f_tc_ho_in_fail_msc_clears_after_ho_detect(charstring id) runs
f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
activate(as_Media());
- BSSAP.send(ts_BSSAP_Conn_Req(g_pars.handover.sccp_addr_bsc, g_pars.handover.sccp_addr_msc,
+ BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc,
f_gen_handover_req()));
BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND);
@@ -3459,11 +4892,19 @@ testcase TC_ho_in_fail_msc_clears_after_ho_detect() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
- pars.handover.sccp_addr_msc := g_bssap.sccp_addr_own;
- pars.handover.sccp_addr_bsc := g_bssap.sccp_addr_peer;
+ f_ctrs_bsc_and_bts_init();
+
+ pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
+ pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
vc_conn := f_start_handler(refers(f_tc_ho_in_fail_msc_clears_after_ho_detect), pars);
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:stopped");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:stopped");
+ f_ctrs_bsc_and_bts_verify();
}
/* The new BSS's lchan times out before the MSC decides that handover failed. */
@@ -3477,7 +4918,7 @@ private function f_tc_ho_in_fail_no_detect(charstring id) runs on MSC_ConnHdlr {
f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
activate(as_Media());
- BSSAP.send(ts_BSSAP_Conn_Req(g_pars.handover.sccp_addr_bsc, g_pars.handover.sccp_addr_msc,
+ BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc,
f_gen_handover_req()));
BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND);
@@ -3540,11 +4981,19 @@ testcase TC_ho_in_fail_no_detect() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
- pars.handover.sccp_addr_msc := g_bssap.sccp_addr_own;
- pars.handover.sccp_addr_bsc := g_bssap.sccp_addr_peer;
+ f_ctrs_bsc_and_bts_init();
+
+ pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
+ pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
vc_conn := f_start_handler(refers(f_tc_ho_in_fail_no_detect), pars);
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:error");
+ f_ctrs_bsc_and_bts_verify();
}
/* Same as f_tc_ho_in_fail_no_detect, but MSC fails to send a Clear Command */
@@ -3558,7 +5007,7 @@ private function f_tc_ho_in_fail_no_detect2(charstring id) runs on MSC_ConnHdlr
f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
activate(as_Media());
- BSSAP.send(ts_BSSAP_Conn_Req(g_pars.handover.sccp_addr_bsc, g_pars.handover.sccp_addr_msc,
+ BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc,
f_gen_handover_req()));
BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND);
@@ -3611,22 +5060,39 @@ testcase TC_ho_in_fail_no_detect2() runs on test_CT {
f_init(1, true);
f_sleep(1.0);
- pars.handover.sccp_addr_msc := g_bssap.sccp_addr_own;
- pars.handover.sccp_addr_bsc := g_bssap.sccp_addr_peer;
+ f_ctrs_bsc_and_bts_init();
+
+ pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
+ pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
vc_conn := f_start_handler(refers(f_tc_ho_in_fail_no_detect2), pars);
vc_conn.done;
+
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_in:error");
+ f_ctrs_bsc_and_bts_verify();
}
type record of charstring Commands;
-private function f_bts_0_cfg(Commands cmds := {}) runs on MSC_ConnHdlr
+private function f_bts_0_cfg(TELNETasp_PT pt, Commands cmds := {})
{
- f_vty_enter_cfg_bts(BSCVTY, 0);
+ f_vty_enter_cfg_bts(pt, 0);
for (var integer i := 0; i < sizeof(cmds); i := i+1) {
- f_vty_transceive(BSCVTY, cmds[i]);
+ f_vty_transceive(pt, cmds[i]);
}
- f_vty_transceive(BSCVTY, "end");
+ f_vty_transceive(pt, "end");
+}
+
+private function f_cs7_inst_0_cfg(TELNETasp_PT pt, Commands cmds := {})
+{
+ f_vty_enter_cfg_cs7_inst(pt, 0);
+ for (var integer i := 0; i < sizeof(cmds); i := i+1) {
+ f_vty_transceive(pt, cmds[i]);
+ }
+ f_vty_transceive(pt, "end");
}
private function f_probe_for_handover(charstring log_label,
@@ -3636,6 +5102,11 @@ private function f_probe_for_handover(charstring log_label,
boolean is_inter_bsc_handover := false)
runs on MSC_ConnHdlr
{
+ /* We're going to thwart any and all handover attempts, just be ready to handle (and ignore) handover target
+ * lchans to be established on bts 1 or bts 2. */
+ f_rslem_suspend(RSL1_PROC);
+ f_rslem_suspend(RSL2_PROC);
+
var RSL_Message rsl;
var charstring log_msg := " (expecting handover)"
@@ -3645,11 +5116,6 @@ runs on MSC_ConnHdlr
log("f_probe_for_handover starting: " & log_label & ": " & log_descr & log_msg);
f_vty_transceive(BSCVTY, handover_vty_cmd);
- /* We're going to thwart any and all handover attempts, just be ready to handle (and ignore) handover target
- * lchans to be established on bts 1 or bts 2. */
- f_rslem_suspend(RSL1_PROC);
- f_rslem_suspend(RSL2_PROC);
-
timer T := 2.0;
T.start;
@@ -3771,7 +5237,7 @@ private function f_tc_ho_neighbor_config_1(charstring id) runs on MSC_ConnHdlr {
*/
log("f_tc_ho_neighbor_config: 1. No 'neighbor' config");
- f_bts_0_cfg({"no neighbors"});
+ f_bts_0_cfg(BSCVTY, {"no neighbors"});
f_probe_for_handover("1.a", "HO to bts 1 works, implicitly listed as neighbor (legacy behavior when none are configured)",
"handover any to arfcn 871 bsic 11",
true);
@@ -3788,6 +5254,43 @@ private function f_tc_ho_neighbor_config_1(charstring id) runs on MSC_ConnHdlr {
"handover any to arfcn 871 bsic 11",
true);
}
+testcase TC_ho_neighbor_config_1() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ f_init(3, true, guard_timeout := 60.0);
+ f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+ vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_1));
+ vc_conn.done;
+
+ /* f_tc_ho_neighbor_config_start() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+
+ /* 1.a */
+ /* "failed" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by sending a Handover Failure message. */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:failed");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:attempted");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:failed");
+
+ /* 1.b */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+
+ /* 1.c */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+
+ /* 1.d */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:failed");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:attempted");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:failed");
+
+ f_ctrs_bsc_and_bts_verify();
+}
+
private function f_tc_ho_neighbor_config_2(charstring id) runs on MSC_ConnHdlr {
f_tc_ho_neighbor_config_start();
@@ -3799,7 +5302,7 @@ private function f_tc_ho_neighbor_config_2(charstring id) runs on MSC_ConnHdlr {
*/
log("f_tc_ho_neighbor_config: 2. explicit local neighbor: 'neighbor bts 1'");
- f_bts_0_cfg({"neighbor bts 1"});
+ f_bts_0_cfg(BSCVTY, {"neighbor bts 1"});
f_sleep(0.5);
f_probe_for_handover("2.a", "HO to bts 1 works, explicitly listed as neighbor",
@@ -3810,6 +5313,33 @@ private function f_tc_ho_neighbor_config_2(charstring id) runs on MSC_ConnHdlr {
"handover any to arfcn 871 bsic 12",
false);
}
+testcase TC_ho_neighbor_config_2() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ f_init(3, true, guard_timeout := 50.0);
+ f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+ vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_2));
+ vc_conn.done;
+
+ /* f_tc_ho_neighbor_config_start() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+
+ /* 2.a */
+ /* "failed" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by sending a Handover Failure message. */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:failed");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:attempted");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:failed");
+
+ /* 2.b */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+
+ f_ctrs_bsc_and_bts_verify();
+}
+
private function f_tc_ho_neighbor_config_3(charstring id) runs on MSC_ConnHdlr {
f_tc_ho_neighbor_config_start();
@@ -3821,7 +5351,7 @@ private function f_tc_ho_neighbor_config_3(charstring id) runs on MSC_ConnHdlr {
*/
log("f_tc_ho_neighbor_config: 3. explicit local neighbor: 'neighbor bts 2'");
- f_bts_0_cfg({"no neighbors", "neighbor bts 2"});
+ f_bts_0_cfg(BSCVTY, {"no neighbors", "neighbor bts 2"});
f_sleep(0.5);
f_probe_for_handover("3.a", "HO to bts 1 doesn't work, not listed as neighbor",
@@ -3831,6 +5361,33 @@ private function f_tc_ho_neighbor_config_3(charstring id) runs on MSC_ConnHdlr {
"handover any to arfcn 871 bsic 12",
true);
}
+testcase TC_ho_neighbor_config_3() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ f_init(3, true, guard_timeout := 50.0);
+ f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+ vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_3));
+ vc_conn.done;
+
+ /* f_tc_ho_neighbor_config_start() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+
+ /* 3.a */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+
+ /* 3.b */
+ /* "failed" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by sending a Handover Failure message. */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:failed");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:attempted");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:failed");
+
+ f_ctrs_bsc_and_bts_verify();
+}
+
private function f_tc_ho_neighbor_config_4(charstring id) runs on MSC_ConnHdlr {
f_tc_ho_neighbor_config_start();
@@ -3842,7 +5399,7 @@ private function f_tc_ho_neighbor_config_4(charstring id) runs on MSC_ConnHdlr {
*/
log("f_tc_ho_neighbor_config: 4. explicit remote neighbor: 'neighbor lac 99 arfcn 123 bsic 45'");
- f_bts_0_cfg({"no neighbors", "neighbor lac 99 arfcn 123 bsic 45"});
+ f_bts_0_cfg(BSCVTY, {"no neighbors", "neighbor lac 99 arfcn 123 bsic 45"});
f_sleep(0.5);
f_probe_for_handover("4.a", "HO to bts 1 doesn't work, not listed as neighbor",
@@ -3855,6 +5412,37 @@ private function f_tc_ho_neighbor_config_4(charstring id) runs on MSC_ConnHdlr {
"handover any to arfcn 123 bsic 45",
true, true);
}
+testcase TC_ho_neighbor_config_4() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ f_init(3, true, guard_timeout := 50.0);
+ f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+ vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_4));
+ vc_conn.done;
+
+ /* f_tc_ho_neighbor_config_start() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+
+ /* 4.a */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+
+ /* 4.b */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+
+ /* 4.c */
+ /* "timeout" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by timing out after the Handover Required message */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:timeout");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:timeout");
+
+ f_ctrs_bsc_and_bts_verify();
+}
+
private function f_tc_ho_neighbor_config_5(charstring id) runs on MSC_ConnHdlr {
f_tc_ho_neighbor_config_start();
@@ -3866,13 +5454,36 @@ private function f_tc_ho_neighbor_config_5(charstring id) runs on MSC_ConnHdlr {
*/
log("f_tc_ho_neighbor_config: 5. explicit remote neighbor re-using ARFCN+BSIC: 'neighbor lac 99 arfcn 871 bsic 12'");
- f_bts_0_cfg({"no neighbors", "neighbor lac 99 arfcn 871 bsic 12"});
+ f_bts_0_cfg(BSCVTY, {"no neighbors", "neighbor lac 99 arfcn 871 bsic 12"});
f_sleep(0.5);
f_probe_for_handover("5.a", "HO to 871-12 triggers inter-BSC HO (ignoring local cells with same ARFCN+BSIC)",
"handover any to arfcn 871 bsic 12",
true, true);
}
+testcase TC_ho_neighbor_config_5() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ f_init(3, true);
+ f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+ vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_5));
+ vc_conn.done;
+
+ /* f_tc_ho_neighbor_config_start() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+
+ /* 5 */
+ /* "timeout" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by timing out after the Handover Required message */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:timeout");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:timeout");
+
+ f_ctrs_bsc_and_bts_verify();
+}
+
private function f_tc_ho_neighbor_config_6(charstring id) runs on MSC_ConnHdlr {
f_tc_ho_neighbor_config_start();
@@ -3885,13 +5496,34 @@ private function f_tc_ho_neighbor_config_6(charstring id) runs on MSC_ConnHdlr {
log("f_tc_ho_neighbor_config: 6. config error: explicit local and remote neighbors with ambiguous ARFCN+BSIC:"
& " 'neighbor bts 2; neighbor lac 99 arfcn 871 bsic 12'");
- f_bts_0_cfg({"no neighbors", "neighbor bts 2", "neighbor lac 99 arfcn 871 bsic 12"});
+ f_bts_0_cfg(BSCVTY, {"no neighbors", "neighbor bts 2", "neighbor lac 99 arfcn 871 bsic 12"});
f_sleep(0.5);
f_probe_for_handover("6.a", "HO to 871-12 is ambiguous = error",
"handover any to arfcn 871 bsic 12",
false);
}
+testcase TC_ho_neighbor_config_6() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ f_init(3, true);
+ f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
+ vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_6));
+ vc_conn.done;
+
+ /* f_tc_ho_neighbor_config_start() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+
+ /* 6.a */
+ /* "timeout" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by timing out after the Handover Required message */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:error");
+
+ f_ctrs_bsc_and_bts_verify();
+}
+
private function f_tc_ho_neighbor_config_7(charstring id) runs on MSC_ConnHdlr {
f_tc_ho_neighbor_config_start();
@@ -3904,7 +5536,7 @@ private function f_tc_ho_neighbor_config_7(charstring id) runs on MSC_ConnHdlr {
log("f_tc_ho_neighbor_config: 7. explicit local and remote neighbors:"
& " 'neighbor bts 2; neighbor lac 99 arfcn 123 bsic 45'");
- f_bts_0_cfg({"no neighbors", "neighbor bts 2", "neighbor lac 99 arfcn 123 bsic 45"});
+ f_bts_0_cfg(BSCVTY, {"no neighbors", "neighbor bts 2", "neighbor lac 99 arfcn 123 bsic 45"});
f_sleep(0.5);
f_probe_for_handover("7.a", "HO to 871-12 does HO to bts 2",
@@ -3914,55 +5546,35 @@ private function f_tc_ho_neighbor_config_7(charstring id) runs on MSC_ConnHdlr {
"handover any to arfcn 123 bsic 45",
true, true);
}
-
-testcase TC_ho_neighbor_config_1() runs on test_CT {
- var MSC_ConnHdlr vc_conn;
- f_init(3, true);
- f_sleep(1.0);
- vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_1));
- vc_conn.done;
-}
-testcase TC_ho_neighbor_config_2() runs on test_CT {
- var MSC_ConnHdlr vc_conn;
- f_init(3, true);
- f_sleep(1.0);
- vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_2));
- vc_conn.done;
-}
-testcase TC_ho_neighbor_config_3() runs on test_CT {
- var MSC_ConnHdlr vc_conn;
- f_init(3, true);
- f_sleep(1.0);
- vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_3));
- vc_conn.done;
-}
-testcase TC_ho_neighbor_config_4() runs on test_CT {
- var MSC_ConnHdlr vc_conn;
- f_init(3, true);
- f_sleep(1.0);
- vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_4));
- vc_conn.done;
-}
-testcase TC_ho_neighbor_config_5() runs on test_CT {
- var MSC_ConnHdlr vc_conn;
- f_init(3, true);
- f_sleep(1.0);
- vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_5));
- vc_conn.done;
-}
-testcase TC_ho_neighbor_config_6() runs on test_CT {
- var MSC_ConnHdlr vc_conn;
- f_init(3, true);
- f_sleep(1.0);
- vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_6));
- vc_conn.done;
-}
testcase TC_ho_neighbor_config_7() runs on test_CT {
var MSC_ConnHdlr vc_conn;
- f_init(3, true);
+ f_init(3, true, guard_timeout := 50.0);
f_sleep(1.0);
+ f_ctrs_bsc_and_bts_init();
vc_conn := f_start_handler(refers(f_tc_ho_neighbor_config_7));
vc_conn.done;
+
+ /* f_tc_ho_neighbor_config_start() */
+ f_ctrs_bsc_and_bts_add(0, "assignment:attempted");
+ f_ctrs_bsc_and_bts_add(0, "assignment:completed");
+
+ /* 7.a */
+ /* "failed" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by sending a Handover Failure message. */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:failed");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:attempted");
+ f_ctrs_bsc_and_bts_add(0, "intra_bsc_ho:failed");
+
+ /* 7.b */
+ /* "timeout" means a handover was triggered and started (which is all this test aims for) and the test ended the
+ * handover quickly by timing out after the Handover Required message */
+ f_ctrs_bsc_and_bts_add(0, "handover:attempted");
+ f_ctrs_bsc_and_bts_add(0, "handover:timeout");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:attempted");
+ f_ctrs_bsc_and_bts_add(0, "interbsc_ho_out:timeout");
+
+ f_ctrs_bsc_and_bts_verify();
}
/* OS#3041: Open and close N connections in a normal fashion, and expect no
@@ -4369,6 +5981,1394 @@ testcase TC_chopped_ipa_payload() runs on test_CT {
}
}
+/* Verify the BSC sends the MS Power Parameters IE during CHAN ACT to make sure
+ the BTS does autonomous MS power control loop */
+testcase TC_assignment_verify_ms_power_params_ie() runs on test_CT {
+ var MSC_ConnHdlr vc_conn;
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+ //pars.encr := valueof(t_EncrParams('01'O, f_rnd_octstring(8)));
+ pars.exp_ms_power_params := true;
+
+ f_init(1, true);
+ f_sleep(1.0);
+ vc_conn := f_start_handler(refers(f_tc_assignment_fr_a5), pars);
+ vc_conn.done;
+}
+
+/***********************************************************************
+ * MSC Pooling
+ ***********************************************************************/
+
+function f_tmsi_nri(integer nri_v, octetstring base_tmsi := '42000023'O, integer nri_bitlen := 10) return octetstring
+{
+ return int2oct( oct2int(base_tmsi) + bit2int( (int2bit(nri_v, 32) << ( 24 - nri_bitlen)) ),
+ 4);
+}
+
+template MobileIdentityLV ts_MI_TMSI_NRI_LV(integer nri_v, integer nri_bitlen := 10) :=
+ ts_MI_TMSI_LV(tmsi := f_tmsi_nri(nri_v, nri_bitlen := nri_bitlen));
+
+private function f_perform_clear(RSL_DCHAN_PT rsl) runs on MSC_ConnHdlr {
+ f_logp("MSC instructs BSC to clear channel");
+ BSSAP.send(ts_BSSMAP_ClearCommand(0));
+ interleave {
+ [] rsl.receive(tr_RSL_DATA_REQ(g_chan_nr, ?, decmatch tr_RRM_RR_RELEASE)) {
+ f_logp("Got RSL RR Release");
+ }
+ [] rsl.receive(tr_RSL_DEACT_SACCH(g_chan_nr)) {
+ f_logp("Got RSL Deact SACCH");
+ }
+ [] BSSAP.receive(tr_BSSMAP_ClearComplete) {
+ f_logp("Got BSSMAP Clear Complete");
+ /* Also drop the SCCP connection */
+ BSSAP.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
+ }
+ [] rsl.receive(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL)) {
+ f_logp("Got RSL RF Chan Rel, sending Rel Ack");
+ rsl.send(ts_RSL_RF_CHAN_REL_ACK(g_chan_nr));
+ }
+ }
+}
+
+private function f_perform_compl_l3(RSL_DCHAN_PT rsl, template PDU_ML3_MS_NW l3_info, boolean do_clear := true)
+runs on MSC_ConnHdlr {
+ timer T := 10.0;
+ var octetstring l3_enc := enc_PDU_ML3_MS_NW(valueof(l3_info));
+
+ f_logp("establish channel, send Complete Layer 3 Info");
+ f_create_bssmap_exp(l3_enc);
+
+ /* RSL_Emulation.f_chan_est() on rsl:
+ * This is basically code dup with s/RSL/rsl from:
+ * RSL_Emulation.f_chan_est(g_pars.ra, l3_enc, g_pars.link_id, g_pars.fn);
+ */
+ var RSL_Message rx_rsl;
+ var GsmRrMessage rr;
+
+ /* request a channel to be established */
+ rsl.send(ts_RSLDC_ChanRqd(g_pars.ra, g_pars.fn));
+ /* expect immediate assignment.
+ * Code dup with s/RSL/rsl from:
+ * rx_rsl := f_rx_or_fail(tr_RSL_IMM_ASSIGN);
+ */
+ timer Tt := 10.0;
+
+ /* request a channel to be established */
+ Tt.start;
+ alt {
+ [] rsl.receive(tr_RSL_IMM_ASSIGN) -> value rx_rsl {
+ Tt.stop;
+ }
+ [] rsl.receive {
+ setverdict(fail, "Unexpected RSL message on DCHAN");
+ mtc.stop;
+ }
+ [] Tt.timeout {
+ setverdict(fail, "Timeout waiting for RSL on DCHAN");
+ mtc.stop;
+ }
+ }
+ rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
+ g_chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
+ rsl.send(ts_RSL_EST_IND(g_chan_nr, valueof(g_pars.link_id), l3_enc));
+
+
+ f_logp("expect BSSAP Complete Layer 3 Info at MSC");
+ var template PDU_BSSAP exp_l3_compl;
+ exp_l3_compl := tr_BSSMAP_ComplL3()
+ if (g_pars.aoip == false) {
+ exp_l3_compl.pdu.bssmap.completeLayer3Information.codecList := omit;
+ } else {
+ exp_l3_compl.pdu.bssmap.completeLayer3Information.codecList := ?;
+ }
+
+ var PDU_BSSAP bssap;
+ T.start;
+ alt {
+ [] BSSAP.receive(exp_l3_compl) -> value bssap {
+ f_logp("received expected Complete Layer 3 Info at MSC");
+ log("rx exp_l3_compl = ", bssap);
+ }
+ [] BSSAP.receive(tr_BSSMAP_ComplL3) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received non-matching COMPLETE LAYER 3 INFORMATION");
+ }
+ [] T.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for COMPLETE LAYER 3 INFORMATION");
+ }
+ }
+
+ /* start ciphering, if requested */
+ if (ispresent(g_pars.encr)) {
+ f_logp("start ciphering");
+ f_cipher_mode(g_pars.encr.enc_alg, g_pars.encr.enc_key);
+ }
+
+ if (do_clear) {
+ f_perform_clear(rsl);
+ }
+ setverdict(pass);
+ f_sleep(1.0);
+}
+
+private function f_tc_mscpool_compl_l3(charstring id) runs on MSC_ConnHdlr {
+ f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
+ if (g_pars.mscpool.rsl_idx == 0) {
+ f_perform_compl_l3(RSL, g_pars.mscpool.l3_info);
+ } else if (g_pars.mscpool.rsl_idx == 1) {
+ f_perform_compl_l3(RSL1, g_pars.mscpool.l3_info);
+ } else if (g_pars.mscpool.rsl_idx == 2) {
+ f_perform_compl_l3(RSL2, g_pars.mscpool.l3_info);
+ }
+}
+
+/* Various Complete Layer 3 by IMSI all end up with the first MSC, because the other MSCs are not connected. */
+private function f_tc_mscpool_L3Compl_on_1_msc(charstring id) runs on MSC_ConnHdlr {
+ f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
+ f_perform_compl_l3(RSL, ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_IMSI_LV('001010000000001'H)), '00F110'O) );
+ f_perform_compl_l3(RSL, ts_CM_SERV_REQ(CM_TYPE_MO_SMS, valueof(ts_MI_IMSI_LV('001010000000002'H))) );
+ f_perform_compl_l3(RSL, ts_PAG_RESP(valueof(ts_MI_IMSI_LV('001010000000003'H))) );
+ f_perform_compl_l3(RSL, ts_ML3_MO_MM_IMSI_DET_Ind(valueof(ts_MI_IMSI_LV('001010000000004'H))) );
+}
+testcase TC_mscpool_L3Compl_on_1_msc() runs on test_CT {
+
+ f_init(1, true);
+ f_sleep(1.0);
+ var MSC_ConnHdlr vc_conn;
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+
+ f_ctrs_msc_init();
+
+ vc_conn := f_start_handler(refers(f_tc_mscpool_L3Compl_on_1_msc), pars);
+ vc_conn.done;
+
+ f_ctrs_msc_expect(0, "mscpool:subscr:new", 4);
+}
+
+/* Three Layer 3 Complete by IMSI are round-robin'ed across two connected MSCs */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_L3Complete_by_imsi_round_robin() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 2);
+ f_sleep(1.0);
+
+ /* Control which MSC gets chosen next by the round-robin, otherwise
+ * would be randomly affected by which other tests ran before this. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ pars1.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_IMSI_LV('001010000000001'H)), '00F110'O));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars2.mscpool.rsl_idx := 1;
+ pars2.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, valueof(ts_MI_IMSI_LV('001010000000002'H))));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:new");
+
+ /* Test round-robin wrap to the first MSC */
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars3.mscpool.rsl_idx := 2;
+ pars3.mscpool.l3_info := valueof(ts_PAG_RESP(valueof(ts_MI_IMSI_LV('001010000000003'H))));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+}
+
+/* Three LU by TMSI are round-robin'ed across two connected MSCs, because they contain the NULL-NRI 0
+ * (configured in osmo-bsc.cfg). */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_LU_by_tmsi_null_nri_0_round_robin() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 2);
+ f_sleep(1.0);
+
+ /* Control which MSC gets chosen next by the round-robin, otherwise
+ * would be randomly affected by which other tests ran before this. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ pars1.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(0)), '00F110'O));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:reattach");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars2.mscpool.rsl_idx := 1;
+ pars2.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(0)), '00F110'O));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:reattach");
+
+ /* Test round-robin wrap to the first MSC */
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars3.mscpool.rsl_idx := 2;
+ pars3.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(0)), '00F110'O));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:reattach");
+}
+
+/* Three LU by TMSI are round-robin'ed across two connected MSCs, because they contain the NULL-NRI 1
+ * (configured in osmo-bsc.cfg). In this case, one of the MSC also has the NULL-NRI as part of its owned NRIs, but the
+ * NULL-NRI setting is stronger than that. */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_LU_by_tmsi_null_nri_1_round_robin() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 2);
+ f_sleep(1.0);
+
+ /* Control which MSC gets chosen next by the round-robin, otherwise
+ * would be randomly affected by which other tests ran before this. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ pars1.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(1)), '00F110'O));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:reattach");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars2.mscpool.rsl_idx := 1;
+ pars2.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(1)), '00F110'O));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:reattach");
+
+ /* Test round-robin wrap to the first MSC */
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars3.mscpool.rsl_idx := 2;
+ pars3.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(1)), '00F110'O));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:reattach");
+}
+
+/* Three Layer 3 Complete by TMSI are round-robin'ed across two connected MSCs, because they contain an NRI not
+ * assigned to any MSC (configured in osmo-bsc.cfg). */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_L3Complete_by_tmsi_unassigned_nri_round_robin() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 2);
+ f_sleep(1.0);
+
+ /* Control which MSC gets chosen next by the round-robin, otherwise
+ * would be randomly affected by which other tests ran before this. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ /* An NRI that is not assigned to any MSC */
+ pars1.mscpool.l3_info := valueof(ts_ML3_MO_MM_IMSI_DET_Ind(valueof(ts_MI_TMSI_NRI_LV(1023))));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars2.mscpool.rsl_idx := 1;
+ /* An NRI that is not assigned to any MSC */
+ pars2.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(768)), '00F110'O));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:new");
+
+ /* Test round-robin wrap to the first MSC */
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars3.mscpool.rsl_idx := 2;
+ /* An NRI that is not assigned to any MSC */
+ pars3.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_SS_ACT, valueof(ts_MI_TMSI_NRI_LV(819))));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+}
+
+/* Three Layer 3 Complete by TMSI are round-robin'ed across two connected MSCs, because they contain an NRI
+ * assigned to an MSC that is currently not connected (configured in osmo-bsc.cfg). */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_L3Complete_by_tmsi_valid_nri_msc_not_connected_round_robin() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 2);
+ f_sleep(1.0);
+
+ /* Control which MSC gets chosen next by the round-robin, otherwise
+ * would be randomly affected by which other tests ran before this. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ /* An NRI that is assigned to an unconnected MSC */
+ pars1.mscpool.l3_info := valueof(ts_PAG_RESP(valueof(ts_MI_TMSI_NRI_LV(512))));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_add(2, "mscpool:subscr:attach_lost");
+ f_ctrs_msc_add(0, "mscpool:subscr:new");
+ f_ctrs_msc_verify();
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars2.mscpool.rsl_idx := 1;
+ /* An NRI that is assigned to an unconnected MSC */
+ pars2.mscpool.l3_info := valueof(ts_ML3_MO_MM_IMSI_DET_Ind(valueof(ts_MI_TMSI_NRI_LV(767))));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_add(2, "mscpool:subscr:attach_lost");
+ f_ctrs_msc_add(1, "mscpool:subscr:new");
+ f_ctrs_msc_verify();
+
+ /* Test round-robin wrap to the first MSC */
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars3.mscpool.rsl_idx := 2;
+ /* An NRI that is assigned to an unconnected MSC */
+ pars3.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(750)), '00F110'O));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_add(2, "mscpool:subscr:attach_lost");
+ f_ctrs_msc_add(0, "mscpool:subscr:new");
+ f_ctrs_msc_verify();
+}
+
+/* Three Layer 3 Complete by TMSI with valid NRI for the second MSC are all directed to the second MSC (configured in
+ * osmo-bsc.cfg). */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_L3Complete_by_tmsi_valid_nri_1() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 2);
+ f_sleep(1.0);
+
+ /* All TMSIs in this test point at the second MSC, set the round robin to point at the first MSC to make sure
+ * this is not using round-robin. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars1.mscpool.rsl_idx := 0;
+ /* An NRI of the second MSC's range (256-511) */
+ pars1.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_SMS, valueof(ts_MI_TMSI_NRI_LV(256))));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:known");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars2.mscpool.rsl_idx := 1;
+ /* An NRI of the second MSC's range (256-511) */
+ pars2.mscpool.l3_info := valueof(ts_PAG_RESP(valueof(ts_MI_TMSI_NRI_LV(260))));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:known");
+
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars3.mscpool.rsl_idx := 2;
+ /* An NRI of the second MSC's range (256-511) */
+ pars3.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(511)), '00F110'O));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:known");
+}
+
+/* Layer 3 Complete by TMSI with valid NRI for the third MSC are directed to the third MSC (configured in osmo-bsc.cfg),
+ * while a round-robin remains unaffected by that. */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_L3Complete_by_tmsi_valid_nri_2() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 3);
+ f_sleep(1.0);
+
+ /* All TMSIs in this test point at the third MSC, set the round robin to point at the second MSC to make sure
+ * this is not using round-robin. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 1");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 2);
+ pars1.mscpool.rsl_idx := 0;
+ /* An NRI of the third MSC's range (512-767) */
+ pars1.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_SMS, valueof(ts_MI_TMSI_NRI_LV(512))));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(2, "mscpool:subscr:known");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 2);
+ pars2.mscpool.rsl_idx := 1;
+ /* An NRI of the third MSC's range (512-767) */
+ pars2.mscpool.l3_info := valueof(ts_PAG_RESP(valueof(ts_MI_TMSI_NRI_LV(678))));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(2, "mscpool:subscr:known");
+
+ /* The above forwardings to third MSC have not affected the round robin, which still points at the second MSC */
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars3.mscpool.rsl_idx := 2;
+ pars3.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_IMSI_LV('001010000000013'H)), '00F110'O));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:new");
+}
+
+/* LU with a TMSI but indicating a different PLMN in its previous LAI: ignore the NRI. */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_LU_by_tmsi_from_other_PLMN() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 3);
+ f_sleep(1.0);
+
+ /* The TMSIs in this test points at the second MSC, but since it is from a different PLMN, round-robin is used
+ * instead, and hits msc 0. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ /* An NRI of the second MSC's range (256-511), but a PLMN that doesn't match with osmo-bsc.cfg */
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ pars1.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(260)), '99F999'O));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+
+ /* An NRI of the third MSC's range (512-767) and a matching PLMN gets directed by NRI. */
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 2);
+ pars2.mscpool.rsl_idx := 1;
+ pars2.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_TMSI_NRI_LV(555)), '00F110'O));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(2, "mscpool:subscr:known");
+}
+
+/* Make sure that whichever MSC paged a subscriber will also get the Paging Response. Page by IMSI, which would be
+ * round-robined to another MSC, to make sure the Paging->Response relation is stronger than the NRI->MSC mapping. */
+private function f_tc_mscpool_paging_imsi(charstring id) runs on MSC_ConnHdlr {
+ var template BSSMAP_FIELD_CellIdentificationList cid_list := { cIl_CI := { ts_BSSMAP_CI_CI(0) } };
+ //cid_list := { cIl_allInBSS := ''O };
+ var RSL_ChanNeeded rsl_chneed := RSL_CHANNEED_SDCCH;
+ var template BSSMAP_IE_ChannelNeeded bssmap_chneed := ts_BSSMAP_IE_ChanNeeded(int2bit(enum2int(valueof(rsl_chneed)),2));
+ var BSSAP_N_UNITDATA_req paging;
+ var hexstring imsi := '001010000000123'H;
+
+ f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
+
+ paging := valueof(ts_BSSAP_UNITDATA_req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc,
+ valueof(ts_BSSMAP_Paging(imsi, cid_list, omit, bssmap_chneed))));
+ BSSAP.send(paging);
+
+ /* Register any RSL conn so that the Paging Command gets received here. With the current RSL_Emulation's main()
+ * handling of '[bts_role] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD()))' it doesn't matter at all which
+ * channel number is picked here. */
+ var RslChannelNr new_chan_nr := valueof(t_RslChanNr0(0, RSL_CHAN_NR_INVALID));
+ f_rslem_register(0, new_chan_nr);
+ RSL.receive(tr_RSL_PAGING_CMD(tr_MI_IMSI(imsi)));
+ f_rslem_unregister(0, new_chan_nr);
+
+ /* Despite the round robin pointing at the second MSC ('roundrobin next 1'), the earlier Paging for the same IMSI
+ * causes this Paging Response to go to the first MSC (bssap_idx := 0). */
+ f_perform_compl_l3(RSL, ts_PAG_RESP(valueof(ts_MI_IMSI_LV(imsi))) );
+ setverdict(pass);
+ f_sleep(1.0);
+}
+testcase TC_mscpool_paging_and_response_imsi() runs on test_CT {
+ f_init(nr_bts := 1, handler_mode := true, nr_msc := 3);
+ f_sleep(1.0);
+
+ /* Testing a Paging on the first MSC to get a Paging Response back to the first MSC. Set round robin to the
+ * second MSC to make sure we're getting the Paging logic, not a coincidental round robin match. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 1");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ pars1.sccp_addr_bsc := g_bssap[pars1.mscpool.bssap_idx].sccp_addr_peer;
+ pars1.sccp_addr_msc := g_bssap[pars1.mscpool.bssap_idx].sccp_addr_own;
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_paging_imsi), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:paged");
+}
+
+/* Make sure that whichever MSC paged a subscriber will also get the Paging Response. Page by TMSI with an NRI value
+ * that matches a different MSC, to make sure the Paging->Response relation is stronger than the NRI->MSC mapping. */
+private function f_tc_mscpool_paging_tmsi(charstring id) runs on MSC_ConnHdlr {
+ var template BSSMAP_FIELD_CellIdentificationList cid_list := { cIl_CI := { ts_BSSMAP_CI_CI(0) } };
+ //cid_list := { cIl_allInBSS := ''O };
+ var RSL_ChanNeeded rsl_chneed := RSL_CHANNEED_SDCCH;
+ var template BSSMAP_IE_ChannelNeeded bssmap_chneed := ts_BSSMAP_IE_ChanNeeded(int2bit(enum2int(valueof(rsl_chneed)),2));
+ var integer nri_v := 300; /* <-- second MSC's NRI */
+ var octetstring tmsi := f_tmsi_nri(nri_v);
+ var BSSAP_N_UNITDATA_req paging;
+
+ f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
+
+ paging := valueof(ts_BSSAP_UNITDATA_req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc,
+ valueof(ts_BSSMAP_Paging('001010000000011'H, cid_list, tmsi, bssmap_chneed))));
+ BSSAP.send(paging);
+
+ /* Register any RSL conn so that the Paging Command gets received here. With the current RSL_Emulation's main()
+ * handling of '[bts_role] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD()))' it doesn't matter at all which
+ * channel number is picked here. */
+ var RslChannelNr new_chan_nr := valueof(t_RslChanNr0(0, RSL_CHAN_NR_INVALID));
+ f_rslem_register(0, new_chan_nr);
+ RSL.receive(tr_RSL_PAGING_CMD(t_MI_TMSI(tmsi)));
+ f_rslem_unregister(0, new_chan_nr);
+
+ /* Despite the NRI matching the second MSC (NRI from 'msc 1' in osmo-bsc.cfg) and round robin pointing at the
+ * third MSC ('roundrobin next 2'), the earlier Paging for the same TMSI causes this Paging Response to go to
+ * the first MSC (bssap_idx := 0). */
+ f_perform_compl_l3(RSL, ts_PAG_RESP(valueof(ts_MI_TMSI_NRI_LV(nri_v))) );
+ setverdict(pass);
+ f_sleep(1.0);
+}
+testcase TC_mscpool_paging_and_response_tmsi() runs on test_CT {
+ f_init(nr_bts := 1, handler_mode := true, nr_msc := 3);
+ f_sleep(1.0);
+
+ /* Testing a Paging on the first MSC to get a Paging Response back to the first MSC. Set round robin to the
+ * third MSC to make sure we're getting the Paging logic, not a coincidental round robin match. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 2");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ pars1.sccp_addr_bsc := g_bssap[pars1.mscpool.bssap_idx].sccp_addr_peer;
+ pars1.sccp_addr_msc := g_bssap[pars1.mscpool.bssap_idx].sccp_addr_own;
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_paging_tmsi), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:paged");
+}
+
+/* For round-robin, skip an MSC that has 'no allow-attach' set. */
+/* FIXME: each run is using a separate RSLem: RSL, RSL1, RSL2. It should work
+ * just as well using only RSL. */
+testcase TC_mscpool_no_allow_attach_round_robin() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 3);
+ f_sleep(1.0);
+ /* Mark the second MSC as offloading, round-robin should skip this MSC now. */
+ f_vty_msc_allow_attach(BSCVTY, {true, false, true});
+
+ /* Control which MSC gets chosen next by the round-robin, otherwise
+ * would be randomly affected by which other tests ran before this. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars1.mscpool.rsl_idx := 0;
+ pars1.mscpool.l3_info := valueof(ts_LU_REQ(LU_Type_IMSI_Attach, valueof(ts_MI_IMSI_LV('001010000000001'H)), '00F110'O));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 2);
+ pars2.mscpool.rsl_idx := 1;
+ pars2.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, valueof(ts_MI_IMSI_LV('001010000000002'H))));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(2, "mscpool:subscr:new");
+
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars3.mscpool.rsl_idx := 2;
+ pars3.mscpool.l3_info := valueof(ts_PAG_RESP(valueof(ts_MI_IMSI_LV('001010000000003'H))));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+}
+
+/* An MSC that has 'no allow-attach' set should still serve subscribers that are already attached according to their
+ * TMSI NRI. */
+testcase TC_mscpool_no_allow_attach_valid_nri() runs on test_CT {
+
+ f_init(nr_bts := 3, handler_mode := true, nr_msc := 3);
+ f_sleep(1.0);
+
+ /* Mark the second MSC as offloading, round-robin should skip this MSC now. */
+ f_vty_msc_allow_attach(BSCVTY, {true, false, true});
+
+ /* Control which MSC gets chosen next by the round-robin, otherwise
+ * would be randomly affected by which other tests ran before this. */
+ f_vty_transceive(BSCVTY, "mscpool roundrobin next 0");
+
+ f_ctrs_msc_init();
+
+ /* Round robin points at msc 0, but the valid NRI directs to msc 1, even though msc 1 has 'no allow-attach'. */
+ var MSC_ConnHdlr vc_conn1;
+ var TestHdlrParams pars1 := f_gen_test_hdlr_pars(bssap_idx := 1);
+ pars1.mscpool.rsl_idx := 0;
+ /* An NRI of the second MSC's range (256-511) */
+ pars1.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, valueof(ts_MI_TMSI_NRI_LV(260))));
+ vc_conn1 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars1);
+ vc_conn1.done;
+ f_ctrs_msc_expect(1, "mscpool:subscr:known");
+
+ var MSC_ConnHdlr vc_conn2;
+ var TestHdlrParams pars2 := f_gen_test_hdlr_pars(bssap_idx := 0);
+ pars2.mscpool.rsl_idx := 1;
+ pars2.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, valueof(ts_MI_IMSI_LV('001010000000002'H))));
+ vc_conn2 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars2);
+ vc_conn2.done;
+ f_ctrs_msc_expect(0, "mscpool:subscr:new");
+
+ var MSC_ConnHdlr vc_conn3;
+ var TestHdlrParams pars3 := f_gen_test_hdlr_pars(bssap_idx := 2);
+ pars3.mscpool.rsl_idx := 2;
+ pars3.mscpool.l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_CALL, valueof(ts_MI_IMSI_LV('001010000000003'H))));
+ vc_conn3 := f_start_handler(refers(f_tc_mscpool_compl_l3), pars3);
+ vc_conn3.done;
+ f_ctrs_msc_expect(2, "mscpool:subscr:new");
+}
+
+/* Allow/Deny emergency calls globally via VTY */
+private function f_vty_allow_emerg_msc(boolean allow) runs on test_CT {
+ f_vty_enter_cfg_msc(BSCVTY, 0);
+ if (allow) {
+ f_vty_transceive(BSCVTY, "allow-emergency allow");
+ } else {
+ f_vty_transceive(BSCVTY, "allow-emergency deny");
+ }
+ f_vty_transceive(BSCVTY, "exit");
+ f_vty_transceive(BSCVTY, "exit");
+}
+
+/* Allow/Deny emergency calls per BTS via VTY */
+private function f_vty_allow_emerg_bts(boolean allow, integer bts_nr) runs on test_CT {
+ f_vty_enter_cfg_bts(BSCVTY, bts_nr);
+ if (allow) {
+ f_vty_transceive(BSCVTY, "rach emergency call allowed 1");
+ } else {
+ f_vty_transceive(BSCVTY, "rach emergency call allowed 0");
+ }
+ f_vty_transceive(BSCVTY, "exit");
+ f_vty_transceive(BSCVTY, "exit");
+}
+
+/* Begin assignmet procedure and send an EMERGENCY SETUP (RR) */
+private function f_assignment_emerg_setup() runs on MSC_ConnHdlr {
+ var PDU_ML3_MS_NW emerg_setup;
+ var octetstring emerg_setup_enc;
+ var RSL_Message emerg_setup_data_ind;
+
+ f_establish_fully(omit, omit);
+
+ emerg_setup := valueof(ts_ML3_MO_CC_EMERG_SETUP(1, valueof(ts_Bcap_voice)));
+ emerg_setup_enc := enc_PDU_ML3_MS_NW(emerg_setup);
+ emerg_setup_data_ind := valueof(ts_RSL_DATA_IND(g_chan_nr, valueof(ts_RslLinkID_DCCH(0)), emerg_setup_enc));
+
+ RSL.send(emerg_setup_data_ind);
+}
+
+/* Test if the EMERGENCY SETUP gets passed on to the MSC via A when EMERGENCY
+ * CALLS are permitted by the BSC config. */
+private function f_TC_assignment_emerg_setup_allow(charstring id) runs on MSC_ConnHdlr {
+ var PDU_BSSAP emerg_setup_data_ind_bssap;
+ var PDU_ML3_MS_NW emerg_setup;
+ timer T := 3.0;
+
+ f_assignment_emerg_setup()
+
+ T.start;
+ alt {
+ [] BSSAP.receive(tr_BSSAP_DTAP) -> value emerg_setup_data_ind_bssap {
+ emerg_setup := dec_PDU_ML3_MS_NW(emerg_setup_data_ind_bssap.pdu.dtap);
+ if (not isbound(emerg_setup.msgs.cc.emergencySetup)) {
+ setverdict(fail, "no emergency setup");
+ }
+ }
+ [] BSSAP.receive {
+ setverdict(fail, "unexpected BSSAP message!");
+ }
+ [] T.timeout {
+ setverdict(fail, "timout waiting for EMERGENCY SETUP!");
+ }
+ }
+
+ setverdict(pass);
+}
+
+/* Test if the EMERGENCY SETUP gets blocked by the BSC if EMERGENCY CALLS are
+ * forbidden by the BSC config. */
+private function f_TC_assignment_emerg_setup_deny(charstring id) runs on MSC_ConnHdlr {
+ var PDU_BSSAP emerg_setup_data_ind_bssap;
+ timer T := 3.0;
+
+ f_assignment_emerg_setup()
+
+ T.start;
+ alt {
+ [] RSL.receive(tr_RSL_DATA_REQ(g_chan_nr, ?, decmatch tr_RRM_RR_RELEASE)) {
+ setverdict(pass);
+ }
+ [] RSL.receive {
+ setverdict(fail, "unexpected RSL message!");
+ }
+ [] T.timeout {
+ setverdict(fail, "timout waiting for RR CHANNEL RELEASE!");
+ }
+ }
+}
+
+/* EMERGENCY CALL situation #1, allowed globally and by BTS */
+testcase TC_assignment_emerg_setup_allow() runs on test_CT {
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+ var MSC_ConnHdlr vc_conn;
+
+ f_init(1, true);
+ f_sleep(1.0);
+
+ f_vty_allow_emerg_msc(true);
+ f_vty_allow_emerg_bts(true, 0);
+ vc_conn := f_start_handler(refers(f_TC_assignment_emerg_setup_allow), pars);
+ vc_conn.done;
+}
+
+/* EMERGENCY CALL situation #2, forbidden globally but allowed by BTS */
+testcase TC_assignment_emerg_setup_deny_msc() runs on test_CT {
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+ var MSC_ConnHdlr vc_conn;
+
+ f_init(1, true);
+ f_sleep(1.0);
+
+ f_vty_allow_emerg_msc(false);
+ f_vty_allow_emerg_bts(true, 0);
+ vc_conn := f_start_handler(refers(f_TC_assignment_emerg_setup_deny), pars);
+ vc_conn.done;
+}
+
+/* EMERGENCY CALL situation #3, allowed globally but forbidden by BTS */
+testcase TC_assignment_emerg_setup_deny_bts() runs on test_CT {
+ var TestHdlrParams pars := f_gen_test_hdlr_pars();
+ var MSC_ConnHdlr vc_conn;
+
+ /* Note: This simulates a spec violation by the MS, correct MS
+ * implementations would not try to establish an emergency call because
+ * the system information tells in advance that emergency calls are
+ * not forbidden */
+
+ f_init(1, true);
+ f_sleep(1.0);
+
+ f_vty_allow_emerg_msc(true);
+ f_vty_allow_emerg_bts(false, 0);
+ vc_conn := f_start_handler(refers(f_TC_assignment_emerg_setup_deny), pars);
+ vc_conn.done;
+}
+
+/* Test what happens when an emergency call arrives while all TCH channels are
+ * busy, the BSC is expected to terminate one call in favor of the incoming
+ * emergency call */
+testcase TC_emerg_premption() runs on test_CT {
+ var ASP_RSL_Unitdata rsl_ud;
+ var integer i;
+ var integer chreq_total, chreq_nochan;
+ var RSL_Message rx_rsl;
+ var RslChannelNr chan_nr;
+
+ f_init(1);
+ f_sleep(1.0);
+
+ f_vty_allow_emerg_msc(true);
+ f_vty_allow_emerg_bts(true, 0);
+
+ /* Fill up all channels on the BTS */
+ chreq_total := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:total");
+ chreq_nochan := f_ctrl_get_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:no_channel");
+ for (i := 0; i < NUM_TCHF_PER_BTS + NUM_TCHH_PER_BTS + NUM_SDCCH_PER_BTS; i := i+1) {
+ chan_nr := f_chreq_act_ack('33'O, i);
+ }
+ IPA_RSL[0].clear;
+ f_ctrl_get_exp_ratectr_abs(IPA_CTRL, "bts", 0, "chreq:total",
+ chreq_total + NUM_TCHF_PER_BTS + NUM_TCHH_PER_BTS + NUM_SDCCH_PER_BTS);
+
+ /* Send Channel request for emegergency call */
+ f_ipa_tx(0, ts_RSL_CHAN_RQD('A5'O, 23));
+
+ /* Expect the BSC to release one (the first) TCH/F on the BTS */
+ chan_nr := valueof(t_RslChanNr_Bm(1));
+ f_expect_chan_rel(0, chan_nr, expect_rr_chan_rel := false, expect_rll_rel_req := false);
+
+ /* Expect the BSC to send activate/assign the a channel for the emergency call */
+ rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+ chan_nr := rx_rsl.ies[0].body.chan_nr;
+ f_ipa_tx(0, ts_RSL_CHAN_ACT_ACK(chan_nr, 33));
+ rx_rsl := f_exp_ipa_rx(0, tr_RSL_IMM_ASSIGN(0));
+}
+
+/* Hopping parameters per a timeslot */
+private type record length(0..64) of integer ArfcnList;
+private type record FHParamsTs {
+ boolean enabled,
+ uint6_t hsn,
+ uint6_t maio,
+ ArfcnList ma
+};
+
+/* Hopping parameters per a transceiver */
+private type record length(8) of FHParamsTs FHParamsTrx;
+
+/* Randomly generate the hopping parameters for the given timeslot numbers */
+private function f_TC_fh_params_gen(template integer tr_tn := (1, 3, 5))
+runs on test_CT return FHParamsTrx {
+ var FHParamsTrx fhp;
+
+ for (var integer tn := 0; tn < 8; tn := tn + 1) {
+ if (not match(tn, tr_tn)) {
+ fhp[tn].enabled := false;
+ fhp[tn].ma := { };
+ continue;
+ }
+
+ /* Random HSN / MAIO values: 0..63 */
+ fhp[tn].hsn := f_rnd_int(64);
+ fhp[tn].maio := f_rnd_int(64);
+ fhp[tn].ma := { };
+
+ /* Random Mobile Allocation (hopping channels) */
+ var integer ma_len := 2 + f_rnd_int(9); /* 2..10 channels */
+ var integer step := 3 + f_rnd_int(4); /* 3..6 stepping */
+ for (var integer i := 1; i <= ma_len; i := i + 1) {
+ fhp[tn].ma := fhp[tn].ma & { i * step };
+ }
+
+ fhp[tn].enabled := true;
+ }
+
+ log("f_TC_fh_params_gen(): ", fhp);
+ return fhp;
+}
+
+/* Make sure that the given Channel Description IE matches the hopping configuration */
+private function f_TC_fh_params_match_chan_desc(in FHParamsTrx fhp, in ChannelDescription cd)
+{
+ var template (present) ChannelDescription tr_cd;
+ var template (present) MaioHsn tr_maio_hsn;
+ var uint3_t tn := cd.chan_nr.tn;
+
+ if (fhp[tn].enabled) {
+ tr_maio_hsn := tr_HsnMaio(fhp[tn].hsn, fhp[tn].maio);
+ tr_cd := tr_ChanDescH1(cd.chan_nr, tr_maio_hsn);
+ } else {
+ tr_cd := tr_ChanDescH0(cd.chan_nr);
+ }
+
+ if (not match(cd, tr_cd)) {
+ setverdict(fail, "Channel Description IE does not match: ",
+ cd, " vs expected ", tr_cd);
+ }
+}
+
+/* Make sure that the given Mobile Allocation IE matches the hopping configuration */
+private function f_TC_fh_params_match_ma(in FHParamsTrx fhp, uint3_t tn,
+ in MobileAllocationLV ma)
+{
+ var template MobileAllocationLV tr_ma := f_TC_fh_params_gen_tr_ma(fhp, tn, ma);
+
+ if (not match(ma, tr_ma)) {
+ setverdict(fail, "Mobile Allocation IE does not match (tn := ",
+ tn, "): ", ma, " vs expected: ", tr_ma);
+ } else {
+ setverdict(pass);
+ }
+}
+
+private function f_TC_fh_params_gen_tr_ma(in FHParamsTrx fhp, uint3_t tn,
+ in MobileAllocationLV ma)
+return template MobileAllocationLV {
+ /* Mobile Allocation IE is expected to be empty if hopping is not enabled */
+ if (not fhp[tn].enabled) {
+ return { len := 0, ma := ''B };
+ }
+
+ var bitstring full_mask := f_pad_bit(''B, 1024, '0'B);
+ var bitstring slot_mask := f_pad_bit(''B, 1024, '0'B);
+ var bitstring ma_mask := ''B;
+
+ /* Compose the full bit-mask (all channels, up to 1024 entries) */
+ for (var integer i := 0; i < lengthof(fhp); i := i + 1) {
+ for (var integer j := 0; j < lengthof(fhp[i].ma); j := j + 1) {
+ if (full_mask[fhp[i].ma[j]] == '1'B)
+ { continue; }
+ full_mask[fhp[i].ma[j]] := '1'B;
+ }
+ }
+
+ /* Compose a bit-mask for the given timeslot number */
+ for (var integer i := 0; i < lengthof(fhp[tn].ma); i := i + 1) {
+ slot_mask[fhp[tn].ma[i]] := '1'B;
+ }
+
+ /* Finally, compose the Mobile Allocation bit-mask */
+ for (var integer i := 0; i < lengthof(full_mask); i := i + 1) {
+ if (full_mask[i] != '1'B)
+ { continue; }
+
+ /* FIXME: ma_mask := ma_mask & slot_mask[i]; // triggers a bug in TITAN */
+ if (slot_mask[i] == '1'B) {
+ ma_mask := ma_mask & '1'B;
+ } else {
+ ma_mask := ma_mask & '0'B;
+ }
+ }
+
+ /* Ensure that ma_mask is octet-aligned */
+ var integer ma_mask_len := (lengthof(ma_mask) + 8 - 1) / 8;
+ ma_mask := f_pad_bit(ma_mask, ma_mask_len * 8, '0'B);
+
+ return { len := ma_mask_len, ma := ma_mask };
+}
+
+/* Configure the hopping parameters in accordance with the given record */
+private function f_TC_fh_params_set(in FHParamsTrx fhp,
+ uint8_t bts_nr := 0,
+ uint8_t trx_nr := 0)
+runs on test_CT {
+ /* Enter the configuration node for the given BTS/TRX numbers */
+ f_vty_enter_cfg_trx(BSCVTY, bts_nr, trx_nr);
+
+ for (var integer tn := 0; tn < lengthof(fhp); tn := tn + 1) {
+ f_vty_transceive(BSCVTY, "timeslot " & int2str(tn));
+
+ if (not fhp[tn].enabled) {
+ f_vty_transceive(BSCVTY, "hopping enabled 0");
+ f_vty_transceive(BSCVTY, "exit"); /* go back */
+ continue;
+ }
+
+ /* Configure HSN / MAIO values */
+ f_vty_transceive(BSCVTY, "hopping sequence-number " & int2str(fhp[tn].hsn));
+ f_vty_transceive(BSCVTY, "hopping maio " & int2str(fhp[tn].maio));
+
+ /* Configure the Mobile Allocation (hopping channels) */
+ for (var integer i := 0; i < lengthof(fhp[tn].ma); i := i + 1) {
+ f_vty_transceive(BSCVTY, "hopping arfcn add " & int2str(fhp[tn].ma[i]));
+ }
+
+ f_vty_transceive(BSCVTY, "hopping enabled 1");
+ f_vty_transceive(BSCVTY, "exit"); /* go back */
+ }
+
+ f_vty_transceive(BSCVTY, "end");
+}
+
+/* Disable frequency hopping on all timeslots */
+private function f_TC_fh_params_unset(in FHParamsTrx fhp,
+ uint8_t bts_nr := 0,
+ uint8_t trx_nr := 0)
+runs on test_CT {
+ /* Enter the configuration node for the given BTS/TRX numbers */
+ f_vty_enter_cfg_trx(BSCVTY, bts_nr, trx_nr);
+
+ for (var integer tn := 0; tn < lengthof(fhp); tn := tn + 1) {
+ f_vty_transceive(BSCVTY, "timeslot " & int2str(tn));
+
+ /* Delete all ARFCNs from the Mobile Allocation (if any) */
+ for (var integer i := 0; i < lengthof(fhp[tn].ma); i := i + 1) {
+ f_vty_transceive(BSCVTY, "hopping arfcn del " & int2str(fhp[tn].ma[i]));
+ }
+
+ f_vty_transceive(BSCVTY, "hopping enabled 0");
+ f_vty_transceive(BSCVTY, "exit"); /* go back */
+ }
+
+ f_vty_transceive(BSCVTY, "end");
+ f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
+}
+
+/* Verify presence and correctness of the hopping parameters (HSN, MAIO)
+ * in the Channel Identification IE of the RSL CHANnel ACTIVation message. */
+testcase TC_fh_params_chan_activ() runs on test_CT {
+ var FHParamsTrx fhp := f_TC_fh_params_gen();
+ var RSL_Message rsl_msg;
+ var RSL_IE_Body ie;
+
+ f_init_vty();
+
+ f_TC_fh_params_set(fhp); /* Enable frequency hopping */
+ f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
+
+ f_init(1);
+
+ /* CS domain: 3 (SDCCH/4+CBCH) + 4 (TCH/F) + 2 (TCH/H) channels available */
+ for (var integer i := 0; i < 9; i := i + 1) {
+ f_ipa_tx(0, ts_RSL_CHAN_RQD(f_rnd_ra_cs(), 23));
+ rsl_msg := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+
+ /* Make sure that Channel Identification IE is present */
+ if (not f_rsl_find_ie(rsl_msg, RSL_IE_CHAN_IDENT, ie)) {
+ setverdict(fail, "RSL Channel Identification IE is absent");
+ continue;
+ }
+
+ /* Make sure that hopping parameters (HSN/MAIO) match */
+ f_TC_fh_params_match_chan_desc(fhp, ie.chan_ident.ch_desc.v);
+
+ /* "Mobile Allocation shall be included but empty" - let's check this */
+ if (ie.chan_ident.ma.v.len != 0) {
+ setverdict(fail, "Mobile Allocation IE is not empty: ",
+ ie.chan_ident.ma, ", despite it shall be");
+ continue;
+ }
+ }
+
+ /* Disable frequency hopping */
+ f_TC_fh_params_unset(fhp);
+
+ f_shutdown_helper();
+}
+
+/* Verify the hopping parameters (HSN, MAIO, MA) in (RR) Immediate Assignment */
+testcase TC_fh_params_imm_ass() runs on test_CT {
+ var FHParamsTrx fhp := f_TC_fh_params_gen();
+ var RSL_Message rsl_msg;
+ var RSL_IE_Body ie;
+
+ f_init_vty();
+
+ f_TC_fh_params_set(fhp); /* Enable frequency hopping */
+ f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
+
+ f_init(1);
+
+ /* CS domain: 3 (SDCCH/4+CBCH) + 4 (TCH/F) + 2 (TCH/H) channels available */
+ for (var integer i := 0; i < 9; i := i + 1) {
+ f_ipa_tx(0, ts_RSL_CHAN_RQD(f_rnd_ra_cs(), 23));
+ rsl_msg := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+
+ f_ipa_tx(0, ts_RSL_CHAN_ACT_ACK(rsl_msg.ies[0].body.chan_nr, 33));
+ rsl_msg := f_exp_ipa_rx(0, tr_RSL_MsgTypeC(RSL_MT_IMMEDIATE_ASSIGN_CMD));
+
+ /* Make sure that Full Immediate Assign Info IE is present */
+ if (not f_rsl_find_ie(rsl_msg, RSL_IE_FULL_IMM_ASS_INFO, ie)) {
+ setverdict(fail, "RSL Full Immediate Assign Info IE is absent");
+ continue;
+ }
+
+ /* Decode the actual Immediate Assignment message */
+ var GsmRrMessage rr_msg := dec_GsmRrMessage(ie.full_imm_ass_info.payload);
+ if (not match(rr_msg.header, t_RrHeader(IMMEDIATE_ASSIGNMENT, ?))) {
+ setverdict(fail, "Failed to match Immediate Assignment: ", rr_msg);
+ continue;
+ }
+
+ /* Make sure that hopping parameters (HSN/MAIO) match */
+ f_TC_fh_params_match_chan_desc(fhp, rr_msg.payload.imm_ass.chan_desc);
+
+ /* Make sure that the Mobile Allocation IE matches */
+ f_TC_fh_params_match_ma(fhp, rr_msg.payload.imm_ass.chan_desc.chan_nr.tn,
+ rr_msg.payload.imm_ass.mobile_allocation);
+ }
+
+ /* Disable frequency hopping */
+ f_TC_fh_params_unset(fhp);
+
+ f_shutdown_helper();
+}
+
+/* Verify the hopping parameters (HSN, MAIO, MA) in (RR) Assignment Command */
+testcase TC_fh_params_assignment_cmd() runs on test_CT {
+ var FHParamsTrx fhp := f_TC_fh_params_gen();
+ var RSL_Message rsl_msg;
+ var RSL_IE_Body ie;
+
+ f_init_vty();
+
+ f_TC_fh_params_set(fhp); /* Enable frequency hopping */
+ f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
+
+ f_init(1);
+
+ /* HACK: work around "Couldn't find Expect for CRCX" */
+ vc_MGCP.stop;
+
+ var template PDU_BSSAP ass_cmd := f_gen_ass_req();
+ ass_cmd.pdu.bssmap.assignmentRequest.codecList := ts_BSSMAP_IE_CodecList({ts_CodecFR});
+
+ /* CS domain (TCH): 4 (TCH/F) + 2 (TCH/H) channels available
+ * NOTE: only 3 SDCCH/4 channels are available on CCCH+SDCCH4+CBCH */
+ for (var integer i := 0; i < 3; i := i + 1) {
+ /* Establish a dedicated channel, so we can trigger (late) TCH assignment */
+ var DchanTuple dt := f_est_dchan(f_rnd_ra_cs(), 23, f_rnd_octstring(16));
+
+ /* Send a BSSMAP Assignment Command, expect CHANnel ACTIVation */
+ BSSAP.send(ts_BSSAP_DATA_req(dt.sccp_conn_id, ass_cmd));
+ rsl_msg := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+
+ /* ACKnowledge CHANnel ACTIVation, expect RSL DATA REQuest */
+ f_ipa_tx(0, ts_RSL_CHAN_ACT_ACK(rsl_msg.ies[0].body.chan_nr, 33));
+ rsl_msg := f_exp_ipa_rx(0, tr_RSL_MsgTypeR(RSL_MT_DATA_REQ));
+
+ /* Make sure that L3 Information IE is present */
+ if (not f_rsl_find_ie(rsl_msg, RSL_IE_L3_INFO, ie)) {
+ setverdict(fail, "RSL L3 Information IE is absent");
+ continue;
+ }
+
+ /* Decode the L3 message and make sure it is (RR) Assignment Command */
+ var GsmRrL3Message l3_msg := dec_GsmRrL3Message(ie.l3_info.payload);
+ if (not match(l3_msg.header, t_RrL3Header(ASSIGNMENT_COMMAND))) {
+ setverdict(fail, "Failed to match Assignment Command: ", l3_msg);
+ continue;
+ }
+
+ /* Make sure that hopping parameters (HSN/MAIO) match */
+ var ChannelDescription chan_desc := l3_msg.payload.ass_cmd.chan_desc;
+ f_TC_fh_params_match_chan_desc(fhp, chan_desc);
+
+ /* Make sure that Cell Channel Description IE is present if FH is enabled */
+ if (chan_desc.h and not ispresent(l3_msg.payload.ass_cmd.cell_chan_desc)) {
+ setverdict(fail, "FH enabled, but Cell Channel Description IE is absent");
+ continue;
+ }
+
+ /* Make sure that the Mobile Allocation IE matches (if present) */
+ var boolean ma_present := ispresent(l3_msg.payload.ass_cmd.mobile_allocation);
+ if (chan_desc.h and ma_present) {
+ f_TC_fh_params_match_ma(fhp, chan_desc.chan_nr.tn,
+ l3_msg.payload.ass_cmd.mobile_allocation.v);
+ } else if (chan_desc.h and not ma_present) {
+ setverdict(fail, "FH enabled, but Mobile Allocation IE is absent");
+ continue;
+ } else if (not chan_desc.h and ma_present) {
+ setverdict(fail, "FH disabled, but Mobile Allocation IE is present");
+ continue;
+ }
+ }
+
+ /* Give the IUT some time to release all channels */
+ f_sleep(3.0);
+
+ /* Disable frequency hopping */
+ f_TC_fh_params_unset(fhp);
+
+ f_shutdown_helper();
+}
+
+/* Verify the hopping parameters (HSN, MAIO, MA) in (RR) Handover Command */
+private function f_TC_fh_params_handover_cmd(in FHParamsTrx fhp)
+runs on test_CT {
+ var RSL_Message rsl_msg;
+ var RSL_IE_Body ie;
+ var DchanTuple dt;
+
+ /* Establish a dedicated channel, so we can trigger handover */
+ dt := f_est_dchan(f_rnd_ra_cs(), 23, f_rnd_octstring(16));
+
+ /* Trigger handover from BTS0 to BTS1 */
+ f_bts_0_cfg(BSCVTY, { "neighbor bts 1" });
+ f_vty_handover(BSCVTY, 0, 0, dt.rsl_chan_nr, 1);
+
+ /* Expect RSL CHANnel ACTIVation on BTS1/TRX0/TS1 */
+ rsl_msg := f_exp_ipa_rx(1, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+
+ /* ACKnowledge channel activation and expect (RR) Handover Command */
+ f_ipa_tx(1, ts_RSL_CHAN_ACT_ACK(rsl_msg.ies[0].body.chan_nr, 33));
+ rsl_msg := f_exp_ipa_rx(0, tr_RSL_MsgTypeR(RSL_MT_DATA_REQ));
+
+ /* Make sure that L3 Information IE is present */
+ if (not f_rsl_find_ie(rsl_msg, RSL_IE_L3_INFO, ie)) {
+ setverdict(fail, "RSL L3 Information IE is absent");
+ return;
+ }
+
+ /* Decode the L3 message and make sure it is (RR) Handover Command */
+ var GsmRrL3Message l3_msg := dec_GsmRrL3Message(ie.l3_info.payload);
+ if (not match(l3_msg.header, t_RrL3Header(HANDOVER_COMMAND))) {
+ setverdict(fail, "Failed to match Handover Command: ", l3_msg);
+ return;
+ }
+
+ /* Make sure that we've got SDCCH/8 on TS1 (expected to be hopping) */
+ var ChannelDescription chan_desc := l3_msg.payload.ho_cmd.chan_desc;
+ if (not match(chan_desc.chan_nr, t_RslChanNr_SDCCH8(1, ?))) {
+ setverdict(fail, "Unexpected channel number: ", chan_desc.chan_nr);
+ return;
+ }
+
+ /* Make sure that hopping parameters (HSN/MAIO) match */
+ f_TC_fh_params_match_chan_desc(fhp, chan_desc);
+
+ /* Make sure that Cell Channel Description IE is present */
+ if (not ispresent(l3_msg.payload.ho_cmd.cell_chan_desc)) {
+ setverdict(fail, "FH enabled, but Cell Channel Description IE is absent");
+ return;
+ }
+
+ /* Make sure that the Mobile Allocation (after time) IE is present and matches */
+ var boolean ma_present := ispresent(l3_msg.payload.ho_cmd.mobile_allocation);
+ if (ma_present) {
+ f_TC_fh_params_match_ma(fhp, chan_desc.chan_nr.tn,
+ l3_msg.payload.ho_cmd.mobile_allocation.v);
+ } else {
+ setverdict(fail, "FH enabled, but Mobile Allocation IE is absent");
+ return;
+ }
+}
+testcase TC_fh_params_handover_cmd() runs on test_CT {
+ var FHParamsTrx fhp := f_TC_fh_params_gen();
+
+ f_init_vty();
+
+ /* (Re)configure TS0 as BCCH and TS1 as SDCCH8 on BTS1/TRX0 */
+ f_vty_enter_cfg_trx(BSCVTY, bts := 1, trx := 0);
+
+ f_vty_transceive(BSCVTY, "timeslot 0");
+ f_vty_transceive(BSCVTY, "phys_chan_config ccch");
+ f_vty_transceive(BSCVTY, "exit"); /* go back */
+
+ f_vty_transceive(BSCVTY, "timeslot 1");
+ f_vty_transceive(BSCVTY, "phys_chan_config sdcch8");
+ f_vty_transceive(BSCVTY, "end"); /* we're done */
+
+ f_TC_fh_params_set(fhp, 1); /* Enable frequency hopping on BTS1 */
+ f_vty_transceive(BSCVTY, "drop bts connection 1 oml");
+
+ f_init(2);
+
+ f_TC_fh_params_handover_cmd(fhp);
+
+ /* Disable frequency hopping on BTS1 */
+ f_TC_fh_params_unset(fhp, 1);
+
+ /* (Re)configure TS0 as CCCH+SDCCH4+CBCH and TS1 as TCH/F */
+ f_vty_enter_cfg_trx(BSCVTY, bts := 1, trx := 0);
+
+ f_vty_transceive(BSCVTY, "timeslot 0");
+ f_vty_transceive(BSCVTY, "phys_chan_config ccch+sdcch4+cbch");
+ f_vty_transceive(BSCVTY, "exit"); /* go back */
+
+ f_vty_transceive(BSCVTY, "timeslot 1");
+ f_vty_transceive(BSCVTY, "phys_chan_config tch/f");
+ f_vty_transceive(BSCVTY, "end"); /* we're done */
+
+ f_shutdown_helper();
+}
+
+/* Verify the hopping parameters in System Information Type 4 */
+testcase TC_fh_params_si4_cbch() runs on test_CT {
+ var FHParamsTrx fhp := f_TC_fh_params_gen(tr_tn := 1);
+ var ASP_RSL_Unitdata rx_rsl_ud;
+ timer T := 5.0;
+
+ f_init_vty();
+
+ /* (Re)configure TS0 as BCCH and TS1 as SDCCH8+CBCH */
+ f_vty_enter_cfg_trx(BSCVTY, trx := 0);
+
+ f_vty_transceive(BSCVTY, "timeslot 0");
+ f_vty_transceive(BSCVTY, "phys_chan_config ccch");
+ f_vty_transceive(BSCVTY, "exit"); /* go back */
+
+ f_vty_transceive(BSCVTY, "timeslot 1");
+ f_vty_transceive(BSCVTY, "phys_chan_config sdcch8+cbch");
+ f_vty_transceive(BSCVTY, "end"); /* we're done */
+
+ f_TC_fh_params_set(fhp); /* Enable frequency hopping */
+ f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
+
+ f_init(1);
+
+ T.start;
+ alt {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_BCCH_INFO(RSL_SYSTEM_INFO_4))) -> value rx_rsl_ud {
+ var RSL_IE_Body ie := rx_rsl_ud.rsl.ies[2].body; /* FULL BCCH Information IE */
+ var SystemInformation si := dec_SystemInformation(ie.other.payload);
+
+ /* Make sure that what we decoded is System Information Type 4 */
+ if (si.header.message_type != SYSTEM_INFORMATION_TYPE_4) {
+ setverdict(fail, "RSL FULL BCCH Information IE contains: ", si);
+ repeat;
+ }
+
+ /* Make sure that CBCH Channel Description IE is present */
+ if (not ispresent(si.payload.si4.cbch_chan_desc)) {
+ setverdict(fail, "CBCH Channel Description IE is absent");
+ break;
+ }
+
+ /* Finally, check the hopping parameters (HSN, MAIO) */
+ var ChannelDescription chan_desc := si.payload.si4.cbch_chan_desc.v;
+ f_TC_fh_params_match_chan_desc(fhp, chan_desc);
+
+ /* 3GPP TS 44.018, section 9.1.36.2 "CBCH Mobile Allocation":
+ * The CBCH Mobile Allocation IE *shall* be present if FH is enabled. */
+ if (chan_desc.h and not ispresent(si.payload.si4.cbch_mobile_alloc)) {
+ setverdict(fail, "FH enabled, but Mobile Allocation IE is absent");
+ break;
+ } else if (chan_desc.h and ispresent(si.payload.si4.cbch_mobile_alloc)) {
+ f_TC_fh_params_match_ma(fhp, chan_desc.chan_nr.tn,
+ si.payload.si4.cbch_mobile_alloc.v);
+ }
+ }
+ [] IPA_RSL[0].receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for RSL BCCH INFOrmation (SI4)");
+ }
+ }
+
+ /* Disable frequency hopping */
+ f_TC_fh_params_unset(fhp);
+
+ /* (Re)configure TS0 as CCCH+SDCCH4+CBCH and TS1 as TCH/F */
+ f_vty_enter_cfg_trx(BSCVTY, trx := 0);
+
+ f_vty_transceive(BSCVTY, "timeslot 0");
+ f_vty_transceive(BSCVTY, "phys_chan_config ccch+sdcch4+cbch");
+ f_vty_transceive(BSCVTY, "exit"); /* go back */
+
+ f_vty_transceive(BSCVTY, "timeslot 1");
+ f_vty_transceive(BSCVTY, "phys_chan_config tch/f");
+ f_vty_transceive(BSCVTY, "end"); /* we're done */
+
+ f_shutdown_helper();
+}
/* Dyn PDCH todo:
* activate OSMO as TCH/F
@@ -4383,14 +7383,32 @@ control {
execute( TC_ctrl_msc_connection_status() );
execute( TC_ctrl_msc0_connection_status() );
execute( TC_ctrl() );
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_SCCPlite_SERVER) {
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_SCCPlite_SERVER) {
execute( TC_ctrl_location() );
}
+ execute( TC_si_default() );
+ execute( TC_si2quater_2_earfcns() );
+ execute( TC_si2quater_3_earfcns() );
+ execute( TC_si2quater_4_earfcns() );
+ execute( TC_si2quater_5_earfcns() );
+ execute( TC_si2quater_6_earfcns() );
+ execute( TC_si2quater_12_earfcns() );
+ execute( TC_si2quater_23_earfcns() );
+ execute( TC_si2quater_32_earfcns() );
+ execute( TC_si2quater_33_earfcns() );
+ execute( TC_si2quater_42_earfcns() );
+ execute( TC_si2quater_48_earfcns() );
+ execute( TC_si2quater_49_earfcns() );
+ execute( TC_si_acc_rotate() );
+ execute( TC_si_acc_ramp_rotate() );
+
/* RSL DCHAN Channel ACtivation / Deactivation */
execute( TC_chan_act_noreply() );
execute( TC_chan_act_counter() );
execute( TC_chan_act_ack_noest() );
+ execute( TC_chan_act_ack_noest_emerg() );
+ execute( TC_chan_rqd_emerg_deny() );
execute( TC_chan_act_ack_est_ind_noreply() );
execute( TC_chan_act_ack_est_ind_refused() );
execute( TC_chan_act_nack() );
@@ -4403,6 +7421,8 @@ control {
execute( TC_chan_rel_hard_rlsd() );
execute( TC_chan_rel_hard_rlsd_ms_dead() );
execute( TC_chan_rel_a_reset() );
+ execute( TC_chan_rel_sccp_tiar_timeout() );
+ execute( TC_chan_rel_rr_cause() );
execute( TC_outbound_connect() );
@@ -4411,9 +7431,12 @@ control {
execute( TC_assignment_csd() );
execute( TC_assignment_ctm() );
execute( TC_assignment_sign() );
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) {
+ execute( TC_assignment_aoip_tla_v6() );
+ }
execute( TC_assignment_fr_a5_0() );
execute( TC_assignment_fr_a5_1() );
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) {
execute( TC_assignment_fr_a5_1_codec_missing() );
}
execute( TC_assignment_fr_a5_3() );
@@ -4428,7 +7451,7 @@ control {
execute( TC_assignment_codec_amr_f() );
execute( TC_assignment_codec_amr_h() );
- if (mp_bssap_cfg.transport == BSSAP_TRANSPORT_AoIP) {
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) {
execute( TC_assignment_codec_amr_f_S1() );
execute( TC_assignment_codec_amr_h_S1() );
execute( TC_assignment_codec_amr_f_S124() );
@@ -4469,6 +7492,11 @@ control {
execute( TC_rll_est_ind_inval_sapi3() );
execute( TC_rll_est_ind_inval_sacch() );
+ /* SAPI N Reject triggered by RLL establishment failures */
+ execute( TC_rll_rel_ind_sapi_n_reject() );
+ execute( TC_rll_err_ind_sapi_n_reject() );
+ execute( TC_rll_timeout_sapi_n_reject() );
+
/* Paging related tests */
execute( TC_paging_imsi_nochan() );
execute( TC_paging_tmsi_nochan() );
@@ -4499,6 +7527,7 @@ control {
execute( TC_oml_unknown_unit_id() );
execute( TC_classmark() );
+ execute( TC_common_id() );
execute( TC_unsol_ass_fail() );
execute( TC_unsol_ass_compl() );
execute( TC_unsol_ho_fail() );
@@ -4513,6 +7542,9 @@ control {
execute( TC_ho_out_fail_no_result_after_ho_cmd() );
execute( TC_ho_into_this_bsc() );
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) {
+ execute( TC_ho_into_this_bsc_tla_v6() );
+ }
execute( TC_ho_in_fail_msc_clears() );
execute( TC_ho_in_fail_msc_clears_after_ho_detect() );
execute( TC_ho_in_fail_no_detect() );
@@ -4538,10 +7570,46 @@ control {
execute( TC_chopped_ipa_ping() );
execute( TC_chopped_ipa_payload() );
+ /* Power control related */
+ execute( TC_assignment_verify_ms_power_params_ie() );
+
+ /* MSC pooling */
+ /* FIXME: in SCCPlite, indicating how many MSCs should be connected does currently not work. Since
+ * RESET->RESET-ACK is unconditionally negotiated for all configured MSCs, they always all appear as connected
+ * to osmo-bsc. The MSC pooling tests however require disconnecting selected MSCs, and hence don't work out as
+ * intended on SCCPlite. So for now, run these only for SCCP/M3UA. */
+ if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) {
+ execute( TC_mscpool_L3Compl_on_1_msc() );
+ execute( TC_mscpool_L3Complete_by_imsi_round_robin() );
+ execute( TC_mscpool_LU_by_tmsi_null_nri_0_round_robin() );
+ execute( TC_mscpool_LU_by_tmsi_null_nri_1_round_robin() );
+ execute( TC_mscpool_L3Complete_by_tmsi_unassigned_nri_round_robin() );
+ execute( TC_mscpool_L3Complete_by_tmsi_valid_nri_msc_not_connected_round_robin() );
+ execute( TC_mscpool_L3Complete_by_tmsi_valid_nri_1() );
+ execute( TC_mscpool_L3Complete_by_tmsi_valid_nri_2() );
+ execute( TC_mscpool_LU_by_tmsi_from_other_PLMN() );
+ execute( TC_mscpool_paging_and_response_imsi() );
+ execute( TC_mscpool_paging_and_response_tmsi() );
+ execute( TC_mscpool_no_allow_attach_round_robin() );
+ execute( TC_mscpool_no_allow_attach_valid_nri() );
+ }
+
/* at bottom as they might crash OsmoBSC before OS#3182 is fixed */
execute( TC_early_conn_fail() );
execute( TC_late_conn_fail() );
+ /* Emergency call handling (deny / allow) */
+ execute( TC_assignment_emerg_setup_allow() );
+ execute( TC_assignment_emerg_setup_deny_msc() );
+ execute( TC_assignment_emerg_setup_deny_bts() );
+ execute( TC_emerg_premption() );
+
+ /* Frequency hopping parameters handling */
+ execute( TC_fh_params_chan_activ() );
+ execute( TC_fh_params_imm_ass() );
+ execute( TC_fh_params_assignment_cmd() );
+ execute( TC_fh_params_handover_cmd() );
+ execute( TC_fh_params_si4_cbch() );
}
}
diff --git a/bsc/BSC_Tests_CBSP.ttcn b/bsc/BSC_Tests_CBSP.ttcn
index 1922102..3dd6f02 100644
--- a/bsc/BSC_Tests_CBSP.ttcn
+++ b/bsc/BSC_Tests_CBSP.ttcn
@@ -25,6 +25,10 @@ import from IPA_Emulation all;
import from IPA_CodecPort all;
import from IPA_Types all;
+import from MobileL3_Types all;
+import from MobileL3_RRM_Types all;
+import from L3_Templates all;
+
import from RSL_Types all;
import from RSL_Emulation all;
@@ -33,19 +37,22 @@ import from CBSP_Templates all;
import from CBSP_Adapter all;
import from CBSP_CodecPort all;
+import from Osmocom_VTY_Functions all;
+import from TELNETasp_PortType all;
+
modulepar {
charstring mp_cbc_ip := "0.0.0.0";
integer mp_cbc_port := 48049;
integer mp_bsc_cbsp_port := 48050;
- /* BTS 0: 262-42-1-0 with CBCH
- * BTS 1: 262-42-1-1 with CBCH
- * BTS 2: 262-42-2-1 with CBCH
- * BTS 3: 262-42-2-3 without CBCH */
- GsmCgiAbstract mp_cgi_bts0 := { '262'H, '42'H, 1, 0 };
- GsmCgiAbstract mp_cgi_bts1 := { '262'H, '42'H, 1, 1 };
- GsmCgiAbstract mp_cgi_bts2 := { '262'H, '42'H, 2, 1 };
- GsmCgiAbstract mp_cgi_bts3 := { '262'H, '42'H, 2, 3 };
+ /* BTS 0: 001-01-1-0 with CBCH
+ * BTS 1: 001-01-1-1 with CBCH
+ * BTS 2: 001-01-2-1 with CBCH
+ * BTS 3: 001-01-2-3 without CBCH */
+ GsmCgiAbstract mp_cgi_bts0 := { '001'H, '01'H, 1, 0 };
+ GsmCgiAbstract mp_cgi_bts1 := { '001'H, '01'H, 1, 1 };
+ GsmCgiAbstract mp_cgi_bts2 := { '001'H, '01'H, 2, 1 };
+ GsmCgiAbstract mp_cgi_bts3 := { '001'H, '01'H, 2, 3 };
}
private type record GsmCgiAbstract {
@@ -64,33 +71,50 @@ private template (value) OCT2 bssmap_lac(GsmCgiAbstract cgi) := ts_BSSMAP_CI_LAC
private template (value) OCT2 bssmap_ci(GsmCgiAbstract cgi) := ts_BSSMAP_CI_CI(cgi.ci);
type component cbsp_test_CT extends test_CT, CBSP_Adapter_CT {
+ var uint16_t g_cbsp_msg_id := 0;
+ var uint16_t g_cbsp_ser_no := 0;
+}
+
+private function f_g_cbsp_next_msg_id_ser_no() runs on cbsp_test_CT
+{
+ g_cbsp_msg_id := g_cbsp_msg_id + 1;
+ g_cbsp_ser_no := g_cbsp_ser_no + 1;
+ log("g_cbsp_msg_id=", g_cbsp_msg_id, " g_cbsp_ser_no=", g_cbsp_ser_no);
}
-private altstep as_IgnRSL(template RSL_Message tr) runs on cbsp_test_CT {
-[] IPA_RSL[0].receive(tr_RSL_UD(tr)) { repeat; }
-[] IPA_RSL[1].receive(tr_RSL_UD(tr)) { repeat; }
-[] IPA_RSL[2].receive(tr_RSL_UD(tr)) { repeat; }
+private altstep as_IgnRSL(template (present) RSL_Message tr) runs on cbsp_test_CT {
+[] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr)) { repeat; }
+[] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr)) { repeat; }
+[] IPA_RSL[2].receive(tr_ASP_RSL_UD(tr)) { repeat; }
}
private altstep as_FailRSL() runs on cbsp_test_CT {
-var template RSL_Message tr := (tr_RSL_SMSCB_CMD);
+var template (present) RSL_Message tr := (tr_RSL_SMSCB_CMD);
var ASP_RSL_Unitdata rx;
-[] IPA_RSL[0].receive(tr_RSL_UD(tr)) -> value rx {
+[] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr)) -> value rx {
setverdict(fail, "Received unexpected RSL ", rx);
mtc.stop;
}
-[] IPA_RSL[1].receive(tr_RSL_UD(tr)) -> value rx {
+[] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr)) -> value rx {
setverdict(fail, "Received unexpected RSL ", rx);
mtc.stop;
}
-[] IPA_RSL[2].receive(tr_RSL_UD(tr)) -> value rx {
+[] IPA_RSL[2].receive(tr_ASP_RSL_UD(tr)) -> value rx {
setverdict(fail, "Received unexpected RSL ", rx);
mtc.stop;
}
}
-private function f_init() runs on cbsp_test_CT {
- BSC_Tests.f_init();
+private function f_vty_set_cbsp_mode(TELNETasp_PT pt, charstring mode) {
+ f_vty_enter_config(pt);
+ f_vty_transceive(pt, "cbc");
+ f_vty_transceive(pt, "mode " & mode);
+ f_vty_transceive(pt, "exit");
+ f_vty_transceive(pt, "exit");
+}
+
+private function f_init(float guard_timeout := 30.0) runs on cbsp_test_CT {
+ BSC_Tests.f_init(guard_timeout := guard_timeout);
activate(as_IgnRSL((tr_RSL_BCCH_INFO, tr_RSL_SACCH_FILL,
tr_RSL_NO_BCCH_INFO, tr_RSL_NO_SACCH_FILL,
tr_RSL_MsgTypeD(?))));
@@ -98,15 +122,20 @@ private function f_init() runs on cbsp_test_CT {
}
private function f_cbsp_init_client() runs on cbsp_test_CT {
f_init();
+ f_vty_set_cbsp_mode(BSCVTY, "server");
CBSP_Adapter.f_connect(mp_bsc_ip, mp_bsc_cbsp_port, "", -1);
- f_cbsp_init_tail();
+ CBSP[0].receive(tr_CBSP_Recv(?, tr_CBSP_RESTART(?, CBSP_BC_MSGT_CBS, ?)));
+ setverdict(pass);
}
-private function f_cbsp_init_server() runs on cbsp_test_CT {
+private function f_cbsp_init_server(uint16_t cbsp_msg_id, uint16_t cbsp_ser_no, float guard_timeout := 30.0) runs on cbsp_test_CT {
var ASP_Event asp_evt;
timer T := 10.0;
- f_init();
+ f_init(guard_timeout := guard_timeout);
+
+ f_vty_set_cbsp_mode(BSCVTY, "client");
+
CBSP_Adapter.f_bind(mp_cbc_ip, mp_cbc_port);
T.start;
@@ -116,11 +145,18 @@ private function f_cbsp_init_server() runs on cbsp_test_CT {
}
[] T.timeout {
setverdict(fail, "Timeout waiting for incoming connection to CBSP Port");
+ mtc.stop;
}
}
- f_cbsp_init_tail();
+ f_expect_cbsp_restart();
+
+ g_cbsp_msg_id := cbsp_msg_id;
+ g_cbsp_ser_no := cbsp_ser_no;
+ log("g_cbsp_msg_id=", g_cbsp_msg_id, " g_cbsp_ser_no=", g_cbsp_ser_no);
+
+ f_cbsp_reset_bss(0);
}
-private function f_cbsp_init_tail() runs on cbsp_test_CT {
+private function f_expect_cbsp_restart() runs on cbsp_test_CT {
interleave {
[] CBSP[0].receive(tr_CBSP_Recv(?, tr_CBSP_RESTART(?, CBSP_BC_MSGT_CBS, CBSP_RI_DATA_LOST)));
/* should we also expect a restart for emergency related messages? */
@@ -128,13 +164,25 @@ private function f_cbsp_init_tail() runs on cbsp_test_CT {
}
}
-function f_gen_page() return CBSP_IE {
- var integer len := f_rnd_int(82);
- var octetstring payload := f_rnd_octstring(len);
- return valueof(ts_CbspMsgContent(payload, len));
+/* Generate a CBSP payload: random size for payload_len == 0, or specific fixed size for payload_len > 0. */
+function f_gen_page(integer payload_len := 0) return CBSP_IE {
+ if (payload_len < 1) {
+ /* The maximum CBSP page payload space is 88, but 6 bytes of payload header are added in the first page:
+ * the maximum length generated here thus is 82. The minimum generated length is 1 (avoiding zero
+ * length). Note, f_rnd_int(82) returns [0..81], so this results in a len ranging [1..82]: */
+ payload_len := 1 + f_rnd_int(82);
+ }
+ log("Generating CBSP payload: ", payload_len, " octets");
+ var octetstring payload := f_rnd_octstring(payload_len);
+ return valueof(ts_CbspMsgContent(payload, payload_len));
}
-function f_cbsp_reset_bss(integer idx) runs on CBSP_Adapter_CT {
+function f_cbsp_reset_bss(integer idx) runs on cbsp_test_CT {
+ /* Make sure no CBSP ETWS commands from a previous CBSP test remain in the RSL queue */
+ IPA_RSL[0].clear;
+ IPA_RSL[1].clear;
+ IPA_RSL[2].clear;
+
var template (value) CBSP_PDU tx;
timer T := 3.0;
tx := ts_CBSP_RESET(cell_list := ts_BSSMAP_CIL_BSS);
@@ -152,6 +200,18 @@ function f_cbsp_reset_bss(integer idx) runs on CBSP_Adapter_CT {
mtc.stop;
}
}
+
+ f_cbsp_expect_disable_etws_pn_broadcast();
+}
+
+function f_cbsp_expect_disable_etws_pn_broadcast() runs on cbsp_test_CT
+{
+ var template ASP_RSL_Unitdata zero_payload := tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(t_RslChanNr_PCH_AGCH(0), ''O));
+ interleave {
+ [] IPA_RSL[0].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 0"); }
+ [] IPA_RSL[1].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 1"); }
+ [] IPA_RSL[2].receive(zero_payload) { log("CBSP: disabled ETWS PN broadcast on bts 2"); }
+ }
}
/* send a WRITE CBS to the BSC; expect either COMPLETE or FAILURE in response*/
@@ -179,6 +239,7 @@ function f_cbsp_write_emerg(uint16_t msg_id, uint16_t ser_no,
}
[] CBSP[0].receive(tr_CBSP_Recv(g_cbsp_conn_id[0], ?)) {
setverdict(fail, "Received unexpected CBSP");
+ mtc.stop;
}
}
}
@@ -193,7 +254,6 @@ function f_cbsp_write(uint16_t msg_id, uint16_t ser_no,
template CBSP_FailureListItems fail_list := omit) runs on cbsp_test_CT {
var template (value) CBSP_PDU tx;
var template CBSP_PDU rx;
- var CBSP_IEs pages := {f_gen_page()};
tx := ts_CBSP_WRITE_CBS(msg_id, ser_no, cell_list, channel_ind, category,
rep_period, num_bcast_req, dcs, content);
@@ -209,6 +269,7 @@ function f_cbsp_write(uint16_t msg_id, uint16_t ser_no,
}
[] CBSP[0].receive(tr_CBSP_Recv(g_cbsp_conn_id[0], ?)) {
setverdict(fail, "Received unexpected CBSP");
+ mtc.stop;
}
}
}
@@ -223,7 +284,6 @@ function f_cbsp_replace(uint16_t msg_id, uint16_t new_ser_no, uint16_t old_ser_n
template CBSP_FailureListItems fail_list := omit) runs on cbsp_test_CT {
var template (value) CBSP_PDU tx;
var template CBSP_PDU rx;
- var CBSP_IEs pages := {f_gen_page()};
tx := ts_CBSP_REPLACE_CBS(msg_id, new_ser_no, old_ser_no, cell_list, channel_ind, category,
rep_period, num_bcast_req, dcs, content);
@@ -241,6 +301,7 @@ function f_cbsp_replace(uint16_t msg_id, uint16_t new_ser_no, uint16_t old_ser_n
}
[] CBSP[0].receive(tr_CBSP_Recv(g_cbsp_conn_id[0], ?)) {
setverdict(fail, "Received unexpected CBSP");
+ mtc.stop;
}
}
}
@@ -268,15 +329,11 @@ function f_cbsp_kill(uint16_t msg_id, uint16_t ser_no, template (omit) uint8_t c
}
[] CBSP[0].receive(tr_CBSP_Recv(g_cbsp_conn_id[0], ?)) {
setverdict(fail, "Received unexpected CBSP");
+ mtc.stop;
}
}
}
-private template (present) ASP_RSL_Unitdata tr_RSL_UD(template (present) RSL_Message rsl) := {
- streamId := ?,
- rsl := rsl
-}
-
template (present) RSL_IE_CbCommandType
tr_RslCbCmdType(template (present) uint2_t lblock := ?, template (present) RSL_CbCommand cmd := ?) := {
command := cmd,
@@ -285,17 +342,43 @@ tr_RslCbCmdType(template (present) uint2_t lblock := ?, template (present) RSL_C
last_block := lblock
}
+/* translate blocks count to RSL_CB_CMD_LASTBLOCK_1..4 values */
+private function f_cbsp_block_count_enc(integer num_blocks) return integer
+{
+ if (num_blocks < 1 or num_blocks > 4) {
+ setverdict(fail, "Invalid num_blocks: ", num_blocks);
+ mtc.stop;
+ }
+ if (num_blocks == 4) {
+ return 0;
+ }
+ return num_blocks;
+}
+
/* build a RSL_Message receive template from a CBSP page */
-private function f_page2rsl(CBSP_IE page, uint16_t msg_id, uint16_t ser_no, boolean ext_cbch := false)
+private function f_page2rsl(CBSP_IE page, uint16_t msg_id, uint16_t ser_no, boolean ext_cbch := false,
+ template (present) integer expect_blocks := ?)
return template (present) RSL_Message
{
- var template RSL_Message tr;
- var integer lblock := page.body.msg_content.user_len / 22;
+ var template (present) RSL_Message tr;
+ var integer len;
+ var integer num_blocks;
var octetstring payload;
- if (page.body.msg_content.user_len mod 22 > 0) {
- lblock := lblock + 1;
- }
+
payload := int2oct(ser_no, 2) & int2oct(msg_id, 2) & '0011'O & page.body.msg_content.val;
+ len := lengthof(payload);
+ num_blocks := len / 22;
+ if (len mod 22 > 0) {
+ num_blocks := num_blocks + 1;
+ }
+
+ if (not istemplatekind(expect_blocks, "omit") and not match(num_blocks, expect_blocks)) {
+ setverdict(fail, "mismatch: CBSP page expect_blocks == ", expect_blocks, ", but generated num_blocks == ", num_blocks);
+ mtc.stop;
+ }
+
+ var integer lblock := f_cbsp_block_count_enc(num_blocks);
+
tr := tr_RSL_SMSCB_CMD(tr_RslCbCmdType(lblock), f_pad_oct(payload, 88, '00'O));
if (ext_cbch) {
tr.ies[3] := tr_RSL_IE(RSL_IE_Body:{smscb_chan_ind := 1});
@@ -316,13 +399,13 @@ testcase TC_cbsp_bsc_server() runs on cbsp_test_CT {
/* Test if BSC (client) is connecting to CBC (server) */
testcase TC_cbsp_bsc_client() runs on cbsp_test_CT {
- f_cbsp_init_server();
+ f_cbsp_init_server(0, 0);
setverdict(pass);
}
/* Test if a BSS-global RESET is executed successfully */
testcase TC_cbsp_reset_bss() runs on cbsp_test_CT {
- f_cbsp_init_server();
+ f_cbsp_init_server(0, 0);
f_cbsp_reset_bss(0);
setverdict(pass);
@@ -331,7 +414,7 @@ testcase TC_cbsp_reset_bss() runs on cbsp_test_CT {
testcase TC_cbsp_write() runs on cbsp_test_CT {
var template (value) CBSP_PDU tx;
var CBSP_IEs pages := {f_gen_page()};
- f_cbsp_init_server();
+ f_cbsp_init_server(0, 0);
tx := ts_CBSP_WRITE_CBS(msg_id:=23, new_ser_nr:=42, cell_list:=ts_BSSMAP_CIL_BSS,
channel_ind:=0, category:=CBSP_CATEG_NORMAL,
@@ -343,20 +426,49 @@ testcase TC_cbsp_write() runs on cbsp_test_CT {
}
/* Write to entire BSS; three cells succeed; one fails (no CBCH) */
-testcase TC_cbsp_write_bss() runs on cbsp_test_CT {
- var CBSP_IEs pages := {f_gen_page()};
+function f_tc_cbsp_write_bss(integer payload_len := -1, template (present) integer expect_blocks) runs on cbsp_test_CT {
+ var CBSP_IEs pages := {f_gen_page(payload_len := payload_len)};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_BSS;
- f_cbsp_init_server();
- f_cbsp_write(1, 1001, cell_list, content:=pages,
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=tr_BSSMAP_CIL_CGI({?,?,?}), fail_list:={?});
- var template RSL_Message tr := f_page2rsl(pages[0], 1, 1001);
+ var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no, expect_blocks := expect_blocks);
+ log("RSL[0,1,2] EXPECTING ", tr_ASP_RSL_UD(tr));
interleave {
- [] IPA_RSL[0].receive(tr_RSL_UD(tr)) {}
- [] IPA_RSL[1].receive(tr_RSL_UD(tr)) {}
- [] IPA_RSL[2].receive(tr_RSL_UD(tr)) {}
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[0]"); }
+ [] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[1]"); }
+ [] IPA_RSL[2].receive(tr_ASP_RSL_UD(tr)) { log("Got SMSCB CMD on RSL[2]"); }
}
+ setverdict(pass);
+
+ /* Make the next test run (if any) use different msg_id and ser_no */
+ f_g_cbsp_next_msg_id_ser_no();
+}
+testcase TC_cbsp_write_bss() runs on cbsp_test_CT {
+ f_cbsp_init_server(1001, 1501, guard_timeout := 60.0);
+ /* In the SMSCB message, there is a head followed by payload,
+ * and the resulting data is segmented in blocks of 22 octets (<= 4 blocks).
+ *
+ * [head][...payload....]|[....................]|[....................]|[....................]
+ * 0 |16 |38 |60 |82
+ * 0 5 |22 |44 |66 |88
+ *
+ * blocks count: 1 | 2 | 3 | 4
+ * payload octets count: 1..16 | 17..38 | 39..60 | 61..82
+ */
+ f_tc_cbsp_write_bss(payload_len := 1, expect_blocks := 1);
+ f_tc_cbsp_write_bss(payload_len := 2, expect_blocks := 1);
+ f_tc_cbsp_write_bss(payload_len := 16, expect_blocks := 1);
+ f_tc_cbsp_write_bss(payload_len := 17, expect_blocks := 2);
+ f_tc_cbsp_write_bss(payload_len := 23, expect_blocks := 2);
+ f_tc_cbsp_write_bss(payload_len := 38, expect_blocks := 2);
+ f_tc_cbsp_write_bss(payload_len := 39, expect_blocks := 3);
+ f_tc_cbsp_write_bss(payload_len := 42, expect_blocks := 3);
+ f_tc_cbsp_write_bss(payload_len := 60, expect_blocks := 3);
+ f_tc_cbsp_write_bss(payload_len := 61, expect_blocks := 4);
+ f_tc_cbsp_write_bss(payload_len := 77, expect_blocks := 4);
+ f_tc_cbsp_write_bss(payload_len := 82, expect_blocks := 4);
}
/* Write to single BTS supporting CBCH: success */
@@ -364,11 +476,11 @@ testcase TC_cbsp_write_bts_cgi() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_CGI({bssmap_cgi(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(2, 1002, cell_list, content:=pages,
+ f_cbsp_init_server(2001, 2501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=cell_list, fail_list:=omit);
- var template RSL_Message tr := f_page2rsl(pages[0], 1, 1001);
- IPA_RSL[0].receive(tr_RSL_UD(tr));
+ var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no);
+ IPA_RSL[0].receive(tr_ASP_RSL_UD(tr));
f_sleep(5.0);
}
@@ -377,8 +489,8 @@ testcase TC_cbsp_write_bts_no_cbch() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_CGI({bssmap_cgi(mp_cgi_bts3)});
- f_cbsp_init_server();
- f_cbsp_write(3, 1003, cell_list, content:=pages,
+ f_cbsp_init_server(3001, 3501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=omit, fail_list:={?});
f_sleep(5.0);
}
@@ -388,8 +500,8 @@ testcase TC_cbsp_write_unknown_bts() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_CGI({ts_BSSMAP_CI_CGI(mp_cgi_bts0.mcc, mp_cgi_bts1.mnc, 22222, 33333)});
- f_cbsp_init_server();
- f_cbsp_write(4, 1004, cell_list, content:=pages,
+ f_cbsp_init_server(4001, 4501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=omit, fail_list:={?});
f_sleep(5.0);
}
@@ -399,10 +511,10 @@ testcase TC_cbsp_write_lac_ci() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(5, 1005, cell_list, content:=pages,
+ f_cbsp_init_server(5001, 5501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=?, fail_list:=omit);
- IPA_RSL[0].receive(tr_RSL_UD(f_page2rsl(pages[0], 5, 1005)));
+ IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
f_sleep(5.0);
}
@@ -411,10 +523,10 @@ testcase TC_cbsp_write_ci() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_CI({bssmap_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(6, 1006, cell_list, content:=pages,
+ f_cbsp_init_server(6001, 6501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=?, fail_list:=omit);
- IPA_RSL[0].receive(tr_RSL_UD(f_page2rsl(pages[0], 6, 1006)));
+ IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
f_sleep(5.0);
}
@@ -422,11 +534,15 @@ testcase TC_cbsp_write_ci() runs on cbsp_test_CT {
testcase TC_cbsp_write_lai() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
- cell_list := ts_BSSMAP_CIL_LAI({bssmap_lai(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(7, 1007, cell_list, content:=pages,
+ /* bts0 and bts1 have the same LAI (only differ in cell identity).
+ * bts2 and bts3 also have the same LAI, but only bts2 has a CBCH.
+ * Target only bts2.
+ */
+ cell_list := ts_BSSMAP_CIL_LAI({bssmap_lai(mp_cgi_bts2)});
+ f_cbsp_init_server(7001, 7501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=?, fail_list:=omit);
- IPA_RSL[0].receive(tr_RSL_UD(f_page2rsl(pages[0], 7, 1007)));
+ IPA_RSL[2].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
f_sleep(5.0);
}
@@ -435,13 +551,13 @@ testcase TC_cbsp_write_lac() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC({bssmap_lac(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(8, 1008, cell_list, content:=pages,
+ f_cbsp_init_server(8001, 8501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages,
success_list:=?, fail_list:=omit);
- var template RSL_Message tr := f_page2rsl(pages[0], 8, 1008);
+ var template (present) RSL_Message tr := f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no);
interleave {
- [] IPA_RSL[0].receive(tr_RSL_UD(tr));
- [] IPA_RSL[1].receive(tr_RSL_UD(tr));
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr));
+ [] IPA_RSL[1].receive(tr_ASP_RSL_UD(tr));
}
f_sleep(5.0);
}
@@ -451,11 +567,21 @@ testcase TC_cbsp_write_then_replace() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(9, 1009, cell_list, num_bcast_req:=10, content:=pages,
+ f_cbsp_init_server(9001, 9501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, num_bcast_req:=10, content:=pages,
success_list:=?, fail_list:=omit);
- f_cbsp_replace(9, 2009, 1009, cell_list, content:=pages,
+
+ IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
+
+ /* Replace: keep the same msg_id, use a new ser_no */
+ var uint16_t old_ser_no := g_cbsp_ser_no;
+ g_cbsp_ser_no := g_cbsp_ser_no + 1;
+ f_cbsp_replace(g_cbsp_msg_id, g_cbsp_ser_no, old_ser_no, cell_list, content:=pages,
success_list:=?, fail_list:=omit);
+
+ IPA_RSL[0].receive(tr_ASP_RSL_UD(f_page2rsl(pages[0], g_cbsp_msg_id, g_cbsp_ser_no)));
+ f_sleep(1.0);
+ setverdict(pass);
}
/* Replace a message that doesn't exist: failure */
@@ -463,8 +589,8 @@ testcase TC_cbsp_replace_nonexist() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_replace(10, 2010, 1010, cell_list, content:=pages,
+ f_cbsp_init_server(10001, 10501);
+ f_cbsp_replace(10, 10023, 10042, cell_list, content:=pages,
success_list:=omit, fail_list:=?);
}
@@ -474,8 +600,8 @@ testcase TC_cbsp_write_too_many() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page(), f_gen_page(), f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(11, 1011, cell_list, rep_period:=1, content:=pages,
+ f_cbsp_init_server(11001, 11501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, rep_period:=1, content:=pages,
success_list:=omit, fail_list:=?);
}
@@ -484,17 +610,17 @@ testcase TC_cbsp_kill_nonexist() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_kill(12, 1012, 0, cell_list, success_list:=omit, fail_list:=?);
+ f_cbsp_init_server(12001, 12501);
+ f_cbsp_kill(g_cbsp_msg_id, g_cbsp_ser_no, 0, cell_list, success_list:=omit, fail_list:=?);
}
/* Write a message, then kill it */
testcase TC_cbsp_write_then_kill() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(13, 1013, cell_list, content:=pages, success_list:=?, fail_list:=omit);
- f_cbsp_kill(13, 1013, 0, cell_list, success_list:=?, fail_list:=omit);
+ f_cbsp_init_server(13001, 13501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages, success_list:=?, fail_list:=omit);
+ f_cbsp_kill(g_cbsp_msg_id, g_cbsp_ser_no, 0, cell_list, success_list:=?, fail_list:=omit);
}
/* Write a message, then reset all messages */
@@ -502,22 +628,140 @@ testcase TC_cbsp_write_then_reset() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
cell_list := ts_BSSMAP_CIL_LAC_CI({bssmap_lac_ci(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write(14, 1014, cell_list, content:=pages, success_list:=?, fail_list:=omit);
+ f_cbsp_init_server(14001, 14501);
+ f_cbsp_write(g_cbsp_msg_id, g_cbsp_ser_no, cell_list, content:=pages, success_list:=?, fail_list:=omit);
f_cbsp_reset_bss(0);
}
-/* Write to single BTS supporting CBCH: success */
-testcase TC_cbsp_emerg_write_bts_cgi() runs on cbsp_test_CT {
+private const octetstring c_ETWS_sec_default :=
+ '00000000000000000000000000000000000000000000000000'O &
+ '00000000000000000000000000000000000000000000000000'O;
+function f_gen_etws_pn(uint16_t ser_nr, uint16_t msg_id, OCT2 msg_type := '0780'O,
+ octetstring sec_inf := c_ETWS_sec_default) return octetstring {
+ return int2oct(ser_nr, 2) & int2oct(msg_id, 2) & msg_type & sec_inf;
+}
+
+/* Write ETWS PN to single BTS; verify it arrives on DCHAN */
+testcase TC_cbsp_emerg_write_bts_cgi_dchan() runs on cbsp_test_CT {
var CBSP_IEs pages := {f_gen_page()};
var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
+ var ASP_RSL_Unitdata rx_rsl_ud;
+
cell_list := ts_BSSMAP_CIL_CGI({bssmap_cgi(mp_cgi_bts0)});
- f_cbsp_init_server();
- f_cbsp_write_emerg(15, 1015, cell_list);
- f_sleep(5.0);
+ f_cbsp_init_server(15001, 15501);
+
+ /* first establish a dedicated channel */
+ var DchanTuple dt := f_est_dchan('23'O, 23, '00010203040506'O);
+
+ /* then send ETWS PN */
+ f_cbsp_write_emerg(g_cbsp_msg_id, g_cbsp_ser_no, cell_list);
+ var template (present) octetstring tr_apdu := f_gen_etws_pn(g_cbsp_msg_id, g_cbsp_ser_no);
+ timer T := 5.0;
+ T.start;
+ alt {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_DATA_REQ(dt.rsl_chan_nr, ?, ?))) -> value rx_rsl_ud {
+ var RSL_IE_Body l3_ie;
+ if (f_rsl_find_ie(rx_rsl_ud.rsl, RSL_IE_L3_INFO, l3_ie) == false) {
+ setverdict(fail, "RSL DATA REQ without L3?");
+ mtc.stop;
+ }
+ var PDU_ML3_NW_MS l3 := dec_PDU_ML3_NW_MS(l3_ie.l3_info.payload);
+ var template (present) APDU_Flags_V tr_flags := {
+ lastSeg := '0'B,
+ firstSeg := '0'B,
+ cR := '0'B,
+ spare := '0'B
+ };
+ if (match(l3, tr_RR_APP_INFO('0001'B, tr_apdu, tr_flags))) {
+ setverdict(pass);
+ }
+ }
+ [] IPA_RSL[0].receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Waiting for APP INFO");
+ }
+ }
+}
+
+/* Write ETWS PN to single BTS; verify it arrives on CCHAN */
+testcase TC_cbsp_emerg_write_bts_cgi_cchan() runs on cbsp_test_CT {
+ var CBSP_IEs pages := {f_gen_page()};
+ var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
+ var ASP_RSL_Unitdata rx_rsl_ud;
+
+ cell_list := ts_BSSMAP_CIL_CGI({bssmap_cgi(mp_cgi_bts0)});
+ f_cbsp_init_server(16001, 16501);
+
+ f_cbsp_write_emerg(g_cbsp_msg_id, g_cbsp_ser_no, cell_list);
+ var template (present) octetstring tr_apdu := f_gen_etws_pn(g_cbsp_ser_no, g_cbsp_msg_id);
+ timer T := 5.0;
+ T.start;
+ alt {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(t_RslChanNr_PCH_AGCH(0), tr_apdu))) {
+ setverdict(pass);
+ }
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(?,?))) {
+ setverdict(fail, "Received unexpected OSMO_ETWS_CMD");
+ mtc.stop;
+ }
+ [] IPA_RSL[0].receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for RSL_OSMO_ETWS_CMD");
+ mtc.stop;
+ }
+ }
+}
+
+/* Write ETWS PN to single BTS; verify it arrives on CCHAN */
+testcase TC_cbsp_emerg_write_bts_cgi_cchan_disable() runs on cbsp_test_CT {
+ var CBSP_IEs pages := {f_gen_page()};
+ var template (value) BSSMAP_FIELD_CellIdentificationList cell_list;
+ var ASP_RSL_Unitdata rx_rsl_ud;
+
+ cell_list := ts_BSSMAP_CIL_CGI({bssmap_cgi(mp_cgi_bts0)});
+ f_cbsp_init_server(17001, 17501);
+
+ f_cbsp_write_emerg(g_cbsp_msg_id, g_cbsp_ser_no, cell_list);
+
+ /* first expect the PN to be enabled */
+ var template (present) octetstring tr_apdu := f_gen_etws_pn(g_cbsp_ser_no, g_cbsp_msg_id);
+ timer T := 5.0;
+ T.start;
+ alt {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(t_RslChanNr_PCH_AGCH(0), tr_apdu))) {
+ setverdict(pass);
+ }
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(?,?))) {
+ setverdict(fail, "Received unexpected OSMO_ETWS_CMD");
+ mtc.stop;
+ }
+ [] IPA_RSL[0].receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for RSL_OSMO_ETWS_CMD (enable)");
+ mtc.stop;
+ }
+ }
+
+ /* then expect it to be disabled after the warning period (5s) */
+ T.start;
+ alt {
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(t_RslChanNr_PCH_AGCH(0), ''O))) {
+ setverdict(pass);
+ }
+ [] IPA_RSL[0].receive(tr_ASP_RSL_UD(tr_RSL_OSMO_ETWS_CMD(?,?))) {
+ setverdict(fail, "Received unexpected OSMO_ETWS_CMD");
+ mtc.stop;
+ }
+ [] IPA_RSL[0].receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for RSL_OSMO_ETWS_CMD (disable)");
+ mtc.stop;
+ }
+ }
}
+
control {
execute( TC_cbsp_bsc_server() );
execute( TC_cbsp_bsc_client() );
@@ -539,6 +783,10 @@ control {
execute( TC_cbsp_kill_nonexist() );
execute( TC_cbsp_write_then_kill() );
execute( TC_cbsp_write_then_reset() );
+
+ execute( TC_cbsp_emerg_write_bts_cgi_dchan() );
+ execute( TC_cbsp_emerg_write_bts_cgi_cchan() );
+ execute( TC_cbsp_emerg_write_bts_cgi_cchan_disable() );
}
diff --git a/bsc/BSC_Tests_LCLS.ttcn b/bsc/BSC_Tests_LCLS.ttcn
index 6087133..72fb525 100644
--- a/bsc/BSC_Tests_LCLS.ttcn
+++ b/bsc/BSC_Tests_LCLS.ttcn
@@ -161,8 +161,8 @@ runs on LCLS_MSC_ConnHdlr {
/* helper function to create and connect a MSC_ConnHdlr component */
/* FIXME: Why can't we use BSC_Tests.f_connect_andler() ?!? */
-private function f_connect_handler(inout LCLS_MSC_ConnHdlr vc_conn) runs on lcls_test_CT {
- connect(vc_conn:RAN, g_bssap.vc_RAN:PROC);
+private function f_connect_handler(inout LCLS_MSC_ConnHdlr vc_conn, integer bssap_idx := 0) runs on lcls_test_CT {
+ connect(vc_conn:RAN, g_bssap[bssap_idx].vc_RAN:PROC);
connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC);
connect(vc_conn:RSL, bts[0].rsl.vc_RSL:CLIENT_PT);
connect(vc_conn:RSL_PROC, bts[0].rsl.vc_RSL:RSL_PROC);
@@ -170,7 +170,7 @@ private function f_connect_handler(inout LCLS_MSC_ConnHdlr vc_conn) runs on lcls
connect(vc_conn:RSL1, bts[1].rsl.vc_RSL:CLIENT_PT);
connect(vc_conn:RSL1_PROC, bts[1].rsl.vc_RSL:RSL_PROC);
}
- connect(vc_conn:BSSAP, g_bssap.vc_RAN:CLIENT);
+ connect(vc_conn:BSSAP, g_bssap[bssap_idx].vc_RAN:CLIENT);
connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT);
}
diff --git a/bsc/MSC_ConnectionHandler.ttcn b/bsc/MSC_ConnectionHandler.ttcn
index 57706c9..76a56fc 100644
--- a/bsc/MSC_ConnectionHandler.ttcn
+++ b/bsc/MSC_ConnectionHandler.ttcn
@@ -30,6 +30,8 @@ import from MGCP_Templates all;
import from MGCP_Emulation all;
import from SDP_Types all;
+import from StatsD_Checker all;
+
import from RSL_Emulation all;
import from RSL_Types all;
@@ -277,6 +279,7 @@ function f_rx_crcx(MgcpCommand mgcp_cmd)
var MgcpOsmuxCID osmux_cid;
var SDP_Message sdp;
var integer cid := f_get_free_mgcp_conn();
+ var charstring local_rtp_addr := host_mgw_rtp_v6; /* Use IPv6 by default if no remote addr is provided by client */
if (match(mgcp_cmd.line.ep, t_MGCP_EP_wildcard)) {
if (cid != 0) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "MGCP wildcard EP only works in first CRCX");
@@ -290,9 +293,14 @@ function f_rx_crcx(MgcpCommand mgcp_cmd)
sdp := mgcp_cmd.sdp;
g_media.mgcp_conn[cid].peer.host := sdp.connection.conn_addr.addr;
g_media.mgcp_conn[cid].peer.port_nr := sdp.media_list[0].media_field.ports.port_number;
+ if (sdp.connection.addr_type == "IP6") {
+ local_rtp_addr := host_mgw_rtp_v6;
+ } else {
+ local_rtp_addr := host_mgw_rtp_v4;
+ }
}
var MgcpConnState mgcp_conn := g_media.mgcp_conn[cid];
- sdp := valueof(ts_SDP(mgcp_conn.mgw.host, mgcp_conn.mgw.host, "foo", "21",
+ sdp := valueof(ts_SDP(mgcp_conn.mgw.host, local_rtp_addr, "foo", "21",
mgcp_conn.mgw.port_nr, { int2str(mgcp_conn.rtp_pt) },
{valueof(ts_SDP_rtpmap(mgcp_conn.rtp_pt,
mgcp_conn.mime_type & "/" &
@@ -314,15 +322,21 @@ function f_rx_mdcx(MgcpCommand mgcp_cmd)
runs on MSC_ConnHdlr return template MgcpResponse {
var SDP_Message sdp;
var integer cid := f_get_mgcp_conn(f_MgcpCmd_extract_conn_id(mgcp_cmd));
+ var charstring local_rtp_addr;
if (isvalue(mgcp_cmd.sdp)) {
sdp := mgcp_cmd.sdp;
g_media.mgcp_conn[cid].peer.host := sdp.connection.conn_addr.addr;
g_media.mgcp_conn[cid].peer.port_nr := sdp.media_list[0].media_field.ports.port_number;
+ if (sdp.connection.addr_type == "IP6") {
+ local_rtp_addr := host_mgw_rtp_v6;
+ } else {
+ local_rtp_addr := host_mgw_rtp_v4;
+ }
} else {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "MDCX has no [recognizable] SDP");
}
var MgcpConnState mgcp_conn := g_media.mgcp_conn[cid];
- sdp := valueof(ts_SDP(mgcp_conn.peer.host, mgcp_conn.peer.host, "foo", "21",
+ sdp := valueof(ts_SDP(mgcp_conn.peer.host, local_rtp_addr, "foo", "21",
mgcp_conn.peer.port_nr, { int2str(mgcp_conn.rtp_pt) },
{valueof(ts_SDP_rtpmap(mgcp_conn.rtp_pt,
mgcp_conn.mime_type & "/" &
@@ -409,7 +423,7 @@ altstep as_Media() runs on MSC_ConnHdlr {
/* this component represents a single subscriber connection at the MSC.
* There is a 1:1 mapping between SCCP connections and RAN_ConnHdlr components.
* We inherit all component variables, ports, functions, ... from RAN_ConnHdlr */
-type component MSC_ConnHdlr extends RAN_ConnHdlr, RSL_DchanHdlr, MGCP_ConnHdlr {
+type component MSC_ConnHdlr extends RAN_ConnHdlr, RSL_DchanHdlr, MGCP_ConnHdlr, StatsD_ConnHdlr {
/* SCCP Connecction Identifier for the underlying SCCP connection */
var integer g_sccp_conn_id;
@@ -425,15 +439,15 @@ type component MSC_ConnHdlr extends RAN_ConnHdlr, RSL_DchanHdlr, MGCP_ConnHdlr {
var TestHdlrParams g_pars;
var charstring host_bts := "127.0.0.2";
- var charstring host_mgw := "127.0.0.3";
+ var charstring host_mgw_mgcp := "127.0.0.3";
+ var charstring host_mgw_rtp_v4 := "127.0.0.5";
+ var charstring host_mgw_rtp_v6 := "::1";
var charstring host_msc := "127.0.0.4";
var boolean g_vty_initialized := false;
}
-/* initialize all parameters */
-function f_MscConnHdlr_init(integer i, HostName bts, HostName mgw, BSSMAP_FIELD_CodecType codecType) runs on MSC_ConnHdlr {
- f_MediaState_init(g_media, i, bts, mgw, codecType);
+function f_MscConnHdlr_init_vty() runs on MSC_ConnHdlr {
if (not g_vty_initialized) {
map(self:BSCVTY, system:BSCVTY);
f_vty_set_prompts(BSCVTY);
@@ -442,6 +456,12 @@ function f_MscConnHdlr_init(integer i, HostName bts, HostName mgw, BSSMAP_FIELD_
}
}
+/* initialize all parameters */
+function f_MscConnHdlr_init(integer i, HostName bts, HostName mgw, BSSMAP_FIELD_CodecType codecType) runs on MSC_ConnHdlr {
+ f_MediaState_init(g_media, i, bts, mgw, codecType);
+ f_MscConnHdlr_init_vty();
+}
+
private function get_next_trans_id() runs on MSC_ConnHdlr return MgcpTransId {
var MgcpTransId tid := int2str(g_trans_id);
g_trans_id := g_trans_id + 1;
@@ -482,7 +502,7 @@ const MGCPOps MSC_MGCPOps := {
}
/* register an expect with the BSSMAP core */
-private function f_create_bssmap_exp(octetstring l3_enc) runs on MSC_ConnHdlr {
+function f_create_bssmap_exp(octetstring l3_enc) runs on MSC_ConnHdlr {
RAN.call(RAN_register:{l3_enc, self}) {
[] RAN.getreply(RAN_register:{?, ?}) {};
}
@@ -509,9 +529,10 @@ type record TestHdlrParamsLcls {
boolean adjust_cx_exp
}
-type record TestHdlrParamsHandover {
- SCCP_PAR_Address sccp_addr_msc,
- SCCP_PAR_Address sccp_addr_bsc
+type record TestHdlrParamsMSCPool {
+ integer bssap_idx,
+ integer rsl_idx,
+ PDU_ML3_MS_NW l3_info optional
}
type record TestHdlrParams {
@@ -525,14 +546,19 @@ type record TestHdlrParams {
bitstring expect_mr_s0_s7 optional, /* typically present for AMR codecs */
TestHdlrEncrParams encr optional,
TestHdlrParamsLcls lcls,
- TestHdlrParamsHandover handover optional,
+ SCCP_PAR_Address sccp_addr_msc optional,
+ SCCP_PAR_Address sccp_addr_bsc optional,
+ uint5_t exp_ms_power_level,
+ boolean exp_ms_power_params,
boolean aoip,
- boolean use_osmux
+ boolean use_osmux,
+ charstring host_aoip_tla,
+ TestHdlrParamsMSCPool mscpool
};
/* Note: Do not use valueof() to get a value of this template, use
* f_gen_test_hdlr_pars() instead in order to get a configuration that is
- * matched to the current test situation (aoio vs. sccplite) */
+ * matched to the current test situation (aoip vs. sccplite) */
template (value) TestHdlrParams t_def_TestHdlrPars := {
ra := '23'O,
fn := 23,
@@ -550,9 +576,18 @@ template (value) TestHdlrParams t_def_TestHdlrPars := {
exp_sts := omit,
adjust_cx_exp := true
},
- handover := omit,
+ sccp_addr_msc := omit,
+ sccp_addr_bsc := omit,
+ exp_ms_power_level := 7, /* calculated from osmo-bsc.cfg "ms max power" */
+ exp_ms_power_params := false,
aoip := true,
- use_osmux := false
+ use_osmux := false,
+ host_aoip_tla := "1.2.3.4",
+ mscpool := {
+ bssap_idx := 0,
+ rsl_idx := 0,
+ l3_info := omit
+ }
}
function f_create_chan_and_exp() runs on MSC_ConnHdlr {
@@ -738,6 +773,9 @@ private template RSL_IE_Body tr_EncrInfo(template RSL_AlgId alg, template octets
/* ensure the RSL CHAN ACT (during assignment) contains values we expect depending on test case */
private function f_check_chan_act(AssignmentState st, RSL_Message chan_act) runs on MSC_ConnHdlr {
var RSL_IE_Body encr_info;
+ var RSL_IE_Body ms_power_param;
+ var RSL_IE_Body ms_power;
+
if (ispresent(g_pars.encr) and g_pars.encr.enc_alg != '01'O) {
if (not f_rsl_find_ie(chan_act, RSL_IE_ENCR_INFO, encr_info)) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing Encryption IE in CHAN ACT");
@@ -755,7 +793,20 @@ private function f_check_chan_act(AssignmentState st, RSL_Message chan_act) runs
}
}
/* FIXME: validate RSL_IE_ACT_TYPE, RSL_IE_CHAN_MODE, RSL_IE_CHAN_IDENT, RSL_IE_BS_POWER,
- * RSL_IE_MS_POWER, RSL_IE_TIMING_ADVANCE */
+ * RSL_IE_TIMING_ADVANCE */
+
+ if (g_pars.exp_ms_power_params and not f_rsl_find_ie(chan_act, RSL_IE_MS_POWER_PARAM, ms_power_param)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "IE MS Power Parameters not found in CHAN ACT");
+ }
+
+ if (not f_rsl_find_ie(chan_act, RSL_IE_MS_POWER, ms_power)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "IE MS Power not found in CHAN ACT");
+ } else {
+ if (not match(ms_power.ms_power, tr_RSL_IE_MS_Power(g_pars.exp_ms_power_level, false))) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Wrong MS Power IE in CHAN ACT, ", ms_power.ms_power.power_level, " vs exp ", g_pars.exp_ms_power_level));
+ }
+ }
+
}
altstep as_assignment(inout AssignmentState st) runs on MSC_ConnHdlr {
@@ -772,6 +823,9 @@ altstep as_assignment(inout AssignmentState st) runs on MSC_ConnHdlr {
/* register our component for this channel number at the RSL Emulation */
f_rslem_register(0, new_chan_nr);
+ /* dispatch queued messages for this channel (if any) */
+ f_rslem_dchan_queue_dispatch();
+
var PDU_ML3_MS_NW l3_tx := valueof(ts_RRM_AssignmentComplete('00'O));
/* send assignment complete over the new channel */
RSL.send(ts_RSL_EST_IND(new_chan_nr, valueof(ts_RslLinkID_DCCH(0)),
@@ -969,7 +1023,7 @@ runs on MSC_ConnHdlr {
var BSSMAP_FIELD_CodecType codecType;
timer T := 10.0;
- if (isvalue(ass_tpl.pdu.bssmap.assignmentRequest.codecList)) {
+ if (not istemplatekind(ass_tpl, "omit") and isvalue(ass_tpl.pdu.bssmap.assignmentRequest.codecList)) {
codecType := valueof(ass_tpl.pdu.bssmap.assignmentRequest.codecList.codecElements[0].codecType);
} else {
/* Make sure a meaningful default is assigned in case the
@@ -977,7 +1031,7 @@ runs on MSC_ConnHdlr {
codecType := FR_AMR;
}
- f_MscConnHdlr_init(g_pars.media_nr, host_bts, host_mgw, codecType);
+ f_MscConnHdlr_init(g_pars.media_nr, host_bts, host_mgw_mgcp, codecType);
/* patch in the LCLS related items, as needed */
f_ass_patch_lcls(ass_tpl, exp_ass_cpl);
@@ -1064,6 +1118,15 @@ runs on MSC_ConnHdlr {
g_media.mgcp_conn[1].mdcx_seen_exp := 0;
}
+ /* On receipt of the BSSAP Assignment Command, the IUT (osmo-bsc) will allocate
+ * a channel and send us RR Assignment Command together with ip.access CRCX.
+ * There is a risk that the RSL Emulation component would dequeue and process
+ * ip.access CRCX faster than we process the Assignment Command and register
+ * the corresponding handler for the indicated RSL channel number. This would
+ * result in a failure, because at that moment there will be no handler for
+ * ip.access CRCX. Let's guard against this and enable additional queueing. */
+ f_rslem_dchan_queue_enable();
+
f_create_mgcp_expect(mgcpcrit);
BSSAP.send(ass_cmd);
@@ -1137,7 +1200,7 @@ runs on MSC_ConnHdlr {
cmd := ts_CRCX(get_next_trans_id(), ep, "sendrecv", call_id);
resp := tr_CRCX_ACK;
}
- cmd.sdp := ts_SDP(host_msc, host_mgw, "23", "42",
+ cmd.sdp := ts_SDP(host_msc, host_mgw_rtp_v4, "23", "42",
14000, { int2str(g_media.mgcp_conn[1].rtp_pt) },
{ valueof(ts_SDP_ptime(20)) });
mgcp_transceive_mgw(cmd, resp);
diff --git a/bsc/README.md b/bsc/README.md
index 6efaa7f..47714e9 100644
--- a/bsc/README.md
+++ b/bsc/README.md
@@ -1,12 +1,18 @@
# BSC_Tests.ttcn
* external interfaces
- * A-bis side: RSL (emulates BTS-side client)
- * A-side: BSSAP/SCCP/M3UA (emulates MSC-side)
+ * A-bis side: RSL (emulates BTS-side client) (OML handled by osmo-bts-omldummy)
+ * A-side (emulates MSC-side)
+ * BSSAP/SCCP/M3UA (AoIP)
+ * BSSAP/SCCP/IPA (SCCPLite)
* MGW side: MGCP (emulates MGW side)
+ * VTY
+ * CTRL
+ * StatsD
{% dot bsc_tests.svg
digraph G {
+ graph [label="AoIP", labelloc=t, fontsize=30];
rankdir=LR;
{ rank=same; BTS; STP; };
BSC [label="IUT\nosmo-bsc",shape="box"];
@@ -17,7 +23,25 @@ digraph G {
ATS -> BSC [label="A-bis RSL"];
ATS -> BSC [label="CTRL"];
ATS -> BSC [label="VTY"];
+ BSC -> ATS [label="StatsD"];
ATS -> STP [label="A BSSAP\nSCCP/M3UA"];
BSC -> STP [label="A BSSAP\nSCCP/M3UA"];
}
%}
+
+{% dot bsc_tests_sccplite.svg
+digraph G {
+ graph [label="SCCPLite", labelloc=t, fontsize=30];
+ rankdir=LR;
+ BSC [label="IUT\nosmo-bsc",shape="box"];
+ ATS [label="ATS\nBSC_Tests.ttcn"];
+ BTS [label="osmo-bts-omldummy\nOML only"];
+
+ BTS -> BSC [label="A-bis OML"];
+ ATS -> BSC [label="A-bis RSL"];
+ ATS -> BSC [label="CTRL"];
+ ATS -> BSC [label="VTY"];
+ BSC -> ATS [label="StatsD"];
+ ATS -> BSC [label="A BSSAP\nSCCP/IPA"];
+}
+%}
diff --git a/bsc/expected-results.xml b/bsc/expected-results.xml
index 3ea202c..1d4f5d7 100644
--- a/bsc/expected-results.xml
+++ b/bsc/expected-results.xml
@@ -1,9 +1,8 @@
<?xml version="1.0"?>
-<testsuite name='BSC_Tests' tests='107' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
+<testsuite name='BSC_Tests' tests='163' failures='11' errors='1' skipped='0' inconc='0' time='MASKED'>
<testcase classname='BSC_Tests' name='TC_ctrl_msc_connection_status' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_ctrl_msc0_connection_status' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_ctrl' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_ctrl_location' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_chan_act_noreply' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_chan_act_counter' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_chan_act_ack_noest' time='MASKED'/>
@@ -19,6 +18,7 @@
<testcase classname='BSC_Tests' name='TC_chan_rel_hard_rlsd' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_chan_rel_hard_rlsd_ms_dead' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_chan_rel_a_reset' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_chan_rel_sccp_tiar_timeout' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_outbound_connect' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_cic_only' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_csd' time='MASKED'/>
@@ -37,6 +37,23 @@
<testcase classname='BSC_Tests' name='TC_assignment_codec_efr' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S1' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S1' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S124' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S124' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S0' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S02' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S024' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S0247' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S0' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S02' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S024' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S0247' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S01234567' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S0234567' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_zero' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_unsupp' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S7' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_codec_fr_exhausted_req_hr' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_codec_fr_exhausted_req_fr' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_assignment_codec_fr_exhausted_req_fr_hr' time='MASKED'/>
@@ -93,6 +110,13 @@
<testcase classname='BSC_Tests' name='TC_ho_in_fail_msc_clears_after_ho_detect' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_ho_in_fail_no_detect' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_ho_in_fail_no_detect2' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_ho_neighbor_config_1' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_ho_neighbor_config_2' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_ho_neighbor_config_3' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_ho_neighbor_config_4' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_ho_neighbor_config_5' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_ho_neighbor_config_6' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_ho_neighbor_config_7' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_bssap_rlsd_does_not_cause_bssmap_reset' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_bssmap_clear_does_not_cause_bssmap_reset' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_ms_rel_ind_does_not_cause_bssmap_reset' time='MASKED'/>
@@ -102,25 +126,9 @@
<testcase classname='BSC_Tests' name='TC_dyn_pdch_osmo_act_nack' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_chopped_ipa_ping' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_chopped_ipa_payload' time='MASKED'/>
+ <testcase classname='BSC_Tests' name='TC_assignment_verify_ms_power_params_ie' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_early_conn_fail' time='MASKED'/>
<testcase classname='BSC_Tests' name='TC_late_conn_fail' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S1' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S1' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S124' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S124' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S0' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S02' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S024' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S0247' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S0' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S02' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S024' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S0247' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S01234567' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_S0234567' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_zero' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_f_unsupp' time='MASKED'/>
- <testcase classname='BSC_Tests' name='TC_assignment_codec_amr_h_S7' time='MASKED'/>
<testcase classname='BSC_Tests_LCLS' name='TC_lcls_gcr_only' time='MASKED'/>
<testcase classname='BSC_Tests_LCLS' name='TC_lcls_gcr_bway_connect' time='MASKED'/>
<testcase classname='BSC_Tests_LCLS' name='TC_lcls_gcr_bway_connect_hr' time='MASKED'/>
@@ -135,4 +143,81 @@
<testcase classname='BSC_Tests_LCLS' name='TC_lcls_bts_gcr_bway_connect' time='MASKED'/>
<testcase classname='BSC_Tests_LCLS' name='TC_lcls_bts_gcr_bway_connect_hr' time='MASKED'/>
<testcase classname='BSC_Tests_LCLS' name='TC_lcls_bts_connect_break' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_bsc_server' time='MASKED'>
+ <failure type='fail-verdict'>Could not connect to CBSP port, check your configuration
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_bsc_server testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_bsc_client' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_reset_bss' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_bss' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_bss testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_bts_cgi' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_bts_cgi testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_bts_no_cbch' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_unknown_bts' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_lac_ci' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_lac_ci testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_ci' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_ci testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_lai' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_lai testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_lac' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_lac testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_then_replace' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_then_replace testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_replace_nonexist' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_too_many' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_kill_nonexist' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_then_kill' time='MASKED'>
+ <error type='DTE'>Dynamic test case error: Performing lengthof() operation on a template of type @CBSP_Types.CBSP_IEs with no exact length.</error>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_write_then_reset' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected CBSP
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_write_then_reset testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_emerg_write_bts_cgi_dchan' time='MASKED'/>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_emerg_write_bts_cgi_cchan' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected OSMO_ETWS_CMD
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_emerg_write_bts_cgi_cchan testcase
+ </failure>
+ </testcase>
+ <testcase classname='BSC_Tests_CBSP' name='TC_cbsp_emerg_write_bts_cgi_cchan_disable' time='MASKED'>
+ <failure type='fail-verdict'>Received unexpected OSMO_ETWS_CMD
+ BSC_Tests_CBSP.ttcn:MASKED BSC_Tests_CBSP control part
+ BSC_Tests_CBSP.ttcn:MASKED TC_cbsp_emerg_write_bts_cgi_cchan_disable testcase
+ </failure>
+ </testcase>
</testsuite>
diff --git a/bsc/gen_links.sh b/bsc/gen_links.sh
index 845f7cc..02e093d 100755
--- a/bsc/gen_links.sh
+++ b/bsc/gen_links.sh
@@ -67,9 +67,10 @@ FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn"
gen_links $DIR $FILES
DIR=../library
-FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp L3_Templates.ttcn BSSMAP_Templates.ttcn RAN_Emulation.ttcnpp RLCMAC_CSN1_Types.ttcn GSM_RR_Types.ttcn RSL_Types.ttcn RSL_Emulation.ttcn MGCP_Emulation.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc BSSAP_CodecPort.ttcn RAN_Adapter.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc IuUP_Emulation.ttcn SCCP_Templates.ttcn IPA_Testing.ttcn "
+FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp L3_Templates.ttcn BSSMAP_Templates.ttcn RAN_Emulation.ttcnpp RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn GSM_RR_Types.ttcn RSL_Types.ttcn RSL_Emulation.ttcn MGCP_Emulation.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc BSSAP_CodecPort.ttcn RAN_Adapter.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc IuUP_Emulation.ttcn SCCP_Templates.ttcn IPA_Testing.ttcn GSM_SystemInformation.ttcn GSM_RestOctets.ttcn "
FILES+="CBSP_Types.ttcn CBSP_Templates.ttcn "
FILES+="CBSP_CodecPort.ttcn CBSP_CodecPort_CtrlFunct.ttcn CBSP_CodecPort_CtrlFunctdef.cc CBSP_Adapter.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn"
gen_links $DIR $FILES
ignore_pp_results
diff --git a/bsc/osmo-bsc.cfg b/bsc/osmo-bsc.cfg
index 74fe255..8dd6655 100644
--- a/bsc/osmo-bsc.cfg
+++ b/bsc/osmo-bsc.cfg
@@ -6,10 +6,11 @@ password foo
log stderr
logging filter all 1
logging color 1
- logging print category 0
- logging timestamp 0
+ logging print category 1
+ logging timestamp 1
+ logging print extended-timestamp 1
+ logging level all everything
logging level rll notice
- logging level cc notice
logging level mm notice
logging level rr notice
logging level rsl notice
@@ -17,10 +18,8 @@ log stderr
logging level pag notice
logging level meas notice
logging level msc notice
- logging level mgcp notice
logging level ho notice
logging level ref notice
- logging level nat notice
logging level ctrl notice
logging level filter debug
logging level pcu debug
@@ -42,15 +41,31 @@ log stderr
logging level lm3ua notice
logging level lmgcp notice
!
-stats interval 5
+stats interval 0
+stats reporter statsd
+ prefix TTCN3
+ level subscriber
+ remote-ip 127.0.0.1
+ remote-port 8125
+ flush-period 1
+ mtu 1024
+ enable
!
line vty
no login
+ bind 127.0.0.1
!
e1_input
e1_line 0 driver ipa
e1_line 0 port 0
no e1_line 0 keepalive
+cs7 instance 0
+ asp asp-clnt-msc-0 2905 1905 m3ua
+ remote-ip 127.0.0.1
+ sccp-address msc2
+ point-code 0.0.2
+ sccp-address msc3
+ point-code 0.0.3
network
network country code 1
mobile network code 1
@@ -64,9 +79,8 @@ network
handover power budget interval 6
handover power budget hysteresis 3
handover maximum distance 9999
- dyn_ts_allow_tch_f 1
- periodic location update 30
timer t3113 10
+ timer t3212 30
bts 0
type sysmobts
band DCS1800
@@ -95,7 +109,6 @@ network
si5 neighbor-list add arfcn 20
codec-support fr hr efr amr
gprs mode gprs
- gprs 11bit_rach_support_for_egprs 0
gprs routing area 0
gprs network-control-order nc0
gprs cell bvci 1234
@@ -127,6 +140,7 @@ network
gprs nsvc 1 remote udp port 0
gprs nsvc 1 remote ip 0.0.0.0
no force-combined-si
+ si2quater neighbor-list add earfcn 111 thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3
trx 0
rf_locked 0
arfcn 871
@@ -134,7 +148,7 @@ network
max_power_red 20
rsl e1 tei 0
timeslot 0
- phys_chan_config CCCH+SDCCH4
+ phys_chan_config CCCH+SDCCH4+CBCH
hopping enabled 0
timeslot 1
phys_chan_config TCH/F
@@ -185,7 +199,6 @@ network
si5 neighbor-list add arfcn 20
codec-support fr hr efr amr
gprs mode gprs
- gprs 11bit_rach_support_for_egprs 0
gprs routing area 0
gprs network-control-order nc0
gprs cell bvci 1235
@@ -217,6 +230,7 @@ network
gprs nsvc 1 remote udp port 0
gprs nsvc 1 remote ip 0.0.0.0
no force-combined-si
+ si2quater neighbor-list add earfcn 111 thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3
trx 0
rf_locked 0
arfcn 871
@@ -224,7 +238,7 @@ network
max_power_red 20
rsl e1 tei 0
timeslot 0
- phys_chan_config CCCH+SDCCH4
+ phys_chan_config CCCH+SDCCH4+CBCH
hopping enabled 0
timeslot 1
phys_chan_config TCH/F
@@ -275,7 +289,6 @@ network
si5 neighbor-list add arfcn 20
codec-support fr hr efr amr
gprs mode gprs
- gprs 11bit_rach_support_for_egprs 0
gprs routing area 0
gprs network-control-order nc0
gprs cell bvci 1236
@@ -307,6 +320,7 @@ network
gprs nsvc 1 remote udp port 0
gprs nsvc 1 remote ip 0.0.0.0
no force-combined-si
+ si2quater neighbor-list add earfcn 111 thresh-hi 20 thresh-lo 10 prio 3 qrxlv 22 meas 3
trx 0
rf_locked 0
arfcn 871
@@ -314,7 +328,7 @@ network
max_power_red 20
rsl e1 tei 0
timeslot 0
- phys_chan_config CCCH+SDCCH4
+ phys_chan_config CCCH+SDCCH4+CBCH
hopping enabled 0
timeslot 1
phys_chan_config TCH/F
@@ -367,7 +381,6 @@ network
timeslot 7
phys_chan_config PDCH
msc 0
- ip.access rtp-base 4000
no bsc-welcome-text
no bsc-msc-lost-text
no bsc-grace-text
@@ -382,8 +395,39 @@ msc 0
amr-config 5_15k forbidden
amr-config 4_75k forbidden
codec-list fr1 fr2 fr3 hr1 hr3
+ mgw remote-ip 127.0.0.1
lcls-mode mgw-loop
+msc 1
+ msc-addr msc2
+ mgw remote-ip 127.0.0.1
+msc 2
+ msc-addr msc3
+ mgw remote-ip 127.0.0.1
+
+network
+ nri bitlen 10
+ # a NULL NRI that is outside the NRI ranges used by the MSCs:
+ nri null add 0
+ # a NULL NRI that is also used by an MSC:
+ nri null add 1
+msc 0
+ nri add 1 255
+msc 1
+ nri add 256 511
+msc 2
+ nri add 512 767
+ # range 768-1024 is not assigned to any MSC on purpose
+
bsc
mid-call-timeout 0
no missing-msc-text
- access-list-name bsc-list
+ctrl
+ bind 127.0.0.1
+cbc
+ mode disabled
+ client
+ remote-ip 127.0.0.1
+ remote-port 48049
+ server
+ local-ip 127.0.0.1
+ local-port 48050
diff --git a/bsc/osmo-stp.cfg b/bsc/osmo-stp.cfg
index f40a02f..8b8ccdb 100644
--- a/bsc/osmo-stp.cfg
+++ b/bsc/osmo-stp.cfg
@@ -6,7 +6,8 @@ log stderr
logging filter all 1
logging color 1
logging print category 1
- logging timestamp 0
+ logging timestamp 1
+ logging print extended-timestamp 1
logging level all everything
logging level lglobal notice
logging level llapd notice
@@ -31,23 +32,34 @@ line vty
!
cs7 instance 0
xua rkm routing-key-allocation dynamic-permitted
-! asp virt-bsc0-0 22905 2905 m3ua
-! local-ip 127.0.0.1
-! remote-ip 127.0.0.1
asp virt-msc0-0 23905 2905 m3ua
local-ip 127.0.0.1
remote-ip 127.0.0.1
as mahlzeit ipa
- routing-key 1 0.23.4
+ routing-key 0 0.23.4
point-code override dpc 0.23.1
-! as virt-bsc0 m3ua
-! asp virt-bsc0-0
-! routing-key 0 0.24.1
as virt-msc0 m3ua
asp virt-msc0-0
- routing-key 0 0.23.1
+ routing-key 1 0.23.1
+
+ asp virt-msc1-0 23906 2905 m3ua
+ local-ip 127.0.0.1
+ remote-ip 127.0.0.1
+ as virt-msc1 m3ua
+ asp virt-msc1-0
+ routing-key 2 0.0.2
+
+ asp virt-msc2-0 23907 2905 m3ua
+ local-ip 127.0.0.1
+ remote-ip 127.0.0.1
+ as virt-msc2 m3ua
+ asp virt-msc2-0
+ routing-key 3 0.0.3
+
route-table system
update route 0.23.1 7.255.7 linkset virt-msc0
+ update route 0.0.2 7.255.7 linkset virt-msc1
+ update route 0.0.3 7.255.7 linkset virt-msc2
listen m3ua 2905
accept-asp-connections dynamic-permitted
listen ipa 5000
diff --git a/bsc/regen_makefile.sh b/bsc/regen_makefile.sh
index def4a3f..f1ea963 100755
--- a/bsc/regen_makefile.sh
+++ b/bsc/regen_makefile.sh
@@ -2,7 +2,7 @@
MAIN=BSC_Tests.ttcn
-FILES="*.ttcn *.ttcnpp IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc SCTPasp_PT.cc RTP_EncDec.cc SDP_EncDec.cc RTP_CodecPort_CtrlFunctDef.cc MGCP_CodecPort_CtrlFunctDef.cc IuUP_EncDec.cc Native_FunctionDefs.cc TELNETasp_PT.cc CBSP_CodecPort_CtrlFunctdef.cc *.c"
+FILES="*.ttcn *.ttcnpp IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc SCTPasp_PT.cc RTP_EncDec.cc SDP_EncDec.cc RTP_CodecPort_CtrlFunctDef.cc MGCP_CodecPort_CtrlFunctDef.cc IuUP_EncDec.cc Native_FunctionDefs.cc TELNETasp_PT.cc CBSP_CodecPort_CtrlFunctdef.cc StatsD_CodecPort_CtrlFunctdef.cc *.c"
export CPPFLAGS_TTCN3="-DIPA_EMULATION_RSL -DIPA_EMULATION_MGCP -DIPA_EMULATION_CTRL -DIPA_EMULATION_SCCP -DRAN_EMULATION_BSSAP -DRAN_EMULATION_MGCP -DRAN_EMULATION_CTRL -DUSE_MTP3_DISTRIBUTOR"
diff --git a/bts/BTS_Tests.cfg b/bts/BTS_Tests.cfg
index 78a288d..ed04163 100644
--- a/bts/BTS_Tests.cfg
+++ b/bts/BTS_Tests.cfg
@@ -12,13 +12,17 @@
#*.BTSVTY.CTRL_HOSTNAME := "10.9.1.191" # sysmoBTS Max
#*.BTSVTY.CTRL_HOSTNAME := "10.9.1.162" # sysmoBTS Pau
#*.BTSVTY.CTRL_HOSTNAME := "192.168.100.130" # sysmoBTS home
-*.BTSVTY.CTRL_HOSTNAME := "127.0.0.1" # osmo-bts-trx
-*.BSCVTY.CTRL_HOSTNAME := "127.0.0.1" # osmo-bsc
+*.BTSVTY.CTRL_HOSTNAME := "127.0.0.20" # osmo-bts-trx
+*.BSCVTY.CTRL_HOSTNAME := "127.0.0.11" # osmo-bsc
[MODULE_PARAMETERS]
+L1CTL_PortType.m_l1ctl_sock_path := "/tmp/osmocom_l2"
#BTS_Tests.mp_rsl_ip := "10.9.1.2" # office
-BTS_Tests.mp_rsl_ip := "192.168.100.2" # home
-#BTS_Tests.mp_pcu_socket := ""
+#BTS_Tests.mp_rsl_ip := "192.168.100.2" # home
+BTS_Tests.mp_rsl_ip := "127.0.0.10"
+BTS_Tests.mp_pcu_socket := "/tmp/pcu_sock"
+BTS_Tests.mp_bts_trxc_ip := "127.0.0.21"
+BTS_Tests.mp_ctrl_ip := "127.0.0.20"
#BTS_Tests_OML.mp_oml_ip := "192.168.102.239" # home
#BTS_Tests_OML.mp_oml_port := 3002
diff --git a/bts/BTS_Tests.ttcn b/bts/BTS_Tests.ttcn
index 15948a3..6412022 100644
--- a/bts/BTS_Tests.ttcn
+++ b/bts/BTS_Tests.ttcn
@@ -29,11 +29,13 @@ import from GSM_Types all;
import from GSM_RR_Types all;
import from Osmocom_Types all;
import from GSM_Types all;
+import from GSM_RestOctets all;
import from GSM_SystemInformation all;
import from L1CTL_PortType all;
import from L1CTL_Types all;
import from LAPDm_Types all;
import from LAPDm_RAW_PT all;
+import from Native_Functions all;
import from Osmocom_CTRL_Adapter all;
import from Osmocom_CTRL_Functions all;
@@ -66,6 +68,7 @@ import from BTS_Tests_LAPDm all;
friend module BTS_Tests_SMSCB;
friend module BTS_Tests_virtphy;
friend module BTS_Tests_LAPDm;
+friend module BTS_Tests_perf;
/* The tests assume a BTS with the following timeslot configuration:
* TS0 : Combined CCCH + SDCCH/4
@@ -82,6 +85,9 @@ modulepar {
charstring mp_rsl_ip := "127.0.0.2";
integer mp_rsl_port := 3003;
integer mp_trx0_arfcn := 871;
+ integer mp_trx1_arfcn := 873;
+ integer mp_trx2_arfcn := 875;
+ integer mp_trx3_arfcn := 877;
charstring mp_bts_trxc_ip := "127.0.0.1";
integer mp_bts_trxc_port := 5701;
charstring mp_pcu_socket := PCU_SOCK_DEFAULT;
@@ -95,6 +101,8 @@ modulepar {
integer mp_rxlev_exp := 57;
integer mp_ul_rxlev_exp := 10;
integer mp_ms_power_level_exp := 7;
+ integer mp_bts_tx_nom_pwr_exp := 50; /* Expected Tx Nominal Output Power of the BTS, in dBm */
+ integer mp_bts_tx_pwr_att_exp := 20; /* Expected Tx Power attenuation wrt to Tx Nominal Output Power, in dB */
integer mp_ms_actual_ta_exp := 0;
integer mp_timing_offset_256syms_exp := 512;
/* Time to wait for RSL conn from BTS during startup of test */
@@ -102,6 +110,12 @@ modulepar {
float mp_ipa_up_delay := 0.0;
/* false for now, as only virtphy supports it, not calypso-l1 nor trxcon */
boolean mp_l1_supports_gprs := false;
+ /* how many transceivers do we expect to connect */
+ integer mp_transceiver_num := 1;
+ /* frequency hopping status */
+ boolean mp_freq_hop_enabled := false;
+ /* frequency hopping parameters */
+ FreqHopConfig mp_fh_config;
}
type record of RslChannelNr ChannelNrs;
@@ -164,6 +178,9 @@ type component ConnHdlr extends RSL_DchanHdlr, lapdm_test_CT {
port TRXC_CODEC_PT BTS_TRXC;
var integer g_bts_trxc_conn_id;
+ /* port to be initialized optionally to access BSC VTY */
+ port TELNETasp_PT BSCVTY;
+
timer g_Tguard;
timer g_Tmeas_exp := 2.0; /* >= 103 SACCH multiframe ~ 500ms */
@@ -175,7 +192,12 @@ type component ConnHdlr extends RSL_DchanHdlr, lapdm_test_CT {
port PCUIF_CODEC_PT PCU;
}
-function f_init_rsl(charstring id) runs on test_CT {
+private function f_init_rsl(charstring id) runs on test_CT {
+ var bitstring trx_mask := '00000000'B;
+ var integer trx_count := 0;
+ var RSLEm_Event ev;
+ timer T;
+
vc_IPA := IPA_Emulation_CT.create(id & "-RSL-IPA");
vc_RSL := RSL_Emulation_CT.create(id & "-RSL");
@@ -185,6 +207,34 @@ function f_init_rsl(charstring id) runs on test_CT {
vc_IPA.start(IPA_Emulation.main_server(mp_rsl_ip, mp_rsl_port));
vc_RSL.start(RSL_Emulation.main(false));
+
+ /* We expect (N = mp_transceiver_num) IPA/RSL transceiver connections here.
+ * See https://gerrit.osmocom.org/q/Ib5ad31388ae25399ad09739aac3fdcb0b3a1f78b. */
+ T.start(mp_ipa_up_timeout);
+ alt {
+ /* These events are sent by the RSL_Emulation_CT */
+ [] RSL_CCHAN.receive(tr_RSLEm_EV(RSLEM_EV_TRX_UP, ?)) -> value ev {
+ /* Make sure that all transceivers use unique stream ID */
+ if (trx_mask[enum2int(ev.sid)] == '1'B) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Duplicate RSL stream ID (", ev.sid, ")"));
+ }
+
+ /* This message (RF RESource INDication) is sent by the IUT itself */
+ RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RF_RES_IND, ev.sid));
+ trx_mask[enum2int(ev.sid)] := '1'B;
+ trx_count := trx_count + 1;
+
+ log(trx_count, "/", mp_transceiver_num, " transceiver(s) connected");
+ if (trx_count < mp_transceiver_num) { repeat; }
+ }
+ /* osmo-bts may send us CCCH LOAD INDication or whatever else */
+ [] RSL_CCHAN.receive(ASP_RSL_Unitdata:?) { repeat; }
+ [] T.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ "Timeout waiting for RSL bring up");
+ }
+ }
}
type record ConnHdlrPars {
@@ -194,15 +244,22 @@ type record ConnHdlrPars {
ConnL1Pars l1_pars,
TestSpecUnion spec optional,
RSL_IE_EncryptionInfo encr optional,
- BtsBand bts0_band optional
+ BtsBand bts0_band optional,
+
+ /* Frequency hopping parameters (disabled if absent) */
+ MaioHsn maio_hsn optional,
+ /* MA bitmap to be indicated in RR Immediate Assignment */
+ MobileAllocationLV ma_map,
+ /* The actual Mobile Allocation (ARFCN list) to be used */
+ L1ctlMA ma
}
/* Test-specific parameters */
-type union TestSpecUnion {
+private type union TestSpecUnion {
RllTestCase rll
}
-template (value) RachControlParameters ts_RachCtrl_default := {
+private template (value) RachControlParameters ts_RachCtrl_default := {
max_retrans := RACH_MAX_RETRANS_7,
tx_integer := '1001'B, /* 12 slots */
cell_barr_access := false,
@@ -210,7 +267,7 @@ template (value) RachControlParameters ts_RachCtrl_default := {
acc := '0000010000000000'B
};
-template (value) CellSelectionParameters ts_CellSelPar_default := {
+private template (value) CellSelectionParameters ts_CellSelPar_default := {
cell_resel_hyst_2dB := 2,
ms_txpwr_max_cch := mp_ms_power_level_exp,
acs := '0'B,
@@ -218,13 +275,34 @@ template (value) CellSelectionParameters ts_CellSelPar_default := {
rxlev_access_min := 0
}
-template (value) LocationAreaIdentification ts_LAI_default := {
+private template (value) LocationAreaIdentification ts_LAI_default := {
mcc_mnc := '262F42'H,
lac := 42
}
+private template (value) GPRSIndicator ts_GPRSIndicator_def := {
+ ra_colour := 0,
+ si13_pos := '0'B
+}
+
+private template (value) SI3RestOctets ts_SI3RestOctets_def
+modifies ts_SI3RestOctets := {
+ gprs_ind := {
+ presence := CSN1_H,
+ ind := ts_GPRSIndicator_def
+ }
+}
+
+private template (value) SI4RestOctets ts_SI4RestOctets_def
+modifies ts_SI4RestOctets := {
+ gprs_ind := {
+ presence := CSN1_H,
+ ind := ts_GPRSIndicator_def
+ }
+}
+
/* Default SYSTEM INFORMATION 3 */
-template (value) SystemInformation ts_SI3_default := {
+private template (value) SystemInformation ts_SI3_default := {
header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_3, 18),
payload := {
si3 := {
@@ -249,12 +327,12 @@ template (value) SystemInformation ts_SI3_default := {
},
cell_sel_par := ts_CellSelPar_default,
rach_control := ts_RachCtrl_default,
- rest_octets := '2C2B2B2B'O /* GPRS present */
+ rest_octets := valueof(ts_SI3RestOctets_def)
}
}
}
-template (value) SystemInformation ts_SI2_default := {
+private template (value) SystemInformation ts_SI2_default := {
header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_2, 22),
payload := {
si2 := {
@@ -265,7 +343,7 @@ template (value) SystemInformation ts_SI2_default := {
}
}
-template (value) SystemInformation ts_SI4_default := {
+private template (value) SystemInformation ts_SI4_default := {
header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_4, 12), /* no CBCH / restoct */
payload := {
si4 := {
@@ -274,18 +352,18 @@ template (value) SystemInformation ts_SI4_default := {
rach_control := ts_RachCtrl_default,
cbch_chan_desc := omit,
cbch_mobile_alloc := omit,
- rest_octets := ''O
+ rest_octets := valueof(ts_SI4RestOctets_def)
}
}
}
-function f_rsl_bcch_fill_raw(RSL_IE_SysinfoType rsl_si_type, octetstring si_enc)
+private function f_rsl_bcch_fill_raw(RSL_IE_SysinfoType rsl_si_type, octetstring si_enc)
runs on test_CT {
log("Setting ", rsl_si_type, ": ", si_enc);
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_BCCH_INFO(rsl_si_type, si_enc)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_BCCH_INFO(rsl_si_type, si_enc)));
}
-function f_rsl_bcch_fill(RSL_IE_SysinfoType rsl_si_type, template (value) SystemInformation si_dec)
+private function f_rsl_bcch_fill(RSL_IE_SysinfoType rsl_si_type, template (value) SystemInformation si_dec)
runs on test_CT {
var octetstring si_enc := enc_SystemInformation(valueof(si_dec));
log("Setting ", rsl_si_type, ": ", si_dec);
@@ -304,6 +382,12 @@ friend function f_init_vty_bsc() runs on test_CT {
f_vty_transceive(BSCVTY, "enable");
}
+friend function f_connhdlr_init_vty_bsc() runs on ConnHdlr {
+ map(self:BSCVTY, system:BSCVTY);
+ f_vty_set_prompts(BSCVTY, "OsmoBSC");
+ f_vty_transceive(BSCVTY, "enable");
+}
+
/* PCU socket may at any time receive a new INFO.ind */
private altstep as_pcu_info_ind(PCUIF_CODEC_PT pt, integer pcu_conn_id,
out PCUIF_Message pcu_last_info) {
@@ -324,9 +408,6 @@ private function f_init_pcu(PCUIF_CODEC_PT pt, charstring id,
pcu_conn_id := -1;
return;
}
-
- f_sleep(0.5); /* workaround for OS#4179 */
-
pcu_conn_id := f_pcuif_connect(pt, mp_pcu_socket);
T.start;
@@ -353,9 +434,8 @@ private function f_init_trxc(TRXC_CODEC_PT pt, charstring id,
}
/* global init function */
-function f_init() runs on test_CT {
+friend function f_init() runs on test_CT {
var charstring id := testcasename();
- timer T := mp_ipa_up_timeout;
g_AllChannels := {
/* TS 1..4: TCH/F */
valueof(ts_RslChanNr_Bm(1)), valueof(ts_RslChanNr_Bm(2)),
@@ -395,13 +475,6 @@ function f_init() runs on test_CT {
};
}
f_init_rsl(id);
- T.start;
- alt {
- [] RSL_CCHAN.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP});
- [] T.timeout {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for ASP_IPA_EVENT_UP");
- }
- }
f_sleep(0.5); /* workaround for OS#3000 */
f_init_vty(id);
f_ipa_ctrl_start(mp_ctrl_ip, mp_ctrl_port);
@@ -435,17 +508,68 @@ function f_init() runs on test_CT {
}
/* Attach L1CTL to master test_CT (classic tests, non-handler mode) */
-function f_init_l1ctl() runs on test_CT {
+friend function f_init_l1ctl() runs on test_CT {
map(self:L1CTL, system:L1CTL);
f_connect_reset(L1CTL);
}
-type function void_fn(charstring id) runs on ConnHdlr;
+private type function void_fn(charstring id) runs on ConnHdlr;
+
+private type record length(8) of FreqHopGroups FreqHopConfig;
+
+private type record of FreqHopGroup FreqHopGroups;
+private type record FreqHopGroup {
+ uint6_t hsn,
+ FreqHopGroupItems trx_maio
+};
+
+private type record of FreqHopGroupItem FreqHopGroupItems;
+private type record FreqHopGroupItem {
+ uint8_t trx_nr,
+ uint6_t maio
+};
+
+friend function f_resolve_fh_params(inout ConnHdlrPars pars, uint8_t trx_nr := 0)
+{
+ var FreqHopGroups groups := mp_fh_config[pars.chan_nr.tn];
+ var integer i, j;
+
+ for (i := 0; i < lengthof(groups); i := i + 1) {
+ var FreqHopGroup g := groups[i];
+ for (j := 0; j < lengthof(g.trx_maio); j := j + 1) {
+ var FreqHopGroupItem gi := g.trx_maio[j];
+ if (gi.trx_nr == trx_nr) {
+ pars.maio_hsn := valueof(ts_HsnMaio(g.hsn, gi.maio));
+ pars.ma := { }; /* to be composed below */
+ break;
+ }
+ }
+
+ if (ispresent(pars.maio_hsn)) {
+ /* Prepare the Mobile Allocation bitmask (length & padding) */
+ pars.ma_map.len := mp_transceiver_num / 8;
+ if (mp_transceiver_num mod 8 > 0)
+ { pars.ma_map.len := pars.ma_map.len + 1; }
+ pars.ma_map.ma := f_pad_bit('0'B, pars.ma_map.len * 8, '0'B);
+
+ /* Compose the actual Mobile Allocation and the bitmask */
+ for (j := 0; j < lengthof(g.trx_maio); j := j + 1) {
+ var FreqHopGroupItem gi := g.trx_maio[j];
+ pars.ma := pars.ma & { l1ctl_ma_def[gi.trx_nr] };
+ pars.ma_map.ma[gi.trx_nr] := '1'B;
+ }
+
+ log("Freq. hopping parameters: maio_hsn := ", pars.maio_hsn,
+ ", ma := ", pars.ma, ", ma_map := ", pars.ma_map);
+ break; /* We're done */
+ }
+ }
+}
/* create a new test component */
-function f_start_handler(void_fn fn, ConnHdlrPars pars,
- boolean pcu_comp := false,
- boolean trxc_comp := false)
+friend function f_start_handler(void_fn fn, ConnHdlrPars pars,
+ boolean pcu_comp := false,
+ boolean trxc_comp := false)
runs on test_CT return ConnHdlr {
var charstring id := testcasename();
var ConnHdlr vc_conn;
@@ -467,21 +591,15 @@ runs on test_CT return ConnHdlr {
map(vc_conn:BTS_TRXC, system:BTS_TRXC);
}
+ /* Obtain frequency hopping parameters for a given timeslot */
+ if (mp_freq_hop_enabled and mp_transceiver_num > 1) {
+ f_resolve_fh_params(pars);
+ }
+
vc_conn.start(f_handler_init(fn, id, pars));
return vc_conn;
}
-template ASP_RSL_Unitdata ts_RSL_UD(template RSL_Message rsl, IpaStreamId sid := IPAC_PROTO_RSL_TRX0) := {
- streamId := sid,
- rsl := rsl
-}
-
-template ASP_RSL_Unitdata tr_RSL_UD(template RSL_Message rsl,
- template IpaStreamId sid := IPAC_PROTO_RSL_TRX0) := {
- streamId := sid,
- rsl := rsl
-}
-
private altstep as_Tguard() runs on ConnHdlr {
[] g_Tguard.timeout {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
@@ -524,8 +642,8 @@ runs on ConnHdlr {
fn.apply(id);
}
-function f_rsl_transceive_ret(template RSL_Message tx, template RSL_Message exp_rx, charstring id,
- boolean ignore_other := false)
+private function f_rsl_transceive_ret(template RSL_Message tx, template RSL_Message exp_rx,
+ charstring id, boolean ignore_other := false)
runs on ConnHdlr return RSL_Message {
var RSL_Message rx;
timer T := 3.0;
@@ -550,14 +668,17 @@ runs on ConnHdlr return RSL_Message {
return rx;
}
-function f_rsl_transceive(template RSL_Message tx, template RSL_Message exp_rx, charstring id,
- boolean ignore_other := false)
+friend function f_rsl_transceive(template RSL_Message tx, template RSL_Message exp_rx,
+ charstring id, boolean ignore_other := false)
runs on ConnHdlr {
var RSL_Message rx := f_rsl_transceive_ret(tx, exp_rx, id, ignore_other);
}
-function f_rsl_chan_act(RSL_IE_ChannelMode mode, boolean encr_enable := false, RSL_IE_List more_ies := {},
- RSL_IE_ActivationType act_type := t_RSL_IE_ActType_IA) runs on ConnHdlr {
+friend function f_rsl_chan_act(RSL_IE_ChannelMode mode,
+ boolean encr_enable := false,
+ RSL_IE_List more_ies := {},
+ RSL_IE_ActivationType act_type := t_RSL_IE_ActType_IA)
+runs on ConnHdlr {
var RSL_Message ch_act := valueof(ts_RSL_CHAN_ACT(g_chan_nr, mode, act_type));
if (encr_enable) {
/* append encryption related IEs, if requested */
@@ -570,13 +691,18 @@ encr_info})) };
f_rsl_transceive(ch_act, tr_RSL_CHAN_ACT_ACK(g_chan_nr), "RSL CHAN ACT");
}
-function f_rsl_chan_deact() runs on ConnHdlr {
+friend function f_rsl_chan_deact() runs on ConnHdlr {
f_rsl_transceive(ts_RSL_RF_CHAN_REL(g_chan_nr), tr_RSL_RF_CHAN_REL_ACK(g_chan_nr),
"RF CHAN REL", true);
}
+/* Default Mobile Allocation to be used for frequency hopping */
+private const L1ctlMA l1ctl_ma_def := { { false, mp_trx0_arfcn }, { false, mp_trx1_arfcn },
+ { false, mp_trx2_arfcn }, { false, mp_trx3_arfcn } };
+
friend template ConnHdlrPars t_Pars(template RslChannelNr chan_nr,
template RSL_IE_ChannelMode chan_mode,
+ template (omit) MaioHsn maio_hsn := omit,
float t_guard := 20.0) := {
chan_nr := valueof(chan_nr),
chan_mode := valueof(chan_mode),
@@ -601,7 +727,10 @@ friend template ConnHdlrPars t_Pars(template RslChannelNr chan_nr,
},
spec := omit,
encr := omit,
- bts0_band := omit
+ bts0_band := omit,
+ maio_hsn := maio_hsn,
+ ma_map := c_MA_null,
+ ma := l1ctl_ma_def
}
/***********************************************************************
@@ -609,7 +738,7 @@ friend template ConnHdlrPars t_Pars(template RslChannelNr chan_nr,
***********************************************************************/
/* Stress test: Do 500 channel activations/deactivations in rapid succession */
-function f_TC_chan_act_stress(charstring id) runs on ConnHdlr {
+private function f_TC_chan_act_stress(charstring id) runs on ConnHdlr {
for (var integer i := 0; i < 500; i := i+1) {
f_rsl_chan_act(g_pars.chan_mode);
f_rsl_chan_deact();
@@ -626,7 +755,7 @@ testcase TC_chan_act_stress() runs on test_CT {
}
/* Test if re-activation of an already active channel fails as expected */
-function f_TC_chan_act_react(charstring id) runs on ConnHdlr {
+private function f_TC_chan_act_react(charstring id) runs on ConnHdlr {
f_rsl_chan_act(g_pars.chan_mode);
/* attempt to activate the same lchan again -> expect reject */
RSL.send(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode));
@@ -650,7 +779,7 @@ testcase TC_chan_act_react() runs on test_CT {
}
/* Attempt to de-activate a channel that's not active */
-function f_TC_chan_deact_not_active(charstring id) runs on ConnHdlr {
+private function f_TC_chan_deact_not_active(charstring id) runs on ConnHdlr {
timer T := 3.0;
RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
T.start;
@@ -672,7 +801,7 @@ testcase TC_chan_deact_not_active() runs on test_CT {
}
/* attempt to activate channel with wrong RSL Channel Nr IE; expect NACK */
-function f_TC_chan_act_wrong_nr(charstring id) runs on ConnHdlr {
+private function f_TC_chan_act_wrong_nr(charstring id) runs on ConnHdlr {
RSL.send(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode));
alt {
[] RSL.receive(tr_RSL_CHAN_ACT_ACK(g_chan_nr)) {
@@ -1081,7 +1210,7 @@ private function f_TC_sacch_chan_act_ho_async(charstring id) runs on ConnHdlr {
f_rsl_chan_act(g_pars.chan_mode, act_type := t_RSL_IE_ActType_HO_ASYNC);
/* don't perform immediate assignment here, as we're testing non-IA case */
/* enable dedicated mode */
- f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
+ f_l1ctl_est_dchan(L1CTL, g_pars);
/* Verify that no DL SACCH is being received */
f_sacch_missing(?);
@@ -1099,7 +1228,7 @@ private function f_TC_sacch_chan_act_ho_async(charstring id) runs on ConnHdlr {
f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_ASYNC);
/* don't perform immediate assignment here, as we're testing non-IA case */
/* enable dedicated mode */
- f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
+ f_l1ctl_est_dchan(L1CTL, g_pars);
/* Verify that DL SACCH is being received */
f_sacch_present(si5);
@@ -1137,7 +1266,7 @@ private function f_TC_sacch_chan_act_ho_sync(charstring id) runs on ConnHdlr {
f_rsl_chan_act(g_pars.chan_mode, act_type := t_RSL_IE_ActType_HO_SYNC);
/* don't perform immediate assignment here, as we're testing non-IA case */
/* enable dedicated mode */
- f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
+ f_l1ctl_est_dchan(L1CTL, g_pars);
/* Verify that no DL SACCH is being received */
f_sacch_missing(?);
@@ -1155,7 +1284,7 @@ private function f_TC_sacch_chan_act_ho_sync(charstring id) runs on ConnHdlr {
f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
/* don't perform immediate assignment here, as we're testing non-IA case */
/* enable dedicated mode */
- f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
+ f_l1ctl_est_dchan(L1CTL, g_pars);
/* Verify that no DL SACCH is being received */
f_sacch_missing(?);
@@ -1173,7 +1302,7 @@ private function f_TC_sacch_chan_act_ho_sync(charstring id) runs on ConnHdlr {
f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
/* don't perform immediate assignment here, as we're testing non-IA case */
/* enable dedicated mode */
- f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
+ f_l1ctl_est_dchan(L1CTL, g_pars);
/* Verify that no DL SACCH is being received */
f_sacch_missing(?);
@@ -1192,7 +1321,7 @@ private function f_TC_sacch_chan_act_ho_sync(charstring id) runs on ConnHdlr {
f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
/* don't perform immediate assignment here, as we're testing non-IA case */
/* enable dedicated mode */
- f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
+ f_l1ctl_est_dchan(L1CTL, g_pars);
/* Verify that DL SACCH is being received */
f_sacch_present(si5);
@@ -1220,40 +1349,8 @@ testcase TC_sacch_chan_act_ho_sync() runs on test_CT {
* RACH Handling
***********************************************************************/
-/* like L1SAP_IS_PACKET_RACH */
-private function ra_is_ps(OCT1 ra) return boolean {
- if ((ra and4b 'F0'O == '70'O) and (ra and4b '0F'O != '0F'O)) {
- return true;
- }
- return false;
-}
-
-/* generate a random RACH for circuit-switched */
-private function f_rnd_ra_cs() return OCT1 {
- var OCT1 ra;
- do {
- ra := f_rnd_octstring(1);
- } while (ra_is_ps(ra));
- return ra;
-}
-
-/* generate a random RACH for packet-switched */
-private function f_rnd_ra_ps() return OCT1 {
- var OCT1 ra;
- do {
- ra := f_rnd_octstring(1);
- } while (not ra_is_ps(ra));
- return ra;
-}
-
-/* generate a random 11-bit RA (packet-switched only) */
-private function f_rnd_ra11_ps() return BIT11 {
- var integer ra11 := f_rnd_int(bit2int('11111111111'B));
- return int2bit(ra11, 11);
-}
-
/* Send 1000 RACH requests and check their RA+FN on the RSL side */
-testcase TC_rach_content() runs on test_CT {
+private function f_TC_rach_content(boolean emerg) runs on test_CT {
f_init();
f_init_l1ctl();
f_l1_tune(L1CTL);
@@ -1261,7 +1358,12 @@ testcase TC_rach_content() runs on test_CT {
var GsmFrameNumber fn_last := 0;
var boolean test_failed := false;
for (var integer i := 0; i < 1000; i := i+1) {
- var OCT1 ra := f_rnd_ra_cs();
+ var OCT1 ra := f_rnd_ra_emerg();
+ if (emerg == true) {
+ ra := f_rnd_ra_emerg();
+ } else {
+ ra := f_rnd_ra_cs();
+ }
var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
if (fn == fn_last) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
@@ -1271,10 +1373,10 @@ testcase TC_rach_content() runs on test_CT {
timer T := 5.0;
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(ra, fn, t_RslChanNr_RACH(0)))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(ra, fn, t_RslChanNr_RACH(0)))) {
T.stop;
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(?, ?, ?, ?))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(?, ?, ?, ?))) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected CHAN RQD");
}
[] RSL_CCHAN.receive { repeat; }
@@ -1291,6 +1393,16 @@ testcase TC_rach_content() runs on test_CT {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
+/* Normal variant */
+testcase TC_rach_content() runs on test_CT {
+ f_TC_rach_content(emerg := false);
+}
+
+/* Emergency call variant */
+testcase TC_rach_content_emerg() runs on test_CT {
+ f_TC_rach_content(emerg := true);
+}
+
/* Send 1000 RACH Requests (flood ~ 89/s) and count if count(Abis) == count(Um) */
testcase TC_rach_count() runs on test_CT {
f_init();
@@ -1311,7 +1423,7 @@ testcase TC_rach_count() runs on test_CT {
timer T := 3.0;
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(?,?))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(?,?))) {
rsl_chrqd := rsl_chrqd + 1;
f_timer_safe_restart(T);
repeat;
@@ -1350,11 +1462,11 @@ testcase TC_rach_load_idle_thresh0() runs on test_CT {
timer T := 5.0;
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, 0, 0))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, 0, 0))) {
setverdict(pass);
repeat;
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
repeat;
}
@@ -1378,7 +1490,7 @@ testcase TC_rach_load_idle_below_thresh() runs on test_CT {
timer T := 5.0;
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
repeat;
}
@@ -1422,7 +1534,7 @@ testcase TC_rach_load_count() runs on test_CT {
timer T := 5.0;
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, ?, ?)))
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, ?, ?)))
-> value rx_ud {
var RSL_IE_Body ie;
f_rsl_find_ie(rx_ud.rsl, RSL_IE_RACH_LOAD, ie);
@@ -1432,7 +1544,7 @@ testcase TC_rach_load_count() runs on test_CT {
}
repeat;
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
repeat;
}
@@ -1465,10 +1577,10 @@ private function f_rach_toffs(int16_t toffs256, boolean expect_pass) runs on tes
timer T := 1.5;
T.start;
alt {
- [expect_pass] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
+ [expect_pass] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
setverdict(pass);
}
- [not expect_pass] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
+ [not expect_pass] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("RACH passed but was expected to be dropped: ", toffs256));
}
[] RSL_CCHAN.receive { repeat; }
@@ -1506,7 +1618,7 @@ testcase TC_rach_max_ta() runs on test_CT {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
-function f_TC_ho_rach(charstring id) runs on ConnHdlr {
+private function f_TC_ho_rach(charstring id) runs on ConnHdlr {
var GsmFrameNumber fn;
var RSL_Message rm;
@@ -1526,7 +1638,7 @@ function f_TC_ho_rach(charstring id) runs on ConnHdlr {
/* Switch the MS side (e.g. trxcon) to a dedicated channel without
* waiting for Immediate Assignment and sending Access Burst */
- f_L1CTL_DM_EST_REQ(L1CTL, { false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
+ f_l1ctl_est_dchan(L1CTL, g_pars);
/* Send handover Access Burst */
fn := f_L1CTL_RACH(L1CTL, ho_ref, chan_nr := g_pars.chan_nr);
@@ -1579,7 +1691,7 @@ testcase TC_ho_rach() runs on test_CT {
* Measurement Processing / Reporting
***********************************************************************/
-template LapdmAddressField ts_LapdmAddr(LapdmSapi sapi, boolean c_r) := {
+private template LapdmAddressField ts_LapdmAddr(LapdmSapi sapi, boolean c_r) := {
spare := '0'B,
lpd := 0,
sapi := sapi,
@@ -1587,7 +1699,7 @@ template LapdmAddressField ts_LapdmAddr(LapdmSapi sapi, boolean c_r) := {
ea := true
}
-template LapdmFrameAB ts_LAPDm_AB(LapdmSapi sapi, boolean c_r, boolean p, octetstring pl) := {
+private template LapdmFrameAB ts_LAPDm_AB(LapdmSapi sapi, boolean c_r, boolean p, octetstring pl) := {
addr := ts_LapdmAddr(sapi, c_r),
ctrl := ts_LapdmCtrlUI(p),
len := 0, /* overwritten */
@@ -1597,7 +1709,7 @@ template LapdmFrameAB ts_LAPDm_AB(LapdmSapi sapi, boolean c_r, boolean p, octets
}
/* handle incoming downlink SACCH and respond with uplink SACCH (meas res) */
-altstep as_l1_sacch() runs on ConnHdlr {
+private altstep as_l1_sacch() runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
[] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
log("SACCH received: ", l1_dl.payload.data_ind.payload);
@@ -1618,7 +1730,7 @@ altstep as_l1_sacch() runs on ConnHdlr {
}
}
-altstep as_l1_dcch() runs on ConnHdlr {
+private altstep as_l1_dcch() runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
[] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_DCCH(?))) -> value l1_dl {
log("DCCH received: ", l1_dl.payload.data_ind.payload);
@@ -1629,22 +1741,22 @@ altstep as_l1_dcch() runs on ConnHdlr {
}
}
-type record MeasElem {
+private type record MeasElem {
uint6_t rxlev,
uint3_t rxqual
}
-type record MeasElemFS {
+private type record MeasElemFS {
MeasElem full,
MeasElem sub
}
-type record ConnL1Pars {
+private type record ConnL1Pars {
boolean dtx_enabled,
boolean toa256_enabled,
MeasElemFS meas_ul,
int16_t timing_offset_256syms,
- uint5_t bs_power_level,
+ uint4_t bs_power_level,
uint5_t ms_power_level,
uint8_t ms_actual_ta
}
@@ -1733,18 +1845,86 @@ private function f_build_meas_res_tmpl() runs on ConnHdlr return template RSL_Me
?, t_toffs);
}
+/* build a template for matching measurement results that do not contain any
+ * MS related measurement (l1_info, l3_info and ms timing offset). */
+private function f_build_meas_res_tmpl_empty() runs on ConnHdlr return template RSL_Message {
+ var ConnL1Pars l1p := g_pars.l1_pars;
+ var template RSL_IE_UplinkMeas ul_meas := {
+ len := 3,
+ rfu := '0'B,
+ dtx_d := l1p.dtx_enabled,
+ rxlev_f_u := ?,
+ reserved1 := '00'B,
+ rxlev_s_u := ?,
+ reserved2 := '00'B,
+ rxq_f_u := ?,
+ rxq_s_u := ?,
+ supp_meas_info := omit
+ };
+ if (l1p.toa256_enabled) {
+ ul_meas.len := (3+8);
+ ul_meas.supp_meas_info := {
+ toa256_mean := f_tolerance(l1p.timing_offset_256syms, -63*256, 192*256, mp_tolerance_timing_offset_256syms),
+ toa256_min := ?,
+ toa256_max := ?,
+ toa256_std_dev := ?
+ }
+ }
+ var template RSL_IE_BS_Power bs_power := {
+ reserved := 0,
+ epc := false,
+ fpc := false,
+ power_level := l1p.bs_power_level
+ };
+
+ return tr_RSL_MEAS_RES_EMPTY(g_chan_nr, g_next_meas_res_nr, ul_meas, bs_power);
+}
+
/* verify we regularly receive measurement reports with incrementing numbers */
-altstep as_meas_res(boolean verify_meas := true) runs on ConnHdlr {
+private altstep as_meas_res(boolean verify_meas := true) runs on ConnHdlr {
var RSL_Message rsl;
+ var boolean chan_est := false;
+
[not verify_meas] RSL.receive(tr_RSL_MEAS_RES(?)) { repeat; }
+
+ /* Receive osmocom specific measurement reports. This is the normal
+ * case. Here we verify that the measurement reports we sent are
+ * comming back as we expect them. */
[] RSL.receive(f_build_meas_res_tmpl()) -> value rsl {
/* increment counter of next to-be-expected meas rep */
g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
/* Re-start the timer expecting the next MEAS RES */
f_timer_safe_restart(g_Tmeas_exp);
+
+ /* The following two cases may only happen in the beginning
+ * of the channel establishment phase. Once we have received
+ * the "our" measurement report the first time, the channel
+ * is established and empty or hardcoded TRXCON reports must
+ * not occur anymore. */
+ chan_est := true;
+
repeat;
}
- [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr, g_next_meas_res_nr)) -> value rsl {
+
+ /* When the BTS has established the channel, the MS might need slightly
+ * more time to establish the channel and actually start sending. The
+ * result is then a measurement report that just lacks the measurement
+ * information of the MS. This is normal and we tolerate this behavior. */
+ [chan_est == false] RSL.receive(f_build_meas_res_tmpl_empty()) -> value rsl {
+ /* increment counter of next to-be-expected meas rep */
+ g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
+ /* Re-start the timer expecting the next MEAS RES */
+ f_timer_safe_restart(g_Tmeas_exp);
+ repeat;
+ }
+
+ /* Due to the TDMA nature of GSM, TRXCON implements a way to emit dummy
+ * measurements if the TTCN3 side does not supply measurement input in
+ * time. In those cases TRXCON will either use a cached measurement
+ * report or a hardcoded one. If TRXCON picks the hardcoded measurement
+ * report the templates above will not match. We tolerate this
+ * behavior, but only once. */
+ [chan_est == false] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr, g_next_meas_res_nr)) -> value rsl {
/* increment counter of next to-be-expected meas rep */
g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
if (g_first_meas_res) {
@@ -1822,10 +2002,26 @@ private function f_rach_req_wait_chan_rqd(integer ra) runs on ConnHdlr return Gs
return fn;
}
+/* Tune to a dedicated channel: L1CTL only */
+private function f_l1ctl_est_dchan(L1CTL_PT pt, ConnHdlrPars pars) {
+ if (not ispresent(pars.maio_hsn)) {
+ pt.send(ts_L1CTL_DM_EST_REQ_H0(pars.chan_nr,
+ 7 /* TODO: mp_tsc */,
+ mp_trx0_arfcn));
+ } else {
+ pt.send(ts_L1CTL_DM_EST_REQ_H1(pars.chan_nr,
+ 7 /* TODO: mp_tsc */,
+ pars.maio_hsn.hsn,
+ pars.maio_hsn.maio,
+ pars.ma));
+ }
+}
+
/* Establish dedicated channel: L1CTL + RSL side */
private function f_est_dchan(boolean encr_enable := false, RSL_IE_List more_ies := {}) runs on ConnHdlr {
var GsmFrameNumber fn;
var ImmediateAssignment imm_ass;
+ var ChannelDescription ch_desc;
var integer ra := 23;
/* Send RACH request and wait for ChanReq */
@@ -1834,26 +2030,28 @@ private function f_est_dchan(boolean encr_enable := false, RSL_IE_List more_ies
/* Activate channel on BTS side */
f_rsl_chan_act(g_pars.chan_mode, encr_enable, more_ies);
+ /* Craft channel description (with or without frequency hopping parameters) */
+ if (ispresent(g_pars.maio_hsn)) {
+ ch_desc := valueof(ts_ChanDescH1(g_pars.chan_nr, g_pars.maio_hsn));
+ } else {
+ ch_desc := valueof(ts_ChanDescH0(g_pars.chan_nr, mp_trx0_arfcn));
+ }
+
/* Send IMM.ASS via CCHAN */
- var ChannelDescription ch_desc := {
- chan_nr := g_pars.chan_nr,
- tsc := 7,
- h := false,
- arfcn := mp_trx0_arfcn,
- maio_hsn := omit
- };
- var MobileAllocation ma := {
- len := 0,
- ma := ''B
- };
- var GsmRrMessage rr_msg := valueof(ts_IMM_ASS(ra, fn, 0, ch_desc, ma));
+ var GsmRrMessage rr_msg := valueof(ts_IMM_ASS(ra, fn, 0, ch_desc, g_pars.ma_map));
RSL.send(ts_RSL_IMM_ASSIGN(enc_GsmRrMessage(rr_msg)));
/* receive IMM.ASS on MS side */
var ImmediateAssignment ia_um;
ia_um := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, fn);
+
+ /* Make sure that IMM.ASS contains hopping parameters (if enabled) */
+ if (ch_desc.h != ia_um.chan_desc.h) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Hopping parameters mismatch");
+ }
+
/* enable dedicated mode */
- f_L1CTL_DM_EST_REQ_IA(L1CTL, ia_um);
+ f_L1CTL_DM_EST_REQ_IA(L1CTL, ia_um, ma := g_pars.ma);
/* enable encryption, if requested */
if (encr_enable) {
var uint8_t alg_id := f_alg_id_to_l1ctl(g_pars.encr.alg_id);
@@ -1864,7 +2062,7 @@ private function f_est_dchan(boolean encr_enable := false, RSL_IE_List more_ies
}
/* establish DChan, verify existance + contents of measurement reports */
-function f_TC_meas_res_periodic(charstring id) runs on ConnHdlr {
+private function f_TC_meas_res_periodic(charstring id) runs on ConnHdlr {
f_l1_tune(L1CTL);
RSL.clear;
@@ -1897,7 +2095,242 @@ function f_TC_meas_res_periodic(charstring id) runs on ConnHdlr {
f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
}
-function f_check_meas_bs_power_level(integer level) runs on ConnHdlr {
+/* Wait until the BTS has reached full tx power (nominal tx power minus configured attenuation) */
+private function f_wait_ramp_up() runs on ConnHdlr return integer {
+ var L1ctlDlMessage l1_dl;
+ var integer max_rx_lvl := mp_bts_tx_nom_pwr_exp - mp_bts_tx_pwr_att_exp;
+ timer Tup := 10.0;
+ Tup.start;
+ alt {
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
+ var GsmRxLev rx_lvl := l1_dl.dl_info.rx_level;
+ log("Received rx_level=", rx_lvl);
+
+ if (rx_lvl != max_rx_lvl) {
+ repeat;
+ }
+ Tup.stop;
+ }
+ [] L1CTL.receive { repeat; }
+ [] Tup.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Didn't reach full power ", max_rx_lvl));
+ }
+ }
+ return max_rx_lvl;
+}
+
+/* verify BTS ramps power up to full tx power (nominal tx power minus configured attenuation) */
+private function f_verify_ramp_up() runs on ConnHdlr {
+ var L1ctlDlMessage l1_dl;
+ var integer initial_rx_lvl := -1;
+ var integer last_rx_lvl := -1;
+ var integer max_rx_lvl := mp_bts_tx_nom_pwr_exp - mp_bts_tx_pwr_att_exp;
+
+ timer T := 2.0;
+ alt {
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
+ var GsmRxLev rx_lvl := l1_dl.dl_info.rx_level;
+ log("Received rx_level=", rx_lvl);
+ if (initial_rx_lvl == -1) {
+ initial_rx_lvl := rx_lvl;
+ last_rx_lvl := rx_lvl;
+
+ /* Expect a somehow low value during first received messages */
+ if (initial_rx_lvl >= max_rx_lvl / 2) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Detected high initial tx power during ramp up: ",
+ initial_rx_lvl , ", full power is", max_rx_lvl));
+ }
+ }
+
+ /* received Rx level bigger than maximum allowed power by CN */
+ if (rx_lvl > max_rx_lvl) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Detected Tx power higher than full power: ",
+ rx_lvl , " > ", max_rx_lvl));
+ }
+
+ /* Make sure it never decreases, since we are rumping up */
+ if (last_rx_lvl > rx_lvl) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Detected Tx power decrease during ramp up: ",
+ last_rx_lvl , " -> ", rx_lvl));
+ }
+
+ if (rx_lvl == max_rx_lvl and not T.running) {
+ /* We reached the maximum power, start timer and receive
+ /* a few more to make sure we don't surpass it */
+ log("Reached full power, wating a bit more until success");
+ T.start;
+ }
+
+ last_rx_lvl := rx_lvl;
+ repeat;
+ }
+ [] L1CTL.receive { repeat; }
+ [] T.timeout { }
+ }
+
+ /* We didn't increase tx power during ramp up */
+ if (initial_rx_lvl < last_rx_lvl) {
+ log("Tx power increased during ramp up: ", initial_rx_lvl , " -> ", last_rx_lvl);
+ } else {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("No Tx power increase during whole ramp up: ",
+ initial_rx_lvl , " -> ", last_rx_lvl));
+ }
+}
+
+/* verify BTS ramps power down to rx_level 0 */
+private function f_verify_ramp_down(integer max_rx_lvl) runs on ConnHdlr {
+ var L1ctlDlMessage l1_dl;
+ var integer last_rx_lvl := max_rx_lvl;
+
+ timer Tdown := 5.0;
+ Tdown.start;
+ alt {
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
+ var GsmRxLev rx_lvl := l1_dl.dl_info.rx_level;
+ log("Received rx_level=", rx_lvl);
+
+ /* received Rx level bigger than maximum allowed power by CN */
+ if (rx_lvl > max_rx_lvl) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Detected Tx power higher than full power: ",
+ rx_lvl , " > ", max_rx_lvl));
+ }
+
+ /* Make sure it never increases, since we are rumping down */
+ if (last_rx_lvl < rx_lvl) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Detected Tx power increase during ramp up: ",
+ last_rx_lvl , " -> ", rx_lvl));
+ }
+
+ last_rx_lvl := rx_lvl;
+ if (last_rx_lvl != 0) {
+ repeat;
+ }
+ /* we reached power level 0, we are done */
+ Tdown.stop;
+ }
+ [] L1CTL.receive { repeat; }
+ [] Tdown.timeout { }
+ }
+
+ /* We didn't increase tx power during ramp down */
+ if (max_rx_lvl > last_rx_lvl) {
+ log("Tx power decreased during ramp down: ", max_rx_lvl , " -> ", last_rx_lvl);
+ } else {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("No Tx power decrease during whole ramp down: ",
+ max_rx_lvl , " -> ", last_rx_lvl));
+ }
+}
+
+/* Verify Tx power reduction and ramping up during BTS bring up */
+private function f_TC_tx_power_start_ramp_up_bcch(charstring id) runs on ConnHdlr {
+ f_l1_tune(L1CTL);
+ RSL.clear;
+
+ f_verify_ramp_up();
+
+ setverdict(pass);
+}
+testcase TC_tx_power_start_ramp_up_bcch() runs on test_CT {
+ var ConnHdlr vc_conn;
+ var ConnHdlrPars pars;
+ f_init();
+ pars := valueof(t_Pars(t_RslChanNr_Bm(0), ts_RSL_ChanMode_SIGN));
+ vc_conn := f_start_handler(refers(f_TC_tx_power_start_ramp_up_bcch), pars,
+ pcu_comp := false, trxc_comp := true);
+ vc_conn.done;
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+}
+
+/* Verify Tx power reduction and ramping downd uring BTS bring shutdown due to Abis link failure */
+private function f_TC_tx_power_start_ramp_down_bcch(charstring id) runs on ConnHdlr {
+ f_connhdlr_init_vty_bsc();
+
+ f_l1_tune(L1CTL);
+ RSL.clear;
+
+ /* Wait until BTS is started and at full power */
+ var integer max_rx_lvl := f_wait_ramp_up();
+ log("Reached nominal level ", max_rx_lvl, ", shutting down OML link");
+
+ f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
+ f_verify_ramp_down(max_rx_lvl);
+
+ setverdict(pass);
+}
+testcase TC_tx_power_start_ramp_down_bcch() runs on test_CT {
+ var ConnHdlr vc_conn;
+ var ConnHdlrPars pars;
+ f_init();
+ pars := valueof(t_Pars(t_RslChanNr_Bm(0), ts_RSL_ChanMode_SIGN));
+ vc_conn := f_start_handler(refers(f_TC_tx_power_start_ramp_down_bcch), pars,
+ pcu_comp := false, trxc_comp := true);
+ vc_conn.done;
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+}
+
+/* Verify Tx power:
+ * + ramping down during ADM state UNLOCKED->LOCKED
+ * + ramping up during ADM state LOCKED->UNLOCKED
+ */
+private function f_TC_tx_power_ramp_adm_state_change(charstring id) runs on ConnHdlr {
+ var L1ctlDlMessage l1_dl;
+ var integer last_rx_lvl;
+
+ f_connhdlr_init_vty_bsc();
+
+ f_l1_tune(L1CTL);
+ RSL.clear;
+
+ /* Wait until BTS is started and at full power */
+ var integer max_rx_lvl := f_wait_ramp_up();
+ log("Reached nominal level ", max_rx_lvl, ", changing ADM state to LOCKED");
+
+ log("ADM STATE UNLOCKED->LOCKED");
+ f_vty_enter_cfg_trx(BSCVTY);
+ f_vty_transceive(BSCVTY, "rf_locked 1");
+ last_rx_lvl := max_rx_lvl;
+ f_verify_ramp_down(max_rx_lvl);
+
+ /* Let some time after we received 0dBm, then check we don't receive BCCH
+ * anymore because scheduler has stopped after ramping down */
+ f_sleep(2.0);
+ L1CTL.clear;
+ timer Tlocked := 2.0;
+ Tlocked.start;
+ alt {
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Received data_ind during rf_locked: ", l1_dl));
+ }
+ [] L1CTL.receive { repeat; }
+ [] Tlocked.timeout { setverdict(pass, "Didn't receive data_ind while in rf_locked state."); }
+ }
+
+ log("ADM STATE LOCKED->UNLOCKED");
+ f_vty_transceive(BSCVTY, "rf_locked 0");
+ f_verify_ramp_up();
+ setverdict(pass);
+}
+testcase TC_tx_power_ramp_adm_state_change() runs on test_CT {
+ var ConnHdlr vc_conn;
+ var ConnHdlrPars pars;
+ f_init();
+ pars := valueof(t_Pars(t_RslChanNr_Bm(0), ts_RSL_ChanMode_SIGN));
+ vc_conn := f_start_handler(refers(f_TC_tx_power_ramp_adm_state_change), pars,
+ pcu_comp := false, trxc_comp := true);
+ vc_conn.done;
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
+}
+
+private function f_check_meas_bs_power_level(integer level) runs on ConnHdlr {
timer T := 8.0;
T.start;
var RSL_Message rsl;
@@ -1919,7 +2352,7 @@ function f_check_meas_bs_power_level(integer level) runs on ConnHdlr {
/* see if the rsl meas res contains our expeced bs power level
bs power set during assignment */
-function f_TC_rsl_bs_pwr_static_ass(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_bs_pwr_static_ass(charstring id) runs on ConnHdlr {
f_l1_tune(L1CTL);
RSL.clear;
@@ -1928,7 +2361,7 @@ function f_TC_rsl_bs_pwr_static_ass(charstring id) runs on ConnHdlr {
f_trxc_fake_toffs256(g_pars.l1_pars.timing_offset_256syms);
}
- var uint5_t pwr_var := 1;
+ var uint4_t pwr_var := 1;
var template (value) RSL_IE_BS_Power bs_power := ts_RSL_IE_BS_Power(pwr_var);
var template (value) RSL_IE pwr := t_RSL_IE(RSL_IE_BS_POWER, RSL_IE_Body:{bs_power := bs_power});
@@ -1942,7 +2375,7 @@ function f_TC_rsl_bs_pwr_static_ass(charstring id) runs on ConnHdlr {
/* see if the rsl meas res contains our expeced bs power level
bs power set after assignment */
-function f_TC_rsl_bs_pwr_static_power_control(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_bs_pwr_static_power_control(charstring id) runs on ConnHdlr {
f_l1_tune(L1CTL);
RSL.clear;
@@ -1951,7 +2384,7 @@ function f_TC_rsl_bs_pwr_static_power_control(charstring id) runs on ConnHdlr {
f_trxc_fake_toffs256(g_pars.l1_pars.timing_offset_256syms);
}
- var uint5_t pwr_var := 1;
+ var uint4_t pwr_var := 1;
var template (value) RSL_IE_BS_Power bs_power := ts_RSL_IE_BS_Power(pwr_var);
f_est_dchan();
@@ -1993,7 +2426,7 @@ testcase TC_rsl_bs_pwr_static_power_control() runs on test_CT {
/* target level -100, first rssi -90, ms power 7, expected increase to 7+6 within 6 seconds,
second rssi -110, ms power 7+6, expected decrease to 7 within 6 seconds,
These power levels are valid for all bands and require no special handling */
-function f_TC_rsl_ms_pwr_dyn_ass_updown(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_ms_pwr_dyn_ass_updown(charstring id) runs on ConnHdlr {
var uint5_t pwr_var := 7;
var L1ctlDlMessage l1_dl;
@@ -2019,9 +2452,11 @@ function f_TC_rsl_ms_pwr_dyn_ass_updown(charstring id) runs on ConnHdlr {
T2.start;
alt {
[] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
- if( not(oct2int(l1_dl.payload.data_ind.payload[0]) > (pwr_var+6))){
+ /* Update sent MS power to follow what BTS requests */
+ f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
+ if (oct2int(l1_dl.payload.data_ind.payload[0]) < (pwr_var + 6)) {
repeat;
- }
+ }
T2.stop;
}
[] L1CTL.receive { repeat; }
@@ -2038,9 +2473,11 @@ function f_TC_rsl_ms_pwr_dyn_ass_updown(charstring id) runs on ConnHdlr {
T4.start;
alt {
[] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
- if( not(oct2int(l1_dl.payload.data_ind.payload[0]) <= (pwr_var))){
+ /* Update sent MS power to follow what BTS requests */
+ f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
+ if (oct2int(l1_dl.payload.data_ind.payload[0]) > pwr_var) {
repeat;
- }
+ }
T4.stop;
setverdict(pass, "Power level in L1 decreased/increased as expected");
}
@@ -2057,7 +2494,7 @@ function f_TC_rsl_ms_pwr_dyn_ass_updown(charstring id) runs on ConnHdlr {
}
/* check that we do not exceed the max power */
-function f_TC_rsl_ms_pwr_dyn_max(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_ms_pwr_dyn_max(charstring id) runs on ConnHdlr {
var uint5_t pwr_var := 7;
var L1ctlDlMessage l1_dl;
@@ -2080,7 +2517,11 @@ function f_TC_rsl_ms_pwr_dyn_max(charstring id) runs on ConnHdlr {
timer T1 := 10.0;
T1.start;
alt {
- [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl { repeat; }
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
+ /* Update sent MS power to follow what BTS requests */
+ f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
+ repeat;
+ }
[] L1CTL.receive { repeat; }
[] T1.timeout {
if( oct2int(l1_dl.payload.data_ind.payload[0]) != pwr_var){
@@ -2095,7 +2536,7 @@ function f_TC_rsl_ms_pwr_dyn_max(charstring id) runs on ConnHdlr {
}
/* see if we reach the band max power */
-function f_TC_rsl_ms_pwr_dyn_up(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_ms_pwr_dyn_up(charstring id) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
var uint5_t pwr_var := 15;
var uint5_t pwr_max_var := f_get_max_power_from_band();
@@ -2122,7 +2563,11 @@ function f_TC_rsl_ms_pwr_dyn_up(charstring id) runs on ConnHdlr {
timer T1 := 10.0;
T1.start;
alt {
- [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl { repeat; }
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
+ /* Update sent MS power to follow what BTS requests */
+ f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
+ repeat;
+ }
[] L1CTL.receive { repeat; }
[] T1.timeout {
var int8_t rcv := oct2int(l1_dl.payload.data_ind.payload[0]);
@@ -2141,7 +2586,7 @@ function f_TC_rsl_ms_pwr_dyn_up(charstring id) runs on ConnHdlr {
}
/* see if we reach the band min power */
-function f_TC_rsl_ms_pwr_dyn_down(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_ms_pwr_dyn_down(charstring id) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
/* set a high value to ensure power decreases */
@@ -2163,13 +2608,17 @@ function f_TC_rsl_ms_pwr_dyn_down(charstring id) runs on ConnHdlr {
/* update power param to enable power loop
as per spec the supplied ms power IE should set the max allowed power...*/
- RSL.send(ts_RSL_MS_PWR_CTRL_with_pp(g_chan_nr, pwr_var));
+ RSL.send(ts_RSL_MS_PWR_CTRL_with_pp(g_chan_nr, pwr_target_val));
/* wait, then check that our power level was increased */
timer T1 := 10.0;
T1.start;
alt {
- [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl { repeat; }
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
+ /* Update sent MS power to follow what BTS requests */
+ f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
+ repeat;
+ }
[] L1CTL.receive { repeat; }
[] T1.timeout {
if( f_power_level_is_lowest_dbm(oct2int(l1_dl.payload.data_ind.payload[0])) ){
@@ -2188,7 +2637,7 @@ function f_TC_rsl_ms_pwr_dyn_down(charstring id) runs on ConnHdlr {
/* see if we change the power level without receiving power parameters, which should not happen
rsl chan act WITHOUT power parameters */
-function f_TC_rsl_ms_pwr_dyn_active(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_ms_pwr_dyn_active(charstring id) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
/* set a high value to ensure power decreases */
@@ -2229,7 +2678,7 @@ function f_TC_rsl_ms_pwr_dyn_active(charstring id) runs on ConnHdlr {
/* see if we change the power level without receiving power parameters, which should not happen
ms power control WITHOUT power parameters */
-function f_TC_rsl_ms_pwr_dyn_active2(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_ms_pwr_dyn_active2(charstring id) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
/* set a high value to ensure power decreases */
@@ -2271,7 +2720,7 @@ function f_TC_rsl_ms_pwr_dyn_active2(charstring id) runs on ConnHdlr {
}
-function f_wait_for_l1_power_level(integer level) runs on ConnHdlr {
+private function f_wait_for_l1_power_level(integer level) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
timer T0 := 10.0;
T0.start;
@@ -2325,7 +2774,7 @@ private function f_get_max_power_from_band() runs on ConnHdlr return integer {
}
type charstring BtsBand ("GSM450","GSM480","GSM750","GSM810","GSM850","GSM900","DCS1800","PCS1900");
-template charstring BtsBand_allGSM:= pattern "GSM???";
+private template charstring BtsBand_allGSM := pattern "GSM???";
private function f_power_from_band(in BtsBand band, out IntegerRecord min_dbm_level, out IntegerRecord max_dbm_level) return IntegerRecord {
// 45.005 4.1.1
var IntegerRecord gsm_power :={31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
@@ -2515,7 +2964,7 @@ testcase TC_meas_res_sign_tchh_toa256() runs on test_CT {
/* establish DChan, and send MS POWER CONTROL messages via RSL, verify that
* the BTS is forwarding those values to the MS via the SACCH L1 header. */
-function f_tc_rsl_ms_pwr_ctrl(charstring id) runs on ConnHdlr {
+private function f_tc_rsl_ms_pwr_ctrl(charstring id) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
var RSL_IE_MS_Power ms_power;
var RSL_Message rsl;
@@ -2584,9 +3033,9 @@ testcase TC_rsl_ms_pwr_ctrl() runs on test_CT {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
-/* establish DChan, verify that the BTS sets the TA in the first SACCH L1 header.
+/* establish DChan, verify that the BTS sets the TA in the first SACCH L1 header.
TA for the IMM ASS messages is still controlled by g_pars.l1_pars.ms_actual_ta! */
-function f_tc_rsl_chan_initial_ta(charstring id) runs on ConnHdlr {
+private function f_tc_rsl_chan_initial_ta(charstring id) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
var uint5_t ta_to_test := 16;
@@ -2635,7 +3084,7 @@ testcase TC_rsl_chan_initial_ta() runs on test_CT {
}
/* establish DChan, verify that the BTS sets MS power in the first SACCH L1 header. */
-function f_tc_rsl_chan_initial_ms_pwr(charstring id) runs on ConnHdlr {
+private function f_tc_rsl_chan_initial_ms_pwr(charstring id) runs on ConnHdlr {
var L1ctlDlMessage l1_dl;
var uint5_t ms_power_level := 7;
@@ -2712,7 +3161,7 @@ testcase TC_conn_fail_crit() runs on test_CT {
* Paging
***********************************************************************/
-function tmsi_is_dummy(TMSIP_TMSI_V tmsi) return boolean {
+private function tmsi_is_dummy(TMSIP_TMSI_V tmsi) return boolean {
if (tmsi == 'FFFFFFFF'O) {
return true;
} else {
@@ -2720,16 +3169,16 @@ function tmsi_is_dummy(TMSIP_TMSI_V tmsi) return boolean {
}
}
-type record allowedFn { integer frame_nr }
-template allowedFn bs_ag_blks_res_0 := { frame_nr := (6, 12, 16, 22, 26, 32, 36, 42, 46) }
-template allowedFn bs_ag_blks_res_1 := { frame_nr := (12, 16, 22, 26, 32, 36, 42, 46) }
-template allowedFn bs_ag_blks_res_2 := { frame_nr := (16, 22, 26, 32, 36, 42, 46) }
-template allowedFn bs_ag_blks_res_3 := { frame_nr := (22, 26, 32, 36, 42, 46) }
-template allowedFn bs_ag_blks_res_4 := { frame_nr := (26, 32, 36, 42, 46) }
-template allowedFn bs_ag_blks_res_5 := { frame_nr := (32, 36, 42, 46) }
-template allowedFn bs_ag_blks_res_6 := { frame_nr := (36, 42, 46) }
-template allowedFn bs_ag_blks_res_7 := { frame_nr := (42, 46) }
-function check_pch_fn(integer frame_nr, integer bs_ag_blks_res) runs on test_CT
+private type record allowedFn { integer frame_nr }
+private template allowedFn bs_ag_blks_res_0 := { frame_nr := (6, 12, 16, 22, 26, 32, 36, 42, 46) }
+private template allowedFn bs_ag_blks_res_1 := { frame_nr := (12, 16, 22, 26, 32, 36, 42, 46) }
+private template allowedFn bs_ag_blks_res_2 := { frame_nr := (16, 22, 26, 32, 36, 42, 46) }
+private template allowedFn bs_ag_blks_res_3 := { frame_nr := (22, 26, 32, 36, 42, 46) }
+private template allowedFn bs_ag_blks_res_4 := { frame_nr := (26, 32, 36, 42, 46) }
+private template allowedFn bs_ag_blks_res_5 := { frame_nr := (32, 36, 42, 46) }
+private template allowedFn bs_ag_blks_res_6 := { frame_nr := (36, 42, 46) }
+private template allowedFn bs_ag_blks_res_7 := { frame_nr := (42, 46) }
+private function check_pch_fn(integer frame_nr, integer bs_ag_blks_res) runs on test_CT
{
var integer frame_nr_51;
frame_nr_51 := frame_nr mod 51
@@ -2771,7 +3220,9 @@ function check_pch_fn(integer frame_nr, integer bs_ag_blks_res) runs on test_CT
return;
}
-altstep as_l1_count_paging(inout integer num_paging_rcv_msgs, inout integer num_paging_rcv_ids, PagingTestCfg cfg)
+private altstep as_l1_count_paging(inout integer num_paging_rcv_msgs,
+ inout integer num_paging_rcv_ids,
+ PagingTestCfg cfg)
runs on test_CT {
var L1ctlDlMessage dl;
[] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_DummyUI)) {
@@ -2784,10 +3235,13 @@ runs on test_CT {
check_pch_fn(dl.dl_info.frame_nr, cfg.bs_ag_blks_res);
- if (match(rr, tr_PAGING_REQ1)) {
+ if (match(rr, tr_PAGING_REQ1(tr_MI_LV(t_MI_NoIdentity(?))))) {
+ /* Ignore empty RR Paging Request (PCH filling) messages.
+ * TODO: does it make sense to count them? */
+ } else if (match(rr, tr_PAGING_REQ1)) {
num_paging_rcv_msgs := num_paging_rcv_msgs + 1;
num_paging_rcv_ids := num_paging_rcv_ids + 1;
- if (isvalue(rr.msgs.rrm.pagingReq_Type1.mobileIdentity2)) {
+ if (ispresent(rr.msgs.rrm.pagingReq_Type1.mobileIdentity2)) {
num_paging_rcv_ids := num_paging_rcv_ids + 1;
}
} else if (match(rr, tr_PAGING_REQ2)) {
@@ -2798,7 +3252,7 @@ runs on test_CT {
if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type2.mobileIdentity2)) {
num_paging_rcv_ids := num_paging_rcv_ids + 1;
}
- if (isvalue(rr.msgs.rrm.pagingReq_Type2.mobileIdentity3)) {
+ if (ispresent(rr.msgs.rrm.pagingReq_Type2.mobileIdentity3)) {
num_paging_rcv_ids := num_paging_rcv_ids + 1;
}
} else if (match(rr, tr_PAGING_REQ3)) {
@@ -2820,7 +3274,7 @@ runs on test_CT {
}
}
-type record PagingTestCfg {
+private type record PagingTestCfg {
boolean combined_ccch,
integer bs_ag_blks_res,
float load_factor,
@@ -2829,20 +3283,13 @@ type record PagingTestCfg {
boolean use_tmsi
}
-type record PagingTestState {
+private type record PagingTestState {
integer num_paging_sent,
integer num_paging_rcv_msgs,
integer num_paging_rcv_ids,
integer num_overload
}
-/* receive + ignore RSL RF RES IND */
-altstep as_rsl_res_ind() runs on test_CT {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RF_RES_IND)) {
- repeat;
- }
-}
-
/* Helper function for paging related testing */
private function f_TC_paging(PagingTestCfg cfg) runs on test_CT return PagingTestState {
f_init();
@@ -2877,14 +3324,14 @@ private function f_TC_paging(PagingTestCfg cfg) runs on test_CT return PagingTes
while (st.num_paging_sent < pkt_total) {
alt {
/* check for presence of CCCH LOAD IND (paging load) */
- [cfg.exp_overload] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
+ [cfg.exp_overload] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
st.num_overload := st.num_overload + 1;
repeat;
}
- [not cfg.exp_overload] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
+ [not cfg.exp_overload] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PCH Overload");
}
- [cfg.exp_load_ind] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND)) {
+ [cfg.exp_load_ind] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND)) {
log("Rx LOAD_IND");
/* FIXME: analyze/verify interval + contents */
repeat;
@@ -2896,18 +3343,17 @@ private function f_TC_paging(PagingTestCfg cfg) runs on test_CT return PagingTes
/* Send paging cmds based on elapsed time */
var integer new_sent := f_min(pkt_total, float2int(T_total.read * pch_blocks_per_sec) + 1);
while (st.num_paging_sent < new_sent) {
+ var MobileIdentityV mi;
+
/* build mobile Identity */
- var MobileL3_CommonIE_Types.MobileIdentityLV mi;
if (cfg.use_tmsi) {
- mi := valueof(ts_MI_TMSI_LV(f_rnd_octstring(4)));
+ mi := valueof(t_MI_TMSI(f_rnd_octstring(4)));
} else {
- mi := valueof(ts_MI_IMSI_LV(f_gen_imsi(st.num_paging_sent)));
+ mi := valueof(ts_MI_IMSI(f_gen_imsi(st.num_paging_sent)));
}
- var octetstring mi_enc_lv := enc_MobileIdentityLV(mi);
- var octetstring mi_enc := substr(mi_enc_lv, 1, lengthof(mi_enc_lv)-1);
/* Send RSL PAGING COMMAND */
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_PAGING_CMD(mi_enc, st.num_paging_sent mod 4)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_PAGING_CMD(mi, st.num_paging_sent mod 4)));
st.num_paging_sent := st.num_paging_sent + 1;
}
@@ -2926,7 +3372,6 @@ private function f_TC_paging(PagingTestCfg cfg) runs on test_CT return PagingTes
}
}
[] T_total.timeout { }
- [] as_rsl_res_ind();
}
}
@@ -2937,12 +3382,11 @@ private function f_TC_paging(PagingTestCfg cfg) runs on test_CT return PagingTes
[] as_l1_count_paging(st.num_paging_rcv_msgs, st.num_paging_rcv_ids, cfg);
[] L1CTL.receive { repeat; }
/* 65535 == empty paging queue, we can terminate*/
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND(65535))) { }
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND)) { repeat; }
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND(65535))) { }
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND)) { repeat; }
[] T_wait.timeout {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Waiting for empty paging queue");
}
- [] as_rsl_res_ind();
}
log("num_paging_sent=", st.num_paging_sent, " rcvd_msgs=", st.num_paging_rcv_msgs,
@@ -3054,20 +3498,11 @@ testcase TC_paging_tmsi_200percent() runs on test_CT {
/***********************************************************************
* Immediate Assignment / AGCH
***********************************************************************/
-const MobileAllocation c_MA_null := {
+private const MobileAllocationLV c_MA_null := {
len := 0,
ma := ''B
}
-template (value) ChannelDescription ts_ChanDesc(template (value) RslChannelNr chan_nr, uint3_t tsc := 7,
- uint12_t arfcn := 871) := {
- chan_nr := chan_nr,
- tsc := tsc,
- h := false,
- arfcn := arfcn,
- maio_hsn := omit
-}
-
private function f_fmt_ia_stats(integer num_tx, integer num_rx, integer num_del) return charstring {
return int2str(num_tx) & " sent, "
& int2str(num_rx) & " received, "
@@ -3088,17 +3523,17 @@ private function f_TC_imm_ass(integer num_total, float sleep_s, float exp_pass)
f_l1_tune(L1CTL);
for (var integer i := 0; i < num_total; i := i+1) {
- var ChannelDescription ch_desc := valueof(ts_ChanDesc(valueof(t_RslChanNr_SDCCH4(0, 0))));
+ var ChannelDescription ch_desc := valueof(ts_ChanDescH0(t_RslChanNr_SDCCH4(0, 0), mp_trx0_arfcn));
var GsmRrMessage ia := valueof(ts_IMM_ASS(42, i, 5, ch_desc, c_MA_null));
var octetstring ia_enc := enc_GsmRrMessage(ia);
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_IMM_ASSIGN(ia_enc, 0)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_IMM_ASSIGN(ia_enc, 0)));
num_tx := num_tx+1;
f_sleep(sleep_s);
}
/* FIXME: check if imm.ass arrive on Um side */
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_DELETE_IND(?, 0))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_DELETE_IND(?, 0))) {
num_del := num_del+1;
repeat;
}
@@ -3106,7 +3541,6 @@ private function f_TC_imm_ass(integer num_total, float sleep_s, float exp_pass)
repeat;
}
[] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?)) -> value l1_dl {
- /* somehow dec_SystemInformation will try to decode even non-RR as SI */
var GsmRrMessage rr := dec_GsmRrMessage(l1_dl.payload.data_ind.payload);
if (not match(rr, tr_IMM_ASS(42, ?, 5, ?, ?))) {
/* FIXME: Why are we seeing paging requests on PCH/AGCH? */
@@ -3155,19 +3589,22 @@ testcase TC_imm_ass_200_76ms() runs on test_CT {
***********************************************************************/
/* tuple of Frame Number + decoded SI */
-type record SystemInformationFn {
+private type record SystemInformationFn {
GsmFrameNumber frame_number,
SystemInformation si
}
/* an arbitrary-length vector of decoded SI + gsmtap header */
-type record of SystemInformationFn SystemInformationVector;
+private type record of SystemInformationFn SystemInformationVector;
/* an array of SI-vectors indexed by TC value */
-type SystemInformationVector SystemInformationVectorPerTc[8];
+private type SystemInformationVector SystemInformationVectorPerTc[8];
/* determine if a given SI vector contains given SI type at least once */
-function f_si_vecslot_contains(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean {
+private function f_si_vecslot_contains(SystemInformationVector arr,
+ RrMessageType key,
+ boolean bcch_ext := false)
+return boolean {
for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
var integer fn_mod51 := arr[i].frame_number mod 51;
if (not bcch_ext and fn_mod51 == 2 or
@@ -3181,14 +3618,19 @@ function f_si_vecslot_contains(SystemInformationVector arr, RrMessageType key, b
}
/* ensure a given TC slot of the SI vector contains given SI type at least once at TC */
-function f_ensure_si_vec_contains(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) {
+private function f_ensure_si_vec_contains(SystemInformationVectorPerTc arr,
+ integer tc, RrMessageType key,
+ boolean ext_bcch := false)
+{
if (not f_si_vecslot_contains(arr[tc], key, ext_bcch)) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No ", key, " in TC=", tc, "!"));
}
}
/* check if a given SI vector contains given SI type at least once on any TC */
-function f_si_vec_contains(SystemInformationVectorPerTc arr, RrMessageType key) return boolean {
+private function f_si_vec_contains(SystemInformationVectorPerTc arr,
+ RrMessageType key)
+return boolean {
for (var integer tc:= 0; tc < sizeof(arr); tc := tc + 1) {
if (f_si_vecslot_contains(arr[tc], key) or
f_si_vecslot_contains(arr[tc], key, true)) {
@@ -3199,7 +3641,11 @@ function f_si_vec_contains(SystemInformationVectorPerTc arr, RrMessageType key)
}
/* determine if a given SI vector contains given SI type at least N of M times */
-function f_si_vecslot_contains_n_of_m(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false, integer n := 1, integer m := 4) return boolean {
+private function f_si_vecslot_contains_n_of_m(SystemInformationVector arr,
+ RrMessageType key,
+ boolean bcch_ext := false,
+ integer n := 1, integer m := 4)
+return boolean {
var integer count := 0;
if (sizeof(arr) < m) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Error: Insufficient SI in array");
@@ -3221,14 +3667,21 @@ function f_si_vecslot_contains_n_of_m(SystemInformationVector arr, RrMessageType
}
/* ensure a given TC slot of the SI vector contains given SI type at least N out of M times at TC */
-function f_ensure_si_vec_contains_n_of_m(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false, integer n, integer m) {
+private function f_ensure_si_vec_contains_n_of_m(SystemInformationVectorPerTc arr,
+ integer tc, RrMessageType key,
+ boolean ext_bcch := false,
+ integer n, integer m)
+{
if (not f_si_vecslot_contains_n_of_m(arr[tc], key, ext_bcch, n, m)) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Not ", n, "/", m, " of ", key, " in TC=", tc, "!"));
}
}
/* determine if a given SI vector contains given SI type at least once */
-function f_si_vecslot_contains_only(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean {
+private function f_si_vecslot_contains_only(SystemInformationVector arr,
+ RrMessageType key,
+ boolean bcch_ext := false)
+return boolean {
for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
var integer fn_mod51 := arr[i].frame_number mod 51;
if (not bcch_ext and fn_mod51 == 2 or
@@ -3242,14 +3695,17 @@ function f_si_vecslot_contains_only(SystemInformationVector arr, RrMessageType k
}
/* ensure a given TC slot of the SI vector contains only given SI type */
-function f_ensure_si_vec_contains_only(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) {
+private function f_ensure_si_vec_contains_only(SystemInformationVectorPerTc arr,
+ integer tc, RrMessageType key,
+ boolean ext_bcch := false)
+{
if (not f_si_vecslot_contains_only(arr[tc], key, ext_bcch)) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Not all ", key, " in TC=", tc, "!"));
}
}
/* SI configuration of cell, against which we validate actual SI messages */
-type set SystemInformationConfig {
+private type set SystemInformationConfig {
boolean bcch_extended,
boolean si1_present,
boolean si2bis_present,
@@ -3269,7 +3725,9 @@ type set SystemInformationConfig {
}
/* validate the SI scheduling according to TS 45.002 version 14.1.0 Release 14, Section 6.3.1.3 */
-function f_validate_si_scheduling(SystemInformationConfig cfg, SystemInformationVectorPerTc si_per_tc) {
+private function f_validate_si_scheduling(SystemInformationConfig cfg,
+ SystemInformationVectorPerTc si_per_tc)
+{
var integer i;
for (i := 0; i < sizeof(si_per_tc); i := i + 1) {
if (sizeof(si_per_tc[i]) == 0) {
@@ -3467,7 +3925,8 @@ function f_validate_si_scheduling(SystemInformationConfig cfg, SystemInformation
}
/* sample Systme Information for specified duration via L1CTL */
-function f_l1_sample_si(L1CTL_PT pt, float duration := 8.0) return SystemInformationVectorPerTc {
+private function f_l1_sample_si(L1CTL_PT pt, float duration := 8.0)
+return SystemInformationVectorPerTc {
timer T := duration;
var SystemInformationVectorPerTc si_per_tc;
var L1ctlDlMessage l1_dl;
@@ -3483,15 +3942,12 @@ function f_l1_sample_si(L1CTL_PT pt, float duration := 8.0) return SystemInforma
T.start;
alt {
[] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
- /* somehow dec_SystemInformation will try to decode even non-RR as SI */
- if (not (l1_dl.payload.data_ind.payload[1] == '06'O)) {
- log("Ignoring non-RR SI ", l1_dl);
+ var SystemInformationFn sig := { frame_number := l1_dl.dl_info.frame_nr };
+ if (dec_SystemInformationSafe(l1_dl.payload.data_ind.payload, sig.si) != 0) {
+ log("Ignoring non-RR or invalid SI ", l1_dl);
repeat;
}
- var SystemInformationFn sig := {
- frame_number := l1_dl.dl_info.frame_nr,
- si := dec_SystemInformation(l1_dl.payload.data_ind.payload)
- }
+
var integer tc := f_gsm_compute_tc(sig.frame_number);
log("SI received at TC=", tc, ": ", sig.si);
/* append to the per-TC bucket */
@@ -3511,7 +3967,7 @@ function f_l1_sample_si(L1CTL_PT pt, float duration := 8.0) return SystemInforma
/* helper function: Set given SI via RSL + validate scheduling.
* CALLER MUST MAKE SURE TO CHANGE GLOBAL si_cfg! */
-function f_TC_si_sched() runs on test_CT {
+private function f_TC_si_sched() runs on test_CT {
var SystemInformationVectorPerTc si_per_tc;
f_init_l1ctl();
f_l1_tune(L1CTL);
@@ -3612,10 +4068,10 @@ private function f_exp_err_rep(template RSL_Cause cause) runs on test_CT {
timer T := 5.0;
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_ERROR_REPORT(cause))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_ERROR_REPORT(cause))) {
setverdict(pass);
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_ERROR_REPORT(?))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_ERROR_REPORT(?))) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Wrong cause in RSL ERR REP");
}
[] RSL_CCHAN.receive {
@@ -3632,7 +4088,7 @@ testcase TC_rsl_protocol_error() runs on test_CT {
f_init();
var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
rsl.ies := omit;
- RSL_CCHAN.send(ts_RSL_UD(rsl));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
f_exp_err_rep(RSL_ERR_PROTO);
}
@@ -3643,7 +4099,7 @@ testcase TC_rsl_mand_ie_error() runs on test_CT {
var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
rsl.ies := { rsl.ies[0] };
- RSL_CCHAN.send(ts_RSL_UD(rsl));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
f_exp_err_rep(RSL_ERR_MAND_IE_ERROR);
}
@@ -3653,7 +4109,7 @@ testcase TC_rsl_ie_content_error() runs on test_CT {
f_init();
var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
rsl.ies[1].body.sysinfo_type := RSL_SYSTEM_INFO_5;
- RSL_CCHAN.send(ts_RSL_UD(rsl));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
f_exp_err_rep(RSL_ERR_IE_CONTENT);
}
@@ -3679,14 +4135,14 @@ testcase TC_err_rep_wrong_mdisc() runs on test_CT {
}
/* Send messages with wrong message type */
-function f_TC_wrong_msg_type_dchan(charstring id) runs on ConnHdlr {
+private function f_TC_wrong_msg_type_dchan(charstring id) runs on ConnHdlr {
var template (value) RSL_Message rsl_tx;
rsl_tx := ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode);
rsl_tx.msg_type := RSL_MT_NOT_CMD;
RSL.send(rsl_tx);
f_rslem_unregister(0, g_chan_nr);
}
-function f_TC_wrong_msg_type_rll(charstring id) runs on ConnHdlr {
+private function f_TC_wrong_msg_type_rll(charstring id) runs on ConnHdlr {
var template (value) RSL_Message rsl_tx;
/* we first have to activate the dedicated channel */
f_rsl_chan_act(g_pars.chan_mode);
@@ -3707,14 +4163,14 @@ testcase TC_err_rep_wrong_msg_type() runs on test_CT {
RSL_CCHAN.clear;
rsl_tx := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
rsl_tx.msg_type := RSL_MT_LOCATION_INFO;
- RSL_CCHAN.send(ts_RSL_UD(rsl_tx));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(rsl_tx));
f_exp_err_rep(RSL_ERR_MSG_TYPE);
/* TRX Management */
RSL_CCHAN.clear;
rsl_tx := ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, ''O);
rsl_tx.msg_type := RSL_MT_UNIT_DATA_IND;
- RSL_CCHAN.send(ts_RSL_UD(rsl_tx));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(rsl_tx));
f_exp_err_rep(RSL_ERR_MSG_TYPE);
/* Dedicated Channel */
@@ -3731,7 +4187,7 @@ testcase TC_err_rep_wrong_msg_type() runs on test_CT {
}
/* Send messages in wrong sequence (RLL to an inactive lchan) */
-function f_TC_err_rep_wrong_sequence(charstring id) runs on ConnHdlr {
+private function f_TC_err_rep_wrong_sequence(charstring id) runs on ConnHdlr {
RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, ts_RslLinkID_DCCH(0), '0102'O));
f_rslem_unregister(0, g_chan_nr);
}
@@ -3752,7 +4208,7 @@ testcase TC_err_rep_wrong_sequence() runs on test_CT {
***********************************************************************/
/* Send IPA DLCX to inactive lchan */
-function f_TC_ipa_dlcx_not_active(charstring id) runs on ConnHdlr {
+private function f_TC_ipa_dlcx_not_active(charstring id) runs on ConnHdlr {
f_rsl_transceive(ts_RSL_IPA_DLCX(g_chan_nr, 0), tr_RSL_IPA_DLCX_ACK(g_chan_nr, ?, ?),
"IPA DLCX ACK");
}
@@ -3764,7 +4220,7 @@ testcase TC_ipa_dlcx_not_active() runs on test_CT {
}
/* Send IPA CRCX twice to inactive lchan */
-function f_TC_ipa_crcx_twice_not_active(charstring id) runs on ConnHdlr {
+private function f_TC_ipa_crcx_twice_not_active(charstring id) runs on ConnHdlr {
f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
"IPA CRCX ACK");
f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_NACK(g_chan_nr, RSL_ERR_RES_UNAVAIL),
@@ -3778,7 +4234,7 @@ testcase TC_ipa_crcx_twice_not_active() runs on test_CT {
}
/* Regular sequence of CRCX/MDCX/DLCX */
-function f_TC_ipa_crcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
+private function f_TC_ipa_crcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
"IPA CRCX ACK");
var uint32_t remote_ip := f_rnd_int(c_UINT32_MAX);
@@ -3799,7 +4255,7 @@ testcase TC_ipa_crcx_mdcx_dlcx_not_active() runs on test_CT {
}
/* Sequence of CRCX, 2x MDCX, DLCX */
-function f_TC_ipa_crcx_mdcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
+private function f_TC_ipa_crcx_mdcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
"IPA CRCX ACK");
var uint32_t remote_ip := f_rnd_int(c_UINT32_MAX);
@@ -3826,7 +4282,7 @@ testcase TC_ipa_crcx_mdcx_mdcx_dlcx_not_active() runs on test_CT {
}
/* IPA CRCX on SDCCH/4 and SDCCH/8 (doesn't make sense) */
-function f_TC_ipa_crcx_sdcch_not_active(charstring id) runs on ConnHdlr {
+private function f_TC_ipa_crcx_sdcch_not_active(charstring id) runs on ConnHdlr {
f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_NACK(g_chan_nr, ?),
"IPA CRCX NACK");
}
@@ -4146,6 +4602,7 @@ testcase TC_pcu_data_req_pdtch() runs on test_CT {
f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PDTCH, data); //c_PCU_DATA);
}
+/* FIXME: PTTCH has nothing to do with TBFs */
testcase TC_pcu_data_req_ptcch() runs on test_CT {
var TfiUsfArr tua := f_TfiUsfArrInit();
var octetstring data := '0000'O & f_rnd_octstring(21);
@@ -4160,6 +4617,95 @@ testcase TC_pcu_data_req_ptcch() runs on test_CT {
f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PTCCH, data);
}
+private function f_TC_pcu_ptcch_ul(uint16_t ra)
+runs on test_CT {
+ var template PCUIF_Message pcu_rach_ind;
+ var PCUIF_send_data sd;
+ var GsmFrameNumber fn;
+ timer T;
+
+ /* Send an Access Burst on PTCCH/U over the Um-interface */
+ fn := f_L1CTL_RACH(L1CTL, ra := ra, combined := 0, offset := 0,
+ chan_nr := ts_RslChanNr_PDCH(7),
+ link_id := ts_RslLinkID_OSMO_PTCCH(0));
+
+ pcu_rach_ind := tr_PCUIF_RACH_IND(bts_nr := 0, trx_nr := 0, ts_nr := 7,
+ ra := ra, fn := fn, sapi := PCU_IF_SAPI_PTCCH);
+
+ /* Expect a RACH.ind on the PCU interface (timeout is one multi-frame) */
+ T.start(52.0 * 4.615 / 1000.0);
+ alt {
+ [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, pcu_rach_ind)) -> value sd {
+ log("Rx an Access Burst on the PCU interface: ", sd.data);
+ setverdict(pass);
+ T.stop;
+ }
+ [] PCU.receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for RACH.ind on the PCU interface");
+ /* Keep going, that's not the end of the world */
+ }
+ }
+}
+
+testcase TC_pcu_ptcch() runs on test_CT {
+ var L1ctlDlMessage dl;
+ var octetstring data;
+ timer T;
+
+ f_init_pcu_test();
+ f_init_l1ctl();
+ f_l1_tune(L1CTL);
+
+ /* Activate PDCH channel on TS7 */
+ f_TC_pcu_act_req(0, 0, 7, true);
+
+ /* Tune trxcon to that PDCH channel */
+ var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_PDCH(7), ts_RSL_ChanMode_SIGN));
+ if (mp_freq_hop_enabled and mp_transceiver_num > 1)
+ { f_resolve_fh_params(pars); }
+ f_l1ctl_est_dchan(L1CTL, pars);
+
+ /* Verify PTCCH/U: send several access bursts, make sure they're received */
+ for (var integer i := 0; i < 16; i := i + 1) {
+ log("Sending an Access Burst towards the L1CTL interface");
+ f_TC_pcu_ptcch_ul(oct2int(f_rnd_ra_ps()));
+ }
+
+ /* Generate a random payload for PTCCH/D (23 octets, CS-1) */
+ data := f_rnd_octstring(23);
+
+ /* Verify PTCCH/D: send a random data block, make sure it's received */
+ log("Sending a PTCCH/D block towards the PCU interface: ", data);
+ f_pcu_wait_rts_and_data_req(0, 0, 7, PCU_IF_SAPI_PTCCH, data);
+
+ /* PTCCH/D period is 2 multi-frames (2 * 52 * 4.615 ms), but
+ * let's give it more time in case if we miss the beginning. */
+ T.start(2.0 * 2.0 * 52.0 * 4.615 / 1000.0);
+ alt {
+ /* PDCH is considered as traffic in trxcon => expect TRAFFIC.ind */
+ [] L1CTL.receive(tr_L1CTL_TRAFFIC_IND(chan_nr := t_RslChanNr_PDCH(7),
+ link_id := tr_RslLinkID_OSMO_PTCCH(?),
+ frame := data)) -> value dl {
+ log("Rx PTCCH/D data (traffic) block on L1CTL: ", dl);
+ setverdict(pass);
+ T.stop;
+ }
+ /* Other PHYs (e.g. virt_phy) may consider PDCH as data => expect DATA.ind */
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(chan_nr := t_RslChanNr_PDCH(7),
+ link_id := tr_RslLinkID_OSMO_PTCCH(?),
+ l2_data := data)) -> value dl {
+ log("Rx PTCCH/D data block on L1CTL: ", dl);
+ setverdict(pass);
+ T.stop;
+ }
+ [] L1CTL.receive { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for DATA.ind on L1CTL");
+ }
+ }
+}
+
/* Send AGCH from PCU; check it appears on Um side */
testcase TC_pcu_data_req_agch() runs on test_CT {
timer T := 3.0;
@@ -4247,7 +4793,7 @@ testcase TC_pcu_rach_content() runs on test_CT {
timer T := 2.0;
T.start;
alt {
- [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND(0, oct2int(ra), 0, ?, fn))) {
+ [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND(0, 0, 0, oct2int(ra), 0, ?, fn))) {
T.stop;
}
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND)) {
@@ -4296,7 +4842,7 @@ testcase TC_pcu_ext_rach_content() runs on test_CT {
/* Compose the expected message */
pcu_rach_ind := tr_PCUIF_RACH_IND(
- bts_nr := 0,
+ bts_nr := 0, trx_nr := 0, ts_nr := 0,
ra := bit2int(ra11),
is_11bit := 1,
burst_type := pcu_bt,
@@ -4379,8 +4925,10 @@ testcase TC_pcu_data_ind_lqual_cb() runs on test_CT {
f_TC_pcu_act_req(0, 0, 7, true);
/* Tune trxcon to that PDCH channel on TS7 */
- f_L1CTL_DM_EST_REQ(L1CTL, { false, mp_trx0_arfcn },
- valueof(ts_RslChanNr_PDCH(7)), 7);
+ var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_PDCH(7), ts_RSL_ChanMode_SIGN));
+ if (mp_freq_hop_enabled and mp_transceiver_num > 1)
+ { f_resolve_fh_params(pars); }
+ f_l1ctl_est_dchan(L1CTL, pars);
/* C/I in centiBels, test range: -256 .. +1280, step 128 */
for (var int16_t i := -256; i <= 1280; i := i + 128) {
@@ -4399,22 +4947,27 @@ testcase TC_pcu_paging_from_rsl() runs on test_CT {
f_init_pcu_test();
for (var integer i := 0; i < 100; i := i+1) {
- var MobileL3_CommonIE_Types.MobileIdentityLV mi;
+ var MobileIdentityLV mi_lv;
+ var octetstring mi_lv_enc;
+ var MobileIdentityV mi;
timer T := 3.0;
+
if (i < 50) {
- mi := valueof(ts_MI_TMSI_LV(f_rnd_octstring(4)));
+ mi := valueof(t_MI_TMSI(f_rnd_octstring(4)));
} else {
- mi := valueof(ts_MI_IMSI_LV(f_gen_imsi(i)));
+ mi := valueof(ts_MI_IMSI(f_gen_imsi(i)));
}
- var octetstring mi_enc_lv := enc_MobileIdentityLV(mi);
- var octetstring mi_enc := substr(mi_enc_lv, 1, lengthof(mi_enc_lv)-1);
- var octetstring t_mi_lv := f_pad_oct(mi_enc_lv, 9, '00'O);
+
+ /* Fancy encoding for PCUIF */
+ mi_lv := valueof(ts_MI_LV(mi));
+ mi_lv_enc := enc_MobileIdentityLV(mi_lv);
+ mi_lv_enc := f_pad_oct(mi_lv_enc, 9, '00'O);
/* Send RSL PAGING COMMAND */
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_PAGING_CMD(mi_enc, i mod 4)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_PAGING_CMD(mi, i mod 4)));
T.start;
alt {
- [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ(0, t_mi_lv))) {
+ [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ(0, mi_lv_enc))) {
}
[] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ)) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PAGING REQ");
@@ -4577,26 +5130,6 @@ testcase TC_pcu_oml_alert() runs on test_CT {
setverdict(pass);
}
-template (value) PDU_ML3_MS_NW ts_RRM_GprsSuspReq(template (value) OCT4 tlli,
- template (value) RoutingAreaIdentificationV rai,
- template (value) OCT1 cause) := {
- discriminator := '0000'B, /* overwritten */
- tiOrSkip := {
- skipIndicator := '0000'B
- },
- msgs := {
- rrm := {
- gPRS_suspensionRequest := {
- messageType := '00110100'B,
- tLLI := tlli,
- routingAreaIdentification := rai,
- suspensionCause := cause,
- service_Support := omit
- }
- }
- }
-}
-
/* test for forwarding of RR SUSPEND from CS lchan to PCU via PCU socket */
private function f_TC_rr_suspend_req(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
@@ -4699,20 +5232,17 @@ testcase TC_pcu_socket_reconnect() runs on test_CT {
}
/* Ensure that GPRS capability is not advertised before PCU socket conncet */
-private function f_get_si3(L1CTL_PT pt) runs on test_CT return SystemInformationType3 {
+private function f_get_si(L1CTL_PT pt, RrMessageType si_type)
+runs on test_CT return SystemInformation {
var L1ctlDlMessage l1_dl;
var SystemInformation si;
+ var integer rc;
timer T := 5.0;
T.start;
alt {
[] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
- /* somehow dec_SystemInformation will try to decode even non-RR as SI */
- if (not (l1_dl.payload.data_ind.payload[1] == '06'O)) {
- log("Ignoring non-RR SI ", l1_dl);
- repeat;
- }
- si := dec_SystemInformation(l1_dl.payload.data_ind.payload)
- if (not ischosen(si.payload.si3)) {
+ rc := dec_SystemInformationSafe(l1_dl.payload.data_ind.payload, si);
+ if (rc != 0 or si.header.message_type != si_type) {
repeat;
}
}
@@ -4720,106 +5250,63 @@ private function f_get_si3(L1CTL_PT pt) runs on test_CT return SystemInformation
repeat;
}
[] T.timeout {
- setverdict(fail, "Timeout waiting for SI3");
- }
- }
- return si.payload.si3;
-}
-
-/* CSN.1 L/H logic: is the bit at the current position using "inverted logic" (true) or not? */
-private function f_bitpos_is_inv(integer idx) return boolean {
- select (idx mod 8) {
- case ((2, 4, 6, 7)) { return true; } /* 1-bits of 0x2B */
- case else { return false; } /* 0-bits of 0x2B */
- }
-}
-/* determine if the bit at position 'idx' in 'str' is a CSN.1 'H' (true) or 'L' (false) */
-private function f_bit_is_high(bitstring str, integer idx) return boolean {
- var boolean invert := f_bitpos_is_inv(idx);
- if (invert) {
- if (str[idx] == '1'B) {
- return false;
- } else {
- return true;
- }
- } else {
- if (str[idx] == '1'B) {
- return true;
- } else {
- return false;
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Timeout waiting for ", si_type));
}
}
+ return si;
}
-/* As the TITAN RAW codec cannot expres the CSN.1 L/H concept yet, we have to do this
- manually. Let's hope https://www.eclipse.org/forums/index.php/t/1099087/ takes off and
- we can replace this piece of code soon ... */
-private function f_si3_has_gprs_indicator(OCT4 si3_restoctets) return boolean {
- var bitstring bits := oct2bit(si3_restoctets);
- var integer idx := 0;
- if (f_bit_is_high(bits, idx)) {
- /* skip Optional selection parameters */
- idx := idx + 16;
- } else {
- idx := idx + 1;
- }
-
- if (f_bit_is_high(bits, idx)) {
- /* skip Optional power offset */
- idx := idx + 3;
- } else {
- idx := idx + 1;
- }
-
- /* skip SI2ter Indicator */
- idx := idx + 1;
+/* Check if GPRS Indicator is present in RR System Information of a given type */
+private function f_si_has_gprs_indicator(RrMessageType si_type)
+runs on test_CT return boolean {
+ var SystemInformation si := f_get_si(L1CTL, si_type);
- /* skip Early CM Sending Control */
- idx := idx + 1;
-
- /* skip Scheduling if and where */
- if (f_bit_is_high(bits, idx)) {
- idx := idx + 4;
- } else {
- idx := idx + 1;
+ if (si_type == SYSTEM_INFORMATION_TYPE_3) {
+ return si.payload.si3.rest_octets.gprs_ind.presence == '1'B;
+ } else if (si_type == SYSTEM_INFORMATION_TYPE_4) {
+ return si.payload.si4.rest_octets.gprs_ind.presence == '1'B;
}
- return f_bit_is_high(bits, idx);
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unhandled SI type");
+ return false;
}
-testcase TC_pcu_socket_noconnect_nosi3gprs() runs on test_CT {
- var SystemInformationType3 si3;
- timer T := 5.0;
-
+/* Make sure that GPRS Indicator is absent when the PCU is not connected */
+private function f_TC_pcu_socket_noconnect(RrMessageType si_type)
+runs on test_CT {
/* don't call f_init() as this would connect PCU socket */
f_init_rsl(testcasename());
- T.start;
- alt {
- [] RSL_CCHAN.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP});
- [] T.timeout {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for ASP_IPA_EVENT_UP");
- }
- }
+
+ /* Send both System Information Type 3 and 4 (with GPRS Indicator) */
f_rsl_bcch_fill(RSL_SYSTEM_INFO_3, ts_SI3_default);
+ f_rsl_bcch_fill(RSL_SYSTEM_INFO_4, ts_SI4_default);
f_init_l1ctl();
f_l1_tune(L1CTL);
-
f_sleep(2.0);
L1CTL.clear;
- si3 := f_get_si3(L1CTL);
- if (f_si3_has_gprs_indicator(si3.rest_octets)) {
- setverdict(fail, "SI3 indicates GPRS even before PCU socket connected");
+
+ if (f_si_has_gprs_indicator(si_type)) {
+ setverdict(fail, si_type, " indicates GPRS even before PCU socket connected");
} else {
setverdict(pass);
}
+
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
-/* Ensure that GPRS capability is advertised after PCU socket connect */
-testcase TC_pcu_socket_connect_si3gprs() runs on test_CT {
- var SystemInformationType3 si3;
+testcase TC_pcu_socket_noconnect_nosi3gprs() runs on test_CT {
+ f_TC_pcu_socket_noconnect(SYSTEM_INFORMATION_TYPE_3);
+}
+testcase TC_pcu_socket_noconnect_nosi4gprs() runs on test_CT {
+ f_TC_pcu_socket_noconnect(SYSTEM_INFORMATION_TYPE_4);
+}
+
+/* Ensure that GPRS capability is advertised after PCU socket connect */
+private function f_TC_pcu_socket_connect(RrMessageType si_type)
+runs on test_CT {
/* this (among other things) establishes the first connection to the PCUIF socket */
f_init();
f_init_l1ctl();
@@ -4827,19 +5314,27 @@ testcase TC_pcu_socket_connect_si3gprs() runs on test_CT {
f_sleep(2.0);
L1CTL.clear;
- si3 := f_get_si3(L1CTL);
- if (not f_si3_has_gprs_indicator(si3.rest_octets)) {
- setverdict(fail, "SI3 indicates no GPRS despite PCU socket connected");
+
+ if (not f_si_has_gprs_indicator(si_type)) {
+ setverdict(fail, si_type, " indicates no GPRS despite PCU socket connected");
} else {
setverdict(pass);
}
+
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
-/* Ensure that GPRS capability is no longer advertised after PCU socket disconnect */
-testcase TC_pcu_socket_disconnect_nosi3gprs() runs on test_CT {
- var SystemInformationType3 si3;
+testcase TC_pcu_socket_connect_si3gprs() runs on test_CT {
+ f_TC_pcu_socket_connect(SYSTEM_INFORMATION_TYPE_3);
+}
+testcase TC_pcu_socket_connect_si4gprs() runs on test_CT {
+ f_TC_pcu_socket_connect(SYSTEM_INFORMATION_TYPE_4);
+}
+
+/* Ensure that GPRS capability is no longer advertised after PCU socket disconnect */
+private function f_TC_pcu_socket_disconnect(RrMessageType si_type)
+runs on test_CT {
/* this (among other things) establishes the first connection to the PCUIF socket */
f_init();
f_init_l1ctl();
@@ -4856,9 +5351,9 @@ testcase TC_pcu_socket_disconnect_nosi3gprs() runs on test_CT {
f_sleep(2.0);
L1CTL.clear;
- si3 := f_get_si3(L1CTL);
- if (f_si3_has_gprs_indicator(si3.rest_octets)) {
- setverdict(fail, "SI3 indicates GPRS after PCU socket disconnected");
+
+ if (f_si_has_gprs_indicator(si_type)) {
+ setverdict(fail, si_type, " indicates GPRS after PCU socket disconnected");
} else {
setverdict(pass);
}
@@ -4866,6 +5361,14 @@ testcase TC_pcu_socket_disconnect_nosi3gprs() runs on test_CT {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
+testcase TC_pcu_socket_disconnect_nosi3gprs() runs on test_CT {
+ f_TC_pcu_socket_disconnect(SYSTEM_INFORMATION_TYPE_3);
+}
+
+testcase TC_pcu_socket_disconnect_nosi4gprs() runs on test_CT {
+ f_TC_pcu_socket_disconnect(SYSTEM_INFORMATION_TYPE_4);
+}
+
/* Verify that the cell_id of SI3 (TS 04.08 9.1.35) and other values are passed properly to the PCU socket (OS#3854) */
testcase TC_pcu_socket_verify_info_ind() runs on test_CT {
var SystemInformation si3 := valueof(ts_SI3_default);
@@ -4876,7 +5379,9 @@ testcase TC_pcu_socket_verify_info_ind() runs on test_CT {
var uint16_t cell_id_si3 := si3.payload.si3.cell_id;
var uint16_t cell_id_pcu := g_pcu_last_info.u.info_ind.cell_id;
if (cell_id_si3 != cell_id_pcu) {
- setverdict(fail, "Expected cell_id ", cell_id_si3, " got: ", cell_id_pcu);
+ setverdict(fail, "Expected cell_id '", cell_id_si3, "' and got '", cell_id_pcu, "'. This either means,",
+ " that the BTS is sending the wrong cell_id, or that the BTS sent it too early",
+ " (OS#4179)");
}
/* Verify LAC */
@@ -4889,24 +5394,129 @@ testcase TC_pcu_socket_verify_info_ind() runs on test_CT {
setverdict(pass);
}
+/* Verify hopping parameters in the INFO.ind message (version >= 10) */
+testcase TC_pcu_info_ind_fh_params() runs on test_CT {
+ var PCUIF_info_ind info_ind;
+ var ConnHdlrPars pars;
+
+ f_init();
+
+ info_ind := g_pcu_last_info.u.info_ind;
+
+ for (var integer i := 0; i < mp_transceiver_num; i := i + 1) {
+ for (var integer tn := 0; tn < 8; tn := tn + 1) {
+ if (info_ind.trx.v10[i].pdch_mask[tn] != '1'B) {
+ /* Skip inactive timeslots */
+ continue;
+ }
+
+ pars := valueof(t_Pars(t_RslChanNr_PDCH(tn), ts_RSL_ChanMode_SIGN));
+ if (mp_freq_hop_enabled and mp_transceiver_num > 1)
+ { f_resolve_fh_params(pars); }
+
+ var template PCUIF_InfoTrxTs tr_ts;
+ if (ispresent(pars.maio_hsn)) {
+ tr_ts := tr_PCUIF_InfoTrxTsH1(
+ hsn := pars.maio_hsn.hsn,
+ maio := pars.maio_hsn.maio,
+ ma := f_pad_bit(pars.ma_map.ma, 64, '0'B));
+ } else {
+ tr_ts := tr_PCUIF_InfoTrxTsH0;
+ }
+
+ var PCUIF_InfoTrxTs ts := info_ind.trx.v10[i].ts[tn];
+ log("Checking timeslot #", tn, " of trx#", i, ": ", ts);
+ if (not match(ts, tr_ts)) {
+ setverdict(fail, "Hopping parameters do not match: ",
+ "received ", ts, " vs expected ", tr_ts);
+ } else {
+ setverdict(pass);
+ }
+ }
+ }
+}
+
+/* Verify IPv4 NSVC address in the INFO.ind message (version >= 10) */
+testcase TC_pcu_socket_nsvc_ipv4() runs on test_CT {
+ f_init_vty_bsc();
+ f_vty_config2(BSCVTY, {"network", "bts 0"} , "gprs nsvc 0 remote ip 127.127.127.127");
+ f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
+
+ f_init();
+
+ var PCUIF_RemoteAddr remote_addr := g_pcu_last_info.u.info_ind.remote_addr;
+ if (not ischosen(remote_addr.v10)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Unexpected remote_addr: ", remote_addr));
+ }
+
+ if (remote_addr.v10.addr_type[0] != PCUIF_ADDR_TYPE_IPV4) {
+ setverdict(fail, "Received address family is not IPv4");
+ }
+
+ if (substr(remote_addr.v10.addr[0], 0, 4) != f_inet_addr("127.127.127.127")) {
+ setverdict(fail, "Unexpected address: ", remote_addr.v10.addr[0]);
+ }
+
+ setverdict(pass);
+}
+
+/* Verify IPv4 NSVC address in the INFO.ind message (version >= 10) */
+testcase TC_pcu_socket_nsvc_ipv6() runs on test_CT {
+ f_init_vty_bsc();
+ f_vty_config2(BSCVTY, {"network", "bts 0"} , "gprs nsvc 0 remote ip fd00::ca:ff:ee");
+
+ f_init();
+
+ var PCUIF_RemoteAddr remote_addr := g_pcu_last_info.u.info_ind.remote_addr;
+ if (not ischosen(remote_addr.v10)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Unexpected remote_addr: ", remote_addr));
+ }
+
+ if (remote_addr.v10.addr_type[0] != PCUIF_ADDR_TYPE_IPV6) {
+ setverdict(fail, "Received address family is not IPv6");
+ }
+
+ if (remote_addr.v10.addr[0] != f_inet6_addr("fd00::ca:ff:ee")) {
+ setverdict(fail, "Unexpected address: ", remote_addr.v10.addr[0]);
+ }
+
+ setverdict(pass);
+}
+
/***********************************************************************
* Osmocom Style Dynamic Timeslot Support
***********************************************************************/
-private function f_dyn_osmo_pdch_act(integer pcu_conn_id, integer bts_nr, integer trx_nr)
+private altstep as_pcuif_check_pdch_mask(integer pcu_conn_id, BIT1 exp,
+ integer bts_nr, integer trx_nr)
runs on ConnHdlr {
var PCUIF_send_data sd;
+
+ [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
+ var bitstring pdch_mask := f_PCUIF_ver_INFO_PDCHMask(sd.data.u.info_ind, trx_nr);
+ if (substr(pdch_mask, g_chan_nr.tn, 1) != exp) {
+ repeat;
+ }
+ }
+}
+
+private function f_dyn_osmo_pdch_act(integer pcu_conn_id, integer bts_nr, integer trx_nr)
+runs on ConnHdlr {
/* Expect BTS to immediately acknowledge activation as PDCH */
PCU.clear;
f_rsl_chan_act(g_pars.chan_mode);
/* expect INFO_IND on PCU interface listing TS as PDCH */
+ timer T_wait := 2.0;
+ T_wait.start;
alt {
- [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
- if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '1'B) {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "PCUIF_INFO_IND PDCH_MASK not '1' after PDCH ACT");
- }
- }
+ [] as_pcuif_check_pdch_mask(pcu_conn_id, '1'B, bts_nr, trx_nr);
[] PCU.receive { repeat; }
+ [] T_wait.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '1' on TS", g_chan_nr.tn));
+ }
}
/* try to activate this PDCH from the PCU point of view */
PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
@@ -4915,18 +5525,19 @@ runs on ConnHdlr {
private function f_dyn_osmo_pdch_deact(integer pcu_conn_id, integer bts_nr, integer trx_nr)
runs on ConnHdlr {
- var PCUIF_send_data sd;
/* Send RSL CHAN REL (deactivate) */
PCU.clear;
RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
/* expect BTS to ask PCU to deactivate the channel */
+ timer T_wait := 2.0;
+ T_wait.start;
alt {
- [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
- if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '0'B) {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "PCUIF_INFO_IND PDCH_MASK not '0' after PDCH DEACT");
- }
- }
+ [] as_pcuif_check_pdch_mask(pcu_conn_id, '0'B, bts_nr, trx_nr);
[] PCU.receive { repeat; }
+ [] T_wait.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '0' on TS", g_chan_nr.tn));
+ }
}
/* Emulate PCU asking BTS to deactivate PDCH */
PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
@@ -4939,7 +5550,7 @@ runs on ConnHdlr {
}
/* Activate Osmocom-style dynamic PDCH from BSC side */
-function f_TC_dyn_osmo_pdch_act_deact(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_osmo_pdch_act_deact(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -4964,7 +5575,7 @@ testcase TC_dyn_osmo_pdch_act_deact() runs on test_CT {
}
/* send a RF CHAN REL for PDCH on an osmocom dynamci PDCH that's already inactive */
-function f_TC_dyn_osmo_pdch_unsol_deact(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_osmo_pdch_unsol_deact(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer pcu_conn_id := -1;
@@ -4986,7 +5597,7 @@ testcase TC_dyn_osmo_pdch_unsol_deact() runs on test_CT {
}
/* try to RSL CHAN ACT a PDCH on an osmocom-style PDCH that's already active */
-function f_TC_dyn_osmo_pdch_double_act(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_osmo_pdch_double_act(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -5012,7 +5623,7 @@ testcase TC_dyn_osmo_pdch_double_act() runs on test_CT {
}
/* try to RSL CHAN ACT a TCH/F on an osmocom-style PDCH */
-function f_TC_dyn_osmo_pdch_tchf_act(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_osmo_pdch_tchf_act(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -5040,7 +5651,7 @@ testcase TC_dyn_osmo_pdch_tchf_act() runs on test_CT {
}
/* try to RSL CHAN ACT the TCH/H on an osmocom-style PDCH */
-function f_TC_dyn_osmo_pdch_tchh_act(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_osmo_pdch_tchh_act(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -5077,7 +5688,6 @@ testcase TC_dyn_osmo_pdch_tchh_act() runs on test_CT {
private function f_dyn_ipa_pdch_act(integer pcu_conn_id, integer bts_nr, integer trx_nr)
runs on ConnHdlr {
- var PCUIF_send_data sd;
/* Expect BTS to immediately acknowledge activation as PDCH */
PCU.clear;
RSL.send(ts_RSL_IPA_PDCH_ACT(g_chan_nr));
@@ -5085,13 +5695,7 @@ runs on ConnHdlr {
timer T_wait := 2.0;
T_wait.start;
alt {
- [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
- if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '1'B) {
- log("PCUIF_INFO_IND PDCH_MASK not yet '1' after PDCH ACT on TS", g_chan_nr.tn,
- " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
- repeat;
- }
- }
+ [] as_pcuif_check_pdch_mask(pcu_conn_id, '1'B, bts_nr, trx_nr);
[] PCU.receive { repeat; }
[] T_wait.timeout {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
@@ -5107,7 +5711,6 @@ runs on ConnHdlr {
private function f_dyn_ipa_pdch_deact(integer pcu_conn_id, integer bts_nr, integer trx_nr)
runs on ConnHdlr {
- var PCUIF_send_data sd;
/* Send RSL CHAN REL (deactivate) */
RSL.send(ts_RSL_IPA_PDCH_DEACT(g_chan_nr));
PCU.clear;
@@ -5115,13 +5718,7 @@ runs on ConnHdlr {
timer T_wait := 2.0;
T_wait.start;
alt {
- [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
- if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '0'B) {
- log("PCUIF_INFO_IND PDCH_MASK not yet '0' after PDCH DEACT on TS", g_chan_nr.tn,
- " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
- repeat;
- }
- }
+ [] as_pcuif_check_pdch_mask(pcu_conn_id, '0'B, bts_nr, trx_nr);
[] PCU.receive { repeat; }
[] T_wait.timeout {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
@@ -5139,7 +5736,7 @@ runs on ConnHdlr {
}
/* Activate and de-activate an IPA-style dynamic TCH/F + PDCH */
-function f_TC_dyn_ipa_pdch_act_deact(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_ipa_pdch_act_deact(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -5166,7 +5763,7 @@ testcase TC_dyn_ipa_pdch_act_deact() runs on test_CT {
}
/* try to RSL CHAN ACT a TCH/F on an IPA-style PDCH */
-function f_TC_dyn_ipa_pdch_tchf_act(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_ipa_pdch_tchf_act(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -5192,7 +5789,7 @@ testcase TC_dyn_ipa_pdch_tchf_act() runs on test_CT {
}
/* Activate IPA style dyn PDCH as TCH/F and then illegally try to activate it as PDCH, too */
-function f_TC_dyn_ipa_pdch_tchf_act_pdch_act_nack(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_ipa_pdch_tchf_act_pdch_act_nack(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -5228,7 +5825,7 @@ testcase TC_dyn_ipa_pdch_tchf_act_pdch_act_nack() runs on test_CT {
}
/* try to RSL CHAN ACT a TCH/F on an IPA-style PDCH that's already in PDCH mode; expect NACK */
-function f_TC_dyn_ipa_pdch_act_tchf_act_nack(charstring id) runs on ConnHdlr {
+private function f_TC_dyn_ipa_pdch_act_tchf_act_nack(charstring id) runs on ConnHdlr {
var PCUIF_Message first_info;
var integer ts_nr := g_chan_nr.tn;
var integer trx_nr := 0;
@@ -5280,14 +5877,15 @@ private function f_tx_lapdm(template (value) LapdmFrame l,
}
}
-type record RllTestCase {
+private type record RllTestCase {
uint3_t sapi,
RslLinkId link_id,
octetstring l3,
boolean exp
}
-type record of RllTestCase RllTestCases;
-template RllTestCase t_EITC(uint3_t sapi, RslLinkId id, octetstring l3, boolean exp) := {
+private type record of RllTestCase RllTestCases;
+private template RllTestCase t_EITC(uint3_t sapi, RslLinkId id,
+ octetstring l3, boolean exp) := {
sapi := sapi,
link_id := id,
l3 := l3,
@@ -5580,11 +6178,11 @@ testcase TC_rll_rel_req() runs on test_CT {
f_rll_testmatrix(tcs, refers(f_TC_rll_rel_req));
}
-/* test if RLL DATA REQ triggers I-frames on Um (TS 48.058 3.5) */
+/* TODO: test if RLL DATA REQ triggers I-frames on Um (TS 48.058 3.5) */
testcase TC_rll_data_req() runs on test_CT {
}
-/* test if I-frames on Um trigger RLL DATA IND (TS 48.058 3.6) */
+/* TODO: test if I-frames on Um trigger RLL DATA IND (TS 48.058 3.6) */
testcase TC_rll_data_ind() runs on test_CT {
}
@@ -5676,7 +6274,7 @@ testcase TC_rll_unit_data_ind_ACCH() runs on test_CT {
***********************************************************************/
/* send UNITDATA_REQ from BTS to MS and expect it to arrive */
-function f_unitdata_mt(RslLinkId link_id, octetstring l3) runs on ConnHdlr {
+private function f_unitdata_mt(RslLinkId link_id, octetstring l3) runs on ConnHdlr {
RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, link_id, l3));
if (link_id.c == SACCH) {
f_l1_exp_lapdm(tr_LAPDm_B4_UI(link_id.sapi, cr_MT_CMD, l3));
@@ -5741,7 +6339,7 @@ private function f_data_mo(
}
/* Test channel activation with A5/n right from the beginning (like in assignment + hand-over) */
-function f_TC_chan_act_encr(charstring id) runs on ConnHdlr {
+private function f_TC_chan_act_encr(charstring id) runs on ConnHdlr {
f_l1_tune(L1CTL);
f_est_dchan(true);
@@ -5780,7 +6378,7 @@ testcase TC_chan_act_a53() runs on test_CT {
/* Test channel activation with A5/n right from the beginning and RSL MODE MODIFY
which should break the en/decryption on purpose by supplying a new key that is unknown to the MS*/
-function f_TC_rsl_modify_encr(charstring id) runs on ConnHdlr {
+private function f_TC_rsl_modify_encr(charstring id) runs on ConnHdlr {
f_l1_tune(L1CTL);
f_est_dchan(true);
@@ -5845,7 +6443,7 @@ testcase TC_rsl_modify_encr() runs on test_CT {
}
/* Test unencrypted channel activation followed by explicit ENCR CMD later */
-function f_TC_encr_cmd(charstring id) runs on ConnHdlr {
+private function f_TC_encr_cmd(charstring id) runs on ConnHdlr {
/* L3 payload doesn't matter, as it is passed transparently */
var BIT3 l3_alg_id := f_alg_id_to_l3(g_pars.encr.alg_id);
var octetstring l3 := enc_PDU_ML3_NW_MS(valueof(ts_RRM_CiphModeCmd(l3_alg_id)));
@@ -5942,23 +6540,23 @@ testcase TC_lapdm_selftest() runs on test_CT {
***********************************************************************/
/* XXX These functions must be kept in sync with g_AllChannels defined on test_CT. */
-function f_g_chan_is_tchf() runs on ConnHdlr return boolean {
+private function f_g_chan_is_tchf() runs on ConnHdlr return boolean {
return (g_chan_nr == valueof(ts_RslChanNr_Bm(1)) or
g_chan_nr == valueof(ts_RslChanNr_Bm(2)) or
g_chan_nr == valueof(ts_RslChanNr_Bm(3)) or
g_chan_nr == valueof(ts_RslChanNr_Bm(4)));
}
-function f_g_chan_is_tchh() runs on ConnHdlr return boolean {
+private function f_g_chan_is_tchh() runs on ConnHdlr return boolean {
return (g_chan_nr == valueof(ts_RslChanNr_Lm(5,0)) or
g_chan_nr == valueof(ts_RslChanNr_Lm(5,1)));
}
-function f_g_chan_is_sdcch4() runs on ConnHdlr return boolean {
+private function f_g_chan_is_sdcch4() runs on ConnHdlr return boolean {
return (g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,0)) or
g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,1)) or
g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,2)) or
g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,3)));
}
-function f_g_chan_is_sdcch8() runs on ConnHdlr return boolean {
+private function f_g_chan_is_sdcch8() runs on ConnHdlr return boolean {
return (g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,0)) or
g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,1)) or
g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,2)) or
@@ -5969,7 +6567,7 @@ function f_g_chan_is_sdcch8() runs on ConnHdlr return boolean {
g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,7)));
}
-function f_test_l2_fill_frames(boolean dtxd) runs on ConnHdlr {
+private function f_test_l2_fill_frames(boolean dtxd) runs on ConnHdlr {
var L1ctlDlMessage dl;
var octetstring l2_fill_frame := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O;
var octetstring l2_fill_frame_sacch := substr(l2_fill_frame, 0, lengthof(l2_fill_frame) - 2);
@@ -6107,15 +6705,15 @@ function f_test_l2_fill_frames(boolean dtxd) runs on ConnHdlr {
}
}
-function f_TC_tch_sign_l2_fill_frame(charstring id) runs on ConnHdlr {
+private function f_TC_tch_sign_l2_fill_frame(charstring id) runs on ConnHdlr {
f_test_l2_fill_frames(false);
}
-function f_TC_tch_sign_l2_fill_frame_dtxd(charstring id) runs on ConnHdlr {
+private function f_TC_tch_sign_l2_fill_frame_dtxd(charstring id) runs on ConnHdlr {
f_test_l2_fill_frames(true);
}
-function f_tch_sign_l2_fill_frame(boolean dtxd) runs on test_CT {
+private function f_tch_sign_l2_fill_frame(boolean dtxd) runs on test_CT {
var ConnHdlr vc_conn;
var ConnHdlrPars pars;
pars.t_guard := 60.0;
@@ -6198,6 +6796,7 @@ control {
execute( TC_sacch_chan_act_ho_async() );
execute( TC_sacch_chan_act_ho_sync() );
execute( TC_rach_content() );
+ execute( TC_rach_content_emerg() );
execute( TC_rach_count() );
execute( TC_rach_max_ta() );
execute( TC_ho_rach() );
@@ -6209,6 +6808,9 @@ control {
execute( TC_meas_res_sign_sdcch4() );
execute( TC_meas_res_sign_sdcch8() );
execute( TC_meas_res_sign_tchh_toa256() );
+ execute( TC_tx_power_start_ramp_up_bcch() );
+ execute( TC_tx_power_start_ramp_down_bcch() );
+ execute( TC_tx_power_ramp_adm_state_change() );
execute( TC_rsl_bs_pwr_static_ass() );
execute( TC_rsl_bs_pwr_static_power_control() );
execute( TC_rsl_ms_pwr_ctrl() );
@@ -6259,6 +6861,7 @@ control {
execute( TC_pcu_data_req_wrong_ts() );
execute( TC_pcu_data_req_ts_inactive() );
}
+ execute( TC_pcu_ptcch() );
execute( TC_pcu_data_req_agch() );
execute( TC_pcu_data_req_pch() );
execute( TC_pcu_data_req_imm_ass_pch() );
@@ -6273,22 +6876,31 @@ control {
execute( TC_pcu_socket_connect_multi() );
execute( TC_pcu_socket_reconnect() );
execute( TC_pcu_socket_noconnect_nosi3gprs() );
+ execute( TC_pcu_socket_noconnect_nosi4gprs() );
execute( TC_pcu_socket_connect_si3gprs() );
+ execute( TC_pcu_socket_connect_si4gprs() );
execute( TC_pcu_socket_disconnect_nosi3gprs() );
+ execute( TC_pcu_socket_disconnect_nosi4gprs() );
execute( TC_pcu_socket_verify_info_ind() );
+ execute( TC_dyn_osmo_pdch_act_deact() );
+ execute( TC_dyn_osmo_pdch_double_act() );
+ execute( TC_dyn_ipa_pdch_act_deact() );
+ execute( TC_dyn_ipa_pdch_act_tchf_act_nack() );
+
+ if (PCUIF_Types.mp_pcuif_version >= 10) {
+ execute( TC_pcu_info_ind_fh_params() );
+ execute( TC_pcu_socket_nsvc_ipv4() );
+ execute( TC_pcu_socket_nsvc_ipv6() );
+ }
} else {
log("PCU socket path not available, skipping PCU tests");
}
- execute( TC_dyn_osmo_pdch_act_deact() );
execute( TC_dyn_osmo_pdch_unsol_deact() );
- execute( TC_dyn_osmo_pdch_double_act() );
execute( TC_dyn_osmo_pdch_tchf_act() );
execute( TC_dyn_osmo_pdch_tchh_act() );
- execute( TC_dyn_ipa_pdch_act_deact() );
execute( TC_dyn_ipa_pdch_tchf_act() );
execute( TC_dyn_ipa_pdch_tchf_act_pdch_act_nack() );
- execute( TC_dyn_ipa_pdch_act_tchf_act_nack() );
execute( TC_rll_est_ind() );
execute( TC_rll_est_req_DCCH_3() );
diff --git a/bts/BTS_Tests_LAPDm.ttcn b/bts/BTS_Tests_LAPDm.ttcn
index da78ccb..9981bbc 100644
--- a/bts/BTS_Tests_LAPDm.ttcn
+++ b/bts/BTS_Tests_LAPDm.ttcn
@@ -6,6 +6,7 @@ import from LAPDm_RAW_PT all;
import from LAPDm_Types all;
import from RSL_Types all;
import from BTS_Tests all;
+import from GSM_RR_Types all;
import from Misc_Helpers all;
/* test that use exclusively only LAPDm over L1CTL */
@@ -51,9 +52,16 @@ function f_establish_dcch() runs on lapdm_test_CT {
}
/* master function switching to a dedicated radio channel */
-function f_switch_dcch(Arfcn arfcn, RslChannelNr chan_nr, GsmTsc tsc) runs on lapdm_test_CT {
- var BCCH_tune_req tune_req := { arfcn := arfcn, combined_ccch := true };
- var DCCH_switch_req sw_req := { arfcn, chan_nr, tsc };
+function f_switch_dcch() runs on ConnHdlr {
+ var BCCH_tune_req tune_req := { arfcn := { false, mp_trx0_arfcn }, combined_ccch := true };
+ var DCCH_switch_req sw_req := { ma := g_pars.ma };
+
+ /* Craft channel description (with or without frequency hopping parameters) */
+ if (ispresent(g_pars.maio_hsn)) {
+ sw_req.chan_desc := valueof(ts_ChanDescH1(g_pars.chan_nr, g_pars.maio_hsn));
+ } else {
+ sw_req.chan_desc := valueof(ts_ChanDescH0(g_pars.chan_nr, mp_trx0_arfcn));
+ }
LAPDM.send(tune_req);
LAPDM.send(sw_req);
@@ -228,10 +236,16 @@ private function fp_common_init() runs on ConnHdlr
/* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
unmap(self:L1CTL, system:L1CTL);
f_lapdm_init();
+
+ /* Obtain frequency hopping parameters for a given timeslot */
+ if (mp_freq_hop_enabled and mp_transceiver_num > 1) {
+ f_resolve_fh_params(g_pars);
+ }
+
/* activate the channel on the BTS side */
f_rsl_chan_act(g_pars.chan_mode, false, {});
/* activate the channel on the MS side */
- f_switch_dcch({false, mp_trx0_arfcn}, g_chan_nr, 7);
+ f_switch_dcch();
}
private function fp_common_fini() runs on ConnHdlr
@@ -813,11 +827,16 @@ testcase TC_nr_seq_error() runs on test_CT {
f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
}
-private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x) runs on ConnHdlr {
+private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
LAPDM.send(t_PH_DATA(0, false, x));
f_sleep(2.0); // T200
LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
- LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0)));
+ timer T1 := 2.0;
+ T1.start;
+ alt {
+ [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
+ [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
+ }
}
/* 25.2.7 Test on receipt of invalid frames
@@ -842,84 +861,90 @@ private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
/* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
- RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
+ T.start
+ alt {
+ [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
+ [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
+ }
+ alt {
/* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
- LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
-
+ [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
+ [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
+ }
/* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
RR frame with the Length indicator greater than zero and a faulty N(R); */
var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.payload := f_rnd_octstring(5);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
EJ frame with the EA bit set to zero and a faulty N(R); */
x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.addr.ea := false;
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
SABM frame with the EL bit set to zero; */
l3_mo := ''O;
x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
x.ab.el := 0;
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
DM frame with the Length indicator greater than zero;*/
x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
x.ab.payload := f_rnd_octstring(5);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
DISC frame with the M bit set to 1; */
x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
x.ab.m := true;
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
UA frame with the EA bit set to zero*/
x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
x.ab.addr.ea := false;
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
I frame with the Length indicator greater than N201;*/
x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 6, l3 := f_rnd_octstring(25)))
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
I frame with the M bit set to 1 and the Length indicator less than N201;*/
x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
x.ab.m := true;
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* command frames with correct Address and Length indicator field and a non-implemented control field */
/* 12: One command frame with Control Field = xxx1 1101. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.ctrl.other := bit2int('00011101'B);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 13: One command frame with Control field = xxx1 1011. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.ctrl.other := bit2int('00011011'B);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 14: One command frame with Control field = xxx1 0111. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.ctrl.other := bit2int('00010001'B);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 15: One command frame with Control field = 01x1 1111. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.ctrl.other := bit2int('01011111'B);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 16: One command frame with Control field = 1xx1 1111. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.ctrl.other := bit2int('10011111'B);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 17: One command frame with Control field = 0011 0011. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.ctrl.other := bit2int('00110011'B);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
/* 18: One command frame with Control field = 1xx1 0011. */
x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
x.ab.ctrl.other := bit2int('10010011'B);
- f_TC_rec_invalid_frame_txrx(0, x);
+ f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
deactivate(d);
fp_common_fini();
diff --git a/bts/BTS_Tests_OML.ttcn b/bts/BTS_Tests_OML.ttcn
index 84d46a4..4835e66 100644
--- a/bts/BTS_Tests_OML.ttcn
+++ b/bts/BTS_Tests_OML.ttcn
@@ -102,8 +102,8 @@ function f_init_oml(charstring id) runs on BSC_OML_CT {
T_oml_guard.start;
activate(as_Tguard());
- OML.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
- //OML.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
+ OML.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP));
+ //OML.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK));
activate(as_SwAct());
activate(as_IPA_evt());
diff --git a/bts/BTS_Tests_SMSCB.ttcn b/bts/BTS_Tests_SMSCB.ttcn
index 292205a..29489fc 100644
--- a/bts/BTS_Tests_SMSCB.ttcn
+++ b/bts/BTS_Tests_SMSCB.ttcn
@@ -23,6 +23,7 @@ import from L1CTL_Types all;
import from LAPDm_Types all;
import from IPA_Emulation all;
import from GSM_RR_Types all;
+import from L3_Templates all;
import from RSL_Types all;
@@ -53,8 +54,8 @@ t_CbchPC(template (value) CbchTestMsgs msgs, template (omit) CbchTestMsg def :=
/* CBCH test parameters for most of our tests */
type record CbchTestPars {
- /* should we execute on SDCCH4 (true) or SDCCH8 (false) ? */
- boolean use_sdcch4,
+ /* Should we execute on SDCCH4 or SDCCH8? */
+ RslChannelNr chan_nr,
/* Parameters for BASIC CBCH */
CbchTestParsChan basic,
/* Parameters for EXTENDED CBCH */
@@ -158,7 +159,7 @@ private function f_rsl_smscb_default_null() runs on test_CT
{
var RSL_IE_CbCommandType cmd_type :=
valueof(ts_RSL_IE_CbCmdType(RSL_CB_CMD_DEFAULT, 1, true));
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_SMSCB_CMD(cmd_type, ''O)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_SMSCB_CMD(cmd_type, ''O)));
}
template RSL_IE t_RSL_IE_SMSCB_EXT := t_RSL_IE(RSL_IE_SMSCB_CHAN_INDICATOR, {smscb_chan_ind := 1});
@@ -180,7 +181,7 @@ runs on test_CT {
if (extd) {
rsl.ies := rsl.ies & { valueof(t_RSL_IE_SMSCB_EXT) };
}
- RSL_CCHAN.send(ts_RSL_UD(rsl));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
}
if (ispresent(pars_chan.default_msg)) {
msg := pars_chan.default_msg;
@@ -190,38 +191,69 @@ runs on test_CT {
if (extd) {
rsl.ies := rsl.ies & { valueof(t_RSL_IE_SMSCB_EXT) };
}
- RSL_CCHAN.send(ts_RSL_UD(rsl));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
}
}
-private function f_vty_cbch_setup(boolean use_sdcch4 := true) runs on test_CT {
+private function f_vty_cbch_setup(in RslChannelNr chan_nr) runs on test_CT {
- if (use_sdcch4 == true) {
- f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 0"},
+ if (match(chan_nr, t_RslChanNr_CBCH4(0))) {
+ f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0", "timeslot 0"},
"phys_chan_config CCCH+SDCCH4+CBCH");
- f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 6"},
- "phys_chan_config SDCCH8");
- } else {
- f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 0"},
+ /* (Re)configure timeslots 1..3 as TCH/F */
+ for (var integer tn := 1; tn <= 3; tn := tn + 1) {
+ f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0",
+ "timeslot " & int2str(tn) },
+ "phys_chan_config TCH/F");
+ }
+ } else if (match(chan_nr, t_RslChanNr_CBCH8(?))) {
+ f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0", "timeslot 0"},
"phys_chan_config CCCH+SDCCH4");
- f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 6"},
+ f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0",
+ "timeslot " & int2str(chan_nr.tn) },
"phys_chan_config SDCCH8+CBCH");
+
+ /* (Re)configure timeslots 1..3 (excluding the given one) as TCH/F */
+ for (var integer tn := 1; tn <= 3; tn := tn + 1) {
+ if (tn == chan_nr.tn)
+ { continue; }
+ f_vty_config2(BSCVTY, { "network", "bts 0", "trx 0",
+ "timeslot " & int2str(tn) },
+ "phys_chan_config TCH/F");
+ }
}
f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
f_sleep(2.0);
}
private function f_smscb_setup(inout CbchTestPars pars) runs on test_CT {
+ /* Make sure we've got either SDCCH4+CBCH or SDCCH8+CBCH.
+ * SDCCH4+CBCH can only be allocated on TS0, SDCCH8+CBCH on TS0..3.
+ * On C0 the first timeslot shall always transmit BCCH, thus TS1..3.*/
+ if (not match(pars.chan_nr, (t_RslChanNr_CBCH4(0), t_RslChanNr_CBCH8(1),
+ t_RslChanNr_CBCH8(2), t_RslChanNr_CBCH8(3)))) {
+ setverdict(inconc, "Unhandled channel number: ", pars.chan_nr);
+ mtc.stop;
+ }
f_cbch_compute_exp_blocks(pars);
f_init_vty_bsc();
/* ensure that a CBCH is present in channel combination */
- f_vty_cbch_setup(pars.use_sdcch4);
+ f_vty_cbch_setup(pars.chan_nr);
f_init();
f_init_l1ctl();
- f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
- /* FIXME: switch to dedicated mode for SDCCH/8 */
+
+ /* Tune L1 to the given CBCH timeslot (SDCCH4+CBCH or SDCCH8+CBCH) */
+ if (match(pars.chan_nr, t_RslChanNr_CBCH4(0))) {
+ f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
+ } else {
+ f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED);
+ /* TODO: also handle frequency hopping parameters */
+ L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(pars.chan_nr,
+ 7 /* TODO: mp_tsc */,
+ mp_trx0_arfcn));
+ }
/* send SMSCB[s] via RSL */
f_smscb_setup_rsl_chan(pars.basic, false);
@@ -230,14 +262,6 @@ private function f_smscb_setup(inout CbchTestPars pars) runs on test_CT {
}
}
-private function f_smscb_cleanup() runs on test_CT {
- /* reset timeslot 0 channel combination to default */
- f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 0"},
- "phys_chan_config CCCH+SDCCH4");
- f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 6"},
- "phys_chan_config SDCCH8");
-}
-
/* construct a receive/match template for given block_nr in given msg */
private function f_get_block_template(CbchTestMsg msg, integer block_nr) return template CBCH_Block {
var template CBCH_Block tr;
@@ -325,17 +349,8 @@ private function f_cbch_report(CbchTestParsChan pars_chan, charstring id)
}
}
-private function t_cbch_chan_nr(CbchTestPars pars, template uint8_t tn) return template RslChannelNr {
- if (pars.use_sdcch4) {
- return t_RslChanNr_CBCH4(tn);
- } else {
- return t_RslChanNr_CBCH8(tn);
- }
-}
-
/* shared function doing the heavy lifting for most CBCH tests */
private function f_TC_smscb(CbchTestPars pars) runs on test_CT {
- var template RslChannelNr t_chan_nr := t_cbch_chan_nr(pars, 0); /* FIXME: TS number */
var L1ctlDlMessage dl;
var integer msg_count;
timer T;
@@ -357,7 +372,7 @@ private function f_TC_smscb(CbchTestPars pars) runs on test_CT {
T.start(5.0 + 3.0 * int2float(msg_count));
/* Expect this to show up exactly once on the basic CBCH (four blocks) */
alt {
- [] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl {
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(pars.chan_nr)) -> value dl {
var integer tb := f_cbch_fn2tb(dl.dl_info.frame_nr);
var CBCH_Block cb := dec_CBCH_Block(dl.payload.data_ind.payload);
log("Tb=", tb, ", CBCH: ", dl, ", block: ", cb);
@@ -385,12 +400,10 @@ private function f_TC_smscb(CbchTestPars pars) runs on test_CT {
}
}
- f_smscb_cleanup();
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass);
}
private function f_TC_smscb_default_only(CbchTestPars pars) runs on test_CT {
- var template RslChannelNr t_chan_nr := t_cbch_chan_nr(pars, 0); /* FIXME: TS number */
var L1ctlDlMessage dl;
timer T := 5.0;
@@ -402,7 +415,7 @@ private function f_TC_smscb_default_only(CbchTestPars pars) runs on test_CT {
T.start;
alt {
- [] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl {
+ [] L1CTL.receive(tr_L1CTL_DATA_IND(pars.chan_nr)) -> value dl {
var integer tb := f_cbch_fn2tb(dl.dl_info.frame_nr);
log("CBCH: ", dl);
var CBCH_Block cb := dec_CBCH_Block(dl.payload.data_ind.payload);
@@ -435,7 +448,6 @@ private function f_TC_smscb_default_only(CbchTestPars pars) runs on test_CT {
[] T.timeout {}
}
- f_smscb_cleanup();
/* don't shut down; some tests still want to continue */
}
@@ -504,7 +516,7 @@ private const CbchTestMsg msg_default := {
/* transmit single-block SMSCB COMMAND */
testcase TC_sms_cb_cmd_sdcch4_1block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_1b_norm)),
extended := omit
};
@@ -512,7 +524,7 @@ testcase TC_sms_cb_cmd_sdcch4_1block() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_1block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := false,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC(msgs_1m_1b_norm)),
extended := omit
};
@@ -522,7 +534,7 @@ testcase TC_sms_cb_cmd_sdcch8_1block() runs on test_CT {
/* transmit dual-block SMSCB COMMAND */
testcase TC_sms_cb_cmd_sdcch4_2block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_2b_norm)),
extended := omit
};
@@ -530,7 +542,7 @@ testcase TC_sms_cb_cmd_sdcch4_2block() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_2block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := false,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC(msgs_1m_2b_norm)),
extended := omit
};
@@ -540,7 +552,7 @@ testcase TC_sms_cb_cmd_sdcch8_2block() runs on test_CT {
/* transmit triple-block SMSCB COMMAND */
testcase TC_sms_cb_cmd_sdcch4_3block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
extended := omit
};
@@ -548,7 +560,7 @@ testcase TC_sms_cb_cmd_sdcch4_3block() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_3block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := false,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
extended := omit
};
@@ -558,7 +570,7 @@ testcase TC_sms_cb_cmd_sdcch8_3block() runs on test_CT {
/* transmit quad-block SMSCB COMMAND */
testcase TC_sms_cb_cmd_sdcch4_4block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_4b_norm)),
extended := omit
};
@@ -566,7 +578,7 @@ testcase TC_sms_cb_cmd_sdcch4_4block() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_4block() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := false,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC(msgs_1m_4b_norm)),
extended := omit
};
@@ -576,7 +588,7 @@ testcase TC_sms_cb_cmd_sdcch8_4block() runs on test_CT {
/* transmit multiple commands of each 4 blocks */
testcase TC_sms_cb_cmd_sdcch4_multi() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_3m_4b_norm)),
extended := omit
};
@@ -584,7 +596,7 @@ testcase TC_sms_cb_cmd_sdcch4_multi() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_multi() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := false,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC(msgs_3m_4b_norm)),
extended := omit
};
@@ -594,7 +606,7 @@ testcase TC_sms_cb_cmd_sdcch8_multi() runs on test_CT {
/* transmit multiple commands of each 4 blocks on CBCH EXTD */
testcase TC_sms_cb_cmd_sdcch4_extd_multi() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC({})),
extended := valueof(t_CbchPC(msgs_3m_4b_norm))
};
@@ -602,7 +614,7 @@ testcase TC_sms_cb_cmd_sdcch4_extd_multi() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_extd_multi() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := false,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC({})),
extended := valueof(t_CbchPC(msgs_3m_4b_norm))
};
@@ -612,7 +624,7 @@ testcase TC_sms_cb_cmd_sdcch8_extd_multi() runs on test_CT {
/* transmit SMSCB COMMAND with SCHEDULE payload */
testcase TC_sms_cb_cmd_sdcch4_schedule() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_4b_sched)),
extended := omit
};
@@ -620,7 +632,7 @@ testcase TC_sms_cb_cmd_sdcch4_schedule() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_schedule() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := false,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC(msgs_1m_4b_sched)),
extended := omit
};
@@ -630,7 +642,7 @@ testcase TC_sms_cb_cmd_sdcch8_schedule() runs on test_CT {
/* set a DEFAULT message; verify it gets transmitted all the time */
testcase TC_sms_cb_cmd_sdcch4_default_only() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_3b_default)),
extended := omit
};
@@ -639,7 +651,7 @@ testcase TC_sms_cb_cmd_sdcch4_default_only() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_default_only() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_3b_default)),
extended := omit
};
@@ -649,7 +661,7 @@ testcase TC_sms_cb_cmd_sdcch8_default_only() runs on test_CT {
testcase TC_sms_cb_cmd_sdcch4_default_and_normal() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_3b_norm, msg_default)),
extended := omit
};
@@ -657,7 +669,7 @@ testcase TC_sms_cb_cmd_sdcch4_default_and_normal() runs on test_CT {
}
testcase TC_sms_cb_cmd_sdcch8_default_and_normal() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH8(2)),
basic := valueof(t_CbchPC(msgs_1m_3b_norm, msg_default)),
extended := omit
};
@@ -667,7 +679,7 @@ testcase TC_sms_cb_cmd_sdcch8_default_and_normal() runs on test_CT {
/* first set a DEFAULT message, then disable it again */
testcase TC_sms_cb_cmd_sdcch4_default_then_null() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_3b_default)),
extended := omit
};
@@ -719,10 +731,10 @@ testcase TC_cbch_load_idle_no_cbch() runs on test_CT {
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
}
[] RSL_CCHAN.receive { repeat; }
@@ -747,18 +759,18 @@ function f_TC_cbc_load_idle() runs on test_CT {
RSL_CCHAN.clear;
T.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC(false, tr_slot_count))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC(false, tr_slot_count))) {
basic_count := basic_count + 1;
repeat;
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD(false, tr_slot_count))) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD(false, tr_slot_count))) -> value rx_ud {
extd_count := extd_count + 1;
repeat;
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
}
[] RSL_CCHAN.receive { repeat; }
@@ -771,17 +783,17 @@ function f_TC_cbc_load_idle() runs on test_CT {
}
}
}
- f_smscb_cleanup();
+
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
testcase TC_cbc_sdcch4_load_idle() runs on test_CT {
f_init_vty_bsc();
- f_vty_cbch_setup(use_sdcch4 := true);
+ f_vty_cbch_setup(valueof(ts_RslChanNr_CBCH4(0)));
f_TC_cbc_load_idle();
}
testcase TC_cbc_sdcch8_load_idle() runs on test_CT {
f_init_vty_bsc();
- f_vty_cbch_setup(use_sdcch4 := false);
+ f_vty_cbch_setup(valueof(ts_RslChanNr_CBCH8(2)));
f_TC_cbc_load_idle();
}
@@ -823,18 +835,18 @@ function f_TC_cbc_load_overload(CbchTestPars pars) runs on test_CT {
T_total.start;
T_retransmit.start;
alt {
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC(true, tr_slot_count_basic))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC(true, tr_slot_count_basic))) {
basic_count := basic_count + 1;
repeat;
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD(false, tr_slot_count_extd))) {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD(false, tr_slot_count_extd))) {
extd_count := extd_count + 1;
repeat;
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_BASIC)) -> value rx_ud {
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
}
- [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
+ [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CBCH_LOAD_IND_EXTD)) -> value rx_ud {
setverdict(fail, "Received unexpected CBCH LOAD IND: ", rx_ud);
}
[] RSL_CCHAN.receive { repeat; }
@@ -852,29 +864,29 @@ function f_TC_cbc_load_overload(CbchTestPars pars) runs on test_CT {
}
}
}
- f_smscb_cleanup();
+
Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
}
testcase TC_cbc_sdcch4_load_overload() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(0)),
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
extended := omit
};
f_init_vty_bsc();
- f_vty_cbch_setup(use_sdcch4 := true);
+ f_vty_cbch_setup(pars.chan_nr);
f_TC_cbc_load_overload(pars);
}
testcase TC_cbc_sdcch8_load_overload() runs on test_CT {
var CbchTestPars pars := {
- use_sdcch4 := true,
+ chan_nr := valueof(ts_RslChanNr_CBCH4(2)),
basic := valueof(t_CbchPC(msgs_1m_3b_norm)),
extended := omit
};
f_init_vty_bsc();
- f_vty_cbch_setup(use_sdcch4 := true);
+ f_vty_cbch_setup(pars.chan_nr);
f_TC_cbc_load_overload(pars);
}
@@ -884,31 +896,6 @@ private template GsmRrMessage tr_PagingType1 := {
payload :=?
};
-private template GsmRrMessage tr_PagingType1_empty := {
- header := t_RrHeader(PAGING_REQUEST_TYPE_1, 5),
- payload := {
- pag_req_1 := {
- chan_needed := {
- second := CHAN_NEED_ANY,
- first := CHAN_NEED_ANY
- },
- page_mode := PAGE_MODE_NORMAL,
- mi1 := {
- len := 1,
- mi := {
- unused := {
- pad := '1111'B,
- odd := false,
- mi_type := MI_TYPE_NONE
- }
- }
- },
- mi2 := omit,
- rest_octets := ?
- }
- }
-};
-
/* we expect four blocks of 14 bytes, let's fill them with content easily distinguishable */
const octetstring c_etws_seg0 := '000102030405060708090a0b0c0d'O;
const octetstring c_etws_seg1 := '101112131415161718191a1b1c1d'O;
@@ -930,7 +917,7 @@ testcase TC_etws_p1ro() runs on test_CT {
f_init_l1ctl();
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
/* wait for a bit until old non-ETWS Paging messages are gone */
f_sleep(1.0);
L1CTL.clear;
@@ -939,7 +926,7 @@ testcase TC_etws_p1ro() runs on test_CT {
[] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl {
var GsmRrMessage l3 := dec_GsmRrMessage(dl.payload.data_ind.payload);
select (l3) {
- case (tr_PagingType1_empty) {
+ case (tr_PAG_REQ1(tr_MI_LV(t_MI_NoIdentity()))) {
var octetstring p1ro := l3.payload.pag_req_1.rest_octets;
var bitstring midamble := oct2bit(substr(p1ro, 0, 3));
var octetstring segment := substr(p1ro, 3, lengthof(p1ro)-3);
@@ -1023,11 +1010,11 @@ testcase TC_etws_p1ro_end() runs on test_CT {
f_init_l1ctl();
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
/* wait for a bit until old non-ETWS Paging messages are gone */
f_sleep(3.0);
/* disable the ETWS PN again */
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_OSMO_ETWS_CMD(''O)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(''O)));
f_sleep(2.0);
T.start;
L1CTL.clear;
@@ -1035,7 +1022,7 @@ testcase TC_etws_p1ro_end() runs on test_CT {
[] L1CTL.receive(tr_L1CTL_DATA_IND(t_chan_nr)) -> value dl {
var GsmRrMessage l3 := dec_GsmRrMessage(dl.payload.data_ind.payload);
select (l3) {
- case (tr_PagingType1_empty) { repeat; }
+ case (tr_PAG_REQ1(tr_MI_LV(t_MI_NoIdentity()))) { repeat; }
case (tr_PagingType1) {
setverdict(fail, "Received non-empty PT1 after disabling ETWS PN: ", l3);
}
@@ -1057,7 +1044,7 @@ testcase TC_etws_pcu() runs on test_CT {
f_init_l1ctl();
f_l1_tune(L1CTL, ccch_mode := CCCH_MODE_COMBINED_CBCH);
- RSL_CCHAN.send(ts_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
+ RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_OSMO_ETWS_CMD(c_etws)));
T.start;
alt {
@@ -1097,7 +1084,6 @@ control {
execute( TC_cbc_sdcch4_load_idle() );
execute( TC_cbc_sdcch4_load_overload() );
- if (false) { /* FIXME: SDCCH/8 support broken, needs trxcon + L1CTL work */
execute( TC_sms_cb_cmd_sdcch8_1block() );
execute( TC_sms_cb_cmd_sdcch8_2block() );
execute( TC_sms_cb_cmd_sdcch8_3block() );
@@ -1108,7 +1094,6 @@ control {
execute( TC_sms_cb_cmd_sdcch8_default_and_normal() );
execute( TC_cbc_sdcch8_load_idle() );
execute( TC_cbc_sdcch8_load_overload() );
- }
execute( TC_etws_p1ro() );
execute( TC_etws_p1ro_end() );
diff --git a/bts/BTS_Tests_perf.ttcn b/bts/BTS_Tests_perf.ttcn
new file mode 100644
index 0000000..5b3b672
--- /dev/null
+++ b/bts/BTS_Tests_perf.ttcn
@@ -0,0 +1,103 @@
+module BTS_Tests_perf {
+
+/* Performance Tests for OsmoBTS
+ * (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * 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
+ *
+ * This test suite tests performance of OsmoBTS under different heavy load scenarios.
+ */
+
+import from Misc_Helpers all;
+import from General_Types all;
+import from Osmocom_Types all;
+import from GSM_Types all;
+import from L1CTL_PortType all;
+import from L1CTL_Types all;
+import from LAPDm_Types all;
+import from IPA_Emulation all;
+import from GSM_RR_Types all;
+
+import from RSL_Types all;
+import from RSL_Emulation all;
+
+import from PCUIF_Types all;
+import from PCUIF_CodecPort all;
+
+import from Osmocom_VTY_Functions all;
+
+import from BTS_Tests all;
+
+/***********************************************************************
+ * Performance tests. Expect osmo-bts to be configured with all TRX as TCH/H.
+ ***********************************************************************/
+
+modulepar {
+ float mp_wait_time := 10.0;
+}
+
+
+/* This test requires BTS with 1 TRX to be configured with following timeslots: TS[0]=CCCH+SDCCH4, TS[1..7]: TCH/H
+ * One can simply take the osmo-bsc.cfg in the same dir and change TS1..7, that's all needed.
+ * It will activate TS1..7 TCH/Hchannels (2 TCH/H per TS, that's 14 channels)
+ * and wait for requested time. This test is useful to bring the BTS (+BTS-TRX)
+ * into a high channel load state to check that the system it runs on can keep
+ * on with full load.
+ */
+function f_TC_highchanload_tchh(charstring id) runs on ConnHdlr {
+ var ChannelNrs chan_nr := { /* TS 1..7: TCH/H */
+ valueof(ts_RslChanNr_Lm(1,0)), valueof(ts_RslChanNr_Lm(1,1)),
+ valueof(ts_RslChanNr_Lm(2,0)), valueof(ts_RslChanNr_Lm(2,1)),
+ valueof(ts_RslChanNr_Lm(3,0)), valueof(ts_RslChanNr_Lm(3,1)),
+ valueof(ts_RslChanNr_Lm(4,0)), valueof(ts_RslChanNr_Lm(4,1)),
+ valueof(ts_RslChanNr_Lm(5,0)), valueof(ts_RslChanNr_Lm(5,1)),
+ valueof(ts_RslChanNr_Lm(6,0)), valueof(ts_RslChanNr_Lm(6,1)),
+ valueof(ts_RslChanNr_Lm(7,0)), valueof(ts_RslChanNr_Lm(7,1))
+ };
+
+ log("Started");
+ for (var integer i := 0; i < sizeof(chan_nr); i := i+1) {
+ log("Registering ", chan_nr[i]);
+ f_rslem_register(0, chan_nr[i]);
+ }
+ log("Registered");
+ for (var integer i := 0; i < sizeof(chan_nr); i := i+1) {
+ f_rsl_transceive(ts_RSL_CHAN_ACT(chan_nr[i],
+ ts_RSL_ChanMode(RSL_CHRT_TCH_H, RSL_CMOD_SP_GSM3 /* AMR*/)),
+ tr_RSL_CHAN_ACT_ACK(chan_nr[i]),
+ log2str("RSL CHAN ACT [", i, "]"));
+ }
+ log("Activated, now waiting ", mp_wait_time, " seconds");
+
+ f_sleep(mp_wait_time);
+ log("sleep done, deactivating");
+
+ for (var integer i := 0; i < sizeof(chan_nr); i := i+1) {
+ f_rsl_transceive(ts_RSL_RF_CHAN_REL(chan_nr[i]),
+ tr_RSL_RF_CHAN_REL_ACK(chan_nr[i]),
+ log2str("RF CHAN REL [", i, "]"),
+ true);
+ }
+ setverdict(pass);
+}
+testcase TC_highchanload_tchh() runs on test_CT {
+ var ConnHdlr vc_conn; /* 1..7 * 2 */
+ var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN,
+ t_guard := 60.0 + mp_wait_time));
+
+ f_init();
+
+ vc_conn := f_start_handler(refers(f_TC_highchanload_tchh), pars);
+ vc_conn.done;
+}
+
+control {
+ execute( TC_highchanload_tchh() );
+}
+
+
+}
diff --git a/bts/README.md b/bts/README.md
index 058e1d2..d7d6bdc 100644
--- a/bts/README.md
+++ b/bts/README.md
@@ -4,6 +4,8 @@
* A-bis side: RSL (emulates BSC-side server)
* Um side: L1CTL to control MS
* PCU side: pcu_socket
+ * VTY
+ * CTRL
{% dot bts_tests.svg
digraph G {
@@ -14,7 +16,7 @@ digraph G {
BSC [label="osmo-bsc\nOML only"];
BTS -> fake_trx [label="bursts"];
fake_trx -> trxcon [label="bursts"];
- trxcon -> ATS [label="bursts"];
+ trxcon -> ATS [label="GSM MAC blocks"];
BTS -> BSC [label="A-bis OML"];
BTS -> ATS [label="A-bis RSL"];
diff --git a/bts/expected-results.xml b/bts/expected-results.xml
index 7d89da3..fa86f8a 100644
--- a/bts/expected-results.xml
+++ b/bts/expected-results.xml
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
-<testsuite name='Titan' tests='88' failures='5' errors='0' skipped='1' inconc='0' time='MASKED'>
+<testsuite name='Titan' tests='156' failures='18' errors='1' skipped='0' inconc='0' time='MASKED'>
<testcase classname='BTS_Tests' name='TC_chan_act_stress' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_chan_act_react' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_chan_deact_not_active' time='MASKED'/>
@@ -9,35 +9,65 @@
<testcase classname='BTS_Tests' name='TC_sacch_info_mod' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_sacch_multi' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_sacch_multi_chg' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_sacch_chan_act' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_sacch_chan_act_ho_async' time='MASKED'>
+ <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Unexpected RSL message received"
+ BTS_Tests.ttcn:MASKED BTS_Tests control part
+ BTS_Tests.ttcn:MASKED TC_sacch_chan_act_ho_async testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests' name='TC_sacch_chan_act_ho_sync' time='MASKED'>
+ <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Unexpected RSL message received"
+ BTS_Tests.ttcn:MASKED BTS_Tests control part
+ BTS_Tests.ttcn:MASKED TC_sacch_chan_act_ho_sync testcase
+ </failure>
+ </testcase>
<testcase classname='BTS_Tests' name='TC_rach_content' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_rach_count' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_rach_max_ta' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_meas_res_sign_tchf' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_meas_res_sign_tchh' time='MASKED'>
- <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Received unspecific MEAS RES { msg_disc := { msg_group := RSL_MDISC_DCHAN (4), transparent := false }, msg_type := RSL_MT_MEAS_RES (40), ies := { { iei := RSL_IE_CHAN_NR (1), body := { chan_nr := { u := { lm := { tag := '0001'B, sub_chan := 0 } }, tn := 5 } } }, { iei := RSL_IE_MEAS_RES_NR (27), body := { meas_res_nr := 1 } }, { iei := RSL_IE_UPLINK_MEAS (25), body := { uplink_meas := { len := 3, rfu := '0'B, dtx_d := false, rxlev_f_u := 10, reserved1 := '00'B, rxlev_s_u := 10, reserved2 := '00'B, rxq_f_u := 7, rxq_s_u := 7, supp_meas_info := omit } } }, { iei := RSL_IE_BS_POWER (4), body := { bs_power := { reserved := 0, epc := false, fpc := false, power_level := 0 } } }, { iei := RSL_IE_L1_INFO (10), body := { l1_info := { ms_power_lvl := 7, fpc := false, reserved := 0, actual_ta := 0 } } }, { iei := RSL_IE_L3_INFO (11), body := { l3_info := { len := 6, payload := '061539390000'O } } }, { iei := RSL_IE_MS_TIMING_OFFSET (37), body := { ms_timing_offset := 65 } } } }"
+ <testcase classname='BTS_Tests' name='TC_ho_rach' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rach_load_idle_thresh0' time='MASKED'>
+ <failure type='fail-verdict'>Unexpected RACH LOAD IND: { streamId := IPAC_PROTO_RSL_TRX0 (0), rsl := { msg_disc := { msg_group := RSL_MDISC_CCHAN (6), transparent := false }, msg_type := RSL_MT_CCCH_LOAD_IND (18), ies := { { iei := RSL_IE_CHAN_NR (1), body := { chan_nr := { u := { ch0 := RSL_CHAN_NR_RACH (17) }, tn := 0 } } }, { iei := RSL_IE_RACH_LOAD (18), body := { rach_load := { len := 6, slot_count := 0, busy_count := 0, access_count := 0 } } } } } }
BTS_Tests.ttcn:MASKED BTS_Tests control part
- BTS_Tests.ttcn:MASKED TC_meas_res_sign_tchh testcase
+ BTS_Tests.ttcn:MASKED TC_rach_load_idle_thresh0 testcase
</failure>
</testcase>
- <testcase classname='BTS_Tests' name='TC_meas_res_sign_sdcch4' time='MASKED'>
- <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Received unspecific MEAS RES { msg_disc := { msg_group := RSL_MDISC_DCHAN (4), transparent := false }, msg_type := RSL_MT_MEAS_RES (40), ies := { { iei := RSL_IE_CHAN_NR (1), body := { chan_nr := { u := { sdcch4 := { tag := '001'B, sub_chan := 0 } }, tn := 0 } } }, { iei := RSL_IE_MEAS_RES_NR (27), body := { meas_res_nr := 14 } }, { iei := RSL_IE_UPLINK_MEAS (25), body := { uplink_meas := { len := 3, rfu := '0'B, dtx_d := false, rxlev_f_u := 7, reserved1 := '00'B, rxlev_s_u := 7, reserved2 := '00'B, rxq_f_u := 7, rxq_s_u := 7, supp_meas_info := omit } } }, { iei := RSL_IE_BS_POWER (4), body := { bs_power := { reserved := 0, epc := false, fpc := false, power_level := 0 } } }, { iei := RSL_IE_L1_INFO (10), body := { l1_info := { ms_power_lvl := 7, fpc := false, reserved := 0, actual_ta := 0 } } }, { iei := RSL_IE_L3_INFO (11), body := { l3_info := { len := 6, payload := '061539390000'O } } }, { iei := RSL_IE_MS_TIMING_OFFSET (37), body := { ms_timing_offset := 65 } } } }"
+ <testcase classname='BTS_Tests' name='TC_rach_load_idle_below_thresh' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rach_load_count' time='MASKED'>
+ <failure type='fail-verdict'>Unexpected RACH LOAD IND: { streamId := IPAC_PROTO_RSL_TRX0 (0), rsl := { msg_disc := { msg_group := RSL_MDISC_CCHAN (6), transparent := false }, msg_type := RSL_MT_CCCH_LOAD_IND (18), ies := { { iei := RSL_IE_CHAN_NR (1), body := { chan_nr := { u := { ch0 := RSL_CHAN_NR_RACH (17) }, tn := 0 } } }, { iei := RSL_IE_RACH_LOAD (18), body := { rach_load := { len := 6, slot_count := 0, busy_count := 0, access_count := 0 } } } } } }
BTS_Tests.ttcn:MASKED BTS_Tests control part
- BTS_Tests.ttcn:MASKED TC_meas_res_sign_sdcch4 testcase
+ BTS_Tests.ttcn:MASKED TC_rach_load_count testcase
</failure>
</testcase>
- <testcase classname='BTS_Tests' name='TC_meas_res_sign_sdcch8' time='MASKED'>
- <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Received unspecific MEAS RES { msg_disc := { msg_group := RSL_MDISC_DCHAN (4), transparent := false }, msg_type := RSL_MT_MEAS_RES (40), ies := { { iei := RSL_IE_CHAN_NR (1), body := { chan_nr := { u := { sdcch8 := { tag := '01'B, sub_chan := 0 } }, tn := 6 } } }, { iei := RSL_IE_MEAS_RES_NR (27), body := { meas_res_nr := 14 } }, { iei := RSL_IE_UPLINK_MEAS (25), body := { uplink_meas := { len := 3, rfu := '0'B, dtx_d := false, rxlev_f_u := 7, reserved1 := '00'B, rxlev_s_u := 7, reserved2 := '00'B, rxq_f_u := 7, rxq_s_u := 7, supp_meas_info := omit } } }, { iei := RSL_IE_BS_POWER (4), body := { bs_power := { reserved := 0, epc := false, fpc := false, power_level := 0 } } }, { iei := RSL_IE_L1_INFO (10), body := { l1_info := { ms_power_lvl := 7, fpc := false, reserved := 0, actual_ta := 0 } } }, { iei := RSL_IE_L3_INFO (11), body := { l3_info := { len := 6, payload := '061539390000'O } } }, { iei := RSL_IE_MS_TIMING_OFFSET (37), body := { ms_timing_offset := 65 } } } }"
+ <testcase classname='BTS_Tests' name='TC_meas_res_sign_tchf' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_meas_res_sign_tchh' time='MASKED'>
+ <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Received unspecific MEAS RES { msg_disc := { msg_group := RSL_MDISC_DCHAN (4), transparent := false }, msg_type := RSL_MT_MEAS_RES (40), ies := { { iei := RSL_IE_CHAN_NR (1), body := { chan_nr := { u := { lm := { tag := '0001'B, sub_chan := 0 } }, tn := 5 } } }, { iei := RSL_IE_MEAS_RES_NR (27), body := { meas_res_nr := 1 } }, { iei := RSL_IE_UPLINK_MEAS (25), body := { uplink_meas := { len := 3, rfu := '0'B, dtx_d := false, rxlev_f_u := 10, reserved1 := '00'B, rxlev_s_u := 10, reserved2 := '00'B, rxq_f_u := 7, rxq_s_u := 7, supp_meas_info := omit } } }, { iei := RSL_IE_BS_POWER (4), body := { bs_power := { reserved := 0, epc := false, fpc := false, power_level := 0 } } }, { iei := RSL_IE_L1_INFO (10), body := { l1_info := { ms_power_lvl := 7, fpc := false, reserved := 0, actual_ta := 0 } } }, { iei := RSL_IE_L3_INFO (11), body := { l3_info := { len := 6, payload := '061539390000'O } } }, { iei := RSL_IE_MS_TIMING_OFFSET (37), body := { ms_timing_offset := 65 } } } }"
BTS_Tests.ttcn:MASKED BTS_Tests control part
- BTS_Tests.ttcn:MASKED TC_meas_res_sign_sdcch8 testcase
+ BTS_Tests.ttcn:MASKED TC_meas_res_sign_tchh testcase
</failure>
</testcase>
+ <testcase classname='BTS_Tests' name='TC_meas_res_sign_sdcch4' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_meas_res_sign_sdcch8' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_meas_res_sign_tchh_toa256' time='MASKED'>
- <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Received unspecific MEAS RES { msg_disc := { msg_group := RSL_MDISC_DCHAN (4), transparent := false }, msg_type := RSL_MT_MEAS_RES (40), ies := { { iei := RSL_IE_CHAN_NR (1), body := { chan_nr := { u := { lm := { tag := '0001'B, sub_chan := 0 } }, tn := 5 } } }, { iei := RSL_IE_MEAS_RES_NR (27), body := { meas_res_nr := 1 } }, { iei := RSL_IE_UPLINK_MEAS (25), body := { uplink_meas := { len := 11, rfu := '0'B, dtx_d := false, rxlev_f_u := 10, reserved1 := '00'B, rxlev_s_u := 10, reserved2 := '00'B, rxq_f_u := 7, rxq_s_u := 7, supp_meas_info := { toa256_mean := 512, toa256_min := 512, toa256_max := 512, toa256_std_dev := 0 } } } }, { iei := RSL_IE_BS_POWER (4), body := { bs_power := { reserved := 0, epc := false, fpc := false, power_level := 0 } } }, { iei := RSL_IE_L1_INFO (10), body := { l1_info := { ms_power_lvl := 7, fpc := false, reserved := 0, actual_ta := 0 } } }, { iei := RSL_IE_L3_INFO (11), body := { l3_info := { len := 6, payload := '061539390000'O } } }, { iei := RSL_IE_MS_TIMING_OFFSET (37), body := { ms_timing_offset := 65 } } } }"
+ <error type='DTE'></error>
+ </testcase>
+ <testcase classname='BTS_Tests' name='TC_rsl_bs_pwr_static_ass' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_bs_pwr_static_power_control' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_ctrl' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_dyn_active' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_dyn_active2' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_dyn_up' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_dyn_down' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_dyn_ass_updown' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_dyn_max' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_chan_initial_ms_pwr' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_chan_initial_ta' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_rsl_modify_encr' time='MASKED'>
+ <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : BTS shouldn't be able to decrypt after key change"
BTS_Tests.ttcn:MASKED BTS_Tests control part
- BTS_Tests.ttcn:MASKED TC_meas_res_sign_tchh_toa256 testcase
+ BTS_Tests.ttcn:MASKED TC_rsl_modify_encr testcase
</failure>
</testcase>
- <testcase classname='BTS_Tests' name='TC_rsl_ms_pwr_ctrl' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_conn_fail_crit' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_paging_imsi_80percent' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_paging_tmsi_80percent' time='MASKED'/>
@@ -66,28 +96,56 @@
<testcase classname='BTS_Tests' name='TC_pcu_deact_req' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_pcu_deact_req_wrong_ts' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_pcu_ver_si13' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_pcu_data_req_wrong_bts' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_pcu_data_req_wrong_trx' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_pcu_data_req_wrong_ts' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_pcu_data_req_ts_inactive' time='MASKED'>
- <skipped>no verdict</skipped>
- </testcase>
- <testcase classname='BTS_Tests' name='TC_pcu_data_req_pdtch' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_pcu_data_req_ptcch' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_ptcch' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_pcu_data_req_agch' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_data_req_pch' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_pcu_data_req_imm_ass_pch' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_pcu_rach_content' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_pcu_ext_rach_content' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_data_ind_lqual_cb' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_pcu_paging_from_rsl' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_time_ind' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_rts_req' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_oml_alert' time='MASKED'>
+ <failure type='fail-verdict'>Could not connect IPA socket from "" port 0 to "127.0.0.1" port 4249; check your configuration
+ BTS_Tests.ttcn:MASKED BTS_Tests control part
+ BTS_Tests.ttcn:MASKED TC_pcu_oml_alert testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests' name='TC_pcu_rr_suspend' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_connect_multi' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_reconnect' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_noconnect_nosi3gprs' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_noconnect_nosi4gprs' time='MASKED'>
+ <failure type='fail-verdict'>SYSTEM_INFORMATION_TYPE_4 (28) indicates GPRS even before PCU socket connected
+ BTS_Tests.ttcn:MASKED BTS_Tests control part
+ BTS_Tests.ttcn:MASKED TC_pcu_socket_noconnect_nosi4gprs testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_connect_si3gprs' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_connect_si4gprs' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_disconnect_nosi3gprs' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_disconnect_nosi4gprs' time='MASKED'>
+ <failure type='fail-verdict'>SYSTEM_INFORMATION_TYPE_4 (28) indicates GPRS after PCU socket disconnected
+ BTS_Tests.ttcn:MASKED BTS_Tests control part
+ BTS_Tests.ttcn:MASKED TC_pcu_socket_disconnect_nosi4gprs testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests' name='TC_pcu_socket_verify_info_ind' time='MASKED'>
+ <failure type='fail-verdict'>Expected cell_id '23' and got '0'. This either means, that the BTS is sending the wrong cell_id, or that the BTS sent it too early (OS#4179)
+ BTS_Tests.ttcn:MASKED BTS_Tests control part
+ BTS_Tests.ttcn:MASKED TC_pcu_socket_verify_info_ind testcase
+ </failure>
+ </testcase>
<testcase classname='BTS_Tests' name='TC_dyn_osmo_pdch_act_deact' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_dyn_osmo_pdch_unsol_deact' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_dyn_osmo_pdch_double_act' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_dyn_ipa_pdch_act_deact' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_dyn_ipa_pdch_act_tchf_act_nack' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_dyn_osmo_pdch_unsol_deact' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_dyn_osmo_pdch_tchf_act' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_dyn_osmo_pdch_tchh_act' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_dyn_ipa_pdch_act_deact' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_dyn_ipa_pdch_tchf_act' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_dyn_ipa_pdch_tchf_act_pdch_act_nack' time='MASKED'/>
- <testcase classname='BTS_Tests' name='TC_dyn_ipa_pdch_act_tchf_act_nack' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_rll_est_ind' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_rll_est_req_DCCH_3' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_rll_est_req_ACCH_3' time='MASKED'/>
@@ -106,6 +164,9 @@
<testcase classname='BTS_Tests' name='TC_encr_cmd_a51' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_encr_cmd_a52' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_encr_cmd_a53' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_err_rep_wrong_mdisc' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_err_rep_wrong_msg_type' time='MASKED'/>
+ <testcase classname='BTS_Tests' name='TC_err_rep_wrong_sequence' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_lapdm_selftest' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_tch_sign_l2_fill_frame' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_tch_sign_l2_fill_frame_dtxd' time='MASKED'>
@@ -116,4 +177,65 @@
</testcase>
<testcase classname='BTS_Tests' name='TC_chopped_ipa_ping' time='MASKED'/>
<testcase classname='BTS_Tests' name='TC_chopped_ipa_payload' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_cbch_load_idle_no_cbch' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_1block' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_2block' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_3block' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_4block' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_multi' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_schedule' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_default_only' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_default_and_normal' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_sms_cb_cmd_sdcch4_default_then_null' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_cbc_sdcch4_load_idle' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_cbc_sdcch4_load_overload' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_etws_p1ro' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_etws_p1ro_end' time='MASKED'/>
+ <testcase classname='BTS_Tests_SMSCB' name='TC_etws_pcu' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_ua_dcch_sapi0' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_ua_dcch_sapi0_nopayload' time='MASKED'>
+ <failure type='fail-verdict'>Initial SABM/UA must contain L3 payload but BTS accepts without
+ BTS_Tests_LAPDm.ttcn:MASKED BTS_Tests_LAPDm control part
+ BTS_Tests_LAPDm.ttcn:MASKED TC_sabm_ua_dcch_sapi0_nopayload testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_ua_dcch_sapi3' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_ua_dcch_sapi4' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_contention' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_retransmit' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_retransmit_bts' time='MASKED'>
+ <failure type='fail-verdict'>Incorrect number of SABM re-transmissions of observed: 7
+ BTS_Tests_LAPDm.ttcn:MASKED BTS_Tests_LAPDm control part
+ BTS_Tests_LAPDm.ttcn:MASKED TC_sabm_retransmit_bts testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_invalid_resp' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_dm' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_establish_ign_first_sabm' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_iframe_seq_and_ack' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_iframe_timer_recovery' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_ns_seq_error' time='MASKED'>
+ <failure type='fail-verdict'>Missing second REJ
+ BTS_Tests_LAPDm.ttcn:MASKED BTS_Tests_LAPDm control part
+ BTS_Tests_LAPDm.ttcn:MASKED TC_ns_seq_error testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_nr_seq_error' time='MASKED'>
+ <failure type='fail-verdict'>Missing DISC from BTS
+ BTS_Tests_LAPDm.ttcn:MASKED BTS_Tests_LAPDm control part
+ BTS_Tests_LAPDm.ttcn:MASKED TC_nr_seq_error testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_rec_invalid_frame' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_segm_concat_dcch' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_segm_concat_sacch' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_t200_n200' time='MASKED'>
+ <failure type='fail-verdict'>"BTS_Tests.ttcn:MASKED : Tguard timeout"
+ BTS_Tests_LAPDm.ttcn:MASKED BTS_Tests_LAPDm control part
+ BTS_Tests_LAPDm.ttcn:MASKED TC_t200_n200 testcase
+ </failure>
+ </testcase>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_rr_response_frame_loss' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_incorrect_cr' time='MASKED'/>
+ <testcase classname='BTS_Tests_LAPDm' name='TC_sabm_incorrect_c' time='MASKED'/>
</testsuite>
diff --git a/bts/gen_links.sh b/bts/gen_links.sh
index aafe231..7aa8398 100755
--- a/bts/gen_links.sh
+++ b/bts/gen_links.sh
@@ -33,7 +33,7 @@ FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn"
gen_links $DIR $FILES
DIR=../library
-FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn Osmocom_VTY_Functions.ttcn GSM_SystemInformation.ttcn Osmocom_Types.ttcn RLCMAC_Types.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc L1CTL_Types.ttcn L1CTL_PortType.ttcn L1CTL_PortType_CtrlFunct.ttcn L1CTL_PortType_CtrlFunctDef.cc LAPDm_RAW_PT.ttcn LAPDm_Types.ttcn "
+FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn Osmocom_VTY_Functions.ttcn GSM_SystemInformation.ttcn GSM_RestOctets.ttcn Osmocom_Types.ttcn RLCMAC_Templates.ttcn RLCMAC_Types.ttcn RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc L1CTL_Types.ttcn L1CTL_PortType.ttcn L1CTL_PortType_CtrlFunct.ttcn L1CTL_PortType_CtrlFunctDef.cc LAPDm_RAW_PT.ttcn LAPDm_Types.ttcn "
#FILES+="NS_Emulation.ttcn NS_CodecPort.ttcn NS_CodecPort_CtrlFunct.ttcn NS_CodecPort_CtrlFunctDef.cc "
#FILES+="BSSGP_Emulation.ttcn Osmocom_Gb_Types.ttcn "
FILES+="IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp IPA_CodecPort.ttcn RSL_Types.ttcn RSL_Emulation.ttcn AbisOML_Types.ttcn "
diff --git a/pcu/osmo-bsc.cfg b/bts/osmo-bsc.cfg
index c561955..84a3a3c 100644
--- a/pcu/osmo-bsc.cfg
+++ b/bts/osmo-bsc.cfg
@@ -3,41 +3,28 @@
!!
password foo
!
-log gsmtap 127.0.0.1
+log gsmtap 127.0.0.10
logging level set-all debug
!
-
log stderr
- logging color 1
logging filter all 1
- logging print level 1
+ logging color 0
logging print category 1
- logging print category-hex 0
- logging print file basename last
+ logging timestamp 1
logging print extended-timestamp 1
logging level set-all debug
- #~ logging level hodec info
- #~ logging level ho info
- #~ logging level nm info
- #~ logging level meas info
- #~ logging level lmi info
- #~ logging level linp notice
- #~ logging level lss7 notice
- #~ logging level lsccp notice
- #~ logging level lsua notice
- #~ logging level lm3ua notice
-
+!
stats interval 5
!
line vty
no login
- bind 127.0.0.1
+ bind 127.0.0.11
!
e1_input
e1_line 0 driver ipa
e1_line 0 port 0
no e1_line 0 keepalive
- ipa bind 127.0.0.1
+ ipa bind 127.0.0.11
cs7 instance 0
point-code 0.23.3
asp asp-clnt-msc-0 2905 0 m3ua
@@ -45,8 +32,8 @@ cs7 instance 0
asp asp-clnt-msc-0
routing-key 2 0.23.3
network
- network country code 262
- mobile network code 42
+ network country code 1
+ mobile network code 1
encryption a5 0
neci 1
paging any use tch 0
@@ -61,8 +48,8 @@ network
bts 0
type sysmobts
band DCS1800
- cell_identity 20960
- location_area_code 13135
+ cell_identity 0
+ location_area_code 1
dtx uplink force
dtx downlink
base_station_id_code 63
@@ -79,7 +66,7 @@ network
early-classmark-sending forbidden
early-classmark-sending-3g allowed
ip.access unit_id 1234 0
- ip.access rsl-ip 127.0.0.1
+ ip.access rsl-ip 127.0.0.10
oml ip.access stream_id 255 line 0
neighbor-list mode manual-si5
neighbor-list add arfcn 100
@@ -112,61 +99,40 @@ network
gprs ns timer tns-alive 3
gprs ns timer tns-alive-retries 10
gprs nsvc 0 nsvci 1234
- gprs nsvc 0 local udp port 22000
+ gprs nsvc 0 local udp port 23000
gprs nsvc 0 remote udp port 23000
- gprs nsvc 0 remote ip 127.0.0.1
+ gprs nsvc 0 remote ip 0.0.0.0
no force-combined-si
trx 0
rf_locked 0
arfcn 871
- nominal power 23
+ nominal power 50
max_power_red 20
rsl e1 tei 0
timeslot 0
phys_chan_config CCCH+SDCCH4
hopping enabled 0
timeslot 1
- phys_chan_config TCH/H
+ phys_chan_config TCH/F
hopping enabled 0
timeslot 2
- phys_chan_config TCH/H
+ phys_chan_config TCH/F
hopping enabled 0
timeslot 3
- phys_chan_config TCH/H
+ phys_chan_config TCH/F_PDCH
hopping enabled 0
timeslot 4
- phys_chan_config TCH/H
+ phys_chan_config TCH/F_TCH/H_PDCH
hopping enabled 0
timeslot 5
phys_chan_config TCH/H
hopping enabled 0
timeslot 6
- phys_chan_config TCH/H
+ phys_chan_config SDCCH8
hopping enabled 0
timeslot 7
phys_chan_config PDCH
hopping enabled 0
- #~ timeslot 1
- #~ phys_chan_config TCH/F
- #~ hopping enabled 0
- #~ timeslot 2
- #~ phys_chan_config TCH/F
- #~ hopping enabled 0
- #~ timeslot 3
- #~ phys_chan_config TCH/F_PDCH
- #~ hopping enabled 0
- #~ timeslot 4
- #~ phys_chan_config TCH/F_TCH/H_PDCH
- #~ hopping enabled 0
- #~ timeslot 5
- #~ phys_chan_config TCH/H
- #~ hopping enabled 0
- #~ timeslot 6
- #~ phys_chan_config SDCCH8
- #~ hopping enabled 0
- #~ timeslot 7
- #~ phys_chan_config PDCH
- #~ hopping enabled 0
msc 0
core-location-area-code 666
core-cell-identity 333
@@ -191,4 +157,3 @@ msc 0
bsc
mid-call-timeout 0
no missing-msc-text
- access-list-name bsc-list
diff --git a/bts/osmo-bts.cfg b/bts/osmo-bts.cfg
new file mode 100644
index 0000000..c2cd0bd
--- /dev/null
+++ b/bts/osmo-bts.cfg
@@ -0,0 +1,56 @@
+!
+! OsmoBTS (0.4.0.446-e0fb) configuration saved from vty
+!!
+!
+log gsmtap 127.0.0.10
+ logging level set-all debug
+!
+log stderr
+ logging filter all 1
+ logging color 0
+ logging print category 1
+ logging timestamp 1
+ logging print extended-timestamp 1
+ logging level set-all debug
+!
+line vty
+ no login
+ bind 127.0.0.20
+!
+e1_input
+ e1_line 0 driver ipa
+ e1_line 0 port 0
+ no e1_line 0 keepalive
+phy 0
+ osmotrx ip local 127.0.0.20
+ osmotrx ip remote 127.0.0.21
+ osmotrx fn-advance 20
+ osmotrx rts-advance 5
+ instance 0
+ osmotrx rx-gain 10
+bts 0
+ band DCS1800
+ ipa unit-id 1234 0
+ oml remote-ip 127.0.0.11
+ rtp jitter-buffer 100
+ paging queue-size 200
+ paging lifetime 0
+ uplink-power-target -75
+ gsmtap-sapi rach
+ gsmtap-sapi agch
+ gsmtap-sapi bcch
+ gsmtap-sapi pch
+ gsmtap-sapi sdcch
+ gsmtap-sapi sacch
+ min-qual-rach 50
+ min-qual-norm -5
+ !settsc
+ pcu-socket /tmp/pcu_sock
+ trx 0
+ power-ramp max-initial 0 mdBm
+ power-ramp step-size 8000 mdB
+ power-ramp step-interval 1
+ ms-power-control dsp
+ phy 0 instance 0
+ctrl
+ bind 127.0.0.20
diff --git a/cbc/CBC_Tests.cfg b/cbc/CBC_Tests.cfg
new file mode 100644
index 0000000..7c2a3ac
--- /dev/null
+++ b/cbc/CBC_Tests.cfg
@@ -0,0 +1,18 @@
+[ORDERED_INCLUDE]
+# Common configuration, shared between test suites
+"../Common.cfg"
+# testsuite specific configuration, not expected to change
+"./CBC_Tests.default"
+
+# Local configuration below
+
+[LOGGING]
+
+[TESTPORT_PARAMETERS]
+
+[MODULE_PARAMETERS]
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
+CBC_Tests.control
diff --git a/cbc/CBC_Tests.default b/cbc/CBC_Tests.default
new file mode 100644
index 0000000..8dbaacc
--- /dev/null
+++ b/cbc/CBC_Tests.default
@@ -0,0 +1,11 @@
+[LOGGING]
+mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
+
+[TESTPORT_PARAMETERS]
+*.CBCVTY.PROMPT1 := "OsmoCBC> "
+*.TCP.noDelay := "yes" // turn off nagle
+
+[MODULE_PARAMETERS]
+// Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoCBC";
+
+[EXECUTE]
diff --git a/cbc/CBC_Tests.ttcn b/cbc/CBC_Tests.ttcn
index 1d5e7ab..85de9b9 100644
--- a/cbc/CBC_Tests.ttcn
+++ b/cbc/CBC_Tests.ttcn
@@ -80,4 +80,34 @@ testcase TC_selftest() runs on test_CT {
log(dec_CBSP_PDU(c_kill_compl));
}
+import from SABP_Types all;
+import from SABP_Templates all;
+import from SABP_IEs all;
+import from SABP_PDU_Descriptions all;
+
+testcase TC_selftest_sabp() runs on test_CT {
+ const octetstring c_write := '00000080930000080006000211120007000240c0000f0010000113f0030282ec0613f0030282ec070001400100000d0002012a000900020000000400010100000056029f01b4d90d064297d9ec37e8fe96b3c9a0303bdd68341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d168341a8d46a3d10012'O;
+
+ log(dec_SABP_PDU(c_write));
+ log(enc_SABP_PDU(dec_SABP_PDU(c_write)));
+
+ var template (value) Service_Areas_List sa_list := {
+ ts_SabpSai('62F224'O, '0023'O, '0042'O)
+ };
+ var template (value) SABP_PDU tx;
+
+ tx := ts_SABP_Write(int2bit(1, 16), int2bit(1, 16), sa_list, 23, 42, '00000000'B, '01011010'B);
+ log("Write: ", enc_SABP_PDU(valueof(tx)))
+
+ var Service_Areas_List sa_list2 := { valueof(ts_SabpSai('62F224'O, '1000'O, '0042'O)) };
+ for (var integer i := 0; i < 2500; i := i+1) {
+ sa_list2 := sa_list2 & {valueof(ts_SabpSai('62F224'O, '2000'O, int2oct(i,2))) };
+ }
+ tx := ts_SABP_Write(int2bit(2, 16), int2bit(2, 16), sa_list2, 23, 42, '00000000'B, '01011010'B);
+ log("Write: ", enc_SABP_PDU(valueof(tx)))
+
+ tx := ts_SABP_Restart(sa_list);
+ log("Restart: ", enc_SABP_PDU(valueof(tx)));
+}
+
}
diff --git a/cbc/SABP_Selftest.ttcn b/cbc/SABP_Selftest.ttcn
new file mode 100644
index 0000000..62e067c
--- /dev/null
+++ b/cbc/SABP_Selftest.ttcn
@@ -0,0 +1,179 @@
+module SABP_Selftest {
+
+/* This is testing the SABP code, specifically re-creating the SABP messages from within
+ * the TCP stream using SABP_Adapter.f_APER_getMsgLen() for the various possible APER
+ * length determinant cases */
+
+import from Osmocom_Types all;
+
+import from SABP_Adapter all;
+import from SABP_Templates all;
+import from IPL4asp_Types all;
+import from IPL4asp_PortType all;
+
+modulepar {
+ charstring mp_bind_ip := "127.0.0.1";
+ integer mp_bind_port := 12345;
+}
+
+type component test_CT extends SABP_Adapter_CT {
+ port IPL4asp_PT TCP;
+ var integer g_tcp_conn_id;
+ timer Tguard := 10.0;
+}
+
+template (value) ASP_Send ts_AS(integer conn_id, octetstring msg) := {
+ connId := conn_id,
+ proto := omit,
+ msg := msg
+}
+
+private altstep as_Tguard() runs on test_CT {
+ [] Tguard.timeout {
+ setverdict(fail, "Tguard timeout");
+ mtc.stop;
+ }
+}
+
+private function f_init() runs on test_CT {
+ var IPL4asp_Types.Result res;
+ var ASP_Event asp_evt;
+
+ activate(as_Tguard());
+ Tguard.start;
+
+ f_bind(mp_bind_ip, mp_bind_port, 0);
+
+ map(self:TCP, system:TCP);
+ res := f_IPL4_connect(TCP, mp_bind_ip, mp_bind_port, "", -1, 0, { tcp:={} });
+ if (not ispresent(res.connId)) {
+ setverdict(fail, "Could not connect to SABP TCP port");
+ mtc.stop;
+ }
+ g_tcp_conn_id := res.connId;
+
+ SABP[0].receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
+ g_sabp_conn_id[0] := asp_evt.connOpened.connId;
+ }
+}
+
+/* send a given input octetstring 'stream' in chunks of 'chunk_size', spaced at 'delay' intervals */
+private function tcp_send_segmented(octetstring stream, integer chunk_size := 1, float delay := 0.05)
+runs on test_CT {
+ var integer i;
+
+ for (i := 0; i < lengthof(stream); i := i+chunk_size) {
+ var integer size := chunk_size;
+ if (lengthof(stream) - i < chunk_size) {
+ size := lengthof(stream) - i;
+ }
+ TCP.send(ts_AS(g_tcp_conn_id, substr(stream, i, size)));
+ f_sleep(delay);
+ }
+}
+
+/* a simple SABP-RESTART message with single-byte length dteerminant (shorter than 128 byte) */
+const octetstring c_restart := '00044010000001000F0009000062F22400230042'O;
+
+/* test whether a message with 1-byte length determinant is parsed */
+testcase TC_1byte_len() runs on test_CT {
+ f_init();
+ TCP.send(ts_AS(g_tcp_conn_id, c_restart));
+ f_sabp_exp(tr_SABP_Restart(?));
+ setverdict(pass);
+}
+
+/* test whether a message with 1-byte length determinant is parsed if each byte is received separately */
+testcase TC_1byte_len_bytewise() runs on test_CT {
+ f_init();
+ tcp_send_segmented(c_restart, 1, 0.05);
+ f_sabp_exp(tr_SABP_Restart(?));
+ setverdict(pass);
+}
+
+/* send three concatenated RESTART in one segment */
+testcase TC_1byte_len_chained() runs on test_CT {
+ var octetstring chain := c_restart & c_restart & c_restart;
+ f_init();
+ TCP.send(ts_AS(g_tcp_conn_id, chain));
+ f_sabp_exp(tr_SABP_Restart(?));
+ f_sabp_exp(tr_SABP_Restart(?));
+ f_sabp_exp(tr_SABP_Restart(?));
+ setverdict(pass);
+}
+
+
+/* SABP write-replace with length determinant encoded over two bytes ('8093'O) */
+const octetstring c_wrepl := '00000080930000080006000211120007000240C0000F0010000113F0030282EC0613F0030282EC070001400100000D0002012A000900020000000400010100000056029F01B4D90D064297D9EC37E8FE96B3C9A0303BDD68341A8D46A3D168341A8D46A3D168341A8D46A3D168341A8D46A3D168341A8D46A3D168341A8D46A3D168341A8D46A3D168341A8D46A3D168341A8D46A3D10012'O;
+
+/* test whether a message with 2-byte length determinant is parsed */
+testcase TC_2byte_len() runs on test_CT {
+ f_init();
+ TCP.send(ts_AS(g_tcp_conn_id, c_wrepl));
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ setverdict(pass);
+}
+
+/* test whether a message with 2-byte length determinant is parsed if each byte is received separately */
+testcase TC_2byte_len_bytewise() runs on test_CT {
+ f_init();
+ tcp_send_segmented(c_wrepl, 1, 0.05);
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ setverdict(pass);
+}
+
+/* send three concatenated WRITE-REPLACE in one segment */
+testcase TC_2byte_len_chained() runs on test_CT {
+ var octetstring chain := c_wrepl & c_wrepl & c_wrepl;
+ f_init();
+ TCP.send(ts_AS(g_tcp_conn_id, chain));
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ setverdict(pass);
+}
+
+/* send three concatenated WRITE-REPLACE in segments of 10 bytes */
+testcase TC_2byte_len_chained_bytewise() runs on test_CT {
+ var octetstring chain := c_wrepl & c_wrepl & c_wrepl;
+ f_init();
+ tcp_send_segmented(chain, 10, 0.05);
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ setverdict(pass);
+}
+
+/* SABP write-replace with length determinant encoded over multiple chunks ('Cx'O case) */
+const octetstring c_chunked := '000000C1000007000600020002000700020002000F00C109C462F2241000004262F2242000000062F2242000000162F2242000000262F2242000000362F2242000000462F2242000000562F2242000000662F2242000000762F2242000000862F2242000000962F2242000000A62F2242000000B62F2242000000C62F2242000000D62F2242000000E62F2242000000F62F2242000001062F2242000001162F2242000001262F2242000001362F2242000001462F2242000001562F2242000001662F2242000001762F2242000001862F2242000001962F2242000001A62F2242000001B62F2242000001C62F2242000001D62F2242000001E62F2242000001F62F2242000002062F2242000002162F2242000002262F2242000002362F2242000002462F2242000002562F2242000002662F2242000002762F2242000002862F2242000002962F2242000002A62F2242000002B62F2242000002C62F2242000002D62F2242000002E62F2242000002F62F2242000003062F2242000003162F2242000003262F2242000003362F2242000003462F2242000003562F2242000003662F2242000003762F2242000003862F2242000003962F2242000003A62F2242000003B62F2242000003C62F2242000003D62F2242000003E62F2242000003F62F2242000004062F2242000004162F2242000004262F2242000004362F2242000004462F2242000004562F2242000004662F2242000004762F2242000004862F2242000004962F2242000004A62F2242000004B62F2242000004C62F2242000004D62F2242000004E62F2242000004F62F2242000005062F2242000005162F2242000005262F2242000005362F2242000005462F2242000005562F2242000005662F2242000005762F2242000005862F2242000005962F2242000005A62F2242000005B62F2242000005C62F2242000005D62F2242000005E62F2242000005F62F2242000006062F2242000006162F2242000006262F2242000006362F2242000006462F2242000006562F2242000006662F2242000006762F2242000006862F2242000006962F2242000006A62F2242000006B62F2242000006C62F2242000006D62F2242000006E62F2242000006F62F2242000007062F2242000007162F2242000007262F2242000007362F2242000007462F2242000007562F2242000007662F2242000007762F2242000007862F2242000007962F2242000007A62F2242000007B62F2242000007C62F2242000007D62F2242000007E62F2242000007F62F2242000008062F2242000008162F2242000008262F2242000008362F2242000008462F2242000008562F2242000008662F2242000008762F2242000008862F2242000008962F2242000008A62F2242000008B62F2242000008C62F2242000008D62F2242000008E62F2242000008F62F2242000009062F2242000009162F2242000009262F2242000009362F2242000009462F2242000009562F2242000009662F2242000009762F2242000009862F2242000009962F2242000009A62F2242000009B62F2242000009C62F2242000009D62F2242000009E62F2242000009F62F224200000A062F224200000A162F224200000A262F224200000A362F224200000A462F224200000A562F224200000A662F224200000A762F224200000A862F224200000A962F224200000AA62F224200000AB62F224200000AC62F224200000AD62F224200000AE62F224200000AF62F224200000B062F224200000B162F224200000B262F224200000B362F224200000B462F224200000B562F224200000B662F224200000B762F224200000B862F224200000B962F224200000BA62F224200000BB62F224200000BC62F224200000BD62F224200000BE62F224200000BF62F224200000C062F224200000C162F224200000C262F224200000C362F224200000C462F224200000C562F224200000C662F224200000C762F224200000C862F224200000C962F224200000CA62F224200000CB62F224200000CC62F224200000CD62F224200000CE62F224200000CF62F224200000D062F224200000D162F224200000D262F224200000D362F224200000D462F224200000D562F224200000D662F224200000D762F224200000D862F224200000D962F224200000DA62F224200000DB62F224200000DC62F224200000DD62F224200000DE62F224200000DF62F224200000E062F224200000E162F224200000E262F224200000E362F224200000E462F224200000E562F224200000E662F224200000E762F224200000E862F224200000E962F224200000EA62F224200000EB62F224200000EC62F224200000ED62F224200000EE62F224200000EF62F224200000F062F224200000F162F224200000F262F224200000F362F224200000F462F224200000F562F224200000F662F224200000F762F224200000F862F224200000F962F224200000FA62F224200000FB62F224200000FC62F224200000FD62F224200000FE62F224200000FF62F2242000010062F2242000010162F2242000010262F2242000010362F2242000010462F2242000010562F2242000010662F2242000010762F2242000010862F2242000010962F2242000010A62F2242000010B62F2242000010C62F2242000010D62F2242000010E62F2242000010F62F2242000011062F2242000011162F2242000011262F2242000011362F2242000011462F2242000011562F2242000011662F2242000011762F2242000011862F2242000011962F2242000011A62F2242000011B62F2242000011C62F2242000011D62F2242000011E62F2242000011F62F2242000012062F2242000012162F2242000012262F2242000012362F2242000012462F2242000012562F2242000012662F2242000012762F2242000012862F2242000012962F2242000012A62F2242000012B62F2242000012C62F2242000012D62F2242000012E62F2242000012F62F2242000013062F2242000013162F2242000013262F2242000013362F2242000013462F2242000013562F2242000013662F2242000013762F2242000013862F2242000013962F2242000013A62F2242000013B62F2242000013C62F2242000013D62F2242000013E62F2242000013F62F2242000014062F2242000014162F2242000014262F2242000014362F2242000014462F2242000014562F2242000014662F2242000014762F2242000014862F2242000014962F2242000014A62F2242000014B62F2242000014C62F2242000014D62F2242000014E62F2242000014F62F2242000015062F2242000015162F2242000015262F2242000015362F2242000015462F2242000015562F2242000015662F2242000015762F2242000015862F2242000015962F2242000015A62F2242000015B62F2242000015C62F2242000015D62F2242000015E62F2242000015F62F2242000016062F2242000016162F2242000016262F2242000016362F2242000016462F2242000016562F2242000016662F2242000016762F2242000016862F2242000016962F2242000016A62F2242000016B62F2242000016C62F2242000016D62F2242000016E62F2242000016F62F2242000017062F2242000017162F2242000017262F2242000017362F2242000017462F2242000017562F2242000017662F2242000017762F2242000017862F2242000017962F2242000017A62F2242000017B62F2242000017C62F2242000017D62F2242000017E62F2242000017F62F2242000018062F2242000018162F2242000018262F2242000018362F2242000018462F2242000018562F2242000018662F2242000018762F2242000018862F2242000018962F2242000018A62F2242000018B62F2242000018C62F2242000018D62F2242000018E62F2242000018F62F2242000019062F2242000019162F2242000019262F2242000019362F2242000019462F2242000019562F2242000019662F2242000019762F2242000019862F2242000019962F2242000019A62F2242000019B62F2242000019C62F2242000019D62F2242000019E62F2242000019F62F224200001A062F224200001A162F224200001A262F224200001A362F224200001A462F224200001A562F224200001A662F224200001A762F224200001A862F224200001A962F224200001AA62F224200001AB62F224200001AC62F224200001AD62F224200001AE62F224200001AF62F224200001B062F224200001B162F224200001B262F224200001B362F224200001B462F224200001B562F224200001B662F224200001B762F224200001B862F224200001B962F224200001BA62F224200001BB62F224200001BC62F224200001BD62F224200001BE62F224200001BF62F224200001C062F224200001C162F224200001C262F224200001C362F224200001C462F224200001C562F224200001C662F224200001C762F224200001C862F224200001C962F224200001CA62F224200001CB62F224200001CC62F224200001CD62F224200001CE62F224200001CF62F224200001D062F224200001D162F224200001D262F224200001D362F224200001D462F224200001D562F224200001D662F224200001D762F224200001D862F224200001D962F224200001DA62F224200001DB62F224200001DC62F224200001DD62F224200001DE62F224200001DF62F224200001E062F224200001E162F224200001E262F224200001E362F224200001E462F224200001E562F224200001E662F224200001E762F224200001E862F224200001E962F224200001EA62F224200001EB62F224200001EC62F224200001ED62F224200001EE62F224200001EF62F224200001F062F224200001F162F224200001F262F224200001F362F224200001F462F224200001F562F224200001F662F224200001F762F224200001F862F224200001F962F224200001FA62F224200001FB62F224200001FC62F224200001FD62F224200001FE62F224200001FF62F2242000020062F2242000020162F2242000020262F2242000020362F2242000020462F2242000020562F2242000020662F2242000020762F2242000020862F2242000020962F2242000020A62F2242000020B62F2242000020C62F2242000020D62F2242000020E62F2242000020F62F2242000021062F2242000021162F2242000021262F2242000021362F2242000021462F2242000021562F2242000021662F2242000021762F2242000021862F2242000021962F2242000021A62F2242000021B62F2242000021C62F2242000021D62F2242000021E62F2242000021F62F2242000022062F2242000022162F2242000022262F2242000022362F2242000022462F2242000022562F2242000022662F2242000022762F2242000022862F2242000022962F2242000022A62F2242000022B62F2242000022C62F2242000022D62F2242000022E62F2242000022F62F2242000023062F2242000023162F2242000023262F2242000023362F2242000023462F2242000023562F2242000023662F2242000023762F2242000023862F2242000023962F2242000023A62F2242000023B62F2242000023C62F2242000023D62F2242000023E62F2242000023F62F2242000024062F2242000024162F2242000024262F2242000024362F2242000024462F2242000024562F2242000024662F2242000024762F2242000024862F2242000024962F2242000024A62F2242000024B62F2242000024C62F2242000024D62F2242000024E62F2242000024F62F2242000025062F2242000025162F2242000025262F2242000025362F2242000025462F2242000025562F2242000025662F2242000025762F2242000025862F2242000025962F2242000025A62F2242000025B62F2242000025C62F2242000025D62F2242000025E62F2242000025F62F2242000026062F2242000026162F2242000026262F2242000026362F2242000026462F2242000026562F2242000026662F2242000026762F2242000026862F2242000026962F2242000026A62F2242000026B62F2242000026C62F2242000026D62F2242000026E62F2242000026F62F2242000027062F2242000027162F2242000027262F2242000027362F2242000027462F2242000027562F2242000027662F2242000027762F2242000027862F2242000027962F2242000027A62F2242000027B62F2242000027C62F2242000027D62F2242000027E62F2242000027F62F2242000028062F2242000028162F2242000028262F2242000028362F2242000028462F2242000028562F2242000028662F2242000028762F2242000028862F2242000028962F2242000028A62F2242000028B62F2242000028C62F2242000028D62F2242000028E62F2242000028F62F2242000029062F2242000029162F2242000029262F2242000029362F2242000029462F2242000029562F2242000029662F2242000029762F2242000029862F2242000029962F2242000029A62F2242000029B62F2242000029C62F2242000029D62F2242000029E62F2242000029F62F224200002A062F224200002A162F224200002A262F224200002A362F224200002A462F224200002A562F224200002A662F224200002A762F224200002A862F224200002A962F224200002AA62F224200002AB62F224200002AC62F224200002AD62F224200002AE62F224200002AF62F224200002B062F224200002B162F224200002B262F224200002B362F224200002B462F224200002B562F224200002B662F224200002B762F224200002B862F224200002B962F224200002BA62F224200002BB62F224200002BC62F224200002BD62F224200002BE62F224200002BF62F224200002C062F224200002C162F224200002C262F224200002C362F224200002C462F224200002C562F224200002C662F224200002C762F224200002C862F224200002C962F224200002CA62F224200002CB62F224200002CC62F224200002CD62F224200002CE62F224200002CF62F224200002D062F224200002D162F224200002D262F224200002D362F224200002D462F224200002D562F224200002D662F224200002D762F224200002D862F224200002D962F224200002DA62F224200002DB62F224200002DC62F224200002DD62F224200002DE62F224200002DF62F224200002E062F224200002E162F224200002E262F224200002E362F224200002E462F224200002E562F224200002E662F224200002E762F224200002E862F224200002E962F224200002EA62F224200002EB62F224200002EC62F224200002ED62F224200002EE62F224200002EF62F224200002F062F224200002F162F224200002F262F224200002F362F224200002F462F224200002F562F224200002F662F224200002F762F224200002F862F224200002F962F224200002FA62F224200002FB62F224200002FC62F224200002FD62F224200002FE62F224200002FF62F2242000030062F2242000030162F2242000030262F2242000030362F2242000030462F2242000030562F2242000030662F2242000030762F2242000030862F2242000030962F2242000030A62F2242000030B62F2242000030C62F2242000030D62F2242000030E62F2242000030F62F2242000031062F2242000031162F2242000031262F2242000031362F2242000031462F2242000031562F2242000031662F2242000031762F2242000031862F2242000031962F2242000031A62F2242000031B62F2242000031C62F2242000031D62F2242000031E62F2242000031F62F2242000032062F2242000032162F2242000032262F2242000032362F2242000032462F2242000032562F2242000032662F2242000032762F2242000032862F2242000032962F2242000032A62F2242000032B62F2242000032C62F2242000032D62F2242000032E62F2242000032F62F2242000033062F2242000033162F2242000033262F2242000033362F2242000033462F2242000033562F2242000033662F2242000033762F2242000033862F2242000033962F2242000033A62F2242000033B62F2242000033C62F2242000033D62F2242000033E62F2242000033F62F2242000034062F2242000034162F2242000034262F2242000034362F2242000034462F2242000034562F2242000034662F2242000034762F2242000034862F2242000034962F2242000034A62F2242000034B62F2242000034C62F2242000034D62F2242000034E62F2242000034F62F2242000035062F2242000035162F2242000035262F2242000035362F2242000035462F2242000035562F2242000035662F2242000035762F2242000035862F2242000035962F2242000035A62F2242000035B62F2242000035C62F2242000035D62F2242000035E62F2242000035F62F2242000036062F2242000036162F2242000036262F2242000036362F2242000036462F2242000036562F2242000036662F2242000036762F2242000036862F2242000036962F2242000036A62F2242000036B62F2242000036C62F2242000036D62F2242000036E62F2242000036F62F2242000037062F2242000037162F2242000037262F2242000037362F2242000037462F2242000037562F2242000037662F2242000037762F2242000037862F2242000037962F2242000037A62F2242000037B62F2242000037C62F2242000037D62F2242000037E62F2242000037F62F2242000038062F2242000038162F2242000038262F2242000038362F2242000038462F2242000038562F2242000038662F2242000038762F2242000038862F2242000038962F2242000038A62F2242000038B62F2242000038C62F2242000038D62F2242000038E62F2242000038F62F2242000039062F2242000039162F2242000039262F2242000039362F2242000039462F2242000039562F2242000039662F2242000039762F2242000039862F2242000039962F2242000039A62F2242000039B62F2242000039C62F2242000039D62F2242000039E62F2242000039F62F224200003A062F224200003A162F224200003A262F224200003A362F224200003A462F224200003A562F224200003A662F224200003A762F224200003A862F224200003A962F224200003AA62F224200003AB62F224200003AC62F224200003AD62F224200003AE62F224200003AF62F224200003B062F224200003B162F224200003B262F224200003B362F224200003B462F224200003B562F224200003B662F224200003B762F224200003B862F224200003B962F224200003BA62F224200003BB62F224200003BC62F224200003BD62F224200003BE62F224200003BF62F224200003C062F224200003C162F224200003C262F224200003C362F224200003C462F224200003C562F224200003C662F224200003C762F224200003C862F224200003C962F224200003CA62F224200003CB62F224200003CC62F224200003CD62F224200003CE62F224200003CF62F224200003D062F224200003D162F224200003D262F224200003D362F224200003D462F224200003D562F224200003D662F224200003D762F224200003D862F224200003D962F224200003DA62F224200003DB62F224200003DC62F224200003DD62F224200003DE62F224200003DF62F224200003E062F224200003E162F224200003E262F224200003E362F224200003E462F224200003E562F224200003E662F224200003E762F224200003E862F224200003E962F224200003EA62F224200003EB62F224200003EC62F224200003ED62F224200003EE62F224200003EF62F224200003F062F224200003F162F224200003F262F224200003F362F224200003F462F224200003F562F224200003F662F224200003F762F224200003F862F224200003F962F224200003FA62F224200003FB62F224200003FC62F224200003FD62F224200003FE62F224200003FF62F2242000040062F2242000040162F2242000040262F2242000040362F2242000040462F2242000040562F2242000040662F2242000040762F2242000040862F2242000040962F2242000040A62F2242000040B62F2242000040C62F2242000040D62F2242000040E62F2242000040F62F2242000041062F2242000041162F2242000041262F2242000041362F2242000041462F2242000041562F2242000041662F2242000041762F2242000041862F2242000041962F2242000041A62F2242000041B62F2242000041C62F2242000041D62F2242000041E62F2242000041F62F2242000042062F2242000042162F2242000042262F2242000042362F2242000042462F2242000042562F2242000042662F2242000042762F2242000042862F2242000042962F2242000042A62F2242000042B62F2242000042C62F2242000042D62F2242000042E62F2242000042F62F2242000043062F2242000043162F2242000043262F2242000043362F2242000043462F2242000043562F2242000043662F2242000043762F2242000043862F2242000043962F2242000043A62F2242000043B62F2242000043C62F2242000043D62F2242000043E62F2242000043F62F2242000044062F2242000044162F2242000044262F2242000044362F2242000044462F2242000044562F2242000044662F2242000044762F2242000044862F2242000044962F2242000044A62F2242000044B62F2242000044C62F2242000044D62F2242000044E62F2242000044F62F2242000045062F2242000045162F2242000045262F2242000045362F2242000045462F2242000045562F2242000045662F2242000045762F2242000045862F2242000045962F2242000045A62F2242000045B62F2242000045C62F2242000045D62F2242000045E62F2242000045F62F2242000046062F2242000046162F2242000046262F2242000046362F2242000046462F2242000046562F2242000046662F2242000046762F2242000046862F2242000046962F2242000046A62F2242000046B62F2242000046C62F2242000046D62F2242000046E62F2242000046F62F2242000047062F2242000047162F2242000047262F2242000047362F2242000047462F2242000047562F2242000047662F2242000047762F2242000047862F2242000047962F2242000047A62F2242000047B62F2242000047C62F2242000047D62F2242000047E62F2242000047F62F2242000048062F2242000048162F2242000048262F2242000048362F2242000048462F2242000048562F2242000048662F2242000048762F2242000048862F2242000048962F2242000048A62F2242000048B62F2242000048C62F2242000048D62F2242000048E62F2242000048F62F2242000049062F2242000049162F2242000049262F2242000049362F2242000049462F2242000049562F2242000049662F2242000049762F2242000049862F2242000049962F2242000049A62F2242000049B62F2242000049C62F2242000049D62F2242000049E62F2242000049F62F224200004A062F224200004A162F224200004A262F224200004A362F224200004A462F224200004A562F224200004A662F224200004A762F224200004A862F224200004A962F224200004AA62F224200004AB62F224200004AC62F224200004AD62F224200004AE62F224200004AF62F224200004B062F224200004B162F224200004B262F224200004B362F224200004B462F224200004B562F224200004B662F224200004B762F224200004B862F224200004B962F224200004BA62F224200004BB62F224200004BC62F224200004BD62F224200004BE62F224200004BF62F224200004C062F224200004C162F224200004C262F224200004C362F224200004C462F224200004C562F224200004C662F224200004C762F224200004C862F224200004C962F224200004CA62F224200004CB62F224200004CC62F224200004CD62F224200004CE62F224200004CF62F224200004D062F224200004D162F224200004D262F224200004D362F224200004D462F224200004D562F224200004D662F224200004D762F224200004D862F224200004D962F224200004DA62F224200004DB62F224200004DC62F224200004DD62F224200004DE62F224200004DF62F224200004E062F224200004E162F224200004E262F224200004E362F224200004E462F224200004E562F224200004E662F224200004E762F224200004E862F224200004E962F224200004EA62F224200004EB62F224200004EC62F224200004ED62F224200004EE62F224200004EF62F224200004F062F224200004F162F224200004F262F224200004F362F224200004F462F224200004F562F224200004F662F224200004F762F224200004F862F224200004F962F224200004FA62F224200004FB62F224200004FC62F224200004FD62F224200004FE62F224200004FF62F2242000050062F2242000050162F2242000050262F2242000050362F2242000050462F2242000050562F2242000050662F2242000050762F2242000050862F2242000050962F2242000050A62F2242000050B62F2242000050C62F2242000050D62F2242000050E62F2242000050F62F2242000051062F2242000051162F2242000051262F2242000051362F2242000051462F2242000051562F2242000051662F2242000051762F2242000051862F2242000051962F2242000051A62F2242000051B62F2242000051C62F2242000051D62F2242000051E62F2242000051F62F2242000052062F2242000052162F2242000052262F2242000052362F2242000052462F2242000052562F2242000052662F2242000052762F2242000052862F2242000052962F2242000052A62F2242000052B62F2242000052C62F2242000052D62F2242000052E62F2242000052F62F2242000053062F2242000053162F2242000053262F2242000053362F2242000053462F2242000053562F2242000053662F2242000053762F2242000053862F2242000053962F2242000053A62F2242000053B62F2242000053C62F2242000053D62F2242000053E62F2242000053F62F2242000054062F2242000054162F2242000054262F2242000054362F2242000054462F2242000054562F2242000054662F2242000054762F2242000054862F2242000054962F2242000054A62F2242000054B62F2242000054C62F2242000054D62F2242000054E62F2242000054F62F2242000055062F2242000055162F2242000055262F2242000055362F2242000055462F2242000055562F2242000055662F2242000055762F2242000055862F2242000055962F2242000055A62F2242000055B62F2242000055C62F2242000055D62F2242000055E62F2242000055F62F2242000056062F2242000056162F2242000056262F2242000056362F2242000056462F2242000056562F2242000056662F2242000056762F2242000056862F2242000056962F2242000056A62F2242000056B62F2242000056C62F2242000056D62F2242000056E62F2242000056F62F2242000057062F2242000057162F2242000057262F2242000057362F2242000057462F2242000057562F2242000057662F2242000057762F2242000057862F2242000057962F2242000057A62F2242000057B62F2242000057C62F2242000057D62F2242000057E62F2242000057F62F2242000058062F2242000058162F2242000058262F2242000058362F2242000058462F2242000058562F2242000058662F2242000058762F2242000058862F2242000058962F2242000058A62F2242000058B62F2242000058C62F2242000058D62F2242000058E62F2242000058F62F2242000059062F2242000059162F2242000059262F2242000059362F2242000059462F2242000059562F2242000059662F2242000059762F2242000059862F2242000059962F2242000059A62F2242000059B62F2242000059C62F2242000059D62F2242000059E62F2242000059F62F224200005A062F224200005A162F224200005A262F224200005A362F224200005A462F224200005A562F224200005A662F224200005A762F224200005A862F224200005A962F224200005AA62F224200005AB62F224200005AC62F224200005AD62F224200005AE62F224200005AF62F224200005B062F224200005B162F224200005B262F224200005B362F224200005B462F224200005B562F224200005B662F224200005B762F224200005B862F224200005B962F224200005BA62F224200005BB62F224200005BC62F224200005BD62F224200005BE62F224200005BF62F224200005C062F224200005C162F224200005C262F224200005C362F224200005C462F224200005C562F224200005C662F224200005C762F224200005C862F224200005C962F224200005CA62F224200005CB62F224200005CC62F224200005CD62F224200005CE62F224200005CF62F224200005D062F224200005D162F224200005D262F224200005D362F224200005D462F224200005D562F224200005D662F224200005D762F224200005D862F224200005D962F224200005DA62F224200005DB62F224200005DC62F224200005DD62F224200005DE62F224200005DF62F224200005E062F224200005E162F224200005E262F224200005E362F224200005E462F224200005E562F224200005E662F224200005E762F224200005E862F224200005E962F224200005EA62F224200005EB62F224200005EC62F224200005ED62F224200005EE62F224200005EF62F224200005F062F224200005F162F224200005F262F224200005F362F224200005F462F224200005F562F224200005F662F224200005F762F224200005F862F224200005F962F224200005FA62F224200005FB62F224200005FC62F224200005FD62F224200005FE62F224200005FF62F2242000060062F2242000060162F2242000060262F2242000060362F2242000060462F2242000060562F2242000060662F2242000060762F2242000060862F2242000060962F2242000060A62F2242000060B62F2242000060C62F2242000060D62F2242000060E62F2242000060F62F2242000061062F2242000061162F2242000061262F2242000061362F2242000061462F2242000061562F2242000061662F2242000061762F2242000061862F2242000061962F2242000061A62F2242000061B62F2242000061C62F2242000061D62F2242000061E62F2242000061F62F2242000062062F2242000062162F2242000062262F2242000062362F2242000062462F2242000062562F2242000062662F2242000062762F2242000062862F2242000062962F2242000062A62F2242000062B62F2242000062C62F2242000062D62F2242000062E62F2242000062F62F2242000063062F2242000063162F2242000063262F2242000063362F2242000063462F2242000063562F2242000063662F2242000063762F2242000063862F2242000063962F2242000063A62F2242000063B62F2242000063C62F2242000063D62F2242000063E62F2242000063F62F2242000064062F2242000064162F2242000064262F2242000064362F2242000064462F2242000064562F2242000064662F2242000064762F2242000064862F2242000064962F2242000064A62F2242000064B62F2242000064C62F2242000064D62F2242000064E62F2242000064F62F2242000065062F2242000065162F2242000065262F2242000065362F2242000065462F2242000065562F2242000065662F2242000065762F2242000065862F2242000065962F2242000065A62F2242000065B62F2242000065C62F2242000065D62F2242000065E62F2242000065F62F2242000066062F2242000066162F2242000066262F2242000066362F2242000066462F2242000066562F2242000066662F2242000066762F2242000066862F2242000066962F2242000066A62F2242000066B62F2242000066C62F2242000066D62F2242000066E62F2242000066F62F2242000067062F2242000067162F2242000067262F2242000067362F2242000067462F2242000067562F2242000067662F2242000067762F2242000067862F2242000067962F2242000067A62F2242000067B62F2242000067C62F2242000067D62F2242000067E62F2242000067F62F2242000068062F2242000068162F2242000068262F2242000068362F2242000068462F2242000068562F2242000068662F2242000068762F2242000068862F2242000068962F2242000068A62F2242000068B62F2242000068C62F2242000068D62F2242000068E62F2242000068F62F2242000069062F2242000069162F2242000069262F2242000069362F2242000069462F2242000069562F2242000069662F2242000069762F2242000069862F2242000069962F2242000069A62F2242000069B62F2242000069C62F2242000069D62F2242000069E62F2242000069F62F224200006A062F224200006A162F224200006A262F224200006A362F224200006A462F224200006A562F224200006A662F224200006A762F224200006A862F224200006A962F224200006AA62F224200006AB62F224200006AC62F224200006AD62F224200006AE62F224200006AF62F224200006B062F224200006B162F224200006B262F224200006B362F224200006B462F224200006B562F224200006B662F224200006B762F224200006B862F224200006B962F224200006BA62F224200006BB62F224200006BC62F224200006BD62F224200006BE62F224200006BF62F224200006C062F224200006C162F224200006C262F224200006C362F224200006C462F224200006C562F224200006C662F224200006C762F224200006C862F224200006C962F224200006CA62F224200006CB62F224200006CC62F224200006CD62F224200006CE62F224200006CF62F224200006D062F224200006D162F224200006D262F224200006D362F224200006D462F224200006D562F224200006D662F224200006D762F224200006D862F224200006D962F224200006DA62F224200006DB62F224200006DC62F224200006DD62F224200006DE62F224200006DF62F224200006E062F224200006E162F224200006E262F224200006E362F224200006E462F224200006E562F224200006E662F224200006E762F224200006E862F224200006E962F224200006EA62F224200006EB62F224200006EC62F224200006ED62F224200006EE62F224200006EF62F224200006F062F224200006F162F224200006F262F224200006F362F224200006F462F224200006F562F224200006F662F224200006F762F224200006F862F224200006F962F224200006FA62F224200006FB62F224200006FC62F224200006FD62F224200006FE62F224200006FF62F2242000070062F2242000070162F2242000070262F2242000070362F2242000070462F2242000070562F2242000070662F2242000070762F2242000070862F2242000070962F2242000070A62F2242000070B62F2242000070C62F2242000070D62F2242000070E62F2242000070F62F2242000071062F2242000071162F2242000071262F2242000071362F2242000071462F2242000071562F2242000071662F2242000071762F2242000071862F2242000071962F2242000071A62F2242000071B62F2242000071C62F2242000071D62F2242000071E62F2242000071F62F2242000072062F2242000072162F2242000072262F2242000072362F2242000072462F2242000072562F2242000072662F2242000072762F2242000072862F2242000072962F2242000072A62F2242000072B62F2242000072C62F2242000072D62F2242000072E62F2242000072F62F2242000073062F2242000073162F2242000073262F2242000073362F2242000073462F2242000073562F2242000073662F2242000073762F2242000073862F2242000073962F2242000073A62F2242000073B62F2242000073C62F2242000073D62F2242000073E62F2242000073F62F2242000074062F2242000074162F2242000074262F2242000074362F2242000074462F2242000074562F2242000074662F2242000074762F2242000074862F2242000074962F2242000074A62F2242000074B62F2242000074C62F2242000074D62F2242000074E62F2242000074F62F2242000075062F2242000075162F2242000075262F2242000075362F2242000075462F2242000075562F2242000075662F2242000075762F2242000075862F2242000075962F2242000075A62F2242000075B62F2242000075C62F2242000075D62F2242000075E62F2242000075F62F2242000076062F2242000076162F2242000076262F2242000076362F2242000076462F2242000076562F2242000076662F2242000076762F2242000076862F2242000076962F2242000076A62F2242000076B62F2242000076C62F2242000076D62F2242000076E62F2242000076F62F2242000077062F2242000077162F2242000077262F2242000077362F2242000077462F2242000077562F2242000077662F2242000077762F2242000077862F2242000077962F2242000077A62F2242000077B62F2242000077C62F2242000077D62F2242000077E62F2242000077F62F2242000078062F2242000078162F2242000078262F2242000078362F2242000078462F2242000078562F2242000078662F2242000078762F2242000078862F2242000078962F2242000078A62F2242000078B62F2242000078C62F2242000078D62F2242000078E62F2242000078F62F2242000079062F2242000079162F2242000079262F2242000079362F2242000079462F2242000079562F2242000079662F2242000079762F2242000079862F2242000079962F2242000079A62F2242000079B62F2242000079C62F2242000079D62F2242000079E62F2242000079F62F224200007A062F224200007A162F224200007A262F224200007A362F224200007A462F224200007A562F224200007A662F224200007A762F224200007A862F224200007A962F224200007AA62F224200007AB62F224200007AC62F224200007AD62F224200007AE62F224200007AF62F224200007B062F224200007B162F224200007B262F224200007B362F224200007B462F224200007B562F224200007B662F224200007B762F224200007B862F224200007B962F224200007BA62F224200007BB62F224200007BC62F224200007BD62F224200007BE62F224200007BF62F224200007C062F224200007C162F224200007C262F224200007C362F224200007C462F224200007C562F224200007C662F224200007C762F224200007C862F224200007C962F224200007CA62F224200007CB62F224200007CC62F224200007CD62F224200007CE62F224200007CF62F224200007D062F224200007D162F224200007D262F224200007D362F224200007D462F224200007D562F224200007D662F224200007D762F224200007D862F224200007D962F224200007DA62F224200007DB62F224200007DC62F224200007DD62F224200007DE62F224200007DF62F224200007E062F224200007E162F224200007E262F224200007E362F224200007E462F224200007E562F224200007E662F224200007E762F224200007E862F224200007E962F224200007EA62F224200007EB62F224200007EC62F224200007ED62F224200007EE62F224200007EF62F224200007F062F224200007F162F224200007F262F224200007F362F224200007F462F224200007F562F224200007F662F224200007F762F224200007F862F224200007F962F224200007FA62F224200007FB62F224200007FC62F224200007FD62F224200007FE62F224200007FF62F2242000080062F2242000080162F2242000080262F2242000080362F2242000080462F2242000080562F2242000080662F2242000080762F2242000080862F2242000080962F2242000080A62F2242000080B62F2242000080C62F2242000080D62F2242000080E62F2242000080F62F2242000081062F2242000081162F2242000081262F2242000081362F2242000081462F2242000081562F2242000081662F2242000081762F2242000081862F2242000081962F2242000081A62F2242000081B62F2242000081C62F2242000081D62F2242000081E62F2242000081F62F2242000082062F2242000082162F2242000082262F2242000082362F2242000082462F2242000082562F2242000082662F2242000082762F2242000082862F2242000082962F2242000082A62F2242000082B62F2242000082C62F2242000082D62F2242000082E62F2242000082F62F2242000083062F2242000083162F2242000083262F2242000083362F2242000083462F2242000083562F2242000083662F2242000083762F2242000083862F2242000083962F2242000083A62F2242000083B62F2242000083C62F2242000083D62F2242000083E62F2242000083F62F2242000084062F2242000084162F2242000084262F2242000084362F2242000084462F2242000084562F2242000084662F2242000084762F2242000084862F2242000084962F2242000084A62F2242000084B62F2242000084C62F2242000084D62F2242000084E62F2242000084F62F2242000085062F2242000085162F2242000085262F2242000085362F2242000085462F2242000085562F2242000085662F2242000085762F2242000085862F2242000085962F2242000085A62F2242000085B62F2242000085C62F2242000085D62F2242000085E62F2242000085F62F2242000086062F2242000086162F2242000086262F2242000086362F2242000086462F2242000086562F2242000086662F2242000086762F2242000086862F2242000086962F2242000086A62F2242000086B62F2242000086C62F2242000086D62F2242000086E62F2242000086F62F2242000087062F2242000087162F2242000087262F2242000087362F2242000087462F2242000087562F2242000087662F2242000087762F2242000087862F2242000087962F2242000087A62F2242000087B62F2242000087C62F2242000087D62F2242000087E62F2242000087F62F2242000088062F2242000088162F2242000088262F2242000088362F2242000088462F2242000088562F2242000088662F2242000088762F2242000088862F2242000088962F2242000088A62F2242000088B62F2242000088C62F2242000088D62F2242000088E62F2242000088F62F2242000089062F2242000089162F2242000089262F2242000089362F2242000089462F2242000089562F2242000089662F2242000089762F2242000089862F2242000089962F2242000089A62F2242000089B62F2242000089C62F2242000089D62F2242000089E62F2242000089F62F224200008A062F224200008A162F224200008A262F224200008A362F224200008A462F224200008A562F224200008A662F224200008A762F224200008A862F224200008A962F224200008AA62F224200008AB62F224200008AC62F224200008AD62F224200008AE62F224200008AF62F224200008B062F224200008B162F224200008B262F224200008B362F224200008B462F224200008B562F224200008B662F224200008B762F224200008B862F224200008B962F224200008BA62F224200008BB62F224200008BC62F224200008BD62F224200008BE62F224200008BF62F224200008C062F224200008C162F224200008C262F224200008C362F224200008C462F224200008C562F224200008C662F224200008C762F224200008C862F224200008C962F224200008CA62F224200008CB62F224200008CC62F224200008CD62F224200008CE62F224200008CF62F224200008D062F224200008D162F224200008D262F224200008D362F224200008D462F224200008D562F224200008D662F224200008D762F224200008D862F224200008D962F224200008DA62F224200008DB62F224200008DC62F224200008DD62F224200008DE62F224200008DF62F224200008E062F224200008E162F224200008E262F224200008E362F224200008E462F224200008E562F224200008E662F224200008E762F224200008E862F224200008E962F224200008EA62F224200008EB62F224200008EC62F224200008ED62F224200008EE62F224200008EF62F224200008F062F224200008F162F224200008F262F224200008F362F224200008F462F224200008F562F224200008F662F224200008F762F224200008F862F224200008F962F224200008FA62F224200008FB62F224200008FC62F224200008FD62F224200008FE62F224200008FF62F2242000090062F2242000090162F2242000090262F2242000090362F2242000090462F2242000090562F2242000090662F2242000090762F2242000090862F2242000090962F2242000090A62F2242000090B62F2242000090C62F2242000090D62F2242000090E62F2242000090F62F2242000091062F2242000091162F2242000091262F2242000091362F2242000091462F2242000091562F2242000091662F2242000091762F2242000091862F2242000091962F2242000091A62F2242000091B62F2242000091C62F2242000091D62F2242000091E62F2242000091F62F22420849200092062F2242000092162F2242000092262F28465242000092362F2242000092462F2242000092562F2242000092662F2242000092762F2242000092862F2242000092962F2242000092A62F2242000092B62F2242000092C62F2242000092D62F2242000092E62F2242000092F62F2242000093062F2242000093162F2242000093262F2242000093362F2242000093462F2242000093562F2242000093662F2242000093762F2242000093862F2242000093962F2242000093A62F2242000093B62F2242000093C62F2242000093D62F2242000093E62F2242000093F62F2242000094062F2242000094162F2242000094262F2242000094362F2242000094462F2242000094562F2242000094662F2242000094762F2242000094862F2242000094962F2242000094A62F2242000094B62F2242000094C62F2242000094D62F2242000094E62F2242000094F62F2242000095062F2242000095162F2242000095262F2242000095362F2242000095462F2242000095562F2242000095662F2242000095762F2242000095862F2242000095962F2242000095A62F2242000095B62F2242000095C62F2242000095D62F2242000095E62F2242000095F62F2242000096062F2242000096162F2242000096262F2242000096362F2242000096462F2242000096562F2242000096662F2242000096762F2242000096862F2242000096962F2242000096A62F2242000096B62F2242000096C62F2242000096D62F2242000096E62F2242000096F62F2242000097062F2242000097162F2242000097262F2242000097362F2242000097462F2242000097562F2242000097662F2242000097762F2242000097862F2242000097962F2242000097A62F2242000097B62F2242000097C62F2242000097D62F2242000097E62F2242000097F62F2242000098062F2242000098162F2242000098262F2242000098362F2242000098462F2242000098562F2242000098662F2242000098762F2242000098862F2242000098962F2242000098A62F2242000098B62F2242000098C62F2242000098D62F2242000098E62F2242000098F62F2242000099062F2242000099162F2242000099262F2242000099362F2242000099462F2242000099562F2242000099662F2242000099762F2242000099862F2242000099962F2242000099A62F2242000099B62F2242000099C62F2242000099D62F2242000099E62F2242000099F62F224200009A062F224200009A162F224200009A262F224200009A362F224200009A462F224200009A562F224200009A662F224200009A762F224200009A862F224200009A962F224200009AA62F224200009AB62F224200009AC62F224200009AD62F224200009AE62F224200009AF62F224200009B062F224200009B162F224200009B262F224200009B362F224200009B462F224200009B562F224200009B662F224200009B762F224200009B862F224200009B962F224200009BA62F224200009BB62F224200009BC62F224200009BD62F224200009BE62F224200009BF62F224200009C062F224200009C162F224200009C262F224200009C3000D0002001600090002002A00040001000000000300075A'O;
+
+/* test whether a message with chnked length determinant is parsed */
+testcase TC_chunked_len() runs on test_CT {
+ f_init();
+ TCP.send(ts_AS(g_tcp_conn_id, c_chunked));
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ setverdict(pass);
+}
+
+/* test whether a message with chunked length determinant is parsed if each byte is received separately */
+testcase TC_chunked_len_bytewise() runs on test_CT {
+ f_init();
+ tcp_send_segmented(c_chunked, 100, 0.05);
+ f_sabp_exp(tr_SABP_Write(?, ?));
+ setverdict(pass);
+}
+
+control {
+ execute( TC_1byte_len() );
+ execute( TC_1byte_len_bytewise() );
+ execute( TC_1byte_len_chained() );
+ execute( TC_2byte_len() );
+ execute( TC_2byte_len_bytewise() );
+ execute( TC_2byte_len_chained() );
+ execute( TC_2byte_len_chained_bytewise() );
+ execute( TC_chunked_len() );
+ execute( TC_chunked_len_bytewise() );
+}
+
+
+}
diff --git a/cbc/gen_links.sh b/cbc/gen_links.sh
index 010d24c..9b8187b 100755
--- a/cbc/gen_links.sh
+++ b/cbc/gen_links.sh
@@ -25,19 +25,19 @@ DIR=$BASEDIR/titan.TestPorts.TELNETasp/src
FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn"
gen_links $DIR $FILES
-DIR=$BASEDIR/titan.ProtocolModules.BSSMAP_v11.2.0/src
+DIR=$BASEDIR/titan.ProtocolModules.BSSMAP/src
FILES="BSSAP_Types.ttcn"
gen_links $DIR $FILES
DIR=../library/sabp
-FILES="SABP_CommonDataTypes.asn SABP_Constants.asn SABP_Containers.asn SABP_IEs.asn SABP_PDU_Contents.asn
-SABP_PDU_Descriptions.asn SABP_Types.ttcn "
+FILES="SABP_CommonDataTypes.asn SABP_Constants.asn SABP_Containers.asn SABP_IEs.asn SABP_PDU_Contents.asn SABP_PDU_Descriptions.asn SABP_Types.ttcn SABP_EncDec.cc SABP_Templates.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+="CBSP_Types.ttcn CBSP_Templates.ttcn "
FILES+="CBSP_CodecPort.ttcn CBSP_CodecPort_CtrlFunct.ttcn CBSP_CodecPort_CtrlFunctdef.cc CBSP_Adapter.ttcn "
+FILES+="SABP_CodecPort.ttcn SABP_CodecPort_CtrlFunct.ttcn SABP_CodecPort_CtrlFunctDef.cc SABP_Adapter.ttcn "
gen_links $DIR $FILES
ignore_pp_results
diff --git a/cbc/regen_makefile.sh b/cbc/regen_makefile.sh
index c1e8590..8a1fb80 100755
--- a/cbc/regen_makefile.sh
+++ b/cbc/regen_makefile.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-FILES="*.ttcn TCCConversion.cc TCCInterface.cc TCCEncoding.cc IPL4asp_PT.cc IPL4asp_discovery.cc TELNETasp_PT.cc Native_FunctionDefs.cc SCTPasp_PT.cc CBSP_CodecPort_CtrlFunctdef.cc "
+FILES="*.ttcn TCCConversion.cc TCCInterface.cc TCCEncoding.cc IPL4asp_PT.cc IPL4asp_discovery.cc TELNETasp_PT.cc Native_FunctionDefs.cc SCTPasp_PT.cc CBSP_CodecPort_CtrlFunctdef.cc SABP_EncDec.cc SABP_CodecPort_CtrlFunctDef.cc "
#FILES+="*.ttcnpp "
FILES+="*.asn"
diff --git a/ccid/CCID_Tests.cfg b/ccid/CCID_Tests.cfg
new file mode 100644
index 0000000..de427b2
--- /dev/null
+++ b/ccid/CCID_Tests.cfg
@@ -0,0 +1,20 @@
+[ORDERED_INCLUDE]
+# Common configuration, shared between test suites
+"../Common.cfg"
+# testsuite specific configuration, not expected to change
+"./CCID_Tests.default"
+
+# Local configuration below
+
+[LOGGING]
+ConsoleMask := ERROR | WARNING | TESTCASE | USER;
+
+[TESTPORT_PARAMETERS]
+
+[MODULE_PARAMETERS]
+
+
+[MAIN_CONTROLLER]
+
+[EXECUTE]
+CCID_Tests.control
diff --git a/ccid/CCID_Tests.default b/ccid/CCID_Tests.default
new file mode 100644
index 0000000..f441d67
--- /dev/null
+++ b/ccid/CCID_Tests.default
@@ -0,0 +1,8 @@
+[LOGGING]
+mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC;
+
+[TESTPORT_PARAMETERS]
+
+[MODULE_PARAMETERS]
+
+[EXECUTE]
diff --git a/ccid/CCID_Tests.ttcn b/ccid/CCID_Tests.ttcn
new file mode 100644
index 0000000..f7423cd
--- /dev/null
+++ b/ccid/CCID_Tests.ttcn
@@ -0,0 +1,621 @@
+module CCID_Tests {
+
+/* TTCN-3 tests for USB CCID (Chip Card Interface Device)
+ *
+ * (C) 2018-2019 by Harald Welte <laforge@gnumonks.org>
+ */
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from Misc_Helpers all;
+
+import from USB_PortType all;
+import from USB_Component all;
+
+import from CCID_Types all;
+import from CCID_Templates all;
+import from CCID_Emulation all;
+
+modulepar {
+ USB_Device_Match mp_usb_dev_match := { vid_pid := { vid := '1d50'H, pid := '6141'H } };
+ integer mp_use_slot_count := 8;
+ boolean mp_test_power_off := true;
+ boolean mp_quirk_resetpar_returns_slotsts := false;
+}
+/* global test component; manages CCID device */
+type component Test_CT {
+ var CCID_Emulation_CT vc_CCID;
+ port USB_PT USB;
+ var Slot_CT vc_SLOT[NR_SLOTS];
+};
+
+/* per-slot test component; manages one slot */
+type component Slot_CT {
+ var uint8_t g_slot_nr;
+ port CCID_SLOT_PT CCID;
+ timer g_Tguard := 120.0;
+};
+
+/* maximum number of slots we are supporting in the test suite */
+private const integer NR_SLOTS := 16;
+
+/***********************************************************************
+ * helper infrastructure
+ ***********************************************************************/
+
+const octetstring c_UICC_SELECT_MF := '00a40004023f00'O;
+const octetstring c_SIM_SELECT_MF := 'a0a40004023f00'O;
+
+/* Table 7 of ISO7816-3 */
+type enumerated ISO7816_Fi {
+ ISO7816_FI_372_4MHz ('0000'B),
+ ISO7816_FI_372_5MHz ('0001'B),
+ ISO7816_FI_558_6MHz ('0010'B),
+ ISO7816_FI_744_8MHz ('0011'B),
+ ISO7816_FI_1116_12MHz ('0100'B),
+ ISO7816_FI_1488_16MHz ('0101'B),
+ ISO7816_FI_1860_20MHz ('0110'B),
+
+ ISO7816_FI_512_5MHz ('1001'B),
+ ISO7816_FI_768_7MHz ('1010'B),
+ ISO7816_FI_1024_10MHz ('1011'B),
+ ISO7816_FI_1536_15MHz ('1100'B),
+ ISO7816_FI_2048_20MHz ('1101'B)
+};
+
+/* Table 8 of ISO7816-3 */
+type enumerated ISO7816_Di {
+ ISO7816_DI_1 ('0001'B),
+ ISO7816_DI_2 ('0010'B),
+ ISO7816_DI_4 ('0011'B),
+ ISO7816_DI_8 ('0100'B),
+ ISO7816_DI_16 ('0101'B),
+ ISO7816_DI_32 ('0110'B),
+ ISO7816_DI_64 ('0111'B),
+
+ ISO7816_DI_12 ('1000'B),
+ ISO7816_DI_20 ('1001'B)
+}
+
+private template (value) CCID_ProtocolData ts_ProtoDataT0(ISO7816_Fi fi, ISO7816_Di di,
+ uint8_t guard_time := 0,
+ uint8_t wait_int := 0) := {
+ T0 := {
+ Findex := enum2int(fi),
+ Dindex := enum2int(di),
+
+ bRFU := '000000'B,
+ inv_convention := false,
+ bRFU2 := '0'B,
+
+ bGuardTimeT0 := guard_time,
+ bWaitingIntegerT0 := wait_int,
+ bClockStop := STOPPING_NOT_ALLOWED
+ }
+};
+
+type function void_fn() runs on Slot_CT;
+
+/* altstep running on the per-slot test component */
+private altstep as_Tguard() runs on Slot_CT {
+ [] g_Tguard.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
+ }
+}
+
+private altstep as_ccid_any() runs on Slot_CT {
+ var CCID_PDU pdu;
+ [] CCID.receive(CCID_PDU:?) -> value pdu {
+ setverdict(fail, "Received unexpected CCID ", pdu);
+ self.stop;
+ }
+ [] CCID.receive {
+ setverdict(fail, "Received unexpected non-CCID");
+ self.stop;
+ }
+}
+
+/* first function inside Slot_CT; wait for CCID_EVENT_UP + call testcase-specific function */
+private function f_handler_init(void_fn fn, integer slot_nr) runs on Slot_CT {
+ g_slot_nr := slot_nr;
+ CCID.receive(CCID_Emulation_Event:{up_down:=CCID_EVENT_UP});
+ g_Tguard.start;
+ activate(as_Tguard());
+
+ fn.apply();
+}
+
+/* start a single slot handler */
+private function f_start_handler(void_fn fn, integer slot_nr) runs on Test_CT
+{
+ var Slot_CT vc;
+
+ vc_SLOT[slot_nr] := Slot_CT.create("Slot" & int2str(slot_nr));
+ connect(vc_SLOT[slot_nr]:CCID, vc_CCID:SLOT[slot_nr]);
+ vc_SLOT[slot_nr].start(f_handler_init(fn, slot_nr));
+}
+
+private function f_wait_handlers_complete() runs on Test_CT {
+ var integer i;
+
+ for (i := 0; i < NR_SLOTS; i := i+1) {
+ if (vc_SLOT[i] != null) {
+ vc_SLOT[i].done;
+ }
+ }
+ setverdict(pass);
+}
+
+private function f_start_and_wait() runs on Test_CT {
+ /* start CCID_Emulation last, it will trigger all the per-slot components */
+ var CCID_Emulation_Params cep := { usb_dev_match := mp_usb_dev_match };
+ vc_CCID.start(CCID_Emulation.main(cep));
+ f_wait_handlers_complete();
+}
+
+private function f_init() runs on Test_CT {
+ var integer i;
+ vc_CCID := CCID_Emulation_CT.create("CCID");
+ map(vc_CCID:USB, system:USB);
+ for (i := 0; i < NR_SLOTS; i := i+1) {
+ vc_SLOT[i] := null;
+ }
+}
+
+
+/* transceive a CCID command (send 'tx' on OUT; expect 'rx' on IN) */
+private function f_ccid_xceive(template (value) CCID_PDU tx, template (present) CCID_PDU exp_rx)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ tx.hdr.bSlot := g_slot_nr;
+ exp_rx.hdr.bSlot := g_slot_nr;
+
+ CCID.send(tx);
+ alt {
+ [] CCID.receive(exp_rx) -> value pdu {
+ return pdu;
+ }
+ [] as_ccid_any();
+ }
+ return pdu;
+}
+
+private template (present) CCID_Header_IN tr_inact :=
+ tr_CCID_HeaderIN_OK(icc_status := (CCID_ICC_STATUS_PRES_INACT, CCID_ICC_STATUS_NO_ICC));
+
+private template (present) CCID_Header_IN tr_act :=
+ tr_CCID_HeaderIN_OK(icc_status := CCID_ICC_STATUS_PRES_ACT);
+
+/* Send IccPowerOn on OUT; expect DataBlock in retunr */
+private function f_ccid_power_on(CCID_PowerSelect psel := CCID_PWRSEL_AUTO,
+ template (present) CCID_Header_IN hdr_in := tr_act)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ pdu := f_ccid_xceive(ts_CCID_IccPowerOn(g_slot_nr, psel),
+ tr_CCID_DataBlock(g_slot_nr, hdr_in := hdr_in) );
+ return pdu;
+}
+
+/* Send IccPowerOn on OUT; expect SlotStatus in return */
+private function f_ccid_power_off(template (present) CCID_Header_IN hdr_in := tr_inact)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ pdu := f_ccid_xceive(ts_CCID_IccPowerOff(g_slot_nr),
+ tr_CCID_SlotStatus(slot := g_slot_nr, hdr_in := hdr_in) );
+ return pdu;
+}
+
+/* Send IccClockCommand on OUT; expect SlotStatus in return */
+private function f_ccid_clock_cmd(CCID_ClockCommand cmd,
+ template (present) CCID_Header_IN hdr_in := tr_CCID_HeaderIN_OK)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ pdu := f_ccid_xceive(ts_CCID_ClockCommand(g_slot_nr, cmd),
+ tr_CCID_SlotStatus(slot := g_slot_nr, hdr_in := hdr_in));
+ return pdu;
+}
+
+/* Send XfrBlock on OUT; expect DataBlock in return */
+private function f_ccid_xfr(octetstring tx, template octetstring rx) runs on Slot_CT return octetstring {
+ var CCID_PDU pdu;
+
+ pdu := f_ccid_xceive(ts_CCID_XfrBlock(g_slot_nr, tx, 0),
+ tr_CCID_DataBlock(g_slot_nr, ?, ?, rx) );
+ return pdu.u.DataBlock.abData;
+}
+
+/* Send SetParameters on OUT; expect Parameters on IN */
+private function f_ccid_set_par(template (value) CCID_ProtocolData par,
+ template (present) CCID_Header_IN hdr_in := tr_CCID_HeaderIN_OK)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ pdu := f_ccid_xceive(ts_CCID_SetParameters(g_slot_nr, par),
+ tr_CCID_Parameters(g_slot_nr, hdr_in := hdr_in));
+ return pdu;
+}
+
+/* Send GetParameters on OUT; expect Parameters on IN */
+private function f_ccid_get_par(template (present) CCID_Header_IN hdr_in := tr_CCID_HeaderIN_OK)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ pdu := f_ccid_xceive(ts_CCID_GetParameters(g_slot_nr),
+ tr_CCID_Parameters(g_slot_nr, hdr_in := hdr_in));
+ return pdu;
+}
+
+/* Send ResetParameters on OUT; expect Parameters on IN */
+private function f_ccid_reset_par(template (present) CCID_Header_IN hdr_in := tr_CCID_HeaderIN_OK)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ /* [at least] Omnikey seems to have failed to follow the CCID spec here :/ */
+ if (mp_quirk_resetpar_returns_slotsts) {
+ pdu := f_ccid_xceive(ts_CCID_ResetParameters(g_slot_nr),
+ tr_CCID_SlotStatus(g_slot_nr, hdr_in := hdr_in));
+ } else {
+ pdu := f_ccid_xceive(ts_CCID_ResetParameters(g_slot_nr),
+ tr_CCID_Parameters(g_slot_nr, hdr_in := hdr_in));
+ }
+ return pdu;
+}
+
+/* Send Escape on OUT; expect Escape on IN */
+private function f_ccid_escape(template (value) octetstring data,
+ template (present) CCID_Header_IN hdr_in := tr_CCID_HeaderIN_OK)
+runs on Slot_CT return CCID_PDU {
+ var CCID_PDU pdu;
+
+ pdu := f_ccid_xceive(ts_CCID_Escape(g_slot_nr, data),
+ tr_CCID_EscapeIN(g_slot_nr, hdr_in := hdr_in));
+ return pdu;
+}
+
+
+/***********************************************************************
+ * Test behavior regarding valid situations
+ ***********************************************************************/
+
+/* request 100 times the slot status */
+private function f_TC_getstatus() runs on Slot_CT
+{
+ var integer i;
+ for (i := 0; i < 100; i := i+1) {
+ CCID.send(ts_CCID_GetSlotStatus(g_slot_nr));
+ /* it would be fun to simply send more requests here, but the CCID
+ * spec doesn't permit more than one unresponded command [per slot] */
+ alt {
+ [] CCID.receive(tr_CCID_SlotStatus(g_slot_nr));
+ [] as_ccid_any();
+ }
+ }
+ setverdict(pass);
+}
+testcase TC_get_status() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_getstatus), i);
+ }
+
+ f_start_and_wait();
+}
+
+
+private function f_TC_power_on() runs on Slot_CT
+{
+ f_ccid_power_on();
+}
+testcase TC_power_on() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_power_on), i);
+ }
+
+ f_start_and_wait();
+}
+
+private function f_TC_power_off() runs on Slot_CT
+{
+ f_ccid_power_on();
+ f_ccid_power_off();
+}
+testcase TC_power_off() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_power_off), i);
+ }
+
+ f_start_and_wait();
+}
+
+
+/* repeat IccPowerOn on slot that's already active (next warm reset ATR) */
+private function f_TC_power_on_warm() runs on Slot_CT
+{
+ var integer i;
+
+ /* initial power on */
+ f_ccid_power_on();
+
+ /* additional power on */
+ for (i := 0; i < 20; i := i+1) {
+ f_ccid_power_on();
+ }
+}
+testcase TC_power_on_warm() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_power_on_warm), i);
+ }
+
+ f_start_and_wait();
+}
+
+/* transfer 1000 APDUs by issuing SELECT MF */
+private function f_TC_select_mf() runs on Slot_CT
+{
+ var integer i;
+ f_ccid_power_on();
+ f_ccid_set_par(ts_ProtoDataT0(ISO7816_FI_512_5MHz, ISO7816_DI_32));
+ for (i := 0; i < 1000; i := i+1) {
+ f_ccid_xfr(c_UICC_SELECT_MF, '??'O);
+ }
+}
+testcase TC_select_mf() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_select_mf), i);
+ }
+
+ f_start_and_wait();
+}
+
+/* GetParametrs: verify contents */
+private function f_TC_get_params() runs on Slot_CT
+{
+ var CCID_PDU par;
+ f_ccid_power_on();
+ par := f_ccid_get_par();
+ log(par);
+}
+testcase TC_get_params() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_get_params), i);
+ }
+ f_start_and_wait();
+}
+
+/* SetParameters: verify change */
+private function f_TC_set_params() runs on Slot_CT
+{
+ var CCID_PDU par;
+ f_ccid_power_on();
+
+ /* get current parameters */
+ par := f_ccid_get_par();
+
+ /* modify some of them */
+ var CCID_ProtocolData pd := par.u.Parameters.abProtocolData;
+ pd.T0.bGuardTimeT0 := 23;
+ pd.T0.bWaitingIntegerT0 := 42;
+ par := f_ccid_set_par(pd);
+
+ /* check if modifications were applied */
+ var template (present) CCID_ProtocolData tr_PD := {
+ T0 := {
+ Findex := ?,
+ Dindex := ?,
+ bRFU := ?,
+ inv_convention := ?,
+ bRFU2 := ?,
+ bGuardTimeT0 := 23,
+ bWaitingIntegerT0 := 42,
+ bClockStop := ?
+ }
+ };
+ if (match(par.u.Parameters.abProtocolData, tr_PD)) {
+ setverdict(pass);
+ } else {
+ setverdict(fail, "SetParameters didn't change GuardTime/WaitingInteger");
+ }
+}
+testcase TC_set_params() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_set_params), i);
+ }
+ f_start_and_wait();
+}
+
+/* ResetParameters: verify change */
+private function f_TC_reset_params() runs on Slot_CT
+{
+ var CCID_PDU par;
+
+ f_TC_set_params();
+ par := f_ccid_reset_par();
+ if (mp_quirk_resetpar_returns_slotsts) {
+ par := f_ccid_get_par();
+ }
+ if (par.u.Parameters.abProtocolData.T0.bGuardTimeT0 == 23 or
+ par.u.Parameters.abProtocolData.T0.bWaitingIntegerT0 == 42) {
+ setverdict(fail, "ResetParameters didn't reset properly");
+ }
+}
+testcase TC_reset_params() runs on Test_CT
+{
+ var integer i;
+
+ f_init();
+
+ for (i := 0; i < mp_use_slot_count; i := i+1) {
+ f_start_handler(refers(f_TC_reset_params), i);
+ }
+ f_start_and_wait();
+}
+
+
+
+/* TODO */
+/* IccPowerOn: verify that CCID resets all parameters to default values */
+/* IccPowerOn: verify that bPowerSelect has no effect in active state */
+/* XfrBlock: length corner cases (Lc/Le max, ...) */
+/* IccClock: verify clock has stopped/restarted */
+/* Abort for command that already terminated */
+/* Abort for command that's still processing */
+
+
+/***********************************************************************
+ * Test behavior regarding invalid situations
+ ***********************************************************************/
+
+/* message for invalid slot number (more than we have) */
+private function f_TC_inval_slot() runs on Slot_CT {
+ CCID.send(ts_CCID_GetSlotStatus(g_slot_nr));
+ alt {
+ [] CCID.receive(tr_CCID_SlotStatus(hdr_in := tr_CCID_HeaderIN_FAIL(CCID_ERR_SLOT_NOT_EXIST))) {
+ setverdict(pass);
+ }
+ [] CCID.receive(tr_CCID_SlotStatus) {
+ setverdict(fail, "Unexpected SlotStatus");
+ mtc.stop;
+ }
+ [] as_ccid_any();
+ }
+}
+testcase TC_inval_slot() runs on Test_CT {
+ f_init();
+ f_start_handler(refers(f_TC_inval_slot), 15);
+ f_start_and_wait();
+}
+
+/* switch card off and then XfrBlock. Requires reader with IccPowerOff support */
+private function f_TC_xfer_off() runs on Slot_CT {
+ f_ccid_power_off();
+ CCID.send(ts_CCID_XfrBlock(g_slot_nr, c_SIM_SELECT_MF, 0));
+ alt {
+ [] CCID.receive(tr_CCID_DataBlock(slot:=g_slot_nr, hdr_in:=tr_CCID_HeaderIN_FAIL)) {
+ setverdict(pass);
+ }
+ [] CCID.receive(tr_CCID_DataBlock(slot:=g_slot_nr, hdr_in:=tr_CCID_HeaderIN_OK)) {
+ setverdict(fail, "Expected XfrBlock to fail");
+ mtc.stop;
+ }
+ [] as_ccid_any();
+ }
+}
+testcase TC_xfer_off() runs on Test_CT {
+ f_init();
+ f_start_handler(refers(f_TC_xfer_off), 0);
+ f_start_and_wait();
+}
+
+
+/* unsupported Mechanical */
+private function f_TC_unsupp_mechanical() runs on Slot_CT {
+ CCID.send(ts_CCID_Mechanical(g_slot_nr, CCID_MECH_FN_EJECT_CARD));
+ alt {
+ [] CCID.receive(tr_CCID_SlotStatus(hdr_in := tr_CCID_HeaderIN_FAIL(CCID_ERR_CMD_NOT_SUPPORTED))) {
+ setverdict(pass);
+ }
+ [] as_ccid_any();
+ }
+}
+testcase TC_unsupp_mechanical() runs on Test_CT {
+ f_init();
+ f_start_handler(refers(f_TC_unsupp_mechanical), 0);
+ f_start_and_wait();
+}
+
+/* unsupported Secure */
+private function f_TC_unsupp_secure() runs on Slot_CT {
+ CCID.send(ts_CCID_Secure(g_slot_nr, 0, 0, ''O));
+ alt {
+ [] CCID.receive(tr_CCID_DataBlock(hdr_in := tr_CCID_HeaderIN_FAIL(CCID_ERR_CMD_NOT_SUPPORTED))) {
+ setverdict(pass);
+ }
+ [] as_ccid_any();
+ }
+}
+testcase TC_unsupp_secure() runs on Test_CT {
+ f_init();
+ f_start_handler(refers(f_TC_unsupp_secure), 0);
+ f_start_and_wait();
+}
+
+
+/* TODO */
+/* truncated message */
+/* IccPowerOn with wrong voltage (> 0x04) */
+/* XfrBlock on empty slot */
+/* GetParameters on empty slot */
+/* SetParameters for bProtocolNum > 0x01 */
+/* SetParameters: invalid parameters */
+/* set unsupported frequency */
+/* set unsupported clock rate */
+/* XfrBlock: bWI in T=0? */
+/* XfrBlock: wLevelParameter not matching level? */
+/* Abort for command that was not even submitted yet*/
+/* dwMaxCCIDMessageLength */
+
+
+control {
+ /* valid transactions */
+ execute( TC_get_status() );
+ execute( TC_power_on() );
+ execute( TC_power_on_warm() );
+ if (mp_test_power_off) {
+ execute( TC_power_off() );
+ }
+ execute( TC_select_mf() );
+ execute( TC_get_params() );
+ execute( TC_set_params() );
+ execute( TC_reset_params() );
+
+ /* error handling */
+ execute( TC_inval_slot() );
+ if (mp_test_power_off) {
+ execute( TC_xfer_off() );
+ }
+ execute( TC_unsupp_mechanical() );
+ execute( TC_unsupp_secure() );
+}
+
+
+
+
+}
diff --git a/ccid/gen_links.sh b/ccid/gen_links.sh
new file mode 100755
index 0000000..e53954b
--- /dev/null
+++ b/ccid/gen_links.sh
@@ -0,0 +1,21 @@
+#!/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"
+#gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.USB/src
+FILES="USB_PT.cc USB_PT.hh USB_PortType.ttcn USB_PortTypes.ttcn USB_Templates.ttcn USB_Types.ttcn USB_Component.ttcn "
+FILES+="CCID_Types.ttcn CCID_Templates.ttcn CCID_Emulation.ttcn "
+gen_links $DIR $FILES
+
+DIR=../library
+FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn "
+FILES+="Native_Functions.ttcn Native_FunctionDefs.cc "
+gen_links $DIR $FILES
+
+ignore_pp_results
diff --git a/ccid/regen_makefile.sh b/ccid/regen_makefile.sh
new file mode 100755
index 0000000..215d9c6
--- /dev/null
+++ b/ccid/regen_makefile.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+FILES="*.ttcn USB_PT.cc Native_FunctionDefs.cc "
+
+../regen-makefile.sh CCID_Tests.ttcn $FILES
+
+#sed -i -e 's/^LINUX_LIBS = -lxml2/LINUX_LIBS = -lxml2 -lusb/' Makefile
+sed -i -e '/^LINUX_LIBS/ s/$/ `pkg-config --libs libusb-1.0`/' Makefile
+sed -i -e '/^CPPFLAGS/ s/$/ `pkg-config --cflags libusb-1.0`/' Makefile
diff --git a/compare-results.py b/compare-results.py
new file mode 100755
index 0000000..ff5004e
--- /dev/null
+++ b/compare-results.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+# Copyright 2018 sysmocom - s.f.m.c. GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import argparse
+import re
+
+doc = "Compare TTCN3 test run results with expected results by junit logs."
+
+# The nicest would be to use an XML library, but I don't want to introduce dependencies on the build slaves.
+re_testcase = re.compile(r'''<testcase classname=['"]([^'"]+)['"].* name=['"]([^'"]+)['"].*>''')
+re_testcase_end = re.compile(r'''(</testcase>|<testcase [^>]*/>)''')
+re_failure = re.compile(r'''(<failure\b|<error\b)''')
+
+RED = "\033[1;31m"
+GREEN = "\033[1;32m"
+YELLOW = "\033[1;33m"
+BLUE = "\033[1;34m"
+NOCOLOR = "\033[0;m"
+
+def col(color, text):
+ return color + text + NOCOLOR
+
+RESULT_PASS = col(GREEN, 'pass')
+RESULT_FAIL = col(RED, 'pass->FAIL')
+RESULT_SKIP = col(BLUE, 'skip')
+RESULT_XFAIL = col(YELLOW, 'xfail')
+RESULT_FIXED = col(GREEN, 'xfail->PASS')
+RESULT_NEW_PASS = col(GREEN, 'NEW: PASS')
+RESULT_NEW_FAIL = col(RED, 'NEW: FAIL')
+
+RESULTS = (
+ RESULT_FAIL,
+ RESULT_NEW_FAIL,
+ RESULT_XFAIL,
+ RESULT_FIXED,
+ RESULT_PASS,
+ RESULT_NEW_PASS,
+ RESULT_SKIP,
+ )
+
+def count(counter, name, result):
+ v = counter.get(result) or 0
+ v += 1
+ counter[result] = v
+ if result != RESULT_SKIP:
+ print('%s %s' % (result, name))
+
+def compare_one(name, expect, result, counter):
+ if result is None:
+ count(counter, name, RESULT_SKIP)
+ elif result == RESULT_PASS:
+ if expect == RESULT_PASS:
+ count(counter, name, RESULT_PASS)
+ elif expect == RESULT_FAIL:
+ count(counter, name, RESULT_FIXED)
+ elif expect is None:
+ count(counter, name, RESULT_NEW_PASS)
+ elif result == RESULT_FAIL:
+ if expect == RESULT_PASS:
+ count(counter, name, RESULT_FAIL)
+ elif expect == RESULT_FAIL:
+ count(counter, name, RESULT_XFAIL)
+ elif expect is None:
+ count(counter, name, RESULT_NEW_FAIL)
+
+def compare(cmdline, f_expected, f_current):
+ expected_list = parse_results(f_expected)
+ current_list = parse_results(f_current)
+
+ expected_dict = dict(expected_list)
+ current_dict = dict(current_list)
+
+ counter = {}
+
+ for expected_name, expected_result in expected_list:
+ compare_one(expected_name, expected_result, current_dict.get(expected_name), counter)
+
+ # Also count new tests
+ for current_name, current_result in current_list:
+ if current_name in expected_dict:
+ continue
+ compare_one(current_name, None, current_result, counter)
+
+
+ print('\nSummary:')
+ for r in RESULTS:
+ v = counter.get(r)
+ if not v:
+ continue
+ print(' %s: %d' % (r, v))
+ print('\n')
+
+def parse_results(f):
+ tests = []
+ name = None
+ result = None
+ for line in f:
+ m = re_testcase.search(line)
+ if m:
+ class_name, test_name = m.groups()
+ name = '%s.%s' % (class_name, test_name)
+
+ m = re_failure.search(line)
+ if m:
+ result = RESULT_FAIL
+
+ m = re_testcase_end.search(line)
+ if m:
+ if not name:
+ continue
+ if result is None:
+ result = RESULT_PASS
+ tests.append((name, result))
+
+ name = None
+ result = None
+
+ return tests
+
+def main(cmdline):
+ with open(cmdline.expected_results, 'r') as f_expected:
+ with open(cmdline.current_results, 'r') as f_current:
+ print('\nComparing expected results %r against results in %r\n--------------------'
+ % (cmdline.expected_results, cmdline.current_results))
+ compare(cmdline, f_expected, f_current)
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=doc)
+ parser.add_argument('expected_results', metavar='expected.junit-xml',
+ help='junit XML file listing the expected test results.')
+ parser.add_argument('current_results', metavar='current.junit-xml',
+ help='junit XML file listing the current test results.')
+
+ cmdline = parser.parse_args()
+ main(cmdline)
diff --git a/compare-results.sh b/compare-results.sh
deleted file mode 100755
index 6037174..0000000
--- a/compare-results.sh
+++ /dev/null
@@ -1,213 +0,0 @@
-#!/usr/bin/env bash
-expected_file="$1"
-results_file="$2"
-
-# Copyright 2018 sysmocom - s.f.m.c. GmbH
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-usage() {
- echo "
-Usage:
-
- $(basename "$0") expected_results.junit-log current_results.junit-log [--allow-* [...]]
-
-Return 0 if the expected results match the current results exactly.
-
- --allow-skip Allow runnning less tests than are listed in the expected file.
- Default is to return failure on any skipped tests.
- --allow-new Allow more test results than found in the expected file.
- Default is to return failure on any unknown tests.
- --allow-xpass If a test was expected to fail but passed, return success.
- Default is to return failure on any mismatch.
-"
-}
-
-if [ ! -f "$expected_file" ]; then
- usage
- echo "Expected file not found: '$expected_file'"
- exit 1
-fi
-
-if [ ! -f "$results_file" ]; then
- usage
- echo "Current results file not found: '$results_file'"
- exit 1
-fi
-
-shift
-shift
-
-allow_xpass=0
-allow_skip=0
-allow_new=0
-
-while test -n "$1"; do
- arg="$1"
- if [ "x$arg" = "x--allow-xpass" ]; then
- allow_xpass=1
- elif [ "x$arg" = "x--allow-skip" ]; then
- allow_skip=1
- elif [ "x$arg" = "x--allow-new" ]; then
- allow_new=1
- else
- usage
- echo "Unknown argument: '$arg'"
- exit 1
- fi
- shift
-done
-
-echo "Comparing expected results $expected_file against results in $results_file
---------------------"
-
-parse_testcase() {
- line="$1"
- suite_name="$(echo "$line" | sed 's,.*classname='"'"'\([^'"'"']*\)'"'"'.*,\1,')"
- test_name="$(echo "$line" | sed 's,.*\<name='"'"'\([^'"'"']*\)'"'"'.*,\1,')"
- if [ -n "$(echo "$line" | grep '/>$')" ]; then
- test_result="pass"
- else
- test_result="FAIL"
- fi
-}
-
-pass=0
-xfail=0
-more_failures=0
-more_successes=0
-skipped=0
-new=0
-
-while read line; do
- parse_testcase "$line"
- exp_suite_name="$suite_name"
- exp_test_name="$test_name"
- exp_test_result="$test_result"
- matched="0"
-
- while read line; do
- parse_testcase "$line"
- if [ "x$exp_suite_name" != "x$suite_name" ]; then
- continue
- fi
- if [ "x$exp_test_name" != "x$test_name" ]; then
- continue
- fi
-
- if [ "x$exp_test_result" = "x$test_result" ]; then
- if [ "x$exp_test_result" = "xFAIL" ]; then
- exp_test_result="xfail"
- (( xfail += 1 ))
- else
- (( pass += 1 ))
- fi
- echo "$exp_test_result $suite_name.$test_name"
- else
- if [ "x$exp_test_result" = "xFAIL" ]; then
- exp_test_result="xfail"
- fi
- echo "$exp_test_result->$test_result $suite_name.$test_name"
- if [ "x$test_result" = "xFAIL" ]; then
- (( more_failures += 1 ))
- else
- (( more_successes += 1 ))
- fi
- fi
- matched="1"
- break
- done <<< "$(grep "<testcase.*$exp_test_name" "$results_file")"
-
- if [ "x$matched" = "x0" ]; then
- echo "skipped $exp_suite_name.$exp_test_name"
- (( skipped += 1 ))
- fi
-
-done <<< "$(grep "<testcase" "$expected_file")"
-
-# Also catch all new tests that aren't covered in the expected results
-while read line; do
- parse_testcase "$line"
- got_suite_name="$suite_name"
- got_test_name="$test_name"
- got_test_result="$test_result"
- matched="0"
-
- while read line; do
- parse_testcase "$line"
- if [ "x$got_suite_name" != "x$suite_name" ]; then
- continue
- fi
- if [ "x$got_test_name" != "x$test_name" ]; then
- continue
- fi
-
- matched="1"
- break
- done <<< "$(grep "<testcase.*$test_name" "$expected_file")"
-
- if [ "x$matched" = "x0" ]; then
- echo "NEW-$got_test_result $got_suite_name.$got_test_name"
- (( new += 1 ))
- fi
-
-done <<< "$(grep "<testcase" "$results_file")"
-
-echo "--------------------"
-overall_verdict=0
-
-ask_update=""
-
-if [ "x$pass" != x0 ]; then
- echo "$pass pass"
-fi
-
-if [ "x$xfail" != x0 ]; then
- echo "$xfail xfail"
-fi
-
-if [ "x$skipped" != x0 ]; then
- echo "$skipped skipped"
- ask_update="$ask_update removed=$skipped"
- if [ "x$allow_skip" = x0 ]; then
- overall_verdict=4
- fi
-fi
-
-if [ "x$new" != x0 ]; then
- echo "$new new"
- ask_update="$ask_update new=$new"
- if [ "x$allow_new" = x0 ]; then
- overall_verdict=3
- fi
-fi
-
-if [ "x$more_successes" != x0 ]; then
- echo "$more_successes pass unexpectedly"
- ask_update="$ask_update xpass=$more_successes"
- if [ "x$allow_xpass" = x0 ]; then
- overall_verdict=2
- fi
-fi
-
-if [ "x$more_failures" != x0 ]; then
- echo "$more_failures FAIL"
- overall_verdict=1
-fi
-
-if [ -n "$ask_update" ]; then
- echo
- echo "(Please update the expected results:$ask_update)"
-fi
-
-exit $overall_verdict
diff --git a/deps/Makefile b/deps/Makefile
index ed265c0..b808dcc 100644
--- a/deps/Makefile
+++ b/deps/Makefile
@@ -13,15 +13,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-ECLIPSEGIT:=https://github.com/eclipse
-ECLIPSEGIT2:=git://git.eclipse.org/gitroot/titan
+ECLIPSEGITHUB:=https://github.com/eclipse
+ECLIPSEGIT2:=https://git.eclipse.org/r/titan
OSMOGITHUB:=https://github.com/osmocom
OSMOGIT:=git://git.osmocom.org
-ECLIPSEGIT_REPOS= titan.Libraries.TCCUsefulFunctions \
+ECLIPSEGITHUB_REPOS= titan.Libraries.TCCUsefulFunctions \
+ titan.ProtocolModules.DNS \
titan.ProtocolModules.ICMP \
titan.ProtocolModules.ICMPv6 \
titan.ProtocolModules.IP \
+ titan.ProtocolModules.JSON_v07_2006 \
titan.ProtocolModules.L2TP \
titan.ProtocolModules.M3UA \
titan.ProtocolModules.SMPP \
@@ -30,13 +32,14 @@ ECLIPSEGIT_REPOS= titan.Libraries.TCCUsefulFunctions \
titan.ProtocolModules.RTP \
titan.ProtocolModules.DIAMETER_ProtocolModule_Generator \
titan.TestPorts.Common_Components.Socket-API \
+ titan.TestPorts.Common_Components.Abstract_Socket \
+ titan.TestPorts.HTTPmsg \
titan.TestPorts.IPL4asp \
titan.TestPorts.LANL2asp \
titan.TestPorts.PCAPasp \
+ titan.TestPorts.PIPEasp \
titan.TestPorts.SIPmsg \
titan.TestPorts.TCPasp \
- titan.TestPorts.TELNETasp \
- titan.TestPorts.UDPasp \
titan.TestPorts.UNIX_DOMAIN_SOCKETasp
ECLIPSEGIT2_REPOS= titan.ProtocolModules.GRE \
@@ -45,76 +48,85 @@ ECLIPSEGIT2_REPOS= titan.ProtocolModules.GRE \
titan.ProtocolModules.SCTP \
titan.ProtocolModules.SUA \
titan.ProtocolModules.SDP \
- titan.TestPorts.GPIO \
titan.ProtocolModules.BSSAPP_v7.3.0 \
titan.ProtocolModules.BSSGP_v13.0.0 \
titan.ProtocolModules.GTP_v13.5.0 \
titan.ProtocolModules.GTPv2_v13.7.0 \
titan.ProtocolModules.ISUP_Q.762 \
+ titan.ProtocolModules.LLC_v7.1.0 \
titan.ProtocolModules.MobileL3_v13.4.0 \
titan.ProtocolModules.NAS_EPS_15.2.0.1 \
titan.ProtocolModules.NS_v7.3.0 \
- titan.ProtocolModules.SNDCP_v7.0.0 \
- titan.ProtocolEmulations.SCCP
+ titan.ProtocolModules.SGsAP_13.2.0 \
+ titan.ProtocolModules.SNDCP_v7.0.0
OSMOGITHUB_REPOS= titan.TestPorts.SCTPasp \
- titan.ProtocolModules.LLC_v7.1.0 \
- titan.ProtocolModules.SGsAP_13.2.0 \
titan.TestPorts.MTP3asp \
- titan.ProtocolEmulations.M3UA
+ titan.TestPorts.UDPasp \
+ titan.TestPorts.TELNETasp \
+ titan.ProtocolEmulations.M3UA \
+ titan.ProtocolEmulations.SCCP
OSMOGIT_REPOS= titan.ProtocolModules.MAP \
- titan.ProtocolModules.BSSMAP
+ titan.ProtocolModules.BSSMAP \
+ titan.TestPorts.USB \
+ osmo-uecups
-ALL_REPOS=$(ECLIPSEGIT_REPOS) $(ECLIPSEGIT2_REPOS) $(OSMOGITHUB_REPOS) $(OSMOGIT_REPOS)
+ALL_REPOS=$(ECLIPSEGITHUB_REPOS) $(ECLIPSEGIT2_REPOS) $(OSMOGITHUB_REPOS) $(OSMOGIT_REPOS)
# Tag names from 'git-describe --tags'; if not available, a commit hash may be used instead.
# In order to keep local changes in the repository of a dependency, set its commit to the
# name of a local branch here (e.g. 'master').
-titan.Libraries.TCCUsefulFunctions_commit= R.30.A
-titan.ProtocolEmulations.M3UA_commit= R.2.A-2-g742cf02
-titan.ProtocolEmulations.SCCP_commit= R.7.A-2-g724c83f
-titan.ProtocolModules.BSSAPP_v7.3.0_commit= R.2.A
-titan.ProtocolModules.BSSGP_v13.0.0_commit= R.2.A
+titan.Libraries.TCCUsefulFunctions_commit= R.35.B-6-gb3687da
+titan.ProtocolEmulations.M3UA_commit= f086e78d74defa044d864f17adaad9433fedc961
+titan.ProtocolEmulations.SCCP_commit= R.7.A-9-g9e70fba
+titan.ProtocolModules.BSSAPP_v7.3.0_commit= R.2.A-4-g20cfaf8
+titan.ProtocolModules.BSSGP_v13.0.0_commit= R.2.A-6-gc447f28
titan.ProtocolModules.BSSMAP_commit= master
-titan.ProtocolModules.GRE_commit= R.2.A
-titan.ProtocolModules.GTP_v13.5.0_commit= R.2.A
-titan.ProtocolModules.GTPv2_v13.7.0_commit= R.2.A
-titan.ProtocolModules.ICMP_commit= R.2.A
-titan.ProtocolModules.ICMPv6_commit= R.2.A
-titan.ProtocolModules.IP_commit= R.10.B-1-g99d0ec9
-titan.ProtocolModules.ISUP_Q.762_commit= R.8.A
-titan.ProtocolModules.L2TP_commit= R.2.A
-titan.ProtocolModules.LLC_v7.1.0_commit= 2a3c09fbf7bae22f802aa88689800f38a1f3732d
+titan.ProtocolModules.DNS_commit= R.7.B
+titan.ProtocolModules.GRE_commit= R.2.A-5-g654c446
+titan.ProtocolModules.GTP_v13.5.0_commit= R.2.A-5-ge120ace
+titan.ProtocolModules.GTPv2_v13.7.0_commit= R.2.A-5-g85cb124
+titan.ProtocolModules.ICMP_commit= e49d9fb9f7de637b4bf4803dc6b6e911a8661640
+titan.ProtocolModules.ICMPv6_commit= 46f4d9b6e1e3c794294a92588401a81e4881dd27
+titan.ProtocolModules.IP_commit= 1be86705f39ae38f3c04b2109806ee20d25e91d0
+titan.ProtocolModules.ISUP_Q.762_commit= R.8.A-5-g42d428b
+titan.ProtocolModules.JSON_v07_2006_commit= R.1.A
+titan.ProtocolModules.L2TP_commit= 17e76d3662bd0bb815158e8a9de1ec413f21b530
+titan.ProtocolModules.LLC_v7.1.0_commit= 09817f113255d7fb56f1d45d3dd629a093d9248d
titan.ProtocolModules.MAP_commit= R.2.A-1-g79c6a3d
-titan.ProtocolModules.M2PA_commit= R.2.A
-titan.ProtocolModules.M3UA_commit= R.2.A
-titan.ProtocolModules.MobileL3_v13.4.0_commit= R.2.A
-titan.ProtocolModules.NAS_EPS_15.2.0.1_commit= 2ba853c7d197f7f39d97b76fca4726a7143fb4ad
-titan.ProtocolModules.NS_v7.3.0_commit= R.2.A
-titan.ProtocolModules.RTP_commit= R.5.A
+titan.ProtocolModules.M2PA_commit= R.2.A-5-ga75b589
+titan.ProtocolModules.M3UA_commit= c496d298876fed55c2b730278b7ee77982555563
+titan.ProtocolModules.MobileL3_v13.4.0_commit= badbad680df216b3211260d56b14734eeb2c9028
+titan.ProtocolModules.NAS_EPS_15.2.0.1_commit= R.1.A-2-g2ba853c
+titan.ProtocolModules.NS_v7.3.0_commit= R.2.A-6-gf73f195
+titan.ProtocolModules.RTP_commit= R.5.A-4-g83ee83a
titan.ProtocolModules.DIAMETER_ProtocolModule_Generator_commit= ffd939595a08da1b8c8176aaa1f8578bfe02a912
-titan.ProtocolModules.ROSE_commit= R.1.C
-titan.ProtocolModules.SCTP_commit= R.2.A
-titan.ProtocolModules.SGsAP_13.2.0_commit= 520dc48dd41ee15c9fd77e71d2ea7a05c58770b9
-titan.ProtocolModules.SDP_commit= R.14.A
-titan.ProtocolModules.SMPP_commit= R.2.A-2-gb7aee69
-titan.ProtocolModules.SNDCP_v7.0.0_commit= R.2.A
-titan.ProtocolModules.SUA_commit= R.5.A
-titan.ProtocolModules.TCP_commit= R.3.A
-titan.ProtocolModules.UDP_commit= R.4.A
-titan.TestPorts.Common_Components.Socket-API_commit= R.6.A
-titan.TestPorts.GPIO_commit= R.3.A
-titan.TestPorts.IPL4asp_commit= R.29.A
-titan.TestPorts.LANL2asp_commit= R.8.B
+titan.ProtocolModules.ROSE_commit= R.1.C-5-g0f6774c
+titan.ProtocolModules.SCTP_commit= R.2.A-5-g556ef3f
+titan.ProtocolModules.SGsAP_13.2.0_commit= R.1.B-3-g5ccaeab
+titan.ProtocolModules.SDP_commit= R.14.A-6-g7f00ea0
+titan.ProtocolModules.SMPP_commit= R.2.A-5-gf2c9017
+titan.ProtocolModules.SNDCP_v7.0.0_commit= R.2.A-5-gd0f0ce6
+titan.ProtocolModules.SUA_commit= R.5.A-5-gcf1137a
+titan.ProtocolModules.TCP_commit= R.3.A-5-g39e5f45
+titan.ProtocolModules.UDP_commit= R.4.A-5-geea8aa3
+titan.TestPorts.Common_Components.Socket-API_commit= R.6.A-6-gf4380d0
+titan.TestPorts.Common_Components.Abstract_Socket_commit= R.9.B-4-gbd41994
+titan.TestPorts.HTTPmsg_commit= R.9.B-4-g9a0dfde
+titan.TestPorts.IPL4asp_commit= R.30.E
+titan.TestPorts.LANL2asp_commit= R.8.C-3-gb07c265
titan.TestPorts.MTP3asp_commit= 1cecdad6f3641a5f19b3833703bff6e5005eff11
-titan.TestPorts.PCAPasp_commit= R.7.A
+titan.TestPorts.PCAPasp_commit= R.8.A-3-g9ad320f
+titan.TestPorts.PIPEasp_commit= R.7.D-3-g8b01154
titan.TestPorts.SCTPasp_commit= R.11.A-2-g2faa9cf
titan.TestPorts.SIPmsg_commit= R.15.A-1-ge4f9dd0
-titan.TestPorts.TCPasp_commit= R.9.A
-titan.TestPorts.TELNETasp_commit= R.9.A
-titan.TestPorts.UDPasp_commit= R.8.A
-titan.TestPorts.UNIX_DOMAIN_SOCKETasp_commit= R.2.A-4-gbacd73d
+titan.TestPorts.TCPasp_commit= R.9.A-5-g2c91bc6
+titan.TestPorts.TELNETasp_commit= R.9.A-5-g7a07a97
+titan.TestPorts.UDPasp_commit= c20d77a34f288dd70dd4aaa30e520778876e9336
+titan.TestPorts.UNIX_DOMAIN_SOCKETasp_commit= R.2.A-8-g7ec4fe0
+titan.TestPorts.USB_commit= master
+osmo-uecups_commit= master
all: $(foreach dir,$(ALL_REPOS),$(dir)/update)
clean: $(foreach dir,$(ALL_REPOS),$(dir)/clean)
@@ -158,8 +170,8 @@ else
endif
endef
-$(foreach dir,$(ECLIPSEGIT_REPOS), \
- $(eval $(call GIT_template,$(dir),$(ECLIPSEGIT))))
+$(foreach dir,$(ECLIPSEGITHUB_REPOS), \
+ $(eval $(call GIT_template,$(dir),$(ECLIPSEGITHUB))))
$(foreach dir,$(ECLIPSEGIT2_REPOS), \
$(eval $(call GIT_template,$(dir),$(ECLIPSEGIT2))))
diff --git a/ggsn_tests/GGSN_Tests.ttcn b/ggsn_tests/GGSN_Tests.ttcn
index 44dba4a..be0e565 100644
--- a/ggsn_tests/GGSN_Tests.ttcn
+++ b/ggsn_tests/GGSN_Tests.ttcn
@@ -14,6 +14,7 @@ module GGSN_Tests {
import from General_Types all;
import from Osmocom_Types all;
+ import from Misc_Helpers all;
import from IPL4asp_PortType all;
import from IPL4asp_Types all;
import from GTP_CodecPort all;
@@ -64,13 +65,6 @@ module GGSN_Tests {
* The tests expect to be able to send ping packets between any two simulated MS within the same
* address range. This requires IP forwarding to be enabled on the corresponding tun interfaces.
*/
-
- /*
- * Whether ggsn supports "(no) echo-interval" VTY command
- * (osmo-ggsn.git Id2c84165dc59dff495106758146a701ca488834f).
- * This option can be dropped after osmo-ggsn release > 1.4.0 exists.
- */
- boolean m_ggsn_supports_echo_interval := true;
}
type set PdpContext {
@@ -203,9 +197,7 @@ module GGSN_Tests {
f_init_vty();
f_vty_set_gpdu_txseq(use_gtpu_txseq);
- if (m_ggsn_supports_echo_interval) {
- f_vty_enable_echo_interval(g_use_echo);
- }
+ f_vty_enable_echo_interval(g_use_echo);
}
/* Altstep implementing responses to any incoming echo requests */
@@ -218,9 +210,13 @@ module GGSN_Tests {
repeat;
};
[not g_use_echo] GTPC.receive(tr_GTPC_PING(?)) {
- setverdict(fail, "GTP Echo Req rceived but not enabled in VTY");
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ "GTP Echo Req rceived but not enabled in VTY");
+ };
+ [] T_default.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ "pinpong T_default timeout");
};
- [] T_default.timeout { setverdict(fail); };
}
/* 'internet' in DNS encoding */
@@ -1506,8 +1502,6 @@ module GGSN_Tests {
execute(TC_pdp_act2_recovery());
execute(TC_act_deact_retrans_duplicate());
- if (m_ggsn_supports_echo_interval) {
- execute(TC_pdp_act_restart_ctr_echo());
- }
+ execute(TC_pdp_act_restart_ctr_echo());
}
}
diff --git a/ggsn_tests/README.md b/ggsn_tests/README.md
index 288018f..71468d5 100644
--- a/ggsn_tests/README.md
+++ b/ggsn_tests/README.md
@@ -3,6 +3,7 @@
* external interfaces
* Gp: GTP (emulates SGSN)
* Gi: IP (emulates Internet)
+ * VTY
{% dot ggsn_tests.svg
digraph G {
diff --git a/hlr/HLR_EUSE.ttcn b/hlr/HLR_EUSE.ttcn
index ef07ca6..17e4776 100644
--- a/hlr/HLR_EUSE.ttcn
+++ b/hlr/HLR_EUSE.ttcn
@@ -49,8 +49,8 @@ private function f_init(charstring hlr_ip, uint16_t hlr_gsup_port, charstring na
timer T := 10.0;
T.start;
alt {
- [] EUSE.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { repeat; }
- [] EUSE.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { }
+ [] EUSE.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { repeat; }
+ [] EUSE.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) { }
[] T.timeout {
setverdict(fail, "EUSE: Timeout waiting for GSUP IPA Link to come up");
self.stop;
diff --git a/hlr/HLR_Tests.cfg b/hlr/HLR_Tests.cfg
index 7416362..1ab6e87 100644
--- a/hlr/HLR_Tests.cfg
+++ b/hlr/HLR_Tests.cfg
@@ -12,6 +12,7 @@
[MODULE_PARAMETERS]
+HLR_Tests.mp_hlr_supports_dgsm := true
[MAIN_CONTROLLER]
diff --git a/hlr/HLR_Tests.default b/hlr/HLR_Tests.default
index 84d4ff3..2e9aac6 100644
--- a/hlr/HLR_Tests.default
+++ b/hlr/HLR_Tests.default
@@ -11,6 +11,11 @@ mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING; // | DEBUG_ENCDEC;
*.VTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes"
*.VTY.CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT := "yes"
*.VTY.PROMPT1 := "OsmoHLR> "
+*.mDNS_UDP.debugging := "YES"
+*.mDNS_UDP.localPort := "4266"
+*.mDNS_UDP.localIPAddr := "239.192.23.42"
+*.mDNS_UDP.broadcast := "enabled"
+*.mDNS_UDP.reuseAddr := "enabled"
[MODULE_PARAMETERS]
Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoHLR";
diff --git a/hlr/HLR_Tests.ttcn b/hlr/HLR_Tests.ttcn
index f309575..36e28b8 100644
--- a/hlr/HLR_Tests.ttcn
+++ b/hlr/HLR_Tests.ttcn
@@ -31,7 +31,13 @@ import from USSD_Helpers all;
import from Osmocom_VTY_Functions all;
import from TELNETasp_PortType all;
+import from MSLookup_mDNS_Types all;
+import from MSLookup_mDNS_Emulation all;
+import from MSLookup_mDNS_Templates all;
+import from DNS_Helpers all;
+
type component test_CT extends CTRL_Adapter_CT {
+ /* emulated GSUP client (MSC/SGSN) */
var IPA_Emulation_CT vc_IPA;
var IPA_CCM_Parameters ccm_pars;
/* legacy tests without ConnHdlr */
@@ -43,13 +49,30 @@ type component test_CT extends CTRL_Adapter_CT {
port TELNETasp_PT VTY;
+ var MSLookup_mDNS_Emulation_CT vc_MSLookup_mDNS;
+
+ /* emulated GSUP server (second HLR) */
+ var IPA_Emulation_CT vc_IPA_server;
+ var GSUP_Emulation_CT vc_GSUP_server;
+
timer g_Tguard := 10.0;
};
modulepar {
+ /* OsmoHLR */
charstring mp_hlr_ip := "127.0.0.1";
integer mp_hlr_gsup_port := 4222;
integer mp_hlr_ctrl_port := 4259;
+ /* how many auth tuples are expected
+ when IE ts_GSUP_IE_NUM_VECTORS_REQ is absent */
+ integer mp_default_num_auth_tuples := 5;
+
+ /* emulated GSUP server (second HLR) */
+ charstring mp_hlr_ts_ip := "127.0.0.99";
+ integer mp_hlr_ts_port := 4222;
+
+ /* drop after osmo-hlr release > 1.2.0 */
+ boolean mp_hlr_supports_dgsm := true;
};
type record HlrSubscrAud2G {
@@ -77,30 +100,48 @@ type component HLR_ConnHdlr extends GSUP_ConnHdlr {
timer g_Tguard := 10.0;
var HLR_ConnHdlrPars g_pars;
port TELNETasp_PT VTY;
+ port MSLookup_mDNS_PT mDNS;
+
+ /* Pass from test_CT for explicit addressing */
+ var GSUP_Emulation_CT vc_GSUP_server;
+ var GSUP_Emulation_CT vc_GSUP_client;
+ var IPA_CCM_Parameters ccm_pars_client;
}
type record HLR_ConnHdlrPars {
HlrSubscriber sub,
- HLR_ConnHdlrParsUssd ussd optional
+ HLR_ConnHdlrParsUssd ussd optional,
+ octetstring source_name optional
}
type record HLR_ConnHdlrParsUssd {
OCT4 sid
}
-template (value) HLR_ConnHdlrPars t_Pars(hexstring imsi, hexstring msisdn := ''H) := {
+template (value) HLR_ConnHdlrPars t_Pars(hexstring imsi, hexstring msisdn := ''H,
+ template (omit) octetstring source_name := omit) := {
sub := {
imsi := imsi,
msisdn := msisdn,
aud2g := omit,
aud3g := omit
},
- ussd := omit
+ ussd := omit,
+ source_name := source_name
}
+template (value) HLR_ConnHdlrPars t_Pars_via_proxy(hexstring imsi, hexstring msisdn := ''H) :=
+ t_Pars(imsi, msisdn, source_name := char2oct("the-source\n"));
template (value) HLR_ConnHdlrPars t_Pars_sub(HlrSubscriber sub) := {
sub := sub,
- ussd := omit
+ ussd := omit,
+ source_name := omit
+}
+
+template (value) HLR_ConnHdlrPars t_Pars_sub_via_proxy(HlrSubscriber sub) := {
+ sub := sub,
+ ussd := omit,
+ source_name := char2oct("the-source\n")
}
type function void_fn() runs on HLR_ConnHdlr;
@@ -113,6 +154,9 @@ function f_init_vty() runs on test_CT {
map(self:VTY, system:VTY);
f_vty_set_prompts(VTY);
f_vty_transceive(VTY, "enable");
+ if (mp_hlr_supports_dgsm) {
+ f_vty_config(VTY, "mslookup", "no mdns bind");
+ }
}
private altstep as_Tguard() runs on test_CT {
@@ -122,6 +166,7 @@ private altstep as_Tguard() runs on test_CT {
}
}
+/* emulated GSUP client (MSC/SGSN) */
function f_init_gsup(charstring id, boolean legacy) runs on test_CT {
id := id & "-GSUP";
var GsupOps ops := {
@@ -155,8 +200,8 @@ function f_init_gsup(charstring id, boolean legacy) runs on test_CT {
timer T := 10.0;
T.start;
alt {
- [not legacy] GSUP_IPA_EVENT.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)) { }
- [legacy] GSUP.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { }
+ [not legacy] GSUP_IPA_EVENT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { }
+ [legacy] GSUP.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { }
[] T.timeout {
setverdict(fail, "No connection to GSUP Port");
mtc.stop;
@@ -164,7 +209,29 @@ function f_init_gsup(charstring id, boolean legacy) runs on test_CT {
}
}
-function f_init(boolean legacy := true) runs on test_CT {
+/* emulated GSUP server (second HLR) */
+function f_init_gsup_server(charstring id) runs on test_CT {
+ id := id & "-GSUP-server";
+ var GsupOps ops := {
+ create_cb := refers(GSUP_Emulation.ExpectedCreateCallback)
+ }
+
+ vc_GSUP_server := GSUP_Emulation_CT.create(id);
+ vc_IPA_server := IPA_Emulation_CT.create(id & "-IPA");
+
+ connect(vc_GSUP_server:GSUP, vc_IPA_server:IPA_GSUP_PORT);
+ map(vc_IPA_server:IPA_PORT, system:IPA_CODEC_PT);
+
+ vc_GSUP_server.start(GSUP_Emulation.main(ops, id));
+ vc_IPA_server.start(IPA_Emulation.main_server(mp_hlr_ts_ip, mp_hlr_ts_port));
+}
+
+function f_init_mslookup() runs on test_CT {
+ vc_MSLookup_mDNS := MSLookup_mDNS_Emulation_CT.create;
+ vc_MSLookup_mDNS.start(MSLookup_mDNS_Emulation.f_main());
+}
+
+function f_init(boolean legacy := true, boolean gsup_server := false) runs on test_CT {
/* activate default guard timer to ensure all tests eventually terminate */
g_Tguard.start;
@@ -172,19 +239,38 @@ function f_init(boolean legacy := true) runs on test_CT {
f_init_gsup("HLR_Test", legacy);
f_init_vty();
+ f_init_mslookup();
+
+ if (gsup_server) {
+ f_init_gsup_server("HLR_Test");
+ }
f_ipa_ctrl_start(mp_hlr_ip, mp_hlr_ctrl_port);
}
-function f_start_handler(void_fn fn, HLR_ConnHdlrPars pars) runs on test_CT return HLR_ConnHdlr {
+/*! Start HLR_ConnHdlr from testCT in a separate thread.
+ * \param void_fn function to run inside the thread.
+ * \param gsup_server if true, connect the emulated GSUP server ports to the new HLR_ConnHdlr. Then both the emulated
+ * GSUP client (MSC/SGSN) and server (second HLR) are connected. Explicit addressing with "to" and
+ * "from" must be used, i.e. 'GSUP.receive(tr_GSUP_UL_REQ(...)) from vc_GSUP_server'. */
+function f_start_handler(void_fn fn, HLR_ConnHdlrPars pars, boolean gsup_server := false) runs on test_CT
+return HLR_ConnHdlr {
var HLR_ConnHdlr vc_conn;
var charstring id := testcasename();
vc_conn := HLR_ConnHdlr.create(id);
connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
+ connect(vc_conn:mDNS, vc_MSLookup_mDNS:mDNS);
+
+ if (gsup_server) {
+ connect(vc_conn:GSUP, vc_GSUP_server:GSUP_CLIENT);
+ connect(vc_conn:GSUP_PROC, vc_GSUP_server:GSUP_PROC);
+ vc_conn.start(f_handler_init(fn, id, vc_GSUP_server, vc_GSUP, ccm_pars, pars));
+ } else {
+ vc_conn.start(f_handler_init(fn, id, omit, vc_GSUP, ccm_pars, pars));
+ }
- vc_conn.start(f_handler_init(fn, id, pars));
return vc_conn;
}
@@ -195,12 +281,23 @@ private function f_handler_init_vty() runs on HLR_ConnHdlr {
}
/* first function inside ConnHdlr component; sets g_pars + starts function */
-function f_handler_init(void_fn fn, charstring id, template (omit) HLR_ConnHdlrPars pars := omit)
+function f_handler_init(void_fn fn, charstring id,
+ template (omit) GSUP_Emulation_CT vc_GSUP_server_test_ct,
+ GSUP_Emulation_CT vc_GSUP_client_test_ct,
+ IPA_CCM_Parameters ccm_pars_client_test_ct,
+ template (omit) HLR_ConnHdlrPars pars := omit)
runs on HLR_ConnHdlr
{
+ /* Pass from test_CT for explicit addressing */
+ if (isvalue(vc_GSUP_server_test_ct)) {
+ vc_GSUP_server := valueof(vc_GSUP_server_test_ct);
+ }
+ vc_GSUP_client := vc_GSUP_client_test_ct;
+ ccm_pars_client := ccm_pars_client_test_ct;
+
if (isvalue(pars)) {
g_pars := valueof(pars);
- f_create_gsup_expect(hex2str(g_pars.sub.imsi));
+ f_create_gsup_expect_explicit(hex2str(g_pars.sub.imsi), vc_GSUP_client);
}
f_handler_init_vty();
fn.apply();
@@ -293,6 +390,30 @@ function f_gen_subs() runs on test_CT return HlrSubscriberList {
return sl;
}
+function f_gen_3G_subs() runs on test_CT return HlrSubscriberList {
+ var HlrSubscriber sub;
+ var HlrSubscriberList sl := {};
+
+ sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "milenage", false));
+ sl := sl & { sub };
+
+ sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "milenage", true));
+ sl := sl & { sub };
+
+ sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
+ "comp128v1", "milenage", false));
+ sl := sl & { sub };
+
+ sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
+ "comp128v2", "milenage", false));
+ sl := sl & { sub };
+
+ sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
+ "comp128v3", "milenage", false));
+ sl := sl & { sub };
+
+ return sl;
+}
function f_vty_transceive_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
var charstring ret := f_vty_transceive_ret(pt, cmd);
@@ -370,8 +491,10 @@ function f_vty_subscr_show_nomatch(TELNETasp_PT VTY, HlrSubscriber sub, template
***********************************************************************/
/* perform SendAuthInfo for given imsi, return the GSUP response/error */
-function f_perform_SAI(hexstring imsi, template (omit) integer exp_err_cause := omit)
+function f_perform_SAI(hexstring imsi, template (omit) integer exp_err_cause := omit,
+ boolean is_eps := false, template (omit) integer num_auth_tuple := omit)
runs on HLR_ConnHdlr return GSUP_PDU {
+ var template GSUP_PDU sai_msg;
var GSUP_PDU ret;
timer T := 3.0;
var boolean exp_fail := false;
@@ -379,7 +502,18 @@ runs on HLR_ConnHdlr return GSUP_PDU {
exp_fail := true;
}
- GSUP.send(valueof(ts_GSUP_SAI_REQ(imsi)));
+ if (is_eps) {
+ sai_msg := ts_GSUP_SAI_REQ_EPS(imsi);
+ } else {
+ sai_msg := ts_GSUP_SAI_REQ(imsi);
+ }
+ if (not istemplatekind(num_auth_tuple, "omit")) {
+ sai_msg.ies := valueof(sai_msg.ies) & {
+ valueof(ts_GSUP_IE_NUM_VECTORS_REQ(int2oct(valueof(num_auth_tuple), 1)))
+ };
+ }
+ GSUP.send(sai_msg);
+
T.start;
alt {
[exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, exp_err_cause)) -> value ret {
@@ -407,7 +541,9 @@ runs on HLR_ConnHdlr return GSUP_PDU {
}
function f_perform_UL(hexstring imsi, template hexstring msisdn,
- template (omit) integer exp_err_cause := omit)
+ template (omit) integer exp_err_cause := omit,
+ GSUP_CnDomain dom := OSMO_GSUP_CN_DOMAIN_PS,
+ template (omit) octetstring source_name := omit)
runs on HLR_ConnHdlr return GSUP_PDU {
var GSUP_PDU ret;
timer T := 3.0;
@@ -417,30 +553,34 @@ runs on HLR_ConnHdlr return GSUP_PDU {
exp_fail := true;
}
- GSUP.send(valueof(ts_GSUP_UL_REQ(imsi)));
+ GSUP.send(valueof(ts_GSUP_UL_REQ(imsi, dom, source_name := source_name)));
T.start;
alt {
- [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause, destination_name := source_name)) -> value ret {
setverdict(pass);
}
- [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?, destination_name := source_name)) -> value ret {
setverdict(fail, "Unexpected UL ERROR Cause");
+ mtc.stop;
}
- [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi, destination_name := source_name)) -> value ret {
setverdict(fail, "Unexpected UL.res for unknown IMSI");
+ mtc.stop;
}
- [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi)) -> value ret {
+ [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi, destination_name := source_name)) -> value ret {
setverdict(fail, "Unexpected ISD.req in error case");
+ mtc.stop;
}
- [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
+ [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?, destination_name := source_name)) -> value ret {
setverdict(fail, "Unexpected UL ERROR");
+ mtc.stop;
}
- [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn)) -> value ret {
- GSUP.send(ts_GSUP_ISD_RES(imsi));
+ [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn, destination_name := source_name)) -> value ret {
+ GSUP.send(ts_GSUP_ISD_RES(imsi, source_name := source_name));
isd_done := true;
repeat;
}
- [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
+ [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi, destination_name := source_name)) -> value ret {
setverdict(pass);
}
[] GSUP.receive { repeat; }
@@ -452,6 +592,45 @@ runs on HLR_ConnHdlr return GSUP_PDU {
return ret;
}
+/* Perform Location Update with IMSI that is unknown to OsmoHLR. Let it ask for the HLR that knows the IMSI via
+ * mslookup. The TTCN-3 testsuite pretends to be the home HLR, that knows the IMSI. The proxy HLR connects to the
+ * home HLR and forwards GSUP messages, until LU is complete.
+ * Make sure to let a timer run while calling this function (see TC_MSLookup_GSUP_proxy). */
+function f_perform_UL_proxy(hexstring imsi, hexstring msisdn, GSUP_CnDomain dom := OSMO_GSUP_CN_DOMAIN_PS)
+runs on HLR_ConnHdlr {
+ var MSLookup_mDNS mdns_msg;
+ var integer id;
+ var charstring domain := "gsup.hlr." & hex2str(imsi) & ".imsi.mdns.osmocom.org";
+ var octetstring destination_name := char2oct(ccm_pars_client.ser_nr) & '00'O; /* TS-MSC IPA name */
+
+ /* Testing the HLR as proxy. The MSC asking the proxy and the home HLR are both enacted by TTCN3 (TS).
+ * MSC=vc_GSUP_client <---> osmo-hlr as proxy <---> vc_GSUP_server=home HLR
+ * GSUP.send(..) to vc_GSUP_client ---> osmo-hlr ---> GSUP.receive(..) from vc_GSUP_server
+ * GSUP.receive(..) from vc_GSUP_client <--- osmo-hlr <--- GSUP.send(..) to vc_GSUP_server */
+
+ /* [GSUP] TS-MSC => HLR proxy: Update Location Request with unknown IMSI */
+ GSUP.send(ts_GSUP_UL_REQ(imsi, dom)) to vc_GSUP_client;
+
+ /* [GSUP] TS-HLR: expect GSUP messages with that IMSI */
+ f_create_gsup_expect_explicit(hex2str(imsi), vc_GSUP_server);
+
+ /* [mDNS] TS-HLR <= HLR proxy: query for GSUP server who knows the IMSI */
+ mDNS.receive(tr_MSLookup_mDNS_query(domain)) -> value mdns_msg;
+
+ /* [mDNS] TS-HLR => HLR proxy: result with IP/port of TS GSUP server */
+ id := mdns_msg.dnsMessage.header.id;
+ mDNS.send(ts_MSLookup_mDNS_result_IPv4(id, domain, f_enc_IPv4(mp_hlr_ts_ip), mp_hlr_ts_port));
+
+ /* [GSUP] TS-HLR <=> HLR proxy <=> TS-MSC: finish up UL */
+ GSUP.receive(tr_GSUP_UL_REQ(imsi)) from vc_GSUP_server;
+ GSUP.send(ts_GSUP_ISD_REQ(imsi, msisdn, destination_name)) to vc_GSUP_server;
+ GSUP.receive(tr_GSUP_ISD_REQ(imsi, g_pars.sub.msisdn)) from vc_GSUP_client;
+ GSUP.send(ts_GSUP_ISD_RES(imsi, destination_name := destination_name)) to vc_GSUP_server;
+ GSUP.receive(tr_GSUP_ISD_RES(imsi)) from vc_GSUP_client;
+ GSUP.send(ts_GSUP_UL_RES(imsi, destination_name)) to vc_GSUP_server;
+ GSUP.receive(tr_GSUP_UL_RES(imsi)) from vc_GSUP_client;
+}
+
/* perform PurgeMS for given imsi, return the GSUP response/error */
function f_perform_PURGE(hexstring imsi, GSUP_CnDomain cn_dom,
template (omit) integer exp_err_cause := omit)
@@ -528,7 +707,8 @@ runs on HLR_ConnHdlr return GSUP_PDU {
}
private function f_SS_expect(hexstring imsi, OCT4 sid, GSUP_SessionState state,
- template SS_FacilityInformation facility := *)
+ template SS_FacilityInformation facility := *,
+ template octetstring destination_name := omit)
runs on HLR_ConnHdlr return GSUP_PDU {
var GSUP_PDU ret;
timer T := 3.0;
@@ -540,20 +720,22 @@ runs on HLR_ConnHdlr return GSUP_PDU {
alt {
[] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, ?)) -> value ret {
setverdict(fail, "Unexpected PROC_SS ERROR Cause");
+ mtc.stop;
}
- [not exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, omit)) -> value ret {
+ [not exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, omit, destination_name := destination_name)) -> value ret {
setverdict(pass);
}
[exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, omit)) -> value ret {
setverdict(fail, "Unexpected PROC_SS.res without SS IE");
+ mtc.stop;
}
/*
- [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, decmatch facility)) -> value ret {
+ [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, decmatch facility, destination_name := destination_name)) -> value ret {
setverdict(pass);
}
*/
- [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, ?)) -> value ret {
+ [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, ?, destination_name := destination_name)) -> value ret {
var GSUP_IeValue ss_ie;
f_gsup_find_ie(ret, OSMO_GSUP_SS_INFO_IE, ss_ie);
var SS_FacilityInformation dec_fac := dec_SS_FacilityInformation(ss_ie.ss_info);
@@ -562,9 +744,13 @@ runs on HLR_ConnHdlr return GSUP_PDU {
setverdict(pass);
} else {
setverdict(fail, "Unexpected PROC_SS.res with non-matching facility IE");
+ mtc.stop;
}
}
- [] GSUP.receive { repeat; }
+ [] GSUP.receive {
+ setverdict(fail, "Unexpected GSUP");
+ mtc.stop;
+ }
[] T.timeout {
setverdict(fail, "Timeout waiting for PROC_SS response");
self.stop;
@@ -576,7 +762,8 @@ runs on HLR_ConnHdlr return GSUP_PDU {
function f_perform_CHECK_IMEI(hexstring imsi, hexstring imei,
template (omit) integer exp_err_cause := omit,
- template (omit) GSUP_IMEIResult result := omit)
+ template (omit) GSUP_IMEIResult result := omit,
+ template (omit) octetstring source_name := omit)
runs on HLR_ConnHdlr {
var GSUP_PDU pdu;
timer T := 3.0;
@@ -585,26 +772,30 @@ runs on HLR_ConnHdlr {
exp_fail := true;
}
- GSUP.send(valueof(ts_GSUP_CHECK_IMEI_REQ(imsi, imei)));
+ GSUP.send(valueof(ts_GSUP_CHECK_IMEI_REQ(imsi, imei, source_name := source_name)));
T.start;
alt {
- [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, exp_err_cause)) -> value pdu {
+ [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, exp_err_cause, destination_name := source_name)) -> value pdu {
setverdict(pass);
}
- [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, ?)) -> value pdu {
+ [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, ?, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected CHECK IMEI ERROR Cause: ", pdu);
+ mtc.stop;
}
- [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, ?)) -> value pdu {
+ [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, ?, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected CHECK IMEI RES instead of ERR");
+ mtc.stop;
}
- [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, ?)) -> value pdu {
+ [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, ?, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected CHECK IMEI ERROR");
+ mtc.stop;
}
- [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, result)) -> value pdu {
+ [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, result, destination_name := source_name)) -> value pdu {
setverdict(pass);
}
- [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, ?)) -> value pdu {
+ [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, ?, destination_name := source_name)) -> value pdu {
setverdict(fail, "Unexpected CHECK IMEI RES");
+ mtc.stop;
}
[] GSUP.receive { repeat; }
[] T.timeout {
@@ -651,10 +842,15 @@ testcase TC_gsup_sai_err_unknown_imsi() runs on test_CT {
vc_conn.done;
}
-function f_start_handler_per_sub(void_fn fn, HlrSubscriberList sl) runs on test_CT {
+function f_start_handler_per_sub(void_fn fn, HlrSubscriberList sl, boolean via_proxy := false) runs on test_CT {
for (var integer i := 0; i < sizeof(sl); i := i+1) {
var HlrSubscriber sub := sl[i];
- var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sub));
+ var HLR_ConnHdlrPars pars;
+ if (via_proxy) {
+ pars := valueof(t_Pars_sub_via_proxy(sub));
+ } else {
+ pars := valueof(t_Pars_sub(sub));
+ }
var HLR_ConnHdlr vc_conn;
f_vty_subscr_create(VTY, sub);
@@ -668,7 +864,11 @@ function f_start_handler_per_sub(void_fn fn, HlrSubscriberList sl) runs on test_
private function f_TC_gsup_sai() runs on HLR_ConnHdlr {
var GSUP_PDU res;
res := f_perform_SAI(g_pars.sub.imsi);
- /* TODO: match if tuple[s] matches expectation */
+ if (ispresent(g_pars.sub.aud3g)) {
+ f_ensure_amf_separation_bit(res, '0'B);
+ }
+
+ f_count_auth_tuples(res, mp_default_num_auth_tuples);
setverdict(pass);
}
testcase TC_gsup_sai() runs on test_CT {
@@ -683,10 +883,95 @@ testcase TC_gsup_sai() runs on test_CT {
setverdict(pass);
}
+/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
+private function f_TC_gsup_sai_num_auth_vectors() runs on HLR_ConnHdlr {
+ var GSUP_PDU res;
+ res := f_perform_SAI(g_pars.sub.imsi, num_auth_tuple := 1);
+ f_count_auth_tuples(res, 1);
+ res := f_perform_SAI(g_pars.sub.imsi, num_auth_tuple := 4);
+ f_count_auth_tuples(res, 4);
+ res := f_perform_SAI(g_pars.sub.imsi, num_auth_tuple := 5);
+ f_count_auth_tuples(res, 5);
+ res := f_perform_SAI(g_pars.sub.imsi, num_auth_tuple := 254);
+ f_count_auth_tuples(res, 5);
+ setverdict(pass);
+}
+testcase TC_gsup_sai_num_auth_vectors() runs on test_CT {
+ var HlrSubscriberList sl;
+ var GSUP_PDU res;
+
+ f_init(false);
+
+ sl := f_gen_subs();
+ f_start_handler_per_sub(refers(f_TC_gsup_sai_num_auth_vectors), sl);
+
+ setverdict(pass);
+}
+
+private function f_ensure_amf_separation_bit(GSUP_PDU res, BIT1 sep_bit)
+{
+ for (var integer i := 0; i < lengthof(res.ies); i := i+1) {
+ var GSUP_IE tuple := res.ies[i];
+ if (tuple.tag != OSMO_GSUP_AUTH_TUPLE_IE) {
+ continue;
+ }
+ var GSUP_IeValue autn;
+ if (f_gsup_find_nested_ie(tuple.val.auth_tuple, OSMO_GSUP_AUTN_IE, autn) == false) {
+ setverdict(fail, "Couldn't find AUTN IE in tuple ", i);
+ mtc.stop;
+ }
+ var bitstring amf := oct2bit(substr(autn.autn, 6, 2));
+ if (amf[0] != sep_bit) {
+ setverdict(fail, "AMF bit 0 (separation bit) must be ", sep_bit," but was not");
+ mtc.stop;
+ }
+ }
+}
+
+private function f_count_auth_tuples(GSUP_PDU res, template (omit) integer expected_auth_tuples := omit)
+{
+ var integer auth_tuples := 0;
+ for (var integer i := 0; i < lengthof(res.ies); i := i+1) {
+ var GSUP_IE tuple := res.ies[i];
+ if (tuple.tag == OSMO_GSUP_AUTH_TUPLE_IE) {
+ auth_tuples := auth_tuples + 1;
+ }
+ }
+
+ if ((not istemplatekind(expected_auth_tuples, "omit")) and
+ not match(auth_tuples, valueof(expected_auth_tuples))) {
+ setverdict(fail,
+ "Did not received expected number of auth tuples. Expected ",
+ mp_default_num_auth_tuples,
+ " but received ", auth_tuples);
+ }
+}
+
+/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
+private function f_TC_gsup_sai_eps() runs on HLR_ConnHdlr {
+ var GSUP_PDU res;
+ res := f_perform_SAI(g_pars.sub.imsi, is_eps := true);
+ f_ensure_amf_separation_bit(res, '1'B);
+
+ /* TODO: match if tuple[s] matches expectation */
+ setverdict(pass);
+}
+testcase TC_gsup_sai_eps() runs on test_CT {
+ var HlrSubscriberList sl;
+ var GSUP_PDU res;
+
+ f_init(false);
+
+ sl := f_gen_3G_subs();
+ f_start_handler_per_sub(refers(f_TC_gsup_sai_eps), sl);
+
+ setverdict(pass);
+}
+
+
/* test UL for unknown IMSI */
private function f_TC_ul_unknown_imsi() runs on HLR_ConnHdlr {
- var GSUP_PDU res;
- res := f_perform_UL(g_pars.sub.imsi, ?, 2);
+ f_perform_UL(g_pars.sub.imsi, ?, 2, source_name := g_pars.source_name);
setverdict(pass);
}
testcase TC_gsup_ul_unknown_imsi() runs on test_CT {
@@ -698,11 +983,20 @@ testcase TC_gsup_ul_unknown_imsi() runs on test_CT {
vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
vc_conn.done;
}
+testcase TC_gsup_ul_unknown_imsi_via_proxy() runs on test_CT {
+ var hexstring imsi := f_rnd_imsi('26242'H);
+ var HLR_ConnHdlrPars pars := valueof(t_Pars_via_proxy(imsi));
+ var HLR_ConnHdlr vc_conn;
+
+ f_init(false);
+ vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
+ vc_conn.done;
+}
/* test UL for a number of different subscriber cases (algo, 2g/3g, ...) */
private function f_TC_gsup_ul() runs on HLR_ConnHdlr {
var GSUP_PDU res;
- res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
+ res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn, source_name := g_pars.source_name);
setverdict(pass);
}
testcase TC_gsup_ul() runs on test_CT {
@@ -715,6 +1009,16 @@ testcase TC_gsup_ul() runs on test_CT {
setverdict(pass);
}
+testcase TC_gsup_ul_via_proxy() runs on test_CT {
+ var HlrSubscriberList sl;
+ var GSUP_PDU res;
+
+ f_init(false);
+ sl := f_gen_subs();
+ f_start_handler_per_sub(refers(f_TC_gsup_ul), sl, via_proxy := true);
+
+ setverdict(pass);
+}
/* Test only the VTY commands */
testcase TC_vty() runs on test_CT {
@@ -905,12 +1209,14 @@ private function f_TC_mo_ussd_iuse_imsi() runs on HLR_ConnHdlr {
op_code := SS_OP_CODE_PROCESS_USS_REQ,
ussd_string := "*#101#");
GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
- OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
+ OSMO_GSUP_SESSION_STATE_BEGIN, ss,
+ source_name := g_pars.source_name)));
resp_str := "Your IMSI is " & hex2str(g_pars.sub.imsi);
res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
OSMO_GSUP_SESSION_STATE_END,
tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
- f_encGSM7bit(resp_str)));
+ f_encGSM7bit(resp_str)),
+ destination_name := g_pars.source_name);
}
testcase TC_mo_ussd_iuse_imsi() runs on test_CT {
var HlrSubscriberList sl;
@@ -926,6 +1232,20 @@ testcase TC_mo_ussd_iuse_imsi() runs on test_CT {
vc_conn.done;
}
}
+testcase TC_mo_ussd_iuse_imsi_via_proxy() runs on test_CT {
+ var HlrSubscriberList sl;
+ var HLR_ConnHdlr vc_conn;
+
+ f_init(false);
+ sl := f_gen_subs();
+ for (var integer i := 0; i < sizeof(sl); i := i+1) {
+ var HLR_ConnHdlrPars pars := valueof(t_Pars_sub_via_proxy(sl[i]));
+ pars.ussd.sid := f_rnd_octstring(4);
+ f_vty_subscr_create(VTY, pars.sub);
+ vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_imsi), pars);
+ vc_conn.done;
+ }
+}
/* Test for USSD request to internal own-msisdn IUSE. */
private function f_TC_mo_ussd_iuse_msisdn() runs on HLR_ConnHdlr {
@@ -935,12 +1255,14 @@ private function f_TC_mo_ussd_iuse_msisdn() runs on HLR_ConnHdlr {
op_code := SS_OP_CODE_PROCESS_USS_REQ,
ussd_string := "*#100#");
GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
- OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
+ OSMO_GSUP_SESSION_STATE_BEGIN, ss,
+ source_name := g_pars.source_name)));
resp_str := "Your extension is " & hex2str(g_pars.sub.msisdn);
res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
OSMO_GSUP_SESSION_STATE_END,
tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
- f_encGSM7bit(resp_str)));
+ f_encGSM7bit(resp_str)),
+ destination_name := g_pars.source_name);
}
testcase TC_mo_ussd_iuse_msisdn() runs on test_CT {
var HlrSubscriberList sl;
@@ -956,6 +1278,20 @@ testcase TC_mo_ussd_iuse_msisdn() runs on test_CT {
vc_conn.done;
}
}
+testcase TC_mo_ussd_iuse_msisdn_via_proxy() runs on test_CT {
+ var HlrSubscriberList sl;
+ var HLR_ConnHdlr vc_conn;
+
+ f_init(false);
+ sl := f_gen_subs();
+ for (var integer i := 0; i < sizeof(sl); i := i+1) {
+ var HLR_ConnHdlrPars pars := valueof(t_Pars_sub_via_proxy(sl[i]));
+ pars.ussd.sid := f_rnd_octstring(4);
+ f_vty_subscr_create(VTY, pars.sub);
+ vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_msisdn), pars);
+ vc_conn.done;
+ }
+}
/* Test routing of USSD to EUSE by a specific route */
private function f_TC_mo_ussd_100() runs on HLR_ConnHdlr {
@@ -1136,12 +1472,14 @@ testcase TC_mo_sss_reject() runs on test_CT {
private function f_TC_gsup_check_imei() runs on HLR_ConnHdlr {
/* store-imei disabled */
f_vty_config(VTY, "hlr", "no store-imei");
- f_perform_CHECK_IMEI(g_pars.sub.imsi, '12345678901234'H, result := OSMO_GSUP_IMEI_RESULT_ACK);
+ f_perform_CHECK_IMEI(g_pars.sub.imsi, '12345678901234'H, result := OSMO_GSUP_IMEI_RESULT_ACK,
+ source_name := g_pars.source_name);
f_vty_subscr_show_nomatch(VTY, g_pars.sub, pattern "*IMEI: *12345678901234*");
/* store-imei enabled */
f_vty_config(VTY, "hlr", "store-imei");
- f_perform_CHECK_IMEI(g_pars.sub.imsi, '12345678901234'H, result := OSMO_GSUP_IMEI_RESULT_ACK);
+ f_perform_CHECK_IMEI(g_pars.sub.imsi, '12345678901234'H, result := OSMO_GSUP_IMEI_RESULT_ACK,
+ source_name := g_pars.source_name);
f_vty_subscr_show(VTY, g_pars.sub, pattern "*IMEI: *12345678901234*");
}
testcase TC_gsup_check_imei() runs on test_CT {
@@ -1153,6 +1491,15 @@ testcase TC_gsup_check_imei() runs on test_CT {
setverdict(pass);
}
+testcase TC_gsup_check_imei_via_proxy() runs on test_CT {
+ var HlrSubscriberList sl;
+
+ f_init(false);
+ sl := f_gen_subs();
+ f_start_handler_per_sub(refers(f_TC_gsup_check_imei), sl, via_proxy := true);
+
+ setverdict(pass);
+}
/* Test Check IMEI with invalid IMEI length */
private function f_TC_gsup_check_imei_invalid_len() runs on HLR_ConnHdlr {
@@ -1366,6 +1713,215 @@ testcase TC_subscr_create_on_demand_sai() runs on test_CT {
vc_conn.done;
}
+/* Send an mslookup mDNS request to the home HLR, asking about a service that is not "gsup.hlr". (Hence the "_other" in
+ * the test name, service "gsup.hlr" has different code paths, see related tests). */
+private function f_TC_MSLookup_mDNS_service_other_home() runs on HLR_ConnHdlr {
+ timer T;
+ var MSLookup_mDNS vl_rmsg;
+ var integer id := f_rnd_int(65535); /* mDNS packet ID */
+ var hexstring msisdn := '49161'H & f_rnd_hexstring(7, 9);
+ var charstring domain := "sip.voice." & hex2str(msisdn) & ".msisdn.mdns.osmocom.org";
+
+ /* Create subscriber */
+ g_pars.sub.msisdn := msisdn;
+ f_vty_subscr_create(VTY, g_pars.sub);
+
+ /* Send mDNS query, expect timeout */
+ mDNS.send(ts_MSLookup_mDNS_query(id, domain));
+ T.start(1.0);
+ alt {
+ [] mDNS.receive(tr_MSLookup_mDNS_result_IPv4(id, domain, '42424242'O, 5060)) {
+ setverdict(fail, "OsmoHLR answered to mDNS query before subscriber did LU");
+ }
+ [] mDNS.receive(MSLookup_mDNS:?) -> value vl_rmsg {
+ repeat;
+ }
+ [] T.timeout {
+ }
+ }
+
+ /* Location update */
+ f_perform_UL(g_pars.sub.imsi, msisdn, dom := OSMO_GSUP_CN_DOMAIN_CS);
+
+ /* Send mDNS query again, expect result */
+ mDNS.send(ts_MSLookup_mDNS_query(id, domain));
+ T.start(1.0);
+ alt {
+ [] mDNS.receive(tr_MSLookup_mDNS_result_IPv4(id, domain, '42424242'O, 5060)) {
+ setverdict(pass);
+ }
+ [] mDNS.receive(MSLookup_mDNS:?) -> value vl_rmsg {
+ repeat;
+ }
+ [] T.timeout {
+ setverdict(fail, "OsmoHLR did not answer to mDNS query");
+ }
+ }
+
+ f_vty_subscr_delete(VTY, g_pars.sub);
+}
+testcase TC_MSLookup_mDNS_service_other_home() runs on test_CT {
+ var hexstring imsi := f_rnd_imsi('26242'H);
+ var HLR_ConnHdlr vc_conn;
+ var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
+
+ f_init(false);
+ f_vty_config(VTY, "mslookup", "mdns bind");
+ f_vty_config2(VTY, {"mslookup", "server"}, "service sip.voice at 66.66.66.66 5060");
+
+ vc_conn := f_start_handler(refers(f_TC_MSLookup_mDNS_service_other_home), pars);
+ vc_conn.done;
+}
+
+/* Let OsmoHLR act as proxy between MSC and another HLR during UL */
+private function f_TC_MSLookup_GSUP_proxy() runs on HLR_ConnHdlr {
+ f_perform_UL_proxy(g_pars.sub.imsi, g_pars.sub.msisdn, OSMO_GSUP_CN_DOMAIN_CS);
+ setverdict(pass);
+}
+testcase TC_MSLookup_GSUP_proxy() runs on test_CT {
+ var hexstring imsi := f_rnd_imsi('26242'H);
+ var hexstring msisdn := '49161'H & f_rnd_hexstring(7, 9);
+ var HLR_ConnHdlr vc_conn;
+ var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi, msisdn));
+
+ f_init(false, true);
+ f_vty_config(VTY, "mslookup", "mdns bind");
+ vc_conn := f_start_handler(refers(f_TC_MSLookup_GSUP_proxy), pars, true);
+
+ timer T := 3.0;
+ T.start;
+ alt {
+ [] vc_conn.done {}
+ [] T.timeout { setverdict(fail, "Timeout"); mtc.stop; };
+ }
+}
+
+/* Request "gsup.hlr" service right after creating subscriber from the home HLR. "TC_MSLookup_mDNS_service_other_home"
+ * is similar, but does not query the "gsup.hlr" service. The "gsup.hlr" service has a different code path in OsmoHLR:
+ * - it exists without being explicitly configured and returns the IP and port of the HLR's own GSUP server
+ * - the request is answered, even if the subscriber is not attached to the HLR (for Location Update via proxy) */
+private function f_TC_MSLookup_mDNS_service_GSUP_HLR_home() runs on HLR_ConnHdlr {
+ timer T;
+ var MSLookup_mDNS vl_rmsg;
+ var integer id := f_rnd_int(65535); /* mDNS packet ID */
+ var charstring domain := "gsup.hlr." & hex2str(g_pars.sub.imsi) & ".imsi.mdns.osmocom.org";
+
+ /* Create subscriber */
+ g_pars.sub.msisdn := '133713381339'H;
+ f_vty_subscr_create(VTY, g_pars.sub);
+
+ /* Send mDNS query, expect result */
+ mDNS.send(ts_MSLookup_mDNS_query(id, domain));
+ T.start(1.0);
+ alt {
+ [] mDNS.receive(tr_MSLookup_mDNS_result_IPv4(id, domain, f_enc_IPv4(mp_hlr_ip), mp_hlr_gsup_port)) {
+ setverdict(pass);
+ }
+ [] mDNS.receive(MSLookup_mDNS:?) -> value vl_rmsg {
+ repeat;
+ }
+ [] T.timeout {
+ setverdict(fail, "OsmoHLR did not answer to mDNS query");
+ }
+ }
+
+ f_vty_subscr_delete(VTY, g_pars.sub);
+}
+testcase TC_MSLookup_mDNS_service_GSUP_HLR_home() runs on test_CT {
+ var hexstring imsi := f_rnd_imsi('26242'H);
+ var HLR_ConnHdlr vc_conn;
+ var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
+
+ f_init(false);
+ f_vty_config(VTY, "mslookup", "mdns bind");
+
+ vc_conn := f_start_handler(refers(f_TC_MSLookup_mDNS_service_GSUP_HLR_home), pars);
+ vc_conn.done;
+}
+
+/* Ask proxy HLR about gsup.hlr service, and expect no answer. */
+private function f_TC_MSLookup_mDNS_service_GSUP_HLR_proxy() runs on HLR_ConnHdlr {
+ timer T;
+ var integer id := f_rnd_int(65535); /* mDNS packet ID */
+ var charstring domain := "gsup.hlr." & hex2str(g_pars.sub.imsi) & ".imsi.mdns.osmocom.org";
+
+ f_perform_UL_proxy(g_pars.sub.imsi, g_pars.sub.msisdn, OSMO_GSUP_CN_DOMAIN_CS);
+
+ /* Send mDNS query, expect timeout */
+ mDNS.send(ts_MSLookup_mDNS_query(id, domain));
+ T.start(1.0);
+ alt {
+ [] mDNS.receive(tr_MSLookup_mDNS_result_IPv4(id, domain, f_enc_IPv4(mp_hlr_ip), mp_hlr_gsup_port)) {
+ setverdict(fail, "mslookup result received from proxy HLR for gsup.hlr service");
+ }
+ [] mDNS.receive(MSLookup_mDNS:?) {
+ repeat;
+ }
+ [] T.timeout {
+ setverdict(pass);
+ }
+ }
+}
+testcase TC_MSLookup_mDNS_service_GSUP_HLR_proxy() runs on test_CT {
+ var hexstring imsi := f_rnd_imsi('26242'H);
+ var hexstring msisdn := '49161'H & f_rnd_hexstring(7, 9);
+ var HLR_ConnHdlr vc_conn;
+ var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi, msisdn));
+
+ f_init(false, true);
+ f_vty_config(VTY, "mslookup", "mdns bind");
+ vc_conn := f_start_handler(refers(f_TC_MSLookup_mDNS_service_GSUP_HLR_proxy), pars, true);
+
+ timer T := 3.0;
+ T.start;
+ alt {
+ [] vc_conn.done {}
+ [] T.timeout { setverdict(fail, "Timeout"); mtc.stop; };
+ }
+}
+
+/* Ask proxy HLR about configured sip.voice service, and expect result. */
+private function f_TC_MSLookup_mDNS_service_other_proxy() runs on HLR_ConnHdlr {
+ timer T;
+ var integer id := f_rnd_int(65535); /* mDNS packet ID */
+ var charstring domain := "sip.voice." & hex2str(g_pars.sub.msisdn) & ".msisdn.mdns.osmocom.org";
+
+ f_perform_UL_proxy(g_pars.sub.imsi, g_pars.sub.msisdn, OSMO_GSUP_CN_DOMAIN_CS);
+
+ /* Send mDNS query, expect result */
+ mDNS.send(ts_MSLookup_mDNS_query(id, domain));
+ T.start(1.0);
+ alt {
+ [] mDNS.receive(tr_MSLookup_mDNS_result_IPv4(id, domain, f_enc_IPv4("66.66.66.66"), 5060)) {
+ setverdict(pass);
+ }
+ [] mDNS.receive(MSLookup_mDNS:?) {
+ repeat;
+ }
+ [] T.timeout {
+ setverdict(fail, "Timeout");
+ }
+ }
+}
+testcase TC_MSLookup_mDNS_service_other_proxy() runs on test_CT {
+ var hexstring imsi := f_rnd_imsi('26242'H);
+ var hexstring msisdn := '49161'H & f_rnd_hexstring(7, 9);
+ var HLR_ConnHdlr vc_conn;
+ var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi, msisdn));
+
+ f_init(false, true);
+ f_vty_config(VTY, "mslookup", "mdns bind");
+ f_vty_config2(VTY, {"mslookup", "server"}, "service sip.voice at 66.66.66.66 5060");
+ vc_conn := f_start_handler(refers(f_TC_MSLookup_mDNS_service_other_proxy), pars, true);
+
+ timer T := 3.0;
+ T.start;
+ alt {
+ [] vc_conn.done {}
+ [] T.timeout { setverdict(fail, "Timeout"); mtc.stop; };
+ }
+}
+
/* TODO:
* UL with ISD error
* UL with ISD timeout
@@ -1383,9 +1939,13 @@ testcase TC_subscr_create_on_demand_sai() runs on test_CT {
control {
execute( TC_gsup_sai_err_invalid_imsi() );
execute( TC_gsup_sai() );
+ execute( TC_gsup_sai_num_auth_vectors() );
+ execute( TC_gsup_sai_eps() );
execute( TC_gsup_ul_unknown_imsi() );
+ execute( TC_gsup_ul_unknown_imsi_via_proxy() );
execute( TC_gsup_sai_err_unknown_imsi() );
execute( TC_gsup_ul() );
+ execute( TC_gsup_ul_via_proxy() );
execute( TC_vty() );
execute( TC_vty_msisdn_isd() );
execute( TC_gsup_purge_cs() );
@@ -1395,7 +1955,9 @@ control {
execute( TC_mo_ussd_unknown() );
execute( TC_mo_ussd_euse_disc() );
execute( TC_mo_ussd_iuse_imsi() );
+ execute( TC_mo_ussd_iuse_imsi_via_proxy() );
execute( TC_mo_ussd_iuse_msisdn() );
+ execute( TC_mo_ussd_iuse_msisdn_via_proxy() );
execute( TC_mo_ussd_euse() );
execute( TC_mo_ussd_euse_continue() );
execute( TC_mo_ussd_euse_defaultroute() );
@@ -1404,11 +1966,20 @@ control {
execute( TC_mo_sss_reject() );
execute( TC_gsup_check_imei() );
+ execute( TC_gsup_check_imei_via_proxy() );
execute( TC_gsup_check_imei_invalid_len() );
execute( TC_gsup_check_imei_unknown_imsi() );
execute( TC_subscr_create_on_demand_check_imei_early() );
execute( TC_subscr_create_on_demand_ul() );
execute( TC_subscr_create_on_demand_sai() );
+
+ if (mp_hlr_supports_dgsm) {
+ execute( TC_MSLookup_mDNS_service_other_home() );
+ execute( TC_MSLookup_GSUP_proxy() );
+ execute( TC_MSLookup_mDNS_service_GSUP_HLR_home() );
+ execute( TC_MSLookup_mDNS_service_GSUP_HLR_proxy() );
+ execute( TC_MSLookup_mDNS_service_other_proxy() );
+ }
};
};
diff --git a/hlr/expected-results.xml b/hlr/expected-results.xml
index b7d2773..7f1c277 100644
--- a/hlr/expected-results.xml
+++ b/hlr/expected-results.xml
@@ -1,10 +1,14 @@
<?xml version="1.0"?>
-<testsuite name='Titan' tests='24' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
+<testsuite name='Titan' tests='31' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
<testcase classname='HLR_Tests' name='TC_gsup_sai_err_invalid_imsi' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_sai' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_gsup_sai_num_auth_vectors' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_gsup_sai_eps' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_ul_unknown_imsi' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_gsup_ul_unknown_imsi_via_proxy' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_sai_err_unknown_imsi' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_ul' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_gsup_ul_via_proxy' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_vty' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_vty_msisdn_isd' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_purge_cs' time='MASKED'/>
@@ -13,12 +17,15 @@
<testcase classname='HLR_Tests' name='TC_mo_ussd_unknown' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_mo_ussd_euse_disc' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_mo_ussd_iuse_imsi' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_mo_ussd_iuse_imsi_via_proxy' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_mo_ussd_iuse_msisdn' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_mo_ussd_iuse_msisdn_via_proxy' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_mo_ussd_euse' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_mo_ussd_euse_continue' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_mo_ussd_euse_defaultroute' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_mo_sss_reject' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_check_imei' time='MASKED'/>
+ <testcase classname='HLR_Tests' name='TC_gsup_check_imei_via_proxy' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_check_imei_invalid_len' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_gsup_check_imei_unknown_imsi' time='MASKED'/>
<testcase classname='HLR_Tests' name='TC_subscr_create_on_demand_check_imei_early' time='MASKED'/>
diff --git a/hlr/gen_links.sh b/hlr/gen_links.sh
index 872820d..c77920d 100755
--- a/hlr/gen_links.sh
+++ b/hlr/gen_links.sh
@@ -35,11 +35,20 @@ FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types
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.DNS/src
+FILES="DNS_EncDec.cc DNS_Types.ttcn"
+gen_links $DIR $FILES
+
+DIR=$BASEDIR/titan.TestPorts.UDPasp/src
+FILES="UDPasp_PT.cc UDPasp_PT.hh UDPasp_PortType.ttcn UDPasp_Types.ttcn"
+gen_links $DIR $FILES
+
DIR=../library
FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp GSUP_Types.ttcn GSUP_Emulation.ttcn "
FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn "
FILES+="Osmocom_VTY_Functions.ttcn "
FILES+="SS_Templates.ttcn USSD_Helpers.ttcn "
+FILES+="MSLookup_mDNS_Types.ttcn MSLookup_mDNS_Emulation.ttcn MSLookup_mDNS_Templates.ttcn DNS_Helpers.ttcn "
gen_links $DIR $FILES
diff --git a/hlr/regen_makefile.sh b/hlr/regen_makefile.sh
index 1a1d812..14b05da 100755
--- a/hlr/regen_makefile.sh
+++ b/hlr/regen_makefile.sh
@@ -2,7 +2,7 @@
MAIN="HLR_Tests.ttcn"
-FILES="*.ttcn *.ttcnpp IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc TELNETasp_PT.cc TCCEncoding.cc SS_EncDec.cc MAP_EncDec.cc *.asn"
+FILES="*.ttcn *.ttcnpp DNS_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc TELNETasp_PT.cc TCCEncoding.cc UDPasp_PT.cc SS_EncDec.cc MAP_EncDec.cc *.asn"
export CPPFLAGS_TTCN3="-DIPA_EMULATION_GSUP -DIPA_EMULATION_CTRL"
diff --git a/lapdm/gen_links.sh b/lapdm/gen_links.sh
index 12830dd..217f485 100755
--- a/lapdm/gen_links.sh
+++ b/lapdm/gen_links.sh
@@ -14,7 +14,7 @@ gen_links $DIR $FILES
DIR=../library
-FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn RLCMAC_CSN1_Types.ttcn Osmocom_Types.ttcn L1CTL_PortType.ttcn L1CTL_PortType_CtrlFunct.ttcn L1CTL_PortType_CtrlFunctDef.cc L1CTL_Types.ttcn LAPDm_RAW_PT.ttcn LAPDm_Types.ttcn RLCMAC_Types.ttcn RLCMAC_EncDec.cc"
+FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn GSM_RR_Types.ttcn RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn Osmocom_Types.ttcn L1CTL_PortType.ttcn L1CTL_PortType_CtrlFunct.ttcn L1CTL_PortType_CtrlFunctDef.cc L1CTL_Types.ttcn LAPDm_RAW_PT.ttcn LAPDm_Types.ttcn RLCMAC_Templates.ttcn RLCMAC_Types.ttcn RLCMAC_EncDec.cc"
gen_links $DIR $FILES
ignore_pp_results
diff --git a/library/BSSAP_CodecPort.ttcn b/library/BSSAP_CodecPort.ttcn
index fdece08..5339b32 100644
--- a/library/BSSAP_CodecPort.ttcn
+++ b/library/BSSAP_CodecPort.ttcn
@@ -126,7 +126,7 @@ type record BSSAP_N_DATA_ind
SCCP_PAR_Importance importance optional
}
-template BSSAP_N_DATA_ind tr_BSSAP_DATA_ind(SCCP_PAR_Connection_Id conn_id,
+template BSSAP_N_DATA_ind tr_BSSAP_DATA_ind(template SCCP_PAR_Connection_Id conn_id,
template PDU_BSSAP bssap := *) := {
userData := bssap,
connectionId := conn_id,
diff --git a/library/BSSAP_LE_Adapter.ttcn b/library/BSSAP_LE_Adapter.ttcn
new file mode 100644
index 0000000..dba8841
--- /dev/null
+++ b/library/BSSAP_LE_Adapter.ttcn
@@ -0,0 +1,130 @@
+module BSSAP_LE_Adapter {
+
+/* This module implements a 'dumb' BSSAP_LE adapter. It creates the M3UA and SCCP components and stacks a
+ * BSSAP_LE codec port on top. As a result, it provides the ability to transceive SCCP-User-SAP primitives
+ * with deoded BSSAP_LE payload. Use this if you want to have full control about what you transmit or
+ * receive, without any automatisms in place. Allows you to refuse connections or other abnormal behavior. */
+
+/* (C) 2017-2020 Harald Welte <laforge@gnumonks.org>
+ * contributions by sysmocom - s.f.m.c. GmbH
+ * 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 General_Types all;
+import from Osmocom_Types all;
+
+import from M3UA_Emulation all;
+import from MTP3asp_Types all;
+import from MTP3asp_PortType all;
+
+import from IPA_Emulation all;
+
+import from SCCP_Types all;
+import from SCCPasp_Types all;
+import from SCCP_Emulation all;
+import from SCCP_Templates all;
+
+import from SCTPasp_Types all;
+import from SCTPasp_PortType all;
+
+import from BSSMAP_LE_Templates all;
+import from BSSAP_LE_Emulation all;
+
+type record BSSAP_LE_Adapter {
+ /* component references */
+ M3UA_CT vc_M3UA, /* only in 3GPP AoIP */
+ SCCP_CT vc_SCCP,
+
+ MSC_SCCP_MTP3_parameters sccp_pars,
+ SCCP_PAR_Address sccp_addr_own,
+ SCCP_PAR_Address sccp_addr_peer,
+
+ /* handler mode */
+ BSSAP_LE_Emulation_CT vc_BSSAP_LE
+}
+
+type record BSSAP_LE_Configuration {
+ charstring sccp_service_type,
+ SCTP_Association_Address sctp_addr,
+ integer own_pc,
+ integer own_ssn,
+ integer peer_pc,
+ integer peer_ssn,
+ octetstring sio,
+ integer rctx
+};
+type record of BSSAP_LE_Configuration BSSAP_LE_Configurations;
+
+private function init_pars(inout BSSAP_LE_Adapter ba, in BSSAP_LE_Configuration cfg) {
+ ba.sccp_pars := {
+ sio := {
+ ni := substr(oct2bit(cfg.sio),0,2),
+ prio := substr(oct2bit(cfg.sio),2,2),
+ si := substr(oct2bit(cfg.sio),4,4)
+ },
+ opc := cfg.own_pc,
+ dpc := cfg.peer_pc,
+ sls := 0,
+ sccp_serviceType := cfg.sccp_service_type,
+ ssn := cfg.own_ssn
+ };
+ ba.sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(cfg.own_pc, cfg.own_ssn, cfg.sio, cfg.sccp_service_type));
+ ba.sccp_addr_peer := valueof(ts_SccpAddr_PC_SSN(cfg.peer_pc, cfg.peer_ssn, cfg.sio, cfg.sccp_service_type));
+}
+
+
+function f_bssap_le_adapter_init(inout BSSAP_LE_Adapter ba, in BSSAP_LE_Configuration cfg, charstring id,
+ template BssapLeOps ops) {
+ init_pars(ba, cfg);
+ ops.sccp_addr_local := ba.sccp_addr_own;
+ ops.sccp_addr_peer := ba.sccp_addr_peer;
+
+ /* create components */
+ ba.vc_SCCP := SCCP_CT.create(id & "-SCCP");
+ if (isvalue(ops)) {
+ ba.vc_BSSAP_LE := BSSAP_LE_Emulation_CT.create(id & "-BSSAP_LE");
+ } else {
+ ba.vc_BSSAP_LE := null;
+ }
+ ba.vc_M3UA := M3UA_CT.create(id & "-M3UA");
+ map(ba.vc_M3UA:SCTP_PORT, system:sctp);
+ /* connect MTP3 service provider (M3UA) to lower side of SCCP */
+ connect(ba.vc_M3UA:MTP3_SP_PORT, ba.vc_SCCP:MTP3_SCCP_PORT);
+ ba.vc_M3UA.start(f_M3UA_Emulation(cfg.sctp_addr, cfg.rctx));
+
+ if (isvalue(ops)) {
+ timer T := 5.0;
+ T.start;
+ //T.timeout;
+ /* connect BSSNAP component to upper side of SCCP */
+ log("Connecting BSSAP_LE_Emulation to SCCP_SP_PORT");
+ connect(ba.vc_BSSAP_LE:BSSAP_LE, ba.vc_SCCP:SCCP_SP_PORT);
+ log("Starting BSSAP_LE_Emulation");
+ ba.vc_BSSAP_LE.start(BSSAP_LE_Emulation.main(valueof(ops), ""));
+ }
+
+
+}
+
+function f_bssap_le_adapter_start(inout BSSAP_LE_Adapter ba) {
+ ba.vc_SCCP.start(SCCPStart(ba.sccp_pars));
+}
+
+function f_bssap_le_adapter_cleanup(inout BSSAP_LE_Adapter ba) {
+ if (ba.vc_BSSAP_LE != null) {
+ disconnect(ba.vc_BSSAP_LE:BSSAP_LE, ba.vc_SCCP:SCCP_SP_PORT);
+ ba.vc_BSSAP_LE.stop;
+ }
+ unmap(ba.vc_M3UA:SCTP_PORT, system:sctp);
+ disconnect(ba.vc_M3UA:MTP3_SP_PORT, ba.vc_SCCP:MTP3_SCCP_PORT);
+ ba.vc_M3UA.stop;
+ ba.vc_SCCP.stop;
+}
+
+
+}
diff --git a/library/BSSAP_LE_CodecPort.ttcn b/library/BSSAP_LE_CodecPort.ttcn
new file mode 100644
index 0000000..f1d930f
--- /dev/null
+++ b/library/BSSAP_LE_CodecPort.ttcn
@@ -0,0 +1,380 @@
+module BSSAP_LE_CodecPort {
+
+/* Simple BSSAP_LE Codec Port, translating between raw SCCP primitives with
+ * octetstring payload towards the SCCP provider, and BSSAP_LE-SCCP primitives
+ * which carry the decoded BSSAP_LE data types as payload.
+ *
+ * (C) 2017 by Harald Welte <laforge@gnumonks.org>
+ * 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 General_Types all;
+import from Osmocom_Types all;
+
+import from SCCPasp_Types all;
+import from SCCP_Types all;
+
+import from BSSAP_LE_Types all;
+
+type record BSSAP_LE_N_CONNECT_req
+{
+ SCCP_PAR_Address calledAddress,
+ SCCP_PAR_Address callingAddress optional,
+ SCCP_PAR_Expedited_Data_Sel expeditedDataSel optional,
+ SCCP_PAR_Quality_Of_Service qualityOfService optional,
+ PDU_BSSAP_LE userData optional,
+ SCCP_PAR_Connection_Id connectionId optional,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_CONNECT_req ts_BSSAP_LE_CONNECT_req(SCCP_PAR_Address called,
+ SCCP_PAR_Address calling,
+ SCCP_PAR_Connection_Id conn_id,
+ template PDU_BSSAP_LE bssap := omit) := {
+ calledAddress := called,
+ callingAddress := calling,
+ expeditedDataSel := omit,
+ qualityOfService := omit,
+ userData := bssap,
+ connectionId := conn_id,
+ importance := omit
+}
+
+type record BSSAP_LE_N_CONNECT_ind
+{
+ SCCP_PAR_Address calledAddress,
+ SCCP_PAR_Address callingAddress optional,
+ SCCP_PAR_Quality_Of_Service qualityOfService optional,
+ PDU_BSSAP_LE userData optional,
+ SCCP_PAR_Connection_Id connectionId optional,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_CONNECT_ind tr_BSSAP_LE_CONNECT_ind(template SCCP_PAR_Address called,
+ template SCCP_PAR_Address calling,
+ template PDU_BSSAP_LE payload := *) := {
+ calledAddress := called,
+ callingAddress := calling,
+ qualityOfService := *,
+ userData := payload,
+ connectionId := *,
+ importance := *
+}
+
+type record BSSAP_LE_N_CONNECT_res
+{
+ SCCP_PAR_Address respondingAddress optional,
+ SCCP_PAR_Expedited_Data_Sel expeditedDataSel optional,
+ SCCP_PAR_Quality_Of_Service qualityOfService optional,
+ PDU_BSSAP_LE userData optional,
+ SCCP_PAR_Connection_Id connectionId optional,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_CONNECT_res ts_BSSAP_LE_CONNECT_res(SCCP_PAR_Connection_Id conn_id,
+ template PDU_BSSAP_LE bssap := omit) := {
+ respondingAddress := omit,
+ expeditedDataSel := omit,
+ qualityOfService := omit,
+ userData := bssap,
+ connectionId := conn_id,
+ importance := omit
+}
+
+type record BSSAP_LE_N_CONNECT_cfm
+{
+ SCCP_PAR_Address respondingAddress optional,
+ SCCP_PAR_Quality_Of_Service qualityOfService optional,
+ PDU_BSSAP_LE userData optional,
+ SCCP_PAR_Connection_Id connectionId optional,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_CONNECT_cfm tr_BSSAP_LE_CONNECT_cfm(template SCCP_PAR_Connection_Id conn_id,
+ template PDU_BSSAP_LE bssap := *) := {
+ respondingAddress := *,
+ qualityOfService := *,
+ userData := bssap,
+ connectionId := conn_id,
+ importance := *
+}
+
+type record BSSAP_LE_N_DATA_req
+{
+ PDU_BSSAP_LE userData ,
+ SCCP_PAR_Connection_Id connectionId optional ,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_DATA_req ts_BSSAP_LE_DATA_req(SCCP_PAR_Connection_Id conn_id,
+ template PDU_BSSAP_LE bssap) := {
+ userData := bssap,
+ connectionId := conn_id,
+ importance := omit
+}
+
+
+type record BSSAP_LE_N_DATA_ind
+{
+ PDU_BSSAP_LE userData ,
+ SCCP_PAR_Connection_Id connectionId optional ,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_DATA_ind tr_BSSAP_LE_DATA_ind(SCCP_PAR_Connection_Id conn_id,
+ template PDU_BSSAP_LE bssap := *) := {
+ userData := bssap,
+ connectionId := conn_id,
+ importance := *
+}
+
+
+type record BSSAP_LE_N_DISCONNECT_req
+{
+ SCCP_PAR_Address respondingAddress optional,
+ SCCP_PAR_Reason reason ,
+ PDU_BSSAP_LE userData optional ,
+ SCCP_PAR_Connection_Id connectionId optional ,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_DISCONNECT_req ts_BSSAP_LE_DISC_req(SCCP_PAR_Connection_Id conn_id,
+ template SCCP_PAR_Reason reason,
+ template PDU_BSSAP_LE bssap := omit) := {
+ respondingAddress := omit,
+ reason := reason,
+ userData := bssap,
+ connectionId := conn_id,
+ importance := omit
+}
+
+
+type record BSSAP_LE_N_DISCONNECT_ind
+{
+ SCCP_PAR_Originator originator ,
+ SCCP_PAR_Address respondingAddress optional ,
+ SCCP_PAR_Reason reason ,
+ PDU_BSSAP_LE userData optional ,
+ SCCP_PAR_Connection_Id connectionId optional ,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_DISCONNECT_ind tr_BSSAP_LE_DISC_ind(template SCCP_PAR_Connection_Id conn_id,
+ template SCCP_PAR_Originator originator,
+ template SCCP_PAR_Reason reason,
+ template PDU_BSSAP_LE bssap := *) := {
+ originator := originator,
+ respondingAddress:= *,
+ reason := reason,
+ userData := bssap,
+ connectionId := conn_id,
+ importance := *
+}
+
+type record BSSAP_LE_N_UNITDATA_req
+{
+ SCCP_PAR_Address calledAddress ,
+ SCCP_PAR_Address callingAddress ,
+ SCCP_PAR_Sequence_Control sequenceControl optional ,
+ SCCP_PAR_Return_Option returnOption optional ,
+ PDU_BSSAP_LE userData ,
+ SCCP_PAR_Importance importance optional
+ }
+
+template BSSAP_LE_N_UNITDATA_req ts_BSSAP_LE_UNITDATA_req(SCCP_PAR_Address called, SCCP_PAR_Address calling, template PDU_BSSAP_LE payload) := {
+ calledAddress := called,
+ callingAddress := calling,
+ sequenceControl := omit,
+ returnOption := omit,
+ userData := payload,
+ importance := omit
+}
+
+type record BSSAP_LE_N_UNITDATA_ind
+{
+ SCCP_PAR_Address calledAddress ,
+ SCCP_PAR_Address callingAddress ,
+ SCCP_PAR_Sequence_Control sequenceControl optional ,
+ SCCP_PAR_Return_Option returnOption optional ,
+ PDU_BSSAP_LE userData ,
+ SCCP_PAR_Importance importance optional
+}
+
+template BSSAP_LE_N_UNITDATA_ind tr_BSSAP_LE_UNITDATA_ind(template SCCP_PAR_Address called, template SCCP_PAR_Address calling, template PDU_BSSAP_LE payload) := {
+ calledAddress := called,
+ callingAddress := calling,
+ sequenceControl := *,
+ returnOption := *,
+ userData := payload,
+ importance := *
+}
+
+type record BSSAP_LE_N_NOTICE_ind
+{
+ SCCP_PAR_Address calledAddress ,
+ SCCP_PAR_Address callingAddress ,
+ SCCP_PAR_Reason_For_Return reasonForReturn ,
+ PDU_BSSAP_LE userData ,
+ SCCP_PAR_Importance importance optional
+}
+
+
+
+private function f_dec_ConnectInd(in ASP_SCCP_N_CONNECT_ind pin, out BSSAP_LE_N_CONNECT_ind pout) {
+ pout.calledAddress := pin.calledAddress;
+ pout.callingAddress := pin.callingAddress;
+ pout.qualityOfService := pin.qualityOfService;
+ if (ispresent(pin.userData)) {
+ pout.userData := dec_PDU_BSSAP_LE(pin.userData);
+ } else {
+ pout.userData := omit;
+ }
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_dec_ConnectCfm(in ASP_SCCP_N_CONNECT_cfm pin, out BSSAP_LE_N_CONNECT_cfm pout) {
+ pout.respondingAddress := pin.respondingAddress;
+ pout.qualityOfService := pin.qualityOfService;
+ if (ispresent(pin.userData)) {
+ pout.userData := dec_PDU_BSSAP_LE(pin.userData);
+ } else {
+ pout.userData := omit;
+ }
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_dec_DataInd(in ASP_SCCP_N_DATA_ind pin, out BSSAP_LE_N_DATA_ind pout) {
+ pout.userData := dec_PDU_BSSAP_LE(pin.userData);
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_dec_DisconnectInd(in ASP_SCCP_N_DISCONNECT_ind pin, out BSSAP_LE_N_DISCONNECT_ind pout) {
+ pout.originator := pin.originator;
+ pout.respondingAddress := pin.respondingAddress;
+ pout.reason := pin.reason;
+ if (ispresent(pin.userData)) {
+ pout.userData := dec_PDU_BSSAP_LE(pin.userData);
+ } else {
+ pout.userData := omit;
+ }
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_dec_UnitdataInd(in ASP_SCCP_N_UNITDATA_ind pin, out BSSAP_LE_N_UNITDATA_ind pout) {
+ pout.calledAddress := pin.calledAddress;
+ pout.callingAddress := pin.callingAddress;
+ pout.sequenceControl := pin.sequenceControl;
+ pout.returnOption := pin.returnOption;
+ pout.userData := dec_PDU_BSSAP_LE(pin.userData);
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_dec_NoticeInd(in ASP_SCCP_N_NOTICE_ind pin, out BSSAP_LE_N_NOTICE_ind pout) {
+ pout.calledAddress := pin.calledAddress;
+ pout.callingAddress := pin.callingAddress;
+ pout.reasonForReturn := pin.reasonForReturn;
+ pout.userData := dec_PDU_BSSAP_LE(pin.userData);
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+
+
+private function f_enc_ConnectReq(in BSSAP_LE_N_CONNECT_req pin, out ASP_SCCP_N_CONNECT_req pout) {
+ pout.calledAddress := pin.calledAddress;
+ pout.callingAddress := pin.callingAddress;
+ pout.expeditedDataSel := pin.expeditedDataSel;
+ pout.qualityOfService := pin.qualityOfService;
+ if (ispresent(pin.userData)) {
+ pout.userData := enc_PDU_BSSAP_LE(pin.userData);
+ } else {
+ pout.userData := omit;
+ }
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_enc_ConnectRes(in BSSAP_LE_N_CONNECT_res pin, out ASP_SCCP_N_CONNECT_res pout) {
+ pout.respondingAddress := pin.respondingAddress;
+ pout.expeditedDataSel := pin.expeditedDataSel;
+ pout.qualityOfService := pin.qualityOfService;
+ if (ispresent(pin.userData)) {
+ pout.userData := enc_PDU_BSSAP_LE(pin.userData);
+ } else {
+ pout.userData := omit;
+ }
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_enc_DataReq(in BSSAP_LE_N_DATA_req pin, out ASP_SCCP_N_DATA_req pout) {
+ pout.userData := enc_PDU_BSSAP_LE(pin.userData);
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_enc_DisconnectReq(in BSSAP_LE_N_DISCONNECT_req pin, out ASP_SCCP_N_DISCONNECT_req pout) {
+ pout.respondingAddress := pin.respondingAddress;
+ pout.reason := pin.reason;
+ if (ispresent(pin.userData)) {
+ pout.userData := enc_PDU_BSSAP_LE(pin.userData);
+ } else {
+ pout.userData := omit;
+ }
+ pout.connectionId := pin.connectionId;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+private function f_enc_UnitdataReq(in BSSAP_LE_N_UNITDATA_req pin, out ASP_SCCP_N_UNITDATA_req pout) {
+ pout.calledAddress := pin.calledAddress;
+ pout.callingAddress := pin.callingAddress;
+ pout.userData := enc_PDU_BSSAP_LE(pin.userData);
+ pout.sequenceControl := pin.sequenceControl;
+ pout.returnOption := pin.returnOption;
+ pout.importance := pin.importance;
+} with {extension "prototype(fast)" }
+
+type port BSSAP_LE_CODEC_PT message {
+ out BSSAP_LE_N_CONNECT_req,
+ BSSAP_LE_N_CONNECT_res,
+ BSSAP_LE_N_DATA_req,
+ BSSAP_LE_N_DISCONNECT_req,
+ BSSAP_LE_N_UNITDATA_req,
+ ASP_SCCP_N_RESET_req;
+ in BSSAP_LE_N_CONNECT_ind,
+ BSSAP_LE_N_CONNECT_cfm,
+ BSSAP_LE_N_DATA_ind,
+ BSSAP_LE_N_DISCONNECT_ind,
+ BSSAP_LE_N_UNITDATA_ind,
+ BSSAP_LE_N_NOTICE_ind,
+ ASP_SCCP_N_RESET_ind,
+ ASP_SCCP_N_RESET_cfm,
+ ASP_SCCP_N_STATE_ind;
+} with { extension "internal user SCCPasp_PT
+ out(BSSAP_LE_N_CONNECT_req -> ASP_SCCP_N_CONNECT_req: function(f_enc_ConnectReq);
+ BSSAP_LE_N_CONNECT_res -> ASP_SCCP_N_CONNECT_res: function(f_enc_ConnectRes);
+ BSSAP_LE_N_DATA_req -> ASP_SCCP_N_DATA_req: function(f_enc_DataReq);
+ BSSAP_LE_N_DISCONNECT_req -> ASP_SCCP_N_DISCONNECT_req: function(f_enc_DisconnectReq);
+ BSSAP_LE_N_UNITDATA_req -> ASP_SCCP_N_UNITDATA_req: function(f_enc_UnitdataReq);
+ ASP_SCCP_N_RESET_req -> ASP_SCCP_N_RESET_req: simple)
+ in(ASP_SCCP_N_CONNECT_ind -> BSSAP_LE_N_CONNECT_ind: function(f_dec_ConnectInd);
+ ASP_SCCP_N_CONNECT_cfm -> BSSAP_LE_N_CONNECT_cfm: function(f_dec_ConnectCfm);
+ ASP_SCCP_N_DATA_ind -> BSSAP_LE_N_DATA_ind: function(f_dec_DataInd);
+ ASP_SCCP_N_DISCONNECT_ind -> BSSAP_LE_N_DISCONNECT_ind: function(f_dec_DisconnectInd);
+ ASP_SCCP_N_UNITDATA_ind -> BSSAP_LE_N_UNITDATA_ind: function(f_dec_UnitdataInd);
+ ASP_SCCP_N_NOTICE_ind -> BSSAP_LE_N_NOTICE_ind: function(f_dec_NoticeInd);
+ ASP_SCCP_N_RESET_ind -> ASP_SCCP_N_RESET_ind: simple;
+ ASP_SCCP_N_RESET_cfm -> ASP_SCCP_N_RESET_cfm: simple;
+ ASP_SCCP_N_STATE_ind -> ASP_SCCP_N_STATE_ind: simple)"
+}
+
+
+}
diff --git a/library/BSSAP_LE_Emulation.ttcn b/library/BSSAP_LE_Emulation.ttcn
new file mode 100644
index 0000000..0b9fe16
--- /dev/null
+++ b/library/BSSAP_LE_Emulation.ttcn
@@ -0,0 +1,704 @@
+module BSSAP_LE_Emulation {
+
+/* BSSAP_LE Emulation, runs on top of BSSAP_LE_CodecPort. It multiplexes/demultiplexes
+ * the individual connections, so there can be separate TTCN-3 components handling
+ * each of the connections.
+ *
+ * The BSSAP_LE_Emulation.main() function processes SCCP primitives from the SCCP
+ * stack via the BSSAP_CodecPort, and dispatches them to the per-connection components.
+ *
+ * Outbound BSSAP/SCCP connections are initiated by sending a BSSAP_LE_Conn_Req primitive
+ * to the component running the BSSAP_LE_Emulation.main() function.
+ *
+ * For each new inbound connections, the BssapLeOps.create_cb() is called. It can create
+ * or resolve a TTCN-3 component, and returns a component reference to which that inbound
+ * connection is routed/dispatched.
+ *
+ * If a pre-existing component wants to register to handle a future inbound connection, it can
+ * do so by registering an "expect" with the expected Layer 3 (DTAP) payload. This is e.g. useful
+ * if you are simulating BTS + MSC, and first trigger a connection from BTS/RSL side in a
+ * component which then subsequently should also handle the MSC emulation.
+ *
+ * Inbound Unit Data messages (such as are dispatched to the BssapLeOps.unitdata_cb() callback,
+ * which is registered with an argument to the main() function below.
+ *
+ * (C) 2017-2020 by Harald Welte <laforge@gnumonks.org>
+ * All rights reserved.
+ *
+ * Released under the terms of GNU General Public License, Version 2 or
+ * (at your option) any later version.
+ */
+
+
+import from General_Types all;
+import from Osmocom_Types all;
+import from SCCP_Emulation all;
+import from SCCPasp_Types all;
+import from IPA_Emulation all;
+import from MobileL3_Types all;
+import from Misc_Helpers all;
+
+import from BSSAP_LE_Types all;
+import from BSSAP_LE_CodecPort all;
+import from BSSMAP_LE_Templates all;
+import from BSSMAP_Templates all;
+import from RAN_Emulation all;
+
+/* General "base class" component definition, of which specific implementations
+ * derive themselves by means of the "extends" feature */
+type component BSSAP_LE_ConnHdlr {
+ /* port towards MSC Emulator core / SCCP connection dispatchar */
+ port BSSAP_LE_Conn_PT BSSAP_LE;
+ /* procedure based port to register for incoming connections */
+ port BSSAP_LE_PROC_PT BSSAP_LE_PROC;
+}
+
+/* Auxiliary primitive that can happen on the port between per-connection client and this dispatcher */
+type enumerated BSSAP_LE_Conn_Prim {
+ /* SCCP tell us that connection was released */
+ CONN_PRIM_DISC_IND,
+ /* we tell SCCP to release connection */
+ CONN_PRIM_DISC_REQ,
+ /* Connection confirmed indication */
+ CONN_PRIM_CONF_IND
+}
+
+/* port between individual per-connection components and this dispatcher */
+type port BSSAP_LE_Conn_PT message {
+ inout
+ PDU_BSSAP_LE,
+ BSSAP_LE_N_UNITDATA_req,
+ /* Client requests us to create SCCP Connection */
+ BSSAP_LE_Conn_Req,
+ /* direct DTAP messages from/to clients */
+ PDU_DTAP_MO, PDU_DTAP_MT,
+ PDU_DTAP_PS_MO, PDU_DTAP_PS_MT,
+ /* misc indications / requests between SCCP and client */
+ BSSAP_LE_Conn_Prim;
+} with { extension "internal" };
+
+type uint2_t N_Sd_Array[4];
+
+/* represents a single BSSAP connection over SCCP */
+type record ConnectionData {
+ /* reference to the instance of the per-connection component */
+ BSSAP_LE_ConnHdlr comp_ref,
+ integer sccp_conn_id,
+ /* array of N(SD) values for MO DTAP messages, indexed by discriminator */
+ N_Sd_Array n_sd
+}
+
+type record ImsiMapping {
+ BSSAP_LE_ConnHdlr comp_ref,
+ hexstring imsi optional,
+ OCT4 tmsi
+}
+
+type component BSSAP_LE_Emulation_CT {
+ /* SCCP ports on the bottom side, using ASP primitives */
+ port BSSAP_LE_CODEC_PT BSSAP_LE;
+ /* BSSAP port to the per-connection clients */
+ port BSSAP_LE_Conn_PT CLIENT;
+
+ /* use 16 as this is also the number of SCCP connections that SCCP_Emulation can handle */
+ var ConnectionData ConnectionTable[16];
+
+ /* pending expected incoming connections */
+ var ExpectData ExpectTable[8];
+
+ /* tables for mapping inbound unitdata (like paging) */
+ var ImsiMapping ImsiTable[16];
+
+ /* procedure based port to register for incoming connections */
+ port BSSAP_LE_PROC_PT PROC;
+
+ var charstring g_ran_id;
+ var integer g_next_e1_ts := 1;
+ var BssapLeOps g_ran_ops;
+};
+
+private function f_conn_id_known(integer sccp_conn_id)
+runs on BSSAP_LE_Emulation_CT return boolean {
+ var integer i;
+ for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].sccp_conn_id == sccp_conn_id){
+ return true;
+ }
+ }
+ return false;
+}
+
+private function f_comp_known(BSSAP_LE_ConnHdlr client)
+runs on BSSAP_LE_Emulation_CT return boolean {
+ var integer i;
+ for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].comp_ref == client) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* resolve component reference by connection ID */
+private function f_comp_by_conn_id(integer sccp_conn_id)
+runs on BSSAP_LE_Emulation_CT return BSSAP_LE_ConnHdlr {
+ var integer i;
+ for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].sccp_conn_id == sccp_conn_id) {
+ return ConnectionTable[i].comp_ref;
+ }
+ }
+ setverdict(fail, "BSSAP-LE Connection table not found by SCCP Connection ID ", sccp_conn_id);
+ mtc.stop;
+}
+
+/* resolve connection ID by component reference */
+private function f_conn_id_by_comp(BSSAP_LE_ConnHdlr client)
+runs on BSSAP_LE_Emulation_CT return integer {
+ for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].comp_ref == client) {
+ return ConnectionTable[i].sccp_conn_id;
+ }
+ }
+ setverdict(fail, "BSSAP-LE Connection table not found by component ", client);
+ mtc.stop;
+}
+
+/* resolve ConnectionTable index component reference */
+private function f_idx_by_comp(BSSAP_LE_ConnHdlr client)
+runs on BSSAP_LE_Emulation_CT return integer {
+ for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].comp_ref == client) {
+ return i;
+ }
+ }
+ setverdict(fail, "BSSAP-LE Connection table not found by component ", client);
+ mtc.stop;
+}
+
+private function f_gen_conn_id()
+runs on BSSAP_LE_Emulation_CT return integer {
+ var integer conn_id;
+
+ do {
+ conn_id := float2int(rnd()*SCCP_Emulation.tsp_max_ConnectionId);
+ } while (f_conn_id_known(conn_id) == true);
+
+ return conn_id;
+}
+
+private function f_conn_table_init()
+runs on BSSAP_LE_Emulation_CT {
+ for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ ConnectionTable[i].comp_ref := null;
+ ConnectionTable[i].sccp_conn_id := -1;
+ ConnectionTable[i].n_sd := { 0, 0, 0, 0 };
+ }
+ for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
+ ImsiTable[i].comp_ref := null;
+ ImsiTable[i].imsi := omit;
+ ImsiTable[i].tmsi := 'FFFFFFFF'O;
+ }
+}
+
+private function f_conn_table_add(BSSAP_LE_ConnHdlr comp_ref, integer sccp_conn_id)
+runs on BSSAP_LE_Emulation_CT {
+ for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].sccp_conn_id == -1) {
+ ConnectionTable[i].comp_ref := comp_ref;
+ ConnectionTable[i].sccp_conn_id := sccp_conn_id;
+ ConnectionTable[i].n_sd := { 0, 0, 0, 0 };
+ log("Added conn table entry ", i, comp_ref, sccp_conn_id);
+ return;
+ }
+ }
+ testcase.stop("BSSAP-LE Connection table full!");
+}
+
+private function f_conn_table_del(integer sccp_conn_id)
+runs on BSSAP_LE_Emulation_CT {
+ for (var integer i := 0; i < sizeof(ConnectionTable); i := i+1) {
+ if (ConnectionTable[i].sccp_conn_id == sccp_conn_id) {
+ log("Deleted conn table entry ", i,
+ ConnectionTable[i].comp_ref, sccp_conn_id);
+ ConnectionTable[i].sccp_conn_id := -1;
+ ConnectionTable[i].comp_ref := null;
+ return
+ }
+ }
+ setverdict(fail, "BSSAP-LE Connection table attempt to delete non-existant ", sccp_conn_id);
+ mtc.stop;
+}
+
+private function f_imsi_table_find(hexstring imsi, template OCT4 tmsi)
+runs on BSSAP_LE_Emulation_CT return BSSAP_LE_ConnHdlr {
+ for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
+ if (ImsiTable[i].imsi == imsi or
+ isvalue(tmsi) and match(ImsiTable[i].tmsi, tmsi)) {
+ return ImsiTable[i].comp_ref;
+ }
+ }
+ return null;
+}
+
+type record BSSAP_LE_Conn_Req {
+ SCCP_PAR_Address addr_peer,
+ SCCP_PAR_Address addr_own,
+ PDU_BSSAP_LE bssap
+}
+template BSSAP_LE_Conn_Req ts_BSSAP_LE_Conn_Req(SCCP_PAR_Address peer, SCCP_PAR_Address own, PDU_BSSAP_LE bssap) := {
+ addr_peer := peer,
+ addr_own := own,
+ bssap := bssap
+};
+
+/* handle (optional) userData portion of various primitives and dispatch it to the client */
+private function f_handle_userData(BSSAP_LE_ConnHdlr client, PDU_BSSAP_LE bssap)
+runs on BSSAP_LE_Emulation_CT {
+ /* decode + send decoded BSSAP to client */
+
+ if (ischosen(bssap.pdu.dtap) and g_ran_ops.decode_dtap) {
+ if (g_ran_ops.role_ms) {
+ /* we are the MS, so any message to us must be MT */
+ var PDU_DTAP_MT mt := {
+ dlci := bssap.dlci,
+ dtap := dec_PDU_ML3_NW_MS(bssap.pdu.dtap)
+ };
+ CLIENT.send(mt) to client;
+ } else {
+ /* we are the Network, so any message to us must be MO */
+ var PDU_DTAP_MO mo := {
+ dlci := bssap.dlci,
+ dtap := dec_PDU_ML3_MS_NW(bssap.pdu.dtap)
+ };
+ CLIENT.send(mo) to client;
+ }
+ } else {
+ CLIENT.send(bssap) to client;
+ }
+}
+
+/* call-back type, to be provided by specific implementation; called when new SCCP connection
+ * arrives */
+type function BssmapLeCreateCallback(BSSAP_LE_N_CONNECT_ind conn_ind, charstring id)
+runs on BSSAP_LE_Emulation_CT return BSSAP_LE_ConnHdlr;
+
+type function BssmapLeUnitdataCallback(PDU_BSSAP_LE bssap)
+runs on BSSAP_LE_Emulation_CT return template PDU_BSSAP_LE;
+
+/* handle common Unitdata such as Paging */
+private function CommonBssmapUnitdataCallback(PDU_BSSAP_LE bssap)
+runs on BSSAP_LE_Emulation_CT return template PDU_BSSAP_LE {
+ if (match(bssap, tr_BSSMAP_LE_Paging)) {
+ var BSSAP_LE_ConnHdlr client := null;
+ client := f_imsi_table_find(bssap.pdu.bssmap.paging.iMSI.digits,
+ bssap.pdu.bssmap.paging.tMSI.tmsiOctets);
+ if (client != null) {
+ log("CommonBssmapUnitdataCallback: IMSI/TMSI found in table, dispatching to ",
+ client);
+ CLIENT.send(bssap) to client;
+ return omit;
+ }
+ log("CommonBssmapUnitdataCallback: IMSI/TMSI not found in table");
+ } else {
+ log("CommonBssmapUnitdataCallback: Not a paging message");
+ }
+ /* ELSE: handle in user callback */
+ return g_ran_ops.unitdata_cb.apply(bssap);
+}
+
+private function f_bssap_le_reset(SCCP_PAR_Address peer, SCCP_PAR_Address own) runs on BSSAP_LE_Emulation_CT {
+ timer T := 5.0;
+
+ BSSAP_LE.send(ts_BSSAP_LE_UNITDATA_req(peer, own, ts_BSSMAP_LE_Reset(GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE)));
+ T.start;
+ alt {
+ [] BSSAP_LE.receive(tr_BSSAP_LE_UNITDATA_ind(own, peer, tr_BSSMAP_LE_ResetAck)) {
+ log("Received RESET-ACK in response to RESET, we're ready to go!");
+ }
+ [] as_reset_ack();
+ [] BSSAP_LE.receive { repeat };
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for RESET-ACK after sending RESET");
+ mtc.stop;
+ }
+ }
+}
+
+private function f_bssap_l3_is_rr(PDU_BSSAP_LE bssap) return boolean {
+ var template octetstring l3 := f_bssap_le_extract_l3(bssap);
+ return f_L3_is_rr(l3);
+}
+
+
+
+type record BssapLeOps {
+ BssmapLeCreateCallback create_cb optional,
+ BssmapLeUnitdataCallback unitdata_cb optional,
+ boolean decode_dtap,
+ boolean role_ms,
+ /* needed for performing BSSMAP RESET */
+ SCCP_PAR_Address sccp_addr_local optional,
+ SCCP_PAR_Address sccp_addr_peer optional
+}
+
+private altstep as_reset_ack() runs on BSSAP_LE_Emulation_CT {
+ var BSSAP_LE_N_UNITDATA_ind ud_ind;
+ [] BSSAP_LE.receive(tr_BSSAP_LE_UNITDATA_ind(?, ?, tr_BSSMAP_LE_Reset)) -> value ud_ind {
+ log("Respoding to inbound RESET with RESET-ACK");
+ BSSAP_LE.send(ts_BSSAP_LE_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
+ ts_BSSMAP_LE_ResetAck));
+ repeat;
+ }
+}
+
+
+private altstep as_main_bssap_le() runs on BSSAP_LE_Emulation_CT {
+ var BSSAP_LE_N_UNITDATA_ind ud_ind;
+ var BSSAP_LE_N_CONNECT_ind conn_ind;
+ var BSSAP_LE_N_CONNECT_cfm conn_cfm;
+ var BSSAP_LE_N_DATA_ind data_ind;
+ var BSSAP_LE_N_DISCONNECT_ind disc_ind;
+ var BSSAP_LE_Conn_Req creq;
+ var PDU_BSSAP_LE bssap;
+ var BSSAP_LE_N_UNITDATA_req bssap_ud;
+ var BSSAP_LE_ConnHdlr vc_conn;
+ var integer targetPointCode;
+ var N_Sd_Array last_n_sd;
+
+ /* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */
+ [] BSSAP_LE.receive(BSSAP_LE_N_UNITDATA_ind:?) -> value ud_ind {
+ /* Connectionless Procedures like RESET */
+ var template PDU_BSSAP_LE resp;
+ resp := CommonBssmapUnitdataCallback(ud_ind.userData);
+ if (isvalue(resp)) {
+ BSSAP_LE.send(ts_BSSAP_LE_UNITDATA_req(ud_ind.callingAddress,
+ ud_ind.calledAddress, resp));
+ }
+ }
+ /* SCCP -> Client: new connection from BSC */
+ [] BSSAP_LE.receive(BSSAP_LE_N_CONNECT_ind:?) -> value conn_ind {
+ vc_conn := g_ran_ops.create_cb.apply(conn_ind, g_ran_id);
+ /* store mapping between client components and SCCP connectionId */
+ f_conn_table_add(vc_conn, conn_ind.connectionId);
+ /* handle user payload */
+ f_handle_userData(vc_conn, conn_ind.userData);
+ /* confirm connection establishment */
+ BSSAP_LE.send(ts_BSSAP_LE_CONNECT_res(conn_ind.connectionId, omit));
+ }
+ /* SCCP -> Client: connection-oriented data in existing connection */
+ [] BSSAP_LE.receive(BSSAP_LE_N_DATA_ind:?) -> value data_ind {
+ vc_conn := f_comp_by_conn_id(data_ind.connectionId);
+ if (ispresent(data_ind.userData)) {
+ f_handle_userData(vc_conn, data_ind.userData);
+ }
+ }
+ /* SCCP -> Client: disconnect of an existing connection */
+ [] BSSAP_LE.receive(BSSAP_LE_N_DISCONNECT_ind:?) -> value disc_ind {
+ vc_conn := f_comp_by_conn_id(disc_ind.connectionId);
+ if (ispresent(disc_ind.userData)) {
+ f_handle_userData(vc_conn, disc_ind.userData);
+ }
+ /* notify client about termination */
+ var BSSAP_LE_Conn_Prim prim := CONN_PRIM_DISC_IND;
+ CLIENT.send(prim) to vc_conn;
+ f_conn_table_del(disc_ind.connectionId);
+ /* TOOD: return confirm to other side? */
+ }
+ /* SCCP -> Client: connection confirm for outbound connection */
+ [] BSSAP_LE.receive(BSSAP_LE_N_CONNECT_cfm:?) -> value conn_cfm {
+ vc_conn := f_comp_by_conn_id(conn_cfm.connectionId);
+ var BSSAP_LE_Conn_Prim prim := CONN_PRIM_CONF_IND;
+ CLIENT.send(prim) to vc_conn;
+ /* handle user payload */
+ if (ispresent(conn_cfm.userData)) {
+ f_handle_userData(vc_conn, conn_cfm.userData);
+ }
+ }
+ [] CLIENT.receive(PDU_BSSAP_LE:?) -> value bssap sender vc_conn {
+ var integer conn_id := f_conn_id_by_comp(vc_conn);
+ /* send it to dispatcher */
+ BSSAP_LE.send(ts_BSSAP_LE_DATA_req(conn_id, bssap));
+ }
+
+ [] CLIENT.receive(BSSAP_LE_N_UNITDATA_req:?) -> value bssap_ud sender vc_conn {
+ BSSAP_LE.send(bssap_ud);
+ }
+
+ /* Disconnect request client -> SCCP */
+ [] CLIENT.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_DISC_REQ) -> sender vc_conn {
+ var integer conn_id := f_conn_id_by_comp(vc_conn);
+ BSSAP_LE.send(ts_BSSAP_LE_DISC_req(conn_id, 0));
+ f_conn_table_del(conn_id);
+ }
+
+ /* BSSAP from client -> SCCP */
+ [] CLIENT.receive(BSSAP_LE_Conn_Req:?) -> value creq sender vc_conn {
+ var integer conn_id;
+ /* send to dispatcher */
+
+ if (f_comp_known(vc_conn) == false) {
+ /* unknown client, create new connection */
+ conn_id := f_gen_conn_id();
+
+ /* store mapping between client components and SCCP connectionId */
+ f_conn_table_add(vc_conn, conn_id);
+
+ BSSAP_LE.send(ts_BSSAP_LE_CONNECT_req(creq.addr_peer, creq.addr_own, conn_id,
+ creq.bssap));
+ } else {
+ /* known client, send via existing connection */
+ conn_id := f_conn_id_by_comp(vc_conn);
+ BSSAP_LE.send(ts_BSSAP_LE_DATA_req(conn_id, creq.bssap));
+ }
+
+ /* InitialL3 contains RR (PAG RESP) or MM (CM SRV REQ), we must increment
+ * counter only on MM/CC/SS, but not on RR */
+ if (g_ran_ops.role_ms and not f_bssap_l3_is_rr(creq.bssap)) {
+ /* we have just sent the first MM message, increment the counter */
+ var integer idx := f_idx_by_comp(vc_conn);
+ ConnectionTable[idx].n_sd[0] := 1;
+ log("patch: N(SD) for ConnIdx ", idx, " set to 1");
+ }
+ }
+
+ [] PROC.getcall(BSSAP_LE_last_n_sd:{?,-}) -> param(vc_conn) {
+ var integer idx := f_idx_by_comp(vc_conn);
+ last_n_sd := ConnectionTable[idx].n_sd;
+ PROC.reply(BSSAP_LE_last_n_sd:{vc_conn, last_n_sd}) to vc_conn;
+ }
+
+ [] PROC.getcall(BSSAP_LE_continue_after_n_sd:{?,?}) -> param(last_n_sd, vc_conn) {
+ var integer idx := f_idx_by_comp(vc_conn);
+ ConnectionTable[idx].n_sd := last_n_sd;
+ PROC.reply(BSSAP_LE_continue_after_n_sd:{last_n_sd, vc_conn}) to vc_conn;
+ }
+}
+
+
+/* send a raw (encoded) L3 message over given SCCP connection */
+private function f_xmit_raw_l3(integer sccp_conn_id, OCT1 dlci, octetstring l3_enc) runs on BSSAP_LE_Emulation_CT
+{
+ var PDU_BSSAP_LE bssap;
+ bssap := valueof(ts_BSSAP_LE_DTAP(l3_enc, dlci));
+ BSSAP_LE.send(ts_BSSAP_LE_DATA_req(sccp_conn_id, bssap));
+}
+
+/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */
+private function f_ML3_patch_seq(inout ConnectionData cd, in PDU_ML3_MS_NW dtap, inout octetstring enc_l3) {
+ var integer n_sd_idx := f_ML3_n_sd_idx(dtap);
+ if (n_sd_idx < 0) {
+ return;
+ }
+ var uint2_t seq_nr := f_next_n_sd(cd.n_sd, n_sd_idx);
+ f_ML3_patch_seq_nr(seq_nr, enc_l3);
+}
+
+function main(BssapLeOps ops, charstring id) runs on BSSAP_LE_Emulation_CT {
+
+ g_ran_id := id;
+ g_ran_ops := ops;
+ f_conn_table_init();
+ f_expect_table_init();
+
+ if (isvalue(ops.sccp_addr_peer) and isvalue(ops.sccp_addr_local)) {
+ f_sleep(1.0); /* HACK to wait for M3UA/ASP to be ACTIVE */
+ f_bssap_le_reset(ops.sccp_addr_peer, ops.sccp_addr_local);
+ }
+
+ while (true) {
+ var BSSAP_LE_ConnHdlr vc_conn;
+ var PDU_DTAP_MO dtap_mo;
+ var PDU_DTAP_MT dtap_mt;
+ var BSSAP_LE_ConnHdlr vc_hdlr;
+ var octetstring l3_info;
+ var hexstring imsi;
+ var OCT4 tmsi;
+ var integer targetPointCode;
+
+ alt {
+ [] as_main_bssap_le();
+
+ [g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_MO:?) -> value dtap_mo sender vc_conn {
+ var integer idx := f_idx_by_comp(vc_conn);
+ /* convert from decoded DTAP to encoded DTAP */
+ var octetstring l3_enc := enc_PDU_ML3_MS_NW(dtap_mo.dtap);
+ /* patch correct L3 send sequence number N(SD) into l3_enc */
+ if (dtap_mo.skip_seq_patching == false) {
+ f_ML3_patch_seq(ConnectionTable[idx], dtap_mo.dtap, l3_enc);
+ }
+ f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, dtap_mo.dlci, l3_enc);
+ }
+
+ [not g_ran_ops.role_ms] CLIENT.receive(PDU_DTAP_MT:?) -> value dtap_mt sender vc_conn {
+ var integer idx := f_idx_by_comp(vc_conn);
+ /* convert from decoded DTAP to encoded DTAP */
+ var octetstring l3_enc := enc_PDU_ML3_NW_MS(dtap_mt.dtap);
+ f_xmit_raw_l3(ConnectionTable[idx].sccp_conn_id, dtap_mt.dlci, l3_enc);
+ }
+
+ [] PROC.getcall(BSSAP_LE_register:{?,?}) -> param(l3_info, vc_hdlr) {
+ f_create_expect(l3_info, vc_hdlr);
+ PROC.reply(BSSAP_LE_register:{l3_info, vc_hdlr}) to vc_hdlr;
+ }
+
+ [] PROC.getcall(BSSAP_LE_register_handoverRequest:{?,?}) -> param(targetPointCode, vc_hdlr) {
+ f_create_expect(omit, vc_hdlr, targetPointCode);
+ PROC.reply(BSSAP_LE_register_handoverRequest:{targetPointCode, vc_hdlr}) to vc_hdlr;
+ }
+
+ [] PROC.getcall(BSSAP_LE_register_imsi:{?,?,?}) -> param(imsi, tmsi, vc_hdlr) {
+ f_create_imsi(imsi, tmsi, vc_hdlr);
+ PROC.reply(BSSAP_LE_register_imsi:{imsi, tmsi, vc_hdlr}) to vc_hdlr;
+ }
+
+
+ }
+ }
+}
+
+/***********************************************************************
+ * "Expect" Handling (mapping for expected incoming SCCP connections)
+ ***********************************************************************/
+
+/* data about an expected future incoming connection */
+type record ExpectData {
+ /* L3 payload based on which we can match it */
+ octetstring l3_payload optional,
+ integer handoverRequestPointCode optional,
+ /* component reference for this connection */
+ BSSAP_LE_ConnHdlr vc_conn
+}
+
+/* procedure based port to register for incoming connections */
+signature BSSAP_LE_register(in octetstring l3, in BSSAP_LE_ConnHdlr hdlr);
+signature BSSAP_LE_register_handoverRequest(in integer targetPointCode, in BSSAP_LE_ConnHdlr hdlr);
+
+/* procedure based port to register for incoming IMSI/TMSI */
+signature BSSAP_LE_register_imsi(in hexstring imsi, in OCT4 tmsi, in BSSAP_LE_ConnHdlr hdlr);
+
+/* If DTAP happens across other channels (e.g. GSUP), provide manual advancing of the n_sd sequence number */
+signature BSSAP_LE_last_n_sd(in BSSAP_LE_ConnHdlr hdlr, out N_Sd_Array last_n_sd);
+
+/* Update conn's n_sd sequence nr after the connection was taken over from elsewhere */
+signature BSSAP_LE_continue_after_n_sd(N_Sd_Array last_n_sd, in BSSAP_LE_ConnHdlr hdlr);
+
+type port BSSAP_LE_PROC_PT procedure {
+ inout BSSAP_LE_register, BSSAP_LE_register_imsi, BSSAP_LE_register_handoverRequest, BSSAP_LE_last_n_sd, BSSAP_LE_continue_after_n_sd;
+} with { extension "internal" };
+
+/* CreateCallback that can be used as create_cb and will use the expectation table */
+function ExpectedCreateCallback(BSSAP_LE_N_CONNECT_ind conn_ind, charstring id)
+runs on BSSAP_LE_Emulation_CT return BSSAP_LE_ConnHdlr {
+ var BSSAP_LE_ConnHdlr ret := null;
+ var octetstring l3_info;
+ var integer i;
+
+ if (ischosen(conn_ind.userData.pdu.bssmap.perf_loc_req)) {
+ var BSSMAP_LE_PerfLocReq plr := conn_ind.userData.pdu.bssmap.perf_loc_req;
+ if (not ispresent(plr.imsi)) {
+ log("ExpectedCreateCallback: Cannot handle PerformLocReq without IMSI!");
+ mtc.stop;
+ }
+ var hexstring imsi := plr.imsi.imsi.oddEvenInd_identity.imsi.digits;
+ /* Find the component by the IMSI [usually] contained in this message */
+ ret := f_imsi_table_find(imsi, omit);
+ if (ret != null) {
+ log("ExpectedCreateCallback: Found ConnHdlr ", ret, " for IMSI ", imsi);
+ return ret;
+ }
+ } else if (ischosen(conn_ind.userData.pdu.bssmap.completeLayer3Information)) {
+ l3_info := conn_ind.userData.pdu.bssmap.completeLayer3Information.layer3Information.layer3info;
+ log("ExpectedCreateCallback completeLayer3Information");
+ } else {
+ setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3");
+ mtc.stop;
+ }
+
+ for (i := 0; i < sizeof(ExpectTable); i:= i+1) {
+ if (not ispresent(ExpectTable[i].l3_payload)) {
+ continue;
+ }
+ if (l3_info == ExpectTable[i].l3_payload) {
+ ret := ExpectTable[i].vc_conn;
+ /* release this entry to be used again */
+ ExpectTable[i].l3_payload := omit;
+ ExpectTable[i].vc_conn := null;
+ log("Found Expect[", i, "] for ", l3_info, " handled at ", ret);
+ /* return the component reference */
+ return ret;
+ }
+ }
+ setverdict(fail, "Couldn't find Expect for incoming connection ", conn_ind);
+ mtc.stop;
+}
+
+
+private function f_create_expect(template octetstring l3, BSSAP_LE_ConnHdlr hdlr,
+ template integer handoverRequestPointCode := omit)
+runs on BSSAP_LE_Emulation_CT {
+ var integer i;
+ log("f_create_expect(l3 := ", l3, ", handoverRequest := ", handoverRequestPointCode);
+ for (i := 0; i < sizeof(ExpectTable); i := i+1) {
+ if (not ispresent(ExpectTable[i].l3_payload)
+ and not ispresent(ExpectTable[i].handoverRequestPointCode)) {
+ if (ispresent(l3)) {
+ ExpectTable[i].l3_payload := valueof(l3);
+ }
+ if (ispresent(handoverRequestPointCode)) {
+ ExpectTable[i].handoverRequestPointCode := valueof(handoverRequestPointCode);
+ }
+ ExpectTable[i].vc_conn := hdlr;
+ if (ispresent(handoverRequestPointCode)) {
+ log("Created Expect[", i, "] for handoverRequest to be handled at ", hdlr);
+ } else {
+ log("Created Expect[", i, "] for ", l3, " to be handled at ", hdlr);
+ }
+ return;
+ }
+ }
+ testcase.stop("No space left in ExpectTable");
+}
+
+private function f_create_imsi(hexstring imsi, OCT4 tmsi, BSSAP_LE_ConnHdlr hdlr)
+runs on BSSAP_LE_Emulation_CT {
+ for (var integer i := 0; i < sizeof(ImsiTable); i := i+1) {
+ if (not ispresent(ImsiTable[i].imsi)) {
+ ImsiTable[i].imsi := imsi;
+ ImsiTable[i].tmsi := tmsi;
+ ImsiTable[i].comp_ref := hdlr;
+ log("Created IMSI[", i, "] for ", imsi, tmsi, " to be handled at ", hdlr);
+ return;
+ }
+ }
+ testcase.stop("No space left in ImsiTable");
+}
+
+
+private function f_expect_table_init()
+runs on BSSAP_LE_Emulation_CT {
+ for (var integer i := 0; i < sizeof(ExpectTable); i := i+1) {
+ ExpectTable[i].l3_payload := omit;
+ ExpectTable[i].handoverRequestPointCode := omit;
+ }
+}
+
+/* helper function for clients to register their IMSI/TMSI */
+function f_bssap_le_register_imsi(hexstring imsi, template (omit) OCT4 tmsi_or_omit)
+runs on BSSAP_LE_ConnHdlr {
+ var OCT4 tmsi;
+
+ /* Resolve omit to a special reserved value */
+ if (istemplatekind(tmsi_or_omit, "omit")) {
+ tmsi := 'FFFFFFFF'O;
+ } else {
+ tmsi := valueof(tmsi_or_omit);
+ }
+
+ BSSAP_LE_PROC.call(BSSAP_LE_register_imsi:{imsi, tmsi, self}) {
+ [] BSSAP_LE_PROC.getreply(BSSAP_LE_register_imsi:{?,?,?}) {};
+ }
+}
+
+
+}
diff --git a/library/BSSAP_LE_Types.ttcn b/library/BSSAP_LE_Types.ttcn
new file mode 100644
index 0000000..604fbe0
--- /dev/null
+++ b/library/BSSAP_LE_Types.ttcn
@@ -0,0 +1,594 @@
+module BSSAP_LE_Types {
+
+/* BSSAP_LE_Types, defining abstract TTCN-3 data types for the 3GPP BSSMAP-LE protocol.
+ *
+ * BSSMAP-LE is a 3GPP standard protocol used by SMLC and its peers in a GSM network.
+ * This file covers 3GPP TS 49.031 version 15.0.0 Release 15
+ *
+ * (C) 2020 by Harald Welte <laforge@gnumonks.org>
+ * 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 General_Types all;
+import from Osmocom_Types all;
+import from BSSAP_Types all;
+import from BSSLAP_Types all;
+import from MobileL3_CommonIE_Types all;
+
+/* TS 49.031 Section 10.1 */
+type enumerated BSSMAP_LE_MsgType {
+ BSSMAP_LE_PERFORM_LOC_REQ ('00101011'B),
+ BSSMAP_LE_PERFORM_LOC_RESP ('00101101'B),
+ BSSMAP_LE_PERFORM_LOC_ABORT ('00101110'B),
+ BSSMAP_LE_PERFORM_LOC_INFO ('00101111'B),
+ BSSMAP_LE_ASSIST_INFO_REQ ('00100000'B),
+ BSSMAP_LE_ASSIST_INFO_RESP ('00100001'B),
+
+ BSSMAP_LE_CONN_ORIENTED_INFO ('00101010'B),
+ BSSMAP_LE_CONN_LESS_INFO ('00111010'B),
+
+ BSSMAP_LE_RESET ('00110000'B),
+ BSSMAP_LE_RESET_ACK ('00110001'B)
+} with { variant "FIELDLENGTH(8)" };
+
+/* TS 49.031 Section 10.2 */
+type enumerated BSSMAP_LE_IEI {
+ BSSMAP_LE_IEI_LCS_QoS ('00111110'B),
+ BSSMAP_LE_IEI_LCS_PRIORITY ('01000011'B),
+ BSSMAP_LE_IEI_LOCATION_TYPE ('01000100'B),
+ BSSMAP_LE_IEI_GANSS_LOCATION_TYPE ('10000010'B),
+ BSSMAP_LE_IEI_GEO_LOCATION ('01000101'B),
+ BSSMAP_LE_IEI_POSITIONING_DATA ('01000110'B),
+ BSSMAP_LE_IEI_GANSS_POS_DATA ('10000011'B),
+ BSSMAP_LE_IEI_VELOCITY_DATA ('01010101'B),
+ BSSMAP_LE_IEI_LCS_CAUSE ('01000111'B),
+ BSSMAP_LE_IEI_LCS_CLIENT_TYPE ('01001000'B),
+ BSSMAP_LE_IEI_APDU ('01001001'B),
+ BSSMAP_LE_IEI_NET_ELEM_ID ('01001010'B),
+ BSSMAP_LE_IEI_REQ_GPS_ASS_D ('01001011'B),
+ BSSMAP_LE_IEI_REQ_GANSS_ASS_D ('01000001'B),
+ BSSMAP_LE_IEI_DECIPH_KEYS ('01001100'B),
+ BSSMAP_LE_IEI_RET_ERR_REQ ('01001101'B),
+ BSSMAP_LE_IEI_RET_ERR_CAUSE ('01001110'B),
+ BSSMAP_LE_IEI_SEGMENTATION ('01001111'B),
+ BSSMAP_LE_IEI_CLASSMARK3_INFO ('00010011'B),
+ BSSMAP_LE_IEI_CAUSE ('00000100'B),
+ BSSMAP_LE_IEI_CELL_ID ('00000101'B),
+ BSSMAP_LE_IEI_CHOSEN_CHAN ('00100001'B),
+ BSSMAP_LE_IEI_IMSI ('00000000'B),
+ BSSMAP_LE_IEI_LCS_CAPABILITY ('01010000'B),
+ BSSMAP_LE_IEI_PKT_MEAS_REP ('01010001'B),
+ BSSMAP_LE_IEI_CELL_ID_LIST ('01010010'B),
+ BSSMAP_LE_IEI_IMEI ('10000000'B),
+ BSSMAP_LE_IEI_BSS_MLAT_CAP ('10000100'B),
+ BSSMAP_LE_IEI_CELL_INFO_LIST ('10000101'B),
+ BSSMAP_LE_IEI_BTS_RX_ACC_LVL ('10000110'B),
+ BSSMAP_LE_IEI_MLAT_METHOD ('10000111'B),
+ BSSMAP_LE_IEI_MLAT_TA ('10001000'B),
+ BSSMAP_LE_IEI_MS_SYNC_ACC ('10001001'B),
+ BSSMAP_LE_IEI_SHORT_ID_SET ('10001010'B),
+ BSSMAP_LE_IEI_RANDOM_ID_SET ('10001011'B),
+ BSSMAP_LE_IEI_SHORT_BSS_ID ('10001100'B),
+ BSSMAP_LE_IEI_RANDOM_ID ('10001101'B),
+ BSSMAP_LE_IEI_SHORT_ID ('10001110'B),
+ BSSMAP_LE_IEI_COVERAGE_CLASS ('10001111'B),
+ BSSMAP_LE_IEI_MTA_ACC_SEC_RQD ('10010000'B)
+} with { variant "FIELDLENGTH(8)" };
+
+/* Section 9.1 */
+type record BSSMAP_LE_PerfLocReq {
+ BSSMAP_LE_MsgType msg_type,
+ BSSMAP_LE_IE_LocationType location_type,
+ BSSMAP_IE_CellIdentifier cell_id,
+ BSSMAP_IE_ClassmarkInformationType3 cm3 optional,
+ BSSMAP_LE_IE_LcsClientType lcs_client_type optional,
+ BSSMAP_IE_ChosenChannel chosen_channel optional,
+ BSSMAP_LE_IE_LcsPriority lcs_priority optional,
+ BSSMAP_LE_IE_LcsQoS lcs_qos optional,
+ BSSMAP_LE_IE_ReqGpsAssD req_gps_ass_d optional,
+ BSSMAP_LE_IE_APDU bsslap_apdu optional,
+ BSSMAP_LE_IE_LcsCapability lcs_capability optional,
+ BSSMAP_LE_IE_PacketMeasRep packet_meas_rep optional,
+ BSSMAP_LE_IE_CellIdList meas_cell_id_list optional,
+ BSSMAP_LE_IE_IMSI imsi optional,
+ BSSMAP_LE_IE_IMEI imei optional
+ // TODO: more optional IEs
+};
+
+/* Section 9.2 */
+type record BSSMAP_LE_PerfLocResp {
+ BSSMAP_LE_MsgType msg_type,
+ BSSMAP_LE_IE_GeographicLoc geographic_loc optional,
+ BSSMAP_LE_IE_PositioningData pos_data optional,
+ BSSMAP_LE_IE_DecipheringKeys deciph_keys optional,
+ BSSMAP_LE_IE_LcsCause lcs_cause optional,
+ BSSMAP_LE_IE_VelocityData velocity_data optional,
+ BSSMAP_LE_IE_GanssPosData ganss_pos_data optional
+};
+
+/* Section 9.4 */
+type record BSSMAP_LE_PerfLocAbort {
+ BSSMAP_LE_MsgType msg_type,
+ BSSMAP_LE_IE_LcsCause lcs_cause
+};
+
+/* Section 9.8 */
+type record BSSMAP_LE_ConnOrientedInfo {
+ BSSMAP_LE_MsgType msg_type,
+ BSSMAP_LE_IE_APDU bsslap_apdu,
+ BSSMAP_LE_IE_Segmentation segmentation optional
+ // TODO: MLA related optional IEs
+};
+
+/* Section 9.9 */
+type record BSSMAP_LE_ConnLessInfo {
+ BSSMAP_LE_MsgType msg_type,
+ BSSMAP_LE_IE_NetElementId source_id,
+ BSSMAP_LE_IE_NetElementId dest_id,
+ BSSMAP_LE_IE_APDU bsslap_apdu optional,
+ BSSMAP_LE_IE_Segmentation segmentation optional,
+ BSSMAP_LE_IE_RetErrReq ret_err_req optional,
+ BSSMAP_LE_IE_RetErrCause ret_err_cause optional
+};
+
+/* Section 9.10 */
+type record BSSMAP_LE_Reset {
+ BSSMAP_LE_MsgType msg_type,
+ BSSMAP_IE_Cause cause
+};
+
+/* Section 9.11 */
+type record BSSMAP_LE_ResetAck {
+ BSSMAP_LE_MsgType msg_type
+};
+
+/* Section 9.12 */
+type record BSSMAP_LE_PerformLocInfo {
+ BSSMAP_LE_MsgType msg_type,
+ BSSMAP_IE_CellIdentifier cell_id,
+ BSSMAP_LE_IE_APDU bsslap_apdu optional
+};
+
+type union BSSMAP_LE_PDU {
+ BSSMAP_LE_PerfLocReq perf_loc_req,
+ BSSMAP_LE_PerfLocResp perf_loc_resp,
+ BSSMAP_LE_PerfLocAbort perf_loc_abort,
+ BSSMAP_LE_ConnOrientedInfo co_info,
+ BSSMAP_LE_ConnLessInfo cl_info,
+ BSSMAP_LE_Reset reset,
+ BSSMAP_LE_ResetAck reset_ack,
+ BSSMAP_LE_PerformLocInfo perf_loc_info,
+ /* The following BSSMAP messages defined in 3GPP TS 48.008 are applicable to the Lb interface to
+ * support signaling to a Type A LMU using an SDCCH */
+ PDU_BSSMAP_CipherModeCommand cipherModeCommand,
+ PDU_BSSMAP_CipherModeComplete cipherModeComplete,
+ PDU_BSSMAP_CipherModeReject cipherModeReject,
+ PDU_BSSMAP_ClassmarkUpdate classmarkUpdate,
+ PDU_BSSMAP_ClearCommand clearCommand,
+ PDU_BSSMAP_ClearComplete clearComplete,
+ PDU_BSSMAP_ClearRequest clearRequest,
+ PDU_BSSMAP_CompleteLayer3Information completeLayer3Information,
+ PDU_BSSMAP_Confusion confusion,
+ PDU_BSSMAP_HandoverRequired handoverRequired,
+ PDU_BSSMAP_HandoverRequiredReject handoverRequiredReject,
+ PDU_BSSMAP_HandoverPerformed handoverPerformed,
+ PDU_BSSMAP_Paging paging
+} with {
+ variant "TAG(
+ perf_loc_req, msg_type = BSSMAP_LE_PERFORM_LOC_REQ;
+ perf_loc_resp, msg_type = BSSMAP_LE_PERFORM_LOC_RESP;
+ perf_loc_abort, msg_type = BSSMAP_LE_PERFORM_LOC_ABORT;
+ co_info, msg_type = BSSMAP_LE_CONN_ORIENTED_INFO;
+ cl_info, msg_type = BSSMAP_LE_CONN_LESS_INFO;
+ reset, msg_type = BSSMAP_LE_RESET;
+ reset_ack, msg_type = BSSMAP_LE_RESET_ACK;
+ perf_loc_info, msg_type = BSSMAP_LE_PERFORM_LOC_INFO;
+ )"
+};
+
+/* Section 10.3 */
+type record BSSMAP_LE_IE_APDU {
+ BSSMAP_LE_IEI iei,
+ uint16_t len,
+ BIT1 spare,
+ BSSMAP_LE_ProtocolId protocol_id,
+ octetstring data
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_APDU)"
+ variant (len) "LENGTHTO(spare,protocol_id,data)"
+};
+type enumerated BSSMAP_LE_ProtocolId {
+ BSSMAP_LE_PROT_RESERVED ('0000000'B),
+ BSSMAP_LE_PROT_BSSLAP ('0000001'B),
+ BSSMAP_LE_PROT_LLP ('0000010'B),
+ BSSMAP_LE_PROT_SMLCPP ('0000011'B)
+} with { variant "FIELDLENGTH(7)" };
+
+/* Section 10.8 */
+type record BSSMAP_LE_IE_DecipheringKeys {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BIT7 spare,
+ boolean ciph_key_flag,
+ OCT7 cur_deciph_key,
+ OCT7 next_deciph_key
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_DECIPH_KEYS)"
+ variant (len) "LENGTHTO(spare,ciph_key_flag,cur_deciph_key,next_deciph_key)"
+}
+
+/* Section 10.9 */
+type record BSSMAP_LE_IE_GeographicLoc {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ octetstring location
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_GEO_LOCATION)"
+ variant (len) "LENGTHTO(location)"
+}
+
+/* Section 10.10 */
+type record BSSMAP_LE_IE_ReqGpsAssD {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BIT16 flags,
+ octetstring sat_data
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_REQ_GPS_ASS_D)"
+ variant (len) "LENGTHTO(flags,sat_data)"
+}
+
+/* Section 10.11 */
+type record BSSMAP_LE_IE_IMSI {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ MobileIdentityV imsi
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_IMSI)"
+ variant (len) "LENGTHTO(imsi)"
+}
+
+/* Section 10.13 */
+type record BSSMAP_LE_IE_LcsCause {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BSSMAP_LE_LcsCause cause,
+ OCT1 diag_val optional
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_IMSI)"
+ variant (len) "LENGTHTO(cause,diag_val)"
+}
+type enumerated BSSMAP_LE_LcsCause {
+ BSSMAP_LE_LCS_CAUSE_UNSPEIFIED ('00000000'B),
+ BSSMAP_LE_LCS_CAUSE_SYSTEM_FAILURE ('00000001'B),
+ BSSMAP_LE_LCS_CAUSE_PROTOCOL_ERROR ('00000010'B),
+ BSSMAP_LE_LCS_CAUSE_DATA_MISSING_IN_REQ ('00000011'B),
+ BSSMAP_LE_LCS_CAUSE_UNEXP_DATA_IN_REQ ('00000100'B),
+ BSSMAP_LE_LCS_CAUSE_POS_METH_FAILURE ('00000101'B),
+ BSSMAP_LE_LCS_CAUSE_TGT_MS_UNREACHABLE ('00000110'B),
+ BSSMAP_LE_LCS_CAUSE_REQUEST_ABORTED ('00000111'B),
+ BSSMAP_LE_LCS_CAUSE_FACILITY_NOTSUPP ('00001000'B),
+ BSSMAP_LE_LCS_CAUSE_INTER_BSC_HO ('00001001'B),
+ BSSMAP_LE_LCS_CAUSE_INTRA_BSC_HO ('00001010'B),
+ BSSMAP_LE_LCS_CAUSE_CONGESTION ('00001011'B),
+ BSSMAP_LE_LCS_CAUSE_INTER_NSE_CHG ('00001100'B),
+ BSSMAP_LE_LCS_CAUSE_RA_UPDAT ('00001101'B),
+ BSSMAP_LE_LCS_CAUSE_PTMSI_REALLOC ('00001110'B),
+ BSSMAP_LE_LCS_CAUSE_GPRS_SUSPENSION ('00001111'B)
+} with { variant "FIELDLENGTH(8)" };
+
+/* Section 10.14 */
+type record BSSMAP_LE_IE_LcsClientType {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BSSMAP_LE_ClientType cltype
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_CAUSE)"
+ variant (len) "LENGTHTO(cltype)"
+}
+type enumerated BSSMAP_LE_ClientType {
+ BSSMAP_LE_LCS_CTYPE_VALUE_ADDED_UNSPECIFIED ('00000000'B),
+ BSSMAP_LE_LCS_CTYPE_PLMN_OPER_UNSPECIFIED ('00100000'B),
+ BSSMAP_LE_LCS_CTYPE_PLMN_OPER_BCAST_SERVICE ('00100001'B),
+ BSSMAP_LE_LCS_CTYPE_PLMN_OPER_OAM ('00100010'B),
+ BSSMAP_LE_LCS_CTYPE_PLMN_OPER_ANON_STATS ('00100011'B),
+ BSSMAP_LE_LCS_CTYPE_PLMN_OPER_TGT_MS_SVC ('00100100'B),
+ BSSMAP_LE_LCS_CTYPE_EMERG_SVC_UNSPECIFIED ('00110000'B),
+ BSSMAP_LE_LCS_CTYPE_LI_UNSPECIFIED ('01000000'B)
+} with { variant "FIELDLENGTH(8)" };
+
+/* Section 10.15 */
+type record BSSMAP_LE_IE_LcsPriority {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ OCT1 priority
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_LCS_PRIORITY)"
+ variant (len) "LENGTHTO(priority)"
+}
+
+/* Section 10.16 */
+type record BSSMAP_LE_IE_LcsQoS {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+
+ BIT6 spare,
+ boolean vel,
+ boolean vert,
+
+ boolean ha,
+ uint7_t horiz_acc,
+
+ boolean va,
+ uint7_t vert_acc,
+
+ BIT2 rt,
+ BIT6 spare2
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_LCS_QoS)"
+ variant (len) "LENGTHTO(spare,vel,vert,ha,horiz_acc,va,vert_acc,rt,spare2)"
+}
+
+/* Section 10.18 */
+type record BSSMAP_LE_IE_LocationType {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BSSMAP_LE_LocInfo loc_info,
+ BSSMAP_LE_PosMethod pos_method optional
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_LOCATION_TYPE)"
+ variant (len) "LENGTHTO(loc_info,pos_method)"
+ variant (pos_method) "PRESENCE(loc_info = BSSMAP_LE_LOC_INFO_ASS_INFO_FOR_TGT_MS,
+ loc_info = BSSMAP_LE_LOC_INFO_DECIPH_KEYS_FOR_BCAST)"
+}
+type enumerated BSSMAP_LE_LocInfo {
+ BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC ('00000000'B),
+ BSSMAP_LE_LOC_INFO_ASS_INFO_FOR_TGT_MS ('00000001'B),
+ BSSMAP_LE_LOC_INFO_DECIPH_KEYS_FOR_BCAST ('00000010'B)
+} with { variant "FIELDLENGTH(8)" };
+type enumerated BSSMAP_LE_PosMethod {
+ BSSMAP_LE_POS_METHOD_RESERVED ('00000000'B),
+ BSSMAP_LE_POS_MOBILE_ASSISTED_EOTD ('00000001'B),
+ BSSMAP_LE_POS_MOBILE_BASED_EOTD ('00000010'B),
+ BSSMAP_LE_POS_ASSISTED_GPS ('00000011'B),
+ BSSMAP_LE_POS_ASSISTED_GANSS ('00000100'B),
+ BSSMAP_LE_POS_ASSISTED_GPS_AND_GANSS ('00000101'B)
+} with { variant "FIELDLENGTH(8)" };
+
+/* Section 10.19 */
+type record BSSMAP_LE_IE_NetElementId {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BIT4 spare,
+ BSSMAP_LE_IdDiscr id_discr,
+ BSSMAP_LE_IdU u
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_NET_ELEM_ID)"
+ variant (len) "LENGTHTO(spare,id_discr,u)"
+ variant (u) "CROSSTAG(
+ cgi, id_discr = BSSMAP_LE_ID_DISC_CGI;
+ lac_ci, id_discr = BSSMAP_LE_ID_DISC_LAC_CI;
+ lai, id_discr = BSSMAP_LE_ID_DISC_LAI;
+ lac, id_discr = BSSMAP_LE_ID_DISC_LAC;
+ lmu, id_discr = BSSMAP_LE_ID_LMU;
+ )"
+};
+type enumerated BSSMAP_LE_IdDiscr {
+ BSSMAP_LE_ID_DISC_CGI ('0000'B),
+ BSSMAP_LE_ID_DISC_LAC_CI ('0001'B),
+ BSSMAP_LE_ID_DISC_LAI ('0100'B),
+ BSSMAP_LE_ID_DISC_LAC ('0101'B),
+ BSSMAP_LE_ID_LMU ('0110'B)
+} with { variant "FIELDLENGTH(4)" };
+type union BSSMAP_LE_IdU {
+ BSSMAP_LE_Id_CGI cgi,
+ BSSMAP_LE_Id_LAC_CI lac_ci,
+ BSSMAP_LE_Id_LAI lai,
+ uint16_t lac,
+ octetstring lmu
+};
+type record BSSMAP_LE_Id_CGI {
+ HEX6n mcc_mnc,
+ uint16_t lac,
+ uint16_t ci
+};
+type record BSSMAP_LE_Id_LAC_CI {
+ uint16_t lac,
+ uint16_t ci
+};
+type record BSSMAP_LE_Id_LAI {
+ HEX6n mcc_mnc,
+ uint16_t lac
+};
+
+/* Section 10.20 */
+type record BSSMAP_LE_IE_PositioningData {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BIT4 spare,
+ uint4_t discr,
+ BSSMAP_LE_PosMethList pos_meth
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_POSITIONING_DATA)"
+ variant (len) "LENGTHTO(spare,discr,pos_meth)"
+};
+type record of BSSMAP_LE_PosMethodN BSSMAP_LE_PosMethList;
+type record BSSMAP_LE_PosMethodN {
+ BSSMAP_LE_Method method,
+ BSSMAP_LE_Usage usage
+};
+type enumerated BSSMAP_LE_Method {
+ BSSMAP_LE_METHOD_TA ('00000'B),
+ BSSMAP_LE_METHOD_RESERVED0 ('00001'B),
+ BSSMAP_LE_METHOD_RESERVED1 ('00010'B),
+ BSSMAP_LE_METHOD_MOBILE_ASS_EOTD ('00011'B),
+ BSSMAP_LE_METHOD_MOBILE_BASED_EOTD ('00100'B),
+ BSSMAP_LE_METHOD_MOBILE_ASS_GPS ('00101'B),
+ BSSMAP_LE_METHOD_MOBILE_BASED_GPS ('00110'B),
+ BSSMAP_LE_METHOD_CONVENTIONAL_GPS ('00111'B),
+ BSSMAP_LE_METHOD_UTDOA ('01000'B),
+ BSSMAP_LE_METHOD_CELL_ID ('01100'B)
+} with { variant "FIELDLENGTH(5)" };
+type enumerated BSSMAP_LE_Usage {
+ BSSMAP_LE_USAGE_ATTEMPTED_UNSUCC ('000'B),
+ BSSMAP_LE_USAGE_ATTEMPTED_SUCC_NOT_USED ('001'B),
+ BSSMAP_LE_USAGE_ATTEMPTED_SUCC_USED_VRFY_NOT_GEN ('010'B),
+ BSSMAP_LE_USAGE_ATTEMPTED_SUCC_USED_GEN ('011'B),
+ BSSMAP_LE_USAGE_ATTEMPTED_SUCC_USAGE_UNDETERMINED ('100'B)
+} with { variant "FIELDLENGTH(3)" };
+
+/* Section 10.21 */
+type record BSSMAP_LE_IE_RetErrReq {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ OCT1 ret_err_type
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_RET_ERR_REQ)"
+ variant (len) "LENGTHTO(ret_err_type)"
+}
+
+/* Section 10.22 */
+type record BSSMAP_LE_IE_RetErrCause {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BSSMAP_LE_RetErrCause cause
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_RET_ERR_REQ)"
+ variant (len) "LENGTHTO(cause)"
+}
+type enumerated BSSMAP_LE_RetErrCause {
+ BSSMAP_LE_RE_CAUSE_UNSPECIFIED ('00000000'B),
+ BSSMAP_LE_RE_CAUSE_SYSTEM_FAILURE ('00000001'B),
+ BSSMAP_LE_RE_CAUSE_PROTOCOL_ERROR ('00000010'B),
+ BSSMAP_LE_RE_CAUSE_DEST_UNKNOWN ('00000011'B),
+ BSSMAP_LE_RE_CAUSE_DEST_UNREACHABLE ('00000100'B),
+ BSSMAP_LE_RE_CAUSE_CONGESTION ('00000101'B)
+} with { variant "FIELDLENGTH(8)" };
+
+/* Section 10.24 */
+type record BSSMAP_LE_IE_Segmentation {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BIT3 spare,
+ boolean s_non_final,
+ uint4_t seg_nr,
+ OCT2 msg_id optional
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_SEGMENTATION)"
+ variant (len) "LENGTHTO(spare,s_non_final,seg_nr,msg_id)"
+}
+
+/* Section 10.26 */
+type record BSSMAP_LE_IE_LcsCapability {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ octetstring lcs_cap
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_LCS_CAPABILITY)"
+ variant (len) "LENGTHTO(lcs_cap)"
+}
+
+type record BSSMAP_LE_IE_PacketMeasRep {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ octetstring pkt_meas_rep
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_PKT_MEAS_REP)"
+ variant (len) "LENGTHTO(pkt_meas_rep)"
+}
+
+type record BSSMAP_LE_IE_CellIdList {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BSSLAP_CellIdList cell_id_list
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_CELL_ID_LIST)"
+ variant (len) "LENGTHTO(cell_id_list)"
+}
+
+/* Section 10.29 */
+type record BSSMAP_LE_IE_IMEI {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ MobileIdentityV imei
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_IMEI)"
+ variant (len) "LENGTHTO(imei)"
+}
+
+/* Section 10.30 */
+type record BSSMAP_LE_IE_VelocityData {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ octetstring data
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_VELOCITY_DATA)"
+ variant (len) "LENGTHTO(data)"
+}
+
+/* Section 10.32 */
+type record BSSMAP_LE_IE_GanssPosData {
+ BSSMAP_LE_IEI iei,
+ uint8_t len,
+ BSSMAP_LE_GanssList list
+} with {
+ variant "PRESENCE(iei = BSSMAP_LE_IEI_VELOCITY_DATA)"
+ variant (len) "LENGTHTO(list)"
+}
+type record of BSSMAP_LE_Ganss BSSMAP_LE_GanssList;
+type record BSSMAP_LE_Ganss {
+ BSSMAP_LE_GanssMethod method,
+ BSSMAP_LE_GanssId id,
+ BSSMAP_LE_Usage usage
+};
+type enumerated BSSMAP_LE_GanssMethod {
+ BSSMAP_LE_GANSS_METH_MS_BASED ('00'B),
+ BSSMAP_LE_GANSS_METH_MS_ASSISTED ('01'B),
+ BSSMAP_LE_GANSS_METH_MS_CONVENTIONAL ('10'B),
+ BSSMAP_LE_GANSS_METH_MS_RESERVED ('11'B)
+} with { variant "FIELDLENGTH(2)" };
+type enumerated BSSMAP_LE_GanssId {
+ BSSMAP_LE_GANSS_ID_GALILEO ('000'B),
+ BSSMAP_LE_GANSS_ID_SBAS ('001'B),
+ BSSMAP_LE_GANSS_ID_MODERNIZED_GPS ('010'B),
+ BSSMAP_LE_GANSS_ID_QZSS ('011'B),
+ BSSMAP_LE_GANSS_ID_GLONASS ('100'B),
+ BSSMAP_LE_GANSS_ID_BDS ('101'B)
+} with { variant "FIELDLENGTH(3)" };
+
+/* FIXME: Further IEs */
+
+
+
+
+type union BSSMAPLEorDTAP {
+ BSSMAP_LE_PDU bssmap,
+ octetstring dtap
+}
+
+type record PDU_BSSAP_LE {
+ BIT1 discriminator, // 0 = BSSMAP-LE; 1 = DTAP-LE
+ BIT7 spare, // always '0000000'B
+ OCT1 dlci optional,
+ LIN1 lengthInd