/* Osmocom HNBLL Interface Types, as per osmo-hnodeb/include/osmocom/hnodeb/hnb_prim.h
 * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 * All rights reserved.
 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
 *
 * 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
 */

module HNBLLIF_Types {

import from General_Types all;
import from Osmocom_Types all;
import from Native_Functions all;

modulepar {
	/* HNBLLIF version supported by the IUT */
	HNBLLIF_Version mp_hnbllif_version := 0;
};

const charstring HNBLL_SOCK_DEFAULT := "/tmp/hnb_prim_sock";
type integer HNBLLIF_Version (0); /* supported versions */

/**********************
 * CTL SAPI
 **********************/


type enumerated HNBLLIF_CTL_MsgType {
	HNBLL_IF_CTL_MSG_HELLO	('0000'O)
} with { variant "FIELDLENGTH(16)" };

type record HNBLLIF_CTL_hello_req {
	HNBLLIF_Sapi	sapi,
	uint16_t	api_version
} with { variant "" };

type record HNBLLIF_CTL_hello_cnf {
	HNBLLIF_Sapi	sapi,
	uint16_t	api_version
} with { variant "" };

type union HNBLLIF_CTL_PrimOpUnion_hello {
	HNBLLIF_CTL_hello_req	req,
	HNBLLIF_CTL_hello_cnf	cnf,
	octetstring		other
} with { variant "" };

type record HNBLLIF_CTL_PrimOp_hello  {
	HNBLLIF_Operation	op,
	HNBLLIF_CTL_PrimOpUnion_hello	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				cnf, 	op = HNBLL_IF_OP_CONFIRM;
				other,	OTHERWISE)"
};

type union HNBLLIF_CTL_PrimUnion {
	HNBLLIF_CTL_PrimOp_hello	hello,
	octetstring		other
} with { variant "" };

type record HNBLLIF_CTL_PrimHdr  {
	HNBLLIF_CTL_MsgType	prim,
	HNBLLIF_CTL_PrimUnion	u
} with { variant (u) "CROSSTAG( hello, 	prim = HNBLL_IF_CTL_MSG_HELLO;
				other,	OTHERWISE)"
};

/**********************
 * IUH SAPI
 **********************/
type enumerated HNBLLIF_IUH_MsgType {
	HNBLL_IF_IUH_MSG_CONFIGURE	('0000'O),
	HNBLL_IF_IUH_MSG_CONN_ESTABLISH	('0001'O),
	HNBLL_IF_IUH_MSG_CONN_RELEASE	('0002'O),
	HNBLL_IF_IUH_MSG_CONN_DATA	('0003'O),
	HNBLL_IF_IUH_MSG_UNITDATA	('0004'O)
} with { variant "FIELDLENGTH(16)" };

/* CONFIGURE */
type record HNBLLIF_IUH_configure_ind {
	uint16_t mcc,
	uint16_t mnc,
	uint16_t cell_identity,
	uint16_t lac,
	uint8_t rac,
	uint8_t reserved,
	uint16_t sac,
	uint16_t rnc_id
} with { variant "" };

type union HNBLLIF_IUH_PrimOpUnion_configure {
	HNBLLIF_IUH_configure_ind ind,
	octetstring		other
} with { variant "" };

type record HNBLLIF_IUH_PrimOp_configure  {
	HNBLLIF_Operation	op,
	HNBLLIF_IUH_PrimOpUnion_configure	u
} with { variant (u) "CROSSTAG( ind, 	op = HNBLL_IF_OP_INDICATION;
				other,	OTHERWISE)"
};

/* CONN_ESTABLISH */
type record HNBLLIF_IUH_conn_establish_req {
	uint32_t context_id,
	uint8_t domain,
	uint8_t est_cause,
	uint16_t reserved, //uint16_t nas_node_selector_bitlen;
	//uint8_t nas_node_selector[128]; /* TODO: check whether we can decrease this buffer size */
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type record HNBLLIF_IUH_conn_establish_cnf {
	uint32_t context_id,
	uint8_t domain,
	uint8_t est_cause
} with { variant "" };

type union HNBLLIF_IUH_PrimOpUnion_conn_establish {
	HNBLLIF_IUH_conn_establish_req req,
	HNBLLIF_IUH_conn_establish_cnf cnf,
	octetstring		other
} with { variant "" };
type record HNBLLIF_IUH_PrimOp_conn_establish  {
	HNBLLIF_Operation	op,
	HNBLLIF_IUH_PrimOpUnion_conn_establish	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				cnf, 	op = HNBLL_IF_OP_CONFIRM;
				other,	OTHERWISE)"
};

