/* 3GPP TS 24.301, EPC (Evolved Packet Core) NAS (Non-Access Stratum) templates in TTCN-3
 * (C) 2019 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
 */

module NAS_Templates {

import from General_Types all;
import from NAS_EPS_Types all;

template (value) PDU_NAS_EPS
ts_NAS_SM(template (value) EPS_SessionManagement sm) := {
	protocolDiscriminator := '0010'B,
	ePS_messages := {
		ePS_SessionManagement := sm
	}
}
template (present) PDU_NAS_EPS
tr_NAS_SM(template (present) EPS_SessionManagement sm) := {
	protocolDiscriminator := '0010'B,
	ePS_messages := {
		ePS_SessionManagement := sm
	}
}

template (value) PDU_NAS_EPS
ts_NAS_MM(template (value) EPS_MobilityManagement mm) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := mm
	}
}
template (present) PDU_NAS_EPS
tr_NAS_MM(template (present) EPS_MobilityManagement mm) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := mm
	}
}

const BIT4 c_EPS_SEC_NONE := '0000'B;
const BIT4 c_EPS_SEC_IP := '0001'B;
const BIT4 c_EPS_SEC_IP_CIPH := '0010'B;

const BIT4 c_EPS_NAS_PD_EMM := '0111'B;
const BIT4 c_EPS_NAS_PD_ESM := '0010'B;

private template (value) ESM_MessageContainerLVE
ts_NAS_EsmMsgContLVE(template (value) octetstring inp) := {
	lengthIndicator := 0,
	content := inp
}
private template (present) ESM_MessageContainerLVE
tr_NAS_EsmMsgContLVE(template (present) octetstring inp) := {
	lengthIndicator := ?,
	content := inp
}

/* 9.9.3.4A - 10.5.1.2/24.008 */
template (value) CipheringKeySequenceNumberTV
ts_CipheringKeySequenceNumberTV(template (value) BIT3 key_seq) := {
	 keySequence := {
		keySequence := key_seq,
		spare := '0'B
	 },
	 elementIdentifier := '1000'B
}

private template (value) MobileIdentityLV
ts_NAS_MobileIdLV(template (value) MobileIdentityV mid) := {
	lengthIndicator := 0,
	mobileIdentityV := mid
}
private template (present) MobileIdentityLV
tr_NAS_MobileIdLV(template (present) MobileIdentityV mid) := {
	lengthIndicator := ?,
	mobileIdentityV := mid
}

private function f_enc_IMSI_NAS(hexstring digits) return IMSI {
	var IMSI l3;
	var integer len := lengthof(digits);
	if (len rem 2 == 1) {	/* modulo remainder */
		l3.oddevenIndicator := '1'B;
		l3.fillerDigit := omit;
	} else {
		l3.oddevenIndicator := '0'B;
		l3.fillerDigit := '1111'B;
	}
	l3.digits := digits;
	return l3;
}

private function f_enc_IMEI_NAS(hexstring digits) return IMEI {
	var IMEI l3;
	var integer len := lengthof(digits);
	if (len rem 2 == 1) {	/* modulo remainder */
		l3.oddevenIndicator := '1'B;
	} else {
		l3.oddevenIndicator := '0'B;
	}
	l3.digits := digits;
	return l3;
}

private function f_enc_IMEI_SV(hexstring digits) return IMEI_SV {
	var IMEI_SV l3;
	var integer len := lengthof(digits);
	if (len rem 2 == 1) {	/* modulo remainder */
		l3.oddevenIndicator := '1'B;
	} else {
		l3.oddevenIndicator := '0'B;
	}
	l3.digits := digits;
	l3.fillerDigit := '1111'B;
	return l3;
}

template (value) GUTI ts_NAS_GUTI(hexstring mcc_mnc, OCT2 mmegi, OCT1 mmec, OCT4 tmsi) := {
	oddevenIndicator := '0'B,
	spare := '1111'B,
	/* use the mcc_mnc format as specified in 3GPP TS 24.301, figure 9.9.3.12.1.
	 * Example: mcc=262, mnc=42 => 262f42.
	 * 	    mcc=001, mnc=01 => 001f01. */
	mccDigit1 := mcc_mnc[0],
	mccDigit2 := mcc_mnc[1],
	mccDigit3 := mcc_mnc[2],
	mncDigit3 := mcc_mnc[3],
	mncDigit1 := mcc_mnc[4],
	mncDigit2 := mcc_mnc[5],
	mMEGI := mmegi,
	mMEC := mmec,
	mTMSI := tmsi
}

