Pau Espin Pedrol | b54acca | 2021-11-22 20:35:44 +0100 | [diff] [blame] | 1 | module 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 | |
| 19 | import from Iuh_CodecPort all; |
| 20 | import from Iuh_CodecPort_CtrlFunct all; |
| 21 | import from HNBAP_Types all; |
| 22 | import from HNBAP_Constants all; |
| 23 | import from HNBAP_PDU_Contents all; |
| 24 | import from HNBAP_PDU_Descriptions all; |
| 25 | import from HNBAP_IEs all; |
| 26 | import from HNBAP_Templates all; |
| 27 | import from RUA_Types all; |
| 28 | import from RUA_Constants all; |
| 29 | import from RUA_PDU_Contents all; |
| 30 | import from RUA_PDU_Descriptions all; |
| 31 | import from RUA_IEs all; |
| 32 | import from RUA_Templates all; |
| 33 | import from Iuh_Types all; |
| 34 | |
| 35 | import from General_Types all; |
| 36 | import from Misc_Helpers all; |
| 37 | import from Osmocom_Types all; |
| 38 | import from IPL4asp_Types all; |
| 39 | import from DNS_Helpers all; |
| 40 | |
Harald Welte | cb3e2d7 | 2022-01-10 19:14:28 +0100 | [diff] [blame] | 41 | /* General "base class" component definition, of which specific implementations |
| 42 | * derive themselves by means of the "extends" feature */ |
| 43 | type component Iuh_ConnHdlr { |
| 44 | port HNBAP_PT HNBAP; |
| 45 | port RUA_PT RUA; |
| 46 | }; |
| 47 | |
Pau Espin Pedrol | b54acca | 2021-11-22 20:35:44 +0100 | [diff] [blame] | 48 | type 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. */ |
| 54 | type union IUHEM_Event { |
| 55 | IUHEM_EventUpDown up_down |
| 56 | } |
| 57 | |
| 58 | type port HNBAP_PT message { |
| 59 | inout HNBAP_PDU, IUHEM_Event; |
| 60 | } with { extension "internal" }; |
| 61 | type port RUA_PT message { |
| 62 | inout RUA_PDU, IUHEM_Event; |
| 63 | } with { extension "internal" }; |
| 64 | |
| 65 | type 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 | |
| 78 | type record Iuh_conn_parameters { |
| 79 | HostName remote_ip, |
| 80 | PortNumber remote_sctp_port, |
| 81 | HostName local_ip, |
| 82 | PortNumber local_sctp_port |
| 83 | } |
| 84 | |
| 85 | function tr_Iuh_RecvFrom_R(template Iuh_PDU msg) |
| 86 | runs 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 | |
| 98 | private 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 | |
| 105 | private template PortEvent tr_SctpAssocChange := { |
| 106 | sctpEvent := { |
| 107 | sctpAssocChange := ? |
| 108 | } |
| 109 | } |
| 110 | private template PortEvent tr_SctpPeerAddrChange := { |
| 111 | sctpEvent := { |
| 112 | sctpPeerAddrChange := ? |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | private 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 */ |
| 121 | private function f_iuh_conn_id() runs on Iuh_Emulation_CT |
| 122 | return 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 Pedrol | 066f46f | 2021-12-23 15:11:05 +0100 | [diff] [blame] | 138 | private 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 Pedrol | b54acca | 2021-11-22 20:35:44 +0100 | [diff] [blame] | 144 | function 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 Pedrol | 066f46f | 2021-12-23 15:11:05 +0100 | [diff] [blame] | 163 | f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_UP}); |
Pau Espin Pedrol | b54acca | 2021-11-22 20:35:44 +0100 | [diff] [blame] | 164 | } |
| 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 Pedrol | 066f46f | 2021-12-23 15:11:05 +0100 | [diff] [blame] | 210 | f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_UP}); /* TODO: send g_last_conn_id */ |
Pau Espin Pedrol | b54acca | 2021-11-22 20:35:44 +0100 | [diff] [blame] | 211 | } |
| 212 | |
| 213 | [] Iuh.receive(ASP_Event:{connClosed:=?}) -> value asp_evt { |
| 214 | log("Iuh: Closed"); |
| 215 | g_self_conn_id := -1; |
Pau Espin Pedrol | 066f46f | 2021-12-23 15:11:05 +0100 | [diff] [blame] | 216 | f_send_IUHEM_Event(IUHEM_Event:{up_down:=IUHEM_EVENT_DOWN}); /* TODO: send asp_evt.connClosed.connId */ |
Pau Espin Pedrol | b54acca | 2021-11-22 20:35:44 +0100 | [diff] [blame] | 217 | if (not emu_is_server()) { |
| 218 | self.stop; |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | } |