This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Harald Welte gerrit-no-reply at lists.osmocom.orgHarald Welte has submitted this change and it was merged. Change subject: Add new GSUP Emulation module, dispatching GSUP based on IMSI ...................................................................... Add new GSUP Emulation module, dispatching GSUP based on IMSI Change-Id: I6d06280fa5729ee921d319854a9b11636cf83495 --- A library/GSUP_Emulation.ttcn 1 file changed, 291 insertions(+), 0 deletions(-) Approvals: Harald Welte: Looks good to me, approved Jenkins Builder: Verified diff --git a/library/GSUP_Emulation.ttcn b/library/GSUP_Emulation.ttcn new file mode 100644 index 0000000..e1a515c --- /dev/null +++ b/library/GSUP_Emulation.ttcn @@ -0,0 +1,291 @@ +module GSUP_Emulation { + +/* GSUP Emulation, runs on top of IPA_Emulation. It multiplexes/demultiplexes + * the individual calls, so there can be separate TTCN-3 components handling + * each of the calls + * + * The GSUP_Emulation.main() function processes GSUP primitives from the IPA/GSUP + * socket via the IPA_Emulation, and dispatches them to the per-connection components. + * + * Outbound GSUP connections are initiated by sending a FIXME primitive + * to the component running the GSUP_Emulation.main() function. + * + * For each new inbound connections, the GsupOps.create_cb() is called. It can create + * or resolve a TTCN-3 component, and returns a component reference to which that inbound + * connection is routed/dispatched. + * + * If a pre-existing component wants to register to handle a future inbound call, it can + * do so by registering an "expect" with the expected destination phone number. This is e.g. useful + * if you are simulating BSC + HUL, and first trigger a connection from BSC side in a + * component which then subsequently should also handle the GSUP emulation. + * + * (C) 2018 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + */ + + +import from Osmocom_Types all; +import from GSUP_Types all; +import from IPA_Emulation all; + +/* General "base class" component definition, of which specific implementations + * derive themselves by means of the "extends" feature */ +type component GSUP_ConnHdlr { + /* ports towards GSUP Emulator core / call dispatchar */ + port GSUP_Conn_PT GSUP; + port GSUPEM_PROC_PT GSUP_PROC; +} + +/* port between individual per-connection components and this dispatcher */ +type port GSUP_Conn_PT message { + inout GSUP_PDU; +} with { extension "internal" }; + + +/* represents a single GSUP call */ +type record ConnectionData { + /* reference to the instance of the per-connection component */ + GSUP_ConnHdlr comp_ref, + charstring imsi +} + +type component GSUP_Emulation_CT { + /* UNIX DOMAIN socket on the bottom side, using primitives */ + port IPA_GSUP_PT GSUP; + /* GSUP port to the per-connection clients */ + port GSUP_Conn_PT GSUP_CLIENT; + + /* use 16 as this is also the number of SCCP connections that SCCP_Emulation can handle */ + var ConnectionData GsupImsiTable[16]; + + /* pending expected incoming connections */ + var ExpectData GsupExpectTable[8]; + /* procedure based port to register for incoming connections */ + port GSUPEM_PROC_PT GSUP_PROC; +}; + +private function f_imsi_known(charstring imsi) +runs on GSUP_Emulation_CT return boolean { + var integer i; + for (i := 0; i < sizeof(GsupImsiTable); i := i+1) { + if (GsupImsiTable[i].imsi == imsi) { + return true; + } + } + return false; +} + +private function f_comp_known(GSUP_ConnHdlr client) +runs on GSUP_Emulation_CT return boolean { + var integer i; + for (i := 0; i < sizeof(GsupImsiTable); i := i+1) { + if (GsupImsiTable[i].comp_ref == client) { + return true; + } + } + return false; +} + +/* resolve component reference by connection ID */ +private function f_comp_by_imsi(charstring imsi) +runs on GSUP_Emulation_CT return GSUP_ConnHdlr { + var integer i; + for (i := 0; i < sizeof(GsupImsiTable); i := i+1) { + if (GsupImsiTable[i].imsi == imsi) { + return GsupImsiTable[i].comp_ref; + } + } + log("GSUP IMSI table not found by IMSI ", imsi); + setverdict(fail); + self.stop; +} + +/* resolve connection ID by component reference */ +private function f_imsi_by_comp(GSUP_ConnHdlr client) +runs on GSUP_Emulation_CT return charstring { + for (var integer i := 0; i < sizeof(GsupImsiTable); i := i+1) { + if (GsupImsiTable[i].comp_ref == client) { + return GsupImsiTable[i].imsi; + } + } + log("GSUP IMSI table not found by component ", client); + setverdict(fail); + self.stop; +} + +private function f_imsi_table_init() +runs on GSUP_Emulation_CT { + for (var integer i := 0; i < sizeof(GsupImsiTable); i := i+1) { + GsupImsiTable[i].comp_ref := null; + GsupImsiTable[i].imsi := ""; + } +} + +private function f_imsi_table_add(GSUP_ConnHdlr comp_ref, charstring imsi) +runs on GSUP_Emulation_CT { + for (var integer i := 0; i < sizeof(GsupImsiTable); i := i+1) { + if (GsupImsiTable[i].imsi == "") { + GsupImsiTable[i].comp_ref := comp_ref; + GsupImsiTable[i].imsi := imsi; + log("Added IMSI table entry ", i, comp_ref, imsi); + return; + } + } + log("GSUP IMSI table full!"); + setverdict(fail); + self.stop; +} + +private function f_imsi_table_del(charstring imsi) +runs on GSUP_Emulation_CT { + for (var integer i := 0; i < sizeof(GsupImsiTable); i := i+1) { + if (GsupImsiTable[i].imsi == imsi) { + log("Deleted GSUP IMSI table entry ", i, + GsupImsiTable[i].comp_ref, imsi); + GsupImsiTable[i].imsi := ""; + GsupImsiTable[i].comp_ref := null; + return + } + } + log("GSUP IMSI table attempt to delete non-existant ", imsi); + setverdict(fail); + self.stop; +} + + +/* call-back type, to be provided by specific implementation; called when new SCCP connection + * arrives */ +type function GsupCreateCallback(GSUP_PDU gsup, charstring id) +runs on GSUP_Emulation_CT return GSUP_ConnHdlr; + +type record GsupOps { + GsupCreateCallback create_cb +} + +function main(GsupOps ops, charstring id) runs on GSUP_Emulation_CT { + + f_imsi_table_init(); + + while (true) { + var GSUP_ConnHdlr vc_conn; + var GSUP_ConnHdlr vc_hdlr; + var GSUP_PDU gsup; + var charstring imsi; + + alt { + + [] GSUP.receive(ASP_IPA_Event:{up_down:=ASP_IPA_EVENT_ID_ACK}) { repeat; } + [] GSUP.receive(ASP_IPA_Event:{up_down:=ASP_IPA_EVENT_UP}) { repeat; } + [] GSUP.receive(ASP_IPA_Event:{up_down:=ASP_IPA_EVENT_DOWN}) { + setverdict(fail, "GSUP Connection Lost"); + self.stop; + } + + /* GSUP -> Client: call related messages */ + [] GSUP.receive(GSUP_PDU:?) -> value gsup { + imsi := hex2str(gsup.ies[0].val.imsi); + + if (f_imsi_known(imsi)) { + vc_conn := f_comp_by_imsi(imsi); + GSUP_CLIENT.send(gsup) to vc_conn; + } else { + /* TODO: Only accept this for SETUP.req? */ + vc_conn := ops.create_cb.apply(gsup, id) + /* store mapping between client components and SCCP connectionId */ + f_imsi_table_add(vc_conn, imsi); + /* handle user payload */ + GSUP_CLIENT.send(gsup) to vc_conn; + } + } + + [] GSUP.receive { repeat; } + + /* Client -> GSUP Socket: Normal message */ + [] GSUP_CLIENT.receive(GSUP_PDU:?) -> value gsup sender vc_conn { + /* forward to GSUP socket */ + GSUP.send(gsup); + } + + + /* Client -> us: procedure call to register expect */ + [] GSUP_PROC.getcall(GSUPEM_register:{?,?}) -> param(imsi, vc_hdlr) { + f_create_expect(imsi, vc_hdlr); + GSUP_PROC.reply(GSUPEM_register:{imsi, vc_hdlr}); + } + + } + } +} + +/*********************************************************************** + * "Expect" Handling (mapping for expected incoming GSUP calls from IUT) + ***********************************************************************/ + +/* data about an expected future incoming connection */ +type record ExpectData { + /* destination number based on which we can match it */ + charstring imsi optional, + /* component reference for this connection */ + GSUP_ConnHdlr vc_conn +} + +/* procedure based port to register for incoming calls */ +signature GSUPEM_register(in charstring imsi, in GSUP_ConnHdlr hdlr); + +type port GSUPEM_PROC_PT procedure { + inout GSUPEM_register; +} with { extension "internal" }; + +/* CreateCallback that can be used as create_cb and will use the expectation table */ +function ExpectedCreateCallback(GSUP_PDU gsup, charstring id) +runs on GSUP_Emulation_CT return GSUP_ConnHdlr { + var GSUP_ConnHdlr ret := null; + var charstring imsi; + var integer i; + + imsi := hex2str(gsup.ies[0].val.imsi); + + for (i := 0; i < sizeof(GsupExpectTable); i:= i+1) { + if (not ispresent(GsupExpectTable[i].imsi)) { + continue; + } + if (imsi == GsupExpectTable[i].imsi) { + ret := GsupExpectTable[i].vc_conn; + /* release this entry to be used again */ + GsupExpectTable[i].imsi := omit; + GsupExpectTable[i].vc_conn := null; + log("Found GsupExpect[", i, "] for ", imsi, " handled at ", ret); + /* return the component reference */ + return ret; + } + } + setverdict(fail, "Couldn't find GsupExpect for incoming imsi ", imsi); + return ret; +} + +/* server/emulation side function to create expect */ +private function f_create_expect(charstring imsi, GSUP_ConnHdlr hdlr) +runs on GSUP_Emulation_CT { + var integer i; + for (i := 0; i < sizeof(GsupExpectTable); i := i+1) { + if (not ispresent(GsupExpectTable[i].imsi)) { + GsupExpectTable[i].imsi := imsi; + GsupExpectTable[i].vc_conn := hdlr; + log("Created GsupExpect[", i, "] for ", imsi, " to be handled at ", hdlr); + return; + } + } + setverdict(fail, "No space left in GsupExpectTable"); +} + +/* client/conn_hdlr side function to use procedure port to create expect in emulation */ +function f_create_gsup_expect(charstring imsi) runs on GSUP_ConnHdlr { + GSUP_PROC.call(GSUPEM_register:{imsi, self}) { + [] GSUP_PROC.getreply(GSUPEM_register:{?,?}) {}; + } +} + +} -- To view, visit https://gerrit.osmocom.org/5954 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: merged Gerrit-Change-Id: I6d06280fa5729ee921d319854a9b11636cf83495 Gerrit-PatchSet: 2 Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Owner: Harald Welte <laforge at gnumonks.org> Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org> Gerrit-Reviewer: Jenkins Builder