module BSSLAP_Types {

/* BSSLAP_Types, defining abstract TTCN-3 data types for the 3GPP BSSLAP protocol.
 *
 * BSSLAP is a 3GPP standard protocol used between BSC and SMLC in a GSM network.
 * This file covers 3GPP TS 48.071 version 15.0.0 Release 15
 *
 * (C) 2020 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;


/* 3GPP TS 48.071 Table 5.1 */
type enumerated BSSLAP_IEI {
	BSSLAP_IEI_TA			('00000001'B),
	BSSLAP_IEI_CELL_ID		('00001001'B),
	BSSLAP_IEI_CHAN_DESC		('00010000'B),
	BSSLAP_IEI_MEAS_REP		('00010100'B),
	BSSLAP_IEI_CAUSE		('00011000'B),
	BSSLAP_IEI_RRLP_FLAG		('00011001'B),
	BSSLAP_IEI_RRLP			('00011011'B),
	BSSLAP_IEI_CELL_ID_LIST		('00011100'B),
	BSSLAP_IEI_ENH_MEAS_REP		('00011101'B),
	BSSLAP_IEI_LAC			('00011110'B),
	BSSLAP_IEI_FREQ_LIST		('00100001'B),
	BSSLAP_IEI_MS_POWER		('00100010'B),
	BSSLAP_IEI_DELTA_TIMER		('00100011'B),
	BSSLAP_IEI_SERVING_CELL_ID	('00100100'B),
	BSSLAP_IEI_ENCR_KEY		('00100101'B),
	BSSLAP_IEI_CIPH_MODE_SET	('00100110'B),
	BSSLAP_IEI_CHAN_MODE		('00100111'B),
	BSSLAP_IEI_MR_CONFIG		('00101000'B),
	BSSLAP_IEI_POLLING_REPETITION	('00101001'B),
	BSSLAP_IEI_PACKET_CHAN_DESC	('00101010'B),
	BSSLAP_IEI_TLLI			('00101011'B),
	BSSLAP_IEI_TFI			('00101100'B),
	BSSLAP_IEI_TBF_START_TIME	('00101101'B),
	BSSLAP_IEI_PWRUP_START_TIME	('00101110'B),
	BSSLAP_IEI_LONG_ENCR_KEY	('00101111'B),
	BSSLAP_IEI_CONCUR_POS_PROC_F	('00110000'B)
} with { variant "FIELDLENGTH(8)" };

/* 3GPP TS 48.071 Section 5.1 */
type enumerated BSSLAP_MsgType {
	BSSLAP_MSGT_TA_REQUEST		('00000001'B),
	BSSLAP_MSGT_TA_RESPONSE		('00000010'B),
	BSSLAP_MSGT_REJECT		('00001010'B),
	BSSLAP_MSGT_RESET		('00001011'B),
	BSSLAP_MSGT_ABORT		('00001100'B),
	BSSLAP_MSGT_TA_LAYER3		('00001101'B),
	BSSLAP_MSGT_MS_POS_CMD		('00001111'B),
	BSSLAP_MSGT_MS_POS_RESP		('00010000'B),
	BSSLAP_MSGT_UTDOA_REQ		('00010001'B),
	BSSLAP_MSGT_UTDOA_RESP		('00010010'B)
} with { variant "FIELDLENGTH(8)" };


/* Section 4.2.1 */
type record BSSLAP_TaRequest {
	BSSLAP_MsgType			msg_type
};

/* Section 4.2.2 */
type record BSSLAP_TaResponse {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_CellId		serving_cell_id,
	BSSLAP_IE_TimingAdvance		timing_advance,
	BSSLAP_IE_MeasRep		meas_rep optional,
	BSSLAP_IE_EnhMeasRep		enh_meas_rep optional,
	BSSLAP_IE_CellIdList		meas_cell_id_list optional,
	BSSLAP_IE_ConcurMethodF		concur_meth_flag optional
};

/* Section 4.2.5 */
type record BSSLAP_Reject {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_Cause			cause
};

/* Section 4.2.6 */
type record BSSLAP_Reset {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_CellId		cell_id,
	BSSLAP_IE_TimingAdvance		timing_advance,
	BSSLAP_IE_ChanDesc		chan_desc,
	BSSLAP_IE_Cause			cause,
	BSSLAP_IE_MeasRep		meas_rep optional,
	BSSLAP_IE_EnhMeasRep		enh_meas_rep optional,
	BSSLAP_IE_CellIdList		meas_cell_id_list optional,
	BSSLAP_IE_LAC			lac optional,
	BSSLAP_IE_FreqList		freq_list optional,
	BSSLAP_IE_ChanMode		chan_mode optional,
	BSSLAP_IE_MultiRateConfig	mr_config optional,
	BSSLAP_IE_PacketChanDesc	pkt_chan_desc optional,
	BSSLAP_IE_TLLI			tlli optional,
	BSSLAP_IE_TFI			tfi optional,
	BSSLAP_IE_StartingTime		tbf_start_time optional,
	BSSLAP_IE_EncryptionKey		encr_key optional,
	BSSLAP_IE_CiphModeSet		ciph_mode_set optional,
	BSSLAP_IE_LongEncryptionKey	long_encr_key optional
};

/* Section 4.2.7 */
type record BSSLAP_Abort {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_Cause			cause
};

/* Section 4.2.8 */
type record BSSLAP_TA_Layer3 {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_TimingAdvance		timing_advance,
	BSSLAP_IE_MeasRep		meas_rep optional,
	BSSLAP_IE_EnhMeasRep		enh_meas_rep optional,
	BSSLAP_IE_CellIdList		meas_cell_id_list optional
};

/* Section 4.2.9 */
type record BSSLAP_MS_PosCmd {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_RrlpFlag		flag,
	BSSLAP_IE_Rrlp			rrlp_info
};

/* Section 4.2.10 */
type record BSSLAP_MS_PosResp {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_RrlpFlag		flag,
	BSSLAP_IE_Rrlp			rrlp_info,
	BSSLAP_IE_TimingAdvance		timing_advance optional,
	BSSLAP_IE_MeasRep		meas_rep optional,
	BSSLAP_IE_EnhMeasRep		enh_meas_rep optional,
	BSSLAP_IE_CellIdList		meas_cell_id_list optional,
	BSSLAP_IE_ConcurMethodF		concur_meth_flag optional
};

/* Section 4.2.11 */
type record BSSLAP_UTDOA_Req {
	BSSLAP_MsgType			msg_type,
	BSSLAP_IE_DeltaTimer		delta_timer optional,
	BSSLAP_IE_PollingRep		polling_repetition optional
};

type union BSSLAP_PDU {
	BSSLAP_TaRequest	ta_req,
	BSSLAP_TaResponse	ta_resp,
	BSSLAP_Reject		reject,
	BSSLAP_Reset		reset,
	BSSLAP_Abort		abort,
	BSSLAP_TA_Layer3	ta_layer3,
	BSSLAP_MS_PosCmd	ms_pos_cmd,
	BSSLAP_MS_PosResp	ms_pos_resp,
	BSSLAP_UTDOA_Req	utdoa_req
	// TODO: U-TDOA Resp
} with { variant "TAG(
		ta_req,		msg_type = BSSLAP_MSGT_TA_REQUEST;
		ta_resp,	msg_type = BSSLAP_MSGT_TA_RESPONSE;
		reject,		msg_type = BSSLAP_MSGT_REJECT;
		reset,		msg_type = BSSLAP_MSGT_RESET;
		abort,		msg_type = BSSLAP_MSGT_ABORT;
		ta_layer3,	msg_type = BSSLAP_MSGT_TA_LAYER3;
		ms_pos_cmd,	msg_type = BSSLAP_MSGT_MS_POS_CMD;
		ms_pos_resp,	msg_type = BSSLAP_MSGT_MS_POS_RESP;
		utdoa_req,	msg_type = BSSLAP_MSGT_UTDOA_REQ;
		)"
};


