module GTPv2_Templates {

/* (C) 2019 by Harald Welte <laforge@gnumonks.org>
 * All rights reserved.
 *
 * Released under the terms of GNU General Public License, Version 2 or
 * (at your option) any later version.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

import from General_Types all;
import from Osmocom_Types all;
import from GTPv2_Types all;

/* 8.14 */
type enumerated GTP2C_PDN_Type {
	GTP2C_PDN_IPv4		('001'B),
	GTP2C_PDN_IPv6		('010'B),
	GTP2C_PDN_IPv4v6	('011'B),
	GTP2C_PDN_non_IP	('100'B),
	GTP2C_PDN_Ethernet	('101'B)
} with { variant "FIELDLENGTH(3)" encode "RAW" };

private function fs_GTP2C_t_bit(template (omit) OCT4 teid) return BIT1 {
	if (istemplatekind(teid, "omit")) {
		return '0'B;
	} else {
		return '1'B;
	}
}

private function fs_GTP2C_p_bit(template (omit) PDU_GTPCv2 piggyback) return BIT1 {
	if (istemplatekind(piggyback, "omit")) {
		return '0'B;
	} else {
		return '1'B;
	}
}

template (present) PDU_GTPCv2 tr_PDU_GTP2C(template OCT4 teid := ?,
					   template (present) OCT3 seq := ?,
					   template (present) GTPCv2_PDUs pdus := ?,
					   template PDU_GTPCv2 piggyback := omit) := {
	spare := '000'B,
	t_Bit := ?,
	p_Bit := ?,
	version := '010'B,
	messageType := ?,
	lengthf := ?,
	tEID := teid,
	sequenceNumber := seq,
	spare3 := '00'O,
	gtpcv2_pdu := pdus,
	piggybackPDU_GTPCv2 := piggyback
}

template (present) OCT1 gtp2_requests := (
	'01'O,	// echoRequest
	'20'O,	// createSessionRequest
	'5F'O,	// createBearerRequest
	'22'O, 	// modifyBearerRequest
	'24'O,	// deleteSessionRequest
	'63'O,	// deleteBearerRequest
	'A8'O,	// deleteIndirectDataForwardingTunnelRequest
	'61'O,	// updateBearerRequest
	'42'O,	// deleteBearerCommand
	'A6'O,	// createIndirectDataForwardingTunnelRequest
	'AA'O,	// releaseAccessBearersRequest
	'B3'O,	// modifyAccessBearersRequest
	'85'O,	// forwardRelocationRequest
	'82'O,	// contextRequest
	'80'O,	// identificationRequest
	'26'O,	// changeNotificationRequest
	'8B'O,	// relocationCancelRequest
	'A0'O,	// createForwardingTunnelRequest
	'65'O,	// deletePDN_ConnectionSetRequest
	'C8'O,	// updatePDN_ConnectionSetRequest
	'9E'O,	// uE_RegistrationQueryRequest
	'E7'O,	// mBMSSessionStartRequest
	'E9'O,	// mBMSSessionUpdateRequest
	'EB'O 	// mBMSSessionStopRequest
);
template (present) OCT1 gtp2_responses := (
	'02'O,	// echoResponse
	'21'O,	// createSessionResponse
	'60'O,	// createBearerResponse
	'23'O, 	// modifyBearerResponse
	'25'O,	// deleteSessionResponse
	'64'O,	// deleteBearerResponse
	'A9'O,	// deleteIndirectDataForwardingTunnelResponse
	'62'O,	// updateBearerResponse
	'43'O,	// deleteBearerFailureIndication
	'A7'O,	// createIndirectDataForwardingTunnelResponse
	'AB'O,	// releaseAccessBearersResponse
	'B4'O,	// modifyAccessBearersResponse
	'86'O,	// forwardRelocationResponse
	'83'O,	// contextResponse
	'81'O,	// identificationResponse
	'27'O,	// changeNotificationResponse
	'8C'O,	// relocationCancelResponse
	'A1'O,	// createForwardingTunnelResponse
	'66'O,	// deletePDN_ConnectionSetResponse
	'C9'O,	// updatePDN_ConnectionSetResponse
	'9F'O,	// uE_RegistrationQueryResponse
	'E8'O,	// mBMSSessionStartResponse
	'EA'O,	// mBMSSessionUpdateResponse
	'EC'O 	// mBMSSessionStopResponse
);

template (present) PDU_GTPCv2 tr_PDU_GTP2C_msgtypes(template (present) OCT1 types) := {
	spare := '000'B,
	t_Bit := ?,
	p_Bit := ?,
	version := '010'B,
	messageType := types,
	lengthf := ?,
	tEID := *,
	sequenceNumber := ?,
	spare3 := '00'O,
	gtpcv2_pdu := ?,
	piggybackPDU_GTPCv2 := *
};

/* 8.3 */
template (value) IMSI ts_GTP2C_Imsi(template (value) hexstring imsi) := {
	elementIdentifier := '01'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	iMSI_Value := imsi
}
template (present) IMSI tr_GTP2C_Imsi(template (present) hexstring imsi) := {
	elementIdentifier := '01'O,
	lengthIndicator := ?,
	instance := ?,
	spare := '0000'B,
	iMSI_Value := f_pad_bcd_number_tmpl(imsi)
}

template (present) MSISDN ts_GTP2C_msisdn(template (present) hexstring msisdn) := {
	elementIdentifier := '4C'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	mSISDN_Value := msisdn
}
private function fs_GTP2C_msisdn(template (omit) hexstring msisdn) return
template (omit) MSISDN {
	if (istemplatekind(msisdn, "omit")) {
		return omit;
	} else {
		return ts_GTP2C_msisdn(msisdn);
	}
}

/* 8.4-1 */
type enumerated GTP2C_Cause {
	Local_Detach 				(2),
	Complete_Detach				(3),
	RAT_changed_from_3GPP_to_Non_3GPP	(4),
	ISR_deactivation			(5),
	Error_Ind_from_RNC_eNB_SGSN_MME		(6),
	IMSI_Detach_Only			(7),
	Reactivation_Required			(8),
	PDN_reconnection_to_APN_disallowed	(9),
	Access_changed_from_Non_3GPP_to_3GPP	(10),
	PDN_connection_inactivity_timer_expires	(11),
	PGW_not_responding			(12),
	Network_Failure				(13),
	QoS_parameter_mismatch			(14),
	EPS_to_5GS_Mobility			(15),
	Request_accepted			(16),
	Request_accepted_partially		(17),
	New_PDN_type_due_to_network_preference	(18),
	New_PDN_type_due_to_single_address_bearer_only (19),
	/* ... */
	Context_Not_Found			(64),
	APN_access_denied__no_subscription	(93)
} with { variant "FIELDLENGTH(8)" encode "RAW" };

/* 8.4 */
template (value) Cause ts_GTP2C_Cause(template (value) GTP2C_Cause cause,
				      template (value) BIT1 cs) := {
	elementIdentifier := '02'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	causeValue := int2oct(enum2int(valueof(cause)), 1),
	cS := cs,
	bCE := '0'B,
	pCE := '0'B,
	spare2 := '00000'B,
	typeOfOffendingIE := omit,
	lengthIndicator2 := omit,
	instanceOfOffendingIE := omit,
	spare3 := omit
}
private function enum2int_GTP2C_Cause_tmpl(template GTP2C_Cause inp) return template integer
{
	if (istemplatekind(inp, "omit")) {
		return omit;
	} else if (istemplatekind(inp, "*")) {
		return *;
	} else if (istemplatekind(inp, "?")) {
		return ?;
	} else {
		return enum2int(valueof(inp));
	}
}
template (present) Cause tr_GTP2C_Cause(template (present) GTP2C_Cause cause) := {
	elementIdentifier := '02'O,
	lengthIndicator := ?,
	instance := ?,
	spare := '0000'B,
	causeValue := int2oct_tmpl(enum2int_GTP2C_Cause_tmpl(cause), 1),
	cS := ?,
	bCE := ?,
	pCE := ?,
	spare2 := '00000'B,
	typeOfOffendingIE := *,
	lengthIndicator2 := *,
	instanceOfOffendingIE := *,
	spare3 := *
}
private function fs_GTP2C_Cause(template (omit) GTP2C_Cause cause, template (value) BIT1 cs) return
template (omit) Cause {
	if (istemplatekind(cause, "omit")) {
		return omit;
	} else {
		return ts_GTP2C_Cause(cause, cs);
	}
}
private function fr_GTP2C_Cause(template GTP2C_Cause cause) return
template Cause {
	if (istemplatekind(cause, "omit")) {
		return omit;
	} else if (istemplatekind(cause, "*")) {
		return *;
	} else {
		return tr_GTP2C_Cause(cause);
	}
}


/* 8.6 */
template (value) AccessPointName ts_GTP2C_APN(template (value) octetstring apn) := {
	elementIdentifier := '47'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	aPN_Value := apn
}
template (present) AccessPointName tr_GTP2C_APN(template (present) octetstring apn) := {
	elementIdentifier := '47'O,
	lengthIndicator := ?,
	instance := ?,
	spare := '0000'B,
	aPN_Value := apn
}

/* 8.7 */
template (value) AggregateMaximumBitRate
ts_GTP2C_Ambr(integer ambr_ul, integer ambr_dl) := {
	elementIdentifier := '48'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	aPN_AMBR_for_uplink := int2oct(ambr_ul, 4),
	aPN_AMBR_for_downlink := int2oct(ambr_dl, 4)
}

/* 8.8 */
template (value) EPS_BearerID
ts_GTP2C_EpsBearerId(template (value) uint4_t bid) := {
	elementIdentifier := '49'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	ePS_Bearer_ID_Value := bid,
	spare2 := '0000'B,
	additionalOctets := omit
}
template (present) EPS_BearerID
tr_GTP2C_EpsBearerId(template (present) uint4_t bid) := {
	elementIdentifier := '49'O,
	lengthIndicator := ?, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	ePS_Bearer_ID_Value := bid,
	spare2 := '0000'B,
	additionalOctets := *
}

/* 8.12 */
template (present) Indication
tr_GTP2C_Indication(template (present) BIT1 oI := ?) := {
	elementIdentifier := '4D'O,
	lengthIndicator := ?,
	instance := '0000'B,
	spare := '0000'B,
	sGWCI := ?,
	iSRAI := ?,
	iSRSI := ?,
	oI := oI,
	dFI := ?,
	hI := ?,
	dTF := ?,
	dAF := ?,
	mSV := ?,
	sI := ?,
	pT := ?,
	pBit := ?,
	cRSI := ?,
	cFSI := ?,
	uIMSI := ?,
	sQCI := ?,
	cCRSI := *,
	iSRAU := *,
	mBMDT := *,
	s4AF := *,
	s6AF := *,
	sRNI := *,
	pBIC := *,
	retLoc := *,
	cPSR := *,
	cLII := *,
	cSFBI := *,
	pPSI := *,
	pPON_PPEI := *,
	pPOF := *,
	aRRL := *,
	cPRAI := *,
	aOPI := *,
	aOSI := *,
	pCRI := *,
	pSCI := *,
	bDWI := *,
	dTCI := *,
	uASI := *,
	nSI := *,
	wPMSI := *,
	uNACCSI := *,
	pNSI := *,
	s11TF := *,
	pMTSMI := *,
	cPOPCI := *,
	ePCOSI := *,
	rOAAI := *,
	tSPCMI := *,
	spare_1 := *,
	spare_2 := *,
	spare_3 := *,
	spare_4 := *,
	spare_5 := *,
	spare_6 := *,
	spare_7 := *,


	additionalOctets := *
}

/* 8.14 */
template (value) PDN_AddressAllocation
ts_GTP2C_PdnAddrAlloc(template (value) BIT3 pdn_type,
		      template (value) PDN_Address_and_Prefix addr_pfx) := {
	elementIdentifier := '4F'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	pDN_Type := pdn_type,
	spare2 := '00000'B,
	pDN_Address_and_Prefix := addr_pfx
}
template (present) PDN_AddressAllocation
tr_GTP2C_PdnAddrAlloc(template (present) BIT3 pdn_type,
		      template (present) PDN_Address_and_Prefix addr_pfx) := {
	elementIdentifier := '4F'O,
	lengthIndicator := ?,
	instance := ?,
	spare := '0000'B,
	pDN_Type := pdn_type,
	spare2 := '00000'B,
	pDN_Address_and_Prefix := addr_pfx
}
template (value) PDN_AddressAllocation
ts_GTP2C_PdnAddrAlloc_v4(template (value) OCT4 addr) :=
	ts_GTP2C_PdnAddrAlloc('001'B, {iPv4_Address:=addr});
template (present) PDN_AddressAllocation
tr_GTP2C_PdnAddrAlloc_v4(template (present) OCT4 addr) :=
	tr_GTP2C_PdnAddrAlloc('001'B, {iPv4_Address:=addr});

template (value) PDN_AddressAllocation
ts_GTP2C_PdnAddrAlloc_v6(template (value) IPv6 addr) :=
	ts_GTP2C_PdnAddrAlloc('010'B, {iPv6_Address:=addr});
template (present) PDN_AddressAllocation
tr_GTP2C_PdnAddrAlloc_v6(template (present) IPv6 addr) :=
	tr_GTP2C_PdnAddrAlloc('010'B, {iPv6_Address:=addr});

template (value) PDN_AddressAllocation
ts_GTP2C_PdnAddrAlloc_v4v6(template (value) IPv4_IPv6 addr) :=
	ts_GTP2C_PdnAddrAlloc('011'B, {iPv4_IPv6:=addr});
template (present) PDN_AddressAllocation
tr_GTP2C_PdnAddrAlloc_v4v6(template (present) IPv4_IPv6 addr) :=
	tr_GTP2C_PdnAddrAlloc('011'B, {iPv4_IPv6:=addr});

/* 8.15 */
template (value) Bearer_QoS
ts_GTP2C_BearerQos(template (value) OCT1 qci,
		   uint40_t max_br_ul, uint40_t max_br_dl,
		   uint40_t g_br_ul, uint40_t g_br_dl,
		   template (value) BIT4 prio_lvl := '1001'B,
		   template (value) BIT1 pe_vuln := '0'B,
		   template (value) BIT1 pe_capa := '0'B) := {
	elementIdentifier := '50'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	pVI := pe_vuln,
	spare2 := '0'B,
	pL := prio_lvl,
	pCI := pe_capa,
	spare3 := '0'B,
	labelQCI := qci,
	maxBitrateUplink := int2oct(max_br_ul, 5),
	maxBitrateDownLink := int2oct(max_br_dl, 5),
	guaranteedBitrateUplink := int2oct(g_br_ul, 5),
	guaranteedBitrateDownLink := int2oct(g_br_dl, 5),
	additionalOctets := omit
}

/* 8.17 */
type enumerated GTP2C_RAT_Type {
	GTP2C_RAT_reserved		('00'O),
	GTP2C_RAT_UTRAN 		('01'O),
	GTP2C_RAT_GERAN			('02'O),
	GTP2C_RAT_WLAN			('03'O),
	GTP2C_RAT_GAN 			('04'O),
	GTP2C_RAT_HSPA_EVOLUTION	('05'O),
	GTP2C_RAT_EUTRAN		('06'O),
	GTP2C_RAT_Virtual		('07'O),
	GTP2C_RAT_EUTRAN_NB_IoT		('08'O),
	GTP2C_RAT_LTE_M			('09'O),
	GTP2C_RAT_NR			('0A'O)
} with { variant "FIELDLENGTH(8)" encode "RAW" };

template (value) RAT_Type ts_GTP2C_RatType(template (value) integer rat) := {
	elementIdentifier := '52'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	rAT_TypeValue := rat,
	additionalOctets := omit
}
template (present) RAT_Type tr_GTP2C_RatType(template (present) integer rat) := {
	elementIdentifier := '52'O,
	lengthIndicator := ?,
	instance := ?,
	spare := '0000'B,
	rAT_TypeValue := rat,
	additionalOctets := *
}

/* 8.21 */
function ts_GTP2C_UserLocInfo(template (omit) CGI cgi := omit,
			      template (omit) SAI sai := omit,
			      template (omit) RAI rai := omit,
			      template (omit) TAI tai := omit,
			      template (omit) ECGI ecgi := omit,
			      template (omit) LAI lai := omit)
return template (value) UserLocationInfo {
	var template (value) UserLocationInfo uli;
	uli.elementIdentifier := '56'O;
	uli.lengthIndicator := 0; // overwritten
	uli.instance := '0000'B;
	uli.spare := '0000'B;
	uli.spare2 := '00'B;
	uli.additionalOctets := omit;

	if (istemplatekind(cgi, "omit")) {
		uli.cGI_Flag := '0'B;
	} else {
		uli.cGI_Flag := '1'B;
	}
	uli.cGI := cgi;

	if (istemplatekind(sai, "omit")) {
		uli.sAI_Flag := '0'B;
	} else {
		uli.sAI_Flag := '1'B;
	}
	uli.sAI := sai;

	if (istemplatekind(rai, "omit")) {
		uli.rAI_Flag := '0'B;
	} else {
		uli.rAI_Flag := '1'B;
	}
	uli.rAI := rai

	if (istemplatekind(tai, "omit")) {
		uli.tAI_Flag := '0'B;
	} else {
		uli.tAI_Flag := '1'B;
	}
	uli.tAI := tai

	if (istemplatekind(ecgi, "omit")) {
		uli.eCGI_Flag := '0'B;
	} else {
		uli.eCGI_Flag := '1'B;
	}
	uli.eCGI := ecgi;

	if (istemplatekind(lai, "omit")) {
		uli.lAI_Flag := '0'B;
	} else {
		uli.lAI_Flag := '1'B;
	}
	uli.lAI := lai

	return uli;
}

/* 8.22 */
private function f_bit4oct(template (omit) octetstring os) return BIT1
{
	if (istemplatekind(os, "omit")) {
		return '0'B;
	} else {
		return '1'B;
	}
}
type enumerated FteidInterface {
	FTEID_IF_S1U_eNodeB_GTPU	(0),
	FTEID_IF_S1U_SGW_GTPU		(1),
	FTEID_IF_S12_RNC_GTPU		(2),
	FTEID_IF_S12_SGW_GTPU		(3),
	FTEID_IF_S5S8_SGW_GTPU		(4),
	FTEID_IF_S5S8_PGW_GTPU		(5),
	FTEID_IF_S5S8_SGW_GTPC		(6),
	FTEID_IF_S5S8_PGW_GTPC		(7),
	FTEID_IF_S5S8_SGW_PMIPv6	(8),
	FTEID_IF_S5S8_PGW_PMIPv6	(9),
	FTEID_IF_S11_MME_GTPC		(10),
	FTEID_IF_S11S4_SGW_GTPC		(11),
	FTEID_IF_S10ND26_MME_GTPC	(12),
	FTEID_IF_S3_MME_GTPC		(13),
	FTEID_IF_S3_SGSN_GTPC		(14),
	FTEID_IF_S4_SGSN_GTPU		(15),
	FTEID_IF_S4_SGW_GTPU		(16),
	FTEID_IF_S16_SGSN_GTPC		(18),
	FTEID_IF_eNB_GTPU_DL_DATA_FW	(19),
	FTEID_IF_eNB_GTPU_UL_DATA_FW	(20),
	FTEID_IF_RNC_GTPU_DATA_FW	(21),
	FTEID_IF_SGSN_GTPU_DATA_FW	(22),
	FTEID_IF_SGWUPF_GTPU_DL_DATA_FW	(23),
	FTEID_IF_Sm_MMBS_GW_GTPC	(24),
	FTEID_IF_Sn_MMBS_GW_GTPC	(25),
	FTEID_IF_Sm_MME_GTPC		(26),
	FTEID_IF_Sn_MME_GTPC		(27),
	FTEID_IF_SGW_GTPU_UL_DATA_FW	(28),
	FTEID_IF_Sn_SGSN_GTPU		(29),
	FTEID_IF_S2b_ePDG_GTPC		(30),
	FTEID_IF_S2bU_ePDG_GTPU		(31),
	FTEID_IF_S2b_PGW_GTPC		(32),
	FTEID_IF_S2bU_PGW_GTPU		(33),
	FTEID_IF_S2a_TWAN_GTPU		(34),
	FTEID_IF_S2a_TWAN_GTPC		(35),
	FTEID_IF_S2a_PGW_GTPC		(36),
	FTEID_IF_S2a_PGW_GTPU		(37),
	FTEID_IF_S11_MME_GTPU		(38),
	FTEID_IF_S11_SGW_GTPU		(39),
	FTEID_IF_N26_AMF_GTPC		(40)
};
template (value) FullyQualifiedTEID
ts_GTP2C_FTEID(FteidInterface if_type, OCT4 teid, uint4_t instance := 0,
		template (omit) OCT4 v4_addr := omit,
		template (omit) OCT16 v6_addr := omit) := {
	elementIdentifier := '57'O,
	lengthIndicator := 0, /* overwritten */
	instance := int2bit(instance, 4),
	spare := '0000'B,
	interfaceType := enum2int(if_type),
	v6_Flag := f_bit4oct(v6_addr),
	v4_Flag := f_bit4oct(v4_addr),
	tEID_GRE_Key := teid,
	iPv4_Address := v4_addr,
	iPv6_Address := v6_addr,
	additionalOctets := omit
}
template (present) FullyQualifiedTEID
tr_GTP2C_FTEID(template (present) integer if_type, template (present) OCT4 teid,
		template BIT4 instance := ?,
		template OCT4 v4_addr := omit,
		template OCT16 v6_addr := omit) := {
	elementIdentifier := '57'O,
	lengthIndicator := ?,
	instance := instance,
	spare := '0000'B,
	interfaceType := if_type,
	v6_Flag := ?,
	v4_Flag := ?,
	tEID_GRE_Key := teid,
	iPv4_Address := v4_addr,
	iPv6_Address := v6_addr,
	additionalOctets := omit
}

/* 8.28 */
template (value) BearerContextIEs
ts_GTP2C_BcContextIE(template (value) uint4_t ebi,
		   template (omit) FullyQualifiedTEID_List teid_list := omit,
		   template (omit) Bearer_QoS qos := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
		   template (omit) ChargingID charging_id := omit) := {
	ePS_Bearer_ID 			:= ts_GTP2C_EpsBearerId(ebi),
	cause 				:= ts_GTP2C_Cause(Request_accepted, '0'B),
	ePS_Bearer_TFT 			:= omit,
	fullyQualifiedTEID 		:= teid_list,
	bearerLevel_QoS 		:= qos,
	chargingID 			:= charging_id,
	bearerFlags 			:= omit,
	transactionIdentifier 		:= omit,
	protocolConfigOptions 		:= omit,
	rAN_NASCause 			:= omit,
	additionalProtocolConfigOptions := omit,
	extendedProtocolConfigOptions 	:= omit
}

template (value) BearerContextGrouped
ts_GTP2C_BcGrouped(template (value) BearerContextIEs ies) := {
	elementIdentifier := '5D'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	bearerContextIEs := ies
}
template (present) BearerContextGrouped
tr_GTP2C_BcGrouped(template (present) BearerContextIEs ies) := {
	elementIdentifier := '5D'O,
	lengthIndicator := ?, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	bearerContextIEs := ies
}

/* 8.29 */
template (value) ChargingID
ts_GTP2C_ChargingID(template (value) OCT4 chargingID_Value) := {
	elementIdentifier := '5D'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	chargingID_Value := chargingID_Value,
	additionalOctets := omit
}

/* 8.30 */
template (value) ChargingCharacteristics
ts_GTP2C_ChargingCaracteristics(template (value) OCT2 cc) := {
	elementIdentifier := '5F'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	chargingCharacteristicsValue := cc,
	additionalOctets := omit
}
template (present) ChargingCharacteristics
tr_GTP2C_ChargingCaracteristics(template (present) OCT2 cc) := {
	elementIdentifier := '5F'O,
	lengthIndicator := ?, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	chargingCharacteristicsValue := cc,
	additionalOctets := omit
}


/* 8.34 */
template (value) PDN_Type
ts_GTP2C_PdnType(template (value) BIT3 pdn_type) := {
	elementIdentifier := '63'O,
	lengthIndicator := 0,
	instance := '0000'B,
	spare := '0000'B,
	pDN_TypeValue := pdn_type,
	spare2 := '00000'B,
	additionalOctets := omit
}
template (present) PDN_Type
tr_GTP2C_PdnType(template (present) BIT3 pdn_type) := {
	elementIdentifier := '63'O,
	lengthIndicator := ?,
	instance := ?,
	spare := ?,
	pDN_TypeValue := pdn_type,
	spare2 := ?,
	additionalOctets := *
}

/* 8.35 */
template (value) ProcedureTransactionID
ts_GTP2C_ProcTransId(template (value) integer pti) := {
	elementIdentifier := '64'O,
	lengthIndicator := 0,
	instance := '0000'B,
	spare := '0000'B,
	pTI_Value := pti,
	additionalOctets := omit
}
private function f_ts_GTP2C_ProcTransId_omit(template (omit) integer pti)
return template (omit) ProcedureTransactionID {
	if (istemplatekind(pti, "omit")) {
		return omit;
	}
	return ts_GTP2C_ProcTransId(pti);
}
template (present) ProcedureTransactionID
tr_GTP2C_ProcTransId(template (present) integer pti) := {
	elementIdentifier := '64'O,
	lengthIndicator := ?,
	instance :=?,
	spare := ?,
	pTI_Value := pti,
	additionalOctets := *
}


/* 8.57 */
template (value) APN_Restriction
ts_GTP2C_ApnRestriction(template (value) integer val) := {
	elementIdentifier := '7F'O,
	lengthIndicator := 0,
	instance := '0000'B,
	spare := '0000'B,
	restrictionTypeValue := val,
	additionalOctets := omit
}
template (present) APN_Restriction
tr_GTP2C_ApnRestriction(template (present) integer val) := {
	elementIdentifier := '7F'O,
	lengthIndicator := ?,
	instance := '0000'B,
	spare := ?,
	restrictionTypeValue := val,
	additionalOctets := *
}


/* 8.58 */
template (value) SelectionMode
ts_GTP2C_SelectionMode(template (value) integer mode) := {
	elementIdentifier := '80'O,
	lengthIndicator := 0, /* overwritten */
	instance := '0000'B,
	spare := '0000'B,
	selectionModeValue := mode,
	spare2 := '000000'B,
	additionalOctets := omit
}
template (present) SelectionMode
tr_GTP2C_SelectionMode(template (present) integer mode) := {
	elementIdentifier := '80'O,
	lengthIndicator := ?,
	instance := ?,
	spare := ?,
	selectionModeValue := mode,
	spare2 := ?,
	additionalOctets := *
}

/* 8.62 Fully qualified PDN Connection Set Identifier (FQ-CSID) */
template (value) NodeID ts_GTP2C_FQCSID_NodeID_IPv4(template (value) OCT4 addr) := {
	globalUnicastIPv4 := addr
}
template (value) FullyQualifiedPDN_ConnectionSetID
ts_GTP2C_FQCSID(template (value) integer nRofCSIDs,
		template (value) integer nodeIDType,
		template (value) NodeID nodeID,
		template (value) PDN_CSID_List pDN_CSID_List,
		template (value) uint4_t instance := 0) := {
	elementIdentifier := '84'O,
	lengthIndicator := 0, /* overwritten */
	instance := int2bit(valueof(instance), 4),
	spare := '0000'B,
	nRofCSIDs := nRofCSIDs,
	nodeIDType := nodeIDType,
	nodeID := nodeID,
	pDN_CSID_List := pDN_CSID_List,
	additionalOctets := omit
}
template (value) FullyQualifiedPDN_ConnectionSetID
ts_GTP2C_FQCSID_IPv4(template (value) OCT4 addr,
		     template (value) OCT2 csid,
		     template (value) uint4_t instance := 0) :=
ts_GTP2C_FQCSID(nRofCSIDs := 1,
		nodeIDType := 0,
		nodeID := ts_GTP2C_FQCSID_NodeID_IPv4(addr),
		pDN_CSID_List := {csid},
		instance := instance);

/* 8.94 Additional Protocol Configuration Options (APCO) */
template (present) ProtocolID_or_ContainerID
tr_GTP2C_PCO_P(template (present) OCT2 protocolID_or_ContainerID := ?,
	       template (present) octetstring protID_orContID_Contents := ?) := {
	protocolID_or_ContainerID := protocolID_or_ContainerID,
	lengthIndicator := ?,
	protID_orContID_Contents := protID_orContID_Contents
}
template (value) ProtocolID_or_ContainerID
ts_GTP2C_PCO_P(template (value) OCT2 protocolID_or_ContainerID,
	       template (value) octetstring protID_orContID_Contents := ''O) := {
	protocolID_or_ContainerID := protocolID_or_ContainerID,
	lengthIndicator := 0,
	protID_orContID_Contents := protID_orContID_Contents
}

template (present) ProtocolID_or_ContainerID tr_GTP2C_PCO_P_DNS_IPv4(template (present) octetstring dns4 := ?) :=
	tr_GTP2C_PCO_P('000d'O, dns4);
template (value) ProtocolID_or_ContainerID ts_GTP2C_PCO_P_DNS_IPv4(template (value) octetstring dns4 := ''O) :=
	ts_GTP2C_PCO_P('000d'O, dns4);

template (present) ProtocolID_or_ContainerID tr_GTP2C_PCO_P_DNS_IPv6(template (present) octetstring dns6 := ?) :=
	tr_GTP2C_PCO_P('0003'O, dns6);
template (value) ProtocolID_or_ContainerID ts_GTP2C_PCO_P_DNS_IPv6(template (value) octetstring dns6 := ''O) :=
	ts_GTP2C_PCO_P('0003'O, dns6);

template (present) ProtocolID_or_ContainerID tr_GTP2C_PCO_P_PCSCF_IPv4(template (present) octetstring pcscf4 := ?) :=
	tr_GTP2C_PCO_P('000C'O, pcscf4);
template (value) ProtocolID_or_ContainerID ts_GTP2C_PCO_P_PCSCF_IPv4(template (value) octetstring pcscf4 := ''O) :=
	ts_GTP2C_PCO_P('000C'O, pcscf4);

template (present) ProtocolID_or_ContainerID tr_GTP2C_PCO_P_PCSCF_IPv6(template (present) octetstring pcscf6 := ?) :=
	tr_GTP2C_PCO_P('0001'O, pcscf6);
template (value) ProtocolID_or_ContainerID ts_GTP2C_PCO_P_PCSCF_IPv6(template (value) octetstring pcscf6 := ''O) :=
	ts_GTP2C_PCO_P('0001'O, pcscf6);

template (value) APCO
ts_GTP2C_APCO(template (value) BIT4 instance := '0000'B,
	      template (value) ProtocolIDs_and_ContainerIDs protocolIDs_and_ContainerIDs := {}) := {
	elementIdentifier := 'A3'O,
	lengthIndicator := 0,
	instance := instance,
	spare := '0000'B,
	configProtocol := '000'B,
	spare2 := '0000'B,
	extensionField := '1'B,
	protocolIDs_and_ContainerIDs := protocolIDs_and_ContainerIDs,
	additionalOctets := omit
}
template (present) APCO
tr_GTP2C_APCO(template (present) BIT4 instance := ?,
	      template ProtocolIDs_and_ContainerIDs protocolIDs_and_ContainerIDs := *) := {
	elementIdentifier := 'A3'O,
	lengthIndicator := ?,
	instance := instance,
	spare := ?,
	configProtocol := '000'B,
	spare2 := '0000'B,
	extensionField := '1'B,
	protocolIDs_and_ContainerIDs := protocolIDs_and_ContainerIDs,
	additionalOctets := *
}

template (value) PDU_GTPCv2 ts_PDU_GTP2C(template (omit) OCT4 teid, template (value) OCT3 seq,
					 template (value) OCT1 msg_type,
					 template (value) GTPCv2_PDUs pdus,
					 template (omit) PDU_GTPCv2 piggyback := omit) := {
	spare := '000'B,
	t_Bit := fs_GTP2C_t_bit(teid),
	p_Bit := fs_GTP2C_p_bit(piggyback),
	version := '010'B,
	messageType := msg_type,
	lengthf := 0, /* overwritten */
	tEID := teid,
	sequenceNumber := seq,
	spare3 := '00'O,
	gtpcv2_pdu := pdus,
	piggybackPDU_GTPCv2 := piggyback
}


template (value) PDU_GTPCv2
ts_GTP2C_EchoReq(template (value) integer rec_val) :=
ts_PDU_GTP2C(omit, '000000'O, '01'O, {
	echoRequest := {
		recovery := {
			elementIdentifier := '03'O,
			lengthIndicator := 0,
			instance := '0000'B,
			spare := '0000'B,
			recoveryValue := rec_val
		},
		sendingNodeFeatures := omit,
		privateExtension := omit
	}});
template (present) PDU_GTPCv2
tr_GTP2C_EchoReq(template (present) OCT3 seq := ?) :=
tr_PDU_GTP2C(omit, seq, { echoRequest := ? }, omit);

template (value) PDU_GTPCv2
ts_GTP2C_EchoResp(template (value) integer rec_val) :=
ts_PDU_GTP2C(omit, '000000'O, '02'O, {
	echoRequest := {
		recovery := {
			elementIdentifier := '03'O,
			lengthIndicator := 0,
			instance := '0000'B,
			spare := '0000'B,
			recoveryValue := rec_val
		},
		sendingNodeFeatures := omit,
		privateExtension := omit
	}});
template (present) PDU_GTPCv2
tr_GTP2C_EchoResp(template (present) OCT3 seq := ?) :=
tr_PDU_GTP2C(omit, seq, { echoResponse := ? }, omit);


private function f_ts_PDN_AddressAllocation_request(template (value) BIT3 pdn_type)
return template (value) PDN_AddressAllocation
{
	var template (value) PDN_AddressAllocation paa;
	select (valueof(pdn_type)) {
	case ('001'B) {
		paa := ts_GTP2C_PdnAddrAlloc_v4('00000000'O);
	}
	case ('010'B) {
		paa := ts_GTP2C_PdnAddrAlloc_v6({ prefixLength := 64,
						  iPv6_Address := '00000000000000000000000000000000'O });
	}
	case ('011'B) {
		paa := ts_GTP2C_PdnAddrAlloc_v4v6({ prefixLength := 64,
						    iPv6_Address := '00000000000000000000000000000000'O,
						    iPv4_Address := '00000000'O });
	}
	}

	return paa;
}

template (present) PDU_GTPCv2
ts_GTP2C_CreateSessionReq(template (value) hexstring imsi, template (omit) hexstring msisdn,
			  integer rat_type, template (value) FullyQualifiedTEID sender_fteid,
			  template (value) octetstring apn, template (value) BIT3 pdn_type,
			  template (omit) FullyQualifiedTEID_List teid_list,
			  template (value) OCT2 chg_car, template (value) uint4_t bearer_id,
			  template (omit) UserLocationInfo uli := omit,
			  template (value) Bearer_QoS qos := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
			  template (omit) APCO apco := omit) :=
ts_PDU_GTP2C('00000000'O, '000000'O, '20'O, {
	createSessionRequest := {
		iMSI := ts_GTP2C_Imsi(imsi),
		mSISDN := fs_GTP2C_msisdn(msisdn),
		mEI := omit,
		userLocationInfo := uli,
		servingNetwork := omit,
		rAT_Type := ts_GTP2C_RatType(rat_type),
		indication := omit,
		fullyQualifiedTEID := { sender_fteid },
		accessPointName := ts_GTP2C_APN(apn),
		selectionMode := ts_GTP2C_SelectionMode(0),
		pDN_Type := ts_GTP2C_PdnType(pdn_type),
		pDN_AddressAllocation := f_ts_PDN_AddressAllocation_request(pdn_type),
		maxAPN_Restriction := ts_GTP2C_ApnRestriction(0),
		ambr := ts_GTP2C_Ambr(102400, 102400),
		linkedEPS_Bearer_ID := omit,
		trustedWLANModeIndication := omit,
		protocolConfigOptions := omit,
		bearerContextGrouped := {
			ts_GTP2C_BcGrouped({
				ePS_Bearer_ID := ts_GTP2C_EpsBearerId(bearer_id),
				cause := omit,
				ePS_Bearer_TFT := omit,
				fullyQualifiedTEID := teid_list,
				bearerLevel_QoS := qos,
				chargingID := omit,
				bearerFlags := omit,
				transactionIdentifier := omit,
				protocolConfigOptions := omit,
				rAN_NASCause := omit,
				additionalProtocolConfigOptions := omit,
				extendedProtocolConfigOptions := omit
				})
		},
		traceInformation := omit,
		recovery := omit,
		csid := omit,
		uE_TimeZone := omit,
		user_CSG_Information := omit,
		chargingCharacteristics := ts_GTP2C_ChargingCaracteristics(chg_car),
		lDN := omit,
		signallingPriorityIndication := omit,
		iP_Addr := omit,
		portNumber := omit,
		aPCO := apco,
		trustedWLANAccessNetworkIdentifier := omit,
		cNOperatorSelectionEntity := omit,
		presenceReportingAreaInformation := omit,
		overloadControlInformationGrouped := omit,
		originationTimeStamp := omit,
		maximumWaitTime := omit,
		wLANLocationTimestamp := omit,
		nBIFOMContainer := omit,
		remoteUEContextGrouped := omit,
		nodeIdentifier := omit,
		extendedProtocolConfigOptions := omit,
		servingPLMNRateControl := omit,
		counter := omit,
		privateExtension := omit
	}});


template (present) PDU_GTPCv2
tr_GTP2C_CreateSessionReq(template (present) hexstring imsi := ?,
			  template (present) octetstring apn := ?,
			  template APCO apco := *) :=
tr_PDU_GTP2C(?, ?, {
	createSessionRequest := {
		iMSI := tr_GTP2C_Imsi(imsi),
		mSISDN := *,
		mEI := *,
		userLocationInfo := *,
		servingNetwork := *,
		rAT_Type := tr_GTP2C_RatType(?),
		indication := *,
		fullyQualifiedTEID := ?,
		accessPointName := tr_GTP2C_APN(apn), // '*'
		selectionMode := ?,
		pDN_Type := *,
		pDN_AddressAllocation := ?,
		maxAPN_Restriction := *,
		ambr := *,
		linkedEPS_Bearer_ID := omit,
		trustedWLANModeIndication := omit,
		protocolConfigOptions := omit,
		bearerContextGrouped := ?,
		traceInformation := *,
		recovery := *,
		csid := omit,
		uE_TimeZone := *,
		user_CSG_Information := omit,
		chargingCharacteristics := *,
		lDN := omit,
		signallingPriorityIndication := *,
		iP_Addr := omit,
		portNumber := omit,
		aPCO := apco,
		trustedWLANAccessNetworkIdentifier := omit,
		cNOperatorSelectionEntity := omit,
		presenceReportingAreaInformation := omit,
		overloadControlInformationGrouped := omit,
		originationTimeStamp := *,
		maximumWaitTime := *,
		wLANLocationTimestamp := omit,
		nBIFOMContainer := omit,
		remoteUEContextGrouped := *,
		nodeIdentifier := *,
		extendedProtocolConfigOptions := omit,
		servingPLMNRateControl := omit,
		counter := omit,
		privateExtension := omit
	}});

template (value) PDU_GTPCv2
ts_GTP2C_CreateSessionResp(template (value) OCT4 d_teid,
			   template (value) OCT3 seq,
			   template (value) GTP2C_Cause cause := Request_accepted,
			   template (omit) FullyQualifiedTEID_List fteids := omit,
			   template (omit) PDN_AddressAllocation addr := omit,
			   template (omit) BearerContextGrouped_List bearerContextGrouped := omit,
			   template (omit) APCO apco := omit) :=
ts_PDU_GTP2C(d_teid, seq, '21'O, {
	createSessionResponse := {
		cause := ts_GTP2C_Cause(cause, '0'B),
		changeReportingAction := omit,
		cSG_InformationReportingAction := omit,
		heNBInformationReporting := omit,
		fullyQualifiedTEID := fteids,
		pDN_AddressAllocation := addr,
		aPN_Restriction := omit,
		ambr := omit,
		linkedEPS_Bearer_ID := omit,
		protocolConfigOptions := omit,
		bearerContextGrouped := bearerContextGrouped,
		recovery := omit,
		chargingGatewayName := omit,
		chargingGatewayAddress := omit,
		csid := omit,
		lDN := omit,
		pGW_Back_OffTime := omit,
		aPCO := apco,
		trustedWLANIPv4Parameters := omit,
		indicationFlags := omit,
		presenceReportingAreaAction := omit,
		loadControlInformationGrouped := omit,
		overloadControlInformationGrouped := omit,
		nBIFOMContainer := omit,
		pDNConnectionChargingID := omit,
		extendedProtocolConfigOptions := omit,
		privateExtension := omit
	}});
template (present) PDU_GTPCv2
tr_GTP2C_CreateSessionResp(template (present) OCT4 d_teid := ?,
			   template (present) OCT3 seq := ?,
			   template (present) GTP2C_Cause cause := ?,
			   template FullyQualifiedTEID_List fteids := *,
			   template PDN_AddressAllocation addr := *,
			   template APN_Restriction apn_restriction := *,
			   template BearerContextGrouped_List bctxg := *,
			   template APCO exp_apco := *) :=
tr_PDU_GTP2C(d_teid, seq, {
	createSessionResponse := {
		cause := tr_GTP2C_Cause(cause),
		changeReportingAction := *,
		cSG_InformationReportingAction := *,
		heNBInformationReporting := *,
		fullyQualifiedTEID := fteids,
		pDN_AddressAllocation := addr,
		aPN_Restriction := apn_restriction,
		ambr := *,
		linkedEPS_Bearer_ID := *,
		protocolConfigOptions := *,
		bearerContextGrouped := bctxg,
		recovery := *,
		chargingGatewayName := *,
		chargingGatewayAddress := *,
		csid := *,
		lDN := *,
		pGW_Back_OffTime := *,
		aPCO := exp_apco,
		trustedWLANIPv4Parameters := *,
		indicationFlags := *,
		presenceReportingAreaAction := *,
		loadControlInformationGrouped := *,
		overloadControlInformationGrouped := *,
		nBIFOMContainer := *,
		pDNConnectionChargingID := *,
		extendedProtocolConfigOptions := *,
		privateExtension := *
	}});


template (value) PDU_GTPCv2
ts_GTP2C_DeleteSessionReq(template (value) OCT4 d_teid,
			  template (omit) GTP2C_Cause cause := omit,
			  template (value) FullyQualifiedTEID sender_fteid,
			  template (omit) FullyQualifiedTEID_List teid_list := omit,
			  template (value) uint4_t bearer_id) :=
ts_PDU_GTP2C(d_teid, '000000'O, '24'O, {
	deleteSessionRequest := {
		cause := fs_GTP2C_Cause(cause, '0'B),
		linkedEPS_Bearer_ID := ts_GTP2C_EpsBearerId(bearer_id),
		uLI := omit,
		indicationFlags := omit,
		protocolConfigOptions := omit,
		originatingNode := omit,
		fullyQualifiedTEID := sender_fteid,
		uE_TimeZone := omit,
		uLITimestamp := omit,
		rANNASReleaseCause := omit,
		trustedWLANAccessNetworkIdentifier := omit,
		tWANIdentifierTimestamp := omit,
		overloadControlInformationGrouped := omit,
		uELocalIP_Addr := omit,
		portNumber := omit,
		extendedProtocolConfigOptions := omit,
		privateExtension := omit
	}});
template (present) PDU_GTPCv2
tr_GTP2C_DeleteSessionReq(template (present) OCT4 d_teid := ?,
			  template (present) OCT3 seq := ?,
			  template GTP2C_Cause cause := *,
			  template (present) uint4_t bearer_id := ?,
			  template Indication indicationFlags := *,
			  template FullyQualifiedTEID sender_fteid := *) :=
tr_PDU_GTP2C(d_teid, seq, {
	deleteSessionRequest := {
		cause := fr_GTP2C_Cause(cause),
		linkedEPS_Bearer_ID := tr_GTP2C_EpsBearerId(bearer_id),
		uLI := *,
		indicationFlags := indicationFlags,
		protocolConfigOptions := *,
		originatingNode := *,
		fullyQualifiedTEID := sender_fteid,
		uE_TimeZone := *,
		uLITimestamp := *,
		rANNASReleaseCause := *,
		trustedWLANAccessNetworkIdentifier := *,
		tWANIdentifierTimestamp := *,
		overloadControlInformationGrouped := *,
		uELocalIP_Addr := *,
		portNumber := *,
		extendedProtocolConfigOptions := *,
		privateExtension := *
	}});


template (value) PDU_GTPCv2
ts_GTP2C_DeleteSessionResp(template (value) OCT4 d_teid,
			   template (value) OCT3 seq,
			   template (value) GTP2C_Cause cause) :=
ts_PDU_GTP2C(d_teid, seq, '25'O, {
	deleteSessionResponse := {
		cause := ts_GTP2C_Cause(cause, '0'B),
		recovery := omit,
		protocolConfigOptions := omit,
		indicationFlags := omit,
		loadControlInformationGrouped := omit,
		overloadControlInformationGrouped := omit,
		extendedProtocolConfigOptions := omit,
		privateExtension := omit

	}});
template (present) PDU_GTPCv2
tr_GTP2C_DeleteSessionResp(template (present) OCT4 d_teid,
			   template (present) OCT3 seq := ?,
			   template (present) GTP2C_Cause cause := ?
			) :=
tr_PDU_GTP2C(d_teid, seq, {
	deleteSessionResponse := {
		cause := tr_GTP2C_Cause(cause),
		recovery := *,
		protocolConfigOptions := *,
		indicationFlags := *,
		loadControlInformationGrouped := *,
		overloadControlInformationGrouped := *,
		extendedProtocolConfigOptions := *,
		privateExtension := *
	}});

template (value) PDU_GTPCv2
ts_GTP2C_CreateBearerReq(template (value) OCT4 d_teid,
			 template (omit) integer proc_trans_id,
			 template (value) uint4_t linked_id,
			 template (value) uint4_t bearer_id,
			 template (value) BearerContextGrouped_List bearer_ctx_list,
			 template (omit) FullyQualifiedPDN_ConnectionSetID_List csid := omit,
			 template (value) Bearer_QoS qos := ts_GTP2C_BearerQos('09'O, 0,0,0,0)) :=
ts_PDU_GTP2C(d_teid, '000000'O, '5F'O, {
	createBearerRequest := {
		procedureTransactionID := f_ts_GTP2C_ProcTransId_omit(proc_trans_id),
		linkedEPS_BearerID := ts_GTP2C_EpsBearerId(linked_id),
		protocolConfigOptions := omit,
		bearerContextGrouped := bearer_ctx_list,
		csid := csid,
		changeReportingAction := omit,
		cSG_InformationReportingAction := omit,
		heNBInformationReporting := omit,
		presenceReportingAreaAction := omit,
		indicationFlags := omit,
		loadControlInformationGrouped := omit,
		overloadControlInformationGrouped := omit,
		nBIFOMContainer := omit,
		privateExtension := omit
	}});
template (present) PDU_GTPCv2
tr_GTP2C_CreateBearerResp(template (present) OCT4 d_teid,
			   template (present) OCT3 seq := ?,
			   template (present) GTP2C_Cause cause := ?
			) :=
tr_PDU_GTP2C(d_teid, seq, {
	createBearerResponse := {
		cause := tr_GTP2C_Cause(cause),
		bearerContextGrouped := *,
		recovery := *,
		csid := *,
		protocolConfigOptions := *,
		uE_TimeZone := *,
		uLI := *,
		trustedWLANAccessNetworkIdentifier := *,
		overloadControlInformationGrouped := *,
		presenceReportingAreaInformation := *,
		iP_Addr := *,
		wLANLocationTimestamp := *,
		portNumber := *,
		nBIFOMContainer := *,
		extendedProtocolConfigOptions := *,
		privateExtension:= *
	}});

template (present) PDU_GTPCv2
tr_GTP2C_ModifyBearerReq(template (present) OCT4 d_teid := ?,
			  template (present) OCT3 seq := ?) :=
tr_PDU_GTP2C(d_teid, seq, {
	modifyBearerRequest := {
		mEI := *,
		userLocationInfo := *,
		servingNetwork := *,
		rAT_Type := *,
		indicationFlags := *,
		fullyQualifiedTEID := *,
		ambr := *,
		delayDownlinkPacketNotificationReq := *,
		bearerContextGrouped := *,
		recovery := *,
		uE_TimeZone := *,
		csid := *,
		user_CSG_Information := *,
		iP_Addr := *,
		portNumber := *,
		lDN := *,
		//maxMBR_APN_AMBR := *,
		cNOperatorSelectionEntity := *,
		presenceReportingAreaInformation := *,
		overloadControlInformationGrouped := *,
		servingPLMNRateControl := *,
		counter := *,
		privateExtension := *
	}});

template (value) PDU_GTPCv2
ts_GTP2C_ModifyBearerResp(template (value) OCT4 d_teid,
			  template (value) OCT3 seq,
			  template (value) GTP2C_Cause cause,
			  template (value) uint4_t bearer_id,
			  template (omit) BearerContextGrouped_List bearerContextGrouped := omit) :=
ts_PDU_GTP2C(d_teid, seq, '23'O, {
	modifyBearerResponse := {
		cause := ts_GTP2C_Cause(cause, '0'B),
		mSISDN := omit,
		linkedEPS_Bearer_ID := ts_GTP2C_EpsBearerId(bearer_id),
		aPN_Restriction := omit,
		protocolConfigOptions := omit,
		bearerContextGrouped := bearerContextGrouped,
		changeReportingAction := omit,
		cSG_InformationReportingAction := omit,
		heNBInformationReporting := omit,
		chargingGatewayName := omit,
		chargingGatewayAddress := omit,
		csid := omit,
		recovery := omit,
		lDN := omit,
		indicationFlags := omit,
		presenceReportingAreaAction := omit,
		loadControlInformationGrouped := omit,
		overloadControlInformationGrouped := omit,
		pDNConnectionChargingID := omit,
		privateExtension := omit
	}});

template (value) PDU_GTPCv2
ts_GTP2C_DeleteBearerReq(template (value) OCT4 d_teid,
			 template (value) integer proc_trans_id,
			 template (value) uint4_t bearer_id,
			 template (value) GTP2C_Cause cause) :=
ts_PDU_GTP2C(d_teid, '000000'O, '63'O, {
	deleteBearerRequest := {
		epsBearerIdentity := { ts_GTP2C_EpsBearerId(bearer_id) },
		bearerContextGrouped := omit,
		procedureTransactionID := ts_GTP2C_ProcTransId(proc_trans_id),
		protocolConfigOptions := omit,
		csid := omit,
		cause := ts_GTP2C_Cause(cause, '0'B),
		indicationFlags := omit,
		loadControlInformationGrouped := omit,
		overloadControlInformationGrouped := omit,
		nBIFOMContainer := omit,
		extendedProtocolConfigOptions := omit,
		privateExtension := omit
	}});


template (present) PDU_GTPCv2
tr_GTP2C_DeleteBearerResp(template (present) OCT4 d_teid,
			  template (present) OCT3 seq := ?,
			  template (present) GTP2C_Cause cause := ?) :=
tr_PDU_GTP2C(d_teid, seq, {
	deleteBearerResponse := {
		cause := tr_GTP2C_Cause(cause),
		linkedBearerIdentity := *,
		bearerContextGrouped := *,
		recovery := *,
		csid := *,
		protocolConfigOptions := *,
		uE_TimeZone := *,
		uLI := *,
		uLITimestamp := *,
		trustedWLANAccessNetworkIdentifier := *,
		tWANIdentifierTimestamp := *,
		overloadControlInformationGrouped := *,
		iP_Addr := *,
		portNumber := *,
		nBIFOMContainer := *,
		privateExtension := *
	}});

/* 8.18 */
template (value) ServingNetwork
ts_GTP2C_ServingNetwork(template (value) hexstring mcc,
			template (value) hexstring mnc,
			template (value) BIT4 instance := '0000'B) :=
{
	elementIdentifier := '53'O,
	lengthIndicator := 0, /* overwritten */
	instance := instance,
	spare := '0000'B,
	mccDigit1 := mcc[0],
	mccDigit2 := mcc[1],
	mccDigit3 := mcc[2],
	mncDigit3 := mnc[2], /* 'F'H for 2 digit MNC */
	mncDigit1 := mnc[0],
	mncDigit2 := mnc[1],
	additionalOctets := omit
}



}
