blob: f5563276e84ccecf61b5f40796ea2af498648550 [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
Harald Weltec6826662019-02-06 22:26:46 +010034#ifdef IPA_EMULATION_OML
35import from AbisOML_Types all;
36#endif
37
Harald Weltedf277252018-02-20 15:49:30 +010038#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +010039import from MGCP_Types all;
Harald Weltedf277252018-02-20 15:49:30 +010040#endif
41
42#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +010043import from GSUP_Types all;
Harald Weltedf277252018-02-20 15:49:30 +010044#endif
Harald Weltec82eef42017-11-24 20:40:12 +010045
Harald Welte7460a722018-10-10 12:28:27 +020046#ifdef IPA_EMULATION_RSPRO
47import from RSPRO all;
48import from RSPRO_Types all;
49#endif
50
51
Harald Weltea76c4bb2017-12-09 02:06:07 +010052import from Osmocom_CTRL_Types all;
53
Harald Welted86cdc62017-11-22 00:45:07 +010054modulepar {
Harald Welte92632e12017-11-25 02:31:20 +010055 /* Use Osmocom extended IPA mux header */
56 boolean mp_ipa_mgcp_uses_osmo_ext := true;
Harald Welted86cdc62017-11-22 00:45:07 +010057}
Harald Welted86cdc62017-11-22 00:45:07 +010058
Harald Welteb3414b22017-11-23 18:22:10 +010059type enumerated IpaMode {
60 IPA_MODE_CLIENT,
61 IPA_MODE_SERVER
62}
63
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +020064type enumerated IpaInitBehavior {
65 IPA_INIT_SEND_IPA_ID_GET,
66 IPA_INIT_SEND_IPA_ID_ACK
67}
68
Harald Weltec76f29f2017-11-22 12:46:46 +010069type record ASP_IPA_Unitdata {
70 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010071 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010072 octetstring payload
73}
74
Harald Welte0d846a72017-12-07 17:58:28 +010075type enumerated ASP_IPA_EventUpDown {
76 ASP_IPA_EVENT_DOWN,
77 ASP_IPA_EVENT_UP,
78 ASP_IPA_EVENT_ID_ACK
79}
80
Harald Weltebdb63702017-12-09 01:15:44 +010081/* an event indicating us whether or not a connection is physically up or down,
82 * and whether we have received an ID_ACK */
Harald Welte0d846a72017-12-07 17:58:28 +010083type union ASP_IPA_Event {
84 ASP_IPA_EventUpDown up_down
85}
86
87template ASP_IPA_Event t_ASP_IPA_EVT_UD(ASP_IPA_EventUpDown ud) := {
88 up_down := ud
89}
90
Harald Welte1dd8f372017-11-25 02:25:27 +010091template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
92 template IpaExtStreamId esid := omit) := {
93 streamId := sid,
94 streamIdExt := esid,
95 payload := pl
96}
97
Harald Weltedf277252018-02-20 15:49:30 +010098#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +010099/* like ASP_IPA_Unitdata, but with RSL_Message abstract type instead of octetstring */
Harald Welte0d846a72017-12-07 17:58:28 +0100100type record ASP_RSL_Unitdata {
101 IpaStreamId streamId,
102 RSL_Message rsl
103};
104
Harald Welte7ae019e2017-12-09 00:54:15 +0100105template ASP_RSL_Unitdata ts_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
Harald Welte0d846a72017-12-07 17:58:28 +0100106 streamId := sid,
107 rsl := valueof(rsl)
108}
109
Harald Welte7ae019e2017-12-09 00:54:15 +0100110template ASP_RSL_Unitdata tr_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
111 streamId := sid,
112 rsl := rsl
113}
114
Harald Welte0d846a72017-12-07 17:58:28 +0100115template IpaStreamId t_IpaSidRSL := ( IPAC_PROTO_RSL_TRX0, IPAC_PROTO_RSL_TRX1,
116 IPAC_PROTO_RSL_TRX2, IPAC_PROTO_RSL_TRX3 );
Harald Weltedf277252018-02-20 15:49:30 +0100117#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100118
Harald Weltec6826662019-02-06 22:26:46 +0100119
Harald Weltebdb63702017-12-09 01:15:44 +0100120/* Client port for general IPA messages, not further decoded */
Harald Weltec76f29f2017-11-22 12:46:46 +0100121type port IPA_SP_PT message {
Harald Welte0d846a72017-12-07 17:58:28 +0100122 inout ASP_IPA_Unitdata, ASP_IPA_Event;
Harald Weltec76f29f2017-11-22 12:46:46 +0100123} with { extension "internal" }
124
Harald Weltedf277252018-02-20 15:49:30 +0100125#ifdef IPA_EMULATION_MGCP
Harald Weltebdb63702017-12-09 01:15:44 +0100126/* Client port for MGCP inside IPA */
Harald Weltec82eef42017-11-24 20:40:12 +0100127type port IPA_MGCP_PT message {
128 inout MgcpCommand, MgcpResponse;
129} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100130#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100131
Harald Weltedf277252018-02-20 15:49:30 +0100132#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +0100133/* Client port for A-bis RSL inside IPA */
Harald Welte0d846a72017-12-07 17:58:28 +0100134type port IPA_RSL_PT message {
135 inout ASP_RSL_Unitdata, ASP_IPA_Event;
136} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100137#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100138
Harald Weltec6826662019-02-06 22:26:46 +0100139#ifdef IPA_EMULATION_OML
140/* Client port for A-bis OML inside IPA */
141type port IPA_OML_PT message {
142 inout OML_PDU, octetstring, ASP_IPA_Event;
143} with { extension "internal" }
144#endif
145
Harald Weltea76c4bb2017-12-09 02:06:07 +0100146/* Client port for CTRL inside IPA */
147type port IPA_CTRL_PT message {
148 inout CtrlMessage, ASP_IPA_Event;
149} with { extension "internal" }
150
Harald Weltedf277252018-02-20 15:49:30 +0100151#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100152/* Client port for CTRL inside IPA */
153type port IPA_GSUP_PT message {
154 inout GSUP_PDU, ASP_IPA_Event;
155} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100156#endif
Harald Weltedf327232017-12-28 22:51:51 +0100157
Harald Welte7460a722018-10-10 12:28:27 +0200158#ifdef IPA_EMULATION_RSPRO
159type port IPA_RSPRO_PT message {
160 inout RsproPDU, ASP_IPA_Event;
161} with { extension "internal" }
162#endif
163
164
165
Harald Weltedf327232017-12-28 22:51:51 +0100166
Harald Welted86cdc62017-11-22 00:45:07 +0100167type component IPA_Emulation_CT {
168 /* down-facing port to IPA codec port */
169 port IPA_CODEC_PT IPA_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100170#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100171 /* up-facing port to SCCP */
172 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100173#endif
174#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100175 /* up-facing port for MGCP */
176 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100177#endif
178#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100179 /* up-facing port for RSL */
180 port IPA_RSL_PT IPA_RSL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100181#endif
Harald Weltec6826662019-02-06 22:26:46 +0100182#ifdef IPA_EMULATION_OML
183 /* up-facing port for OML */
184 port IPA_OML_PT IPA_OML_PORT;
185#endif
Harald Weltea76c4bb2017-12-09 02:06:07 +0100186 /* up-facing port for CTRL */
187 port IPA_CTRL_PT IPA_CTRL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100188#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100189 /* up-facing port for GSUP */
190 port IPA_GSUP_PT IPA_GSUP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100191#endif
Harald Welte7460a722018-10-10 12:28:27 +0200192#ifdef IPA_EMULATION_RSPRO
193 /* up-facing port for RSPRO */
194 port IPA_RSPRO_PT IPA_RSPRO_PORT;
195#endif
Harald Weltedf327232017-12-28 22:51:51 +0100196
Harald Weltec76f29f2017-11-22 12:46:46 +0100197 /* up-facing port for other streams */
198 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +0100199
200 var boolean g_initialized := false;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100201 var IPL4asp_Types.ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +0100202 /* Are we a BSC/MGW (truel) or MSC (false) */
203 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +0100204
205 var IpaMode g_mode;
Harald Welte2d86aff2018-04-17 11:23:04 +0200206 var boolean g_ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200207 var IpaInitBehavior g_init_behavior;
Harald Weltee09921f2017-12-07 17:49:00 +0100208 var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +0100209}
210
Harald Weltee21096d2017-12-04 20:45:12 +0100211type record IPA_CCM_Parameters {
212 charstring ser_nr optional,
213 charstring name optional,
214 charstring location1 optional,
215 charstring location2 optional,
216 charstring equip_version optional,
217 charstring sw_version optional,
218 charstring ip_addr optional,
219 charstring mac_addr optional,
220 charstring unit_id optional,
221 charstring osmo_rand optional
222}
223
Harald Weltee09921f2017-12-07 17:49:00 +0100224const IPA_CCM_Parameters c_IPA_default_ccm_pars := {
225 ser_nr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100226 name := "mahlzeit",
Harald Weltee09921f2017-12-07 17:49:00 +0100227 location1 := "",
228 location2 := "",
229 equip_version := "",
230 sw_version := "",
231 ip_addr := "",
232 mac_addr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100233 unit_id := "0/1/2",
Harald Weltee09921f2017-12-07 17:49:00 +0100234 osmo_rand := ""
Harald Weltee21096d2017-12-04 20:45:12 +0100235};
236
Harald Weltebdb63702017-12-09 01:15:44 +0100237/* Function to use to connect as client to a remote IPA Server */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100238function f_connect(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
239 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 Welted86cdc62017-11-22 00:45:07 +0100242 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
243 local_host, local_port, 0, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200244 if (not ispresent(res.connId)) {
Stefan Sperling6a90be42018-08-31 15:05:39 +0200245 setverdict(fail, "Could not connect IPA socket from ", local_host, " port ", local_port,
246 " to ", remote_host, " port ", remote_port, "; check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200247 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200248 }
Harald Welted86cdc62017-11-22 00:45:07 +0100249 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100250 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100251 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100252}
253
Harald Weltebdb63702017-12-09 01:15:44 +0100254/* Function to use to bind to a local port as IPA server, accepting remote clients */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100255function f_bind(charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100256 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100257 var IPL4asp_Types.Result res;
Harald Welteb3414b22017-11-23 18:22:10 +0100258 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
259 local_host, local_port, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200260 if (not ispresent(res.connId)) {
261 setverdict(fail, "Could not listen IPA socket, check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200262 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200263 }
Harald Welteb3414b22017-11-23 18:22:10 +0100264 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100265 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100266 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100267}
268
Harald Weltedf277252018-02-20 15:49:30 +0100269#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100270template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
271 sio := { '10'B, '00'B, '0011'B },
272 opc := opc,
273 dpc := 0,
274 sls := 0,
275 data := data
276}
Harald Weltedf277252018-02-20 15:49:30 +0100277#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100278
279
280private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
281 len := 0, /* overwritten by codec */
282 tag := tag,
Harald Welte95686e02018-08-02 15:05:43 +0200283 data := char2oct(payload) & '00'O
Harald Welted86cdc62017-11-22 00:45:07 +0100284}
285
Harald Welte0d846a72017-12-07 17:58:28 +0100286private function f_send_IPA_EVT(template ASP_IPA_Event evt) runs on IPA_Emulation_CT {
Harald Welte2e32e432018-05-24 20:00:00 +0200287 if (IPA_SP_PORT.checkstate("Connected")) {
288 IPA_SP_PORT.send(evt);
289 }
Harald Weltedf277252018-02-20 15:49:30 +0100290#ifdef IPA_EMULATION_RSL
Harald Welte5819b552017-12-09 02:55:46 +0100291 if (IPA_RSL_PORT.checkstate("Connected")) {
292 IPA_RSL_PORT.send(evt);
293 }
Harald Weltedf277252018-02-20 15:49:30 +0100294#endif
Harald Weltec6826662019-02-06 22:26:46 +0100295#ifdef IPA_EMULATION_OML
296 if (IPA_OML_PORT.checkstate("Connected")) {
297 IPA_OML_PORT.send(evt);
298 }
299#endif
Harald Welte5819b552017-12-09 02:55:46 +0100300 if (IPA_CTRL_PORT.checkstate("Connected")) {
301 IPA_CTRL_PORT.send(evt);
302 }
Harald Weltedf277252018-02-20 15:49:30 +0100303#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100304 if (IPA_GSUP_PORT.checkstate("Connected")) {
305 IPA_GSUP_PORT.send(evt);
306 }
Harald Weltedf277252018-02-20 15:49:30 +0100307#endif
Harald Welte7460a722018-10-10 12:28:27 +0200308#ifdef IPA_EMULATION_RSPRO
309 if (IPA_RSPRO_PORT.checkstate("Connected")) {
310 IPA_RSPRO_PORT.send(evt);
311 }
312#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100313 /* FIXME: to other ports */
314}
315
Harald Welted86cdc62017-11-22 00:45:07 +0100316/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100317private 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 +0100318 var integer i;
319 var PDU_IPA_CCM resp := {
320 msg_type := IPAC_MSGT_ID_RESP,
321 u := {
322 resp := {}
323 }
324 }
325
326 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
327 var IpaCcmIdTag tag := get.u.get[i].tag;
328 var charstring foo;
329 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100330 case (IPAC_IDTAG_SERNR) {
331 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100332 }
333 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100334 foo := g_ccm_pars.name;
335 }
336 case (IPAC_IDTAG_LOCATION1) {
337 foo := g_ccm_pars.location1;
338 }
339 case (IPAC_IDTAG_LOCATION2) {
340 foo := g_ccm_pars.location2;
341 }
342 case (IPAC_IDTAG_EQUIPVERS) {
343 foo := g_ccm_pars.equip_version;
344 }
345 case (IPAC_IDTAG_SWVERSION) {
346 foo := g_ccm_pars.sw_version;
347 }
348 case (IPAC_IDTAG_IPADDR) {
349 foo := g_ccm_pars.ip_addr;
350 }
351 case (IPAC_IDTAG_MACADDR) {
352 foo := g_ccm_pars.mac_addr;
353 }
354 case (IPAC_IDTAG_UNIT) {
355 foo := g_ccm_pars.unit_id;
356 }
357 case (IPAC_IDTAG_OSMO_RAND) {
358 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100359 }
360 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100361 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100362 }
363 }
364 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
365 }
366
367 return resp;
368}
369
370/* transmit IPA CCM message */
371private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100372 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 +0100373 log("CCM Tx:", ccm);
374 IPA_PORT.send(ipa_tx);
375}
376
377template PDU_IPA_CCM ts_IPA_PONG := {
378 msg_type := IPAC_MSGT_PONG,
379 u := omit
380}
381
382template PDU_IPA_CCM ts_IPA_ACK := {
383 msg_type := IPAC_MSGT_ID_ACK,
384 u := omit
385}
386
Harald Welteb3414b22017-11-23 18:22:10 +0100387template PDU_IPA_CCM ts_IPA_ID_GET := {
388 msg_type := IPAC_MSGT_ID_GET,
389 u := {
390 get := {
391 { 1, IPAC_IDTAG_UNITNAME }
392 }
393 }
394}
395
Harald Welted86cdc62017-11-22 00:45:07 +0100396/* receive IPA CCM message */
Harald Welte2d86aff2018-04-17 11:23:04 +0200397private function f_ccm_rx_client(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100398 select (ccm.msg_type) {
399 case (IPAC_MSGT_PING) {
400 f_ccm_tx(valueof(ts_IPA_PONG));
401 }
402 case (IPAC_MSGT_ID_ACK) {
Harald Welte2d86aff2018-04-17 11:23:04 +0200403 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welted86cdc62017-11-22 00:45:07 +0100404 }
405 case (IPAC_MSGT_ID_GET) {
406 f_ccm_tx(f_ccm_make_id_resp(ccm));
407 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200408 case else {
409 log("Unknown/unsupported IPA CCM message type", ccm);
410 }
411 }
412}
413
414private function f_ccm_rx_server(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
415 select (ccm.msg_type) {
416 case (IPAC_MSGT_PING) {
417 f_ccm_tx(valueof(ts_IPA_PONG));
418 }
419 case (IPAC_MSGT_ID_ACK) {
420 /* the IPA server should at some point receive an ID_ACK from the client,
421 * in case of RSL/OML from nanoBTS, this is actually the first message after
422 * the TCP connection is established. Other implementations may differ.
423 * We currently ignore it completely - but actually we should make sure that
424 * one ID_ACK is received by the server at some point */
Harald Welte2e32e432018-05-24 20:00:00 +0200425 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welte2d86aff2018-04-17 11:23:04 +0200426 }
Harald Welte3bc387f2018-02-21 12:18:46 +0100427 case (IPAC_MSGT_ID_RESP) {
428 log("IPA ID RESP: ", ccm.u.resp);
Harald Welte2d86aff2018-04-17 11:23:04 +0200429 /* acknowledge any identity that the client may have sent */
430 f_ccm_tx(valueof(ts_IPA_ACK));
Harald Welte3bc387f2018-02-21 12:18:46 +0100431 }
Harald Welted86cdc62017-11-22 00:45:07 +0100432 case else {
433 log("Unknown/unsupported IPA CCM message type", ccm);
434 }
435 }
436}
437
Harald Weltec76f29f2017-11-22 12:46:46 +0100438private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
439 var ASP_IPA_Unitdata ret := {
440 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100441 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100442 payload := ipa_rx.msg
443 }
444 return ret;
445}
446
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100447private function f_from_asp(IPL4asp_Types.ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100448 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
449 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100450 return ret;
451}
Harald Welted86cdc62017-11-22 00:45:07 +0100452
Harald Weltedf277252018-02-20 15:49:30 +0100453#ifdef IPA_EMULATION_RSL
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100454private function f_from_rsl(IPL4asp_Types.ConnectionId connId, ASP_RSL_Unitdata rsl_tx) return IPA_Send {
Harald Welte0d846a72017-12-07 17:58:28 +0100455 var octetstring payload := enc_RSL_Message(rsl_tx.rsl);
456 var IPA_Send ret := valueof(t_IPA_Send(connId, rsl_tx.streamId, payload));
457 return ret;
458}
Harald Weltedf277252018-02-20 15:49:30 +0100459#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100460
Harald Weltec6826662019-02-06 22:26:46 +0100461#ifdef IPA_EMULATION_OML
462private function f_from_oml(IPL4asp_Types.ConnectionId connId, OML_PDU oml_tx) return IPA_Send {
463 var octetstring payload := enc_OML_PDU(oml_tx);
464 var IPA_Send ret := valueof(t_IPA_Send(connId, IPAC_PROTO_OML, payload));
465 return ret;
466}
467#endif
468
Harald Weltebdb63702017-12-09 01:15:44 +0100469/* main function to use for a client-side IPA implementation */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100470function main_client(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
471 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Welte2d86aff2018-04-17 11:23:04 +0200472 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars,
473 boolean ccm_enabled := true) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100474 g_mode := IPA_MODE_CLIENT;
Harald Welte2d86aff2018-04-17 11:23:04 +0200475 g_ccm_enabled := ccm_enabled;
Harald Weltee09921f2017-12-07 17:49:00 +0100476 f_connect(remote_host, remote_port, local_host, local_port, ccm_pars);
Harald Welte2d86aff2018-04-17 11:23:04 +0200477 if (g_ccm_enabled) {
478 /* we're a client: Send ID_ACK immediately after connect */
479 f_ccm_tx(valueof(ts_IPA_ACK));
480 }
Harald Welte03c0e562017-12-09 02:55:12 +0100481 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welteb3414b22017-11-23 18:22:10 +0100482 ScanEvents();
483}
484
Harald Weltebdb63702017-12-09 01:15:44 +0100485/* main function to use for a server-side IPA implementation */
Harald Welte2d86aff2018-04-17 11:23:04 +0200486function main_server(charstring local_host, IPL4asp_Types.PortNumber local_port,
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200487 boolean ccm_enabled := true,
488 IpaInitBehavior init_behavior := IPA_INIT_SEND_IPA_ID_GET)
489runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100490 g_mode := IPA_MODE_SERVER;
Harald Welte2d86aff2018-04-17 11:23:04 +0200491 g_ccm_enabled := ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200492 g_init_behavior := init_behavior;
Harald Welteb3414b22017-11-23 18:22:10 +0100493 f_bind(local_host, local_port);
494 ScanEvents();
495}
496
Harald Weltedf277252018-02-20 15:49:30 +0100497private function f_ctrl_to_user(octetstring msg) runs on IPA_Emulation_CT {
498 var charstring msg_ch := oct2char(msg);
499 IPA_CTRL_PORT.send(dec_CtrlMessage(msg_ch));
500}
501
502#ifdef IPA_EMULATION_GSUP
503private function f_gsup_to_user(octetstring msg) runs on IPA_Emulation_CT {
504 var GSUP_PDU gsup := dec_GSUP_PDU(msg);
505 f_gsup_postprocess_decoded(gsup);
506 IPA_GSUP_PORT.send(gsup);
507}
508#endif
509
Harald Welte7460a722018-10-10 12:28:27 +0200510#ifdef IPA_EMULATION_RSPRO
511private function f_rspro_to_user(octetstring msg) runs on IPA_Emulation_CT {
512 var RsproPDU rspro := dec_RsproPDU(msg);
513 IPA_RSPRO_PORT.send(rspro);
514}
515#endif
516
Harald Weltedf277252018-02-20 15:49:30 +0100517#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100518private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
519 var charstring msg_ch := oct2char(msg);
520 if (g_is_bsc_mgw) {
521 log("============");
522 log(msg_ch);
523 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
524 } else {
525 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
526 }
527}
528
Harald Welte92632e12017-11-25 02:31:20 +0100529private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
530 if (mp_ipa_mgcp_uses_osmo_ext) {
531 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
532 } else {
533 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
534 }
535}
Harald Weltedf277252018-02-20 15:49:30 +0100536#endif
Harald Welte92632e12017-11-25 02:31:20 +0100537
Harald Weltebdb63702017-12-09 01:15:44 +0100538/* main loop function for both client and server. 'thread' of the component */
Harald Welteb3414b22017-11-23 18:22:10 +0100539private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100540 var IPA_RecvFrom ipa_rx;
Harald Welteb3414b22017-11-23 18:22:10 +0100541 var ASP_Event asp_evt;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100542 var Socket_API_Definitions.PortEvent port_evt;
Harald Weltedf277252018-02-20 15:49:30 +0100543 var octetstring payload;
544 var CtrlMessage ctrl_msg;
545 var ASP_IPA_Unitdata ipa_ud;
546#ifdef IPA_EMULATION_SCCP
547 var ASP_MTP3_TRANSFERreq mtp_req;
548#endif
549#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100550 var MgcpCommand mgcp_cmd;
551 var MgcpResponse mgcp_rsp;
Harald Weltedf277252018-02-20 15:49:30 +0100552#endif
553#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100554 var GSUP_PDU gsup_msg;
Harald Weltedf277252018-02-20 15:49:30 +0100555#endif
556#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100557 var ASP_RSL_Unitdata rsl;
Harald Weltedf277252018-02-20 15:49:30 +0100558#endif
Harald Weltec6826662019-02-06 22:26:46 +0100559#ifdef IPA_EMULATION_OML
560 var OML_PDU oml;
561#endif
Harald Welte7460a722018-10-10 12:28:27 +0200562#ifdef IPA_EMULATION_RSPRO
563 var RsproPDU rspro;
564#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100565
Harald Welte3e6ad892017-12-12 14:39:46 +0100566 /* Set function for dissecting the binary */
567 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
568 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
569
Harald Welted86cdc62017-11-22 00:45:07 +0100570 while (true) {
571 alt {
572 /* Received IPA -> up into SCCP stack */
Harald Welte2d86aff2018-04-17 11:23:04 +0200573 [g_ccm_enabled] IPA_PORT.receive(IPA_RecvFrom:{?,IPAC_PROTO_CCM,omit,?}) -> value ipa_rx {
574 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
575 log("CCM Rx:", ccm);
576 select (g_mode) {
577 case (IPA_MODE_CLIENT) {
578 f_ccm_rx_client(ccm);
579 }
580 case (IPA_MODE_SERVER) {
581 f_ccm_rx_server(ccm);
582 }
583 case else {
584 setverdict(fail, "Unknown mode");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200585 mtc.stop;
Harald Welte2d86aff2018-04-17 11:23:04 +0200586 }
Harald Weltedf277252018-02-20 15:49:30 +0100587 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200588 }
589 [] IPA_PORT.receive(IPA_RecvFrom:?) -> value ipa_rx {
590 select (ipa_rx.streamId) {
Harald Weltedf277252018-02-20 15:49:30 +0100591#ifdef IPA_EMULATION_SCCP
592 case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100593 var ASP_MTP3_TRANSFERind mtp;
594 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
595 MTP3_SP_PORT.send(mtp);
Harald Weltedf277252018-02-20 15:49:30 +0100596 }
597#endif
598#ifdef IPA_EMULATION_MGCP
599 case (IPAC_PROTO_MGCP_OLD) {
Harald Weltec82eef42017-11-24 20:40:12 +0100600 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100601 }
602#endif
603#ifdef IPA_EMULATION_RSL
604 case (t_IpaSidRSL) {
Harald Welte0d846a72017-12-07 17:58:28 +0100605 rsl := {
606 streamId := ipa_rx.streamId,
607 rsl := dec_RSL_Message(ipa_rx.msg)
608 };
609 IPA_RSL_PORT.send(rsl);
Harald Weltedf277252018-02-20 15:49:30 +0100610 }
611#endif
Harald Weltec6826662019-02-06 22:26:46 +0100612#ifdef IPA_EMULATION_OML
613 case (IPAC_PROTO_OML) {
614 oml := dec_OML_PDU(ipa_rx.msg)
615 IPA_OML_PORT.send(oml);
616 }
617#endif
Harald Weltedf277252018-02-20 15:49:30 +0100618 case (IPAC_PROTO_OSMO) {
Harald Weltec82eef42017-11-24 20:40:12 +0100619 select (ipa_rx.streamIdExt) {
Harald Weltedf277252018-02-20 15:49:30 +0100620#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100621 case (IPAC_PROTO_EXT_MGCP) {
622 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100623 }
624#endif
625 case (IPAC_PROTO_EXT_CTRL) {
Harald Weltea76c4bb2017-12-09 02:06:07 +0100626 f_ctrl_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100627 }
628#ifdef IPA_EMULATION_GSUP
629 case (IPAC_PROTO_EXT_GSUP) {
Harald Weltedf327232017-12-28 22:51:51 +0100630 f_gsup_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100631 }
632#endif
Harald Welte7460a722018-10-10 12:28:27 +0200633#ifdef IPA_EMULATION_RSPRO
634 case (IPAC_PROTO_EXT_RSPRO) {
635 f_rspro_to_user(ipa_rx.msg);
636 }
637#endif
Harald Weltedf277252018-02-20 15:49:30 +0100638 case else {
Harald Weltec82eef42017-11-24 20:40:12 +0100639 IPA_SP_PORT.send(f_to_asp(ipa_rx));
640 }
Harald Welted86cdc62017-11-22 00:45:07 +0100641 }
Harald Weltedf277252018-02-20 15:49:30 +0100642 }
643 case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100644 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100645 }
646 }
647 }
648
Harald Welteb3414b22017-11-23 18:22:10 +0100649 /* server only */
650 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
651 log("IPA: Connected");
652 g_ipa_conn_id := asp_evt.connOpened.connId;
Harald Welte0d846a72017-12-07 17:58:28 +0100653 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welte2d86aff2018-04-17 11:23:04 +0200654 if (g_mode == IPA_MODE_SERVER and g_ccm_enabled) {
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200655 select (g_init_behavior) {
656 case (IPA_INIT_SEND_IPA_ID_GET) {
657 f_ccm_tx(valueof(ts_IPA_ID_GET));
658 }
659 case (IPA_INIT_SEND_IPA_ID_ACK) {
660 f_ccm_tx(valueof(ts_IPA_ACK));
661 }
662 }
Harald Welteb3414b22017-11-23 18:22:10 +0100663 }
664 }
665
666 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
667 log("IPA: Closed");
668 g_ipa_conn_id := -1;
Harald Welte0d846a72017-12-07 17:58:28 +0100669 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
Harald Welteb3414b22017-11-23 18:22:10 +0100670 self.stop;
671 }
672
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100673 [] IPA_PORT.receive(Socket_API_Definitions.PortEvent:{result:={errorCode:=ERROR_SOCKET, connId:=?, os_error_code:=?, os_error_text:=?}}) -> value port_evt {
674 log("PortEvent: ERROR_SOCKET: ", port_evt);
675 g_ipa_conn_id := -1;
676 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
677 self.stop;
678 }
679
Harald Weltedf277252018-02-20 15:49:30 +0100680#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100681 /* Received SCCP -> down into IPA */
682 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100683 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
684 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100685 IPA_PORT.send(ipa_tx);
686 }
Harald Weltedf277252018-02-20 15:49:30 +0100687#endif
Harald Weltec76f29f2017-11-22 12:46:46 +0100688
Harald Weltedf277252018-02-20 15:49:30 +0100689#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100690 /* Received MGCP -> down into IPA */
691 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100692 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
693 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100694 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
695 }
696 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100697 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100698 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100699 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
700 }
Harald Weltedf277252018-02-20 15:49:30 +0100701#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100702
Harald Weltea76c4bb2017-12-09 02:06:07 +0100703 [] IPA_CTRL_PORT.receive(CtrlMessage:?) -> value ctrl_msg {
704 payload := char2oct(enc_CtrlMessage(ctrl_msg));
705 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_CTRL));
706 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
707 }
708
Harald Weltedf277252018-02-20 15:49:30 +0100709#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100710 [] IPA_GSUP_PORT.receive(GSUP_PDU:?) -> value gsup_msg {
Harald Welte2f562b12018-01-24 20:52:38 +0100711 f_gsup_preprocess_encoded(gsup_msg);
Harald Weltedf327232017-12-28 22:51:51 +0100712 payload := enc_GSUP_PDU(gsup_msg);
713 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_GSUP));
714 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
715 }
Harald Weltedf277252018-02-20 15:49:30 +0100716#endif
Harald Weltedf327232017-12-28 22:51:51 +0100717
Harald Welte7460a722018-10-10 12:28:27 +0200718#ifdef IPA_EMULATION_RSPRO
719 [] IPA_RSPRO_PORT.receive(RsproPDU:?) -> value rspro {
720 payload := enc_RsproPDU(rspro);
721 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_RSPRO));
722 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
723 }
724#endif
725
Harald Weltedf277252018-02-20 15:49:30 +0100726#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100727 /* Received RSL -> down into IPA */
728 [] IPA_RSL_PORT.receive(ASP_RSL_Unitdata:?) -> value rsl {
729 IPA_PORT.send(f_from_rsl(g_ipa_conn_id, rsl));
730 }
Harald Weltedf277252018-02-20 15:49:30 +0100731#endif
Harald Weltec6826662019-02-06 22:26:46 +0100732#ifdef IPA_EMULATION_OML
733 /* Received OML -> down into IPA */
734 [] IPA_OML_PORT.receive(OML_PDU:?) -> value oml {
735 IPA_PORT.send(f_from_oml(g_ipa_conn_id, oml));
736 }
737 [] IPA_OML_PORT.receive(octetstring:?) -> value payload {
738 IPA_PORT.send(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_OML, payload));
739 }
740#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100741 /* Received MISC (OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100742 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
743 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
744 }
745
746
Harald Welted86cdc62017-11-22 00:45:07 +0100747 }
748 }
749}
750
Harald Welte2e32e432018-05-24 20:00:00 +0200751/***********************************************************************
752 * IPA Event waiter component. Wait for ASP_IPA_EVENT_ID_ACK
753 ***********************************************************************/
754
755type component IPA_EventWaiter_CT {
756 port IPA_SP_PT IPA_SP_PORT;
757}
758
759function waiter_main(template ASP_IPA_Event wait_for := t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK))
760runs on IPA_EventWaiter_CT {
761
762 alt {
763 [] IPA_SP_PORT.receive(wait_for) {
764 setverdict(pass);
765 }
766 [] IPA_SP_PORT.receive { repeat; }
767 }
768}
769
770
Harald Welted86cdc62017-11-22 00:45:07 +0100771}