BSC_Tests: Start with much simpler tests at BSSAP / SCCP level

Rather than using the more complex RSL Emulation and BSSAP emulation
components, we attach to the RSL and BSSAP Codec Ports and send some
messages back and forth for low-level testing such as timeouts, response
to RACH requests, failure of MSC to react to CR requests, etc.
diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn
index 9b26800..55d54a3 100644
--- a/bsc/BSC_Tests.ttcn
+++ b/bsc/BSC_Tests.ttcn
@@ -1,126 +1,213 @@
 module BSC_Tests {
 
 import from Osmocom_Types all;
-
+import from GSM_Types all;
 import from IPL4asp_Types all;
 
+import from BSSAP_Adapter all;
+import from BSSAP_CodecPort all;
+import from BSSMAP_Templates all;
 import from IPA_Emulation all;
+import from IPA_Types all;
+import from RSL_Types all;
 
-import from MTP3asp_Types all;
+import from RSL_Tests all;
 
-import from SCCP_Types all;
-import from SCCPasp_Types all;
-import from SCCP_Emulation all;
-
-import from MSC_Simulation all;
-import from BTS_Simulation all;
-
-const integer NUM_MSC := 1;
 const integer NUM_BTS := 1;
+const float T3101_MAX := 12.0;
 
-type record MscState {
-	MSC_CT MSC,
-	MSC_SCCP_MTP3_parameters sccp_pars,
-	SCCP_PAR_Address sccp_addr_own
-}
-
-type record BtsState {
-	BTS_CT BTS
-}
-
-type component test_CT {
-	var MscState msc[NUM_MSC];
-	var BtsState bts[NUM_BTS];
+type component test_CT extends BSSAP_Adapter_CT {
+	var IPA_Client bts[NUM_BTS];
+	port IPA_RSL_PT IPA_RSL[NUM_BTS];
 
 	var boolean g_initialized := false;
-	var octetstring g_sio := '83'O;
+	timer T_guard := 30.0;
+
 }
 
 modulepar {
-	PortNumber mp_msc_port := 5000;
-	charstring mp_msc_ip := "127.0.0.1";
-
-	charstring mp_sccp_service_type := "mtp3_itu";
-
-	integer mp_bsc_pc := 196;
-	integer mp_bsc_ssn := 254;
-
-	integer mp_msc_pc := 185;	/* 0.23.1 */
-	integer mp_msc_ssn := 254;
-
 	charstring mp_bsc_ip := "127.0.0.1";
 	integer mp_bsc_rsl_port := 3003;
 }
 
-/* construct a SCCP_PAR_Address with just PC + SSN and no GT */
-template (value) SCCP_PAR_Address ts_SccpAddr_PC_SSN(integer pc, integer ssn) := {
-	addressIndicator := {
-		pointCodeIndic := '1'B,
-		ssnIndicator := '1'B,
-		globalTitleIndic := '0000'B,
-		routingIndicator := '1'B
-	},
-	signPointCode := SCCP_SPC_int2bit(pc, mp_sccp_service_type, '83'O),
-	//signPointCode := SCCP_SPC_int2bit(pc, mp_sccp_service_type, g_sio),
-	subsystemNumber := ssn,
-	globalTitle := omit
+type record IPA_Client {
+	IPA_Emulation_CT vc_IPA,
+	IPA_CCM_Parameters ccm_pars,
+	charstring id
 }
 
-template MTP3_Field_sio ts_sio(octetstring sio_in) := {
-	ni := substr(oct2bit(sio_in),0,2),
-	prio := substr(oct2bit(sio_in),2,2),
-	si := substr(oct2bit(sio_in),4,4)
-}
-
-template MSC_SCCP_MTP3_parameters ts_SCCP_Pars(octetstring sio, integer opc, integer dpc,
-						integer local_ssn) := {
-	sio := ts_sio(sio),
-	opc := opc,
-	dpc := dpc,
-	sls := 0,
-	sccp_serviceType := mp_sccp_service_type,
-	ssn := local_ssn
-};
-
-function f_init_MscState(inout MscState msc_st, integer opc, integer dpc, integer local_ssn, integer remote_ssn)
+function f_ipa_rsl_start(inout IPA_Client clnt, charstring bsc_host, PortNumber bsc_port, integer i)
 runs on test_CT {
-	msc_st.sccp_pars := valueof(ts_SCCP_Pars(g_sio, opc, dpc, local_ssn));
-	msc_st.sccp_addr_own := valueof(ts_SccpAddr_PC_SSN(opc, local_ssn));
+	timer T := 10.0;
+
+	clnt.id := "IPA" & int2str(i);
+	clnt.vc_IPA := IPA_Emulation_CT.create(clnt.id & "-IPA");
+	clnt.ccm_pars := c_IPA_default_ccm_pars;
+	clnt.ccm_pars.name := "Osmocom TTCN-3 BTS Simulator";
+	clnt.ccm_pars.unit_id := int2str(1234+i) & "/0/0";
+
+	map(clnt.vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
+	connect(clnt.vc_IPA:IPA_RSL_PORT, self:IPA_RSL[i]);
+
+	clnt.vc_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", -1, clnt.ccm_pars));
+
+	/* 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}) {
+		T.stop;
+		IPA_RSL[i].send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_PAGING_LOAD_IND(23)));
+		}
+	[] IPA_RSL[i].receive { repeat }
+	[] T.timeout {
+		setverdict(fail, "Timeout waiting for ASP_IPA_EVENT_ID_ACK");
+		self.stop;
+		}
+	}
+}
+
+function f_sleep(float seconds) {
+	timer T := seconds;
+	T.start;
+	T.timeout;
+}
+
+altstep as_Tguard() runs on test_CT {
+	[] T_guard.timeout { setverdict(fail, "Timeout of T_guard"); }
 }
 
 function f_init() runs on test_CT {
 	var integer i;
-	var charstring id;
 
-	for (i := 0; i < NUM_MSC; i := i+1) {
-		f_init_MscState(msc[i], mp_msc_pc +i, mp_bsc_pc, mp_msc_ssn, mp_bsc_ssn);
-		msc[i].MSC := MSC_CT.create;
-		id := "MSC" & int2str(i);
-		msc[i].MSC.start(MSC_Simulation.main(mp_msc_ip, mp_msc_port + i, msc[i].sccp_pars, msc[i].sccp_addr_own, id));
+	if (g_initialized) {
+		return;
 	}
+	g_initialized := true;
+
+	/* Call a function of our 'parent component' BSSAP_Adapter_CT to start the
+	 * MSC-side BSSAP emulation */
+	f_bssap_init("VirtMSC");
+
+	f_sleep(5.0);
 
 	for (i := 0; i < NUM_BTS; i := i+1) {
-		bts[i].BTS := BTS_CT.create;
-		id := "BTS" & int2str(i);
-		bts[i].BTS.start(BTS_Simulation.main(mp_bsc_ip, mp_bsc_rsl_port, id));
+		f_ipa_rsl_start(bts[i], mp_bsc_ip, mp_bsc_rsl_port, i);
 	}
+	f_sleep(0.5);
 
+	T_guard.start;
+	activate(as_Tguard());
 }
 
-testcase TC_recv_dump() runs on test_CT {
-	var integer i;
-	timer T := 30.0;
+function f_exp_ipa_rx(integer bts_nr, template 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 {
+		T.stop;
+		}
+	[] IPA_RSL[bts_nr].receive { repeat; }
+	[] T.timeout { setverdict(fail, "Timeout expecting ", t_rx); }
+	}
+	return rx_rsl_ud.rsl;
+}
+
+function f_ipa_tx(integer bts_nr, template 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));
+}
+
+
+testcase TC_chan_act_noreply() runs on test_CT {
+	var BSSAP_N_UNITDATA_ind ud_ind;
 
 	f_init();
+	f_bssap_reset();
 
-	alt {
-		[] msc[0].MSC.done { }
-		[] T.timeout { setverdict(fail); }
-	}
+	IPA_RSL[0].send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_CHAN_RQD('23'O, 23)));
+	f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+	setverdict(pass);
 }
 
