ggsn: Improve checks around Gy messages

Change-Id: I702796f2f941b78da904faa2ffdba4185333bc0d
diff --git a/ggsn_tests/GGSN_Tests.ttcn b/ggsn_tests/GGSN_Tests.ttcn
index 965dcbe..ae2a9bf 100644
--- a/ggsn_tests/GGSN_Tests.ttcn
+++ b/ggsn_tests/GGSN_Tests.ttcn
@@ -130,9 +130,11 @@
 		var integer g_use_echo_intval := 0; /* 0 = disabled */
 
 		/* emulated PCRF, used with m_ggsn_impl = GGSN_IMPL_OPEN5GS */
+		var DIAMETER_conn_parameters g_gx_pars;
 		var DIAMETER_Emulation_CT vc_Gx;
 		port DIAMETER_PT Gx_UNIT;
 		port DIAMETEREM_PROC_PT Gx_PROC;
+		var DIAMETER_conn_parameters g_gy_pars;
 		var DIAMETER_Emulation_CT vc_Gy;
 		port DIAMETER_PT Gy_UNIT;
 		port DIAMETEREM_PROC_PT Gy_PROC;
@@ -212,10 +214,9 @@
 			unitdata_cb := refers(DiameterForwardUnitdataCallback),
 			raw := true /* handler mode (single component for all IMSI)) */
 		};
-		var DIAMETER_conn_parameters pars;
 
 		/* Gx setup: */
-		pars := {
+		g_gx_pars := {
 			remote_ip := m_ggsn_ip_gtpc,
 			remote_sctp_port := -1,
 			local_ip := m_bind_ip_gtpc,
@@ -229,10 +230,10 @@
 		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));
+		vc_Gx.start(DIAMETER_Emulation.main(ops, g_gx_pars, id));
 
 		/* Gy setup: */
-		pars := {
+		g_gy_pars := {
 			remote_ip := m_ggsn_ip_gtpc,
 			remote_sctp_port := -1,
 			local_ip := m_bind_ip_gtpc,
@@ -246,7 +247,7 @@
 		map(vc_Gy:DIAMETER, system:DIAMETER_CODEC_PT);
 		connect(vc_Gy:DIAMETER_UNIT, self:Gy_UNIT);
 		connect(vc_Gy:DIAMETER_PROC, self:Gy_PROC);
-		vc_Gy.start(DIAMETER_Emulation.main(ops, pars, id));
+		vc_Gy.start(DIAMETER_Emulation.main(ops, g_gy_pars, id));
 
 		f_diameter_wait_capability(Gx_UNIT);
 		f_diameter_wait_capability(Gy_UNIT);
@@ -485,9 +486,173 @@
 		}
 	}
 