/* Section 5.2 */
type record BSSLAP_IE_TimingAdvance {
	BSSLAP_IEI		iei,
	uint8_t			ta
} with { variant "PRESENCE(iei = BSSLAP_IEI_TA)" };


/* Section 5.4 */
type record BSSLAP_IE_CellId {
	BSSLAP_IEI		iei,
	uint16_t		cell_id
} with { variant "PRESENCE(iei = BSSLAP_IEI_CELL_ID)" };

/* Section 5.8 */
type record BSSLAP_IE_ChanDesc {
	BSSLAP_IEI		iei,
	OCT3			chan_desc
} with { variant "PRESENCE(iei = BSSLAP_IEI_CHAN_DESC)" };


/* Section 5.12 */
type record BSSLAP_IE_MeasRep {
	BSSLAP_IEI		iei,
	uint8_t			len,
	octetstring		meas_rep
} with {
	variant "PRESENCE(iei = BSSLAP_IEI_MEAS_REP)"
	variant (len) "LENGTHTO(meas_rep)"
};

/* Section 5.14 */
type record BSSLAP_IE_Cause {
	BSSLAP_IEI		iei,
	BSSLAP_Cause		cause
} with { variant "PRESENCE(iei = BSSLAP_IEI_CAUSE)" };
type enumerated BSSLAP_Cause {
	BSSLAP_CAUSE_CONGESTION			('00000000'B),
	BSSLAP_CAUSE_CHAN_MODE_NOT_SUPP		('00000001'B),
	BSSLAP_CAUSE_POS_PROC_NOT_SUPP		('00000010'B),
	BSSLAP_CAUSE_OTHER_RADIO_EVT_FAIL	('00000011'B),
	BSSLAP_CAUSE_INTRA_BSS_HO		('00000100'B),
	BSSLAP_CAUSE_SUPERV_TIMER_EXPIRED	('00000101'B),
	BSSLAP_CAUSE_INTER_BSS_HO		('00000110'B),
	BSSLAP_CAUSE_LOSS_SIG_CONN_MS		('00000111'B),
	BSSLAP_CAUSE_INCORR_SERV_CELL_ID	('00001000'B),
	BSSLAP_CAUSE_BSSAP_LE_SEGMENT_ERR	('00001001'B),
	BSSLAP_CAUSE_CONCUR_POS_PROC_NOT_EN	('00001010'B)
};

