epdg: Test UE-initiated Detach Procedure

Related: OS#6333
Change-Id: I19114c69119e42622f323378dd356217d107cb32
diff --git a/epdg/EPDG_Tests.ttcn b/epdg/EPDG_Tests.ttcn
index de5e7a8..82a2375 100644
--- a/epdg/EPDG_Tests.ttcn
+++ b/epdg/EPDG_Tests.ttcn
@@ -359,7 +359,7 @@
 }
 
 /* Diameter SWx SAR + SAA. */
-private altstep as_DIA_SWx_SA_success() runs on EPDG_ConnHdlr {
+private altstep as_DIA_SWx_SA_success(template (present) CxDx_3GPP_Server_Assignment_Type server_ass_type := ?) runs on EPDG_ConnHdlr {
 	var PDU_DIAMETER rx_dia;
 	var template (omit) AVP avp;
 	var octetstring sess_id;
@@ -404,7 +404,28 @@
 	}
 }
 
-/* Diameter SWx SAR + SAA. */
+/* Send STR as PGW to AAA server, expect back STA */
+private function f_S6b_ST_success() runs on EPDG_ConnHdlr {
+	var PDU_DIAMETER rx_dia;
+	var UINT32 hbh_id := f_rnd_octstring(4);
+	var UINT32 ete_id := f_rnd_octstring(4);
+
+	/* Unlike STR, STA contains no IMSI. Register ete_id in DIAMETER_Emulation,
+	 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
+	 */
+	f_epdg_connhldr_S6b_expect_eteid(ete_id);
+
+	S6b.send(ts_DIA_S6b_STR(g_pars.imsi, DIAMETER_LOGOUT,
+				hbh_id := hbh_id, ete_id := ete_id));
+	alt {
+	[] S6b.receive(tr_DIA_S6b_STA(DIAMETER_SUCCESS)) -> value rx_dia {}
+	[] S6b.receive(PDU_DIAMETER:?) -> value rx_dia {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia));
+		}
+	}
+}
+
+/* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */
 private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr {
 	var PDU_GTPCv2 rx_msg;
 	var BearerContextIEs rx_bctx_ies;
@@ -444,8 +465,27 @@
 		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
 	}
 }
-private function f_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr {
-	as_GTP2C_CreateSession_success();
+
+/* ePDG Deletes session at the PGW. PGW sends Diameter s6b AAR + AAA. */
+private altstep as_GTP2C_DeleteSession_success() runs on EPDG_ConnHdlr {
+	var PDU_GTPCv2 rx_msg;
+	var BearerContextIEs rx_bctx_ies;
+	var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
+	var template (value) PDN_AddressAllocation paa;
+	var template (value) BearerContextIEs bctx_ies;
+
+	[] GTP2.receive(tr_GTP2C_DeleteSessionReq(g_pars.teic_local)) -> value rx_msg {
+		/* Upon rx of DeleteSession, emulate PGW requesting the AAA server for Sesssion Termination. */
+		f_S6b_ST_success();
+
+		GTP2.send(ts_GTP2C_DeleteSessionResp(g_pars.teic_remote,
+						     rx_msg.sequenceNumber,
+						     Request_accepted));
+		setverdict(pass);
+	}
+	[] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
+	}
 }
 
 /* Expect DeleteBearerResponse */
@@ -493,7 +533,7 @@
 	var GSUP_PDU rx_gsup;
 	var template octetstring destination_name := *;
 	GSUP.send(ts_GSUP_UL_REQ(g_pars.imsi));
-	as_DIA_SWx_SA_success();
+	as_DIA_SWx_SA_success(REGISTRATION);
 	/* Expect a positive response back to the translator */
 	alt {
 	[] GSUP.receive(tr_GSUP_UL_RES(g_pars.imsi, destination_name));
@@ -508,7 +548,7 @@
 private function f_GSUP_EPDGTunnel_success() runs on EPDG_ConnHdlr {
 	var GSUP_PDU rx_gsup;
 	GSUP.send(ts_GSUP_EPDGTunnel_REQ(g_pars.imsi));
-	f_GTP2C_CreateSession_success();
+	as_GTP2C_CreateSession_success();
 	/* Expect a positive response back to the translator; */
 	var template (present) GSUP_IEs pdp_info := {
 			tr_GSUP_IE_PDP_CONTEXT_ID(?),
@@ -526,10 +566,30 @@
 	setverdict(pass);
 }
 
+/* GSUP Purge MS Req + Resp, triggers S2b DeleteSession Req + Response. */
+private function f_GSUP_PurgeMS_success() runs on EPDG_ConnHdlr {
+	var GSUP_PDU rx_gsup;
+	GSUP.send(ts_GSUP_PURGE_MS_REQ(g_pars.imsi, OSMO_GSUP_CN_DOMAIN_PS));
+	as_GTP2C_DeleteSession_success();
+	/* ePDG internally sends STR to its AAA-Server. Since all sessions
+	become inactive, AAA-Server sends SAR(USER_DEREGISTRATION) to HSS: */
+
+	/* Expect a positive response back to the translator; */
+	as_DIA_SWx_SA_success(USER_DEREGISTRATION);
+	alt {
+	[] GSUP.receive(tr_GSUP_PURGE_MS_RES(g_pars.imsi));
+	[] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
+		}
+	}
+	setverdict(pass);
+}
+
 private function f_TC_authinfo_normal(charstring id) runs on EPDG_ConnHdlr {
 	f_GSUP_AI_success();
 	f_GSUP_LU_success();
 	f_GSUP_EPDGTunnel_success();
+	f_GSUP_PurgeMS_success();
 }
 
 testcase TC_authinfo_normal() runs on MTC_CT {