diff options
Diffstat (limited to 'library/S1AP_Emulation.ttcn')
-rw-r--r-- | library/S1AP_Emulation.ttcn | 309 |
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; |