laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/33898 )
Change subject: S1AP_Emulation: improve accessibility of unit-data ......................................................................
S1AP_Emulation: improve accessibility of unit-data
When S1AP unit-data is passed around, there is always the problem that it is routed to the MTC_CT. The reason for this is that S1AP_Emulation cannot determine a specific receiver component because unit-data does not contain any addressing fields that would identifiy a specific eNB or UE.
Unfortunately it can be a huge problem when developing test fixtures that use unit-data from inside a ConnHdlr component. It is no problem to send unit-data using S1AP.send(), but it is impossible to receive unit-data through the same path.
The solution that is proposed in this patch uses a mechanism that allows to create an expectation for a specific procedureCode. When the S1AP_Emulation sees a messages with the expected procedureCode, it will forward it to the ConnHdlr component.
Related: OS#5760 Change-Id: I041b45b247e365b0d4ee8645c07dc5f26007af82 --- M library/S1AP_Emulation.ttcn 1 file changed, 110 insertions(+), 1 deletion(-)
Approvals: laforge: Looks good to me, approved pespin: Looks good to me, but someone else must approve Jenkins Builder: Verified
diff --git a/library/S1AP_Emulation.ttcn b/library/S1AP_Emulation.ttcn index 38c738b..bb3a2a4 100644 --- a/library/S1AP_Emulation.ttcn +++ b/library/S1AP_Emulation.ttcn @@ -15,7 +15,9 @@ * * 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. + * 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 @@ -107,6 +109,8 @@ var AssociationData S1apAssociationTable[16]; /* 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 */ @@ -367,6 +371,32 @@ } }
+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; @@ -397,6 +427,7 @@ var PDU_NAS_EPS nas; 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; @@ -448,6 +479,7 @@ [] 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))); @@ -491,6 +523,10 @@ 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; + } }
} @@ -504,10 +540,19 @@ S1AP_ConnHdlr vc_conn }
+/* 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);
type port S1APEM_PROC_PT procedure { inout S1APEM_register; + inout S1APEM_register_proc; } with { extension "internal" };
/* Function that can be used as create_cb and will use the expect table */ @@ -573,6 +618,39 @@ } }
+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); +}
private function f_expect_table_init() runs on S1AP_Emulation_CT { @@ -582,6 +660,11 @@ 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; + } }
function DummyUnitdataCallback(S1AP_PDU msg)