-	private altstep as_DIA_Gy_CCR(DCC_NONE_CC_Request_Type req_type) runs on GT_CT {
+	private function f_tr_DIA_Gy_CCR(template (omit) PdpContext ctx, DCC_NONE_CC_Request_Type req_type)
+	runs on GT_CT return template (present) PDU_DIAMETER
+	{
+		var template (present) PDU_DIAMETER tpl;
+		var charstring smf_origin_host := "smf.localdomain";
+		var template (present) octetstring imsi := ?;
+		var template (present) octetstring msisdn := ?;
+		var template (present) octetstring imeisv := ?;
+		var template (present) octetstring rat_type := ?;
+		var template (present) OCT4 charging_char := ?;
+		var template (present) OCT1 nsapi := ?;
+		if (not istemplatekind(ctx, "omit")) {
+			var PdpContext ctx_val := valueof(ctx);
+			imsi := char2oct(f_dec_TBCD(imsi_hex2oct(ctx_val.imsi)));
+			msisdn := char2oct(f_dec_TBCD(substr(ctx_val.msisdn, 1, lengthof(ctx_val.msisdn) -1)));
+			imeisv := char2oct(f_dec_TBCD(ctx_val.imeisv));
+			rat_type := ctx_val.ratType;
+			charging_char := char2oct(oct2str(ctx_val.charging_char));
+			nsapi := char2oct(hex2str(bit2hex(ctx_val.nsapi)));
+		}
+		select (req_type) {
+			case (INITIAL_REQUEST) {
+				tpl := tr_DIAMETER(flags:='11000000'B, cmd_code:=Credit_Control,
+					avps := superset(
+						tr_AVP_SessionId,
+						tr_AVP_OriginHost(smf_origin_host),
+						tr_AVP_OriginRealm(g_gy_pars.origin_realm),
+						tr_AVP_DestinationRealm(g_gy_pars.origin_realm),
+						tr_AVP_AuthAppId(int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4)),
+						tr_AVP_ServiceContextId,
+						tr_AVP_CcReqType(req_type),
+						tr_AVP_CcReqNum(?),
+						tr_AVP_EventTimestamp(?),
+						tr_AVP_SubcrId({tr_AVP_SubcrIdType(END_USER_IMSI), tr_AVP_SubcrIdData(imsi)}),
+						tr_AVP_SubcrId({tr_AVP_SubcrIdType(END_USER_E164), tr_AVP_SubcrIdData(msisdn)}),
+						tr_AVP_RequestedAction(DIRECT_DEBITING),
+						tr_AVP_3GPP_AoCRequestType,
+						tr_AVP_MultipleServicesIndicator,
+						tr_AVP_Multiple_Services_Credit_Control(content := superset(
+							tr_AVP_Requested_Service_Unit,
+							tr_AVP_Used_Service_Unit,
+							tr_AVP_3GPP_QoS_Information,
+							tr_AVP_GI_3GPP_RatType(rat_type)
+						)),
+						tr_AVP_3GPP_ServiceInformation(content := superset(
+							tr_AVP_3GPP_PSInformation(content := superset(
+								tr_AVP_3GPP_ChargingId,
+								tr_AVP_3GPP_PDPType((IPv4,IPv6,IPv4v6)),
+								tr_AVP_3GPP_PDPAddress(tr_AVP_Address((IP,IP6), ?)),
+								tr_AVP_3GPP_SGSNAddress(tr_AVP_Address(IP, f_inet_addr(m_bind_ip_gtpc))),
+								tr_AVP_3GPP_GGSNAddress(tr_AVP_Address(IP, f_inet_addr(m_ggsn_ip_gtpc))),
+								tr_AVP_3GPP_CalledStationId,
+								tr_AVP_3GPP_SelectionMode,
+								tr_AVP_3GPP_ChargingCharacteristics(charging_char),
+								tr_AVP_3GPP_SGSNMCCMNC,
+								tr_AVP_3GPP_NSAPI(nsapi),
+								tr_AVP_3GPP_MS_TimeZone,
+								tr_AVP_3GPP_ULI,
+								tr_AVP_UserEquipmentInfo({
+									tr_AVP_UserEquipmentInfoType(IMEISV),
+									tr_AVP_UserEquipmentInfoValue(imeisv)
+								})
+							))
+						))
+					));
+			}
+			case (UPDATE_REQUEST) {
+				tpl := tr_DIAMETER(flags:='11000000'B, cmd_code:=Credit_Control,
+					avps := superset(
+						tr_AVP_SessionId,
+						tr_AVP_OriginHost(smf_origin_host),
+						tr_AVP_OriginRealm(g_gy_pars.origin_realm),
+						tr_AVP_DestinationRealm(g_gy_pars.origin_realm),
+						tr_AVP_AuthAppId(int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4)),
+						tr_AVP_ServiceContextId,
+						tr_AVP_CcReqType(req_type),
+						tr_AVP_CcReqNum(?),
+						tr_AVP_DestinationHost(?),
+						tr_AVP_EventTimestamp(?),
+						tr_AVP_SubcrId({tr_AVP_SubcrIdType(END_USER_IMSI), tr_AVP_SubcrIdData(imsi)}),
+						tr_AVP_SubcrId({tr_AVP_SubcrIdType(END_USER_E164), tr_AVP_SubcrIdData(msisdn)}),
+						tr_AVP_RequestedAction(DIRECT_DEBITING),
+						tr_AVP_3GPP_AoCRequestType,
+						tr_AVP_MultipleServicesIndicator,
+						tr_AVP_Multiple_Services_Credit_Control(content := superset(
+							tr_AVP_Requested_Service_Unit,
+							tr_AVP_Used_Service_Unit,
+							tr_AVP_3GPP_Reporting_Reason,
+							tr_AVP_3GPP_QoS_Information,
+							tr_AVP_GI_3GPP_RatType(rat_type)
+						)),
+						tr_AVP_3GPP_ServiceInformation(content := superset(
+							tr_AVP_3GPP_PSInformation(content := superset(
+								tr_AVP_3GPP_ChargingId,
+								/* tr_AVP_3GPP_PDPType, Only in INIT */
+								tr_AVP_3GPP_PDPAddress(tr_AVP_Address((IP,IP6), ?)),
+								tr_AVP_3GPP_SGSNAddress(tr_AVP_Address(IP, f_inet_addr(m_bind_ip_gtpc))),
+								tr_AVP_3GPP_GGSNAddress(tr_AVP_Address(IP, f_inet_addr(m_ggsn_ip_gtpc))),
+								tr_AVP_3GPP_CalledStationId,
+								tr_AVP_3GPP_SelectionMode,
+								tr_AVP_3GPP_ChargingCharacteristics(charging_char),
+								tr_AVP_3GPP_SGSNMCCMNC,
+								tr_AVP_3GPP_NSAPI(nsapi),
+								tr_AVP_3GPP_MS_TimeZone,
+								tr_AVP_3GPP_ULI,
+								tr_AVP_UserEquipmentInfo({
+									tr_AVP_UserEquipmentInfoType(IMEISV),
+									tr_AVP_UserEquipmentInfoValue(imeisv)
+								})
+							))
+						))
+					));
+			}
+			case (TERMINATION_REQUEST) {
+				tpl := tr_DIAMETER(flags:='11000000'B, cmd_code:=Credit_Control,
+					avps := superset(
+						tr_AVP_SessionId,
+						tr_AVP_OriginHost(smf_origin_host),
+						tr_AVP_OriginRealm(g_gy_pars.origin_realm),
+						tr_AVP_DestinationRealm(g_gy_pars.origin_realm),
+						tr_AVP_AuthAppId(int2oct(c_DIAMETER_CREDIT_CONTROL_AID, 4)),
+						tr_AVP_ServiceContextId,
+						tr_AVP_CcReqType(req_type),
+						tr_AVP_CcReqNum(?),
+						tr_AVP_DestinationHost(?),
+						tr_AVP_EventTimestamp(?),
+						tr_AVP_SubcrId({tr_AVP_SubcrIdType(END_USER_IMSI), tr_AVP_SubcrIdData(imsi)}),
+						tr_AVP_SubcrId({tr_AVP_SubcrIdType(END_USER_E164), tr_AVP_SubcrIdData(msisdn)}),
+						tr_AVP_TerminationCause(?),
+						tr_AVP_RequestedAction(DIRECT_DEBITING),
+						tr_AVP_3GPP_AoCRequestType,
+						tr_AVP_MultipleServicesIndicator,
+						tr_AVP_Multiple_Services_Credit_Control(content := superset(
+							/* tr_AVP_Requested_Service_Unit, Only in INIT and UPDATE */
+							tr_AVP_Used_Service_Unit,
+							tr_AVP_3GPP_QoS_Information,
+							tr_AVP_GI_3GPP_RatType(rat_type)
+						)),
+						tr_AVP_3GPP_ServiceInformation(content := superset(
+							tr_AVP_3GPP_PSInformation(content := superset(
+								tr_AVP_3GPP_ChargingId,
+								/* tr_AVP_3GPP_PDPType, Only in INIT */
+								tr_AVP_3GPP_PDPAddress(tr_AVP_Address((IP,IP6), ?)),
+								tr_AVP_3GPP_SGSNAddress(tr_AVP_Address(IP, f_inet_addr(m_bind_ip_gtpc))),
+								tr_AVP_3GPP_GGSNAddress(tr_AVP_Address(IP, f_inet_addr(m_ggsn_ip_gtpc))),
+								tr_AVP_3GPP_CalledStationId,
+								tr_AVP_3GPP_SelectionMode,
+								tr_AVP_3GPP_ChargingCharacteristics(charging_char),
+								tr_AVP_3GPP_SGSNMCCMNC,
+								tr_AVP_3GPP_NSAPI(nsapi),
+								tr_AVP_3GPP_MS_TimeZone,
+								tr_AVP_3GPP_ULI,
+								tr_AVP_UserEquipmentInfo({
+									tr_AVP_UserEquipmentInfoType(IMEISV),
+									tr_AVP_UserEquipmentInfoValue(imeisv)
+								})
+							))
+						))
+					));
+			}
+		}
+		return tpl;
+	}
+
+	private altstep as_DIA_Gy_CCR(template (omit) PdpContext ctx, DCC_NONE_CC_Request_Type req_type) runs on GT_CT {
 		var PDU_DIAMETER rx_dia;
-		[] Gy_UNIT.receive(tr_DIA_Gy_CCR(req_type := req_type)) -> value rx_dia {
+		[] Gy_UNIT.receive(f_tr_DIA_Gy_CCR(ctx, req_type := req_type)) -> value rx_dia {
 			var template (value) PDU_DIAMETER tx_dia;
 			var template (omit) AVP avp;
 			var octetstring sess_id;
@@ -530,7 +695,7 @@
 			as_DIA_Gx_CCR(INITIAL_REQUEST);
 		}
 		if (Gy_PROC.checkstate("Connected")) {
-			as_DIA_Gy_CCR(INITIAL_REQUEST);
+			as_DIA_Gy_CCR(ctx, INITIAL_REQUEST);
 		}
 		alt {
 			[] GTPC.receive(tr_GTPC_MsgType(g_peer_c, createPDPContextResponse, ctx.teic)) -> value ud {
@@ -595,7 +760,7 @@
 			as_DIA_Gx_CCR(TERMINATION_REQUEST);
 		}
 		if (Gy_PROC.checkstate("Connected") and expect_diameter) {
-			as_DIA_Gy_CCR(TERMINATION_REQUEST);
+			as_DIA_Gy_CCR(ctx, TERMINATION_REQUEST);
 		}
 		alt {
 			[] GTPC.receive(tr_GTPC_MsgType(g_peer_c, deletePDPContextResponse, expect_teid)) -> value ud {
@@ -2001,7 +2166,7 @@
 		f_init();
 
 		for (var integer i := 0; i < num_ctx; i := i + 1) {
-			ctx[i] := valueof(t_DefinePDP(f_rnd_imsi('26242'H), f_dec_TBCD(f_rnd_msisdn('1234'O)), c_ApnInternet, valueof(t_EuaIPv4Dyn)));
+			ctx[i] := valueof(t_DefinePDP(f_rnd_imsi('26242'H), "1234" & int2str(f_rnd_int(4294967296)), c_ApnInternet, valueof(t_EuaIPv4Dyn)));
 			ctx[i].teic := int2oct(i+1, 4); /* +1: skip TEIC=0 */
 			ctx[i].teid := int2oct(i+1, 4); /* +1: skip TEID=0 */
 			ctx[i].pco_req := valueof(ts_PCO_IPv4_DNS_CONT);
@@ -2012,7 +2177,7 @@
 		T_next.start;
 		alt {
 		[Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(INITIAL_REQUEST) { repeat; }
-		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(INITIAL_REQUEST) { repeat; }
+		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(omit, INITIAL_REQUEST) { repeat; }
 		[] pingpong();
 		[] T_next.timeout {
 			f_send_gtpc(ts_GTPC_CreatePDP(g_peer_c, g_c_seq_nr, ctx[next_req_ctx].imsi, g_restart_ctr,
@@ -2068,7 +2233,7 @@
 		T_next.start;
 		alt {
 		[Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(TERMINATION_REQUEST) { repeat; }
-		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(TERMINATION_REQUEST) { repeat; }
+		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(omit, TERMINATION_REQUEST) { repeat; }
 		[] pingpong();
 		[] T_next.timeout {
 			f_send_gtpc(ts_GTPC_DeletePDP(g_peer_c, g_c_seq_nr, ctx[next_req_ctx].teic_remote, ctx[next_req_ctx].nsapi, '1'B));
@@ -2121,12 +2286,12 @@
 		T_next.start;
 		alt {
 		[Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(INITIAL_REQUEST) { repeat; }
-		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(INITIAL_REQUEST) { repeat; }
+		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(omit, INITIAL_REQUEST) { repeat; }
 		[] pingpong();
 		[] T_next.timeout {
 			if (cont_req) {
 				if (next_req_ctx - rx_resp_ctx < 100) { /* if we have too many in progress, wait a bit to continue */
-					ctx := valueof(t_DefinePDP(f_rnd_imsi('26242'H), f_dec_TBCD(f_rnd_msisdn('1234'O)), c_ApnInternet, valueof(t_EuaIPv4Dyn)));
+					ctx := valueof(t_DefinePDP(f_rnd_imsi('26242'H), "1234" & int2str(f_rnd_int(4294967296)), c_ApnInternet, valueof(t_EuaIPv4Dyn)));
 					ctx.nsapi := '0001'B;
 					ctx.teic := int2oct(next_req_ctx+1, 4); /* +1: skip TEIC=0 */
 					ctx.teid := int2oct(next_req_ctx+1, 4); /* +1: skip TEID=0 */
@@ -2172,7 +2337,7 @@
 		T_next.start;
 		alt {
 		[Gx_PROC.checkstate("Connected")] as_DIA_Gx_CCR(TERMINATION_REQUEST) { repeat; }
-		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(TERMINATION_REQUEST) { repeat; }
+		[Gy_PROC.checkstate("Connected")] as_DIA_Gy_CCR(omit, TERMINATION_REQUEST) { repeat; }
 		[] pingpong();
 		[] T_next.timeout {
 			f_send_gtpc(ts_GTPC_DeletePDP(g_peer_c, g_c_seq_nr, teic_list[next_req_ctx], '0001'B, '1'B));
@@ -2225,17 +2390,17 @@
 
 		g_gy_validity_time := 2;
 		/* First update reports octests/pkt on both UL/DL (see icmp ping-pong above) */
-		as_DIA_Gy_CCR(UPDATE_REQUEST);
+		as_DIA_Gy_CCR(ctx, UPDATE_REQUEST);
 
 		/* Second update: 0 ul/dl pkt/octet should be reported, since nothing was sent */
-		as_DIA_Gy_CCR(UPDATE_REQUEST);
+		as_DIA_Gy_CCR(ctx, UPDATE_REQUEST);
 
 		/* Third update: make sure report contains again octets/pkts for both UL/DL: */
 		f_send_gtpu(ctx, f_gen_icmpv4_echo(saddr, dns1_addr));
 		f_wait_icmp4_echo_reply(ctx);
 		f_send_gtpu(ctx, f_gen_icmpv4_echo(saddr, dns1_addr));
 		f_wait_icmp4_echo_reply(ctx);
-		as_DIA_Gy_CCR(UPDATE_REQUEST);
+		as_DIA_Gy_CCR(ctx, UPDATE_REQUEST);
 
 		/* Let the CCA reach the GGSN */
 		f_sleep(0.5);