pgw: Support having several DIAMETER_ConnHdlr per PGW_Session_CT

A new intermediate component DIAMETER_ConnHdlr_CT is added which extends
the required DIAMETER_ConnHdlr by the DIAMETER_Emulation, and forwards
it to the PGW_Session_CT. This way, the PGW_Session_CT, which usually
runs the test code, will have access to GTP2, Gx and Gy messages for the
session.

Initial Gy support for PGW_Tests is added in follow-up patch.

Change-Id: I28f1ac0a013e479058f28a6feff6901b33f6c247
diff --git a/pgw/PGW_Tests.ttcn b/pgw/PGW_Tests.ttcn
index 775b904..16bea57 100644
--- a/pgw/PGW_Tests.ttcn
+++ b/pgw/PGW_Tests.ttcn
@@ -37,9 +37,9 @@
 	port GTP2EM_PT TEID0;
 
 	/* emulated PCRF */
-	var DIAMETER_Emulation_CT vc_DIAMETER;
-	port DIAMETER_PT DIAMETER_UNIT;
-	port DIAMETEREM_PROC_PT DIAMETER_PROC;
+	var DIAMETER_Emulation_CT vc_Gx;
+	port DIAMETER_PT Gx_UNIT;
+	port DIAMETEREM_PROC_PT Gx_PROC;
 	/* global test case guard timer (actual timeout value is set in f_init()) */
 	timer T_guard;
 }
@@ -52,10 +52,36 @@
 		}
 }
 
+type component DIAMETER_ConnHdlr_CT extends DIAMETER_ConnHdlr {
+	port DIAMETER_Conn_PT DIAMETER_CLIENT;
+}
+
+function f_diam_connhldr_ct_main(hexstring imsi) runs on DIAMETER_ConnHdlr_CT {
+	var PDU_DIAMETER msg;
+
+	if (DIAMETER_PROC.checkstate("Connected")) {
+		f_diameter_expect(imsi);
+	}
+
+	while (true) {
+		alt {
+		[] DIAMETER_CLIENT.receive(PDU_DIAMETER:?) -> value msg {
+			DIAMETER.send(msg);
+			}
+		[] DIAMETER.receive(PDU_DIAMETER:?) -> value msg {
+			DIAMETER_CLIENT.send(msg);
+			}
+		}
+	}
+}
+
+
 /* per-session component; we typically have 1..N per testcase */
-type component PGW_Session_CT extends GTP2_ConnHdlr, DIAMETER_ConnHdlr {
+type component PGW_Session_CT extends GTP2_ConnHdlr {
 	var SessionPars	g_pars;
 
+	port DIAMETER_Conn_PT Gx;
+
 	/* TEI (Data) local side */
 	var OCT4	g_teid;
 	/* TEI (Control) local side */
@@ -139,13 +165,13 @@
 		auth_app_id := omit,
 		vendor_app_id := c_DIAMETER_3GPP_Gx_AID
 	};
-	vc_DIAMETER := DIAMETER_Emulation_CT.create(id);
-	map(vc_DIAMETER:DIAMETER, system:DIAMETER_CODEC_PT);
-	connect(vc_DIAMETER:DIAMETER_UNIT, self:DIAMETER_UNIT);
-	connect(vc_DIAMETER:DIAMETER_PROC, self:DIAMETER_PROC);
-	vc_DIAMETER.start(DIAMETER_Emulation.main(ops, pars, id));
+	vc_Gx := DIAMETER_Emulation_CT.create(id);
+	map(vc_Gx:DIAMETER, system:DIAMETER_CODEC_PT);
+	connect(vc_Gx:DIAMETER_UNIT, self:Gx_UNIT);
+	connect(vc_Gx:DIAMETER_PROC, self:Gx_PROC);
+	vc_Gx.start(DIAMETER_Emulation.main(ops, pars, id));
 
-	f_diameter_wait_capability(DIAMETER_UNIT);
+	f_diameter_wait_capability(Gx_UNIT);
 	/* Give some time for our emulation to get out of SUSPECT list of SUT (3 watchdong ping-pongs):
 	 * RFC6733 sec 5.1
 	 * RFC3539 sec 3.4.1 [5]
@@ -177,31 +203,38 @@
 	}
 }
 
-function f_start_handler(void_fn fn, template (omit) SessionPars pars := omit)
+function f_start_handler(void_fn fn, template (omit) SessionPars pars_tmpl := omit)
 runs on PGW_Test_CT return PGW_Session_CT {
 	var charstring id := testcasename();
+	var DIAMETER_ConnHdlr_CT vc_conn_gx;
 	var PGW_Session_CT vc_conn;
+	var SessionPars pars;
+
+	if (isvalue(pars_tmpl)) {
+		pars := valueof(pars_tmpl);
+	} else {
+		/*TODO: set default values */
+	}
+
 	vc_conn := PGW_Session_CT.create(id);
 	connect(vc_conn:GTP2, vc_GTP2:CLIENT);
 	connect(vc_conn:GTP2_PROC, vc_GTP2:CLIENT_PROC);
 
