module BSSGP_Types {

/* BSSGP type definitions in TTCN-3
 * (C) 2018 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 GSM_Types all;
	import from GSM_RR_Types all;
	import from L3_Templates all;
	import from BSSGP_Helper_Functions all;

	type enumerated BssgpPduType {
		DL_UNITDATA		('00'H),
		UL_UNITDATA		('01'H),
		RA_CAPABILITY		('02'H),
		DL_MBMS_UNITDATA	('04'H),
		UL_MBMS_UNITDATA	('05'H),
		/* between GMM SAPs */
		PAGING_PS		('06'H),
		PAGING_CS		('07'H),
		RA_CAPABILITY_UPDATE	('08'H),
		RA_CAPABILITY_UPDATE_ACK ('09'H),
		RADIO_STATUS		('0A'H),
		SUSPEND			('0B'H),
		SUSPEND_ACK		('0C'H),
		SUSPEND_NACK		('0D'H),
		RESUME			('0E'H),
		RESUME_ACK		('0F'H),
		RESUME_NACK		('10'H),
		/* between NM SAPs */
		BVC_BLOCK		('20'H),
		BVC_BLOCK_ACK		('21'H),
		BVC_RESET		('22'H),
		BVC_RESET_ACK		('23'H),
		BVC_UNBLOCK		('24'H),
		BVC_UNBLOCK_ACK		('25'H),
		FLOW_CONTROL_BVC	('26'H),
		FLOW_CONTROL_BVC_ACK	('27'H),
		FLOW_CONTROL_MS		('28'H),
		FLOW_CONTROL_MS_ACK	('29'H),
		FLUSH_LL		('2A'H),
		FLUSH_LL_ACK		('2B'H),
		LLC_DISCARDED		('2C'H),
		FLOW_CONTROL_PFC	('2D'H),
		FLOW_CONTROL_PFC_ACK	('2E'H),
		SGSN_INVOKE_TRACE	('40'H),
		STATUS			('41'H)
		/* between PFM SAPs : TODO */
		/* between LCS SAPs : TODO */
		/* between RIM SAPs : TODO */
		/* between MBMS SAPs : TODO */
	} with { variant "FIELDLENGTH(8)" };

	type enumerated BssgpIEI {
		ALIGNMENT_OCTETS		('00'H),
		BMAX_DEFAULT_MS			('01'H),
		BSS_AREA_INDICATION		('02'H),
		BUCKET_LEAK_RATE		('03'H),
		BVCI				('04'H),
		BVC_BUCKET_SIZE			('05'H),
		BVC_MEASUREMENT			('06'H),
		CAUSE				('07'H),
		CELL_ID				('08'H),
		CHENNEL_NEEDED			('09'H),
		DRX_PARAMETERS			('0A'H),
		EMLPP_PRIORITY			('0B'H),
		FLUSH_ACTION			('0C'H),
		IMSI				('0D'H),
		LLC_PDU				('0E'H),
		LLC_FRAMES_DISCARDED		('0F'H),
		LOCATION_AREA			('10'H),
		MOBILE_IDENTITY			('11'H),
		MS_BUCKET_SIZE			('12'H),
		MS_RADIO_ACCESS_CAPABILITY	('13'H),
		OMC_ID				('14'H),
		PDU_IN_ERROR			('15'H),
		PDU_LIFETIME			('16'H),
		PRIORITY			('17'H),
		QOS_PROFILE			('18'H),
		RADIO_CAUSE			('19'H),
		RA_CAP_UPD_CAUSE		('1A'H),
		ROUTEING_AREA			('1B'H),
		R_DEFAULT_MS			('1C'H),
		SUSPE_DN_REFERENCE_NR		('1D'H),
		TAG				('1E'H),
		TLLI				('1F'H),
		TMSI				('20'H),
		TRACE_REFERENCE			('21'H),
		TRACE_TYPE			('22'H),
		TRANSACTION_ID			('23'H),
		TRIGGER_ID			('24'H),
		NUMBER_OF_OCTETS_AFFECTED	('25'H),
		LSA_IDENTIFIER_LIST		('26'H),
		LSA_INFORMATION			('27'H),
		PACKET_FLOW_IDENTIFIER		('28'H),
		PACKET_FLOW_TIMER		('29'H),
		AGGREGATE_BSS_QOS_PROFILE	('3a'H),
		FEATURE_BITMAP			('3b'H),
		BUCKET_FILL_RATIO		('3c'H),
		SERVICE_UTRAN_CCO		('3d'H),
		NSEI				('3e'H),
		RRLP_APDU			('3f'H),
		LCS_QOS				('40'H),
		LCS_CLIENT_TYPE			('41'H),
		REQUESTED_GPS_ASSIST_DATA	('42'H),
		LOCATION_TYPE			('43'H),
		LOCATION_ESTIMATE		('44'H),
		POSITIONING_DATA		('45'H),
		DECIPHERING_KEYS		('46'H),
		LCS_PRIORITY			('47'H),
		LCS_CAUSE			('48'H),
		LCS_CAPABILITY			('49'H),
		RRLP_FLAGS			('4a'H),
		RIM_APPLICATION_IDENTITY	('4b'H),
		RIM_SEQUENCE_NUMBER		('4c'H),
		RAN_INFO_REUEST_AC		('4d'H),
		RAN_INFO_AC			('4e'H),
		RIM_PDU_INDICATIONS		('4f'H),
		PFC_FLOC_CONTROL_PARAMETERS	('52'H),
		GLOBAL_CN_ID			('53'H),
		RIM_ROUTING_INFORMATION		('54'H),
		RIM_PROTOCOL_VERSION_NUMBER	('55'H),
		APP_ERROR_CONTAINER		('56'H),
		/* FIXME */
		EXTENDED_FEATURE_BITMAP		('69'H)
	} with { variant "FIELDLENGTH(8)" };

	type enumerated BssgpCause {
		BSSGP_CAUSE_PROC_OVERLOAD			('00'H),
		BSSGP_CAUSE_EQUIMENT_FAILURE			('01'H),
		BSSGP_CAUSE_TRANSIT_NETWORK_FAILURE		('02'H),
		BSSGP_CAUSE_NET_SV_CAP_MOD_GT_ZERO_KBPS		('03'H),
		BSSGP_CAUSE_UNKNOWN_MS				('04'H),
		BSSGP_CAUSE_BVCI_UNKNOWN			('05'H),
		BSSGP_CAUSE_CELL_TRAFFIC_CONGESTION		('06'H),
		BSSGP_CAUSE_SGSN_CONGESTION			('07'H),
		BSSGP_CAUSE_OM_INTERVENTION			('08'H),
		BSSGP_CAUSE_BVCI_BLOCKED			('09'H),
		BSSGP_CAUSE_PFC_CREATE_FAILURE			('0a'H),
		BSSGP_CAUSE_PFC_PREEMPTED			('0b'H),
		BSSGP_CAUSE_ABQP_NO_MORE_SUPPORTED		('0c'H),
		BSSGP_CAUSE_SEMANTICALLY_INCORRECT_PDU		('20'H),
		BSSGP_CAUSE_INVALID_MANDATORY_IE		('21'H),
		BSSGP_CAUSE_MISSING_MANDATORY_IE		('22'H),
		BSSGP_CAUSE_MISSING_CONDITIONAL_IE		('23'H),
		BSSGP_CAUSE_UNEXPECTED_CONDITIONAL_IE		('24'H),
		BSSGP_CAUSE_CONDITIONAL_IE_ERROR		('25'H),
		BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE ('26'H),
		BSSGP_CAUSE_PROTOCOL_ERROR_UNSPECIFIED		('27'H),
		BSSGP_CAUSE_PDU_NOT_COMPATIBLE_WITH_FEATURE_SET	('28'H),
		BSSGP_CAUSE_REQUESTED_INFO_NOT_AVAILABLE	('29'H),
		BSSGP_CAUSE_UNKNOWN_DESTINATION_ADDRESS		('2a'H),
		BSSGP_CAUSE_UNKNOWN_RIM_APP_IDENTITY		('2b'H),
		BSSGP_CAUSE_INVALID_CONTAINER_UNIT_INFO		('2c'H),
		BSSGP_CAUSE_PFC_QUEUING				('2d'H),
		BSSGP_CAUSE_PFC_CREATED_SUCCESSFULLY		('2e'H),
		BSSGP_CAUSE_T12_EXPIRY				('2f'H),
		BSSGP_CAUSE_MS_UNDER_PS_HANDOVER_TREATMENT	('30'H),
		BSSGP_CAUSE_UPLINK_QUALITY			('31'H),
		BSSGP_CAUSE_UPLINK_STRENGTH			('32'H),
		BSSGP_CAUSE_DOWNLINK_QUALITY			('33'H),
		BSSGP_CAUSE_DOWNLINK_STRENGTH			('34'H),
		BSSGP_CAUSE_DISTANCE				('35'H),
		BSSGP_CAUSE_BETTER_CELL				('36'H),
		BSSGP_CAUSE_TRAFFIC				('37'H),
		BSSGP_CAUSE_OM_INTERVENTION2			('38'H),
		BSSGP_CAUSE_MS_BACK_ON_OLD_CHANNEL		('39'H),
		BSSGP_CAUSE_T13_EXPIRY				('3a'H),
		BSSGP_CAUSE_T14_EXPIRY				('3b'H),
		BSSGP_CAUSE_NOT_ALL_REQUESTED_PFC_CREATED	('3c'H)
	} with { variant "FIELDLENGTH(8)" };

	/* 11.3.28 */
	type record BssgpQosProfile {
		uint16_t	r,
		BIT2		spare,
		boolean		c_r,
		boolean		t,
		boolean		a,
		uint3_t		precedence
	} with { variant (c_r) "FIELDLENGTH(1)"
		 variant (t) "FIELDLENGTH(1)"
		 variant (a) "FIELDLENGTH(1)"
	};

	/* 11.3.84 */
	type record BssgpFeatureBitmap {
		boolean		mbms,
		boolean		enh_radio_status,
		boolean		pfc_fc,
		boolean		rim,
		boolean		lcs,
		boolean		inr,
		boolean		cbl,
		boolean		pfc
	} with { variant "" };

	/* 11.3.47 */
	type record BssgpServiceUtranCco {
		uint5_t		spare,
		uint3_t		value_part
	} with { variant "" };

	/* 11.3.84 */
	type record BssgpExtendedFeatureBitmap {
		BIT7		spare,
		BIT1		ps_handover
	} with { variant "" };

	type uint16_t BssgpPduLifetime;

	/* TS 48.008 3.2.2.18 */
	type record BssmapPriority {
		BIT1		spare,
		boolean		pci,
		uint4_t		level,
		boolean		qa,
		boolean		pvi
	} with { variant "" };

	type BssmapPriority BssgpPriority;

	type uint32_t BssgpTlli;

	type uint16_t BssgpBvci;

	type record BssgpCellId {
		RoutingAreaIdentification	ra_id,
		CellIdentity			cell_id
	} with { variant "" };

	type union BssgpIeUnion {
		uint16_t		bmax_default_ms,  /* 11.3.2 */
		uint16_t		bucket_leak_rate, /* 11.3.4 */
		uint16_t		bvc_bucket_size,  /* 11.3.5 */
		BssgpBvci		bvci,		/* 11.3.6 */
		uint16_t		bvc_measurement, /* 11.3.7 */
		BssgpCause		cause,		/* 11.3.8 */
		BssgpCellId		cell_id,	/* 11.3.9 */
		DrxParameter		drx_parameter,	/* 10.3.11 */
		MobileIdentityV		imsi,		/* 11.3.14 */
		LocationAreaIdentification lai,		/* 11.3.17 */
		MobileIdentityV		mobile_id,	/* 11.3.20 */
		BssgpPduLifetime	pdu_lifetime,	/* 11.3.25 */
		BssgpPriority		priority,	/* 11.3.27 */
		BssgpQosProfile		qos_profile,	/* 11.3.28 */
		BssgpTlli		tlli,		/* 11.3.25 */
		uint16_t		r_default_ms,	/* 11.3.32 */
		GsmTmsi			tmsi,		/* 11.3.36 */
		BssgpServiceUtranCco	svc_utran_cco,	/* 11.3.47 */
		BssgpFeatureBitmap	feature_bitmap,	/* 11.3.40 */
		BssgpExtendedFeatureBitmap ext_feature_bitmap,	/* 11.3.84 */
		octetstring		other
	};

	type record BssgpTLV {
		BssgpIEI	iei,
		/* we cannot express a variable-length "length" field with extension octets in the TTCN-3
		 * syntax, so we simply assume a plain 16 bit length value here and have a 'pseudl-BSSGP'
		 * translator in front which explands all variable-length "length" fields to 16bits */
		uint16_t	len,
		BssgpIeUnion	u
	} with {
		variant (u) "CROSSTAG(
					bmax_default_ms,	iei = BMAX_DEFAULT_MS;
					bucket_leak_rate,	iei = BUCKET_LEAK_RATE;
					bvc_bucket_size,	iei = BVC_BUCKET_SIZE;
					bvci,			iei = BVCI;
					bvc_measurement,	iei = BVC_MEASUREMENT;
					cause,			iei = CAUSE;
					cell_id,		iei = CELL_ID;
					drx_parameter,		iei = DRX_PARAMETERS;
					imsi,			iei = IMSI;
					lai,			iei = LOCATION_AREA;
					priority,		iei = PRIORITY;
					mobile_id,		iei = MOBILE_IDENTITY;
					pdu_lifetime,		iei = PDU_LIFETIME;
					qos_profile,		iei = QOS_PROFILE;
					tlli,			iei = TLLI;
					r_default_ms,		iei = R_DEFAULT_MS;
					tmsi,			iei = TMSI;
					svc_utran_cco,		iei = SERVICE_UTRAN_CCO;
					feature_bitmap,		iei = FEATURE_BITMAP;
					ext_feature_bitmap,	iei = EXTENDED_FEATURE_BITMAP;
					other, OTHERWISE)"
		variant (len) "LENGTHTO(u)"
	};

	external function enc_BssgpTLV(in BssgpTLV pdu) return octetstring
		with { extension "prototype(convert) encode(RAW)" };
	external function dec_BssgpTLV(in octetstring stream) return BssgpTLV
		with { extension "prototype(convert) decode(RAW)" };


	type record of BssgpTLV BssgpTLVs;

	/* 10.2.1 */
	type record BssgpDlUnitdata {
		BssgpTlli		tlli,
		BssgpQosProfile		qos_profile,
		BssgpTLV		pdu_lifetime,
		/* optional parts */
		BssgpTLVs		tlvs
	} with { variant "" };

	/* 10.2.2 */
	type record BssgpUlUnitdata {
		BssgpTlli		tlli,
		BssgpQosProfile		qos_profile,
		BssgpTLV		cell_id,
		/* optional parts */
		BssgpTLVs		tlvs
	} with { variant "" };

	type record BssgpNormalPdu {
		BssgpTLVs		tlvs optional
	} with { variant "" };

	type union BssgpPduUnion {
		BssgpDlUnitdata		dl_unitdata,
		BssgpUlUnitdata		ul_unitdata,
		BssgpNormalPdu		other
	};

	type record BssgpPdu {
		BssgpPduType		pdu_type,
		BssgpPduUnion		u
	} with {
		variant (u) "CROSSTAG(
					dl_unitdata,	pdu_type = DL_UNITDATA;
					ul_unitdata,	pdu_type = UL_UNITDATA;
					other,		OTHERWISE)"
	}

	external function enc_BssgpPdu(in BssgpPdu pdu) return octetstring
		with { extension "prototype(convert) encode(RAW)" };
	external function dec_BssgpPdu(in octetstring stream) return BssgpPdu
		with { extension "prototype(convert) decode(RAW)" };

	template BssgpPdu t_BSSGP_other(template BssgpPduType pdu_type, template BssgpTLVs tlvs) := {
		pdu_type := pdu_type,
		u := {
			other := {
				tlvs := tlvs
			}
		}
	}

	template BssgpTLV t_BSSGP_IE_Cause(template BssgpCause cause) := {
		iei := CAUSE,
		len := 1,
		u := { cause := cause }
	}

	template BssgpTLV t_BSSGP_IE_Bvci(template BssgpBvci bvci) := {
		iei := BVCI,
		len := 2,
		u := { bvci := bvci }
	}

	template BssgpTLV t_BSSGP_IE_CellId(template BssgpCellId cid) := {
		iei := CELL_ID,
		len := 8,
		u := { cell_id := cid }
	}

	template BssgpTLV t_BSSGP_IE_Lifetime(uint16_t time) := {
		iei := PDU_LIFETIME,
		len := 2,
		u := { pdu_lifetime := time }
	}

	template BssgpTLV t_BSSGP_IE_Tmsi(template GsmTmsi tmsi) := {
		iei := TMSI,
		len := 4,
		u := { tmsi := tmsi }
	}

	template BssgpTLV t_BSSGP_IE_Imsi(template hexstring imsi) := {
		iei := IMSI,
		len := 4,
		u := { mobile_id := tr_MI_IMSI(imsi) }
	}

	template BssgpTLV t_BSSGP_IE_Qos(BssgpQosProfile qos) := {
		iei := QOS_PROFILE,
		len := 0,
		u := {
			qos_profile := qos
		}
	}

	template BssgpTLV t_BssgpIE(template BssgpIEI iei, template BssgpIeUnion u) := {
		iei := iei,
		len := 0,
		u := u
	}

	template BssgpTLV t_BSSGP_IE_PDU(BssgpPdu pdu) :=
		t_BssgpIE(PDU_IN_ERROR, { other := f_BSSGP_compact_len(enc_BssgpPdu(pdu)) });

	template BssgpPdu t_BVC_RESET(template BssgpCause cause, template BssgpBvci bvci, template BssgpCellId cell_id) := 
		t_BSSGP_other(BVC_RESET, { t_BSSGP_IE_Bvci(bvci), t_BSSGP_IE_Cause(cause), t_BSSGP_IE_CellId(cell_id) });
	template BssgpPdu t_BVC_RESET_ACK(template BssgpBvci bvci, template BssgpCellId cell_id) := 
		t_BSSGP_other(BVC_RESET_ACK, { t_BSSGP_IE_Bvci(bvci), t_BSSGP_IE_CellId(cell_id) });

	template BssgpPdu t_BVC_UNBLOCK(template BssgpBvci bvci) := t_BSSGP_other(BVC_UNBLOCK, { t_BSSGP_IE_Bvci(bvci) });
	template BssgpPdu t_BVC_UNBLOCK_ACK(template BssgpBvci bvci) := t_BSSGP_other(BVC_UNBLOCK_ACK, { t_BSSGP_IE_Bvci(bvci) });

	template BssgpPdu t_BVC_BLOCK(template BssgpBvci bvci, template BssgpCause cause) := 
		t_BSSGP_other(BVC_BLOCK, { t_BSSGP_IE_Bvci(bvci), t_BSSGP_IE_Cause(cause) });
	template BssgpPdu t_BVC_BLOCK_ACK(template BssgpBvci bvci) := t_BSSGP_other(BVC_BLOCK_ACK, { t_BSSGP_IE_Bvci(bvci) });


	template BssgpPdu tr_BSSGP_type(template BssgpPduType pdu_type, template BssgpPduUnion u := ?) := {
		pdu_type := pdu_type,
		u := u
	}

	template BssgpPdu t_BVC_FC_BVC := t_BSSGP_other(FLOW_CONTROL_BVC, ?);
	template BssgpPdu t_BVC_FC_BVC_ACK := t_BSSGP_other(FLOW_CONTROL_BVC_ACK, {});
	template BssgpPdu t_BVC_FC_MS := t_BSSGP_other(FLOW_CONTROL_MS, ?);
	template BssgpPdu t_BVC_FC_MS_ACK := t_BSSGP_other(FLOW_CONTROL_MS_ACK, {});

	template BssgpPdu t_BSSGP_STATUS(template BssgpTLVs tlvs) := t_BSSGP_other(STATUS, tlvs);
	
} with { encode "RAW" };