/* Section 5.15 */
type record BSSLAP_IE_RrlpFlag {
	BSSLAP_IEI		iei,
	BIT7			spare,
	boolean			not_a_pos_cmd
} with { variant "PRESENCE(iei = BSSLAP_IEI_RRLP_FLAG)" };

/* Section 5.16 */
type record BSSLAP_IE_Rrlp {
	BSSLAP_IEI		iei,
	uint16_t		len,
	octetstring		rrlp_apdu
} with {
	variant "PRESENCE(iei = BSSLAP_IEI_RRLP)"
	variant (len) "LENGTHTO(rrlp_apdu)"
};

/* Section 5.17 */
type record BSSLAP_IE_CellIdList {
	BSSLAP_IEI		iei,
	uint8_t			len,
	BSSLAP_CellIdList	cell_id_list
} with {
	variant "PRESENCE(iei = BSSLAP_IEI_CELL_ID_LIST)"
	variant (len) "LENGTHTO(cell_id_list)"
};
type record of BSSLAP_CellIdListEnt BSSLAP_CellIdList;
type union BSSLAP_CellIdListEnt {
	BIT4			spare,
	BSSLAP_CellIdDiscr	discr,
	BSSLAP_CellIdListEntU	u
}// with {
//};
type enumerated BSSLAP_CellIdDiscr {
	BSSLAP_CIDL_DISC_CGI	('0000'B),
	BSSLAP_CIDL_DISC_LAC_CI	('0001'B),
	BSSLAP_CIDL_DISC_3G_1	('0010'B),
	BSSLAP_CIDL_DISC_3G_2	('0011'B)
} with { variant "FIELDLENGTH(4)" };
type union BSSLAP_CellIdListEntU {
	BSSLAP_CellIdListEntCGI		cgi,
	BSSLAP_CellIdListEntLACCI	lac_ci,
	BSSLAP_CellIdListEnt3G1		umts_cont1,
	BSSLAP_CellIdListEnt3G2		umts_cont2
};
type record BSSLAP_CellIdListEntCGI {
	HEX6n		mcc_mnc,
	uint16_t	lac,
	uint16_t	ci
};
type record BSSLAP_CellIdListEntLACCI {
	uint16_t	lac,
	uint16_t	ci
};
type record BSSLAP_CellIdListEnt3G1 {
	OCT9		cont
};
type record BSSLAP_CellIdListEnt3G2 {
	OCT6		cont
};

