blob: e05afe553985565a620b9f97d180f8a24afbfe5b [file] [log] [blame]
Pau Espin Pedrolb54acca2021-11-22 20:35:44 +01001module Iuh_Emulation {
2
3/* Iuh Emulation, runs on top of Iuh_CodecPort. It multiplexes/demultiplexes
4 * HNBAP and RUA.
5 *
6 * The Iuh_Emulation.main() function processes Iuh primitives from the Iuh
7 * socket via the Iuh_CodecPort, and dispatches them to HNBAP/RUA ports.
8 *
9 * (C) 2021 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
10 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
11 * All rights reserved.
12 *
13 * Released under the terms of GNU General Public License, Version 2 or
14 * (at your option) any later version.
15 *
16 * SPDX-License-Identifier: GPL-2.0-or-later
17 */
18
19import from Iuh_CodecPort all;
20import from Iuh_CodecPort_CtrlFunct all;
21import from HNBAP_Types all;
22import from HNBAP_Constants all;
23import from HNBAP_PDU_Contents all;
24import from HNBAP_PDU_Descriptions all;
25import from HNBAP_IEs all;
26import from HNBAP_Templates all;
27import from RUA_Types all;
28import from RUA_Constants all;
29import from RUA_PDU_Contents all;
30import from RUA_PDU_Descriptions all;
31import from RUA_IEs all;
32import from RUA_Templates all;
33import from Iuh_Types all;
34
35import from General_Types all;
36import from Misc_Helpers all;
37import from Osmocom_Types all;
38import from IPL4asp_Types all;
39import from DNS_Helpers all;
40
Harald Weltecb3e2d72022-01-10 19:14:28 +010041/* General "base class" component definition, of which specific implementations
42 * derive themselves by means of the "extends" feature */
43type component Iuh_ConnHdlr {
44 port HNBAP_PT HNBAP;
45 port RUA_PT RUA;
46};
47
Pau Espin Pedrolb54acca2021-11-22 20:35:44 +010048type enumerated IUHEM_EventUpDown {
49 IUHEM_EVENT_DOWN,
50 IUHEM_EVENT_UP
51}
52
53/* an event indicating us whether or not a connection is physically up or down. */
54type union IUHEM_Event {
55 IUHEM_EventUpDown up_down
56}
57
58type port HNBAP_PT message {
59 inout HNBAP_PDU, IUHEM_Event;
60} with { extension "internal" };
61type port RUA_PT message {
62 inout RUA_PDU, IUHEM_Event;
63} with { extension "internal" };
64
65type component Iuh_Emulation_CT {
66 /* Port facing to the SCTP SUT */
67 port Iuh_CODEC_PT Iuh;
68 /* Port facing to user upper side stack: */
69 port HNBAP_PT HNBAP;
70 port RUA_PT RUA;
71
72 var Iuh_conn_parameters g_pars;
73 var charstring g_Iuh_id;
74 var integer g_self_conn_id := -1;
75 var IPL4asp_Types.ConnectionId g_last_conn_id := -1; /* server only */
76}
77
78type record Iuh_conn_parameters {
79 HostName remote_ip,
80 PortNumber remote_sctp_port,
81 HostName local_ip,
82 PortNumber local_sctp_port
83}
84
85function tr_Iuh_RecvFrom_R(template Iuh_PDU msg)
86runs on Iuh_Emulation_CT return template Iuh_RecvFrom {
87 var template Iuh_RecvFrom mrf := {
88 connId := ?,
89 remName := ?,
90 remPort := ?,
91 locName := ?,
92 locPort := ?,
93 msg := msg
94 }
95 return mrf;
96}
97
98private template (value) SctpTuple ts_SCTP(template (omit) integer ppid := omit) := {
99 sinfo_stream := omit,
100 sinfo_ppid := ppid,
101 remSocks := omit,
102 assocId := omit
103};
104
105private template PortEvent tr_SctpAssocChange := {
106 sctpEvent := {
107 sctpAssocChange := ?
108 }
109}
110private template PortEvent tr_SctpPeerAddrChange := {
111 sctpEvent := {
112 sctpPeerAddrChange := ?
113 }
114}
115
116private function emu_is_server() runs on Iuh_Emulation_CT return boolean {
117 return g_pars.remote_sctp_port == -1
118}
119
120/* Resolve TCP/IP connection identifier depending on server/client mode */
121private function f_iuh_conn_id() runs on Iuh_Emulation_CT
122return IPL4asp_Types.ConnectionId {
123 var IPL4asp_Types.ConnectionId conn_id;
124
125 if (not emu_is_server()) {
126 conn_id := g_self_conn_id;
127 } else {
128 conn_id := g_last_conn_id;
129 }
130
131 if (conn_id == -1) { /* Just to be sure */
132 f_shutdown(__FILE__, __LINE__, fail, "Connection is not established");
133 }
134
135 return conn_id;
136}
137
Pau Espin Pedrol066f46f2021-12-23 15:11:05 +0100138private function f_send_IUHEM_Event(template (value) IUHEM_Event evt) runs on Iuh_Emulation_CT {
139 if (HNBAP.checkstate("Connected")) {
140 HNBAP.send(evt);
141 }
142}
143
Pau Espin Pedrolb54acca2021-11-22 20:35:44 +0100144function main(Iuh_conn_parameters p, charstring id) runs on Iuh_Emulation_CT {
145 var Result res;
146 g_pars := p;
147 g_Iuh_id := id;
148
149 map(self:Iuh, system:Iuh_CODEC_PT);
150 if (emu_is_server()) {
151 res := Iuh_CodecPort_CtrlFunct.f_IPL4_listen(Iuh, p.local_ip, p.local_sctp_port, { sctp := valueof(ts_SCTP) });
152 } else {
153 res := Iuh_CodecPort_CtrlFunct.f_IPL4_connect(Iuh, p.remote_ip, p.remote_sctp_port,
154 p.local_ip, p.local_sctp_port, -1, { sctp := valueof(ts_SCTP) });
155 }
156 if (not ispresent(res.connId)) {
157 f_shutdown(__FILE__, __LINE__, fail, "Could not connect Iuh socket, check your configuration");
158 }
159 g_self_conn_id := res.connId;
160
161 /* notify user about SCTP establishment */
162 if (p.remote_sctp_port != -1) {
Pau Espin Pedrol066f46f2021-12-23 15:11:05 +0100163 f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_UP});
Pau Espin Pedrolb54acca2021-11-22 20:35:44 +0100164 }
165
166 while (true) {
167 var Iuh_RecvFrom mrf;
168 var HNBAP_PDU hnbap_msg;
169 var RUA_PDU rua_msg;
170 var ASP_Event asp_evt;
171
172 alt {
173 /* HNBAP from client: pass on transparently */
174 [] HNBAP.receive(HNBAP_PDU:?) -> value hnbap_msg {
175 /* Pass message through */
176 Iuh.send(t_Iuh_Send_HNBAP(f_iuh_conn_id(), hnbap_msg));
177 }
178 /* RUA from client: pass on transparently */
179 [] RUA.receive(RUA_PDU:?) -> value rua_msg {
180 /* Pass message through */
181 Iuh.send(t_Iuh_Send_RUA(f_iuh_conn_id(), rua_msg));
182 }
183
184 /* Iuh received from peer (HNBGW or HnodeB) */
185 [] Iuh.receive(tr_Iuh_RecvFrom_R(?)) -> value mrf {
186 if (not match(mrf.connId, f_iuh_conn_id())) {
187 f_shutdown(__FILE__, __LINE__, fail, log2str("Received message from unexpected conn_id!", mrf));
188 }
189
190 if (match(mrf, t_Iuh_RecvFrom_HNBAP(?))) {
191 HNBAP.send(mrf.msg.hnbap);
192 } else if (match(mrf, t_Iuh_RecvFrom_RUA(?))) {
193 RUA.send(mrf.msg.rua);
194 } else {
195 /* TODO: special handling, as it contains multiple HNB connection ids */
196 f_shutdown(__FILE__, __LINE__, fail, log2str("UNEXPECTED MESSAGE RECEIVED!", mrf));
197 }
198 }
199 [] Iuh.receive(tr_SctpAssocChange) { }
200 [] Iuh.receive(tr_SctpPeerAddrChange) { }
201
202 /* server only */
203 [] Iuh.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
204 if (not emu_is_server()) {
205 f_shutdown(__FILE__, __LINE__, fail, log2str("Unexpected event receiver in client mode", asp_evt));
206 }
207 g_last_conn_id := asp_evt.connOpened.connId;
208 log("Established a new Iuh connection (conn_id=", g_last_conn_id, ")");
209
Pau Espin Pedrol066f46f2021-12-23 15:11:05 +0100210 f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_UP}); /* TODO: send g_last_conn_id */
Pau Espin Pedrolb54acca2021-11-22 20:35:44 +0100211 }
212
213 [] Iuh.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
214 log("Iuh: Closed");
215 g_self_conn_id := -1;
Pau Espin Pedrol066f46f2021-12-23 15:11:05 +0100216 f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_DOWN}); /* TODO: send asp_evt.connClosed.connId */
Pau Espin Pedrolb54acca2021-11-22 20:35:44 +0100217 if (not emu_is_server()) {
218 self.stop;
219 }
220 }
221 }
222 }
223}
224
225}