template (value) EPS_MobileIdentityV
ts_NAS_MobileId_IMSI(hexstring imsi) := {
	typeOfIdentity := '001'B,
	oddEvenInd_identity := {
		imsi := f_enc_IMSI_NAS(imsi)
	}
}

template (value) EPS_MobileIdentityV
ts_NAS_MobileId_IMEI(hexstring imei) := {
	typeOfIdentity := '011'B,
	oddEvenInd_identity := {
		imei := f_enc_IMEI_NAS(imei)
	}
}

template (value) EPS_MobileIdentityV
ts_NAS_MobileId_GUTI_fields(hexstring mcc_mnc, OCT2 mmegi, OCT1 mmec, OCT4 tmsi) := {
	typeOfIdentity := '110'B,
	oddEvenInd_identity := {
		guti := ts_NAS_GUTI(mcc_mnc, mmegi, mmec, tmsi)
	}
}

template (value) EPS_MobileIdentityV
ts_NAS_MobileId_GUTI(template (value) GUTI guti) := {
	typeOfIdentity := '110'B,
	oddEvenInd_identity := {
		guti := guti
	}
}

/* 9.9.3.12 EPS mobile identity */
template (value) EPS_MobileIdentityLV
ts_EPS_MobileId_IMSI(hexstring imsi) := {
	 ePS_MobileIdentity := ts_NAS_MobileId_IMSI(imsi)
}

template (value) EPS_MobileIdentityLV
ts_EPS_MobileId_IMEI(hexstring imei) := {
	 ePS_MobileIdentity := ts_NAS_MobileId_IMEI(imei)
}

template (value) EPS_MobileIdentityLV
ts_EPS_MobileId_GUTI(hexstring mcc_mnc, OCT2 mmegi, OCT1 mmec, OCT4 tmsi) := {
	 ePS_MobileIdentity := ts_NAS_MobileId_GUTI_fields(mcc_mnc, mmegi, mmec, tmsi)
}

template (value) EPS_MobileIdentityLV
ts_EPS_MobileId_GUTI_(template (value) GUTI guti) := {
	 ePS_MobileIdentity := ts_NAS_MobileId_GUTI(guti)
}

/* 9.9.3.25 Nonce */
template (value) NonceTV
ts_NonceTV(template (value) OCT4 nonce) := {
	 elementIdentifier := '55'O,
	 noncevalue := nonce
}
function f_ts_NonceTV(template (omit) OCT4 nonce) return template (omit) NonceTV {
	if (istemplatekind(nonce, "omit")) {
		return omit;
	}
	return ts_NonceTV(nonce);
}

/* 9.9.3.26 P-TMSI signature */
template (value) P_TMSISignatureTV
ts_PTMSI_SignatureTV(template (value) OCT3 ptmsi_sig) := {
	 elementIdentifier := '19'O,
	 valueField := ptmsi_sig
}

/* 9.9.3.34 UE network capability */
template (value) UENetworkCapabilityLV
ts_UENetworkCapabilityLV(template (value) UENetworkCapabilityV ue_net_cap) := {
	 lengthIndicator := 0, /* overwritten */
	 uENetworkCapabilityV := ue_net_cap
}
template (value) UENetworkCapabilityTLV
ts_UENetworkCapabilityTLV(template (value) UENetworkCapabilityV ue_net_cap) := {
	 elementIdentifier := '58'O,
	 uENetworkCapabilityLV := ts_UENetworkCapabilityLV(ue_net_cap)
}

/* 9.9.3.45 GUTI Type */
const BIT1 GUTI_TYPE_NATIVE := '0'B;
const BIT1 GUTI_TYPE_MAPPED := '1'B;
template (value) GUTI_TypeTV
ts_GUTI_TypeTV(template (value) BIT1 guti_type) := {
	gUTI_Type := guti_type,
	spare := '000'B,
	elementIdentifier := '1110'B
}

template (value) PDU_NAS_EPS
ts_NAS_EMM_SecurityProtected(BIT4 sec_hdr_t, integer seq_nr, octetstring inner_nas) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_SecurityProtectedNASMessage := {
				securityHeaderType := sec_hdr_t,
				messageAuthenticationCode := '00000000'O,
				sequenceNumber := seq_nr,
				nAS_Message := inner_nas
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_EMM_SecurityProtected := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_SecurityProtectedNASMessage := ?
		}
	}
}

const BIT3 NAS_PDN_T_IPv4 := '001'B;
const BIT3 NAS_PDN_T_IPv6 := '010'B;
const BIT3 NAS_PDN_T_IPv4v6 := '011'B;
const BIT3 NAS_PDN_T_NonIP := '101'B;