/* CONN_RELEASE */
type record HNBLLIF_IUH_conn_release_req {
	uint32_t context_id,
	uint8_t domain,
	uint8_t spare1,
	uint8_t cause_type,
	uint8_t cause,
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };


type union HNBLLIF_IUH_PrimOpUnion_conn_release {
	HNBLLIF_IUH_conn_release_req req,
	octetstring		other
} with { variant "" };
type record HNBLLIF_IUH_PrimOp_conn_release  {
	HNBLLIF_Operation	op,
	HNBLLIF_IUH_PrimOpUnion_conn_release	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				other,	OTHERWISE)"
};

/* CONN_DATA */
type record HNBLLIF_IUH_conn_data_ind {
	uint32_t context_id,
	uint8_t domain,
	uint8_t spare1,
	uint16_t spare2,
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type record HNBLLIF_IUH_conn_data_req {
	uint32_t context_id,
	uint8_t domain,
	uint8_t spare1,
	uint16_t spare2,
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type union HNBLLIF_IUH_PrimOpUnion_conn_data {
	HNBLLIF_IUH_conn_data_req req,
	HNBLLIF_IUH_conn_data_ind ind,
	octetstring		other
} with { variant "" };
type record HNBLLIF_IUH_PrimOp_conn_data  {
	HNBLLIF_Operation	op,
	HNBLLIF_IUH_PrimOpUnion_conn_data	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				ind, 	op = HNBLL_IF_OP_INDICATION;
				other,	OTHERWISE)"
};

/* UNITDATA */
type record HNBLLIF_IUH_unitdata_ind {
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type record HNBLLIF_IUH_unitdata_req {
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type union HNBLLIF_IUH_PrimOpUnion_unitdata {
	HNBLLIF_IUH_unitdata_req req,
	HNBLLIF_IUH_unitdata_ind ind,
	octetstring		other
} with { variant "" };
type record HNBLLIF_IUH_PrimOp_unitdata  {
	HNBLLIF_Operation	op,
	HNBLLIF_IUH_PrimOpUnion_unitdata	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				ind, 	op = HNBLL_IF_OP_INDICATION;
				other,	OTHERWISE)"
};

type union HNBLLIF_IUH_PrimUnion {
	HNBLLIF_IUH_PrimOp_configure		configure,
	HNBLLIF_IUH_PrimOp_conn_establish	conn_establish,
	HNBLLIF_IUH_PrimOp_conn_release		conn_release,
	HNBLLIF_IUH_PrimOp_conn_data		conn_data,
	HNBLLIF_IUH_PrimOp_unitdata		unitdata,
	octetstring		other
} with { variant "" };

type record HNBLLIF_IUH_PrimHdr  {
	HNBLLIF_IUH_MsgType	prim,
	HNBLLIF_IUH_PrimUnion	u
} with { variant (u) "CROSSTAG( configure, 	prim = HNBLL_IF_IUH_MSG_CONFIGURE;
				conn_establish,	prim = HNBLL_IF_IUH_MSG_CONN_ESTABLISH;
				conn_release,	prim = HNBLL_IF_IUH_MSG_CONN_RELEASE;
				conn_data,	prim = HNBLL_IF_IUH_MSG_CONN_DATA;
				unitdata,	prim = HNBLL_IF_IUH_MSG_UNITDATA;
				other,	OTHERWISE)"
};

/**********************
 * AUDIO SAPI
 **********************/
type enumerated HNBLLIF_AUDIO_MsgType {
	HNBLL_IF_AUDIO_MSG_CONN_ESTABLISH	('0000'O),
	HNBLL_IF_AUDIO_MSG_CONN_RELEASE		('0001'O),
	HNBLL_IF_AUDIO_MSG_CONN_DATA		('0002'O)
} with { variant "FIELDLENGTH(16)" };

const integer HNBLLIF_MAX_RFCIS := 64;
const integer HNBLLIF_MAX_SUBFLOWS := 7;
type record length(HNBLLIF_MAX_RFCIS) of uint8_t HNBLLIF_AUDIO_IPTIs;
type record length(HNBLLIF_MAX_SUBFLOWS) of uint16_t HNBLLIF_AUDIO_RFCI_SubflowSizes;
type record length(HNBLLIF_MAX_RFCIS) of HNBLLIF_AUDIO_RFCI_SubflowSizes HNBLLIF_AUDIO_SubflowSizes;
type record length(HNBLLIF_MAX_RFCIS) of uint8_t HNBLLIF_AUDIO_RFCIs;

/* CONN_ESTABLISH */
type record HNBLLIF_AUDIO_conn_establish_req {
	uint32_t context_id,
	uint16_t remote_rtp_port,
	uint8_t reserved,
	HNBLLIF_AddrType remote_rtp_address_type,
	HNBLLIF_Addr remote_addr,
	uint8_t transparent, /* 1=transparent; 0=SMpSDU */
	uint8_t data_pdu_type,
	uint16_t supported_versions_mask, /* host byte order */
	uint8_t num_rfci,
	uint8_t num_subflows,
	HNBLLIF_AUDIO_SubflowSizes subflow_sizes,
	uint8_t IPTIs_present, /* 1=present; 0=not present */
	HNBLLIF_AUDIO_IPTIs IPTIs, /* values range 0-15, 4 bits */
	HNBLLIF_AUDIO_RFCIs rfci optional /* only available in audio SAPI ver >= 1 */
} with { variant ""  };

type record HNBLLIF_AUDIO_conn_establish_cnf {
	uint32_t context_id,
	uint32_t audio_conn_id,
	uint16_t local_rtp_port,
	uint8_t error_code,
	HNBLLIF_AddrType local_rtp_address_type,
	HNBLLIF_Addr local_addr
} with { variant "" };

type union HNBLLIF_AUDIO_PrimOpUnion_conn_establish {
	HNBLLIF_AUDIO_conn_establish_req req,
	HNBLLIF_AUDIO_conn_establish_cnf cnf,
	octetstring		other
} with { variant "" };
type record HNBLLIF_AUDIO_PrimOp_conn_establish  {
	HNBLLIF_Operation	op,
	HNBLLIF_AUDIO_PrimOpUnion_conn_establish	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				cnf, 	op = HNBLL_IF_OP_CONFIRM;
				other,	OTHERWISE)"
};

