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());
 }
 
 }
diff --git a/hnbgw/gen_links.sh b/hnbgw/gen_links.sh
index aabc8c0..4be3b53 100755
--- a/hnbgw/gen_links.sh
+++ b/hnbgw/gen_links.sh
@@ -22,6 +22,7 @@
 gen_links $DIR $FILES
 
 # Required by MGCP and IPA
+# Required by PFCP/UDP
 DIR=$BASEDIR/titan.TestPorts.IPL4asp/src
 FILES="IPL4asp_Functions.ttcn  IPL4asp_PT.cc  IPL4asp_PT.hh IPL4asp_PortType.ttcn  IPL4asp_Types.ttcn  IPL4asp_discovery.cc IPL4asp_protocol_L234.hh"
 gen_links $DIR $FILES
@@ -76,6 +77,10 @@
 FILES="TELNETasp_PT.cc  TELNETasp_PT.hh  TELNETasp_PortType.ttcn"
 gen_links $DIR $FILES
 
+DIR=$BASEDIR/titan.ProtocolModules.PFCP_v15.1.0/src
+FILES="PFCP_Types.ttcn"
+gen_links $DIR $FILES
+
 DIR=../library/hnbap
 FILES="HNBAP_CommonDataTypes.asn HNBAP_Constants.asn HNBAP_Containers.asn HNBAP_IEs.asn HNBAP_PDU_Contents.asn HNBAP_PDU_Descriptions.asn "
 FILES+="HNBAP_EncDec.cc  HNBAP_Types.ttcn  HNBAP_Templates.ttcn "
@@ -95,6 +100,7 @@
 FILES="Iuh_Types.ttcn Iuh_CodecPort.ttcn Iuh_CodecPort_CtrlFunctDef.cc Iuh_CodecPort_CtrlFunct.ttcn Iuh_Emulation.ttcn DNS_Helpers.ttcn "
 FILES+="MGCP_Emulation.ttcn MGCP_Types.ttcn MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn MGCP_CodecPort_CtrlFunctDef.cc "
 FILES+="RAN_Adapter.ttcnpp RAN_Emulation.ttcnpp BSSAP_CodecPort.ttcn SCCP_Templates.ttcn "
+FILES+="PFCP_CodecPort.ttcn PFCP_CodecPort_CtrlFunct.ttcn PFCP_CodecPort_CtrlFunctDef.cc PFCP_Emulation.ttcn PFCP_Templates.ttcn "
 FILES+="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc IuUP_Emulation.ttcn "
 FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
 
diff --git a/hnbgw/osmo-hnbgw.cfg b/hnbgw/osmo-hnbgw.cfg
index f11f613..e4dfed2 100644
--- a/hnbgw/osmo-hnbgw.cfg
+++ b/hnbgw/osmo-hnbgw.cfg
@@ -33,3 +33,8 @@
   remote-addr msc
  iups
   remote-addr sgsn
+ pfcp
+  remote-addr 127.0.0.1
+  local-addr 127.0.0.2
+  local-port 8805
+ timer pfcp x26 5
diff --git a/hnbgw/regen_makefile.sh b/hnbgw/regen_makefile.sh
index 47f7ee8..13db985 100755
--- a/hnbgw/regen_makefile.sh
+++ b/hnbgw/regen_makefile.sh
@@ -27,6 +27,7 @@
 	RANAP_EncDec.cc
 	MGCP_CodecPort_CtrlFunctDef.cc
 	UD_PT.cc
+	PFCP_CodecPort_CtrlFunctDef.cc
 "
 
 export CPPFLAGS_TTCN3="
diff --git a/library/ranap/RANAP_Templates.ttcn b/library/ranap/RANAP_Templates.ttcn
index 11947d9..7fac3a4 100644
--- a/library/ranap/RANAP_Templates.ttcn
+++ b/library/ranap/RANAP_Templates.ttcn
@@ -1291,6 +1291,86 @@
 	}
 } }
 