/*********************************************************************************
 * Mobility Management
 *********************************************************************************/

/* 8.2.1 Attach Accept */
template (value) PDU_NAS_EPS
ts_NAS_AttachAccept(template (value) EPS_AttachResultV result,
		    template (value) GPRSTimerV t3412,
		    template (value) TAI_Lists tai_lists,
		    template (value) octetstring esm_enc) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachAccept := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01000010'B,
				ePS_AttachResult := result,
				spare := '0000'B,
				t3412 := t3412,
				tAI_List := {
					lengthIndicator := 0,
					trackingAreaIdentityLists := tai_lists
				},
				eSM_MessageContainer := ts_NAS_EsmMsgContLVE(esm_enc),
				gUTI := omit,
				locationAreaIdentification := omit,
				msIdentity := omit,
				eMMCause := omit,
				t3402 := omit,
				t3423 := omit,
				equivalentPLMNs := omit,
				emergencyNumberList := omit,
				ePS_NetworkFeatureSupport := omit,
				additionalUpdateResult := omit,
				t3412_Extended := omit,
				t3324 := omit,
				extendedDRXParameters := omit,
				dNCID := omit,
				sMS_ServiceStatus := omit,
				non3GPP_NW_ProvidedPolicies := omit,
				t3448 := omit,
				networkPolicy := omit,
				t3447 := omit,
				extendedEmergencyNumberList := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_AttachAccept(template (present) EPS_AttachResultV result := ?,
		    template (present) GPRSTimerV t3412 := ?,
		    template (present) TAI_Lists tai_lists := ?,
		    template (present) octetstring esm_enc := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachAccept := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01000010'B,
				ePS_AttachResult := result,
				spare := ?,
				t3412 := t3412,
				tAI_List := {
					lengthIndicator := ?,
					trackingAreaIdentityLists := tai_lists
				},
				eSM_MessageContainer := tr_NAS_EsmMsgContLVE(esm_enc),
				gUTI := *,
				locationAreaIdentification := *,
				msIdentity := *,
				eMMCause := *,
				t3402 := *,
				t3423 := *,
				equivalentPLMNs := *,
				emergencyNumberList := *,
				ePS_NetworkFeatureSupport := *,
				additionalUpdateResult := *,
				t3412_Extended := *,
				t3324 := *,
				extendedDRXParameters := *,
				dNCID := *,
				sMS_ServiceStatus := *,
				non3GPP_NW_ProvidedPolicies := *,
				t3448 := *,
				networkPolicy := *,
				t3447 := *,
				extendedEmergencyNumberList := *
			}
		}
	}
}


/* 8.2.2 Attach Complete */
template (value) PDU_NAS_EPS
ts_NAS_AttachComplete(template (value) octetstring esm_enc) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachComplete := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01000011'B,
				eSM_MessageContainer := ts_NAS_EsmMsgContLVE(esm_enc)
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_AttachComplete(template (present) octetstring esm_enc := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachComplete := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01000011'B,
				eSM_MessageContainer := tr_NAS_EsmMsgContLVE(esm_enc)
			}
		}
	}
}

/* 9.9.3.14 EPS update type */
const BIT3 c_EPS_UPD_TYPE_TA_UPD := '000'B;
const BIT3 c_EPS_UPD_TYPE_COMB_TA_LA_UPD := '001'B;
const BIT3 c_EPS_UPD_TYPE_COMB_TA_LA_UPD_IMSI_ATTACH := '010'B;
const BIT3 c_EPS_UPD_TYPE_TA_UPD_PERIODIC := '011'B;
template (value) EPS_UpdateTypeV ts_EPS_UpdateTypeV(BIT3 typeOfUpdate := c_EPS_UPD_TYPE_TA_UPD, BIT1 activeFlag := '0'B) := {
	 typeOfUpdate := typeOfUpdate,
	 activeFlag := activeFlag
}

/* 9.9.3.21 NAS key set identifier */
const BIT3 c_NAS_KEY_SET_ID_NO_KEY := '111'B;
const BIT1 c_NAS_TSC_NATIVE_SEC_CTX := '0'B;
const BIT1 c_NAS_TSC_MAPPED_SEC_CTX := '1'B;
template (value) NAS_KeySetIdentifierV ts_NAS_KeySetIdentifierV(BIT3 identifier := c_NAS_KEY_SET_ID_NO_KEY, BIT1 tSC := c_NAS_TSC_NATIVE_SEC_CTX) := {
	identifier := identifier,
	tSC := tSC
}
template (present) NAS_KeySetIdentifierV tr_NAS_KeySetIdentifierV(template (present) BIT3 identifier := ?,
								  template (present) BIT1 tSC := ?) := {
	identifier := identifier,
	tSC := tSC
}