/* Section 5.18 */
type record BSSLAP_IE_EnhMeasRep {
	BSSLAP_IEI		iei,
	uint8_t			len,
	octetstring		meas_rep
} with {
	variant "PRESENCE(iei = BSSLAP_IEI_ENH_MEAS_REP)"
	variant (len) "LENGTHTO(meas_rep)"
};

/* Section 5.19 */
type record BSSLAP_IE_LAC {
	BSSLAP_IEI		iei,
	uint16_t		lac
} with { variant "PRESENCE(iei = BSSLAP_IEI_LAC)" };

/* Section 5.20 */
type record BSSLAP_IE_FreqList {
	BSSLAP_IEI		iei,
	uint8_t			len,
	octetstring		freq_list
} with {
	variant "PRESENCE(iei = BSSLAP_IEI_FREQ_LIST)"
	variant (len) "LENGTHTO(freq_list)"
};

/* Section 5.21 */
type record BSSLAP_IE_MsPower {
	BSSLAP_IEI		iei,
	uint8_t			ms_pwr
} with { variant "PRESENCE(iei = BSSLAP_IEI_MS_POWER)" };

/* Section 5.22 */
type record BSSLAP_IE_DeltaTimer {
	BSSLAP_IEI		iei,
	uint8_t			timer_val
} with { variant "PRESENCE(iei = BSSLAP_IEI_MS_POWER)" };

/* Section 5.23 */
type record BSSLAP_IE_ServingCellId {
	BSSLAP_IEI		iei,
	uint8_t			len,
	octetstring		val	// FIXME: like TS 08.08
} with {
	variant "PRESENCE(iei = BSSLAP_IEI_SERVING_CELL_ID)"
	variant (len) "LENGTHTO(val)"
};

/* Section 5.24 */
type record BSSLAP_IE_EncryptionKey {
	BSSLAP_IEI		iei,
	OCT8			kc
} with { variant "PRESENCE(iei = BSSLAP_IEI_ENCR_KEY)" };

/* Section 5.25 */
type record BSSLAP_IE_CiphModeSet {
	BSSLAP_IEI		iei,
	BIT1			spare,
	BIT3			iei2,
	BIT3			algo_id,
	boolean			sc
} with { variant "PRESENCE(iei = BSSLAP_IEI_CIPH_MODE_SET)" };

/* Section 5.26 */
type record BSSLAP_IE_ChanMode {
	BSSLAP_IEI		iei,
	OCT1			mode
} with { variant "PRESENCE(iei = BSSLAP_IEI_CHAN_MODE)" };

/* Section 5.27 */
type record BSSLAP_IE_MultiRateConfig {
	BSSLAP_IEI		iei,
	uint8_t			len,
	/* TODO: Unify with TS 48.018 */
	uint3_t			mr_speech_ver,
	boolean			nscb,
	boolean			icmi,
	BIT1			spare,
	uint2_t			start_mode,
	octetstring		parameters
} with {
	variant "PRESENCE(iei = BSSLAP_IEI_MR_CONFIG)"
	variant (len) "LENGTHTO(mr_speech_ver,nscb,icmi,spare,start_mode,parameters)"
};

/* Section 5.28 */
type record BSSLAP_IE_PollingRep {
	BSSLAP_IEI		iei,
	BIT2			spare,
	uint6_t			num_rep
} with { variant "PRESENCE(iei = BSSLAP_IEI_MR_CONFIG)" };

/* Section 5.29 */
type record BSSLAP_IE_PacketChanDesc {
	BSSLAP_IEI		iei,
	OCT4			chan_desc
} with { variant "PRESENCE(iei = BSSLAP_IEI_PACKET_CHAN_DESC)" };

