blob: 41a3968d83419ac572efb89e0f3d34831533a937 [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
Harald Weltec76f29f2017-11-22 12:46:46 +010054type record ASP_IPA_Unitdata {
55 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010056 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010057 octetstring payload
58}
59
Harald Welte0d846a72017-12-07 17:58:28 +010060type enumerated ASP_IPA_EventUpDown {
61 ASP_IPA_EVENT_DOWN,
62 ASP_IPA_EVENT_UP,
63 ASP_IPA_EVENT_ID_ACK
64}
65
Harald Weltebdb63702017-12-09 01:15:44 +010066/* an event indicating us whether or not a connection is physically up or down,
67 * and whether we have received an ID_ACK */
Harald Welte0d846a72017-12-07 17:58:28 +010068type union ASP_IPA_Event {
69 ASP_IPA_EventUpDown up_down
70}
71
72template ASP_IPA_Event t_ASP_IPA_EVT_UD(ASP_IPA_EventUpDown ud) := {
73 up_down := ud
74}
75
Harald Welte1dd8f372017-11-25 02:25:27 +010076template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
77 template IpaExtStreamId esid := omit) := {
78 streamId := sid,
79 streamIdExt := esid,
80 payload := pl
81}
82
Harald Weltedf277252018-02-20 15:49:30 +010083#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +010084/* like ASP_IPA_Unitdata, but with RSL_Message abstract type instead of octetstring */
Harald Welte0d846a72017-12-07 17:58:28 +010085type record ASP_RSL_Unitdata {
86 IpaStreamId streamId,
87 RSL_Message rsl
88};
89
Harald Welte7ae019e2017-12-09 00:54:15 +010090template ASP_RSL_Unitdata ts_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
Harald Welte0d846a72017-12-07 17:58:28 +010091 streamId := sid,
92 rsl := valueof(rsl)
93}
94
Harald Welte7ae019e2017-12-09 00:54:15 +010095template ASP_RSL_Unitdata tr_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
96 streamId := sid,
97 rsl := rsl
98}
99
Harald Welte0d846a72017-12-07 17:58:28 +0100100template IpaStreamId t_IpaSidRSL := ( IPAC_PROTO_RSL_TRX0, IPAC_PROTO_RSL_TRX1,
101 IPAC_PROTO_RSL_TRX2, IPAC_PROTO_RSL_TRX3 );
Harald Weltedf277252018-02-20 15:49:30 +0100102#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100103
Harald Weltebdb63702017-12-09 01:15:44 +0100104/* Client port for general IPA messages, not further decoded */
Harald Weltec76f29f2017-11-22 12:46:46 +0100105type port IPA_SP_PT message {
Harald Welte0d846a72017-12-07 17:58:28 +0100106 inout ASP_IPA_Unitdata, ASP_IPA_Event;
Harald Weltec76f29f2017-11-22 12:46:46 +0100107} with { extension "internal" }
108
Harald Weltedf277252018-02-20 15:49:30 +0100109#ifdef IPA_EMULATION_MGCP
Harald Weltebdb63702017-12-09 01:15:44 +0100110/* Client port for MGCP inside IPA */
Harald Weltec82eef42017-11-24 20:40:12 +0100111type port IPA_MGCP_PT message {
112 inout MgcpCommand, MgcpResponse;
113} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100114#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100115
Harald Weltedf277252018-02-20 15:49:30 +0100116#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +0100117/* Client port for A-bis RSL inside IPA */
Harald Welte0d846a72017-12-07 17:58:28 +0100118type port IPA_RSL_PT message {
119 inout ASP_RSL_Unitdata, ASP_IPA_Event;
120} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100121#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100122
Harald Weltea76c4bb2017-12-09 02:06:07 +0100123/* Client port for CTRL inside IPA */
124type port IPA_CTRL_PT message {
125 inout CtrlMessage, ASP_IPA_Event;
126} with { extension "internal" }
127
Harald Weltedf277252018-02-20 15:49:30 +0100128#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100129/* Client port for CTRL inside IPA */
130type port IPA_GSUP_PT message {
131 inout GSUP_PDU, ASP_IPA_Event;
132} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100133#endif
Harald Weltedf327232017-12-28 22:51:51 +0100134
135
Harald Welted86cdc62017-11-22 00:45:07 +0100136type component IPA_Emulation_CT {
137 /* down-facing port to IPA codec port */
138 port IPA_CODEC_PT IPA_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100139#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100140 /* up-facing port to SCCP */
141 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100142#endif
143#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100144 /* up-facing port for MGCP */
145 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100146#endif
147#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100148 /* up-facing port for RSL */
149 port IPA_RSL_PT IPA_RSL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100150#endif
Harald Weltea76c4bb2017-12-09 02:06:07 +0100151 /* up-facing port for CTRL */
152 port IPA_CTRL_PT IPA_CTRL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100153#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100154 /* up-facing port for GSUP */
155 port IPA_GSUP_PT IPA_GSUP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100156#endif
Harald Weltedf327232017-12-28 22:51:51 +0100157
Harald Weltec76f29f2017-11-22 12:46:46 +0100158 /* up-facing port for other streams */
159 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +0100160
161 var boolean g_initialized := false;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100162 var IPL4asp_Types.ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +0100163 /* Are we a BSC/MGW (truel) or MSC (false) */
164 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +0100165
166 var IpaMode g_mode;
Harald Welte2d86aff2018-04-17 11:23:04 +0200167 var boolean g_ccm_enabled;
Harald Weltee09921f2017-12-07 17:49:00 +0100168 var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +0100169}
170
Harald Weltee21096d2017-12-04 20:45:12 +0100171type record IPA_CCM_Parameters {
172 charstring ser_nr optional,
173 charstring name optional,
174 charstring location1 optional,
175 charstring location2 optional,
176 charstring equip_version optional,
177 charstring sw_version optional,
178 charstring ip_addr optional,
179 charstring mac_addr optional,
180 charstring unit_id optional,
181 charstring osmo_rand optional
182}
183
Harald Weltee09921f2017-12-07 17:49:00 +0100184const IPA_CCM_Parameters c_IPA_default_ccm_pars := {
185 ser_nr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100186 name := "mahlzeit",
Harald Weltee09921f2017-12-07 17:49:00 +0100187 location1 := "",
188 location2 := "",
189 equip_version := "",
190 sw_version := "",
191 ip_addr := "",
192 mac_addr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100193 unit_id := "0/1/2",
Harald Weltee09921f2017-12-07 17:49:00 +0100194 osmo_rand := ""
Harald Weltee21096d2017-12-04 20:45:12 +0100195};
196
Harald Weltebdb63702017-12-09 01:15:44 +0100197/* Function to use to connect as client to a remote IPA Server */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100198function f_connect(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
199 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100200 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100201 var IPL4asp_Types.Result res;
Harald Welted86cdc62017-11-22 00:45:07 +0100202 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
203 local_host, local_port, 0, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200204 if (not ispresent(res.connId)) {
205 setverdict(fail, "Could not connect IPA socket, check your configuration");
206 self.stop;
207 }
Harald Welted86cdc62017-11-22 00:45:07 +0100208 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100209 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100210 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100211}
212
Harald Weltebdb63702017-12-09 01:15:44 +0100213/* Function to use to bind to a local port as IPA server, accepting remote clients */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100214function f_bind(charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100215 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100216 var IPL4asp_Types.Result res;
Harald Welteb3414b22017-11-23 18:22:10 +0100217 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
218 local_host, local_port, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200219 if (not ispresent(res.connId)) {
220 setverdict(fail, "Could not listen IPA socket, check your configuration");
221 self.stop;
222 }
Harald Welteb3414b22017-11-23 18:22:10 +0100223 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100224 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100225 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100226}
227
Harald Weltedf277252018-02-20 15:49:30 +0100228#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100229template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
230 sio := { '10'B, '00'B, '0011'B },
231 opc := opc,
232 dpc := 0,
233 sls := 0,
234 data := data
235}
Harald Weltedf277252018-02-20 15:49:30 +0100236#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100237
238
239private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
240 len := 0, /* overwritten by codec */
241 tag := tag,
242 data := payload
243}
244
Harald Welte0d846a72017-12-07 17:58:28 +0100245private function f_send_IPA_EVT(template ASP_IPA_Event evt) runs on IPA_Emulation_CT {
Harald Weltedf277252018-02-20 15:49:30 +0100246#ifdef IPA_EMULATION_RSL
Harald Welte5819b552017-12-09 02:55:46 +0100247 if (IPA_RSL_PORT.checkstate("Connected")) {
248 IPA_RSL_PORT.send(evt);
249 }
Harald Weltedf277252018-02-20 15:49:30 +0100250#endif
Harald Welte5819b552017-12-09 02:55:46 +0100251 if (IPA_CTRL_PORT.checkstate("Connected")) {
252 IPA_CTRL_PORT.send(evt);
253 }
Harald Weltedf277252018-02-20 15:49:30 +0100254#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100255 if (IPA_GSUP_PORT.checkstate("Connected")) {
256 IPA_GSUP_PORT.send(evt);
257 }
Harald Weltedf277252018-02-20 15:49:30 +0100258#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100259 /* FIXME: to other ports */
260}
261
Harald Welted86cdc62017-11-22 00:45:07 +0100262/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100263private 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 +0100264 var integer i;
265 var PDU_IPA_CCM resp := {
266 msg_type := IPAC_MSGT_ID_RESP,
267 u := {
268 resp := {}
269 }
270 }
271
272 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
273 var IpaCcmIdTag tag := get.u.get[i].tag;
274 var charstring foo;
275 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100276 case (IPAC_IDTAG_SERNR) {
277 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100278 }
279 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100280 foo := g_ccm_pars.name;
281 }
282 case (IPAC_IDTAG_LOCATION1) {
283 foo := g_ccm_pars.location1;
284 }
285 case (IPAC_IDTAG_LOCATION2) {
286 foo := g_ccm_pars.location2;
287 }
288 case (IPAC_IDTAG_EQUIPVERS) {
289 foo := g_ccm_pars.equip_version;
290 }
291 case (IPAC_IDTAG_SWVERSION) {
292 foo := g_ccm_pars.sw_version;
293 }
294 case (IPAC_IDTAG_IPADDR) {
295 foo := g_ccm_pars.ip_addr;
296 }
297 case (IPAC_IDTAG_MACADDR) {
298 foo := g_ccm_pars.mac_addr;
299 }
300 case (IPAC_IDTAG_UNIT) {
301 foo := g_ccm_pars.unit_id;
302 }
303 case (IPAC_IDTAG_OSMO_RAND) {
304 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100305 }
306 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100307 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100308 }
309 }
310 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
311 }
312
313 return resp;
314}
315
316/* transmit IPA CCM message */
317private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100318 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 +0100319 log("CCM Tx:", ccm);
320 IPA_PORT.send(ipa_tx);
321}
322
323template PDU_IPA_CCM ts_IPA_PONG := {
324 msg_type := IPAC_MSGT_PONG,
325 u := omit
326}
327
328template PDU_IPA_CCM ts_IPA_ACK := {
329 msg_type := IPAC_MSGT_ID_ACK,
330 u := omit
331}
332
Harald Welteb3414b22017-11-23 18:22:10 +0100333template PDU_IPA_CCM ts_IPA_ID_GET := {
334 msg_type := IPAC_MSGT_ID_GET,
335 u := {
336 get := {
337 { 1, IPAC_IDTAG_UNITNAME }
338 }
339 }
340}
341
Harald Welted86cdc62017-11-22 00:45:07 +0100342/* receive IPA CCM message */
Harald Welte2d86aff2018-04-17 11:23:04 +0200343private function f_ccm_rx_client(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100344 select (ccm.msg_type) {
345 case (IPAC_MSGT_PING) {
346 f_ccm_tx(valueof(ts_IPA_PONG));
347 }
348 case (IPAC_MSGT_ID_ACK) {
Harald Welte2d86aff2018-04-17 11:23:04 +0200349 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welted86cdc62017-11-22 00:45:07 +0100350 }
351 case (IPAC_MSGT_ID_GET) {
352 f_ccm_tx(f_ccm_make_id_resp(ccm));
353 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200354 case else {
355 log("Unknown/unsupported IPA CCM message type", ccm);
356 }
357 }
358}
359
360private function f_ccm_rx_server(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
361 select (ccm.msg_type) {
362 case (IPAC_MSGT_PING) {
363 f_ccm_tx(valueof(ts_IPA_PONG));
364 }
365 case (IPAC_MSGT_ID_ACK) {
366 /* the IPA server should at some point receive an ID_ACK from the client,
367 * in case of RSL/OML from nanoBTS, this is actually the first message after
368 * the TCP connection is established. Other implementations may differ.
369 * We currently ignore it completely - but actually we should make sure that
370 * one ID_ACK is received by the server at some point */
371 }
Harald Welte3bc387f2018-02-21 12:18:46 +0100372 case (IPAC_MSGT_ID_RESP) {
373 log("IPA ID RESP: ", ccm.u.resp);
Harald Welte2d86aff2018-04-17 11:23:04 +0200374 /* acknowledge any identity that the client may have sent */
375 f_ccm_tx(valueof(ts_IPA_ACK));
Harald Welte3bc387f2018-02-21 12:18:46 +0100376 }
Harald Welted86cdc62017-11-22 00:45:07 +0100377 case else {
378 log("Unknown/unsupported IPA CCM message type", ccm);
379 }
380 }
381}
382
Harald Weltec76f29f2017-11-22 12:46:46 +0100383private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
384 var ASP_IPA_Unitdata ret := {
385 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100386 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100387 payload := ipa_rx.msg
388 }
389 return ret;
390}
391
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100392private function f_from_asp(IPL4asp_Types.ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100393 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
394 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100395 return ret;
396}
Harald Welted86cdc62017-11-22 00:45:07 +0100397
Harald Weltedf277252018-02-20 15:49:30 +0100398#ifdef IPA_EMULATION_RSL
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100399private function f_from_rsl(IPL4asp_Types.ConnectionId connId, ASP_RSL_Unitdata rsl_tx) return IPA_Send {
Harald Welte0d846a72017-12-07 17:58:28 +0100400 var octetstring payload := enc_RSL_Message(rsl_tx.rsl);
401 var IPA_Send ret := valueof(t_IPA_Send(connId, rsl_tx.streamId, payload));
402 return ret;
403}
Harald Weltedf277252018-02-20 15:49:30 +0100404#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100405
Harald Weltebdb63702017-12-09 01:15:44 +0100406/* main function to use for a client-side IPA implementation */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100407function main_client(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
408 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Welte2d86aff2018-04-17 11:23:04 +0200409 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars,
410 boolean ccm_enabled := true) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100411 g_mode := IPA_MODE_CLIENT;
Harald Welte2d86aff2018-04-17 11:23:04 +0200412 g_ccm_enabled := ccm_enabled;
Harald Weltee09921f2017-12-07 17:49:00 +0100413 f_connect(remote_host, remote_port, local_host, local_port, ccm_pars);
Harald Welte2d86aff2018-04-17 11:23:04 +0200414 if (g_ccm_enabled) {
415 /* we're a client: Send ID_ACK immediately after connect */
416 f_ccm_tx(valueof(ts_IPA_ACK));
417 }
Harald Welte03c0e562017-12-09 02:55:12 +0100418 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welteb3414b22017-11-23 18:22:10 +0100419 ScanEvents();
420}
421
Harald Weltebdb63702017-12-09 01:15:44 +0100422/* main function to use for a server-side IPA implementation */
Harald Welte2d86aff2018-04-17 11:23:04 +0200423function main_server(charstring local_host, IPL4asp_Types.PortNumber local_port,
424 boolean ccm_enabled := true) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100425 g_mode := IPA_MODE_SERVER;
Harald Welte2d86aff2018-04-17 11:23:04 +0200426 g_ccm_enabled := ccm_enabled;
Harald Welteb3414b22017-11-23 18:22:10 +0100427 f_bind(local_host, local_port);
428 ScanEvents();
429}
430
Harald Weltedf277252018-02-20 15:49:30 +0100431private function f_ctrl_to_user(octetstring msg) runs on IPA_Emulation_CT {
432 var charstring msg_ch := oct2char(msg);
433 IPA_CTRL_PORT.send(dec_CtrlMessage(msg_ch));
434}
435
436#ifdef IPA_EMULATION_GSUP
437private function f_gsup_to_user(octetstring msg) runs on IPA_Emulation_CT {
438 var GSUP_PDU gsup := dec_GSUP_PDU(msg);
439 f_gsup_postprocess_decoded(gsup);
440 IPA_GSUP_PORT.send(gsup);
441}
442#endif
443
444#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100445private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
446 var charstring msg_ch := oct2char(msg);
447 if (g_is_bsc_mgw) {
448 log("============");
449 log(msg_ch);
450 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
451 } else {
452 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
453 }
454}
455
Harald Welte92632e12017-11-25 02:31:20 +0100456private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
457 if (mp_ipa_mgcp_uses_osmo_ext) {
458 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
459 } else {
460 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
461 }
462}
Harald Weltedf277252018-02-20 15:49:30 +0100463#endif
Harald Welte92632e12017-11-25 02:31:20 +0100464
Harald Weltebdb63702017-12-09 01:15:44 +0100465/* main loop function for both client and server. 'thread' of the component */
Harald Welteb3414b22017-11-23 18:22:10 +0100466private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100467 var IPA_RecvFrom ipa_rx;
Harald Welteb3414b22017-11-23 18:22:10 +0100468 var ASP_Event asp_evt;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100469 var Socket_API_Definitions.PortEvent port_evt;
Harald Weltedf277252018-02-20 15:49:30 +0100470 var octetstring payload;
471 var CtrlMessage ctrl_msg;
472 var ASP_IPA_Unitdata ipa_ud;
473#ifdef IPA_EMULATION_SCCP
474 var ASP_MTP3_TRANSFERreq mtp_req;
475#endif
476#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100477 var MgcpCommand mgcp_cmd;
478 var MgcpResponse mgcp_rsp;
Harald Weltedf277252018-02-20 15:49:30 +0100479#endif
480#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100481 var GSUP_PDU gsup_msg;
Harald Weltedf277252018-02-20 15:49:30 +0100482#endif
483#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100484 var ASP_RSL_Unitdata rsl;
Harald Weltedf277252018-02-20 15:49:30 +0100485#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100486
Harald Welte3e6ad892017-12-12 14:39:46 +0100487 /* Set function for dissecting the binary */
488 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
489 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
490
Harald Welted86cdc62017-11-22 00:45:07 +0100491 while (true) {
492 alt {
493 /* Received IPA -> up into SCCP stack */
Harald Welte2d86aff2018-04-17 11:23:04 +0200494 [g_ccm_enabled] IPA_PORT.receive(IPA_RecvFrom:{?,IPAC_PROTO_CCM,omit,?}) -> value ipa_rx {
495 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
496 log("CCM Rx:", ccm);
497 select (g_mode) {
498 case (IPA_MODE_CLIENT) {
499 f_ccm_rx_client(ccm);
500 }
501 case (IPA_MODE_SERVER) {
502 f_ccm_rx_server(ccm);
503 }
504 case else {
505 setverdict(fail, "Unknown mode");
506 self.stop;
507 }
Harald Weltedf277252018-02-20 15:49:30 +0100508 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200509 }
510 [] IPA_PORT.receive(IPA_RecvFrom:?) -> value ipa_rx {
511 select (ipa_rx.streamId) {
Harald Weltedf277252018-02-20 15:49:30 +0100512#ifdef IPA_EMULATION_SCCP
513 case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100514 var ASP_MTP3_TRANSFERind mtp;
515 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
516 MTP3_SP_PORT.send(mtp);
Harald Weltedf277252018-02-20 15:49:30 +0100517 }
518#endif
519#ifdef IPA_EMULATION_MGCP
520 case (IPAC_PROTO_MGCP_OLD) {
Harald Weltec82eef42017-11-24 20:40:12 +0100521 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100522 }
523#endif
524#ifdef IPA_EMULATION_RSL
525 case (t_IpaSidRSL) {
Harald Welte0d846a72017-12-07 17:58:28 +0100526 rsl := {
527 streamId := ipa_rx.streamId,
528 rsl := dec_RSL_Message(ipa_rx.msg)
529 };
530 IPA_RSL_PORT.send(rsl);
Harald Weltedf277252018-02-20 15:49:30 +0100531 }
532#endif
533 case (IPAC_PROTO_OSMO) {
Harald Weltec82eef42017-11-24 20:40:12 +0100534 select (ipa_rx.streamIdExt) {
Harald Weltedf277252018-02-20 15:49:30 +0100535#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100536 case (IPAC_PROTO_EXT_MGCP) {
537 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100538 }
539#endif
540 case (IPAC_PROTO_EXT_CTRL) {
Harald Weltea76c4bb2017-12-09 02:06:07 +0100541 f_ctrl_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100542 }
543#ifdef IPA_EMULATION_GSUP
544 case (IPAC_PROTO_EXT_GSUP) {
Harald Weltedf327232017-12-28 22:51:51 +0100545 f_gsup_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100546 }
547#endif
548 case else {
Harald Weltec82eef42017-11-24 20:40:12 +0100549 IPA_SP_PORT.send(f_to_asp(ipa_rx));
550 }
Harald Welted86cdc62017-11-22 00:45:07 +0100551 }
Harald Weltedf277252018-02-20 15:49:30 +0100552 }
553 case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100554 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100555 }
556 }
557 }
558
Harald Welteb3414b22017-11-23 18:22:10 +0100559 /* server only */
560 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
561 log("IPA: Connected");
562 g_ipa_conn_id := asp_evt.connOpened.connId;
Harald Welte0d846a72017-12-07 17:58:28 +0100563 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welte2d86aff2018-04-17 11:23:04 +0200564 if (g_mode == IPA_MODE_SERVER and g_ccm_enabled) {
Harald Welteb3414b22017-11-23 18:22:10 +0100565 f_ccm_tx(valueof(ts_IPA_ID_GET));
566 }
567 }
568
569 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
570 log("IPA: Closed");
571 g_ipa_conn_id := -1;
Harald Welte0d846a72017-12-07 17:58:28 +0100572 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
Harald Welteb3414b22017-11-23 18:22:10 +0100573 self.stop;
574 }
575
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100576 [] IPA_PORT.receive(Socket_API_Definitions.PortEvent:{result:={errorCode:=ERROR_SOCKET, connId:=?, os_error_code:=?, os_error_text:=?}}) -> value port_evt {
577 log("PortEvent: ERROR_SOCKET: ", port_evt);
578 g_ipa_conn_id := -1;
579 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
580 self.stop;
581 }
582
Harald Weltedf277252018-02-20 15:49:30 +0100583#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100584 /* Received SCCP -> down into IPA */
585 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100586 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
587 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100588 IPA_PORT.send(ipa_tx);
589 }
Harald Weltedf277252018-02-20 15:49:30 +0100590#endif
Harald Weltec76f29f2017-11-22 12:46:46 +0100591
Harald Weltedf277252018-02-20 15:49:30 +0100592#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100593 /* Received MGCP -> down into IPA */
594 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100595 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
596 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100597 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
598 }
599 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100600 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100601 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100602 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
603 }
Harald Weltedf277252018-02-20 15:49:30 +0100604#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100605
Harald Weltea76c4bb2017-12-09 02:06:07 +0100606 [] IPA_CTRL_PORT.receive(CtrlMessage:?) -> value ctrl_msg {
607 payload := char2oct(enc_CtrlMessage(ctrl_msg));
608 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_CTRL));
609 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
610 }
611
Harald Weltedf277252018-02-20 15:49:30 +0100612#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100613 [] IPA_GSUP_PORT.receive(GSUP_PDU:?) -> value gsup_msg {
Harald Welte2f562b12018-01-24 20:52:38 +0100614 f_gsup_preprocess_encoded(gsup_msg);
Harald Weltedf327232017-12-28 22:51:51 +0100615 payload := enc_GSUP_PDU(gsup_msg);
616 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_GSUP));
617 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
618 }
Harald Weltedf277252018-02-20 15:49:30 +0100619#endif
Harald Weltedf327232017-12-28 22:51:51 +0100620
Harald Weltedf277252018-02-20 15:49:30 +0100621#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100622 /* Received RSL -> down into IPA */
623 [] IPA_RSL_PORT.receive(ASP_RSL_Unitdata:?) -> value rsl {
624 IPA_PORT.send(f_from_rsl(g_ipa_conn_id, rsl));
625 }
Harald Weltedf277252018-02-20 15:49:30 +0100626#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100627
628 /* Received MISC (OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100629 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
630 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
631 }
632
633
Harald Welted86cdc62017-11-22 00:45:07 +0100634 }
635 }
636}
637
638}