/* 8.2.26 Tracking Area Update Accept */
template (present) PDU_NAS_EPS
tr_PDU_NAS_EPS_TrackingAreaUpdateAccept := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_TrackingAreaUpdateAccept := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01001001'B,
				updateResult := {
					valueOfUpdateResult := ?,
					spare := '0'B
				},
				spareHalfOctet := '0000'B,
				t3412 := *,
				gUTI := *,
				tAI_List := *,
				ePSBearerContextStatus := *,
				locationAreaIdentification := *,
				msIdentity := *,
				eMMCause := *,
				t3402 := *,
				t3423 := *,
				equivalentPLMNs := *,
				emergencyNumberList := *,
				ePS_NetworkFeatureSupport := *,
				additionalUpdateResult := *,
				t3412_Extended := *,
				t3324 := *,
				extendedDRXParameters := *,
				headerCompressionConfigurationStatus := *,
				dNCID := *,
				sMS_ServiceStatus := *,
				non3GPP_NW_ProvidedPolicies := *,
				t3448 := *,
				networkPolicy := *,
				t3447 := *,
				extendedEmergencyNumberList := *
			}
		}
	}
}

/* 8.2.27 Tracking Area Update Complete */
template (value) PDU_NAS_EPS
ts_PDU_NAS_EPS_TrackingAreaUpdateComplete(template (value) BIT4 securityHeaderType := c_EPS_SEC_NONE) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_TrackingAreaUpdateComplete := {
				securityHeaderType := securityHeaderType,
				messageType := '01001010'B
			}
		}
	}
}

/* 8.2.28 Tracking Area Update Reject */
template (present) PDU_NAS_EPS
tr_PDU_NAS_EPS_TrackingAreaUpdateReject(template (present) EMM_CauseV cause := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_TrackingAreaUpdateReject := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01001011'B,
				emmCause := cause,
				t3346 := *,
				extendedEmmCause := *
			}
		}
	}
}

/* 8.2.29 Tracking Area Update Request */
template (value) PDU_NAS_EPS
ts_PDU_NAS_EPS_TrackingAreaUpdateRequest(template (value) EPS_MobileIdentityLV old_guti,
					 template (value) NAS_KeySetIdentifierV kset_id := ts_NAS_KeySetIdentifierV,
					 template (omit) P_TMSISignatureTV old_ptmsi_sig := omit,
					 template (omit) GUTI_TypeTV old_guti_type := omit,
					 template (omit) NonceTV nonce_ue := omit,
					 template (omit) CipheringKeySequenceNumberTV gprs_cksn := omit,
					 template (omit) UENetworkCapabilityTLV ue_net_cap := omit) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_TrackingAreaUpdateRequest := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01001000'B,
				ePSupdateType := ts_EPS_UpdateTypeV,
				nasKeySetId := kset_id,
				oldGUTI := old_guti,
				nonCurrentNative_nasKeySetId := omit,
				gprsCipheringKeySequenceNumber := gprs_cksn,
				old_P_TMSISignature := old_ptmsi_sig,
				additionalGUTI := omit,
				nonce := nonce_ue,
				uENetworkCapability := ue_net_cap,
				lastVisitedRegisteredTAI := omit,
				dRXParameter := omit,
				uE_RadioCapabilityInfoUpdateNeeded := omit,
				ePSBearerContextStatus := omit,
				mSNetworkCapability := omit,
				oldLocationAreaIdentification := omit,
				tMSIStatusTV := omit,
				mobileStationClassmark2 := omit,
				mobileStationClassmark3 := omit,
				supportedCodecList := omit,
				additionalUpdateType := omit,
				voiceDomainPrefandUEsettings := omit,
				oldGUTI_Type := old_guti_type,
				deviceProperties := omit,
				mS_NetworkFeatureSupport := omit,
				tMSIBasedNRIContainer := omit,
				t3324 := omit,
				t3412_Extended := omit,
				extendedDRXParameters := omit,
				uEAdditionalSecurityCapability := omit,
				uEStatus := omit
			}
		}
	}
}

/* 8.2.3 Attach Reject */
template (value) PDU_NAS_EPS
ts_NAS_AttachReject(template (value) EMM_CauseV cause) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachReject := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01000100'B,
				emmCause := cause,
				eSM_MessageContainer := omit,
				t3346 := omit,
				t3402 := omit,
				extendedEmmCause := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_AttachReject(template (present) EMM_CauseV cause := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachReject := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01000100'B,
				emmCause := cause,
				eSM_MessageContainer := omit,
				t3346 := omit,
				t3402 := omit,
				extendedEmmCause := omit
			}
		}
	}
}

