RAW_NS: rework NS connection to use NS_Provider

Previous RAW_NS only supported NS over UDP because
it handled the UDP connection on it's own.
Because of this there was no cleanup function for the tests
because no virtual component were started.
Using the new NS_Provider allows to use the same tests over
UDP and FR with no changes.

Change-Id: I8a3b6c72798a75f434f54229fdbfc802cd13967e
diff --git a/library/RAW_NS.ttcnpp b/library/RAW_NS.ttcnpp
new file mode 100644
index 0000000..c8fc518
--- /dev/null
+++ b/library/RAW_NS.ttcnpp
@@ -0,0 +1,260 @@
+module RAW_NS {
+
+/* Osmocom NS test suite for NS in TTCN-3
+ * (C) 2018-2019 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 Misc_Helpers all;
+import from General_Types all;
+import from Osmocom_Types all;
+import from Osmocom_Gb_Types all;
+import from NS_Emulation all;
+import from NS_Types all;
+import from BSSGP_Types all;
+import from NS_Emulation all;
+import from Native_Functions all;
+import from IPL4asp_Types all;
+import from NS_Provider_IPL4 all;
+#ifdef NS_EMULATION_FR
+import from NS_Provider_FR all;
+#endif
+
+public type component RAW_NS_CT {
+	/* UDP port towards the bottom (IUT) */
+	port NS_PROVIDER_PT NSCP[4];
+	var NS_Provider_IPL4_CT vc_NSP_IP[4];
+#ifdef NS_EMULATION_FR
+	var NS_Provider_FR_CT vc_NSP_FR[4];
+#endif
+	var NSConfiguration g_nsconfig;
+	timer g_T_guard;
+}
+
+public altstep as_Tguard() runs on RAW_NS_CT {
+	[] g_T_guard.timeout {
+		setverdict(fail, "Timeout of T_guard");
+		mtc.stop;
+		}
+}
+
+function f_init_ns_codec(NSConfiguration ns_config, integer idx := 0, float guard_secs := 60.0, charstring id := testcasename()) runs on RAW_NS_CT {
+	var Result res;
+
+	if (not g_T_guard.running) {
+		g_T_guard.start(guard_secs);
+		activate(as_Tguard());
+	}
+
+	if (not isbound(g_nsconfig)) {
+		g_nsconfig := ns_config;
+	}
+
+	if (ischosen(ns_config.nsvc[idx].provider.ip)) {
+		/* Connect the UDP socket */
+		vc_NSP_IP[idx] := NS_Provider_IPL4_CT.create(id & "-provIP");
+		connect(self:NSCP[idx], vc_NSP_IP[idx]:NSE);
+		vc_NSP_IP[idx].start(NS_Provider_IPL4.main(ns_config.nsvc[idx], ns_config, id));
+#ifdef NS_EMULATION_FR
+	} else if (ischosen(ns_config.nsvc[idx].provider.fr)) {
+		vc_NSP_FR[idx] := NS_Provider_FR_CT.create(id & "-provFR");
+		connect(self:NSCP[idx], vc_NSP_FR[idx]:NSE);
+		vc_NSP_FR[idx].start(NS_Provider_FR.main(ns_config.nsvc[idx], ns_config, id));
+#endif
+	} else {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unsupported NS provider");
+	}
+
+	NSCP[idx].receive(NS_Provider_Evt:{link_status:=NS_PROV_LINK_STATUS_UP});
+}
+
+function f_clean_ns_codec() runs on RAW_NS_CT {
+	for (var integer i := 0; i < lengthof(vc_NSP_IP); i := i + 1) {
+		vc_NSP_IP[i].stop;
+	}
+#ifdef NS_EMULATION_FR
+	for (var integer i := 0; i < lengthof(vc_NSP_FR); i := i + 1) {
+		vc_NSP_FR[i].stop;
+	}
+#endif NS_EMULATION_FR
+}
+
+public altstep ax_rx_fail_on_any_ns(integer idx := 0) runs on RAW_NS_CT {
+	var PDU_NS nrf;
+	[] NSCP[idx].receive(PDU_NS: ?) -> value nrf {
+		setverdict(fail, "Received unexpected NS: ", nrf);
+		mtc.stop;
+		}
+}
+
+function f_ns_exp(template PDU_NS exp_rx, integer idx := 0) runs on RAW_NS_CT return PDU_NS {
+	var PDU_NS nrf;
+	log("f_ns_exp() expecting ", exp_rx);
+	/* last activated altstep has the lowest priority */
+	var default d := activate(ax_rx_fail_on_any_ns());
+	alt {
+	[] NSCP[idx].receive(PDU_NS: exp_rx) -> value nrf { }
+	}
+	deactivate(d);
+	return nrf;
+}
+
+/* perform outbound NS-ALIVE procedure */
+function f_outgoing_ns_alive(integer idx := 0) runs on RAW_NS_CT {
+	NSCP[idx].send(t_NS_ALIVE);
+	alt {
+	[] NSCP[idx].receive(t_NS_ALIVE_ACK);
+	[] NSCP[idx].receive { repeat; }
+	}
+}
+
+/* perform outbound NS-ALIVE procedure */
+function f_outgoing_ns_alive_no_ack(integer idx := 0, float tout := 10.0) runs on RAW_NS_CT {
+	timer T := tout;
+	NSCP[idx].send(t_NS_ALIVE);
+	T.start;
+	alt {
+	[] NSCP[idx].receive(t_NS_ALIVE_ACK) {
+		setverdict(fail, "Received unexpected NS-ALIVE ACK");
+		}
+	[] NSCP[idx].receive { repeat; }
+	[] T.timeout {
+		setverdict(pass);
+		}
+	}
+}
+
+function f_outgoing_ns_reset(integer idx := 0, float tout := 10.0) runs on RAW_NS_CT {
+	timer T := tout;
+	var template PDU_NS reset := ts_NS_RESET(NS_CAUSE_EQUIPMENT_FAILURE, g_nsconfig.nsvc[idx].nsvci, g_nsconfig.nsei)
+	NSCP[idx].send(reset);
+	T.start;
+	alt {
+	[] NSCP[idx].receive(ts_NS_RESET_ACK(g_nsconfig.nsvc[idx].nsvci, g_nsconfig.nsei)) {
+		setverdict(pass);
+		}
+	[] NSCP[idx].receive { repeat; }
+	[] T.timeout {
+		setverdict(fail, "Failed to receive a RESET ACK");
+		}
+	}
+}
+
+/* perform outbound NS-BLOCK procedure */
+function f_outgoing_ns_block(NsCause cause, integer idx := 0) runs on RAW_NS_CT {
+	NSCP[idx].send(ts_NS_BLOCK(cause, g_nsconfig.nsvc[idx].nsvci));
+	alt {
+	[] NSCP[idx].receive(tr_NS_BLOCK_ACK(g_nsconfig.nsvc[idx].nsvci));
+	[] NSCP[idx].receive { repeat; }
+	}
+}
+
+/* perform outbound NS-UNBLOCK procedure */
+function f_outgoing_ns_unblock(integer idx := 0) runs on RAW_NS_CT {
+	NSCP[idx].send(t_NS_UNBLOCK);
+	alt {
+	[] NSCP[idx].receive(t_NS_UNBLOCK_ACK);
+	[] NSCP[idx].receive { repeat; }
+	}
+}
+
+/* receive NS-ALIVE and ACK it */
+altstep as_rx_alive_tx_ack(boolean oneshot := false, integer idx := 0) runs on RAW_NS_CT {
+	[] NSCP[idx].receive(t_NS_ALIVE) {
+		NSCP[idx].send(t_NS_ALIVE_ACK);
+		if (not oneshot) { repeat; }
+		}
+}
+
+/* Transmit BSSGP RESET for given BVCI and expect ACK */
+function f_tx_bvc_reset_rx_ack(BssgpBvci bvci, template (omit) BssgpCellId tx_cell_id, template BssgpCellId rx_cell_id,
+			       integer idx := 0, boolean exp_ack := true)
+runs on RAW_NS_CT {
+	var PDU_BSSGP bssgp_tx := valueof(ts_BVC_RESET(BSSGP_CAUSE_NET_SV_CAP_MOD_GT_ZERO_KBPS, bvci,
+						       tx_cell_id));
+	timer T := 5.0;
+	NSCP[idx].send(ts_NS_UNITDATA(t_SduCtrlB, 0, enc_PDU_BSSGP(bssgp_tx)));
+	T.start;
+	alt {
+	[exp_ack] NSCP[idx].receive(tr_NS_UNITDATA(t_SduCtrlB, 0,
+						   decmatch tr_BVC_RESET_ACK(bvci, rx_cell_id))) {
+		setverdict(pass);
+		}
+	[exp_ack] T.timeout {
+		setverdict(fail, "No response to BVC-RESET");
+		}
+	[not exp_ack] T.timeout {
+		setverdict(pass);
+		}
+	[] NSCP[idx].receive { repeat; }
+	}
+}
+
+/* Receive a BSSGP RESET for given BVCI and ACK it */
+altstep as_rx_bvc_reset_tx_ack(BssgpBvci bvci, template BssgpCellId rx_cell_id, template (omit) BssgpCellId tx_cell_id,
+				boolean oneshot := false, integer idx := 0) runs on RAW_NS_CT {
+	var PDU_NS ns_rf;
+	[] NSCP[idx].receive(tr_NS_UNITDATA(t_SduCtrlB, 0,
+						  decmatch tr_BVC_RESET(?, bvci, rx_cell_id)))
+								-> value ns_rf {
+		var PDU_BSSGP bssgp_rx := dec_PDU_BSSGP(ns_rf.pDU_NS_Unitdata.nS_SDU);
+		var PDU_BSSGP bssgp_tx := valueof(ts_BVC_RESET_ACK(bvci, tx_cell_id));
+		NSCP[idx].send(ts_NS_UNITDATA(t_SduCtrlB, 0, enc_PDU_BSSGP(bssgp_tx)));
+		if (not oneshot) { repeat; }
+		}
+}
+
+
+/* Receive a BSSGP UNBLOCK for given BVCI and ACK it */
+altstep as_rx_bvc_unblock_tx_ack(BssgpBvci bvci, boolean oneshot := false, integer idx := 0) runs on RAW_NS_CT {
+	var PDU_NS ns_rf;
+	[] NSCP[idx].receive(tr_NS_UNITDATA(t_SduCtrlB, 0, decmatch t_BVC_UNBLOCK(bvci))) -> value ns_rf {
+		var PDU_BSSGP bssgp_rx := dec_PDU_BSSGP(ns_rf.pDU_NS_Unitdata.nS_SDU);
+		var PDU_BSSGP bssgp_tx := valueof(t_BVC_UNBLOCK_ACK(bvci));
+		NSCP[idx].send(ts_NS_UNITDATA(t_SduCtrlB, 0, enc_PDU_BSSGP(bssgp_tx)));
+		if (not oneshot) { repeat; }
+		}
+}
+
+/* Receive a BSSGP FLOW-CONTROL-BVC and ACK it */
+altstep as_rx_bvc_fc_tx_ack(BssgpBvci bvci, boolean oneshot := false, integer idx := 0) runs on RAW_NS_CT {
+	var PDU_NS ns_rf;
+	[] NSCP[idx].receive(tr_NS_UNITDATA(t_SduCtrlB, bvci,
+					    decmatch tr_BVC_FC_BVC))
+								-> value ns_rf {
+		var PDU_BSSGP bssgp_rx := dec_PDU_BSSGP(ns_rf.pDU_NS_Unitdata.nS_SDU);
+		var OCT1 tag := bssgp_rx.pDU_BSSGP_FLOW_CONTROL_BVC.tag.unstructured_Value;
+		var PDU_BSSGP bssgp_tx := valueof(t_BVC_FC_BVC_ACK(tag));
+		NSCP[idx].send(ts_NS_UNITDATA(t_SduCtrlB, bvci, enc_PDU_BSSGP(bssgp_tx)));
+		if (not oneshot) { repeat; }
+		}
+}
+
+/**********************************************************************************
+ * Classic Gb/IP bring-up test cases using NS-{RESET,BLOCK,UNBLOCK} and no IP-SNS *
+ **********************************************************************************/
+
+/* Receive a NS-RESET and ACK it */
+public altstep as_rx_ns_reset_ack(boolean oneshot := false, integer idx := 0) runs on RAW_NS_CT {
+	var PDU_NS ns_rf;
+	[] NSCP[idx].receive(tr_NS_RESET(NS_CAUSE_OM_INTERVENTION, g_nsconfig.nsvc[idx].nsvci,
+						  g_nsconfig.nsei)) -> value ns_rf {
+		NSCP[idx].send(ts_NS_RESET_ACK(g_nsconfig.nsvc[idx].nsvci, g_nsconfig.nsei));
+		if (not oneshot) { repeat; }
+		}
+}
+/* Receive a NS-UNBLOCK and ACK it */
+public altstep as_rx_ns_unblock_ack(boolean oneshot := false, integer idx := 0) runs on RAW_NS_CT {
+	var PDU_NS ns_rf;
+	[] NSCP[idx].receive(t_NS_UNBLOCK) -> value ns_rf {
+		NSCP[idx].send(t_NS_UNBLOCK_ACK);
+		if (not oneshot) { repeat; }
+		}
+}
+
+}