+/* CHAN RQD -> CHAN ACT -> CHAN ACT ACK -> RF CHAN REL */
+testcase TC_chan_act_ack_noest() runs on test_CT {
+	var RSL_Message rx_rsl;
+
+	f_init();
+	f_bssap_reset();
+
+	/* Send CHAN RQD and wait for allocation; acknowledge it */
+	f_ipa_tx(0, ts_RSL_CHAN_RQD('23'O, 23));
+	rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+	var RslChannelNr chan_nr := rx_rsl.ies[0].body.chan_nr;
+	f_ipa_tx(0, ts_RSL_CHAN_ACT_ACK(chan_nr, 23));
+
+	/* 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);
+
+	setverdict(pass);
+}
+
+/* Test behavior if MSC never answers to CR */
+testcase TC_chan_act_ack_est_ind_noreply() runs on test_CT {
+	var RSL_Message rx_rsl;
+
+	f_init();
+	f_bssap_reset();
+
+	/* Send CHAN RQD and wait for allocation; acknowledge it */
+	f_ipa_tx(0, ts_RSL_CHAN_RQD('23'O, 23));
+	rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+	var RslChannelNr chan_nr := rx_rsl.ies[0].body.chan_nr;
+	f_ipa_tx(0, ts_RSL_CHAN_ACT_ACK(chan_nr, 23));
+
+	var octetstring l3 := '00010203040506'O
+	f_ipa_tx(0, ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3));
+
+	BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3)));
+
+	/* expect BSC to disable the channel again if there's no response from MSC */
+	rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), T3101_MAX);
+
+	setverdict(pass);
+}
+
+/* Test behavior if MSC answers with CREF to CR */
+testcase TC_chan_act_ack_est_ind_refused() runs on test_CT {
+	var BSSAP_N_CONNECT_ind rx_c_ind;
+	var RSL_Message rx_rsl;
+
+	f_init();
+	f_bssap_reset();
+
+	/* Send CHAN RQD and wait for allocation; acknowledge it */
+	f_ipa_tx(0, ts_RSL_CHAN_RQD('23'O, 23));
+	rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV));
+	var RslChannelNr chan_nr := rx_rsl.ies[0].body.chan_nr;
+	f_ipa_tx(0, ts_RSL_CHAN_ACT_ACK(chan_nr, 23));
+
+	var octetstring l3 := '00010203040506'O
+	f_ipa_tx(0, ts_RSL_EST_IND(chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3));
+
+	BSSAP.receive(tr_BSSAP_CONNECT_ind(?, ?, tr_BSSMAP_ComplL3(l3))) -> value rx_c_ind;
+	BSSAP.send(ts_BSSAP_DISC_req(rx_c_ind.connectionId, 0));
+
+	/* expect BSC to disable the channel */
+	rx_rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL), T3101_MAX);
+
+	setverdict(pass);
+}
+
+
+
 control {
-	execute( TC_recv_dump() );
+	execute( TC_chan_act_noreply() );
+	execute( TC_chan_act_ack_noest() );
+	execute( TC_chan_act_ack_est_ind_noreply() );
+	execute( TC_chan_act_ack_est_ind_refused() );
 }
 
 }