/* Section 5.30 */
type record BSSLAP_IE_TLLI {
	BSSLAP_IEI		iei,
	OCT4			tlli
} with { variant "PRESENCE(iei = BSSLAP_IEI_TLLI)" };

/* Section 5.31 */
type record BSSLAP_IE_TFI {
	BSSLAP_IEI		iei,
	BIT3			spare,
	uint5_t			tfi
} with { variant "PRESENCE(iei = BSSLAP_IEI_TFI)" };

/* Section 5.32 */
type record BSSLAP_IE_StartingTime {
	BSSLAP_IEI		iei,
	uint5_t			t1_p,
	uint6_t			t3,
	uint6_t			t2
} with { variant "PRESENCE(iei = BSSLAP_IEI_TBF_START_TIME)" };

/* Section 5.33 */
type record BSSLAP_IE_LongEncryptionKey {
	BSSLAP_IEI		iei,
	OCT16			kc
} with { variant "PRESENCE(iei = BSSLAP_IEI_LONG_ENCR_KEY)" };

/* Section 5.34 */
type record BSSLAP_IE_ConcurMethodF {
	BSSLAP_IEI		iei,
	BSSLAP_ConcurMethodF	flag
} with { variant "PRESENCE(iei = BSSLAP_IEI_CONCUR_POS_PROC_F)" };
type enumerated BSSLAP_ConcurMethodF {
	BSSLAP_SECOND_CONCUR_ALLOWED	('00000000'B),
	BSSLAP_SECOND_CONCUR_DISALLOWED	('11111111'B)
} with { variant "FIELDLENGTH(8)" };



external function enc_BSSLAP_PDU(in BSSLAP_PDU msg) return octetstring
	with { extension "prototype(convert) encode(RAW)" };
external function dec_BSSLAP_PDU(in octetstring stream) return BSSLAP_PDU
	with { extension "prototype(convert) decode(RAW)" };

template (value) BSSLAP_PDU ts_BSSLAP_TA_Req := {
	ta_req := {
		msg_type := BSSLAP_MSGT_TA_REQUEST
	}
}
template (present) BSSLAP_PDU tr_BSSLAP_TA_Req := {
	ta_req := {
		msg_type := BSSLAP_MSGT_TA_REQUEST
	}
}

template (value) BSSLAP_PDU
ts_BSSLAP_TA_Resp(uint16_t cell_id, uint8_t ta)  := {
	ta_resp := {
		msg_type := BSSLAP_MSGT_TA_RESPONSE,
		serving_cell_id := ts_BSSLAP_IE_CellId(cell_id),
		timing_advance := ts_BSSLAP_IE_TA(ta),
		meas_rep := omit,
		enh_meas_rep := omit,
		meas_cell_id_list := omit,
		concur_meth_flag := omit
 	}
}
template (present) BSSLAP_PDU
tr_BSSLAP_TA_Resp(template (present) uint16_t cell_id, template (present) uint8_t ta)  := {
	ta_resp := {
		msg_type := BSSLAP_MSGT_TA_RESPONSE,
		serving_cell_id := tr_BSSLAP_IE_CellId(cell_id),
		timing_advance := tr_BSSLAP_IE_TA(ta),
		meas_rep := *,
		enh_meas_rep := *,
		meas_cell_id_list := *,
		concur_meth_flag := *
 	}
}

template (value) BSSLAP_PDU
ts_BSSLAP_Reject(BSSLAP_Cause cause) := {
	reject := {
		msg_type := BSSLAP_MSGT_REJECT,
		cause := ts_BSSLAP_IE_Cause(cause)
	}
}
template (present) BSSLAP_PDU
tr_BSSLAP_Reject(template (present) BSSLAP_Cause cause) := {
	reject := {
		msg_type := BSSLAP_MSGT_REJECT,
		cause := tr_BSSLAP_IE_Cause(cause)
	}
}


template (value) BSSLAP_PDU
ts_BSSLAP_Abort(BSSLAP_Cause cause) := {
	abort := {
		msg_type := BSSLAP_MSGT_ABORT,
		cause := ts_BSSLAP_IE_Cause(cause)
	}
}
template (present) BSSLAP_PDU
tr_BSSLAP_Abort(template (present) BSSLAP_Cause cause) := {
	abort := {
		msg_type := BSSLAP_MSGT_ABORT,
		cause := tr_BSSLAP_IE_Cause(cause)
	}
}