/* 8.2.4 Attach Request */
template (value) PDU_NAS_EPS
ts_NAS_AttachRequest(template (value) BIT3 att_type,
		     template (value) NAS_KeySetIdentifierV kset_id,
		     template (value) EPS_MobileIdentityV mobile_id,
		     template (value) UENetworkCapabilityV ue_net_cap,
		     template (value) octetstring esm_enc) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachRequest := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01000001'B,
				ePS_attachType := {
					typeOfAttach := att_type,
					spare := '0'B
				},
				nasKeySetId := kset_id,
				ePSMobileId := {
					lengthIndicator := 0,
					ePS_MobileIdentity := mobile_id
				},
				uENetworkCapability := {
					lengthIndicator := 0,
					uENetworkCapabilityV := ue_net_cap
				},
				eSM_MessageContainer := ts_NAS_EsmMsgContLVE(esm_enc),
				old_P_TMSISignature := omit,
				additionalGUTI := omit,
				lastVisitedRegisteredTAI := omit,
				dRXParameter := omit,
				mSNetworkCapability := omit,
				oldLocationAreaIdentification := omit,
				tMSIStatusTV := omit,
				mobileStationClassmark2 := omit,
				mobileStationClassmark3 := omit,
				supportedCodecList := omit,
				additionalUpdateType := omit,
				voiceDomainPrefandUEsettings := omit,
				deviceProperties := omit,
				oldGUTI_Type := omit,
				mS_NetworkFeatureSupport := omit,
				tMSIBasedNRIContainer := omit,
				t3324 := omit,
				t3412_Extended := omit,
				extendedDRXParameters := omit,
				uEAdditionalSecurityCapability := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_AttachRequest(template (present) BIT3 att_type := ?,
		    template (present) NAS_KeySetIdentifierV kset_id := ?,
		    template (present) EPS_MobileIdentityV mobile_id := ?,
		    template (present) UENetworkCapabilityV ue_net_cap := ?,
		    template (present) octetstring esm_enc := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AttachRequest := {
				securityHeaderType := ?,
				messageType := '01000001'B,
				ePS_attachType := {
					typeOfAttach := att_type,
					spare := ?
				},
				nasKeySetId := kset_id,
				ePSMobileId := {
					lengthIndicator := ?,
					ePS_MobileIdentity := mobile_id
				},
				uENetworkCapability := {
					lengthIndicator := ?,
					uENetworkCapabilityV := ue_net_cap
				},
				eSM_MessageContainer := tr_NAS_EsmMsgContLVE(esm_enc),
				old_P_TMSISignature := *,
				additionalGUTI := *,
				lastVisitedRegisteredTAI := *,
				dRXParameter := *,
				mSNetworkCapability := *,
				oldLocationAreaIdentification := *,
				tMSIStatusTV := *,
				mobileStationClassmark2 := *,
				mobileStationClassmark3 := *,
				supportedCodecList := *,
				additionalUpdateType := *,
				voiceDomainPrefandUEsettings := *,
				deviceProperties := *,
				oldGUTI_Type := *,
				mS_NetworkFeatureSupport := *,
				tMSIBasedNRIContainer := *,
				t3324 := *,
				t3412_Extended := *,
				extendedDRXParameters := *,
				uEAdditionalSecurityCapability := *
			}
		}
	}
}


/* 8.2.5 Authentication Failure */
template (value) PDU_NAS_EPS
ts_NAS_AuthFail(template (value) EMM_CauseV cause /* template (omit) OCT14 auth_fail_par */) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationFailure := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01011100'B,
				emmCause := cause,
				authenticationFailureParameter := omit
			}
		}
	}
}
template (value) PDU_NAS_EPS
ts_NAS_AuthFail_par(template (value) EMM_CauseV cause,
		    template (value) OCT14 auth_fail_par) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationFailure := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01011100'B,
				emmCause := cause,
				authenticationFailureParameter := {
					elementIdentifier := '30'O,
					lengthIndicator := lengthof(auth_fail_par),
					authenticationFailureParameter := auth_fail_par
				}
			}
		}
	}
}

/* 8.2.6 Authentication Reject */
template (value) PDU_NAS_EPS
ts_NAS_AuthRej := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationReject := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01010100'B
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_AuthRej := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationReject := {
				securityHeaderType := ?,
				messageType := '01010100'B
			}
		}
	}
}

