bsc: Introduce Osmux infra and one test for osmo-bsc

Test verifies once osmux is enabled in osmo-bsc, BSSMAP RESET (ACK)
contains Osmux Support IE and that it correctly handles BSSMAP ASsign
Req with Osmux CID.

Related: OS#2551
Depends: osmo-bsc 6de754cdde5319af3059d8fc6abf85037ec7eacc
Depends: titan.ProtocolModules.BSSMAP Iaf1e137269c0da20b2c96fd104b57edf336693af
Change-Id: If69c716dc06d61d810c32d1720a237c7535baca8
diff --git a/bsc/BSC_Tests.ttcn b/bsc/BSC_Tests.ttcn
index 0583b30..c731b7c 100644
--- a/bsc/BSC_Tests.ttcn
+++ b/bsc/BSC_Tests.ttcn
@@ -89,6 +89,9 @@
 	/* are we initialized yet */
 	var boolean g_initialized := false;
 
+	/* Osmux is enabled through VTY */
+	var boolean g_osmux_enabled := false;
+
 	/* global test case guard timer */
 	timer T_guard := 30.0;
 
@@ -140,16 +143,16 @@
 private function f_legacy_bssap_reset() runs on test_CT {
 	var BSSAP_N_UNITDATA_ind ud_ind;
 	timer T := 5.0;
-	BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.sccp_addr_own, ts_BSSMAP_Reset(0)));
+	BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.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)) {
+	[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.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)) -> value ud_ind {
+	[] 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));
+			   ts_BSSMAP_ResetAck(g_osmux_enabled)));
 		repeat;
 		}
 	[] BSSAP.receive { repeat; }
@@ -257,15 +260,15 @@
 			mtc.stop;
 		}
 	/* always respond with RESET ACK to RESET */
-	[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset)) -> value ud_ind {
+	[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled))) -> value ud_ind {
 		BSSAP.send(ts_BSSAP_UNITDATA_req(ud_ind.callingAddress, ud_ind.calledAddress,
-			   ts_BSSMAP_ResetAck));
+			   ts_BSSMAP_ResetAck(g_osmux_enabled)));
 		repeat;
 		}
 }
 
 altstep no_bssmap_reset() runs on test_CT {
-	[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset)) {
+	[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(?, ?, tr_BSSMAP_Reset(g_osmux_enabled))) {
 		setverdict(fail, "unexpected BSSMAP Reset");
 		mtc.stop;
 	}
@@ -289,6 +292,22 @@
 	vc_MGCP.start(MGCP_Emulation.main(ops, mgcp_pars, id));
 }
 
+/* Enable or disable (current default) Osmux. When enabling, BSSMAP Reset
+ * contains extra IE (OsmuxSupport) and osmo-bsc will handle AssignReq with
+ * OsmuxCID IE.
+ */
+private function f_vty_allow_osmux(boolean allow) runs on test_CT {
+	f_vty_enter_cfg_msc(BSCVTY, 0);
+	if (allow) {
+		f_vty_transceive(BSCVTY, "osmux on");
+	} else {
+		f_vty_transceive(BSCVTY, "osmux off");
+	}
+	f_vty_transceive(BSCVTY, "exit");
+	f_vty_transceive(BSCVTY, "exit");
+	g_osmux_enabled := allow;
+}
+
 function f_init_vty(charstring id := "foo") runs on test_CT {
 	if (BSCVTY.checkstate("Mapped")) {
 		/* skip initialization if already executed once */
@@ -302,7 +321,7 @@
 /* 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) runs on test_CT {
+function f_init(integer nr_bts := NUM_BTS, boolean handler_mode := false, boolean allow_osmux := false) runs on test_CT {
 	var integer i;
 
 	if (g_initialized) {
@@ -313,10 +332,15 @@
 	T_guard.start;
 	activate(as_Tguard());
 
+	f_init_vty("VirtMSC");
+	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) {
-		f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", MSC_RanOps);
+		var RanOps ranops := MSC_RanOps;
+		ranops.use_osmux := g_osmux_enabled;
+		f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", ranops);
 		f_ran_adapter_start(g_bssap);
 	} else {
 		f_ran_adapter_init(g_bssap, mp_bssap_cfg, "VirtMSC", omit);
@@ -328,7 +352,6 @@
 	f_ipa_ctrl_start(mp_bsc_ip, mp_bsc_ctrl_port);
 
 	f_init_mgcp("VirtMSC");
-	f_init_vty("VirtMSC");
 
 	for (i := 0; i < nr_bts; i := i+1) {
 		/* wait until osmo-bts-omldummy has respawned */
@@ -605,15 +628,24 @@
 }
 
 /* generate an assignment request for either AoIP or SCCPlite */
-function f_gen_ass_req() return PDU_BSSAP {
+function f_gen_ass_req(boolean osmux_enabled := false) 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) {
 		var BSSMAP_IE_AoIP_TransportLayerAddress tla :=
 						valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
-		ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla));
+		if (osmux_enabled) {
+			ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla, osmux_cid));
+		} else {
+			ass_cmd := valueof(ts_BSSMAP_AssignmentReq(omit, tla));
+		}
 	} else {
 		var BSSMAP_IE_CircuitIdentityCode cic := valueof(ts_BSSMAP_IE_CIC(0,1));
-		ass_cmd := valueof(ts_BSSMAP_AssignmentReq(cic, omit));
+		if (osmux_enabled) {
+			ass_cmd := valueof(ts_BSSMAP_AssignmentReq(cic, omit, osmux_cid));
+		} else {
+			ass_cmd := valueof(ts_BSSMAP_AssignmentReq(cic, omit));
+		}
 	}
 	return ass_cmd;
 }