/* CONN_RELEASE */
type record HNBLLIF_AUDIO_conn_release_req {
	uint32_t audio_conn_id
} with { variant "" };


type union HNBLLIF_AUDIO_PrimOpUnion_conn_release {
	HNBLLIF_AUDIO_conn_release_req req,
	octetstring		other
} with { variant "" };
type record HNBLLIF_AUDIO_PrimOp_conn_release  {
	HNBLLIF_Operation	op,
	HNBLLIF_AUDIO_PrimOpUnion_conn_release	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				other,	OTHERWISE)"
};

/* CONN_DATA */
type record HNBLLIF_AUDIO_conn_data_ind {
	uint32_t audio_conn_id,
	uint8_t frame_nr,
	uint8_t fqc, /* enumerated IuUP_FQC */
	uint8_t rfci,
	uint8_t spare,
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type record HNBLLIF_AUDIO_conn_data_req {
	uint32_t audio_conn_id,
	uint8_t frame_nr,
	uint8_t fqc,  /* enumerated IuUP_FQC */
	uint8_t rfci,
	uint8_t spare,
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type union HNBLLIF_AUDIO_PrimOpUnion_conn_data {
	HNBLLIF_AUDIO_conn_data_req req,
	HNBLLIF_AUDIO_conn_data_ind ind,
	octetstring		other
} with { variant "" };
type record HNBLLIF_AUDIO_PrimOp_conn_data  {
	HNBLLIF_Operation	op,
	HNBLLIF_AUDIO_PrimOpUnion_conn_data	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				ind, 	op = HNBLL_IF_OP_INDICATION;
				other,	OTHERWISE)"
};

type union HNBLLIF_AUDIO_PrimUnion {
	HNBLLIF_AUDIO_PrimOp_conn_establish	conn_establish,
	HNBLLIF_AUDIO_PrimOp_conn_release	conn_release,
	HNBLLIF_AUDIO_PrimOp_conn_data		conn_data,
	octetstring		other
} with { variant "" };

type record HNBLLIF_AUDIO_PrimHdr  {
	HNBLLIF_AUDIO_MsgType	prim,
	HNBLLIF_AUDIO_PrimUnion	u
} with { variant (u) "CROSSTAG( conn_establish,	prim = HNBLL_IF_AUDIO_MSG_CONN_ESTABLISH;
				conn_release,	prim = HNBLL_IF_AUDIO_MSG_CONN_RELEASE;
				conn_data,	prim = HNBLL_IF_AUDIO_MSG_CONN_DATA;
				other,	OTHERWISE)"
};