/* 8.2.7 Authentication Request */
template (value) PDU_NAS_EPS
ts_NAS_AuthReq(template (value) NAS_KeySetIdentifierV kset_id,
	       OCT16 rand, OCT16 autn) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationRequest := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01010010'B,
				nasKeySetId := kset_id,
				spare := '0000'B,
				authenticationParameterRAND := {
					rAND := rand
				},
				authenticationParameterAUTN := {
					lengthIndicator := lengthof(autn),
					aUTN := autn
				}
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_AuthReq(template (present) NAS_KeySetIdentifierV kset_id := ?,
	       template (present) OCT16 rand := ?,
	       template (present) OCT16 autn := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationRequest := {
				securityHeaderType := ?,
				messageType := '01010010'B,
				nasKeySetId := kset_id,
				spare := '0000'B,
				authenticationParameterRAND := {
					rAND := rand
				},
				authenticationParameterAUTN := {
					lengthIndicator := ?,
					aUTN := autn
				}
			}
		}
	}
}

/* 8.2.8 Authentication Response */
template (value) PDU_NAS_EPS
ts_NAS_AuthResp(octetstring res) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationResponse := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01010011'B,
				authenticationResponseParameter := {
					lengthIndicator := lengthof(res),
					authenticationResponseParameter := {
						rES := res
					}
				}
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_AuthResp(template OCT16 res := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_AuthenticationResponse := {
				securityHeaderType := ?,
				messageType := '01010011'B,
				authenticationResponseParameter := {
					lengthIndicator := ?,
					authenticationResponseParameter := {
						rES := res
					}
				}
			}
		}
	}
}

/* 8.2.13 EMM information */
template (present) PDU_NAS_EPS
tr_NAS_EMMInformation := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_EMM_Information := {
				securityHeaderType := ?,
				messageType := '01100001'B,
				fullNameForNetwork := *,
				shortNameForNetwork := *,
				localTimeZone := *,
				universalTimeAndLocalTimeZone := *,
				networkDaylightSavingTime := *
			}
		}
	}
}

/* 8.2.18 Identity Request */
template (value) PDU_NAS_EPS
ts_NAS_IdentityReq(template (value) IdentityType2V id_type) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_IdentityRequest := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01010101'B,
				identityType := id_type,
				spareHalfOctet := '0000'B
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_IdentityReq(template (present) IdentityType2V id_type := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_IdentityRequest := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01010101'B,
				identityType := id_type,
				spareHalfOctet := ?
			}
		}
	}
}

/* 8.2.19 Identity Response */
template (value) PDU_NAS_EPS
ts_NAS_IdentityResp(template (value) MobileIdentityV mobile_id) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_IdentityResponse := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01010110'B,
				mobileIdentity := ts_NAS_MobileIdLV(mobile_id)
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_IdentityResp(template (present) MobileIdentityV mobile_id := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_IdentityResponse := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01010110'B,
				mobileIdentity := tr_NAS_MobileIdLV(mobile_id)
			}
		}
	}
}




/* 8.2.20 Security Mode Command */
template (value) PDU_NAS_EPS
ts_NAS_SecModeCmd(template (value) NAS_SecurityAlgorithmsV alg,
		  template (value) NAS_KeySetIdentifierV kset_id,
		  template (value) UESecurityCapabilityLV ue_sec_cap) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_SecurityModeCommand := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01011101'B,
				selected_NAS_SecurityAlgorithms := alg,
				nasKeySetId := kset_id,
				spareHalfOctet := '0000'B,
				replayed_UE_SecurityCapability := ue_sec_cap,
				iMEISV_Request := omit,
				replayedNonceUE := omit,
				nonceMME := omit,
				hashMME := omit,
				uEAdditionalSecurityCapability := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_SecModeCmd(template (present) NAS_SecurityAlgorithmsV alg := ?,
		  template (present) NAS_KeySetIdentifierV kset_id := ?,
		  template (present) UESecurityCapabilityLV ue_sec_cap := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_SecurityModeCommand := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01011101'B,
				selected_NAS_SecurityAlgorithms := alg,
				nasKeySetId := kset_id,
				spareHalfOctet := ?,
				replayed_UE_SecurityCapability := ue_sec_cap,
				iMEISV_Request := *,
				replayedNonceUE := *,
				nonceMME := *,
				hashMME := *,
				uEAdditionalSecurityCapability := *
			}
		}
	}
}