@@ -632,13 +664,22 @@
 }
 
 /* generate an assignment complete template for either AoIP or SCCPlite */
-function f_gen_exp_compl() return template PDU_BSSAP {
+function f_gen_exp_compl(boolean expect_osmux := false) 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) {
-		exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?);
+		if (expect_osmux) {
+			exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?, osmux_cid);
+		} else {
+			exp_compl := tr_BSSMAP_AssignmentComplete(omit, ?, omit);
+		}
 	} else {
 		/* CIC is optional "*" as the MSC allocated it */
-		exp_compl := tr_BSSMAP_AssignmentComplete(*, omit);
+		if (expect_osmux) {
+			exp_compl := tr_BSSMAP_AssignmentComplete(*, omit, osmux_cid);
+		} else {
+			exp_compl := tr_BSSMAP_AssignmentComplete(*, omit);
+		}
 	}
 	return exp_compl;
 }
@@ -1002,9 +1043,9 @@
 	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)));
+	BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.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)) { }
+	[] 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_DISC_ind(dt.sccp_conn_id, ?, ?)) { }
 	}
 
@@ -1491,9 +1532,9 @@
 	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)));
+	BSSAP.send(ts_BSSAP_UNITDATA_req(g_bssap.sccp_addr_peer, g_bssap.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)) { }
+	[] BSSAP.receive(tr_BSSAP_UNITDATA_ind(g_bssap.sccp_addr_own, g_bssap.sccp_addr_peer, tr_BSSMAP_ResetAck(g_osmux_enabled))) { }
 	[] BSSAP.receive { repeat; }
 	}
 
@@ -1945,8 +1986,8 @@
 type record of CodecListTest CodecListTests
 
 private function f_TC_assignment_codec(charstring id) runs on MSC_ConnHdlr {
-	var PDU_BSSAP ass_cmd := f_gen_ass_req();
-	var template PDU_BSSAP exp_compl := f_gen_exp_compl();
+	var PDU_BSSAP ass_cmd := f_gen_ass_req(g_pars.use_osmux);
+	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) {
@@ -2568,6 +2609,31 @@
 	setverdict(pass);
 }
 
+testcase TC_assignment_osmux() runs on test_CT {
+	var TestHdlrParams pars := f_gen_test_hdlr_pars();
+	var MSC_ConnHdlr vc_conn;
+
+	/* See note above */
+	var RSL_IE_Body mr_conf := {
+		other := {
+			len := 2,
+			payload := '2804'O
+		}
+	};
+
+	pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecAMR_H}));
+	pars.ass_codec_list.codecElements[0].s0_7 := '00000100'B; /* 5,90k */
+	pars.ass_codec_list.codecElements[0].s8_15 := '00000111'B;
+	pars.expect_mr_conf_ie := mr_conf;
+	pars.use_osmux := true;
+
+	f_init(1, true, true);
+	f_sleep(1.0);
+
+	vc_conn := f_start_handler(refers(f_TC_assignment_codec), pars);
+	vc_conn.done;
+}
+
 /* test the procedure of the MSC requesting a Classmark Update:
  * a) BSSMAP Classmark Request should result in RR CLASSMARK ENQUIRY,
  * b) L3 RR CLASSMARK CHANGE should result in BSSMAP CLASSMARK UPDATE */
@@ -3993,6 +4059,8 @@
 	execute( TC_assignment_codec_req_hr_fr() );
 	execute( TC_assignment_codec_req_fr_hr() );
 
+	execute( TC_assignment_osmux() );
+
 	/* RLL Establish Indication on inactive DCHAN / SAPI */
 	execute( TC_rll_est_ind_inact_lchan() );
 	execute( TC_rll_est_ind_inval_sapi1() );