blob: 7a26a6be612a40586b2840b85625f5b9fa892018 [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 *
11 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
12 * 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 Weltea76c4bb2017-12-09 02:06:07 +010042import from Osmocom_CTRL_Types all;
43
Harald Welted86cdc62017-11-22 00:45:07 +010044modulepar {
Harald Welte92632e12017-11-25 02:31:20 +010045 /* Use Osmocom extended IPA mux header */
46 boolean mp_ipa_mgcp_uses_osmo_ext := true;
Harald Welted86cdc62017-11-22 00:45:07 +010047}
Harald Welted86cdc62017-11-22 00:45:07 +010048
Harald Welteb3414b22017-11-23 18:22:10 +010049type enumerated IpaMode {
50 IPA_MODE_CLIENT,
51 IPA_MODE_SERVER
52}
53
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +020054type enumerated IpaInitBehavior {
55 IPA_INIT_SEND_IPA_ID_GET,
56 IPA_INIT_SEND_IPA_ID_ACK
57}
58
Harald Weltec76f29f2017-11-22 12:46:46 +010059type record ASP_IPA_Unitdata {
60 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010061 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010062 octetstring payload
63}
64
Harald Welte0d846a72017-12-07 17:58:28 +010065type enumerated ASP_IPA_EventUpDown {
66 ASP_IPA_EVENT_DOWN,
67 ASP_IPA_EVENT_UP,
68 ASP_IPA_EVENT_ID_ACK
69}
70
Harald Weltebdb63702017-12-09 01:15:44 +010071/* an event indicating us whether or not a connection is physically up or down,
72 * and whether we have received an ID_ACK */
Harald Welte0d846a72017-12-07 17:58:28 +010073type union ASP_IPA_Event {
74 ASP_IPA_EventUpDown up_down
75}
76
77template ASP_IPA_Event t_ASP_IPA_EVT_UD(ASP_IPA_EventUpDown ud) := {
78 up_down := ud
79}
80
Harald Welte1dd8f372017-11-25 02:25:27 +010081template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
82 template IpaExtStreamId esid := omit) := {
83 streamId := sid,
84 streamIdExt := esid,
85 payload := pl
86}
87
Harald Weltedf277252018-02-20 15:49:30 +010088#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +010089/* like ASP_IPA_Unitdata, but with RSL_Message abstract type instead of octetstring */
Harald Welte0d846a72017-12-07 17:58:28 +010090type record ASP_RSL_Unitdata {
91 IpaStreamId streamId,
92 RSL_Message rsl
93};
94
Harald Welte7ae019e2017-12-09 00:54:15 +010095template ASP_RSL_Unitdata ts_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
Harald Welte0d846a72017-12-07 17:58:28 +010096 streamId := sid,
97 rsl := valueof(rsl)
98}
99
Harald Welte7ae019e2017-12-09 00:54:15 +0100100template ASP_RSL_Unitdata tr_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
101 streamId := sid,
102 rsl := rsl
103}
104
Harald Welte0d846a72017-12-07 17:58:28 +0100105template IpaStreamId t_IpaSidRSL := ( IPAC_PROTO_RSL_TRX0, IPAC_PROTO_RSL_TRX1,
106 IPAC_PROTO_RSL_TRX2, IPAC_PROTO_RSL_TRX3 );
Harald Weltedf277252018-02-20 15:49:30 +0100107#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100108
Harald Weltebdb63702017-12-09 01:15:44 +0100109/* Client port for general IPA messages, not further decoded */
Harald Weltec76f29f2017-11-22 12:46:46 +0100110type port IPA_SP_PT message {
Harald Welte0d846a72017-12-07 17:58:28 +0100111 inout ASP_IPA_Unitdata, ASP_IPA_Event;
Harald Weltec76f29f2017-11-22 12:46:46 +0100112} with { extension "internal" }
113
Harald Weltedf277252018-02-20 15:49:30 +0100114#ifdef IPA_EMULATION_MGCP
Harald Weltebdb63702017-12-09 01:15:44 +0100115/* Client port for MGCP inside IPA */
Harald Weltec82eef42017-11-24 20:40:12 +0100116type port IPA_MGCP_PT message {
117 inout MgcpCommand, MgcpResponse;
118} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100119#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100120
Harald Weltedf277252018-02-20 15:49:30 +0100121#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +0100122/* Client port for A-bis RSL inside IPA */
Harald Welte0d846a72017-12-07 17:58:28 +0100123type port IPA_RSL_PT message {
124 inout ASP_RSL_Unitdata, ASP_IPA_Event;
125} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100126#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100127
Harald Weltea76c4bb2017-12-09 02:06:07 +0100128/* Client port for CTRL inside IPA */
129type port IPA_CTRL_PT message {
130 inout CtrlMessage, ASP_IPA_Event;
131} with { extension "internal" }
132
Harald Weltedf277252018-02-20 15:49:30 +0100133#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100134/* Client port for CTRL inside IPA */
135type port IPA_GSUP_PT message {
136 inout GSUP_PDU, ASP_IPA_Event;
137} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100138#endif
Harald Weltedf327232017-12-28 22:51:51 +0100139
140
Harald Welted86cdc62017-11-22 00:45:07 +0100141type component IPA_Emulation_CT {
142 /* down-facing port to IPA codec port */
143 port IPA_CODEC_PT IPA_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100144#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100145 /* up-facing port to SCCP */
146 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100147#endif
148#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100149 /* up-facing port for MGCP */
150 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100151#endif
152#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100153 /* up-facing port for RSL */
154 port IPA_RSL_PT IPA_RSL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100155#endif
Harald Weltea76c4bb2017-12-09 02:06:07 +0100156 /* up-facing port for CTRL */
157 port IPA_CTRL_PT IPA_CTRL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100158#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100159 /* up-facing port for GSUP */
160 port IPA_GSUP_PT IPA_GSUP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100161#endif
Harald Weltedf327232017-12-28 22:51:51 +0100162
Harald Weltec76f29f2017-11-22 12:46:46 +0100163 /* up-facing port for other streams */
164 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +0100165
166 var boolean g_initialized := false;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100167 var IPL4asp_Types.ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +0100168 /* Are we a BSC/MGW (truel) or MSC (false) */
169 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +0100170
171 var IpaMode g_mode;
Harald Welte2d86aff2018-04-17 11:23:04 +0200172 var boolean g_ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200173 var IpaInitBehavior g_init_behavior;
Harald Weltee09921f2017-12-07 17:49:00 +0100174 var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +0100175}
176
Harald Weltee21096d2017-12-04 20:45:12 +0100177type record IPA_CCM_Parameters {
178 charstring ser_nr optional,
179 charstring name optional,
180 charstring location1 optional,
181 charstring location2 optional,
182 charstring equip_version optional,
183 charstring sw_version optional,
184 charstring ip_addr optional,
185 charstring mac_addr optional,
186 charstring unit_id optional,
187 charstring osmo_rand optional
188}
189
Harald Weltee09921f2017-12-07 17:49:00 +0100190const IPA_CCM_Parameters c_IPA_default_ccm_pars := {
191 ser_nr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100192 name := "mahlzeit",
Harald Weltee09921f2017-12-07 17:49:00 +0100193 location1 := "",
194 location2 := "",
195 equip_version := "",
196 sw_version := "",
197 ip_addr := "",
198 mac_addr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100199 unit_id := "0/1/2",
Harald Weltee09921f2017-12-07 17:49:00 +0100200 osmo_rand := ""
Harald Weltee21096d2017-12-04 20:45:12 +0100201};
202
Harald Weltebdb63702017-12-09 01:15:44 +0100203/* Function to use to connect as client to a remote IPA Server */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100204function f_connect(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
205 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100206 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100207 var IPL4asp_Types.Result res;
Harald Welted86cdc62017-11-22 00:45:07 +0100208 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
209 local_host, local_port, 0, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200210 if (not ispresent(res.connId)) {
Stefan Sperling6a90be42018-08-31 15:05:39 +0200211 setverdict(fail, "Could not connect IPA socket from ", local_host, " port ", local_port,
212 " to ", remote_host, " port ", remote_port, "; check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200213 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200214 }
Harald Welted86cdc62017-11-22 00:45:07 +0100215 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100216 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100217 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100218}
219
Harald Weltebdb63702017-12-09 01:15:44 +0100220/* Function to use to bind to a local port as IPA server, accepting remote clients */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100221function f_bind(charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100222 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100223 var IPL4asp_Types.Result res;
Harald Welteb3414b22017-11-23 18:22:10 +0100224 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
225 local_host, local_port, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200226 if (not ispresent(res.connId)) {
227 setverdict(fail, "Could not listen IPA socket, check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200228 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200229 }
Harald Welteb3414b22017-11-23 18:22:10 +0100230 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100231 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100232 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100233}
234
Harald Weltedf277252018-02-20 15:49:30 +0100235#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100236template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
237 sio := { '10'B, '00'B, '0011'B },
238 opc := opc,
239 dpc := 0,
240 sls := 0,
241 data := data
242}
Harald Weltedf277252018-02-20 15:49:30 +0100243#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100244
245
246private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
247 len := 0, /* overwritten by codec */
248 tag := tag,
Harald Welte95686e02018-08-02 15:05:43 +0200249 data := char2oct(payload) & '00'O
Harald Welted86cdc62017-11-22 00:45:07 +0100250}
251
Harald Welte0d846a72017-12-07 17:58:28 +0100252private function f_send_IPA_EVT(template ASP_IPA_Event evt) runs on IPA_Emulation_CT {
Harald Welte2e32e432018-05-24 20:00:00 +0200253 if (IPA_SP_PORT.checkstate("Connected")) {
254 IPA_SP_PORT.send(evt);
255 }
Harald Weltedf277252018-02-20 15:49:30 +0100256#ifdef IPA_EMULATION_RSL
Harald Welte5819b552017-12-09 02:55:46 +0100257 if (IPA_RSL_PORT.checkstate("Connected")) {
258 IPA_RSL_PORT.send(evt);
259 }
Harald Weltedf277252018-02-20 15:49:30 +0100260#endif
Harald Welte5819b552017-12-09 02:55:46 +0100261 if (IPA_CTRL_PORT.checkstate("Connected")) {
262 IPA_CTRL_PORT.send(evt);
263 }
Harald Weltedf277252018-02-20 15:49:30 +0100264#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100265 if (IPA_GSUP_PORT.checkstate("Connected")) {
266 IPA_GSUP_PORT.send(evt);
267 }
Harald Weltedf277252018-02-20 15:49:30 +0100268#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100269 /* FIXME: to other ports */
270}
271
Harald Welted86cdc62017-11-22 00:45:07 +0100272/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100273private 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 +0100274 var integer i;
275 var PDU_IPA_CCM resp := {
276 msg_type := IPAC_MSGT_ID_RESP,
277 u := {
278 resp := {}
279 }
280 }
281
282 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
283 var IpaCcmIdTag tag := get.u.get[i].tag;
284 var charstring foo;
285 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100286 case (IPAC_IDTAG_SERNR) {
287 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100288 }
289 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100290 foo := g_ccm_pars.name;
291 }
292 case (IPAC_IDTAG_LOCATION1) {
293 foo := g_ccm_pars.location1;
294 }
295 case (IPAC_IDTAG_LOCATION2) {
296 foo := g_ccm_pars.location2;
297 }
298 case (IPAC_IDTAG_EQUIPVERS) {
299 foo := g_ccm_pars.equip_version;
300 }
301 case (IPAC_IDTAG_SWVERSION) {
302 foo := g_ccm_pars.sw_version;
303 }
304 case (IPAC_IDTAG_IPADDR) {
305 foo := g_ccm_pars.ip_addr;
306 }
307 case (IPAC_IDTAG_MACADDR) {
308 foo := g_ccm_pars.mac_addr;
309 }
310 case (IPAC_IDTAG_UNIT) {
311 foo := g_ccm_pars.unit_id;
312 }
313 case (IPAC_IDTAG_OSMO_RAND) {
314 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100315 }
316 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100317 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100318 }
319 }
320 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
321 }
322
323 return resp;
324}
325
326/* transmit IPA CCM message */
327private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100328 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 +0100329 log("CCM Tx:", ccm);
330 IPA_PORT.send(ipa_tx);
331}
332
333template PDU_IPA_CCM ts_IPA_PONG := {
334 msg_type := IPAC_MSGT_PONG,
335 u := omit
336}
337
338template PDU_IPA_CCM ts_IPA_ACK := {
339 msg_type := IPAC_MSGT_ID_ACK,
340 u := omit
341}
342
Harald Welteb3414b22017-11-23 18:22:10 +0100343template PDU_IPA_CCM ts_IPA_ID_GET := {
344 msg_type := IPAC_MSGT_ID_GET,
345 u := {
346 get := {
347 { 1, IPAC_IDTAG_UNITNAME }
348 }
349 }
350}
351
Harald Welted86cdc62017-11-22 00:45:07 +0100352/* receive IPA CCM message */
Harald Welte2d86aff2018-04-17 11:23:04 +0200353private function f_ccm_rx_client(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100354 select (ccm.msg_type) {
355 case (IPAC_MSGT_PING) {
356 f_ccm_tx(valueof(ts_IPA_PONG));
357 }
358 case (IPAC_MSGT_ID_ACK) {
Harald Welte2d86aff2018-04-17 11:23:04 +0200359 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welted86cdc62017-11-22 00:45:07 +0100360 }
361 case (IPAC_MSGT_ID_GET) {
362 f_ccm_tx(f_ccm_make_id_resp(ccm));
363 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200364 case else {
365 log("Unknown/unsupported IPA CCM message type", ccm);
366 }
367 }
368}
369
370private function f_ccm_rx_server(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
371 select (ccm.msg_type) {
372 case (IPAC_MSGT_PING) {
373 f_ccm_tx(valueof(ts_IPA_PONG));
374 }
375 case (IPAC_MSGT_ID_ACK) {
376 /* the IPA server should at some point receive an ID_ACK from the client,
377 * in case of RSL/OML from nanoBTS, this is actually the first message after
378 * the TCP connection is established. Other implementations may differ.
379 * We currently ignore it completely - but actually we should make sure that
380 * one ID_ACK is received by the server at some point */
Harald Welte2e32e432018-05-24 20:00:00 +0200381 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welte2d86aff2018-04-17 11:23:04 +0200382 }
Harald Welte3bc387f2018-02-21 12:18:46 +0100383 case (IPAC_MSGT_ID_RESP) {
384 log("IPA ID RESP: ", ccm.u.resp);
Harald Welte2d86aff2018-04-17 11:23:04 +0200385 /* acknowledge any identity that the client may have sent */
386 f_ccm_tx(valueof(ts_IPA_ACK));
Harald Welte3bc387f2018-02-21 12:18:46 +0100387 }
Harald Welted86cdc62017-11-22 00:45:07 +0100388 case else {
389 log("Unknown/unsupported IPA CCM message type", ccm);
390 }
391 }
392}
393
Harald Weltec76f29f2017-11-22 12:46:46 +0100394private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
395 var ASP_IPA_Unitdata ret := {
396 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100397 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100398 payload := ipa_rx.msg
399 }
400 return ret;
401}
402
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100403private function f_from_asp(IPL4asp_Types.ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100404 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
405 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100406 return ret;
407}
Harald Welted86cdc62017-11-22 00:45:07 +0100408
Harald Weltedf277252018-02-20 15:49:30 +0100409#ifdef IPA_EMULATION_RSL
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100410private function f_from_rsl(IPL4asp_Types.ConnectionId connId, ASP_RSL_Unitdata rsl_tx) return IPA_Send {
Harald Welte0d846a72017-12-07 17:58:28 +0100411 var octetstring payload := enc_RSL_Message(rsl_tx.rsl);
412 var IPA_Send ret := valueof(t_IPA_Send(connId, rsl_tx.streamId, payload));
413 return ret;
414}
Harald Weltedf277252018-02-20 15:49:30 +0100415#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100416
Harald Weltebdb63702017-12-09 01:15:44 +0100417/* main function to use for a client-side IPA implementation */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100418function main_client(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
419 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Welte2d86aff2018-04-17 11:23:04 +0200420 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars,
421 boolean ccm_enabled := true) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100422 g_mode := IPA_MODE_CLIENT;
Harald Welte2d86aff2018-04-17 11:23:04 +0200423 g_ccm_enabled := ccm_enabled;
Harald Weltee09921f2017-12-07 17:49:00 +0100424 f_connect(remote_host, remote_port, local_host, local_port, ccm_pars);
Harald Welte2d86aff2018-04-17 11:23:04 +0200425 if (g_ccm_enabled) {
426 /* we're a client: Send ID_ACK immediately after connect */
427 f_ccm_tx(valueof(ts_IPA_ACK));
428 }
Harald Welte03c0e562017-12-09 02:55:12 +0100429 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welteb3414b22017-11-23 18:22:10 +0100430 ScanEvents();
431}
432
Harald Weltebdb63702017-12-09 01:15:44 +0100433/* main function to use for a server-side IPA implementation */
Harald Welte2d86aff2018-04-17 11:23:04 +0200434function main_server(charstring local_host, IPL4asp_Types.PortNumber local_port,
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200435 boolean ccm_enabled := true,
436 IpaInitBehavior init_behavior := IPA_INIT_SEND_IPA_ID_GET)
437runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100438 g_mode := IPA_MODE_SERVER;
Harald Welte2d86aff2018-04-17 11:23:04 +0200439 g_ccm_enabled := ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200440 g_init_behavior := init_behavior;
Harald Welteb3414b22017-11-23 18:22:10 +0100441 f_bind(local_host, local_port);
442 ScanEvents();
443}
444
Harald Weltedf277252018-02-20 15:49:30 +0100445private function f_ctrl_to_user(octetstring msg) runs on IPA_Emulation_CT {
446 var charstring msg_ch := oct2char(msg);
447 IPA_CTRL_PORT.send(dec_CtrlMessage(msg_ch));
448}
449
450#ifdef IPA_EMULATION_GSUP
451private function f_gsup_to_user(octetstring msg) runs on IPA_Emulation_CT {
452 var GSUP_PDU gsup := dec_GSUP_PDU(msg);
453 f_gsup_postprocess_decoded(gsup);
454 IPA_GSUP_PORT.send(gsup);
455}
456#endif
457
458#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100459private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
460 var charstring msg_ch := oct2char(msg);
461 if (g_is_bsc_mgw) {
462 log("============");
463 log(msg_ch);
464 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
465 } else {
466 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
467 }
468}
469
Harald Welte92632e12017-11-25 02:31:20 +0100470private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
471 if (mp_ipa_mgcp_uses_osmo_ext) {
472 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
473 } else {
474 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
475 }
476}
Harald Weltedf277252018-02-20 15:49:30 +0100477#endif
Harald Welte92632e12017-11-25 02:31:20 +0100478
Harald Weltebdb63702017-12-09 01:15:44 +0100479/* main loop function for both client and server. 'thread' of the component */
Harald Welteb3414b22017-11-23 18:22:10 +0100480private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100481 var IPA_RecvFrom ipa_rx;
Harald Welteb3414b22017-11-23 18:22:10 +0100482 var ASP_Event asp_evt;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100483 var Socket_API_Definitions.PortEvent port_evt;
Harald Weltedf277252018-02-20 15:49:30 +0100484 var octetstring payload;
485 var CtrlMessage ctrl_msg;
486 var ASP_IPA_Unitdata ipa_ud;
487#ifdef IPA_EMULATION_SCCP
488 var ASP_MTP3_TRANSFERreq mtp_req;
489#endif
490#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100491 var MgcpCommand mgcp_cmd;
492 var MgcpResponse mgcp_rsp;
Harald Weltedf277252018-02-20 15:49:30 +0100493#endif
494#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100495 var GSUP_PDU gsup_msg;
Harald Weltedf277252018-02-20 15:49:30 +0100496#endif
497#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100498 var ASP_RSL_Unitdata rsl;
Harald Weltedf277252018-02-20 15:49:30 +0100499#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100500
Harald Welte3e6ad892017-12-12 14:39:46 +0100501 /* Set function for dissecting the binary */
502 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
503 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
504
Harald Welted86cdc62017-11-22 00:45:07 +0100505 while (true) {
506 alt {
507 /* Received IPA -> up into SCCP stack */
Harald Welte2d86aff2018-04-17 11:23:04 +0200508 [g_ccm_enabled] IPA_PORT.receive(IPA_RecvFrom:{?,IPAC_PROTO_CCM,omit,?}) -> value ipa_rx {
509 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
510 log("CCM Rx:", ccm);
511 select (g_mode) {
512 case (IPA_MODE_CLIENT) {
513 f_ccm_rx_client(ccm);
514 }
515 case (IPA_MODE_SERVER) {
516 f_ccm_rx_server(ccm);
517 }
518 case else {
519 setverdict(fail, "Unknown mode");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200520 mtc.stop;
Harald Welte2d86aff2018-04-17 11:23:04 +0200521 }
Harald Weltedf277252018-02-20 15:49:30 +0100522 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200523 }
524 [] IPA_PORT.receive(IPA_RecvFrom:?) -> value ipa_rx {
525 select (ipa_rx.streamId) {
Harald Weltedf277252018-02-20 15:49:30 +0100526#ifdef IPA_EMULATION_SCCP
527 case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100528 var ASP_MTP3_TRANSFERind mtp;
529 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
530 MTP3_SP_PORT.send(mtp);
Harald Weltedf277252018-02-20 15:49:30 +0100531 }
532#endif
533#ifdef IPA_EMULATION_MGCP
534 case (IPAC_PROTO_MGCP_OLD) {
Harald Weltec82eef42017-11-24 20:40:12 +0100535 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100536 }
537#endif
538#ifdef IPA_EMULATION_RSL
539 case (t_IpaSidRSL) {
Harald Welte0d846a72017-12-07 17:58:28 +0100540 rsl := {
541 streamId := ipa_rx.streamId,
542 rsl := dec_RSL_Message(ipa_rx.msg)
543 };
544 IPA_RSL_PORT.send(rsl);
Harald Weltedf277252018-02-20 15:49:30 +0100545 }
546#endif
547 case (IPAC_PROTO_OSMO) {
Harald Weltec82eef42017-11-24 20:40:12 +0100548 select (ipa_rx.streamIdExt) {
Harald Weltedf277252018-02-20 15:49:30 +0100549#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100550 case (IPAC_PROTO_EXT_MGCP) {
551 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100552 }
553#endif
554 case (IPAC_PROTO_EXT_CTRL) {
Harald Weltea76c4bb2017-12-09 02:06:07 +0100555 f_ctrl_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100556 }
557#ifdef IPA_EMULATION_GSUP
558 case (IPAC_PROTO_EXT_GSUP) {
Harald Weltedf327232017-12-28 22:51:51 +0100559 f_gsup_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100560 }
561#endif
562 case else {
Harald Weltec82eef42017-11-24 20:40:12 +0100563 IPA_SP_PORT.send(f_to_asp(ipa_rx));
564 }
Harald Welted86cdc62017-11-22 00:45:07 +0100565 }
Harald Weltedf277252018-02-20 15:49:30 +0100566 }
567 case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100568 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100569 }
570 }
571 }
572
Harald Welteb3414b22017-11-23 18:22:10 +0100573 /* server only */
574 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
575 log("IPA: Connected");
576 g_ipa_conn_id := asp_evt.connOpened.connId;
Harald Welte0d846a72017-12-07 17:58:28 +0100577 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welte2d86aff2018-04-17 11:23:04 +0200578 if (g_mode == IPA_MODE_SERVER and g_ccm_enabled) {
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200579 select (g_init_behavior) {
580 case (IPA_INIT_SEND_IPA_ID_GET) {
581 f_ccm_tx(valueof(ts_IPA_ID_GET));
582 }
583 case (IPA_INIT_SEND_IPA_ID_ACK) {
584 f_ccm_tx(valueof(ts_IPA_ACK));
585 }
586 }
Harald Welteb3414b22017-11-23 18:22:10 +0100587 }
588 }
589
590 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
591 log("IPA: Closed");
592 g_ipa_conn_id := -1;
Harald Welte0d846a72017-12-07 17:58:28 +0100593 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
Harald Welteb3414b22017-11-23 18:22:10 +0100594 self.stop;
595 }
596
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100597 [] IPA_PORT.receive(Socket_API_Definitions.PortEvent:{result:={errorCode:=ERROR_SOCKET, connId:=?, os_error_code:=?, os_error_text:=?}}) -> value port_evt {
598 log("PortEvent: ERROR_SOCKET: ", port_evt);
599 g_ipa_conn_id := -1;
600 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
601 self.stop;
602 }
603
Harald Weltedf277252018-02-20 15:49:30 +0100604#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100605 /* Received SCCP -> down into IPA */
606 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100607 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
608 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100609 IPA_PORT.send(ipa_tx);
610 }
Harald Weltedf277252018-02-20 15:49:30 +0100611#endif
Harald Weltec76f29f2017-11-22 12:46:46 +0100612
Harald Weltedf277252018-02-20 15:49:30 +0100613#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100614 /* Received MGCP -> down into IPA */
615 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100616 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
617 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100618 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
619 }
620 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100621 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100622 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100623 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
624 }
Harald Weltedf277252018-02-20 15:49:30 +0100625#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100626
Harald Weltea76c4bb2017-12-09 02:06:07 +0100627 [] IPA_CTRL_PORT.receive(CtrlMessage:?) -> value ctrl_msg {
628 payload := char2oct(enc_CtrlMessage(ctrl_msg));
629 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_CTRL));
630 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
631 }
632
Harald Weltedf277252018-02-20 15:49:30 +0100633#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100634 [] IPA_GSUP_PORT.receive(GSUP_PDU:?) -> value gsup_msg {
Harald Welte2f562b12018-01-24 20:52:38 +0100635 f_gsup_preprocess_encoded(gsup_msg);
Harald Weltedf327232017-12-28 22:51:51 +0100636 payload := enc_GSUP_PDU(gsup_msg);
637 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_GSUP));
638 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
639 }
Harald Weltedf277252018-02-20 15:49:30 +0100640#endif
Harald Weltedf327232017-12-28 22:51:51 +0100641
Harald Weltedf277252018-02-20 15:49:30 +0100642#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100643 /* Received RSL -> down into IPA */
644 [] IPA_RSL_PORT.receive(ASP_RSL_Unitdata:?) -> value rsl {
645 IPA_PORT.send(f_from_rsl(g_ipa_conn_id, rsl));
646 }
Harald Weltedf277252018-02-20 15:49:30 +0100647#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100648
649 /* Received MISC (OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100650 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
651 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
652 }
653
654
Harald Welted86cdc62017-11-22 00:45:07 +0100655 }
656 }
657}
658
Harald Welte2e32e432018-05-24 20:00:00 +0200659/***********************************************************************
660 * IPA Event waiter component. Wait for ASP_IPA_EVENT_ID_ACK
661 ***********************************************************************/
662
663type component IPA_EventWaiter_CT {
664 port IPA_SP_PT IPA_SP_PORT;
665}
666
667function waiter_main(template ASP_IPA_Event wait_for := t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK))
668runs on IPA_EventWaiter_CT {
669
670 alt {
671 [] IPA_SP_PORT.receive(wait_for) {
672 setverdict(pass);
673 }
674 [] IPA_SP_PORT.receive { repeat; }
675 }
676}
677
678
Harald Welted86cdc62017-11-22 00:45:07 +0100679}