/* 8.2.21 Security Mode Complete */
template (value) PDU_NAS_EPS
ts_NAS_SecModeCmpl := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_SecurityModeComplete := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01011110'B,
				iMEISV := omit,
				replayedNASMessageContainer := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_SecModeCmpl := {
	protocolDiscriminator := c_EPS_NAS_PD_EMM,
	ePS_messages := {
		ePS_MobilityManagement := {
			pDU_NAS_EPS_SecurityModeComplete := {
				securityHeaderType := c_EPS_SEC_NONE,
				messageType := '01011110'B,
				iMEISV := *,
				replayedNASMessageContainer := *
			}
		}
	}
}

/*********************************************************************************
 * Session Management
 *********************************************************************************/

/* 9.9.4.11 - 10.5.6.3/24.008 */
private function ts_NAS_PCO_TLV(template (omit) ProtocolConfigOptionsV pco)
return template (omit) ProtocolConfigOptionsTLV {
	var template (value) ProtocolConfigOptionsTLV ret;
	if (istemplatekind(pco, "omit")) {
		return omit;
	}
	ret := {
		elementIdentifier := '27'O,
		protocolConfigOptions := {
			lengthIndicator := 0,
			protocolConfigOptionsV := pco
		}
	}
	return ret;
}
private function tr_NAS_PCO_TLV(template ProtocolConfigOptionsV pco := ?)
return template ProtocolConfigOptionsTLV {
	var template ProtocolConfigOptionsTLV ret := {
		elementIdentifier := '27'O,
		protocolConfigOptions := {
			lengthIndicator := ?,
			protocolConfigOptionsV := pco
		}
	}
	if (istemplatekind(pco, "omit")) {
		return omit;
	} else if (istemplatekind(pco, "*")) {
		return *;
	} else {
		return ret;
	}
}



/* 8.3.20 PDN Connectivity Request */
template (value) PDU_NAS_EPS
ts_NAS_PdnConnReq(template (value) BIT4 bearer_id,
		  template (value) BIT8 proc_tid,
		  template (value) BIT3 pdn_type,
		  template (value) BIT3 req_type) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_PDN_ConnectivityRequest := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11010000'B,
				requestType := {
					requestTypeValue := req_type,
					spare := '0'B
				},
				pDN_Type := {
					pDN_TypeValue := pdn_type,
					spare := '0'B
				},
				eSM_InformationTransferFlag := omit,
				accessPointName := omit,
				protocolConfigOptions := omit,
				deviceProperties := omit,
				nBIFOMContainer := omit,
				headerCompressinConfiguration := omit,
				extendedProtocolConfigurationOptions := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_PdnConnReq(template (present) BIT4 bearer_id := ?,
		  template (present) BIT8 proc_tid := ?,
		  template (present) BIT3 pdn_type := ?,
		  template (present) BIT3 req_type := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_PDN_ConnectivityRequest := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11010000'B,
				requestType := {
					requestTypeValue := req_type,
					spare := '0'B
				},
				pDN_Type := {
					pDN_TypeValue := pdn_type,
					spare := '0'B
				},
				eSM_InformationTransferFlag := omit,
				accessPointName := omit,
				protocolConfigOptions := omit,
				deviceProperties := omit,
				nBIFOMContainer := omit,
				headerCompressinConfiguration := omit,
				extendedProtocolConfigurationOptions := omit
			}
		}
	}
}

/* 8.3.19 PDN Connectivity Reject */
template (value) PDU_NAS_EPS
ts_NAS_PdnConnRej(template (value) BIT4 bearer_id,
		  template (value) BIT8 proc_tid,
		  template (value) ESM_CauseV cause) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_PDN_ConnectivityReject := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11010001'B,
				esmCause := cause,
				protocolConfigOptions := omit,
				backOffTimer := omit,
				reAttemptIndicator := omit,
				nBIFOMContainer := omit,
				extendedProtocolConfigurationOptions := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_PdnConnRej(template (present) BIT4 bearer_id := ?,
		  template (present) BIT8 proc_tid := ?,
		  template (present) ESM_CauseV cause := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_PDN_ConnectivityReject := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11010001'B,
				esmCause := cause,
				protocolConfigOptions := *,
				backOffTimer := *,
				reAttemptIndicator := *,
				nBIFOMContainer := *,
				extendedProtocolConfigurationOptions := *
			}
		}
	}
}


