hnbgw: test PS RAB GTP mapping

Related: SYS#5895
Change-Id: I93c4689ddc016eb4eb25f8cbdd0142936c6f972b
diff --git a/hnbgw/HNBGW_Tests.ttcn b/hnbgw/HNBGW_Tests.ttcn
index 81d9f1a..7429c38 100644
--- a/hnbgw/HNBGW_Tests.ttcn
+++ b/hnbgw/HNBGW_Tests.ttcn
@@ -57,6 +57,11 @@
 import from MGCP_CodecPort all;
 import from SDP_Types all;
 
+import from PFCP_Types all;
+import from PFCP_Emulation all;
+import from PFCP_Templates all;
+import from PFCP_CodecPort all;
+
 modulepar {
 	/* IP address at which the HNodeB can be reached */
 	charstring mp_hnodeb_ip := "127.0.0.1";
@@ -91,6 +96,13 @@
 		sio := '83'O,
 		rctx := 2
 	};
+
+	/* IP address at which we listen for PFCP to emulate a UPF in ttcn3 */
+	charstring mp_pfcp_ip_local := "127.0.0.1";
+
+	/* IP address from which the SUT (osmo-hnbgw) sends PFCP requests, and to which the ttcn3 UPF emulation sends
+	 * PFCP responses. */
+	charstring mp_pfcp_ip_remote := "127.0.0.2";
 }
 
 function MSC_UnitdataCallback(RANAP_PDU ranap) runs on RAN_Emulation_CT return template RANAP_PDU {
@@ -168,7 +180,8 @@
 	boolean ps_domain,
 	MgcpParameters mgcp_pars optional,
 	HnbConfig hnb optional,
-	boolean separate_sccp_cr
+	boolean separate_sccp_cr,
+	charstring pfcp_local_addr
 }
 
 /* We extend:
@@ -176,7 +189,7 @@
    * RAN_ConnHdlr (for the Iu side, emulating the MSC)
    * MGCP_ConnHdlr (for the MGCP side, emulating the MGW)
  */
