sgsn: First PDP CTX ACT test: TC_attach_pdp_act

Change-Id: Ia1bfaca99a2a70bb097e2ee44f54e4a31b849a1b
diff --git a/sgsn/SGSN_Tests.ttcn b/sgsn/SGSN_Tests.ttcn
index 3cf1657..9209c69 100644
--- a/sgsn/SGSN_Tests.ttcn
+++ b/sgsn/SGSN_Tests.ttcn
@@ -18,13 +18,21 @@
 import from GSUP_Types all;
 import from IPA_Emulation all;
 
+import from GTP_Emulation all;
+import from GTP_Templates all;
+import from GTP_CodecPort all;
+import from GTPC_Types all;
+import from GTPU_Types all;
+
 import from TELNETasp_PortType all;
 import from Osmocom_VTY_Functions all;
 
+
 modulepar {
 	/* IP/port on which we run our internal GSUP/HLR emulation */
 	charstring mp_hlr_ip := "127.0.0.1";
 	integer mp_hlr_port := 4222;
+	charstring mp_ggsn_ip := "127.0.0.2";
 };
 
 type record GbInstance {
@@ -41,12 +49,14 @@
 	/* only to get events from IPA underneath GSUP */
 	port IPA_CTRL_PT GSUP_IPA_EVENT;
 
+	var GTP_Emulation_CT vc_GTP;
+
 	port TELNETasp_PT SGSNVTY;
 
 	var boolean g_initialized := false;
 };
 
-type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr {
+type component BSSGP_ConnHdlr extends BSSGP_Client_CT, GSUP_ConnHdlr, GTP_ConnHdlr {
 	var BSSGP_ConnHdlrPars g_pars;
 	timer g_Tguard;
 }
@@ -118,6 +128,21 @@
 	}
 }
 
+private function f_init_gtp(charstring id) runs on test_CT {
+	id := id & "-GTP";
+
+	var GtpEmulationCfg gtp_cfg := {
+		gtpc_bind_ip := mp_ggsn_ip,
+		gtpc_bind_port := GTP1C_PORT,
+		gtpu_bind_ip := mp_ggsn_ip,
+		gtpu_bind_port := GTP1U_PORT,
+		sgsn_role := false
+	};
+
+	vc_GTP := GTP_Emulation_CT.create(id);
+	vc_GTP.start(GTP_Emulation.main(gtp_cfg));
+}
+
 private function f_init_vty() runs on test_CT {
 	map(self:SGSNVTY, system:SGSNVTY);
 	f_vty_set_prompts(SGSNVTY);
@@ -147,6 +172,7 @@
 
 	f_init_gb(g_gb[0]);
 	f_init_gsup("SGSN_Test");
+	f_init_gtp("SGSN_Test");
 	f_init_vty();
 }
 
@@ -184,6 +210,9 @@
 	connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
 	connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
 
+	connect(vc_conn:GTP, vc_GTP:CLIENT);
+	connect(vc_conn:GTP_PROC, vc_GTP:CLIENT_PROC);
+
 	vc_conn.start(f_handler_init(fn, id, pars));
 	return vc_conn;
 }
@@ -205,6 +234,8 @@
 	f_bssgp_client_register(g_pars.imsi, g_pars.tlli, g_pars.bssgp_cell_id);
 	/* tell GSUP dispatcher to send this IMSI to us */
 	f_create_gsup_expect(hex2str(g_pars.imsi));
+	/* tell GTP dispatcher to send this IMSI to us */
+	f_gtp_register_imsi(g_pars.imsi);
 
 	g_Tguard.start(pars.t_guard);
 	activate(as_Tguard());
@@ -349,9 +380,12 @@
 }
 
 private function f_gmm_gsup_lu_isd() runs on BSSGP_ConnHdlr {
+	var GSUP_PDU gsup;
 	/* Expect MSC to perform LU with HLR */
 	GSUP.receive(tr_GSUP_UL_REQ(g_pars.imsi));
-	GSUP.send(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
+	gsup := valueof(ts_GSUP_ISD_REQ(g_pars.imsi, g_pars.msisdn));
+	gsup.ies := gsup.ies & { valueof(ts_GSUP_IE_PdpInfo(char2oct("*"), '0121'O, ''O)) };
+	GSUP.send(gsup);
 	GSUP.receive(tr_GSUP_ISD_RES(g_pars.imsi));
 	GSUP.send(ts_GSUP_UL_RES(g_pars.imsi));
 }
@@ -720,7 +754,146 @@
 	vc_conn.done;
 }
 