-	if (isbound(vc_DIAMETER)) {
-		connect(vc_conn:DIAMETER, vc_DIAMETER:DIAMETER_CLIENT);
-		connect(vc_conn:DIAMETER_PROC, vc_DIAMETER:DIAMETER_PROC);
+	if (isbound(vc_Gx)) {
+		vc_conn_gx := DIAMETER_ConnHdlr_CT.create(id);
+		connect(vc_conn_gx:DIAMETER, vc_Gx:DIAMETER_CLIENT);
+		connect(vc_conn_gx:DIAMETER_PROC, vc_Gx:DIAMETER_PROC);
+		connect(vc_conn:Gx, vc_conn_gx:DIAMETER_CLIENT);
+		vc_conn_gx.start(f_diam_connhldr_ct_main(pars.imsi));
 	}
 
 	vc_conn.start(f_handler_init(fn, pars));
 	return vc_conn;
 }
 
-private function f_handler_init(void_fn fn, template (omit) SessionPars pars := omit)
+private function f_handler_init(void_fn fn, SessionPars pars)
 runs on PGW_Session_CT {
-	if (isvalue(pars)) {
-		g_pars := valueof(pars);
-	}
-	if (DIAMETER_PROC.checkstate("Connected")) {
-		f_diameter_expect(g_pars.imsi);
-	}
+	g_pars := valueof(pars);
 	fn.apply();
 }
 
@@ -225,9 +258,9 @@
 	return f_concat_pad(12, '49123'H, suffix);
 }
 
-private altstep as_DIA_CCR(DCC_NONE_CC_Request_Type req_type) runs on PGW_Session_CT {
+private altstep as_DIA_Gx_CCR(DCC_NONE_CC_Request_Type req_type) runs on PGW_Session_CT {
 	var PDU_DIAMETER rx_dia;
-	[] DIAMETER.receive(tr_DIA_Gx_CCR(req_type := req_type)) -> value rx_dia {
+	[] Gx.receive(tr_DIA_Gx_CCR(req_type := req_type)) -> value rx_dia {
 		var template (omit) AVP avp;
 		var octetstring sess_id;
 		var AVP_Unsigned32 req_num;
@@ -238,10 +271,10 @@
 		avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_DCC_NONE_CC_Request_Number);
 		req_num := valueof(avp.avp_data.avp_DCC_NONE_CC_Request_Number);
 
-		DIAMETER.send(ts_DIA_Gx_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id,
+		Gx.send(ts_DIA_Gx_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id,
 					 req_type, req_num));
 	}
-	[] DIAMETER.receive(PDU_DIAMETER:?) -> value rx_dia {
+	[] Gx.receive(PDU_DIAMETER:?) -> value rx_dia {
 		setverdict(fail, "Received unexpected DIAMETER ", rx_dia);
 		self.stop;
 	}
@@ -330,8 +363,8 @@
 	g2c.gtpcv2_pdu.createSessionRequest.servingNetwork := ts_GTP2C_ServingNetwork('001'H, '01F'H);
 
 	GTP2.send(g2c);
-	if (DIAMETER_PROC.checkstate("Connected")) {
-		as_DIA_CCR(INITIAL_REQUEST);
+	if (Gx.checkstate("Connected")) {
+		as_DIA_Gx_CCR(INITIAL_REQUEST);
 	}
 	alt {
 	[] GTP2.receive(tr_GTP2C_CreateSessionResp(d_teid:=g_teic, cause:='10'O)) -> value rx {
@@ -389,8 +422,8 @@
 					  teid_list := {}, bearer_id := 1);
 
 	GTP2.send(g2c);
-	if (DIAMETER_PROC.checkstate("Connected") and expect_diameter) {
-		as_DIA_CCR(TERMINATION_REQUEST);
+	if (Gx.checkstate("Connected") and expect_diameter) {
+		as_DIA_Gx_CCR(TERMINATION_REQUEST);
 	}
 	alt {
 	[] GTP2.receive(tr_GTP2C_DeleteSessionResp(d_teid := exp_teid, cause := exp_cause)) {