diff options
Diffstat (limited to 'library/Iuh_Emulation.ttcn')
-rw-r--r-- | library/Iuh_Emulation.ttcn | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/library/Iuh_Emulation.ttcn b/library/Iuh_Emulation.ttcn new file mode 100644 index 00000000..e1f283fa --- /dev/null +++ b/library/Iuh_Emulation.ttcn @@ -0,0 +1,210 @@ +module Iuh_Emulation { + +/* Iuh Emulation, runs on top of Iuh_CodecPort. It multiplexes/demultiplexes + * HNBAP and RUA. + * + * The Iuh_Emulation.main() function processes Iuh primitives from the Iuh + * socket via the Iuh_CodecPort, and dispatches them to HNBAP/RUA ports. + * + * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de> + * Author: Pau Espin Pedrol <pespin@sysmocom.de> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from Iuh_CodecPort all; +import from Iuh_CodecPort_CtrlFunct all; +import from HNBAP_Types all; +import from HNBAP_Constants all; +import from HNBAP_PDU_Contents all; +import from HNBAP_PDU_Descriptions all; +import from HNBAP_IEs all; +import from HNBAP_Templates all; +import from RUA_Types all; +import from RUA_Constants all; +import from RUA_PDU_Contents all; +import from RUA_PDU_Descriptions all; +import from RUA_IEs all; +import from RUA_Templates all; +import from Iuh_Types all; +import from SCTP_Templates all; + +import from General_Types all; +import from Misc_Helpers all; +import from Osmocom_Types all; +import from IPL4asp_Types all; +import from DNS_Helpers all; + +/* General "base class" component definition, of which specific implementations + * derive themselves by means of the "extends" feature */ +type component Iuh_ConnHdlr { + port HNBAP_PT HNBAP; + port RUA_PT RUA; +}; + +type enumerated IUHEM_EventUpDown { + IUHEM_EVENT_DOWN, + IUHEM_EVENT_UP +} + +/* an event indicating us whether or not a connection is physically up or down. */ +type union IUHEM_Event { + IUHEM_EventUpDown up_down +} + +type port HNBAP_PT message { + inout HNBAP_PDU, IUHEM_Event; +} with { extension "internal" }; +type port RUA_PT message { + inout RUA_PDU, IUHEM_Event; +} with { extension "internal" }; + +type component Iuh_Emulation_CT { + /* Port facing to the SCTP SUT */ + port Iuh_CODEC_PT Iuh; + /* Port facing to user upper side stack: */ + port HNBAP_PT HNBAP; + port RUA_PT RUA; + + var Iuh_conn_parameters g_pars; + var charstring g_Iuh_id; + var integer g_self_conn_id := -1; + var IPL4asp_Types.ConnectionId g_last_conn_id := -1; /* server only */ +} + +type record Iuh_conn_parameters { + HostName remote_ip, + PortNumber remote_sctp_port, + HostName local_ip, + PortNumber local_sctp_port +} + +function tr_Iuh_RecvFrom_R(template Iuh_PDU msg) +runs on Iuh_Emulation_CT return template Iuh_RecvFrom { + var template Iuh_RecvFrom mrf := { + connId := ?, + remName := ?, + remPort := ?, + locName := ?, + locPort := ?, + msg := msg + } + return mrf; +} + +private function emu_is_server() runs on Iuh_Emulation_CT return boolean { + return g_pars.remote_sctp_port == -1 +} + +/* Resolve TCP/IP connection identifier depending on server/client mode */ +private function f_iuh_conn_id() runs on Iuh_Emulation_CT +return IPL4asp_Types.ConnectionId { + var IPL4asp_Types.ConnectionId conn_id; + + if (not emu_is_server()) { + conn_id := g_self_conn_id; + } else { + conn_id := g_last_conn_id; + } + + if (conn_id == -1) { /* Just to be sure */ + f_shutdown(__FILE__, __LINE__, fail, "Connection is not established"); + } + + return conn_id; +} + +private function f_send_IUHEM_Event(template (value) IUHEM_Event evt) runs on Iuh_Emulation_CT { + if (HNBAP.checkstate("Connected")) { + HNBAP.send(evt); + } +} + +function main(Iuh_conn_parameters p, charstring id) runs on Iuh_Emulation_CT { + var Result res; + g_pars := p; + g_Iuh_id := id; + + map(self:Iuh, system:Iuh_CODEC_PT); + if (emu_is_server()) { + res := Iuh_CodecPort_CtrlFunct.f_IPL4_listen(Iuh, p.local_ip, p.local_sctp_port, + { sctp := valueof(ts_SctpTuple) }); + } else { + res := Iuh_CodecPort_CtrlFunct.f_IPL4_connect(Iuh, p.remote_ip, p.remote_sctp_port, + p.local_ip, p.local_sctp_port, -1, + { sctp := valueof(ts_SctpTuple) }); + } + if (not ispresent(res.connId)) { + f_shutdown(__FILE__, __LINE__, fail, "Could not connect Iuh socket, check your configuration"); + } + g_self_conn_id := res.connId; + + /* notify user about SCTP establishment */ + if (p.remote_sctp_port != -1) { + f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_UP}); + } + + while (true) { + var Iuh_RecvFrom mrf; + var HNBAP_PDU hnbap_msg; + var RUA_PDU rua_msg; + var ASP_Event asp_evt; + + alt { + /* HNBAP from client: pass on transparently */ + [] HNBAP.receive(HNBAP_PDU:?) -> value hnbap_msg { + /* Pass message through */ + Iuh.send(t_Iuh_Send_HNBAP(f_iuh_conn_id(), hnbap_msg)); + } + /* RUA from client: pass on transparently */ + [] RUA.receive(RUA_PDU:?) -> value rua_msg { + /* Pass message through */ + Iuh.send(t_Iuh_Send_RUA(f_iuh_conn_id(), rua_msg)); + } + + /* Iuh received from peer (HNBGW or HnodeB) */ + [] Iuh.receive(tr_Iuh_RecvFrom_R(?)) -> value mrf { + if (not match(mrf.connId, f_iuh_conn_id())) { + f_shutdown(__FILE__, __LINE__, fail, log2str("Received message from unexpected conn_id!", mrf)); + } + + if (match(mrf, t_Iuh_RecvFrom_HNBAP(?))) { + HNBAP.send(mrf.msg.hnbap); + } else if (match(mrf, t_Iuh_RecvFrom_RUA(?))) { + RUA.send(mrf.msg.rua); + } else { + /* TODO: special handling, as it contains multiple HNB connection ids */ + f_shutdown(__FILE__, __LINE__, fail, log2str("UNEXPECTED MESSAGE RECEIVED!", mrf)); + } + } + [] Iuh.receive(tr_SctpAssocChange) { } + [] Iuh.receive(tr_SctpPeerAddrChange) { } + + /* server only */ + [] Iuh.receive(ASP_Event:{connOpened:=?}) -> value asp_evt { + if (not emu_is_server()) { + f_shutdown(__FILE__, __LINE__, fail, log2str("Unexpected event receiver in client mode", asp_evt)); + } + g_last_conn_id := asp_evt.connOpened.connId; + log("Established a new Iuh connection (conn_id=", g_last_conn_id, ")"); + + f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_UP}); /* TODO: send g_last_conn_id */ + } + + [] Iuh.receive(ASP_Event:{connClosed:=?}) -> value asp_evt { + log("Iuh: Closed"); + g_self_conn_id := -1; + f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_DOWN}); /* TODO: send asp_evt.connClosed.connId */ + if (not emu_is_server()) { + self.stop; + } + } + } + } +} + +} |