aboutsummaryrefslogtreecommitdiffstats
path: root/library/S1AP_Emulation.ttcn
diff options
context:
space:
mode:
Diffstat (limited to 'library/S1AP_Emulation.ttcn')
-rw-r--r--library/S1AP_Emulation.ttcn309
1 files changed, 241 insertions, 68 deletions
diff --git a/library/S1AP_Emulation.ttcn b/library/S1AP_Emulation.ttcn
index d09b4996..3cce0912 100644
--- a/library/S1AP_Emulation.ttcn
+++ b/library/S1AP_Emulation.ttcn
@@ -1,22 +1,27 @@
module S1AP_Emulation {
-/* S1AP Emulation, runs on top of S1AP_CodecPort. It multiplexes/demultiplexes
- * the individual IMSIs/subscribers, so there can be separate TTCN-3 components handling
- * each of them.
+/* S1AP Emulation, runs on top of S1AP_CodecPort. It multiplexes/demultiplexes
+ * the individual subscribers by their UE association (MME_UE_S1AP_ID/
+ * ENB_UE_S1AP_ID identifiers), so there can be separate TTCN-3 components
+ * handling each of them.
*
* The S1AP_Emulation.main() function processes S1AP primitives from the S1AP
- * socket via the S1AP_CodecPort, and dispatches them to the per-IMSI components.
+ * socket via the S1AP_CodecPort, and dispatches them to the per-subscriber
+ * components.
*
- * For each new IMSI, the S1apOps.create_cb() is called. It can create
- * or resolve a TTCN-3 component, and returns a component reference to which that IMSI
- * is routed/dispatched.
+ * For each new subscruber, the S1apOps.create_cb() is called. It can create
+ * or resolve a TTCN-3 component, and returns a component reference to which
+ * that subscriber traffic is routed/dispatched.
*
- * If a pre-existing component wants to register to handle a future inbound IMSI, it can
- * do so by registering an "expect" with the expected IMSI.
+ * If a pre-existing component wants to register to handle a future inbound UE
+ * association, it can do so by registering an "expect" with the expected
+ * MME_UE_S1AP_ID/ENB_UE_S1AP_ID identifiers. It is also possible to register
+ * an expect for a specific procedureCode, in case the expected message is non
+ * UE related (unit-data).
*
- * Inbound non-UE related S1AP messages (such as RESET, SETUP, OVERLOAD) are dispatched to
- * the S1apOps.unitdata_cb() callback, which is registered with an argument to the
- * main() function below.
+ * Inbound non-UE related S1AP messages (such as RESET, SETUP, OVERLOAD) are
+ * dispatched to the S1apOps.unitdata_cb() callback, which is registered with
+ * an argument to the main() function below.
*
* (C) 2019 by Harald Welte <laforge@gnumonks.org>
* All rights reserved.
@@ -35,6 +40,7 @@ import from S1AP_PDU_Contents all;
import from S1AP_PDU_Descriptions all;
import from S1AP_IEs all;
import from S1AP_Templates all;
+import from SCTP_Templates all;
import from NAS_EPS_Types all;
import from NAS_Templates all;
@@ -62,8 +68,13 @@ type record NAS_Keys {
octetstring k_nas_int,
octetstring k_nas_enc
};
+type record ResetNAScounts {
+/* empty */
+};
type union S1APEM_Config {
- NAS_Keys set_nas_keys
+ NAS_Keys set_nas_keys,
+ ResetNAScounts reset_nas_counts,
+ NAS_ALG_INT set_nas_alg_int
};
type enumerated S1APEM_EventUpDown {
@@ -91,8 +102,6 @@ type record AssociationData {
EUTRAN_CGI cgi optional,
TAI tai optional,
NAS_UE_State nus
-
- //hexstring imsi optional
};
type component S1AP_Emulation_CT {
@@ -104,8 +113,10 @@ type component S1AP_Emulation_CT {
port S1AP_Conn_PT S1AP_CLIENT;
/* currently tracked connections */
var AssociationData S1apAssociationTable[16];
- /* pending expected CRCX */
+ /* pending expected S1AP Association (UE oriented) */
var ExpectData S1apExpectTable[8];
+ /* pending expected S1AP PDU */
+ var ExpectDataProc S1apExpectTableProc[8];
/* procedure based port to register for incoming connections */
port S1APEM_PROC_PT S1AP_PROC;
/* test port for unit data messages */
@@ -196,7 +207,8 @@ private function f_assoc_id_by_s1ap_ids(template (omit) MME_UE_S1AP_ID mme_id,
runs on S1AP_Emulation_CT return integer {
var integer i;
for (i := 0; i < sizeof(S1apAssociationTable); i := i+1) {
- if (match(S1apAssociationTable[i].enb_ue_s1ap_id, enb_id)) {
+ if (istemplatekind(enb_id, "omit") or
+ match(S1apAssociationTable[i].enb_ue_s1ap_id, enb_id)) {
if (istemplatekind(mme_id, "omit")) {
return i;
} else {
@@ -253,7 +265,7 @@ runs on S1AP_Emulation_CT {
var integer i;
for (i := 0; i < sizeof(S1apAssociationTable); i := i+1) {
if (S1apAssociationTable[i].comp_ref == comp_ref and
- S1apAssociationTable[i].mme_ue_s1ap_id == enb_id) {
+ S1apAssociationTable[i].enb_ue_s1ap_id == enb_id) {
S1apAssociationTable[i].enb_ue_s1ap_id := omit;
S1apAssociationTable[i].mme_ue_s1ap_id := omit;
S1apAssociationTable[i].comp_ref := null;
@@ -273,24 +285,7 @@ runs on S1AP_Emulation_CT {
S1apAssociationTable[i].cgi := omit;
S1apAssociationTable[i].tai := omit;
S1apAssociationTable[i].nus := valueof(t_NAS_UE_State(g_pars.role));
- }
-}
-
-private template (value) SctpTuple ts_SCTP(template (omit) integer ppid := 18) := {
- sinfo_stream := omit,
- sinfo_ppid := ppid,
- remSocks := omit,
- assocId := omit
-};
-
-private template PortEvent tr_SctpAssocChange := {
- sctpEvent := {
- sctpAssocChange := ?
- }
-}
-private template PortEvent tr_SctpPeerAddrChange := {
- sctpEvent := {
- sctpPeerAddrChange := ?
+ S1apAssociationTable[i].comp_ref := null;
}
}
@@ -342,6 +337,55 @@ private function f_nas_try_decaps(PDU_NAS_EPS nas) return PDU_NAS_EPS
}
*/
+function handle_S1AP_UeContextReleaseCmd(template (present) S1AP_PDU rel_cmd) runs on S1AP_Emulation_CT {
+ if (ispresent(rel_cmd.initiatingMessage.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.uE_S1AP_ID_pair)) {
+ var template MME_UE_S1AP_ID mme_ue_id;
+ var template ENB_UE_S1AP_ID enb_ue_id;
+ var integer assoc_id;
+ var S1AP_ConnHdlr vc_conn
+
+ mme_ue_id := rel_cmd.initiatingMessage.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.uE_S1AP_ID_pair.mME_UE_S1AP_ID;
+ enb_ue_id := rel_cmd.initiatingMessage.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.uE_S1AP_ID_pair.eNB_UE_S1AP_ID;
+
+ assoc_id := f_assoc_id_by_s1ap_ids(mme_ue_id, enb_ue_id);
+ vc_conn := S1apAssociationTable[assoc_id].comp_ref;
+
+ f_s1ap_id_table_del(vc_conn, valueof(enb_ue_id));
+ } else {
+ /* TODO: The UE CONTEXT RELEASE COMMAND (see also: 3GPP TS 36.413, section 9.1.4.6), may identify the
+ * context by either an uE_S1AP_ID_pair (MME_UE_S1AP_ID and ENB_UE_S1AP_ID) or an MME_UE_S1AP_ID alone.
+ * The latter case is not implemented here yet. */
+ setverdict(fail, "complete implementation of UeContextReleaseCmd handling");
+ mtc.stop;
+ }
+}
+
+private function SendToS1apExpectTableProc(S1AP_PDU msg) runs on S1AP_Emulation_CT {
+ var integer procedureCode;
+ var S1AP_ConnHdlr vc_conn;
+
+ if (ispresent(msg.initiatingMessage.procedureCode)) {
+ procedureCode := msg.initiatingMessage.procedureCode;
+ } else if (ispresent(msg.unsuccessfulOutcome.procedureCode)) {
+ procedureCode := msg.unsuccessfulOutcome.procedureCode;
+ } else if (ispresent(msg.successfulOutcome.procedureCode)) {
+ procedureCode := msg.successfulOutcome.procedureCode;
+ } else {
+ return;
+ }
+
+ for (var integer i := 0; i < sizeof(S1apExpectTableProc); i := i+1) {
+ if (S1apExpectTableProc[i].procedureCode == procedureCode) {
+ vc_conn := S1apExpectTableProc[i].vc_conn;
+ if (vc_conn != null) {
+ S1AP_CLIENT.send(msg) to vc_conn;
+ }
+ }
+ }
+
+ return;
+}
+
function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_Emulation_CT {
var Result res;
g_pars := p;
@@ -351,10 +395,12 @@ function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_E
map(self:S1AP, system:S1AP_CODEC_PT);
if (p.remote_sctp_port == -1) {
- res := S1AP_CodecPort_CtrlFunct.f_IPL4_listen(S1AP, p.local_ip, p.local_sctp_port, { sctp := valueof(ts_SCTP) });
+ res := S1AP_CodecPort_CtrlFunct.f_IPL4_listen(S1AP, p.local_ip, p.local_sctp_port,
+ { sctp := valueof(ts_SctpTuple(18)) });
} else {
res := S1AP_CodecPort_CtrlFunct.f_IPL4_connect(S1AP, p.remote_ip, p.remote_sctp_port,
- p.local_ip, p.local_sctp_port, -1, { sctp := valueof(ts_SCTP) });
+ p.local_ip, p.local_sctp_port, -1,
+ { sctp := valueof(ts_SctpTuple(18)) });
}
if (not ispresent(res.connId)) {
setverdict(fail, "Could not connect S1AP socket, check your configuration");
@@ -370,12 +416,15 @@ function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_E
while (true) {
var S1AP_ConnHdlr vc_conn;
var PDU_NAS_EPS nas;
- var hexstring imsi;
+ var MME_UE_S1AP_ID mme_id;
+ var ENB_UE_S1AP_ID enb_id;
+ var integer procedureCode;
var S1AP_RecvFrom mrf;
var S1AP_PDU msg;
var S1APEM_Config s1cfg;
var charstring vlr_name, mme_name;
var integer ai;
+ var octetstring kasme;
alt {
/* Configuration primitive from client */
@@ -384,6 +433,17 @@ function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_E
S1apAssociationTable[assoc_id].nus.k_nas_int := s1cfg.set_nas_keys.k_nas_int;
S1apAssociationTable[assoc_id].nus.k_nas_enc := s1cfg.set_nas_keys.k_nas_enc;
}
+ /* Configuration primitive from client */
+ [] S1AP_CLIENT.receive(S1APEM_Config:{reset_nas_counts:=?}) -> value s1cfg sender vc_conn {
+ var integer assoc_id := f_assoc_id_by_comp(vc_conn);
+ S1apAssociationTable[assoc_id].nus.rx_count := 0;
+ S1apAssociationTable[assoc_id].nus.tx_count := 0;
+ }
+ /* Configuration primitive from client */
+ [] S1AP_CLIENT.receive(S1APEM_Config:{set_nas_alg_int:=?}) -> value s1cfg sender vc_conn {
+ var integer assoc_id := f_assoc_id_by_comp(vc_conn);
+ S1apAssociationTable[assoc_id].nus.alg_int := s1cfg.set_nas_alg_int;
+ }
/* S1AP from client: InitialUE */
[] S1AP_CLIENT.receive(tr_S1AP_InitialUE) -> value msg sender vc_conn {
/* create a table entry about this connection */
@@ -422,14 +482,11 @@ function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_E
[] S1AP.receive(tr_S1AP_RecvFrom_R(?)) -> value mrf {
if (match(mrf.msg, tr_S1AP_nonUErelated)) {
/* non-UE-related S1AP message */
+ SendToS1apExpectTableProc(mrf.msg);
var template S1AP_PDU resp := ops.unitdata_cb.apply(mrf.msg);
if (isvalue(resp)) {
S1AP.send(t_S1AP_Send(g_s1ap_conn_id, valueof(resp)));
}
- } else if (match(mrf.msg, tr_S1AP_UeContextReleaseCmd)) {
- /* TODO: special handling, as it contains multiple eNB or MME IDs */
- setverdict(fail, "implement UeContextReleaseCmd handling");
- mtc.stop;
} else {
/* Ue-related S1AP message */
/* obtain MME + ENB UE S1AP ID */
@@ -439,7 +496,7 @@ function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_E
if (f_s1ap_ids_known(mme_ue_id, enb_ue_id)) {
/* if yes, dispatch to the ConnHdlr for this Ue-Connection */
var template (omit) octetstring nas_enc;
- var integer assoc_id := f_assoc_id_by_s1ap_ids(mme_ue_id, enb_ue_id);
+ var integer assoc_id := f_assoc_id_by_s1ap_ids(mme_ue_id, enb_ue_id);
vc_conn := S1apAssociationTable[assoc_id].comp_ref;
nas_enc := f_S1AP_get_NAS_PDU(mrf.msg);
if (isvalue(nas_enc)) {
@@ -447,6 +504,11 @@ function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_E
if (match(nas, tr_NAS_EMM_SecurityProtected)) {
nas := f_nas_try_decaps(S1apAssociationTable[assoc_id].nus, nas);
}
+ /* DL/UlNasTransport are not interesting, don't send them */
+ if (not match(mrf.msg, (tr_S1AP_DlNasTransport, tr_S1AP_UlNasTransport))) {
+ /* send raw S1AP */
+ S1AP_CLIENT.send(mrf.msg) to vc_conn;
+ }
/* send decoded NAS */
S1AP_CLIENT.send(nas) to vc_conn;
} else {
@@ -459,46 +521,74 @@ function main(S1APOps ops, S1AP_conn_parameters p, charstring id) runs on S1AP_E
f_s1ap_id_table_add(vc_conn, mme_ue_id, valueof(enb_ue_id));
S1AP_CLIENT.send(mrf.msg) to vc_conn;
}
+ if (match(mrf.msg, tr_S1AP_UeContextReleaseCmd)) {
+ handle_S1AP_UeContextReleaseCmd(mrf.msg);
+ }
}
}
[] S1AP.receive(tr_SctpAssocChange) { }
[] S1AP.receive(tr_SctpPeerAddrChange) { }
- [] S1AP_PROC.getcall(S1APEM_register:{?,?}) -> param(imsi, vc_conn) {
- f_create_expect(imsi, vc_conn);
- S1AP_PROC.reply(S1APEM_register:{imsi, vc_conn}) to vc_conn;
+ [] S1AP_PROC.getcall(S1APEM_register:{?,?,?}) -> param(mme_id, enb_id, vc_conn) {
+ f_create_expect(mme_id, enb_id, vc_conn);
+ S1AP_PROC.reply(S1APEM_register:{mme_id, enb_id, vc_conn}) to vc_conn;
+ }
+ [] S1AP_PROC.getcall(S1APEM_register_proc:{?,?}) -> param(procedureCode, vc_conn) {
+ f_create_expect_proc(procedureCode, vc_conn);
+ S1AP_PROC.reply(S1APEM_register_proc:{procedureCode, vc_conn}) to vc_conn;
+ }
+ [] S1AP_PROC.getcall(S1APEM_derive_nas_token:{?, ?, -}) -> param(kasme, vc_conn) {
+ var integer assoc_id := f_assoc_id_by_comp(vc_conn);
+ var OCT32 nas_token := f_kdf_nas_token(kasme, S1apAssociationTable[assoc_id].nus.tx_count)
+ S1apAssociationTable[assoc_id].nus.tx_count := S1apAssociationTable[assoc_id].nus.tx_count + 1;
+ S1AP_PROC.reply(S1APEM_derive_nas_token:{kasme, vc_conn, nas_token}) to vc_conn;
}
}
-
}
}
/* "Expect" Handling */
type record ExpectData {
- hexstring imsi optional,
+ MME_UE_S1AP_ID mme_id optional,
+ ENB_UE_S1AP_ID enb_id optional,
S1AP_ConnHdlr vc_conn
}
-signature S1APEM_register(in hexstring imsi, in S1AP_ConnHdlr hdlr);
+/* represents a single S1AP PDU that we expect. When a matching PDU is seen, it is forwarded to the registered
+ * component */
+type record ExpectDataProc {
+ integer procedureCode optional,
+ S1AP_ConnHdlr vc_conn /* component handling this UE connection */
+};
+
+signature S1APEM_register(in MME_UE_S1AP_ID mme_id, in ENB_UE_S1AP_ID enb_id, in S1AP_ConnHdlr hdlr);
+signature S1APEM_register_proc(in integer procedureCode, in S1AP_ConnHdlr hdlr);
+signature S1APEM_derive_nas_token(in octetstring kasme, in S1AP_ConnHdlr hdlr, out OCT32 nas_token);
type port S1APEM_PROC_PT procedure {
inout S1APEM_register;
+ inout S1APEM_register_proc;
+ inout S1APEM_derive_nas_token;
} with { extension "internal" };
-/* Function that can be used as create_cb and will usse the expect table */
-function ExpectedCreateCallback(S1AP_PDU msg, hexstring imsi, charstring id)
+/* Function that can be used as create_cb and will use the expect table */
+function ExpectedCreateCallback(S1AP_PDU msg,
+ template (omit) MME_UE_S1AP_ID mme_id,
+ template (omit) ENB_UE_S1AP_ID enb_id, charstring id)
runs on S1AP_Emulation_CT return S1AP_ConnHdlr {
var S1AP_ConnHdlr ret := null;
var integer i;
for (i := 0; i < sizeof(S1apExpectTable); i := i+1) {
- if (not ispresent(S1apExpectTable[i].imsi)) {
+ if (not ispresent(S1apExpectTable[i].mme_id) and not ispresent(S1apExpectTable[i].enb_id)) {
continue;
}
- if (imsi == S1apExpectTable[i].imsi) {
+
+ if (valueof(mme_id) == S1apExpectTable[i].mme_id and valueof(enb_id) == S1apExpectTable[i].enb_id) {
ret := S1apExpectTable[i].vc_conn;
/* Release this entry */
- S1apExpectTable[i].imsi := omit;
+ S1apExpectTable[i].mme_id := omit;
+ S1apExpectTable[i].enb_id := omit;
S1apExpectTable[i].vc_conn := null;
log("Found Expect[", i, "] for ", msg, " handled at ", ret);
return ret;
@@ -508,22 +598,28 @@ runs on S1AP_Emulation_CT return S1AP_ConnHdlr {
mtc.stop;
}
-private function f_create_expect(hexstring imsi, S1AP_ConnHdlr hdlr)
+private function f_create_expect(template (omit) MME_UE_S1AP_ID mme_id,
+ template (omit) ENB_UE_S1AP_ID enb_id,
+ S1AP_ConnHdlr hdlr)
runs on S1AP_Emulation_CT {
var integer i;
/* Check an entry like this is not already presnt */
for (i := 0; i < sizeof(S1apExpectTable); i := i+1) {
- if (imsi == S1apExpectTable[i].imsi) {
- setverdict(fail, "IMSI already present", imsi);
+ if (not ispresent(S1apExpectTable[i].mme_id) and not ispresent(S1apExpectTable[i].enb_id)) {
+ continue;
+ }
+ if (valueof(mme_id) == S1apExpectTable[i].mme_id and valueof(enb_id) == S1apExpectTable[i].enb_id) {
+ setverdict(fail, "UE MME id / UE ENB id pair already present", mme_id, enb_id);
mtc.stop;
}
}
for (i := 0; i < sizeof(S1apExpectTable); i := i+1) {
- if (not ispresent(S1apExpectTable[i].imsi)) {
- S1apExpectTable[i].imsi := imsi;
+ if (not ispresent(S1apExpectTable[i].mme_id) and not ispresent(S1apExpectTable[i].enb_id)) {
+ S1apExpectTable[i].mme_id := valueof(mme_id);
+ S1apExpectTable[i].enb_id := valueof(enb_id);
S1apExpectTable[i].vc_conn := hdlr;
- log("Created Expect[", i, "] for ", imsi, " to be handled at ", hdlr);
+ log("Created Expect[", i, "] for UE MME id:", mme_id, ", UE ENB id:", enb_id, " to be handled at ", hdlr);
return;
}
}
@@ -531,18 +627,70 @@ runs on S1AP_Emulation_CT {
}
/* client/conn_hdlr side function to use procedure port to create expect in emulation */
-function f_create_s1ap_expect(hexstring imsi) runs on S1AP_ConnHdlr {
- S1AP_PROC.call(S1APEM_register:{imsi, self}) {
- [] S1AP_PROC.getreply(S1APEM_register:{?,?}) {};
+function f_create_s1ap_expect(template (omit) MME_UE_S1AP_ID mme_id,
+ template (omit) ENB_UE_S1AP_ID enb_id) runs on S1AP_ConnHdlr {
+ S1AP_PROC.call(S1APEM_register:{mme_id, enb_id, self}) {
+ [] S1AP_PROC.getreply(S1APEM_register:{?,?,?}) {};
+ }
+}
+
+private function f_create_expect_proc(integer procedureCode, S1AP_ConnHdlr hdlr) runs on S1AP_Emulation_CT {
+ var integer i;
+
+ /* Check an entry like this is not already presnt */
+ for (i := 0; i < sizeof(S1apExpectTableProc); i := i+1) {
+ if (S1apExpectTableProc[i].vc_conn == null) {
+ continue;
+ }
+ if (S1apExpectTableProc[i].procedureCode == procedureCode) {
+ setverdict(fail, "procedureCode ", procedureCode, " already present");
+ mtc.stop;
+ }
+ }
+ for (i := 0; i < sizeof(S1apExpectTableProc); i := i+1) {
+ if (S1apExpectTableProc[i].vc_conn == null) {
+ S1apExpectTableProc[i].procedureCode := procedureCode;
+ S1apExpectTableProc[i].vc_conn := hdlr;
+ log("Created Expect[", i, "] for PDU:", procedureCode, " to be handled at ", hdlr);
+ return;
+ }
+ }
+ testcase.stop("No space left in S1apExpectTableProc")
+}
+
+/* client/conn_hdlr side function to use procedure port to create expect (PDU) in emulation */
+function f_create_s1ap_expect_proc(integer procedureCode, S1AP_ConnHdlr hdlr) runs on S1AP_ConnHdlr
+{
+ S1AP_PROC.call(S1APEM_register_proc:{procedureCode, self}) {
+ [] S1AP_PROC.getreply(S1APEM_register_proc:{?,?}) {};
}
+
+ log(procedureCode);
}
+/* Derive NAS Token (and post-increment ul_count): */
+function f_s1apem_derive_nas_token(in octetstring kasme) runs on S1AP_ConnHdlr return OCT32
+{
+ var OCT32 nas_token;
+ S1AP_PROC.call(S1APEM_derive_nas_token:{kasme, self, -}) {
+ [] S1AP_PROC.getreply(S1APEM_derive_nas_token:{kasme, self, ?}) -> param(nas_token) {
+ return nas_token;
+ };
+ }
+}
private function f_expect_table_init()
runs on S1AP_Emulation_CT {
var integer i;
for (i := 0; i < sizeof(S1apExpectTable); i := i + 1) {
- S1apExpectTable[i].imsi := omit;
+ S1apExpectTable[i].mme_id := omit;
+ S1apExpectTable[i].enb_id := omit;
+ S1apExpectTable[i].vc_conn := null;
+ }
+
+ for (i := 0; i < sizeof(S1apExpectTableProc); i := i + 1) {
+ S1apExpectTableProc[i].procedureCode := omit;
+ S1apExpectTableProc[i].vc_conn := null;
}
}
@@ -573,7 +721,13 @@ function f_S1AP_get_ENB_UE_S1AP_ID(S1AP_PDU s1ap) return template (omit) ENB_UE_
case (tr_S1AP_UeContextReleaseReq) {
return im.value_.UEContextReleaseRequest.protocolIEs[1].value_.ENB_UE_S1AP_ID;
}
- /* UeContextReleaseCmd needs special handling; it can contain any number of MME/UE IDs */
+ case (tr_S1AP_UeContextReleaseCmd) {
+ if (ispresent(im.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.uE_S1AP_ID_pair)) {
+ return im.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.uE_S1AP_ID_pair.eNB_UE_S1AP_ID;
+ } else {
+ return omit;
+ }
+ }
case (tr_S1AP_ConnEstInd) {
return im.value_.ConnectionEstablishmentIndication.protocolIEs[1].value_.ENB_UE_S1AP_ID;
}
@@ -619,7 +773,13 @@ function f_S1AP_get_MME_UE_S1AP_ID(S1AP_PDU s1ap) return template (omit) MME_UE_
case (tr_S1AP_UeContextReleaseReq) {
return im.value_.UEContextReleaseRequest.protocolIEs[0].value_.MME_UE_S1AP_ID;
}
- /* UeContextReleaseCmd needs special handling; it can contain any number of MME/UE IDs */
+ case (tr_S1AP_UeContextReleaseCmd) {
+ if (ispresent(im.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.uE_S1AP_ID_pair)) {
+ return im.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.uE_S1AP_ID_pair.mME_UE_S1AP_ID;
+ } else {
+ return im.value_.uEContextReleaseCommand.protocolIEs[0].value_.uE_S1AP_IDs.mME_UE_S1AP_ID;
+ }
+ }
case (tr_S1AP_ConnEstInd) {
return im.value_.ConnectionEstablishmentIndication.protocolIEs[0].value_.MME_UE_S1AP_ID;
}
@@ -650,7 +810,7 @@ function f_S1AP_get_MME_UE_S1AP_ID(S1AP_PDU s1ap) return template (omit) MME_UE_
function f_S1AP_get_NAS_PDU(S1AP_PDU s1ap) return template (omit) NAS_PDU
{
- var integer i;
+ var integer i, j;
if (ischosen(s1ap.initiatingMessage)) {
var InitiatingMessage im := s1ap.initiatingMessage;
@@ -671,6 +831,19 @@ function f_S1AP_get_NAS_PDU(S1AP_PDU s1ap) return template (omit) NAS_PDU
}
}
}
+ case (tr_S1AP_IntialCtxSetupReq) {
+ var InitialContextSetupRequest msg := im.value_.initialContextSetupRequest;
+ for (i := 0; i < lengthof(msg.protocolIEs); i := i+1) {
+ if (msg.protocolIEs[i].id == id_E_RABToBeSetupListCtxtSUReq) {
+ var E_RABToBeSetupListCtxtSUReq rab_req := msg.protocolIEs[i].value_.E_RABToBeSetupListCtxtSUReq;
+ for (j := 0; j < lengthof(rab_req); j := j+1) {
+ var E_RABToBeSetupItemCtxtSUReq it := rab_req[j].value_.E_RABToBeSetupItemCtxtSUReq;
+ return it.nAS_PDU;
+ }
+ }
+ }
+ return omit;
+ }
}
}
return omit;