/**********************
 * GTP SAPI
 **********************/
type enumerated HNBLLIF_GTP_MsgType {
	HNBLL_IF_GTP_MSG_CONN_ESTABLISH	('0000'O),
	HNBLL_IF_GTP_MSG_CONN_RELEASE		('0001'O),
	HNBLL_IF_GTP_MSG_CONN_DATA		('0002'O)
} with { variant "FIELDLENGTH(16)" };

/* CONN_ESTABLISH */
type record HNBLLIF_GTP_conn_establish_req {
	uint32_t context_id,
	uint32_t remote_tei,
	uint8_t reserved,
	HNBLLIF_AddrType remote_gtpu_address_type,
	HNBLLIF_Addr remote_gtpu_addr
} with { variant "" };

type record HNBLLIF_GTP_conn_establish_cnf {
	uint32_t context_id,
	uint32_t gtp_conn_id,
	uint32_t local_tei,
	uint8_t error_code,
	HNBLLIF_AddrType local_gtpu_address_type,
	HNBLLIF_Addr local_gtpu_addr
} with { variant "" };

type union HNBLLIF_GTP_PrimOpUnion_conn_establish {
	HNBLLIF_GTP_conn_establish_req req,
	HNBLLIF_GTP_conn_establish_cnf cnf,
	octetstring		other
} with { variant "" };
type record HNBLLIF_GTP_PrimOp_conn_establish  {
	HNBLLIF_Operation	op,
	HNBLLIF_GTP_PrimOpUnion_conn_establish	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				cnf, 	op = HNBLL_IF_OP_CONFIRM;
				other,	OTHERWISE)"
};

/* CONN_RELEASE */
type record HNBLLIF_GTP_conn_release_req {
	uint32_t gtp_conn_id
} with { variant "" };

type union HNBLLIF_GTP_PrimOpUnion_conn_release {
	HNBLLIF_GTP_conn_release_req req,
	octetstring		other
} with { variant "" };
type record HNBLLIF_GTP_PrimOp_conn_release  {
	HNBLLIF_Operation	op,
	HNBLLIF_GTP_PrimOpUnion_conn_release	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				other,	OTHERWISE)"
};

/* CONN_DATA */
type record HNBLLIF_GTP_conn_data_req {
	uint32_t gtp_conn_id,
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type record HNBLLIF_GTP_conn_data_ind {
	uint32_t gtp_conn_id,
	uint32_t data_len,
	octetstring data /* RANAP message */
} with { variant (data_len) "LENGTHTO (data)" };

type union HNBLLIF_GTP_PrimOpUnion_conn_data {
	HNBLLIF_GTP_conn_data_req req,
	HNBLLIF_GTP_conn_data_ind ind,
	octetstring		other
} with { variant "" };
type record HNBLLIF_GTP_PrimOp_conn_data  {
	HNBLLIF_Operation	op,
	HNBLLIF_GTP_PrimOpUnion_conn_data	u
} with { variant (u) "CROSSTAG( req, 	op = HNBLL_IF_OP_REQUEST;
				ind, 	op = HNBLL_IF_OP_INDICATION;
				other,	OTHERWISE)"
};