+template (value) TransportLayerInformation ts_TLI_ps(template (value) TransportLayerAddress tla,
+						     template (value) GTP_TEI gtp_tei) := {
+	transportLayerAddress := tla,
+	iuTransportAssociation := {
+		gTP_TEI := gtp_tei
+	},
+	iE_Extensions := omit
+}
+template TransportLayerInformation tr_TLI_ps(template TransportLayerAddress tla,
+					     template (value) GTP_TEI gtp_tei) := {
+	transportLayerAddress := tla,
+	iuTransportAssociation := {
+		gTP_TEI := gtp_tei
+	},
+	iE_Extensions := *
+}
+
+template (value) RAB_SetupOrModifyList ts_RAB_SML_ps(template (value) RAB_ID rab_id,
+						     template (value) TransportLayerAddress tla,
+						     template (value) GTP_TEI gtp_tei) := { {
+	{
+		id := id_RAB_SetupOrModifyItem,
+		firstCriticality := reject,
+		firstValue := {
+			rAB_SetupOrModifyItemFirst := {
+				rAB_ID := rab_id,
+				nAS_SynchronisationIndicator := omit,
+				rAB_Parameters := ts_RabParams,
+				userPlaneInformation := ts_UserPlaneInfo,
+				transportLayerInformation := ts_TLI_ps(tla, gtp_tei),
+				service_Handover := omit,
+				iE_Extensions := omit
+			}
+		},
+		secondCriticality := ignore,
+		secondValue := {
+			rAB_SetupOrModifyItemSecond := {
+				pDP_TypeInformation := omit,
+				dataVolumeReportingIndication := omit,
+				dl_GTP_PDU_SequenceNumber := omit,
+				ul_GTP_PDU_SequenceNumber := omit,
+				dl_N_PDU_SequenceNumber := omit,
+				ul_N_PDU_SequenceNumber := omit,
+				iE_Extensions := omit
+			}
+		}
+	}
+} }
+template RAB_SetupOrModifyList tr_RAB_SML_ps(template (present) RAB_ID rab_id,
+					     template TransportLayerAddress tla,
+					     template (value) GTP_TEI gtp_tei) := { {
+	{
+		id := id_RAB_SetupOrModifyItem,
+		firstCriticality := reject,
+		firstValue := {
+			rAB_SetupOrModifyItemFirst := {
+				rAB_ID := rab_id,
+				nAS_SynchronisationIndicator := *,
+				rAB_Parameters := ts_RabParams,
+				userPlaneInformation := ts_UserPlaneInfo,
+				transportLayerInformation := tr_TLI_ps(tla, gtp_tei),
+				service_Handover := *,
+				iE_Extensions := *
+			}
+		},
+		secondCriticality := ignore,
+		secondValue := {
+			rAB_SetupOrModifyItemSecond := {
+				pDP_TypeInformation := omit,
+				dataVolumeReportingIndication := omit,
+				dl_GTP_PDU_SequenceNumber := omit,
+				ul_GTP_PDU_SequenceNumber := omit,
+				dl_N_PDU_SequenceNumber := omit,
+				ul_N_PDU_SequenceNumber := omit,
+				iE_Extensions := omit
+			}
+		}
+	}
+} }
+
 template (value) RAB_SetupOrModifiedList ts_RAB_SMdL(template (value) RAB_ID rab_id,
 						  template (value) TransportLayerAddress tla,
 						  template (value) BindingID binding_id) := { {
@@ -1311,6 +1391,26 @@
 	}
 } }
 
+template (value) RAB_SetupOrModifiedList ts_RAB_SMdL_ps(template (value) RAB_ID rab_id,
+							template (value) TransportLayerAddress tla,
+							template (value) GTP_TEI gtp_tei) := { {
+	{
+		id := id_RAB_SetupOrModifiedItem,
+		criticality := ignore,
+		value_ := {
+			rAB_SetupOrModifiedItem := {
+				rAB_ID := rab_id,
+				transportLayerAddress := tla,
+				iuTransportAssociation := {
+					gTP_TEI := gtp_tei
+				},
+				dl_dataVolumes := omit,
+				iE_Extensions := omit
+			}
+		}
+	}
+} }
+
 template RAB_SetupOrModifiedList tr_RAB_SMdL(template (present) RAB_ID rab_id,
 					  template TransportLayerAddress tla,
 					  template BindingID binding_id) := { {