-type component ConnHdlr extends RAN_ConnHdlr, MGCP_ConnHdlr, RUA_ConnHdlr {
+type component ConnHdlr extends RAN_ConnHdlr, MGCP_ConnHdlr, RUA_ConnHdlr, PFCP_ConnHdlr {
 	var integer g_sccp_conn_id;
 	var TestHdlrParams g_pars;
 	timer g_Tguard;
@@ -267,6 +280,23 @@
 	vc_MGCP.start(MGCP_Emulation.main(ops, pars, id));
 }
 
+function f_init_pfcp(charstring id) runs on ConnHdlr {
+	id := id & "-PFCP";
+
+	var PFCP_Emulation_Cfg pfcp_cfg := {
+		pfcp_bind_ip := mp_pfcp_ip_local,
+		pfcp_bind_port := PFCP_PORT,
+		pfcp_remote_ip := mp_pfcp_ip_remote,
+		pfcp_remote_port := PFCP_PORT,
+		role := UPF
+	};
+
+	vc_PFCP := PFCP_Emulation_CT.create(id) alive;
+	connect(self:PFCP, vc_PFCP:CLIENT);
+	connect(self:PFCP_PROC, vc_PFCP:CLIENT_PROC);
+	vc_PFCP.start(PFCP_Emulation.main(pfcp_cfg));
+}
+
 function f_init_hnodeb(charstring id, integer hnb_idx, RuaOps rua_ops) runs on test_CT {
 	id := id & "-Iuh" & int2str(hnb_idx);
 
@@ -417,6 +447,9 @@
 function f_init_handler(TestHdlrParams pars, float t_guard := 20.0) runs on ConnHdlr {
 	/* make parameters available via component variable */
 	g_pars := pars;
+
+	f_init_pfcp(testcasename());
+
 	/* start guard timer and activate it as default */
 	g_Tguard.start(t_guard);
 	activate(as_Tguard_ConnHdlr());
@@ -643,7 +676,8 @@
 	imsi := f_gen_imsi(imsi_suffix),
 	ps_domain := ps_domain,
 	hnb := omit,	/* filled in later */
-	separate_sccp_cr := separate_sccp_cr
+	separate_sccp_cr := separate_sccp_cr,
+	pfcp_local_addr := mp_pfcp_ip_local
 }
 
 /* Create an Iuh connection; send InitialUE; expect it to appear on new SCCP conenction */
@@ -1139,8 +1173,152 @@
 	vc_conn.done;
 }
 
+type record FTeid {
+	HostName addr,
+	OCT4 teid
+}
+
+type record FTeids {
+	FTeid local,
+	FTeid remote
+}
 
 
+/* 'local' and 'remote' refer to the GTP information from the UPF's point of view:
+ * HNB                             UPF                 CN
+ * access.remote <---> access.local | core.local <---> core.remote
+ */
+type record GtpParameters {
+	FTeids core,
+	FTeids access
+}
+
+/* HNB                             UPF                 CN
+ * access.remote <---> access.local | core.local <---> core.remote
+ * 127.0.0.4           127.0.0.3      127.0.0.2        127.0.0.1
+ * 0x44004400          0x30303030     0x22002200       0x10101010
+ */
+template GtpParameters t_GtpParameters := {
+	core := {
+		local := {
+			addr := "127.0.0.2",
+			teid := '22002200'O
+		},
+		remote := {
+			addr := "127.0.0.1",
+			teid := '10101010'O
+		}
+	},
+	access := {
+		local := {
+			addr := "127.0.0.3",
+			teid := '30303030'O
+		},
+		remote := {
+			addr := "127.0.0.4",
+			teid := '44004400'O
+		}
+	}
+}
+
+friend function f_tc_ps_rab_assignment(charstring id, TestHdlrParams pars) runs on ConnHdlr {
+	var RANAP_PDU tx;
+	var RANAP_PDU rx;
+	timer T := 5.0;
+
+	f_init_handler(pars);
+
+	f_pfcp_register();
+
+	var PDU_PFCP m;
+	var Node_ID upf_node_id := valueof(ts_PFCP_Node_ID_fqdn("\07osmocom\03org"));
+
+	PFCP.receive(tr_PFCP_Assoc_Setup_Req()) -> value m;
+	PFCP.send(ts_PFCP_Assoc_Setup_Resp(m.sequence_number, upf_node_id,
+					   ts_PFCP_Cause(REQUEST_ACCEPTED), 1234));
+
+	tx := f_build_initial_ue(g_pars);
+	f_iuh2iu_connect(tx);
+
+	var GtpParameters gtp_pars := valueof(t_GtpParameters);
+	var template RAB_SetupOrModifyList rab_sml;
+
+	/* Send RAB Assignment Request */
+	rab_sml := ts_RAB_SML_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.core.remote.addr), gtp_pars.core.remote.teid);
+	tx := valueof(ts_RANAP_RabAssReq(rab_sml));
+	BSSAP.send(tx);
+
+	/* Expect PFCP Session Establishment Request. */
+	PFCP.receive(tr_PFCP_Session_Est_Req()) -> value m;
+	var F_SEID hnbgw_f_seid := m.message_body.pfcp_session_establishment_request.CP_F_SEID;
+	var PFCP_Session_Establishment_Request serq := m.message_body.pfcp_session_establishment_request;
+
+	/* Acting as UPF, invent a new PFCP SEID to send to HNBGW. Respond to the Session Establishment.
+	 * The PFCP response must have the same sequence_number as the request. */
+	var F_SEID up_f_seid := valueof(ts_PFCP_F_SEID_ipv4("127.0.0.1", '1111111111111111'O));
+	var template PDU_PFCP r := ts_PFCP_Session_Est_Resp(m.sequence_number, upf_node_id, hnbgw_f_seid.seid);
+	r.message_body.pfcp_session_establishment_response := {
+		offending_ie := omit,
+		UP_F_SEID := up_f_seid,
+		created_PDR_list := {
+			ts_PFCP_Created_PDR(pdr_id := serq.create_PDR_list[0].grouped_ie.pdr_id,
+					    local_F_TEID := ts_PFCP_F_TEID_ipv4(gtp_pars.core.local.teid,
+										gtp_pars.core.local.addr)),
+			ts_PFCP_Created_PDR(pdr_id := serq.create_PDR_list[1].grouped_ie.pdr_id,
+					    local_F_TEID := ts_PFCP_F_TEID_ipv4(gtp_pars.access.local.teid,
+										gtp_pars.access.local.addr))
+		},
+		load_control_information := omit,
+		overload_control_information := omit,
+		node_list := omit,
+		failed_rule_id := omit,
+		created_traffic_endpoint_list := omit
+	};
+	PFCP.send(r);
+
+	/* Expect on Iuh: RAB Assignment Request with IP/port from PFCP Session Est Resp */
+	rab_sml := ts_RAB_SML_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.access.local.addr),
+				 gtp_pars.access.local.teid);
+	rx := valueof(ts_RANAP_RabAssReq(rab_sml));
+	RUA.receive(rx);
+
+	/* Send back RAB Assignment Response via Iuh */
+	var template RAB_SetupOrModifiedList rab_smdl;
+	rab_smdl := ts_RAB_SMdL_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.access.remote.addr),
+				   gtp_pars.access.remote.teid);
+	tx := valueof(ts_RANAP_RabAssResp(rab_smdl));
+	RUA.send(tx);
+	T.start;
+
+	PFCP.receive(tr_PFCP_Session_Mod_Req(up_f_seid.seid)) -> value m;
+	r := ts_PFCP_Session_Mod_Resp(m.sequence_number, hnbgw_f_seid.seid);
+	PFCP.send(r);
+
+	rab_smdl := ts_RAB_SMdL_ps(t_RAB_id(23), f_ts_RAB_TLA(gtp_pars.core.local.addr), gtp_pars.core.local.teid);
+	BSSAP.receive(tr_RANAP_RabAssResp(rab_smdl));
+
+	f_sleep(2.0);
+	tx := valueof(ts_RANAP_IuReleaseCommand(ts_RanapCause_om_intervention));
+	f_iu2iuh(tx);
+
+	tx := valueof(ts_RANAP_IuReleaseComplete());
+	f_iuh2iu(tx);
+
+	PFCP.receive(tr_PFCP_Session_Del_Req(up_f_seid.seid)) -> value m;
+	PFCP.send(ts_PFCP_Session_Del_Resp(m.sequence_number, hnbgw_f_seid.seid));
+
+	f_sleep(2.0);
+}
+
+testcase TC_ps_rab_assignment() runs on test_CT {
+	var ConnHdlr vc_conn;
+	f_init();
+	f_start_hnbs();
+	f_sleep(1.0);
+
+	vc_conn := f_start_handler_with_pars(refers(f_tc_ps_rab_assignment), t_pars(7, ps_domain := true));
+	vc_conn.done;
+}
 
 control {
 	execute(TC_hnb_register());
@@ -1156,6 +1334,7 @@
 	execute(TC_rab_assign_mgcp_to());
 	execute(TC_ranap_cs_mo_disconnect());
 	execute(TC_ranap_ps_mo_disconnect());
+	execute(TC_ps_rab_assignment());
 }
 
 }