template (value) BSSLAP_PDU ts_BSSLAP_TA_Layer3(uint8_t ta) := {
	ta_layer3 := {
		msg_type := BSSLAP_MSGT_TA_LAYER3,
		timing_advance := ts_BSSLAP_IE_TA(ta),
		meas_rep := omit,
		enh_meas_rep := omit,
		meas_cell_id_list := omit
	}
}

template (present) BSSLAP_PDU tr_BSSLAP_TA_Layer3(template BSSLAP_IE_TimingAdvance timing_advance := *) := {
	ta_layer3 := {
		msg_type := BSSLAP_MSGT_TA_LAYER3,
		timing_advance := timing_advance,
		meas_rep := *,
		enh_meas_rep := *,
		meas_cell_id_list := *
	}
}

template (value) BSSLAP_IE_ChanDesc ts_BSSLAP_IE_ChanDesc := {
	iei := BSSLAP_IEI_CHAN_DESC,
	chan_desc := '112233'O /* FIXME */
}

template (value) BSSLAP_PDU
ts_BSSLAP_Reset(uint16_t cell_id,
		uint8_t ta,
		BSSLAP_IE_ChanDesc chan_desc,
		BSSLAP_Cause cause) := {
	reset := {
		msg_type := BSSLAP_MSGT_RESET,
		cell_id := ts_BSSLAP_IE_CellId(cell_id),
		timing_advance := ts_BSSLAP_IE_TA(ta),
		chan_desc := chan_desc,
		cause := ts_BSSLAP_IE_Cause(cause),
		meas_rep := omit,
		enh_meas_rep := omit,
		meas_cell_id_list := omit,
		lac := omit,
		freq_list := omit,
		chan_mode := omit,
		mr_config := omit,
		pkt_chan_desc := omit,
		tlli := omit,
		tfi := omit,
		tbf_start_time := omit,
		encr_key := omit,
		ciph_mode_set := omit,
		long_encr_key := omit
	}
}

template (present) BSSLAP_PDU
tr_BSSLAP_Reset(template (present) BSSLAP_Cause cause) := {
	reset := {
		msg_type := BSSLAP_MSGT_RESET,
		cell_id := ?,
		timing_advance := ?,
		chan_desc := ?,
		cause := tr_BSSLAP_IE_Cause(cause),
		meas_rep := *,
		enh_meas_rep := *,
		meas_cell_id_list := *,
		lac := *,
		freq_list := *,
		chan_mode := *,
		mr_config := *,
		pkt_chan_desc := *,
		tlli := *,
		tfi := *,
		tbf_start_time := *,
		encr_key := *,
		ciph_mode_set := *,
		long_encr_key := *
	}
}

template (value) BSSLAP_IE_TimingAdvance ts_BSSLAP_IE_TA(uint8_t ta) := {
	iei := BSSLAP_IEI_TA,
	ta := ta
}
template (present) BSSLAP_IE_TimingAdvance tr_BSSLAP_IE_TA(template (present) uint8_t ta) := {
	iei := BSSLAP_IEI_TA,
	ta := ta
}

template (value) BSSLAP_IE_CellId ts_BSSLAP_IE_CellId(uint16_t cell_id) := {
	iei := BSSLAP_IEI_CELL_ID,
	cell_id := cell_id
}
template (present) BSSLAP_IE_CellId tr_BSSLAP_IE_CellId(template (present) uint16_t cell_id) := {
	iei := BSSLAP_IEI_CELL_ID,
	cell_id := cell_id
}

template (value) BSSLAP_IE_Cause ts_BSSLAP_IE_Cause(BSSLAP_Cause cause) := {
	iei := BSSLAP_IEI_CAUSE,
	cause := cause
}
template (present) BSSLAP_IE_Cause tr_BSSLAP_IE_Cause(template (present) BSSLAP_Cause cause) := {
	iei := BSSLAP_IEI_CAUSE,
	cause := cause
}






} with { encode "RAW" };