type union HNBLLIF_GTP_PrimUnion {
	HNBLLIF_GTP_PrimOp_conn_establish	conn_establish,
	HNBLLIF_GTP_PrimOp_conn_release		conn_release,
	HNBLLIF_GTP_PrimOp_conn_data		conn_data,
	octetstring		other
} with { variant "" };

type record HNBLLIF_GTP_PrimHdr  {
	HNBLLIF_GTP_MsgType	prim,
	HNBLLIF_GTP_PrimUnion	u
} with { variant (u) "CROSSTAG( conn_establish,	prim = HNBLL_IF_GTP_MSG_CONN_ESTABLISH;
				conn_release,	prim = HNBLL_IF_GTP_MSG_CONN_RELEASE;
				conn_data,	prim = HNBLL_IF_GTP_MSG_CONN_DATA;
				other,	OTHERWISE)"
};


/**********************
* General
**********************/

type enumerated HNBLLIF_AddrType {
	HNBLL_IF_ADDR_TYPE_UNSPEC	('00'O),
	HNBLL_IF_ADDR_TYPE_IPV4		('01'O),
	HNBLL_IF_ADDR_TYPE_IPV6		('02'O)
} with { variant "FIELDLENGTH(8)" };
type octetstring HNBLLIF_Addr length(16);

type enumerated HNBLLIF_Sapi {
	HNBLL_IF_SAPI_CTL		(-1),
	HNBLL_IF_SAPI_IUH		('00000001'O),
	HNBLL_IF_SAPI_GTP		('00000002'O),
	HNBLL_IF_SAPI_AUDIO		('00000003'O)
} with { variant "FIELDLENGTH(32)"
	 variant "COMP(2scompl)"
};

type enumerated HNBLLIF_Operation {
	HNBLL_IF_OP_REQUEST	('0000'O),
	HNBLL_IF_OP_RESPONSE	('0001'O),
	HNBLL_IF_OP_INDICATION	('0002'O),
	HNBLL_IF_OP_CONFIRM	('0003'O)
} with { variant "FIELDLENGTH(16)" };

type union HNBLLIF_SapiUnion {
	HNBLLIF_CTL_PrimHdr		ctl,
	HNBLLIF_IUH_PrimHdr		iuh,
	HNBLLIF_GTP_PrimHdr		gtp,
	HNBLLIF_AUDIO_PrimHdr		audio,
	octetstring			other
} with { variant "" };

type record HNBLLIF_Message {
	HNBLLIF_Sapi sapi,
	HNBLLIF_SapiUnion u
} with { variant (u) "CROSSTAG( ctl, 		sapi = HNBLL_IF_SAPI_CTL;
				iuh, 		sapi = HNBLL_IF_SAPI_IUH;
				gtp, 		sapi = HNBLL_IF_SAPI_GTP;
				audio, 		sapi = HNBLL_IF_SAPI_AUDIO;
				other,	OTHERWISE)"
};

external function enc_HNBLLIF_Message(in HNBLLIF_Message pdu) return octetstring
	with { extension "prototype(convert) encode(RAW)" };
external function dec_HNBLLIF_Message(in octetstring stream) return HNBLLIF_Message
	with { extension "prototype(convert) decode(RAW)" };

function f_HNBLLIF_AF2addr_type(AddressFamily address_family)
return HNBLLIF_AddrType {
	if (address_family == AF_INET) {
		return HNBLL_IF_ADDR_TYPE_IPV4;
	} else if (address_family == AF_INET6) {
		return HNBLL_IF_ADDR_TYPE_IPV6;
	} else {
		return HNBLL_IF_ADDR_TYPE_UNSPEC;
	}
}

function f_HNBLLIF_Addr(HNBLLIF_AddrType addr_type, charstring addr_str)
return HNBLLIF_Addr {
	var HNBLLIF_Addr addr;

	if (addr_type == HNBLL_IF_ADDR_TYPE_IPV4)  {
		addr := f_inet_addr(addr_str);
	} else {
		addr := f_inet6_addr(addr_str);
	}

	return addr;
}


} with { encode "RAW" variant "BYTEORDER(first)" };