/* 8.3.6 Activate Default EPS Bearer Context Request */
template (value) PDU_NAS_EPS
ts_NAS_ActDefEpsBearCtxReq(template (value) BIT4 bearer_id,
			   template (value) BIT8 proc_tid,
			   template (value) EPS_QualityOfServiceV qos,
			   template (value) octetstring apn,
			   template (value) BIT3 addr_type,
			   template (value) octetstring addr_info) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_ActDefEPSBearerContextRequest := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11000001'B,
				ePS_QoS := {
					lengthIndicator := 0,
					ePS_QualityOfServiceV := qos
				},
				accessPointName := {
					lengthIndicator := 0,
					accessPointNameValue := apn
				},
				pDN_Address := {
					lengthIndicator := 0,
					typeValue := addr_type,
					spare := '00000'B,
					addressInformation := addr_info
				},
				transactionIdentifier := omit,
				negotiatedQoS := omit,
				negotiated_LLC_SAPI := omit,
				radioPriority := omit,
				packetFlowID := omit,
				aPN_AMBR := omit,
				esmCause := omit,
				protocolConfigOptions := omit,
				connectivityType := omit,
				wLANOffloadIndication := omit,
				nBIFOMContainer := omit,
				headerCompressinConfiguration := omit,
				controlPlaneOnlyIndication := omit,
				extendedProtocolConfigurationOptions := omit,
				servingPLMNRateControl := omit,
				extended_APN_AMBR := omit,
				extendedQoS := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_ActDefEpsBearCtxReq(template (present) BIT4 bearer_id := ?,
			   template (present) BIT8 proc_tid := ?,
			   template (present) EPS_QualityOfServiceV qos := ?,
			   template (present) octetstring apn := ?,
			   template (present) BIT3 addr_type := ?,
			   template (present) octetstring addr_info := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_ActDefEPSBearerContextRequest := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11000001'B,
				ePS_QoS := {
					lengthIndicator := ?,
					ePS_QualityOfServiceV := qos
				},
				accessPointName := {
					lengthIndicator := 0,
					accessPointNameValue := apn
				},
				pDN_Address := {
					lengthIndicator := 0,
					typeValue := addr_type,
					spare := '00000'B,
					addressInformation := addr_info
				},
				transactionIdentifier := *,
				negotiatedQoS := *,
				negotiated_LLC_SAPI := *,
				radioPriority := *,
				packetFlowID := *,
				aPN_AMBR := *,
				esmCause := *,
				protocolConfigOptions := *,
				connectivityType := *,
				wLANOffloadIndication := *,
				nBIFOMContainer := *,
				headerCompressinConfiguration := *,
				controlPlaneOnlyIndication := *,
				extendedProtocolConfigurationOptions := *,
				servingPLMNRateControl := *,
				extended_APN_AMBR := *,
				extendedQoS := *
			}
		}
	}
}

/* 8.3.4 Activate Default EPS Bearer Context Accept */
template (value) PDU_NAS_EPS
ts_NAS_ActDefEpsBearCtxAck(template (value) BIT4 bearer_id,
			   template (value) BIT8 proc_tid,
			   template (omit) ProtocolConfigOptionsV pco) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_ActDefEPSBearerContextAccept := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11000010'B,
				protocolConfigOptions := ts_NAS_PCO_TLV(pco),
				extendedProtocolConfigurationOptions := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_ActDefEpsBearCtxAck(template (present) BIT4 bearer_id := ?,
			   template (present) BIT8 proc_tid := ?,
			   template ProtocolConfigOptionsV pco := *) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_ActDefEPSBearerContextAccept := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11000010'B,
				protocolConfigOptions := tr_NAS_PCO_TLV(pco),
				extendedProtocolConfigurationOptions := *
			}
		}
	}
}


/* 8.3.5 Activate Default EPS Bearer Context Reject */
template (value) PDU_NAS_EPS
ts_NAS_ActDefEpsBearCtxRej(template (value) BIT4 bearer_id,
			   template (value) BIT8 proc_tid,
			   template (value) ESM_CauseV cause) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_ActDefEPSBearerContextReject := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11000011'B,
				esmCause := cause,
				protocolConfigOptions := omit,
				extendedProtocolConfigurationOptions := omit
			}
		}
	}
}
template (present) PDU_NAS_EPS
tr_NAS_ActDefEpsBearCtxRej(template (present) BIT4 bearer_id := ?,
			   template (present) BIT8 proc_tid := ?,
			   template (present) ESM_CauseV cause := ?) := {
	protocolDiscriminator := c_EPS_NAS_PD_ESM,
	ePS_messages := {
		ePS_SessionManagement := {
			pDU_NAS_EPS_ActDefEPSBearerContextReject := {
				ePSBearerIdentity := bearer_id,
				procedureTransactionIdentifier := proc_tid,
				messageType := '11000011'B,
				esmCause := cause,
				protocolConfigOptions := *,
				extendedProtocolConfigurationOptions := *
			}
		}
	}
}

}