module M3UA_Templates {

/* M3UA Templates, building on top of M3UA_Types from Ericsson.
 *
 * (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 M3UA_Types all;
import from General_Types all;
import from Osmocom_Types all;

const OCT1 c_M3UA_VERSION := '01'O;

const OCT1 c_M3UA_NI_NATIONAL := '02'O;
const OCT1 c_M3UA_NI_INTERNATIONAL := '00'O;

const OCT2 c_M3UA_ST_T_STATE_CHG := '0001'O;
const OCT2 c_M3UA_ST_I_RESERVED := '0001'O;
const OCT2 c_M3UA_ST_I_AS_INACTIVE := '0002'O;
const OCT2 c_M3UA_ST_I_AS_ACTIVE := '0003'O;
const OCT2 c_M3UA_ST_I_AS_PENDING := '0004'O;

const OCT2 c_M3UA_ST_T_OTHER := '0002'O;
const OCT2 c_M3UA_ST_I_INSUFF_RESRC := '0001'O
const OCT2 c_M3UA_ST_I_ALTERNATE_ASP := '0002'O
const OCT2 c_M3UA_ST_I_ASP_FAILUREP := '0003'O

private function f_aspid_or_omit(template (omit) OCT4 aspid)
return template (omit) M3UA_ASP_Identifier {
	var template (omit) M3UA_ASP_Identifier id;
	if (istemplatekind(aspid, "omit")) {
		return omit;
	} else {
		id.tag := '0011'O;
		id.lengthInd := 8;
		id.aSPIdentifier := aspid;
		return id;
	}
}

function tr_M3UA_asp_id(template OCT4 aspid)
return template M3UA_ASP_Identifier {
	var template M3UA_ASP_Identifier id := {
		tag := '0011'O,
		lengthInd := 8,
		aSPIdentifier := aspid
	};
	if (istemplatekind(aspid, "omit")) {
		return omit;
	} else if (istemplatekind(aspid, "*")) {
		return *;
	} else {
		return id;
	}
}


/***********************************************************************
 * ASPSM Class
 ***********************************************************************/

template (value) PDU_M3UA ts_M3UA_ASPUP(template (omit) OCT4 aspid := omit,
					template (omit) octetstring infostr := omit) := {
	m3UA_ASPUP := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0301'O,
		messageLength := 0, // overwritten
		messageParameters := {
			aSP_Identifier := f_aspid_or_omit(aspid),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPUP(template OCT4 aspid := *,
					  template octetstring infostr := omit) := {
	m3UA_ASPUP := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0301'O,
		messageLength := ?, // overwritten
		messageParameters := {
			aSP_Identifier := tr_M3UA_asp_id(aspid),
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_ASPUP_ACK := {
	m3UA_ASPUP_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0304'O,
		messageLength := 0, // overwritten
		messageParameters := {
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPUP_ACK := {
	m3UA_ASPUP_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0304'O,
		messageLength := ?,
		messageParameters := {
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_ASPDN := {
	m3UA_ASPDN := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0302'O,
		messageLength := 0, // overwritten
		messageParameters := {
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPDN := {
	m3UA_ASPDN := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0302'O,
		messageLength := ?,
		messageParameters := {
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_ASPDN_ACK := {
	m3UA_ASPUP_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0305'O,
		messageLength := 0, // overwritten
		messageParameters := {
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPDN_ACK := {
	m3UA_ASPUP_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0305'O,
		messageLength := ?,
		messageParameters := {
			info_String := *
		}
	}
}

template (value) M3UA_Heartbeat_Data ts_M3UA_hb_data(template (value) octetstring hb_data) := {
	tag := '0009'O,
	lengthInd := 0, // overwritten
	heartbeat_Data := hb_data
}

template (present) M3UA_Heartbeat_Data tr_M3UA_hb_data(template (present) octetstring hb_data) := {
	tag := '0009'O,
	lengthInd := ?,
	heartbeat_Data := hb_data
}

template (value) PDU_M3UA ts_M3UA_BEAT(template (omit) M3UA_Heartbeat_Data hbd := omit) := {
	m3UA_BEAT := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0303'O,
		messageLength := 0, // overwritten
		messageParameters := {
			heartbeat_Data := hbd
		}
	}
}
template (present) PDU_M3UA tr_M3UA_BEAT(template M3UA_Heartbeat_Data hbd := *) := {
	m3UA_BEAT := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0303'O,
		messageLength := ?,
		messageParameters := {
			heartbeat_Data := hbd
		}
	}
}

template (value) PDU_M3UA ts_M3UA_BEAT_ACK(template (omit) M3UA_Heartbeat_Data hb_data)  := {
	m3UA_BEAT_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0306'O,
		messageLength := 0, // overwritten
		messageParameters := {
			heartbeat_Data := hb_data
		}
	}
}
template (present) PDU_M3UA tr_M3UA_BEAT_ACK(template M3UA_Heartbeat_Data hb_data := *) := {
	m3UA_BEAT_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0306'O,
		messageLength := ?,
		messageParameters := {
			heartbeat_Data := hb_data
		}
	}
}




/***********************************************************************
 * ASPTM Class
 ***********************************************************************/


const M3UA_Traffic_Mode_Type c_M3UA_TMT_override := {
	tag := '000B'O,
	lengthInd := 8,
	trafficModeType := int2oct(1, 4)
}

const M3UA_Traffic_Mode_Type c_M3UA_TMT_loadshare := {
	tag := '000B'O,
	lengthInd := 8,
	trafficModeType := int2oct(2, 4)
}

const M3UA_Traffic_Mode_Type c_M3UA_TMT_broadcast := {
	tag := '000B'O,
	lengthInd := 8,
	trafficModeType := int2oct(3, 4)
}

function ts_M3UA_routing_ctx(template (omit) octetstring rctx)
return template (omit) M3UA_Routing_Context {
	var template (omit) M3UA_Routing_Context id;
	if (istemplatekind(rctx, "omit")) {
		return omit;
	} else {
		id.tag := '0006'O;
		id.lengthInd := 0; // overwritten
		id.routingContext := rctx;
		return id;
	}
}

function tr_M3UA_routing_ctx(template octetstring rctx)
return template M3UA_Routing_Context {
	var template M3UA_Routing_Context id;
	if (istemplatekind(rctx, "omit")) {
		return omit;
	} else if (istemplatekind(rctx, "*")) {
		return *;
	} else {
		id.tag := '0006'O;
		id.lengthInd := ?;
		id.routingContext := rctx;
		return id;
	}
}

template (value) PDU_M3UA ts_M3UA_ASPAC(template (omit) M3UA_Traffic_Mode_Type tmt,
					template (omit) OCT4 rctx) := {
	m3UA_ASPAC := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0401'O,
		messageLength := 0, // overwritten
		messageParameters := {
			traffic_Mode_Type := tmt,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPAC(template M3UA_Traffic_Mode_Type tmt,
					  template OCT4 rctx) := {
	m3UA_ASPAC := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0401'O,
		messageLength := ?,
		messageParameters := {
			traffic_Mode_Type := tmt,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_ASPAC_ACK(template (omit) M3UA_Traffic_Mode_Type tmt,
					template (omit) OCT4 rctx) := {
	m3UA_ASPAC_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0403'O,
		messageLength := 0, // overwritten
		messageParameters := {
			traffic_Mode_Type := tmt,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPAC_ACK(template M3UA_Traffic_Mode_Type tmt,
					      template OCT4 rctx) := {
	m3UA_ASPAC_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0403'O,
		messageLength := ?,
		messageParameters := {
			traffic_Mode_Type := tmt,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_ASPIA(template (omit) OCT4 rctx) := {
	m3UA_ASPIA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0402'O,
		messageLength := 0, // overwritten
		messageParameters := {
			routing_Context := ts_M3UA_routing_ctx(rctx),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPIA(template OCT4 rctx) := {
	m3UA_ASPIA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0402'O,
		messageLength := ?,
		messageParameters := {
			routing_Context := tr_M3UA_routing_ctx(rctx),
			info_String := *
		}
	}
}


template (value) PDU_M3UA ts_M3UA_ASPIA_ACK(template (omit) OCT4 rctx) := {
	m3UA_ASPIA_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0404'O,
		messageLength := 0, // overwritten
		messageParameters := {
			routing_Context := ts_M3UA_routing_ctx(rctx),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ASPIA_ACK(template OCT4 rctx) := {
	m3UA_ASPIA_Ack := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0404'O,
		messageLength := ?,
		messageParameters := {
			routing_Context := tr_M3UA_routing_ctx(rctx),
			info_String := *
		}
	}
}

/***********************************************************************
 * SSNM Class
 ***********************************************************************/

template (value) M3UA_Point_Code ts_M3UA_PC(uint24_t pc, uint8_t mask := 0) := {
	mask := int2oct(mask, 1),
	affected_Point_Code := int2oct(pc, 3)
}

template (value) M3UA_Affected_Point_Codes ts_M3UA_AffPc(template (value) M3UA_Point_Codes pcs) := {
	tag := '0012'O,
	lengthInd := 0,
	pointCodes := pcs
}
template (present) M3UA_Affected_Point_Codes tr_M3UA_AffPc(template (present) M3UA_Point_Codes pcs) := {
	tag := '0012'O,
	lengthInd := ?,
	pointCodes := pcs
}

template (value) M3UA_User_Cause ts_M3UA_UserCause(template (value) OCT2 cause,
						   template (value) OCT2 user) := {
	tag := '0204'O,
	lengthInd := 0,
	cause := cause,
	user := user
}
template (present) M3UA_User_Cause tr_M3UA_UserCause(template (present) OCT2 cause,
						     template (present) OCT2 user) := {
	tag := '0204'O,
	lengthInd := ?,
	cause := cause,
	user := user
}

template (value) PDU_M3UA ts_M3UA_DUNA(template (value) M3UA_Point_Codes affected_pcs,
				       template (omit) OCT4 rctx := omit) := {
	m3UA_DUNA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0201'O,
		messageLength := 0,
		messageParameters := {
			network_Appearance := omit,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			affected_Point_Codes := ts_M3UA_AffPc(affected_pcs),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_DUNA(template (present) M3UA_Point_Codes affected_pcs := ?,
					 template OCT4 rctx := *):= {
	m3UA_DUNA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0201'O,
		messageLength := ?,
		messageParameters := {
			network_Appearance := *,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			affected_Point_Codes := tr_M3UA_AffPc(affected_pcs),
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_DAVA(template (value) M3UA_Point_Codes affected_pcs,
				       template (omit) OCT4 rctx := omit) := {
	m3UA_DAVA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0202'O,
		messageLength := 0,
		messageParameters := {
			network_Appearance := omit,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			affected_Point_Codes := ts_M3UA_AffPc(affected_pcs),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_DAVA(template (present) M3UA_Point_Codes affected_pcs := ?,
					 template OCT4 rctx := *):= {
	m3UA_DAVA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0202'O,
		messageLength := ?,
		messageParameters := {
			network_Appearance := *,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			affected_Point_Codes := tr_M3UA_AffPc(affected_pcs),
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_DAUD(template (value) M3UA_Point_Codes affected_pcs,
				       template (omit) OCT4 rctx := omit) := {
	m3UA_DAUD := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0203'O,
		messageLength := 0,
		messageParameters := {
			network_Appearance := omit,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			affected_Point_Codes := ts_M3UA_AffPc(affected_pcs),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_DAUD(template (present) M3UA_Point_Codes affected_pcs := ?,
					 template OCT4 rctx := *):= {
	m3UA_DAUD := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0203'O,
		messageLength := ?,
		messageParameters := {
			network_Appearance := *,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			affected_Point_Codes := tr_M3UA_AffPc(affected_pcs),
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_SCON(template (value) M3UA_Point_Codes affected_pcs,
				       template (omit) OCT4 rctx := omit) := {
	m3UA_SCON := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0204'O,
		messageLength := 0,
		messageParameters := {
			network_Appearance := omit,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			affected_Point_Codes := ts_M3UA_AffPc(affected_pcs),
			concerned_Destination := omit,
			congestion_Indicators := omit,
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_SCON(template (present) M3UA_Point_Codes affected_pcs := ?,
					 template OCT4 rctx := *):= {
	m3UA_SCON := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0204'O,
		messageLength := ?,
		messageParameters := {
			network_Appearance := *,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			affected_Point_Codes := tr_M3UA_AffPc(affected_pcs),
			concerned_Destination := *,
			congestion_Indicators := *,
			info_String := *
		}
	}
}

template (value) PDU_M3UA ts_M3UA_DUPU(template (value) M3UA_Point_Codes affected_pcs,
					template (value) OCT2 cause,
					template (value) OCT2 user,
					template (omit) OCT4 rctx := omit) := {
	m3UA_DUPU := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0205'O,
		messageLength := 0,
		messageParameters := {
			network_Appearance := omit,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			affected_Point_Codes := ts_M3UA_AffPc(affected_pcs),
			user_Cause := ts_M3UA_UserCause(cause, user),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_DUPU(template (present) M3UA_Point_Codes affected_pcs := ?,
					 template (present) OCT2 cause := ?,
					 template (present) OCT2 user := ?,
					 template OCT4 rctx := *):= {
	m3UA_DUPU := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0205'O,
		messageLength := ?,
		messageParameters := {
			network_Appearance := *,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			affected_Point_Codes := tr_M3UA_AffPc(affected_pcs),
			user_Cause := tr_M3UA_UserCause(cause, user),
			info_String := *
		}
	}
}

template (present) PDU_M3UA tr_M3UA_DRST := {
	m3UA_DRST := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0206'O,
		messageLength := ?,
		messageParameters := ?
	}
}

template (present) PDU_M3UA tr_M3UA_SSNM := (tr_M3UA_DUNA, tr_M3UA_DAVA, tr_M3UA_DAUD,
					     tr_M3UA_SCON, tr_M3UA_DUPU, tr_M3UA_DRST);

/***********************************************************************
 * MGMT Class
 ***********************************************************************/

template (value) M3UA_Error_Code ts_M3UA_err_code(template (value) OCT4 val) := {
	tag := '000C'O,
	lengthInd := 8,
	errorCode := val
}
template (present) M3UA_Error_Code tr_M3UA_err_code(template (present) OCT4 val) := {
	tag := '000C'O,
	lengthInd := 8,
	errorCode := val
}

template (value) M3UA_Status ts_M3UA_status(template (value) OCT2 status_type,
					    template (value) OCT2 status_info) := {
	tag := '000D'O,
	lengthInd := 8,
	statusType := status_type,
	statusInfo := status_info
}

template (present) M3UA_Status tr_M3UA_status(template (present) OCT2 status_type,
					      template (present) OCT2 status_info) := {
	tag := '000D'O,
	lengthInd := 8,
	statusType := status_type,
	statusInfo := status_info
}


template (value) PDU_M3UA ts_M3UA_ERR(template (value) OCT4 err_code,
				      template (omit) OCT4 rctx) := {
	m3UA_ERR := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0000'O,
		messageLength := 0, // overwritten
		messageParameters := {
			error_Code := ts_M3UA_err_code(err_code),
			routing_Context := ts_M3UA_routing_ctx(rctx),
			affected_Point_Codes := omit,
			network_Appearance := omit,
			diagnostic_information := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_ERR(template (present) OCT4 err_code,
				      template OCT4 rctx) := {
	m3UA_ERR := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0000'O,
		messageLength := ?,
		messageParameters := {
			error_Code := tr_M3UA_err_code(err_code),
			routing_Context := tr_M3UA_routing_ctx(rctx),
			affected_Point_Codes := *,
			network_Appearance := *,
			diagnostic_information := *
		}
	}
}


template (value) PDU_M3UA ts_M3UA_NOTIFY(template (value) OCT2 status_type,
					 template (value) OCT2 status_info,
					 template (omit) OCT4 rctx,
					 template (omit) OCT4 aspid := omit,
					 template (omit) octetstring infostr := omit) := {
	m3UA_NOTIFY := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0001'O,
		messageLength := 0, // overwritten
		messageParameters := {
			status := ts_M3UA_status(status_type, status_info),
			aSP_Identifier := f_aspid_or_omit(aspid),
			routing_Context := ts_M3UA_routing_ctx(rctx),
			info_String := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_NOTIFY(template (present) OCT2 status_type,
					   template (present) OCT2 status_info,
					   template OCT4 rctx,
					   template OCT4 aspid := *,
					   template octetstring infostr := *) := {
	m3UA_NOTIFY := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0001'O,
		messageLength := ?,
		messageParameters := {
			status := tr_M3UA_status(status_type, status_info),
			aSP_Identifier := *,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			info_String := *
		}
	}
}

/***********************************************************************
 * Message Transfer Class
 ***********************************************************************/

template (value) M3UA_Protocol_Data ts_M3UA_protocol_data(template (value) OCT4 opc,
							  template (value) OCT4 dpc,
							  template (value) OCT1 si,
							  template (value) OCT1 ni,
							  template (value) OCT1 mp,
							  template (value) OCT1 sls,
							  template (value) octetstring data) := {
	tag := '0210'O,
	lengthInd := 0, // overwritten
	oPC := opc,
	dPC := dpc,
	sI := si,
	nI := ni,
	mP := mp,
	sLS := sls,
	userProtocolData := data
}
template (present) M3UA_Protocol_Data tr_M3UA_protocol_data(template (present) OCT4 opc,
							  template (present) OCT4 dpc,
							  template (present) OCT1 si,
							  template (present) OCT1 ni,
							  template (present) OCT1 mp,
							  template (present) OCT1 sls,
							  template (present) octetstring data) := {
	tag := '0210'O,
	lengthInd := ?,
	oPC := opc,
	dPC := dpc,
	sI := si,
	nI := ni,
	mP := mp,
	sLS := sls,
	userProtocolData := data
}


template (value) PDU_M3UA ts_M3UA_DATA(template (omit) OCT4 rctx,
				       template (value) M3UA_Protocol_Data data) := {
	m3UA_DATA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0101'O,
		messageLength := 0, // overwritten
		messageParameters :={
			network_Appearance := omit,
			routing_Context := ts_M3UA_routing_ctx(rctx),
			protocol_Data := data,
			correlation_ID := omit
		}
	}
}
template (present) PDU_M3UA tr_M3UA_DATA(template OCT4 rctx,
				       template (present) M3UA_Protocol_Data data) := {
	m3UA_DATA := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0101'O,
		messageLength := ?, // overwritten
		messageParameters := {
			network_Appearance := *,
			routing_Context := tr_M3UA_routing_ctx(rctx),
			protocol_Data := data,
			correlation_ID := *
		}
	}
}

/***********************************************************************
 * Routing Key Management
 ***********************************************************************/

template (value) M3UA_Local_Routing_Key_Id ts_M3UA_lrkid(template (value) OCT4 id) := {
	tag := '020a'O,
	lengthInd := 8,
	localRkId := id
}

template (present) M3UA_Local_Routing_Key_Id tr_M3UA_lrkid(template (present) OCT4 id) := {
	tag := '020a'O,
	lengthInd := 8,
	localRkId := id
}


template (value) M3UA_Routing_Key ts_M3UA_rkey(OCT4 id, OCT3 dpc,
						template (omit) M3UA_Traffic_Mode_Type tmt := omit,
						template (omit) OCT4 rctx := omit) := {
	tag := '0207'O,
	lengthInd := 0, // overwritten
	routingKey := {
		local_Routing_Key_Id := ts_M3UA_lrkid(id),
		routing_Context := ts_M3UA_routing_ctx(rctx),
		traffic_Mode_Type := tmt,
		destination_Point_Code := {
			tag := '020b'O,
			lengthInd := 8,
			pointCode := { '00'O, dpc }
		},
		network_Appearance := omit,
		service_Indicators := omit,
		opc_List := omit
	}
}
template (present) M3UA_Routing_Key tr_M3UA_rkey(template (present) OCT4 id, template (present) OCT3 dpc,
						template M3UA_Traffic_Mode_Type tmt := *,
						template OCT4 rctx := *) := {
	tag := '0207'O,
	lengthInd := ?,
	routingKey := {
		local_Routing_Key_Id := tr_M3UA_lrkid(id),
		routing_Context := tr_M3UA_routing_ctx(rctx),
		traffic_Mode_Type := tmt,
		destination_Point_Code := {
			tag := '020b'O,
			lengthInd := 8,
			pointCode := { '00'O, dpc }
		},
		network_Appearance := omit,
		service_Indicators := omit,
		opc_List := omit
	}
}


const OCT4 c_M3UA_REGSTS_SUCCESS := '00000000'O;
const OCT4 c_M3UA_REGSTS_ERR_UNKNOWN := '00000001'O;
const OCT4 c_M3UA_REGSTS_ERR_INVAL_DPC := '00000002'O;
const OCT4 c_M3UA_REGSTS_ERR_INVAL_NA := '00000003'O;
const OCT4 c_M3UA_REGSTS_ERR_INVAL_RKEY := '00000004'O;
const OCT4 c_M3UA_REGSTS_ERR_EPERM := '00000005'O;
// ...

const OCT4 c_m3UA_DEREGSTS_SUCCESS := '00000000'O;
const OCT4 c_m3UA_DEREGSTS_ERR_UNKNOWN := '00000001'O;
const OCT4 c_m3UA_DEREGSTS_ERR_INVAL_RCTX := '00000002'O;
const OCT4 c_m3UA_DEREGSTS_ERR_EPERM := '00000003'O;
const OCT4 c_m3UA_DEREGSTS_ERR_NOT_REG := '00000004'O;
const OCT4 c_m3UA_DEREGSTS_ERR_ASP_ACTIVE := '00000005'O;

template (value) M3UA_Registration_Result ts_M3UA_reg_res(template (value) OCT4 id,
							    template (value) OCT4 status,
							    template (value) OCT4 rctx) := {
	tag := '0208'O,
	lengthInd := 0, // overwritten
	registrationResult := {
		local_Routing_Key_Id := ts_M3UA_lrkid(id),
		registration_Status := {
			tag := '0212'O,
			lengthInd := 8,
			registrationStatus := status
		},
		routing_Context := ts_M3UA_routing_ctx(rctx)
	}
}
template (present) M3UA_Registration_Result tr_M3UA_reg_res(template (present) OCT4 id,
							    template (present) OCT4 status,
							    template (present) OCT4 rctx) := {
	tag := '0208'O,
	lengthInd := ?,
	registrationResult := {
		local_Routing_Key_Id := tr_M3UA_lrkid(id),
		registration_Status := {
			tag := '0212'O,
			lengthInd := 8,
			registrationStatus := status
		},
		routing_Context := tr_M3UA_routing_ctx(rctx)
	}
}

template (value) M3UA_Deregistration_Result ts_M3UA_dereg_res(template (value) OCT4 rctx,
							      template (value) OCT4 status) := {
	tag := '0209'O,
	lengthInd := 0, // overwritten
	deregistrationResult := {
		routing_Context := ts_M3UA_routing_ctx(rctx),
		deregistration_Status := {
			tag := '0213'O,
			lengthInd := 8,
			deregistrationStatus := status
		}
	}
}
template (present) M3UA_Deregistration_Result tr_M3UA_dereg_res(template (present) OCT4 rctx,
								template (present) OCT4 status) := {
	tag := '0209'O,
	lengthInd := ?,
	deregistrationResult := {
		routing_Context := tr_M3UA_routing_ctx(rctx),
		deregistration_Status := {
			tag := '0213'O,
			lengthInd := 8,
			deregistrationStatus := status
		}
	}
}


template (value) PDU_M3UA ts_M3UA_REG_REQ(template (value) M3UA_Routing_Keys rkeys) := {
	m3UA_REG_REQ := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0901'O,
		messageLength := 0, // overwritten
		messageParameters := rkeys
	}
}
template (present) PDU_M3UA tr_M3UA_REG_REQ(template (present) M3UA_Routing_Keys rkeys) := {
	m3UA_REG_REQ := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0901'O,
		messageLength := ?,
		messageParameters := rkeys
	}
}


template (value) PDU_M3UA ts_M3UA_REG_RSP(template (value) M3UA_Registration_Results res) := {
	m3UA_REG_RSP := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0902'O,
		messageLength := 0, // overwritten
		messageParameters := res
	}
}
template (present) PDU_M3UA tr_M3UA_REG_RSP(template (present) M3UA_Registration_Results res) := {
	m3UA_REG_RSP := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0902'O,
		messageLength := ?,
		messageParameters := res
	}
}

template (value) PDU_M3UA ts_M3UA_DEREG_REQ(template (value) M3UA_Routing_Context rctx) := {
	m3UA_DEREG_REQ := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0903'O,
		messageLength := 0, // overwritten
		messageParameters := {
			routing_Context := rctx
		}
	}
}
template (present) PDU_M3UA tr_M3UA_DEREG_REQ(template (present) M3UA_Routing_Context rctx) := {
	m3UA_DEREG_REQ := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0903'O,
		messageLength := ?,
		messageParameters := {
			routing_Context := rctx
		}
	}
}

template (value) PDU_M3UA ts_M3UA_DEREG_RSP(template (value) M3UA_Deregistration_Results res) := {
	m3UA_DEREG_RSP := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0904'O,
		messageLength := 0, // overwritten
		messageParameters := res
	}
}
template (present) PDU_M3UA tr_M3UA_DEREG_RSP(template (present) M3UA_Deregistration_Results res) := {
	m3UA_DEREG_RSP := {
		version := c_M3UA_VERSION,
		reserved := '00'O,
		messageClassAndType := '0904'O,
		messageLength := ?,
		messageParameters := res
	}
}



}