+type record PdpActPars {
+	BIT3			tid,
+	BIT4			nsapi,
+	BIT4			sapi,
+	QoSV			qos,
+	PDPAddressV		addr,
+	octetstring		apn optional,
+	ProtocolConfigOptionsV	pco optional,
+	OCT1			exp_rej_cause optional,
 
+	OCT4			ggsn_tei_c,
+	OCT4			ggsn_tei_u,
+	octetstring		ggsn_ip_c,
+	octetstring		ggsn_ip_u,
+
+	GtpPeer			sgsn,
+	OCT4			sgsn_tei_c optional,
+	OCT4			sgsn_tei_u optional
+};
+
+function f_pdp_ctx_act(PdpActPars apars) runs on BSSGP_ConnHdlr {
+	var boolean exp_rej := ispresent(apars.exp_rej_cause);
+	var Gtp1cUnitdata g_ud;
+
+	BSSGP.send(ts_SM_ACT_PDP_REQ(apars.tid, apars.nsapi, apars.sapi, apars.qos, apars.addr,
+				     apars.apn, apars.pco));
+	if (not exp_rej) {
+		GTP.receive(tr_GTPC_MsgType(?, createPDPContextRequest, ?)) -> value g_ud {
+			var integer seq_nr := oct2int(g_ud.gtpc.opt_part.sequenceNumber);
+			var GTPC_PDUs gtpc_rx := g_ud.gtpc.gtpc_pdu;
+			apars.sgsn_tei_c := gtpc_rx.createPDPContextRequest.teidControlPlane.teidControlPlane;
+			apars.sgsn_tei_u := gtpc_rx.createPDPContextRequest.teidDataI.teidDataI;
+			var OCT1 cause := int2oct(128, 1);
+			GTP.send(ts_GTPC_CreatePdpResp(g_ud.peer, seq_nr,
+							apars.sgsn_tei_c, cause,
+							apars.ggsn_tei_c, apars.ggsn_tei_u,
+							apars.nsapi,
+							apars.ggsn_ip_c, apars.ggsn_ip_u));
+		}
+	}
+	alt {
+	[exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_REJ(apars.tid, apars.exp_rej_cause))) {
+		setverdict(pass);
+		}
+	[exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_ACCEPT)) {
+		setverdict(fail, "Unexpected PDP CTX ACT ACC");
+		}
+	[not exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_REJ(apars.tid, ?))) {
+		setverdict(fail, "Unexpected PDP CTX ACT FAIL");
+		}
+	[not exp_rej] BSSGP.receive(tr_BD_L3(tr_SM_ACT_PDP_ACCEPT(apars.tid, apars.sapi))) {
+		setverdict(pass);
+		}
+	}
+}
+
+/* Table 10.5.156/3GPP TS 24.008 */
+template (value) QoSV t_QosDefault := {
+	reliabilityClass := '011'B, /* unacknowledged GTP+LLC, acknowledged RLC */
+	delayClass := '100'B,	/* best effort */
+	spare1 := '00'B,
+	precedenceClass := '010'B, /* normal */
+	spare2 := '0'B,
+	peakThroughput := '0000'B, /* subscribed */
+	meanThroughput := '00000'B, /* subscribed */
+	spare3 := '000'B,
+	deliverErroneusSDU := omit,
+	deliveryOrder := omit,
+	trafficClass := omit,
+	maxSDUSize := omit,
+	maxBitrateUplink := omit,
+	maxBitrateDownlink := omit,
+	sduErrorRatio := omit,
+	residualBER := omit,
+	trafficHandlingPriority := omit,
+	transferDelay := omit,
+	guaranteedBitRateUplink := omit,
+	guaranteedBitRateDownlink := omit,
+	sourceStatisticsDescriptor := omit,
+	signallingIndication := omit,
+	spare4 := omit,
+	maxBitrateDownlinkExt := omit,
+	guaranteedBitRateDownlinkExt := omit,
+	maxBitrateUplinkExt := omit,
+	guaranteedBitRateUplinkExt := omit,
+	maxBitrateDownlinkExt2 := omit,
+	guaranteedBitRateDownlinkExt2 := omit,
+	maxBitrateUplinkExt2 := omit,
+	guaranteedBitRateUplinkExt2 := omit
+}
+
+/* 10.5.6.4 / 3GPP TS 24.008 */
+template (value) PDPAddressV t_AddrIPv4dyn := {
+	pdpTypeOrg := '0001'B, /* IETF */
+	spare := '0000'B,
+	pdpTypeNum := '21'O, /* IPv4 */
+	addressInfo := omit
+}
+template (value) PDPAddressV t_AddrIPv6dyn := {
+	pdpTypeOrg := '0001'B, /* IETF */
+	spare := '0000'B,
+	pdpTypeNum := '53'O, /* IPv6 */
+	addressInfo := omit
+}
+
+template (value) PdpActPars t_PdpActPars := {
+	tid := '000'B,
+	nsapi := '0101'B, /* < 5 are reserved */
+	sapi := '0011'B, /* 3/5/9/11 */
+	qos := t_QosDefault,
+	addr := t_AddrIPv4dyn,
+	apn := omit,
+	pco := omit,
+	exp_rej_cause := omit,
+
+	/* FIXME: make below dynamic !! */
+	ggsn_tei_c := '00010000'O,
+	ggsn_tei_u := '00020000'O,
+	ggsn_ip_c := '7F000001'O,
+	ggsn_ip_u := '7F000001'O,
+
+	sgsn := { },
+	sgsn_tei_c := omit,
+	sgsn_tei_u := omit
+}
+
+private function f_TC_attach_pdp_act(charstring id) runs on BSSGP_ConnHdlr {
+	var PdpActPars apars := valueof(t_PdpActPars);
+
+	/* first perform regular attach */
+	f_TC_attach(id);
+
+	f_pdp_ctx_act(apars);
+}
+testcase TC_attach_pdp_act() runs on test_CT {
+	var BSSGP_ConnHdlr vc_conn;
+	f_init();
+	vc_conn := f_start_handler(refers(f_TC_attach_pdp_act), testcasename(), g_gb[0], 17);
+	vc_conn.done;
+}
 
 
 control {
@@ -739,6 +912,7 @@
 	execute( TC_detach_unknown_poweroff() );
 	execute( TC_detach_nopoweroff() );
 	execute( TC_detach_poweroff() );
+	execute( TC_attach_pdp_act() );
 }