hnb: Introduce HNB_Tests testsuite
A new Iuh CodecPort + Emulation is introduced to (de)mux RANAP and RUA
in the same SCTP socket.
The Iuh_CodecPort.ttcn file has currently a hack to be able to test
HNBAP, since titan seem to be reporting sinfo_ppid=0 when in fact it
received sinfo_ppid=20 (HNBAP).
A couple tests are added to validate HNBAP HNBRegister Request + Accept
or Reject. In current osmo-hnodeb state, both tests pass if run
separately, but fail if run sequentially since osmo-hnodeb still doesn't
re-connect properly after first test finishes and connection is dropped.
Related: SYS#5516
Change-Id: I7227917148e98a2c777f4b05d8d2eca6e9c121b7
diff --git a/library/Iuh_CodecPort.ttcn b/library/Iuh_CodecPort.ttcn
new file mode 100644
index 0000000..569a27f
--- /dev/null
+++ b/library/Iuh_CodecPort.ttcn
@@ -0,0 +1,141 @@
+module Iuh_CodecPort {
+
+/* Simple Iuh Codec Port, translating between raw SCTP primitives with
+ * octetstring payload towards the IPL4asp provider, and Iuh primitives
+ * which carry the decoded Iuh data types as payload.
+ *
+ * (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 IPL4asp_PortType all;
+ import from IPL4asp_Types all;
+ import from HNBAP_PDU_Descriptions all;
+ import from HNBAP_Types all;
+ import from RUA_PDU_Descriptions all;
+ import from RUA_Types all;
+ import from Iuh_Types all;
+
+ type record Iuh_RecvFrom {
+ ConnectionId connId,
+ HostName remName,
+ PortNumber remPort,
+ HostName locName,
+ PortNumber locPort,
+ Iuh_PDU msg
+ };
+
+ template Iuh_RecvFrom t_Iuh_RecvFrom(template Iuh_PDU msg) := {
+ connId := ?,
+ remName := ?,
+ remPort := ?,
+ locName := ?,
+ locPort := ?,
+ msg := msg
+ }
+
+ template Iuh_RecvFrom t_Iuh_RecvFrom_HNBAP(template HNBAP_PDU hnbap_msg := ?) := {
+ connId := ?,
+ remName := ?,
+ remPort := ?,
+ locName := ?,
+ locPort := ?,
+ msg := {
+ hnbap := hnbap_msg
+ }
+ }
+
+ template Iuh_RecvFrom t_Iuh_RecvFrom_RUA(template RUA_PDU rua_msg := ?) := {
+ connId := ?,
+ remName := ?,
+ remPort := ?,
+ locName := ?,
+ locPort := ?,
+ msg := {
+ rua := rua_msg
+ }
+ }
+
+ type record Iuh_Send {
+ ConnectionId connId,
+ Iuh_PDU msg
+ };
+
+ template Iuh_Send t_Iuh_Send_HNBAP(template ConnectionId connId, template HNBAP_PDU hnbap_msg) := {
+ connId := connId,
+ msg := {
+ hnbap := hnbap_msg
+ }
+ }
+
+ template Iuh_Send t_Iuh_Send_RUA(template ConnectionId connId, template RUA_PDU rua_msg) := {
+ connId := connId,
+ msg := {
+ rua := rua_msg
+ }
+ }
+
+ private function IPL4_to_Iuh_RecvFrom(in ASP_RecvFrom pin, out Iuh_RecvFrom pout) {
+ pout.connId := pin.connId;
+ pout.remName := pin.remName;
+ pout.remPort := pin.remPort;
+ pout.locName := pin.locName;
+ pout.locPort := pin.locPort;
+ select (pin.proto.sctp.sinfo_ppid) {
+ case (19) {
+ pout.msg.rua := dec_RUA_PDU(pin.msg);
+ }
+ case (20) {
+ pout.msg.hnbap := dec_HNBAP_PDU(pin.msg);
+ }
+ case (0) {
+ /* FIXME: lower layers report sinfo_ppid=0: */
+ pout.msg.hnbap := dec_HNBAP_PDU(pin.msg);
+ }
+ case else {
+ pout.msg.payload := pin.msg;
+ }
+ }
+ } with { extension "prototype(fast)" };
+
+ private function Iuh_to_IPL4_Send(in Iuh_Send pin, out ASP_Send pout) {
+ var integer sctp_ppid;
+ if (ischosen(pin.msg.rua)) {
+ sctp_ppid := 19;
+ pout.msg := enc_RUA_PDU(pin.msg.rua);
+ } else if (ischosen(pin.msg.hnbap)) {
+ sctp_ppid := 20;
+ pout.msg := enc_HNBAP_PDU(pin.msg.hnbap);
+ } else { /*TODO: abort?*/
+ sctp_ppid := 0;
+ pout.msg := pin.msg.payload;
+ }
+ pout.connId := pin.connId;
+ pout.proto := {
+ sctp := {
+ sinfo_stream := omit,
+ sinfo_ppid := sctp_ppid,
+ remSocks := omit,
+ assocId := omit
+ }
+ };
+ } with { extension "prototype(fast)" };
+
+ type port Iuh_CODEC_PT message {
+ out Iuh_Send;
+ in Iuh_RecvFrom,
+ ASP_ConnId_ReadyToRelease,
+ ASP_Event;
+ } with { extension "user IPL4asp_PT
+ out(Iuh_Send -> ASP_Send:function(Iuh_to_IPL4_Send))
+ in(ASP_RecvFrom -> Iuh_RecvFrom: function(IPL4_to_Iuh_RecvFrom);
+ ASP_ConnId_ReadyToRelease -> ASP_ConnId_ReadyToRelease: simple;
+ ASP_Event -> ASP_Event: simple)"
+ }
+}
diff --git a/library/Iuh_CodecPort_CtrlFunct.ttcn b/library/Iuh_CodecPort_CtrlFunct.ttcn
new file mode 100644
index 0000000..c0c7003
--- /dev/null
+++ b/library/Iuh_CodecPort_CtrlFunct.ttcn
@@ -0,0 +1,43 @@
+module Iuh_CodecPort_CtrlFunct {
+
+ import from Iuh_CodecPort all;
+ import from IPL4asp_Types all;
+
+ external function f_IPL4_listen(
+ inout Iuh_CODEC_PT portRef,
+ in HostName locName,
+ in PortNumber locPort,
+ in ProtoTuple proto,
+ in OptionList options := {}
+ ) return Result;
+
+ external function f_IPL4_connect(
+ inout Iuh_CODEC_PT portRef,
+ in HostName remName,
+ in PortNumber remPort,
+ in HostName locName,
+ in PortNumber locPort,
+ in ConnectionId connId,
+ in ProtoTuple proto,
+ in OptionList options := {}
+ ) return Result;
+
+ external function f_IPL4_close(
+ inout Iuh_CODEC_PT portRef,
+ in ConnectionId id,
+ in ProtoTuple proto := { unspecified := {} }
+ ) return Result;
+
+ external function f_IPL4_setUserData(
+ inout Iuh_CODEC_PT portRef,
+ in ConnectionId id,
+ in UserData userData
+ ) return Result;
+
+ external function f_IPL4_getUserData(
+ inout Iuh_CODEC_PT portRef,
+ in ConnectionId id,
+ out UserData userData
+ ) return Result;
+
+}
diff --git a/library/Iuh_CodecPort_CtrlFunctDef.cc b/library/Iuh_CodecPort_CtrlFunctDef.cc
new file mode 100644
index 0000000..2f08dec
--- /dev/null
+++ b/library/Iuh_CodecPort_CtrlFunctDef.cc
@@ -0,0 +1,55 @@
+#include "IPL4asp_PortType.hh"
+#include "Iuh_CodecPort.hh"
+#include "IPL4asp_PT.hh"
+
+namespace Iuh__CodecPort__CtrlFunct {
+
+ IPL4asp__Types::Result f__IPL4__listen(
+ Iuh__CodecPort::Iuh__CODEC__PT& portRef,
+ const IPL4asp__Types::HostName& locName,
+ const IPL4asp__Types::PortNumber& locPort,
+ const IPL4asp__Types::ProtoTuple& proto,
+ const IPL4asp__Types::OptionList& options)
+ {
+ return f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options);
+ }
+
+ IPL4asp__Types::Result f__IPL4__connect(
+ Iuh__CodecPort::Iuh__CODEC__PT& portRef,
+ const IPL4asp__Types::HostName& remName,
+ const IPL4asp__Types::PortNumber& remPort,
+ const IPL4asp__Types::HostName& locName,
+ const IPL4asp__Types::PortNumber& locPort,
+ const IPL4asp__Types::ConnectionId& connId,
+ const IPL4asp__Types::ProtoTuple& proto,
+ const IPL4asp__Types::OptionList& options)
+ {
+ return f__IPL4__PROVIDER__connect(portRef, remName, remPort,
+ locName, locPort, connId, proto, options);
+ }
+
+ IPL4asp__Types::Result f__IPL4__close(
+ Iuh__CodecPort::Iuh__CODEC__PT& portRef,
+ const IPL4asp__Types::ConnectionId& connId,
+ const IPL4asp__Types::ProtoTuple& proto)
+ {
+ return f__IPL4__PROVIDER__close(portRef, connId, proto);
+ }
+
+ IPL4asp__Types::Result f__IPL4__setUserData(
+ Iuh__CodecPort::Iuh__CODEC__PT& portRef,
+ const IPL4asp__Types::ConnectionId& connId,
+ const IPL4asp__Types::UserData& userData)
+ {
+ return f__IPL4__PROVIDER__setUserData(portRef, connId, userData);
+ }
+
+ IPL4asp__Types::Result f__IPL4__getUserData(
+ Iuh__CodecPort::Iuh__CODEC__PT& portRef,
+ const IPL4asp__Types::ConnectionId& connId,
+ IPL4asp__Types::UserData& userData)
+ {
+ return f__IPL4__PROVIDER__getUserData(portRef, connId, userData);
+ }
+
+}
diff --git a/library/Iuh_Emulation.ttcn b/library/Iuh_Emulation.ttcn
new file mode 100644
index 0000000..75a95ba
--- /dev/null
+++ b/library/Iuh_Emulation.ttcn
@@ -0,0 +1,212 @@
+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 General_Types all;
+import from Misc_Helpers all;
+import from Osmocom_Types all;
+import from IPL4asp_Types all;
+import from DNS_Helpers all;
+
+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 template (value) SctpTuple ts_SCTP(template (omit) integer ppid := omit) := {
+ sinfo_stream := omit,
+ sinfo_ppid := ppid,
+ remSocks := omit,
+ assocId := omit
+};
+
+private template PortEvent tr_SctpAssocChange := {
+ sctpEvent := {
+ sctpAssocChange := ?
+ }
+}
+private template PortEvent tr_SctpPeerAddrChange := {
+ sctpEvent := {
+ sctpPeerAddrChange := ?
+ }
+}
+
+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;
+}
+
+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_SCTP) });
+ } 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_SCTP) });
+ }
+ 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) {
+ HNBAP.send(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, ")");
+
+ HNBAP.send(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;
+ HNBAP.send(IUHEM_Event:{up_down:=IUHEM_EVENT_DOWN}); /* TODO: send asp_evt.connClosed.connId */
+ if (not emu_is_server()) {
+ self.stop;
+ }
+ }
+ }
+ }
+}
+
+}
diff --git a/library/Iuh_Types.ttcn b/library/Iuh_Types.ttcn
new file mode 100644
index 0000000..17f9c5f
--- /dev/null
+++ b/library/Iuh_Types.ttcn
@@ -0,0 +1,36 @@
+/* Osmocom Iuh Interface Types
+ * (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
+ */
+
+ /* Iuh Codec Port Types
+ *
+ * (C) 2019 by Harald Welte <laforge@gnumonks.org>
+ * 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
+ */
+
+module Iuh_Types {
+
+import from HNBAP_PDU_Descriptions all;
+import from HNBAP_Types all;
+import from RUA_PDU_Descriptions all;
+import from RUA_Types all;
+
+type union Iuh_PDU {
+ HNBAP_PDU hnbap,
+ RUA_PDU rua,
+ octetstring payload
+}
+
+};
diff --git a/library/hnbap/HNBAP_Templates.ttcn b/library/hnbap/HNBAP_Templates.ttcn
new file mode 100644
index 0000000..44704f8
--- /dev/null
+++ b/library/hnbap/HNBAP_Templates.ttcn
@@ -0,0 +1,135 @@
+/* HNBAP Templates in TTCN-3
+ * (C) 2021 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
+ */
+
+module HNBAP_Templates {
+
+import from General_Types all;
+import from Osmocom_Types all;
+
+import from HNBAP_IEs all;
+import from HNBAP_CommonDataTypes all;
+import from HNBAP_Constants all;
+import from HNBAP_Containers all;
+import from HNBAP_PDU_Contents all;
+import from HNBAP_PDU_Descriptions all;
+
+/*********************************************************************************
+ * 3GPP TS 25.469
+ *********************************************************************************/
+
+template (value) Cause ts_HnbapCause(template (value) CauseRadioNetwork c) := {
+ radioNetwork := c
+}
+
+/* 9.1.3 HNB REGISTER REQUEST */
+template (present) HNBAP_PDU
+tr_HNBAP_HNBRegisterRequest(template (present) octetstring hNB_Identity_Info := ?,
+ template (present) OCT3 plmnid := ?,
+ template (present) BIT28 cell_identity := ?,
+ template (present) OCT2 lac := ?,
+ template (present) OCT1 rac := ?,
+ template (present) OCT2 sac := ?) := {
+ initiatingMessage := {
+ procedureCode := id_HNBRegister,
+ criticality := reject,
+ value_ := {
+ hNBRegisterRequest := {
+ protocolIEs := {
+ {
+ id := HNBAP_Constants.id_HNB_Identity,
+ criticality := reject,
+ value_ := {
+ hNB_Identity := {
+ hNB_Identity_Info := hNB_Identity_Info,
+ iE_Extensions := omit
+ }
+ }
+ }, {
+ id := 8,
+ criticality := reject,
+ value_ := {
+ hNB_Location_Information := {
+ macroCoverageInfo := omit,
+ geographicalCoordinates := omit,
+ iE_Extensions := omit
+ }
+ }
+ }, {
+ id := 9,
+ criticality := reject,
+ value_ := { pLMNidentity := plmnid }
+ }, {
+ id := 11,
+ criticality := reject,
+ value_ := { cellIdentity := cell_identity }
+ }, {
+ id := 6,
+ criticality := reject,
+ value_ := { lAC := lac }
+ }, {
+ id := 7,
+ criticality := reject,
+ value_ := { rAC := rac }
+ }, {
+ id := 10,
+ criticality := reject,
+ value_ := { sAC := sac }
+ }
+ },
+ protocolExtensions := omit
+ }
+ }
+ }
+}
+
+
+/* 9.1.4 HNB REGISTER ACCEPT */
+template (value) HNBAP_PDU
+ts_HNBAP_HNBRegisterAccept(template (value) uint16_t rnc_id) := {
+ successfulOutcome := {
+ procedureCode := id_HNBRegister,
+ criticality := reject,
+ value_ := {
+ hNBRegisterAccept := {
+ protocolIEs := {
+ {
+ id := HNBAP_Constants.id_RNC_ID,
+ criticality := reject,
+ value_ := { RNC_ID := rnc_id }
+ }
+ },
+ protocolExtensions := omit /* TODO: Mux Port Number (optional) 9.2.29 */
+ }
+ }
+ }
+}
+
+/* 9.1.5 HNB REGISTER REJECT */
+template (value) HNBAP_PDU
+ts_HNBAP_HNBRegisterReject(template (value) Cause cause) := {
+ unsuccessfulOutcome := {
+ procedureCode := id_HNBRegister,
+ criticality := reject,
+ value_ := {
+ HNBRegisterReject := {
+ protocolIEs := {
+ {
+ id := HNBAP_Constants.id_Cause,
+ criticality := ignore,
+ value_ := { Cause := cause }
+ }
+ },
+ protocolExtensions := omit /* TODO: CriticalityDiagnostics, BackoffTimer */
+ }
+ }
+ }
+}
+
+}
diff --git a/library/rua/RUA_Templates.ttcn b/library/rua/RUA_Templates.ttcn
new file mode 100644
index 0000000..b7387bf
--- /dev/null
+++ b/library/rua/RUA_Templates.ttcn
@@ -0,0 +1,22 @@
+/* RUA Templates in TTCN-3
+ * (C) 2021 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
+ */
+
+module RUA_Templates {
+
+import from RUA_IEs all;
+import from RUA_CommonDataTypes all;
+import from RUA_Constants all;
+import from RUA_Containers all;
+import from RUA_PDU_Contents all;
+import from RUA_PDU_Descriptions all;
+
+
+/* TODO: Add RUA Templates here */
+}