dexter has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/33937 )
Change subject: MME_Tests: add testcase TC_RIM_RAN_INF
......................................................................
MME_Tests: add testcase TC_RIM_RAN_INF
The proposed testcase models a full RIM RAN INFORMATION REQUEST that
originates at the eNB (S1AP), is forwarded by the MME towards GERAN
(GTP) and goes back towards the MME (GTP) and is eventually forwarded
by the MME back to the eNB (S1AP).
Related: OS#5760
Related: OS#5759
Change-Id: I22d5aaab64df2824099977fb574afb86a4b7e91f
---
M mme/MME_Tests.ttcn
1 file changed, 290 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/37/33937/1
diff --git a/mme/MME_Tests.ttcn b/mme/MME_Tests.ttcn
index cf6bcfc..c05e58e 100644
--- a/mme/MME_Tests.ttcn
+++ b/mme/MME_Tests.ttcn
@@ -18,6 +18,8 @@
import from S1AP_Emulation all;
import from S1AP_PDU_Descriptions all;
import from S1AP_IEs all;
+import from S1AP_PDU_Contents all;
+import from S1AP_Constants all;
import from NAS_EPS_Types all;
import from NAS_Templates all;
@@ -43,6 +45,9 @@
friend module MME_Tests_SGsAP;
+import from Osmocom_Gb_Types all;
+
+
/* (maximum) number of emulated eNBs */
const integer NUM_ENB := 3;
@@ -84,6 +89,35 @@
var UeParams g_ue_pars[NUM_UE];
}
+/* Encode an S1AP Global-ENB-ID into an octetstring */
+private function enc_S1AP_Global_ENB_ID(Global_ENB_ID global_enb_id) return octetstring
{
+
+ /* Due to the limitations of libfftranscode, we can not define encoders (or decoders)
for individual
+ * information elements (in S1AP_Types.cc). Unfortuantely Global-ENB-ID also appears in
BSSGP in its
+ * encoded form. (see also: GTP-C 3GPP TS 48.018, section 11.3.70). To encode a given
Global-ENB-ID
+ * we craft a full S1AP PDU and encode it. Then we can cut out the encoded Global-ENB-ID
from the
+ * generated octetstring. */
+
+ var SupportedTAs supported_tas_dummy := {{
+ tAC := '0000'O,
+ broadcastPLMNs := { '00f000'O },
+ iE_Extensions := omit
+ }};
+ var octetstring encoded;
+ var integer global_enb_id_len;
+
+ if (ispresent(global_enb_id.eNB_ID.macroENB_ID)) {
+ global_enb_id_len := 8
+ } else {
+ /* All other ENB ID types fit into 8 byte (homeENB_ID, short_macroENB_ID,
long_macroENB_ID) */
+ global_enb_id_len := 9
+ }
+
+ encoded := enc_S1AP_PDU(valueof(ts_S1AP_SetupReq(global_enb_id, supported_tas_dummy,
v32)));
+
+ return substr(encoded, 11, global_enb_id_len);
+}
+
type component ConnHdlr extends S1AP_ConnHdlr, SGsAP_ConnHdlr, DIAMETER_ConnHdlr,
GTP_ConnHdlr {
var ConnHdlrPars g_pars;
timer g_Tguard := 30.0;
@@ -294,6 +328,7 @@
/* S1AP part */
connect(vc_conn:S1AP, vc_S1AP[s1ap_idx]:S1AP_CLIENT);
connect(vc_conn:S1AP_PROC, vc_S1AP[s1ap_idx]:S1AP_PROC);
+
if (isbound(vc_SGsAP)) {
/* SGsAP part */
connect(vc_conn:SGsAP, vc_SGsAP:SGsAP_CLIENT);
@@ -629,13 +664,251 @@
vc_conn.done;
}
+external function enc_PDU_GTPC_RAN_INF_REQ(in PDU_BSSGP_RAN_INFORMATION_REQUEST_GTPC
gtpc_pdu) return octetstring
+with { extension "prototype(convert)"
+ extension "encode(RAW)"
+ }
+
+external function enc_PDU_GTPC_RAN_INF(in PDU_BSSGP_RAN_INFORMATION_GTPC gtpc_pdu) return
octetstring
+with { extension "prototype(convert)"
+ extension "encode(RAW)"
+ }
+
+function f_convert_plmn(OCT3 pLMNidentity) return hexstring {
+ var hexstring pLMNidentity_hex := oct2hex(pLMNidentity);
+ var hexstring pLMNidentity_hex_swapped;
+ pLMNidentity_hex_swapped[0] := pLMNidentity_hex[1];
+ pLMNidentity_hex_swapped[1] := pLMNidentity_hex[0];
+ pLMNidentity_hex_swapped[2] := pLMNidentity_hex[3];
+ pLMNidentity_hex_swapped[3] := pLMNidentity_hex[2];
+ pLMNidentity_hex_swapped[4] := pLMNidentity_hex[5];
+ pLMNidentity_hex_swapped[5] := pLMNidentity_hex[4];
+ return pLMNidentity_hex_swapped;
+}
+
+/* Make a template for a GTPC BSSGP container that contains a RAN INFORMATION REQUEST.
The template can be used to
+ * craft the request for the S1AP/S1-MME interface and also to verfify the contents of
the coresponding request on
+ * the GTPC/Gn interface */
+private function f_TC_RIM_RAN_INF_REQ_req_make_rIMInformation(GTP_CellId geran_gtp_ci,
boolean ts)
+ runs on ConnHdlr return template PDU_BSSGP_RAN_INFORMATION_REQUEST_GTPC {
+ var template RIM_Routing_Address_GTPC gtpc_dst_addr, gtpc_src_addr;
+ var template RAN_Information_Request_RIM_Container_GTPC gtpc_rim_req_cont;
+ var template PDU_BSSGP_RAN_INFORMATION_REQUEST_GTPC gtpc_bssgp_cont;
+ var octetstring gnbid;
+ var GTP_CellId eutran_gtp_ci;
+ eutran_gtp_ci.ra_id.lai.mcc_mnc :=
f_convert_plmn(g_pars.enb_pars[g_pars.mme_idx].global_enb_id.pLMNidentity);
+
+ gnbid := enc_S1AP_Global_ENB_ID(g_pars.enb_pars[g_pars.mme_idx].global_enb_id);
+ gtpc_dst_addr := t_GTPC_RIM_Routing_Address_cid(geran_gtp_ci);
+ gtpc_src_addr := t_GTPC_RIM_Routing_Address_enbid(eutran_gtp_ci,
+ oct2int(g_pars.enb_pars[g_pars.mme_idx].supported_tas[0].tAC),
+ gnbid);
+
+ if (ts) {
+ gtpc_rim_req_cont := ts_GTPC_RAN_Information_Request_RIM_Container(
+ ts_GTPC_RIM_Application_Identity(RIM_APP_ID_NACC),
+ ts_GTPC_RIM_Sequence_Number(1),
+ ts_GTPC_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
+ ts_GTPC_RIM_Protocol_Version_Number(1),
+ tsu_GTPC_RAN_Information_Request_Application_Container_NACC(geran_gtp_ci),
+ omit);
+ gtpc_bssgp_cont := ts_GTPC_RAN_Information_Request(
+ ts_GTPC_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, gtpc_dst_addr),
+ ts_GTPC_RIM_Routing_Information(RIM_ADDR_EUTRAN_NODEB_ID, gtpc_src_addr),
+ gtpc_rim_req_cont);
+
+ } else {
+ gtpc_rim_req_cont := tr_GTPC_RAN_Information_Request_RIM_Container(
+ ts_GTPC_RIM_Application_Identity(RIM_APP_ID_NACC),
+ ts_GTPC_RIM_Sequence_Number(1),
+ ts_GTPC_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
+ ts_GTPC_RIM_Protocol_Version_Number(1),
+ tru_GTPC_RAN_Information_Request_Application_Container_NACC(geran_gtp_ci));
+ gtpc_bssgp_cont := tr_GTPC_RAN_Information_Request(
+ tr_GTPC_RIM_Routing_Information(RIM_ADDR_GERAN_CELL_ID, gtpc_dst_addr),
+ tr_GTPC_RIM_Routing_Information(RIM_ADDR_EUTRAN_NODEB_ID, gtpc_src_addr),
+ gtpc_rim_req_cont);
+ }
+
+ return gtpc_bssgp_cont;
+}
+
+/* Make initial RAN INFORMATION REQUEST message that is sent on the S1AP/S1-MME interface
*/
+private function f_TC_RIM_RAN_INF_REQ_req_make_s1ap_req(GTP_CellId geran_gtp_ci)
+ runs on ConnHdlr return template (value) S1AP_PDU {
+ var template (value) Inter_SystemInformationTransferType inf;
+
+ inf.rIMTransfer.rIMInformation :=
enc_PDU_GTPC_RAN_INF_REQ(valueof(f_TC_RIM_RAN_INF_REQ_req_make_rIMInformation(geran_gtp_ci,
true)));
+ inf.rIMTransfer.rIMRoutingAddress.gERAN_Cell_ID.lAI.pLMNidentity := '00f110'O;
+ inf.rIMTransfer.rIMRoutingAddress.gERAN_Cell_ID.lAI.lAC := 'AAAA'O;
+ inf.rIMTransfer.rIMRoutingAddress.gERAN_Cell_ID.lAI.iE_Extensions := omit;
+ inf.rIMTransfer.rIMRoutingAddress.gERAN_Cell_ID.rAC := 'BB'O;
+ inf.rIMTransfer.rIMRoutingAddress.gERAN_Cell_ID.cI := '04C7'O;
+ inf.rIMTransfer.rIMRoutingAddress.gERAN_Cell_ID.iE_Extensions := omit;
+ inf.rIMTransfer.iE_Extensions := omit;
+
+ return ts_S1AP_eNBDirectInfTrans(inf);
+}
+
+/* Make RAN INFORMATION (response) message that is sent on the GTPC/Gn interface */
+private function f_TC_RIM_RAN_INF_REQ_req_make_gtp_ran_info(template Gtp1cUnitdata
req_gtpc_pdu,
+ GTP_CellId geran_gtp_ci, octetstring geran_si)
+ runs on ConnHdlr return template (value) Gtp1cUnitdata {
+ var template Gtp1cUnitdata res_gtpc_pdu;
+ var template RAN_Information_RIM_Container_GTPC gtpc_rim_res_cont;
+ var template PDU_BSSGP_RAN_INFORMATION_GTPC gtpc_bssgp_rim_res_pdu;
+ var template RIM_Routing_Information_GTPC gtpc_rim_dst_cell_id, gtpc_rim_src_cell_id;
+ var template RIM_RoutingAddress gtpc_rim_ra;
+ var template RIM_RoutingAddress_Discriminator gtpc_rim_ra_discr;
+
+ /* Assemble GTPC RAN Information */
+ gtpc_rim_res_cont :=
ts_GTPC_RAN_Information_RIM_Container(ts_GTPC_RIM_Application_Identity(RIM_APP_ID_NACC),
+ ts_GTPC_RIM_Sequence_Number(2),
+ ts_GTPC_RIM_PDU_Indications(false, RIM_PDU_TYPE_SING_REP),
+ ts_GTPC_RIM_Protocol_Version_Number(1),
+
tsu_GTPC_ApplContainer_or_ApplErrContainer_NACC(tsu_GTPC_ApplContainer_NACC(geran_gtp_ci,
false, 3, geran_si)),
+ omit);
+
+ /* The source becomes the destination and vice versa */
+ gtpc_rim_dst_cell_id :=
req_gtpc_pdu.gtpc.gtpc_pdu.ranInformationRelay.transparentContainer.
+
rANTransparentContainerField.pDU_BSSGP_RAN_INFORMATION_REQUEST.source_Cell_Identifier
+ gtpc_rim_src_cell_id :=
req_gtpc_pdu.gtpc.gtpc_pdu.ranInformationRelay.transparentContainer.
+
rANTransparentContainerField.pDU_BSSGP_RAN_INFORMATION_REQUEST.destination_Cell_Identifier
+ gtpc_bssgp_rim_res_pdu := ts_GTPC_RAN_Information(gtpc_rim_dst_cell_id,
+ gtpc_rim_src_cell_id,
+ gtpc_rim_res_cont);
+
+ /* Assemble RIM Routing Address */
+ gtpc_rim_ra.type_gtpc := '9F'O;
+ gtpc_rim_ra.lengthf := 4;
+ gtpc_rim_ra.rIM_RoutingAddressValue :=
g_pars.enb_pars[g_pars.mme_idx].global_enb_id.pLMNidentity &
+ g_pars.enb_pars[g_pars.mme_idx].supported_tas[0].tAC &
+ enc_S1AP_Global_ENB_ID(g_pars.enb_pars[g_pars.mme_idx].global_enb_id);
+ gtpc_rim_ra_discr.type_gtpc := 'B2'O;
+ gtpc_rim_ra_discr.lengthf := lengthof(gtpc_rim_ra.rIM_RoutingAddressValue);
+ gtpc_rim_ra_discr.rra_discriminator := '0010'B;
+ gtpc_rim_ra_discr.spare := '0000'B;
+
+ res_gtpc_pdu := ts_GTPC_RANInfoRelay(g_gn_iface_peer,
+ ts_RANTransparentContainer_RAN_INFO(gtpc_bssgp_rim_res_pdu),
+ gtpc_rim_ra, gtpc_rim_ra_discr);
+
+ return res_gtpc_pdu;
+}
+
+/* Make template to verify the RAN INFORMATION REQUEST as it appears on the GTPC/Gn
interface */
+private function f_TC_RIM_RAN_INF_req_make_gtpc_req(GTP_CellId geran_gtp_ci)
+ runs on ConnHdlr return template Gtp1cUnitdata {
+ var template Gtp1cUnitdata msg;
+ var template GTPC_PDUs pdus;
+ var template RANTransparentContainer ran_transp_cont;
+
+ ran_transp_cont := tr_RANTransparentContainer_RAN_INFO_REQ(
+ f_TC_RIM_RAN_INF_REQ_req_make_rIMInformation(geran_gtp_ci, false));
+ pdus := tr_RANInfoRelay(ran_transp_cont);
+ msg := tr_GTPC_MsgType(g_gn_iface_peer, rANInformationRelay, '00000000'O,
pdus);
+
+ return msg;
+}
+
+/* Make template to verify the RAN INFORMATION (response) as it appears on the
S1AP/S1-MME interface */
+private function f_TC_RIM_RAN_INF_req_make_s1ap_resp(Gtp1cUnitdata
ran_information_gtpc_pdu)
+ runs on ConnHdlr return template S1AP_PDU {
+ var template S1AP_PDU msg;
+ var template Inter_SystemInformationTransferType inf;
+
+ inf.rIMTransfer.rIMInformation := enc_PDU_GTPC_RAN_INF(
+ ran_information_gtpc_pdu.gtpc.gtpc_pdu.ranInformationRelay.
+ transparentContainer.rANTransparentContainerField.
+ pDU_BSSGP_RAN_INFORMATION);
+ /* TODO: Check back if a rIMRoutingAddress is mandatory in this message. At the moment
the MME
+ * does not add this information element. */
+ inf.rIMTransfer.rIMRoutingAddress := omit;
+ inf.rIMTransfer.iE_Extensions := omit;
+ msg := tr_S1AP_MMEDirectInfTrans(inf);
+
+ return msg;
+}
+
+private function f_TC_RIM_RAN_INF(ConnHdlrPars pars) runs on ConnHdlr {
+ timer T := 5.0;
+ f_init_handler(pars);
+ f_gtp_register_teid('00000000'O);
+ var Gtp1cUnitdata req_gtpc_pdu;
+ var Gtp1cUnitdata resp_gtpc_pdu;
+ var GTP_CellId geran_gtp_ci;
+
+ /* Assemble data of a fictitiously GERAN cell */
+ geran_gtp_ci.ra_id.rac := oct2int('BB'O);
+ geran_gtp_ci.ra_id.lai.mcc_mnc := '262f42'H
+ geran_gtp_ci.ra_id.lai.lac := oct2int('AAAA'O);
+ geran_gtp_ci.cell_id := oct2int('04C7'O);
+ const octetstring geran_si1 := '198fb100000000000000000000000000007900002b'O;
+ const octetstring geran_si3 := '1b753000f110236ec9033c2747407900003c0b2b2b'O;
+ const octetstring geran_si13 := '009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b'O;
+ const octetstring geran_si := geran_si1 & geran_si3 & geran_si13;
+
+ /* Send initial RAN information request via S1AP to MME and expect the MME to forward
the request on GTP-C
+ * (eNB -> MME -> SGSN) */
+ S1AP.send(f_TC_RIM_RAN_INF_REQ_req_make_s1ap_req(geran_gtp_ci));
+ T.start;
+ alt {
+ [] GTP.receive(f_TC_RIM_RAN_INF_req_make_gtpc_req(geran_gtp_ci)) -> value
req_gtpc_pdu {
+ setverdict(pass);
+ }
+ [] GTP.receive {
+ setverdict(fail, "unexpected GTPC message from MME");
+ }
+ [] T.timeout {
+ setverdict(fail, "no GTPC RAN INFORMATION REQUEST from MME");
+ }
+ }
+
+ /* Send RAN information response via GTP-C to MME and expect the MME to forward the
respnse on S1AP
+ * (SGSN -> MME -> eNB) */
+ f_create_s1ap_expect_proc(id_MMEDirectInformationTransfer, self);
+ resp_gtpc_pdu := valueof(f_TC_RIM_RAN_INF_REQ_req_make_gtp_ran_info(req_gtpc_pdu,
geran_gtp_ci, geran_si));
+ GTP.send(resp_gtpc_pdu);
+ T.start;
+ alt {
+ [] S1AP.receive(f_TC_RIM_RAN_INF_req_make_s1ap_resp(resp_gtpc_pdu)) {
+ setverdict(pass);
+ }
+ [] S1AP.receive {
+ setverdict(fail, "unexpected S1AP message from MME");
+ }
+ [] T.timeout {
+ setverdict(fail, "no S1AP RAN INFORMATION from MME");
+ }
+ }
+
+ setverdict(pass);
+}
+
+testcase TC_RIM_RAN_INF() runs on MTC_CT {
+ var charstring id := testcasename();
+
+ f_init_diameter(id);
+ f_init_s1ap(id, 4);
+ f_s1ap_setup(0);
+ f_init_gtp(id);
+
+ timer T := 3.0;
+
+ var ConnHdlrPars pars := f_init_pars(ue_idx := 0);
+ var ConnHdlr vc_conn;
+ vc_conn := f_start_handler_with_pars(refers(f_TC_RIM_RAN_INF), pars);
+
+ vc_conn.done;
+}
+
control {
execute( TC_s1ap_setup_wrong_plmn() );
execute( TC_s1ap_setup_wrong_tac() );
execute( TC_s1ap_setup() );
execute( TC_s1ap_attach() );
execute( TC_gn_echo_request() );
+ execute( TC_RIM_RAN_INF() );
}
-
}
--
To view, visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/33937
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I22d5aaab64df2824099977fb574afb86a4b7e91f
Gerrit-Change-Number: 33937
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange