blob: 413d2909fa1ae2224884fbfef6b14c14d4d7db4d [file] [log] [blame]
Harald Welted86cdc62017-11-22 00:45:07 +01001module IPA_Emulation {
2
Harald Weltebdb63702017-12-09 01:15:44 +01003/* This module implements the IPA multiplex protocol on top of TCP, using the IPL4asp
4 * test-port as provider. It implements both client and server roles, as well was the CCM
Harald Welte35bb7162018-01-03 21:07:52 +01005 * handshake for establishing the identity of the client to the server.
6 *
7 * It already knows certain well-known sub-protocols such as A-bis RSL, MGCP and SCCP and
8 * GSUP. IT hence transcodes messages so the user can work with abstract data types rather
9 * than binary messages. It handles multiple packets inside one TCP segment.
10 *
Harald Welte7460a722018-10-10 12:28:27 +020011 * (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
Harald Welte35bb7162018-01-03 21:07:52 +010012 * All rights reserved.
13 *
14 * Released under the terms of GNU General Public License, Version 2 or
15 * (at your option) any later version.
16 */
Harald Weltebdb63702017-12-09 01:15:44 +010017
Harald Welted86cdc62017-11-22 00:45:07 +010018import from IPA_Types all;
19import from IPA_CodecPort all;
20import from IPA_CodecPort_CtrlFunct all;
21import from IPL4asp_Types all;
Harald Welte12188832017-11-29 11:47:13 +010022import from IPL4asp_PortType all;
Stefan Sperling830dc9d2018-02-12 21:08:28 +010023import from Socket_API_Definitions all;
Harald Welted86cdc62017-11-22 00:45:07 +010024
Harald Weltedf277252018-02-20 15:49:30 +010025#ifdef IPA_EMULATION_SCCP
26import from MTP3asp_Types all;
27import from MTP3asp_PortType all;
28#endif
29
30#ifdef IPA_EMULATION_RSL
31import from RSL_Types all;
32#endif
33
34#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +010035import from MGCP_Types all;
Harald Weltedf277252018-02-20 15:49:30 +010036#endif
37
38#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +010039import from GSUP_Types all;
Harald Weltedf277252018-02-20 15:49:30 +010040#endif
Harald Weltec82eef42017-11-24 20:40:12 +010041
Harald Welte7460a722018-10-10 12:28:27 +020042#ifdef IPA_EMULATION_RSPRO
43import from RSPRO all;
44import from RSPRO_Types all;
45#endif
46
47
Harald Weltea76c4bb2017-12-09 02:06:07 +010048import from Osmocom_CTRL_Types all;
49
Harald Welted86cdc62017-11-22 00:45:07 +010050modulepar {
Harald Welte92632e12017-11-25 02:31:20 +010051 /* Use Osmocom extended IPA mux header */
52 boolean mp_ipa_mgcp_uses_osmo_ext := true;
Harald Welted86cdc62017-11-22 00:45:07 +010053}
Harald Welted86cdc62017-11-22 00:45:07 +010054
Harald Welteb3414b22017-11-23 18:22:10 +010055type enumerated IpaMode {
56 IPA_MODE_CLIENT,
57 IPA_MODE_SERVER
58}
59
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +020060type enumerated IpaInitBehavior {
61 IPA_INIT_SEND_IPA_ID_GET,
62 IPA_INIT_SEND_IPA_ID_ACK
63}
64
Harald Weltec76f29f2017-11-22 12:46:46 +010065type record ASP_IPA_Unitdata {
66 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010067 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010068 octetstring payload
69}
70
Harald Welte0d846a72017-12-07 17:58:28 +010071type enumerated ASP_IPA_EventUpDown {
72 ASP_IPA_EVENT_DOWN,
73 ASP_IPA_EVENT_UP,
74 ASP_IPA_EVENT_ID_ACK
75}
76
Harald Weltebdb63702017-12-09 01:15:44 +010077/* an event indicating us whether or not a connection is physically up or down,
78 * and whether we have received an ID_ACK */
Harald Welte0d846a72017-12-07 17:58:28 +010079type union ASP_IPA_Event {
80 ASP_IPA_EventUpDown up_down
81}
82
83template ASP_IPA_Event t_ASP_IPA_EVT_UD(ASP_IPA_EventUpDown ud) := {
84 up_down := ud
85}
86
Harald Welte1dd8f372017-11-25 02:25:27 +010087template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
88 template IpaExtStreamId esid := omit) := {
89 streamId := sid,
90 streamIdExt := esid,
91 payload := pl
92}
93
Harald Weltedf277252018-02-20 15:49:30 +010094#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +010095/* like ASP_IPA_Unitdata, but with RSL_Message abstract type instead of octetstring */
Harald Welte0d846a72017-12-07 17:58:28 +010096type record ASP_RSL_Unitdata {
97 IpaStreamId streamId,
98 RSL_Message rsl
99};
100
Harald Welte7ae019e2017-12-09 00:54:15 +0100101template ASP_RSL_Unitdata ts_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
Harald Welte0d846a72017-12-07 17:58:28 +0100102 streamId := sid,
103 rsl := valueof(rsl)
104}
105
Harald Welte7ae019e2017-12-09 00:54:15 +0100106template ASP_RSL_Unitdata tr_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
107 streamId := sid,
108 rsl := rsl
109}
110
Harald Welte0d846a72017-12-07 17:58:28 +0100111template IpaStreamId t_IpaSidRSL := ( IPAC_PROTO_RSL_TRX0, IPAC_PROTO_RSL_TRX1,
112 IPAC_PROTO_RSL_TRX2, IPAC_PROTO_RSL_TRX3 );
Harald Weltedf277252018-02-20 15:49:30 +0100113#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100114
Harald Weltebdb63702017-12-09 01:15:44 +0100115/* Client port for general IPA messages, not further decoded */
Harald Weltec76f29f2017-11-22 12:46:46 +0100116type port IPA_SP_PT message {
Harald Welte0d846a72017-12-07 17:58:28 +0100117 inout ASP_IPA_Unitdata, ASP_IPA_Event;
Harald Weltec76f29f2017-11-22 12:46:46 +0100118} with { extension "internal" }
119
Harald Weltedf277252018-02-20 15:49:30 +0100120#ifdef IPA_EMULATION_MGCP
Harald Weltebdb63702017-12-09 01:15:44 +0100121/* Client port for MGCP inside IPA */
Harald Weltec82eef42017-11-24 20:40:12 +0100122type port IPA_MGCP_PT message {
123 inout MgcpCommand, MgcpResponse;
124} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100125#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100126
Harald Weltedf277252018-02-20 15:49:30 +0100127#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +0100128/* Client port for A-bis RSL inside IPA */
Harald Welte0d846a72017-12-07 17:58:28 +0100129type port IPA_RSL_PT message {
130 inout ASP_RSL_Unitdata, ASP_IPA_Event;
131} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100132#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100133
Harald Weltea76c4bb2017-12-09 02:06:07 +0100134/* Client port for CTRL inside IPA */
135type port IPA_CTRL_PT message {
136 inout CtrlMessage, ASP_IPA_Event;
137} with { extension "internal" }
138
Harald Weltedf277252018-02-20 15:49:30 +0100139#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100140/* Client port for CTRL inside IPA */
141type port IPA_GSUP_PT message {
142 inout GSUP_PDU, ASP_IPA_Event;
143} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100144#endif
Harald Weltedf327232017-12-28 22:51:51 +0100145
Harald Welte7460a722018-10-10 12:28:27 +0200146#ifdef IPA_EMULATION_RSPRO
147type port IPA_RSPRO_PT message {
148 inout RsproPDU, ASP_IPA_Event;
149} with { extension "internal" }
150#endif
151
152
153
Harald Weltedf327232017-12-28 22:51:51 +0100154
Harald Welted86cdc62017-11-22 00:45:07 +0100155type component IPA_Emulation_CT {
156 /* down-facing port to IPA codec port */
157 port IPA_CODEC_PT IPA_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100158#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100159 /* up-facing port to SCCP */
160 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100161#endif
162#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100163 /* up-facing port for MGCP */
164 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100165#endif
166#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100167 /* up-facing port for RSL */
168 port IPA_RSL_PT IPA_RSL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100169#endif
Harald Weltea76c4bb2017-12-09 02:06:07 +0100170 /* up-facing port for CTRL */
171 port IPA_CTRL_PT IPA_CTRL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100172#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100173 /* up-facing port for GSUP */
174 port IPA_GSUP_PT IPA_GSUP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100175#endif
Harald Welte7460a722018-10-10 12:28:27 +0200176#ifdef IPA_EMULATION_RSPRO
177 /* up-facing port for RSPRO */
178 port IPA_RSPRO_PT IPA_RSPRO_PORT;
179#endif
Harald Weltedf327232017-12-28 22:51:51 +0100180
Harald Weltec76f29f2017-11-22 12:46:46 +0100181 /* up-facing port for other streams */
182 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +0100183
184 var boolean g_initialized := false;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100185 var IPL4asp_Types.ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +0100186 /* Are we a BSC/MGW (truel) or MSC (false) */
187 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +0100188
189 var IpaMode g_mode;
Harald Welte2d86aff2018-04-17 11:23:04 +0200190 var boolean g_ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200191 var IpaInitBehavior g_init_behavior;
Harald Weltee09921f2017-12-07 17:49:00 +0100192 var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +0100193}
194
Harald Weltee21096d2017-12-04 20:45:12 +0100195type record IPA_CCM_Parameters {
196 charstring ser_nr optional,
197 charstring name optional,
198 charstring location1 optional,
199 charstring location2 optional,
200 charstring equip_version optional,
201 charstring sw_version optional,
202 charstring ip_addr optional,
203 charstring mac_addr optional,
204 charstring unit_id optional,
205 charstring osmo_rand optional
206}
207
Harald Weltee09921f2017-12-07 17:49:00 +0100208const IPA_CCM_Parameters c_IPA_default_ccm_pars := {
209 ser_nr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100210 name := "mahlzeit",
Harald Weltee09921f2017-12-07 17:49:00 +0100211 location1 := "",
212 location2 := "",
213 equip_version := "",
214 sw_version := "",
215 ip_addr := "",
216 mac_addr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100217 unit_id := "0/1/2",
Harald Weltee09921f2017-12-07 17:49:00 +0100218 osmo_rand := ""
Harald Weltee21096d2017-12-04 20:45:12 +0100219};
220
Harald Weltebdb63702017-12-09 01:15:44 +0100221/* Function to use to connect as client to a remote IPA Server */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100222function f_connect(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
223 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100224 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100225 var IPL4asp_Types.Result res;
Harald Welted86cdc62017-11-22 00:45:07 +0100226 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
227 local_host, local_port, 0, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200228 if (not ispresent(res.connId)) {
Stefan Sperling6a90be42018-08-31 15:05:39 +0200229 setverdict(fail, "Could not connect IPA socket from ", local_host, " port ", local_port,
230 " to ", remote_host, " port ", remote_port, "; check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200231 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200232 }
Harald Welted86cdc62017-11-22 00:45:07 +0100233 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100234 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100235 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100236}
237
Harald Weltebdb63702017-12-09 01:15:44 +0100238/* Function to use to bind to a local port as IPA server, accepting remote clients */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100239function f_bind(charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100240 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100241 var IPL4asp_Types.Result res;
Harald Welteb3414b22017-11-23 18:22:10 +0100242 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
243 local_host, local_port, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200244 if (not ispresent(res.connId)) {
245 setverdict(fail, "Could not listen IPA socket, check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200246 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200247 }
Harald Welteb3414b22017-11-23 18:22:10 +0100248 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100249 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100250 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100251}
252
Harald Weltedf277252018-02-20 15:49:30 +0100253#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100254template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
255 sio := { '10'B, '00'B, '0011'B },
256 opc := opc,
257 dpc := 0,
258 sls := 0,
259 data := data
260}
Harald Weltedf277252018-02-20 15:49:30 +0100261#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100262
263
264private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
265 len := 0, /* overwritten by codec */
266 tag := tag,
Harald Welte95686e02018-08-02 15:05:43 +0200267 data := char2oct(payload) & '00'O
Harald Welted86cdc62017-11-22 00:45:07 +0100268}
269
Harald Welte0d846a72017-12-07 17:58:28 +0100270private function f_send_IPA_EVT(template ASP_IPA_Event evt) runs on IPA_Emulation_CT {
Harald Welte2e32e432018-05-24 20:00:00 +0200271 if (IPA_SP_PORT.checkstate("Connected")) {
272 IPA_SP_PORT.send(evt);
273 }
Harald Weltedf277252018-02-20 15:49:30 +0100274#ifdef IPA_EMULATION_RSL
Harald Welte5819b552017-12-09 02:55:46 +0100275 if (IPA_RSL_PORT.checkstate("Connected")) {
276 IPA_RSL_PORT.send(evt);
277 }
Harald Weltedf277252018-02-20 15:49:30 +0100278#endif
Harald Welte5819b552017-12-09 02:55:46 +0100279 if (IPA_CTRL_PORT.checkstate("Connected")) {
280 IPA_CTRL_PORT.send(evt);
281 }
Harald Weltedf277252018-02-20 15:49:30 +0100282#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100283 if (IPA_GSUP_PORT.checkstate("Connected")) {
284 IPA_GSUP_PORT.send(evt);
285 }
Harald Weltedf277252018-02-20 15:49:30 +0100286#endif
Harald Welte7460a722018-10-10 12:28:27 +0200287#ifdef IPA_EMULATION_RSPRO
288 if (IPA_RSPRO_PORT.checkstate("Connected")) {
289 IPA_RSPRO_PORT.send(evt);
290 }
291#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100292 /* FIXME: to other ports */
293}
294
Harald Welted86cdc62017-11-22 00:45:07 +0100295/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100296private function f_ccm_make_id_resp(PDU_IPA_CCM get) runs on IPA_Emulation_CT return PDU_IPA_CCM {
Harald Welted86cdc62017-11-22 00:45:07 +0100297 var integer i;
298 var PDU_IPA_CCM resp := {
299 msg_type := IPAC_MSGT_ID_RESP,
300 u := {
301 resp := {}
302 }
303 }
304
305 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
306 var IpaCcmIdTag tag := get.u.get[i].tag;
307 var charstring foo;
308 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100309 case (IPAC_IDTAG_SERNR) {
310 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100311 }
312 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100313 foo := g_ccm_pars.name;
314 }
315 case (IPAC_IDTAG_LOCATION1) {
316 foo := g_ccm_pars.location1;
317 }
318 case (IPAC_IDTAG_LOCATION2) {
319 foo := g_ccm_pars.location2;
320 }
321 case (IPAC_IDTAG_EQUIPVERS) {
322 foo := g_ccm_pars.equip_version;
323 }
324 case (IPAC_IDTAG_SWVERSION) {
325 foo := g_ccm_pars.sw_version;
326 }
327 case (IPAC_IDTAG_IPADDR) {
328 foo := g_ccm_pars.ip_addr;
329 }
330 case (IPAC_IDTAG_MACADDR) {
331 foo := g_ccm_pars.mac_addr;
332 }
333 case (IPAC_IDTAG_UNIT) {
334 foo := g_ccm_pars.unit_id;
335 }
336 case (IPAC_IDTAG_OSMO_RAND) {
337 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100338 }
339 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100340 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100341 }
342 }
343 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
344 }
345
346 return resp;
347}
348
349/* transmit IPA CCM message */
350private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100351 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_CCM, enc_PDU_IPA_CCM(ccm)));
Harald Welted86cdc62017-11-22 00:45:07 +0100352 log("CCM Tx:", ccm);
353 IPA_PORT.send(ipa_tx);
354}
355
356template PDU_IPA_CCM ts_IPA_PONG := {
357 msg_type := IPAC_MSGT_PONG,
358 u := omit
359}
360
361template PDU_IPA_CCM ts_IPA_ACK := {
362 msg_type := IPAC_MSGT_ID_ACK,
363 u := omit
364}
365
Harald Welteb3414b22017-11-23 18:22:10 +0100366template PDU_IPA_CCM ts_IPA_ID_GET := {
367 msg_type := IPAC_MSGT_ID_GET,
368 u := {
369 get := {
370 { 1, IPAC_IDTAG_UNITNAME }
371 }
372 }
373}
374
Harald Welted86cdc62017-11-22 00:45:07 +0100375/* receive IPA CCM message */
Harald Welte2d86aff2018-04-17 11:23:04 +0200376private function f_ccm_rx_client(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100377 select (ccm.msg_type) {
378 case (IPAC_MSGT_PING) {
379 f_ccm_tx(valueof(ts_IPA_PONG));
380 }
381 case (IPAC_MSGT_ID_ACK) {
Harald Welte2d86aff2018-04-17 11:23:04 +0200382 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welted86cdc62017-11-22 00:45:07 +0100383 }
384 case (IPAC_MSGT_ID_GET) {
385 f_ccm_tx(f_ccm_make_id_resp(ccm));
386 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200387 case else {
388 log("Unknown/unsupported IPA CCM message type", ccm);
389 }
390 }
391}
392
393private function f_ccm_rx_server(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
394 select (ccm.msg_type) {
395 case (IPAC_MSGT_PING) {
396 f_ccm_tx(valueof(ts_IPA_PONG));
397 }
398 case (IPAC_MSGT_ID_ACK) {
399 /* the IPA server should at some point receive an ID_ACK from the client,
400 * in case of RSL/OML from nanoBTS, this is actually the first message after
401 * the TCP connection is established. Other implementations may differ.
402 * We currently ignore it completely - but actually we should make sure that
403 * one ID_ACK is received by the server at some point */
Harald Welte2e32e432018-05-24 20:00:00 +0200404 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welte2d86aff2018-04-17 11:23:04 +0200405 }
Harald Welte3bc387f2018-02-21 12:18:46 +0100406 case (IPAC_MSGT_ID_RESP) {
407 log("IPA ID RESP: ", ccm.u.resp);
Harald Welte2d86aff2018-04-17 11:23:04 +0200408 /* acknowledge any identity that the client may have sent */
409 f_ccm_tx(valueof(ts_IPA_ACK));
Harald Welte3bc387f2018-02-21 12:18:46 +0100410 }
Harald Welted86cdc62017-11-22 00:45:07 +0100411 case else {
412 log("Unknown/unsupported IPA CCM message type", ccm);
413 }
414 }
415}
416
Harald Weltec76f29f2017-11-22 12:46:46 +0100417private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
418 var ASP_IPA_Unitdata ret := {
419 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100420 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100421 payload := ipa_rx.msg
422 }
423 return ret;
424}
425
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100426private function f_from_asp(IPL4asp_Types.ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100427 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
428 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100429 return ret;
430}
Harald Welted86cdc62017-11-22 00:45:07 +0100431
Harald Weltedf277252018-02-20 15:49:30 +0100432#ifdef IPA_EMULATION_RSL
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100433private function f_from_rsl(IPL4asp_Types.ConnectionId connId, ASP_RSL_Unitdata rsl_tx) return IPA_Send {
Harald Welte0d846a72017-12-07 17:58:28 +0100434 var octetstring payload := enc_RSL_Message(rsl_tx.rsl);
435 var IPA_Send ret := valueof(t_IPA_Send(connId, rsl_tx.streamId, payload));
436 return ret;
437}
Harald Weltedf277252018-02-20 15:49:30 +0100438#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100439
Harald Weltebdb63702017-12-09 01:15:44 +0100440/* main function to use for a client-side IPA implementation */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100441function main_client(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
442 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Welte2d86aff2018-04-17 11:23:04 +0200443 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars,
444 boolean ccm_enabled := true) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100445 g_mode := IPA_MODE_CLIENT;
Harald Welte2d86aff2018-04-17 11:23:04 +0200446 g_ccm_enabled := ccm_enabled;
Harald Weltee09921f2017-12-07 17:49:00 +0100447 f_connect(remote_host, remote_port, local_host, local_port, ccm_pars);
Harald Welte2d86aff2018-04-17 11:23:04 +0200448 if (g_ccm_enabled) {
449 /* we're a client: Send ID_ACK immediately after connect */
450 f_ccm_tx(valueof(ts_IPA_ACK));
451 }
Harald Welte03c0e562017-12-09 02:55:12 +0100452 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welteb3414b22017-11-23 18:22:10 +0100453 ScanEvents();
454}
455
Harald Weltebdb63702017-12-09 01:15:44 +0100456/* main function to use for a server-side IPA implementation */
Harald Welte2d86aff2018-04-17 11:23:04 +0200457function main_server(charstring local_host, IPL4asp_Types.PortNumber local_port,
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200458 boolean ccm_enabled := true,
459 IpaInitBehavior init_behavior := IPA_INIT_SEND_IPA_ID_GET)
460runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100461 g_mode := IPA_MODE_SERVER;
Harald Welte2d86aff2018-04-17 11:23:04 +0200462 g_ccm_enabled := ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200463 g_init_behavior := init_behavior;
Harald Welteb3414b22017-11-23 18:22:10 +0100464 f_bind(local_host, local_port);
465 ScanEvents();
466}
467
Harald Weltedf277252018-02-20 15:49:30 +0100468private function f_ctrl_to_user(octetstring msg) runs on IPA_Emulation_CT {
469 var charstring msg_ch := oct2char(msg);
470 IPA_CTRL_PORT.send(dec_CtrlMessage(msg_ch));
471}
472
473#ifdef IPA_EMULATION_GSUP
474private function f_gsup_to_user(octetstring msg) runs on IPA_Emulation_CT {
475 var GSUP_PDU gsup := dec_GSUP_PDU(msg);
476 f_gsup_postprocess_decoded(gsup);
477 IPA_GSUP_PORT.send(gsup);
478}
479#endif
480
Harald Welte7460a722018-10-10 12:28:27 +0200481#ifdef IPA_EMULATION_RSPRO
482private function f_rspro_to_user(octetstring msg) runs on IPA_Emulation_CT {
483 var RsproPDU rspro := dec_RsproPDU(msg);
484 IPA_RSPRO_PORT.send(rspro);
485}
486#endif
487
Harald Weltedf277252018-02-20 15:49:30 +0100488#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100489private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
490 var charstring msg_ch := oct2char(msg);
491 if (g_is_bsc_mgw) {
492 log("============");
493 log(msg_ch);
494 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
495 } else {
496 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
497 }
498}
499
Harald Welte92632e12017-11-25 02:31:20 +0100500private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
501 if (mp_ipa_mgcp_uses_osmo_ext) {
502 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
503 } else {
504 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
505 }
506}
Harald Weltedf277252018-02-20 15:49:30 +0100507#endif
Harald Welte92632e12017-11-25 02:31:20 +0100508
Harald Weltebdb63702017-12-09 01:15:44 +0100509/* main loop function for both client and server. 'thread' of the component */
Harald Welteb3414b22017-11-23 18:22:10 +0100510private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100511 var IPA_RecvFrom ipa_rx;
Harald Welteb3414b22017-11-23 18:22:10 +0100512 var ASP_Event asp_evt;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100513 var Socket_API_Definitions.PortEvent port_evt;
Harald Weltedf277252018-02-20 15:49:30 +0100514 var octetstring payload;
515 var CtrlMessage ctrl_msg;
516 var ASP_IPA_Unitdata ipa_ud;
517#ifdef IPA_EMULATION_SCCP
518 var ASP_MTP3_TRANSFERreq mtp_req;
519#endif
520#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100521 var MgcpCommand mgcp_cmd;
522 var MgcpResponse mgcp_rsp;
Harald Weltedf277252018-02-20 15:49:30 +0100523#endif
524#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100525 var GSUP_PDU gsup_msg;
Harald Weltedf277252018-02-20 15:49:30 +0100526#endif
527#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100528 var ASP_RSL_Unitdata rsl;
Harald Weltedf277252018-02-20 15:49:30 +0100529#endif
Harald Welte7460a722018-10-10 12:28:27 +0200530#ifdef IPA_EMULATION_RSPRO
531 var RsproPDU rspro;
532#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100533
Harald Welte3e6ad892017-12-12 14:39:46 +0100534 /* Set function for dissecting the binary */
535 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
536 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
537
Harald Welted86cdc62017-11-22 00:45:07 +0100538 while (true) {
539 alt {
540 /* Received IPA -> up into SCCP stack */
Harald Welte2d86aff2018-04-17 11:23:04 +0200541 [g_ccm_enabled] IPA_PORT.receive(IPA_RecvFrom:{?,IPAC_PROTO_CCM,omit,?}) -> value ipa_rx {
542 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
543 log("CCM Rx:", ccm);
544 select (g_mode) {
545 case (IPA_MODE_CLIENT) {
546 f_ccm_rx_client(ccm);
547 }
548 case (IPA_MODE_SERVER) {
549 f_ccm_rx_server(ccm);
550 }
551 case else {
552 setverdict(fail, "Unknown mode");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200553 mtc.stop;
Harald Welte2d86aff2018-04-17 11:23:04 +0200554 }
Harald Weltedf277252018-02-20 15:49:30 +0100555 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200556 }
557 [] IPA_PORT.receive(IPA_RecvFrom:?) -> value ipa_rx {
558 select (ipa_rx.streamId) {
Harald Weltedf277252018-02-20 15:49:30 +0100559#ifdef IPA_EMULATION_SCCP
560 case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100561 var ASP_MTP3_TRANSFERind mtp;
562 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
563 MTP3_SP_PORT.send(mtp);
Harald Weltedf277252018-02-20 15:49:30 +0100564 }
565#endif
566#ifdef IPA_EMULATION_MGCP
567 case (IPAC_PROTO_MGCP_OLD) {
Harald Weltec82eef42017-11-24 20:40:12 +0100568 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100569 }
570#endif
571#ifdef IPA_EMULATION_RSL
572 case (t_IpaSidRSL) {
Harald Welte0d846a72017-12-07 17:58:28 +0100573 rsl := {
574 streamId := ipa_rx.streamId,
575 rsl := dec_RSL_Message(ipa_rx.msg)
576 };
577 IPA_RSL_PORT.send(rsl);
Harald Weltedf277252018-02-20 15:49:30 +0100578 }
579#endif
580 case (IPAC_PROTO_OSMO) {
Harald Weltec82eef42017-11-24 20:40:12 +0100581 select (ipa_rx.streamIdExt) {
Harald Weltedf277252018-02-20 15:49:30 +0100582#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100583 case (IPAC_PROTO_EXT_MGCP) {
584 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100585 }
586#endif
587 case (IPAC_PROTO_EXT_CTRL) {
Harald Weltea76c4bb2017-12-09 02:06:07 +0100588 f_ctrl_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100589 }
590#ifdef IPA_EMULATION_GSUP
591 case (IPAC_PROTO_EXT_GSUP) {
Harald Weltedf327232017-12-28 22:51:51 +0100592 f_gsup_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100593 }
594#endif
Harald Welte7460a722018-10-10 12:28:27 +0200595#ifdef IPA_EMULATION_RSPRO
596 case (IPAC_PROTO_EXT_RSPRO) {
597 f_rspro_to_user(ipa_rx.msg);
598 }
599#endif
Harald Weltedf277252018-02-20 15:49:30 +0100600 case else {
Harald Weltec82eef42017-11-24 20:40:12 +0100601 IPA_SP_PORT.send(f_to_asp(ipa_rx));
602 }
Harald Welted86cdc62017-11-22 00:45:07 +0100603 }
Harald Weltedf277252018-02-20 15:49:30 +0100604 }
605 case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100606 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100607 }
608 }
609 }
610
Harald Welteb3414b22017-11-23 18:22:10 +0100611 /* server only */
612 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
613 log("IPA: Connected");
614 g_ipa_conn_id := asp_evt.connOpened.connId;
Harald Welte0d846a72017-12-07 17:58:28 +0100615 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welte2d86aff2018-04-17 11:23:04 +0200616 if (g_mode == IPA_MODE_SERVER and g_ccm_enabled) {
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200617 select (g_init_behavior) {
618 case (IPA_INIT_SEND_IPA_ID_GET) {
619 f_ccm_tx(valueof(ts_IPA_ID_GET));
620 }
621 case (IPA_INIT_SEND_IPA_ID_ACK) {
622 f_ccm_tx(valueof(ts_IPA_ACK));
623 }
624 }
Harald Welteb3414b22017-11-23 18:22:10 +0100625 }
626 }
627
628 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
629 log("IPA: Closed");
630 g_ipa_conn_id := -1;
Harald Welte0d846a72017-12-07 17:58:28 +0100631 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
Harald Welteb3414b22017-11-23 18:22:10 +0100632 self.stop;
633 }
634
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100635 [] IPA_PORT.receive(Socket_API_Definitions.PortEvent:{result:={errorCode:=ERROR_SOCKET, connId:=?, os_error_code:=?, os_error_text:=?}}) -> value port_evt {
636 log("PortEvent: ERROR_SOCKET: ", port_evt);
637 g_ipa_conn_id := -1;
638 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
639 self.stop;
640 }
641
Harald Weltedf277252018-02-20 15:49:30 +0100642#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100643 /* Received SCCP -> down into IPA */
644 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100645 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
646 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100647 IPA_PORT.send(ipa_tx);
648 }
Harald Weltedf277252018-02-20 15:49:30 +0100649#endif
Harald Weltec76f29f2017-11-22 12:46:46 +0100650
Harald Weltedf277252018-02-20 15:49:30 +0100651#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100652 /* Received MGCP -> down into IPA */
653 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100654 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
655 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100656 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
657 }
658 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100659 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100660 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100661 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
662 }
Harald Weltedf277252018-02-20 15:49:30 +0100663#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100664
Harald Weltea76c4bb2017-12-09 02:06:07 +0100665 [] IPA_CTRL_PORT.receive(CtrlMessage:?) -> value ctrl_msg {
666 payload := char2oct(enc_CtrlMessage(ctrl_msg));
667 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_CTRL));
668 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
669 }
670
Harald Weltedf277252018-02-20 15:49:30 +0100671#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100672 [] IPA_GSUP_PORT.receive(GSUP_PDU:?) -> value gsup_msg {
Harald Welte2f562b12018-01-24 20:52:38 +0100673 f_gsup_preprocess_encoded(gsup_msg);
Harald Weltedf327232017-12-28 22:51:51 +0100674 payload := enc_GSUP_PDU(gsup_msg);
675 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_GSUP));
676 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
677 }
Harald Weltedf277252018-02-20 15:49:30 +0100678#endif
Harald Weltedf327232017-12-28 22:51:51 +0100679
Harald Welte7460a722018-10-10 12:28:27 +0200680#ifdef IPA_EMULATION_RSPRO
681 [] IPA_RSPRO_PORT.receive(RsproPDU:?) -> value rspro {
682 payload := enc_RsproPDU(rspro);
683 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_RSPRO));
684 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
685 }
686#endif
687
Harald Weltedf277252018-02-20 15:49:30 +0100688#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100689 /* Received RSL -> down into IPA */
690 [] IPA_RSL_PORT.receive(ASP_RSL_Unitdata:?) -> value rsl {
691 IPA_PORT.send(f_from_rsl(g_ipa_conn_id, rsl));
692 }
Harald Weltedf277252018-02-20 15:49:30 +0100693#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100694
695 /* Received MISC (OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100696 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
697 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
698 }
699
700
Harald Welted86cdc62017-11-22 00:45:07 +0100701 }
702 }
703}
704
Harald Welte2e32e432018-05-24 20:00:00 +0200705/***********************************************************************
706 * IPA Event waiter component. Wait for ASP_IPA_EVENT_ID_ACK
707 ***********************************************************************/
708
709type component IPA_EventWaiter_CT {
710 port IPA_SP_PT IPA_SP_PORT;
711}
712
713function waiter_main(template ASP_IPA_Event wait_for := t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK))
714runs on IPA_EventWaiter_CT {
715
716 alt {
717 [] IPA_SP_PORT.receive(wait_for) {
718 setverdict(pass);
719 }
720 [] IPA_SP_PORT.receive { repeat; }
721 }
722}
723
724
Harald Welted86cdc62017-11-22 00:45:07 +0100725}