module UECUPS_Types {

import from General_Types all;
import from Osmocom_Types all;

const integer UECUPS_SCTP_PORT := 4268;

type enumerated UECUPS_AddrType {
	IPV4	(1),
	IPV6	(2)
};

type enumerated UECUPS_Result {
	OK			(1),
	ERR_INVALID_DATA	(2),
	ERR_NOT_FOUND		(3)
};

type record UECUPS_SockAddr {
	UECUPS_AddrType	addr_type,
	OCT4_16n	ip,
	uint16_t	Port
};

const charstring UECUPS_GtpExtHdr_PduSessContainer_Type_ul_pdu_sess_info := "ul_pdu_sess_info";
const charstring UECUPS_GtpExtHdr_PduSessContainer_Type_dl_pdu_sess_info := "dl_pdu_sess_info";
type record UECUPS_GtpExtHdr_PduSessContainer {
	charstring pdu_type, /* ("ul_pdu_sess_info"|"dl_pdu_sess_info") */
	uint32_t qfi
};

type record UECUPS_GtpExtHdr {
	boolean 				sequence_number optional,
	boolean 				n_pdu_number optional,
	UECUPS_GtpExtHdr_PduSessContainer	pdu_session_container optional
};

/* Create a new GTP-U tunnel in the user plane */
type record UECUPS_CreateTun {
	/* TEID in transmit + receive direction */
	uint32_t		tx_teid,
	uint32_t		rx_teid,

	/* user address (allocated inside the tunnel) */
	UECUPS_AddrType 	user_addr_type,
	OCT4_16n		user_addr,

	/* GTP endpoint (UDP IP/Port tuples) */
	UECUPS_SockAddr 	local_gtp_ep,
	UECUPS_SockAddr 	remote_gtp_ep,

	/* TUN device */
	charstring		tun_dev_name,
	charstring		tun_netns_name optional,
	UECUPS_GtpExtHdr	gtp_ext_hdr optional
};

type record UECUPS_CreateTunRes {
	UECUPS_Result	result
};

/* Destroy an existing GTP-U tunnel in the user plane */
type record UECUPS_DestroyTun {
	/* local GTP endpoint + TEID are sufficient for unique identification */
	UECUPS_SockAddr local_gtp_ep,
	uint32_t	rx_teid
};

type record UECUPS_DestroyTunRes {
	UECUPS_Result	result
};

/* User requests deaemon to start a program in given network namespace */
type record UECUPS_StartProgram {
	/* the command to be started (with optional environment entries) */
	charstring	command,
	charstring_list	environment optional,
	/* user + group to use when starting command */
	charstring	run_as_user,
	/* network namespace in which to start the command */
	charstring      tun_netns_name optional
};
type record of charstring charstring_list;

/* Daemon informs us that a program has been started */
type record UECUPS_StartProgramRes {
	UECUPS_Result	result,
	integer		pid
};

/* Daemon informs us that a program has terminated */
type record UECUPS_ProgramTermInd {
	integer		pid,
	integer		exit_code
};

type record UeCUPS_ResetAllState {
};

type record UeCUPS_ResetAllStateRes {
	UECUPS_Result	result
};

type union PDU_UECUPS {
	UECUPS_CreateTun	create_tun,
	UECUPS_CreateTunRes	create_tun_res,

	UECUPS_DestroyTun	destroy_tun,
	UECUPS_DestroyTunRes	destroy_tun_res,

	UECUPS_StartProgram	start_program,
	UECUPS_StartProgramRes	start_program_res,
	UECUPS_ProgramTermInd	program_term_ind,

	UeCUPS_ResetAllState	reset_all_state,
	UeCUPS_ResetAllStateRes	reset_all_state_res
};



external function f_enc_PDU_UECUPS(in PDU_UECUPS inp) return octetstring
        with { extension "prototype(convert) encode(JSON)" }
external function f_dec_PDU_UECUPS(in octetstring inp) return PDU_UECUPS
        with { extension "prototype(convert) decode(JSON)" }


private function f_get_addrtype(OCT4_16n addr) return UECUPS_AddrType
{
	if (lengthof(addr) == 4) {
		return IPV4;
	} else {
		return IPV6;
	}
}

private const integer GTP1U_PORT := 2152;

template (value) UECUPS_SockAddr
ts_UECUPS_SockAddr(OCT4_16n ip, uint16_t Port := GTP1U_PORT) := {
	addr_type := f_get_addrtype(ip),
	ip := ip,
	Port := Port
}

template (value) UECUPS_GtpExtHdr_PduSessContainer
ts_UECUPS_GtpExtHdr_PduSessContainer(template (value) charstring pdu_type,
				     template (value) uint32_t qfi)
:= {
	pdu_type := pdu_type,
	qfi := qfi
};

template (value) UECUPS_GtpExtHdr
ts_UECUPS_GtpExtHdr(template (omit) boolean sequence_number := omit,
		    template (omit) boolean n_pdu_number := omit,
		    template (omit) UECUPS_GtpExtHdr_PduSessContainer pdu_session_container := omit)
:= {
	sequence_number := sequence_number,
	n_pdu_number := n_pdu_number,
	pdu_session_container := pdu_session_container
};

template (value) UECUPS_CreateTun
ts_UECUPS_CreateTun(template (value) uint32_t tx_teid,
		    template (value) uint32_t rx_teid,
		    template (value) UECUPS_AddrType user_addr_type,
		    template (value) OCT4_16n user_addr,
		    template (value) UECUPS_SockAddr local_gtp_ep,
		    template (value) UECUPS_SockAddr remote_gtp_ep,
		    template (value) charstring tun_dev_name := "tun",
		    template (omit) charstring tun_netns_name := omit,
		    template (omit) UECUPS_GtpExtHdr gtp_ext_hdr := omit)
:= {
	tx_teid := tx_teid,
	rx_teid := rx_teid,
	user_addr_type := user_addr_type,
	user_addr := user_addr,
	local_gtp_ep := local_gtp_ep,
	remote_gtp_ep := remote_gtp_ep,
	tun_dev_name := tun_dev_name,
	tun_netns_name := tun_netns_name,
	gtp_ext_hdr := gtp_ext_hdr
};

template (value) UECUPS_DestroyTun
ts_UECUPS_DestroyTun(template (value) UECUPS_SockAddr local_gtp_ep,
		     template (value) uint32_t rx_teid)
:= {
	local_gtp_ep := local_gtp_ep,
	rx_teid := rx_teid
};

template (value) UECUPS_StartProgram
ts_UECUPS_StartProgram(template (value) charstring command,
		       template (omit) charstring_list environment := omit,
		       template (value) charstring run_as_user := "root",
		       template (omit) charstring tun_netns_name := omit)
:= {
	command := command,
	environment := environment,
	run_as_user := run_as_user,
	tun_netns_name := tun_netns_name
};

} with { encode "JSON" };
