blob: 3ec69226edabaaf4d7042e73ed13d3c78473cb60 [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
Pau Espin Pedrol76ba5412019-06-10 11:00:33 +02005 * handshake for establishing the identity of the client to the server.
Harald Welte35bb7162018-01-03 21:07:52 +01006 *
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 Welte34b5a952019-05-27 11:54:11 +020011 * (C) 2017-2019 by Harald Welte <laforge@gnumonks.org>
12 * contributions by sysmocom - s.f.m.c. GmbH
Harald Welte35bb7162018-01-03 21:07:52 +010013 * All rights reserved.
14 *
15 * Released under the terms of GNU General Public License, Version 2 or
16 * (at your option) any later version.
Harald Welte34b5a952019-05-27 11:54:11 +020017 *
18 * SPDX-License-Identifier: GPL-2.0-or-later
Harald Welte35bb7162018-01-03 21:07:52 +010019 */
Harald Weltebdb63702017-12-09 01:15:44 +010020
Harald Welted86cdc62017-11-22 00:45:07 +010021import from IPA_Types all;
22import from IPA_CodecPort all;
23import from IPA_CodecPort_CtrlFunct all;
24import from IPL4asp_Types all;
Harald Welte12188832017-11-29 11:47:13 +010025import from IPL4asp_PortType all;
Stefan Sperling830dc9d2018-02-12 21:08:28 +010026import from Socket_API_Definitions all;
Harald Welted86cdc62017-11-22 00:45:07 +010027
Harald Weltedf277252018-02-20 15:49:30 +010028#ifdef IPA_EMULATION_SCCP
29import from MTP3asp_Types all;
30import from MTP3asp_PortType all;
31#endif
32
33#ifdef IPA_EMULATION_RSL
34import from RSL_Types all;
35#endif
36
Harald Weltec6826662019-02-06 22:26:46 +010037#ifdef IPA_EMULATION_OML
38import from AbisOML_Types all;
39#endif
40
Harald Weltedf277252018-02-20 15:49:30 +010041#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +010042import from MGCP_Types all;
Harald Weltedf277252018-02-20 15:49:30 +010043#endif
44
45#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +010046import from GSUP_Types all;
Harald Weltedf277252018-02-20 15:49:30 +010047#endif
Harald Weltec82eef42017-11-24 20:40:12 +010048
Harald Welte7460a722018-10-10 12:28:27 +020049#ifdef IPA_EMULATION_RSPRO
50import from RSPRO all;
51import from RSPRO_Types all;
52#endif
53
54
Harald Weltea76c4bb2017-12-09 02:06:07 +010055import from Osmocom_CTRL_Types all;
56
Harald Welted86cdc62017-11-22 00:45:07 +010057modulepar {
Harald Welte92632e12017-11-25 02:31:20 +010058 /* Use Osmocom extended IPA mux header */
59 boolean mp_ipa_mgcp_uses_osmo_ext := true;
Harald Welted86cdc62017-11-22 00:45:07 +010060}
Harald Welted86cdc62017-11-22 00:45:07 +010061
Harald Welteb3414b22017-11-23 18:22:10 +010062type enumerated IpaMode {
63 IPA_MODE_CLIENT,
64 IPA_MODE_SERVER
65}
66
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +020067type enumerated IpaInitBehavior {
68 IPA_INIT_SEND_IPA_ID_GET,
69 IPA_INIT_SEND_IPA_ID_ACK
70}
71
Harald Weltec76f29f2017-11-22 12:46:46 +010072type record ASP_IPA_Unitdata {
73 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010074 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010075 octetstring payload
76}
77
Harald Welte0d846a72017-12-07 17:58:28 +010078type enumerated ASP_IPA_EventUpDown {
79 ASP_IPA_EVENT_DOWN,
80 ASP_IPA_EVENT_UP,
81 ASP_IPA_EVENT_ID_ACK
82}
83
Harald Weltebdb63702017-12-09 01:15:44 +010084/* an event indicating us whether or not a connection is physically up or down,
85 * and whether we have received an ID_ACK */
Harald Welte0d846a72017-12-07 17:58:28 +010086type union ASP_IPA_Event {
87 ASP_IPA_EventUpDown up_down
88}
89
90template ASP_IPA_Event t_ASP_IPA_EVT_UD(ASP_IPA_EventUpDown ud) := {
91 up_down := ud
92}
93
Harald Welte1dd8f372017-11-25 02:25:27 +010094template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
95 template IpaExtStreamId esid := omit) := {
96 streamId := sid,
97 streamIdExt := esid,
98 payload := pl
99}
100
Harald Weltedf277252018-02-20 15:49:30 +0100101#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +0100102/* like ASP_IPA_Unitdata, but with RSL_Message abstract type instead of octetstring */
Harald Welte0d846a72017-12-07 17:58:28 +0100103type record ASP_RSL_Unitdata {
104 IpaStreamId streamId,
105 RSL_Message rsl
106};
107
Harald Welte7ae019e2017-12-09 00:54:15 +0100108template ASP_RSL_Unitdata ts_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
Harald Welte0d846a72017-12-07 17:58:28 +0100109 streamId := sid,
110 rsl := valueof(rsl)
111}
112
Harald Welte7ae019e2017-12-09 00:54:15 +0100113template ASP_RSL_Unitdata tr_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
114 streamId := sid,
115 rsl := rsl
116}
117
Harald Welte0d846a72017-12-07 17:58:28 +0100118template IpaStreamId t_IpaSidRSL := ( IPAC_PROTO_RSL_TRX0, IPAC_PROTO_RSL_TRX1,
119 IPAC_PROTO_RSL_TRX2, IPAC_PROTO_RSL_TRX3 );
Harald Weltedf277252018-02-20 15:49:30 +0100120#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100121
Harald Weltec6826662019-02-06 22:26:46 +0100122
Harald Weltebdb63702017-12-09 01:15:44 +0100123/* Client port for general IPA messages, not further decoded */
Harald Weltec76f29f2017-11-22 12:46:46 +0100124type port IPA_SP_PT message {
Harald Welte0d846a72017-12-07 17:58:28 +0100125 inout ASP_IPA_Unitdata, ASP_IPA_Event;
Harald Weltec76f29f2017-11-22 12:46:46 +0100126} with { extension "internal" }
127
Harald Weltedf277252018-02-20 15:49:30 +0100128#ifdef IPA_EMULATION_MGCP
Harald Weltebdb63702017-12-09 01:15:44 +0100129/* Client port for MGCP inside IPA */
Harald Weltec82eef42017-11-24 20:40:12 +0100130type port IPA_MGCP_PT message {
131 inout MgcpCommand, MgcpResponse;
132} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100133#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100134
Harald Weltedf277252018-02-20 15:49:30 +0100135#ifdef IPA_EMULATION_RSL
Harald Weltebdb63702017-12-09 01:15:44 +0100136/* Client port for A-bis RSL inside IPA */
Harald Welte0d846a72017-12-07 17:58:28 +0100137type port IPA_RSL_PT message {
138 inout ASP_RSL_Unitdata, ASP_IPA_Event;
139} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100140#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100141
Harald Weltec6826662019-02-06 22:26:46 +0100142#ifdef IPA_EMULATION_OML
143/* Client port for A-bis OML inside IPA */
144type port IPA_OML_PT message {
145 inout OML_PDU, octetstring, ASP_IPA_Event;
146} with { extension "internal" }
147#endif
148
Harald Weltea76c4bb2017-12-09 02:06:07 +0100149/* Client port for CTRL inside IPA */
150type port IPA_CTRL_PT message {
151 inout CtrlMessage, ASP_IPA_Event;
152} with { extension "internal" }
153
Harald Weltedf277252018-02-20 15:49:30 +0100154#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100155/* Client port for CTRL inside IPA */
156type port IPA_GSUP_PT message {
157 inout GSUP_PDU, ASP_IPA_Event;
158} with { extension "internal" }
Harald Weltedf277252018-02-20 15:49:30 +0100159#endif
Harald Weltedf327232017-12-28 22:51:51 +0100160
Harald Welte7460a722018-10-10 12:28:27 +0200161#ifdef IPA_EMULATION_RSPRO
162type port IPA_RSPRO_PT message {
163 inout RsproPDU, ASP_IPA_Event;
164} with { extension "internal" }
165#endif
166
167
168
Harald Weltedf327232017-12-28 22:51:51 +0100169
Harald Welted86cdc62017-11-22 00:45:07 +0100170type component IPA_Emulation_CT {
171 /* down-facing port to IPA codec port */
172 port IPA_CODEC_PT IPA_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100173#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100174 /* up-facing port to SCCP */
175 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100176#endif
177#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100178 /* up-facing port for MGCP */
179 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100180#endif
181#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100182 /* up-facing port for RSL */
183 port IPA_RSL_PT IPA_RSL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100184#endif
Harald Weltec6826662019-02-06 22:26:46 +0100185#ifdef IPA_EMULATION_OML
186 /* up-facing port for OML */
187 port IPA_OML_PT IPA_OML_PORT;
188#endif
Harald Weltea76c4bb2017-12-09 02:06:07 +0100189 /* up-facing port for CTRL */
190 port IPA_CTRL_PT IPA_CTRL_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100191#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100192 /* up-facing port for GSUP */
193 port IPA_GSUP_PT IPA_GSUP_PORT;
Harald Weltedf277252018-02-20 15:49:30 +0100194#endif
Harald Welte7460a722018-10-10 12:28:27 +0200195#ifdef IPA_EMULATION_RSPRO
196 /* up-facing port for RSPRO */
197 port IPA_RSPRO_PT IPA_RSPRO_PORT;
198#endif
Harald Weltedf327232017-12-28 22:51:51 +0100199
Harald Weltec76f29f2017-11-22 12:46:46 +0100200 /* up-facing port for other streams */
201 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +0100202
203 var boolean g_initialized := false;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100204 var IPL4asp_Types.ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +0100205 /* Are we a BSC/MGW (truel) or MSC (false) */
206 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +0100207
208 var IpaMode g_mode;
Harald Welte2d86aff2018-04-17 11:23:04 +0200209 var boolean g_ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200210 var IpaInitBehavior g_init_behavior;
Harald Weltee09921f2017-12-07 17:49:00 +0100211 var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +0100212}
213
Harald Weltee21096d2017-12-04 20:45:12 +0100214type record IPA_CCM_Parameters {
215 charstring ser_nr optional,
216 charstring name optional,
217 charstring location1 optional,
218 charstring location2 optional,
219 charstring equip_version optional,
220 charstring sw_version optional,
221 charstring ip_addr optional,
222 charstring mac_addr optional,
223 charstring unit_id optional,
224 charstring osmo_rand optional
225}
226
Harald Weltee09921f2017-12-07 17:49:00 +0100227const IPA_CCM_Parameters c_IPA_default_ccm_pars := {
228 ser_nr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100229 name := "mahlzeit",
Harald Weltee09921f2017-12-07 17:49:00 +0100230 location1 := "",
231 location2 := "",
232 equip_version := "",
233 sw_version := "",
234 ip_addr := "",
235 mac_addr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100236 unit_id := "0/1/2",
Harald Weltee09921f2017-12-07 17:49:00 +0100237 osmo_rand := ""
Harald Weltee21096d2017-12-04 20:45:12 +0100238};
239
Harald Weltebdb63702017-12-09 01:15:44 +0100240/* Function to use to connect as client to a remote IPA Server */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100241function f_connect(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
242 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100243 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100244 var IPL4asp_Types.Result res;
Harald Welted86cdc62017-11-22 00:45:07 +0100245 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
246 local_host, local_port, 0, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200247 if (not ispresent(res.connId)) {
Stefan Sperling6a90be42018-08-31 15:05:39 +0200248 setverdict(fail, "Could not connect IPA socket from ", local_host, " port ", local_port,
249 " to ", remote_host, " port ", remote_port, "; check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200250 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200251 }
Harald Welted86cdc62017-11-22 00:45:07 +0100252 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100253 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100254 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100255}
256
Harald Weltebdb63702017-12-09 01:15:44 +0100257/* Function to use to bind to a local port as IPA server, accepting remote clients */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100258function f_bind(charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100259 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100260 var IPL4asp_Types.Result res;
Pau Espin Pedrol76ba5412019-06-10 11:00:33 +0200261 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
Harald Welteb3414b22017-11-23 18:22:10 +0100262 local_host, local_port, { tcp:={} });
Harald Welte9220f632018-05-23 20:27:02 +0200263 if (not ispresent(res.connId)) {
Maxb7aae8b2019-03-11 15:22:02 +0100264 setverdict(fail, "Could not listen IPA socket ", local_host, ":", local_port, ", check your configuration");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200265 mtc.stop;
Harald Welte9220f632018-05-23 20:27:02 +0200266 }
Harald Welteb3414b22017-11-23 18:22:10 +0100267 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100268 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100269 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100270}
271
Harald Weltedf277252018-02-20 15:49:30 +0100272#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100273template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
274 sio := { '10'B, '00'B, '0011'B },
275 opc := opc,
276 dpc := 0,
277 sls := 0,
278 data := data
279}
Harald Weltedf277252018-02-20 15:49:30 +0100280#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100281
282
283private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
284 len := 0, /* overwritten by codec */
285 tag := tag,
Harald Welte95686e02018-08-02 15:05:43 +0200286 data := char2oct(payload) & '00'O
Harald Welted86cdc62017-11-22 00:45:07 +0100287}
288
Harald Welte0d846a72017-12-07 17:58:28 +0100289private function f_send_IPA_EVT(template ASP_IPA_Event evt) runs on IPA_Emulation_CT {
Harald Welte2e32e432018-05-24 20:00:00 +0200290 if (IPA_SP_PORT.checkstate("Connected")) {
291 IPA_SP_PORT.send(evt);
292 }
Harald Weltedf277252018-02-20 15:49:30 +0100293#ifdef IPA_EMULATION_RSL
Harald Welte5819b552017-12-09 02:55:46 +0100294 if (IPA_RSL_PORT.checkstate("Connected")) {
295 IPA_RSL_PORT.send(evt);
296 }
Harald Weltedf277252018-02-20 15:49:30 +0100297#endif
Harald Weltec6826662019-02-06 22:26:46 +0100298#ifdef IPA_EMULATION_OML
299 if (IPA_OML_PORT.checkstate("Connected")) {
300 IPA_OML_PORT.send(evt);
301 }
302#endif
Harald Welte5819b552017-12-09 02:55:46 +0100303 if (IPA_CTRL_PORT.checkstate("Connected")) {
304 IPA_CTRL_PORT.send(evt);
305 }
Harald Weltedf277252018-02-20 15:49:30 +0100306#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100307 if (IPA_GSUP_PORT.checkstate("Connected")) {
308 IPA_GSUP_PORT.send(evt);
309 }
Harald Weltedf277252018-02-20 15:49:30 +0100310#endif
Harald Welte7460a722018-10-10 12:28:27 +0200311#ifdef IPA_EMULATION_RSPRO
312 if (IPA_RSPRO_PORT.checkstate("Connected")) {
313 IPA_RSPRO_PORT.send(evt);
314 }
315#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100316 /* FIXME: to other ports */
317}
318
Harald Welted86cdc62017-11-22 00:45:07 +0100319/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100320private 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 +0100321 var integer i;
322 var PDU_IPA_CCM resp := {
323 msg_type := IPAC_MSGT_ID_RESP,
324 u := {
325 resp := {}
326 }
327 }
328
329 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
330 var IpaCcmIdTag tag := get.u.get[i].tag;
331 var charstring foo;
332 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100333 case (IPAC_IDTAG_SERNR) {
334 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100335 }
336 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100337 foo := g_ccm_pars.name;
338 }
339 case (IPAC_IDTAG_LOCATION1) {
340 foo := g_ccm_pars.location1;
341 }
342 case (IPAC_IDTAG_LOCATION2) {
343 foo := g_ccm_pars.location2;
344 }
345 case (IPAC_IDTAG_EQUIPVERS) {
346 foo := g_ccm_pars.equip_version;
347 }
348 case (IPAC_IDTAG_SWVERSION) {
349 foo := g_ccm_pars.sw_version;
350 }
351 case (IPAC_IDTAG_IPADDR) {
352 foo := g_ccm_pars.ip_addr;
353 }
354 case (IPAC_IDTAG_MACADDR) {
355 foo := g_ccm_pars.mac_addr;
356 }
357 case (IPAC_IDTAG_UNIT) {
358 foo := g_ccm_pars.unit_id;
359 }
360 case (IPAC_IDTAG_OSMO_RAND) {
361 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100362 }
363 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100364 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100365 }
366 }
367 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
368 }
369
370 return resp;
371}
372
373/* transmit IPA CCM message */
374private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100375 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 +0100376 log("CCM Tx:", ccm);
377 IPA_PORT.send(ipa_tx);
378}
379
380template PDU_IPA_CCM ts_IPA_PONG := {
381 msg_type := IPAC_MSGT_PONG,
382 u := omit
383}
384
385template PDU_IPA_CCM ts_IPA_ACK := {
386 msg_type := IPAC_MSGT_ID_ACK,
387 u := omit
388}
389
Harald Welteb3414b22017-11-23 18:22:10 +0100390template PDU_IPA_CCM ts_IPA_ID_GET := {
391 msg_type := IPAC_MSGT_ID_GET,
392 u := {
393 get := {
394 { 1, IPAC_IDTAG_UNITNAME }
395 }
396 }
397}
398
Harald Welted86cdc62017-11-22 00:45:07 +0100399/* receive IPA CCM message */
Harald Welte2d86aff2018-04-17 11:23:04 +0200400private function f_ccm_rx_client(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100401 select (ccm.msg_type) {
402 case (IPAC_MSGT_PING) {
403 f_ccm_tx(valueof(ts_IPA_PONG));
404 }
405 case (IPAC_MSGT_ID_ACK) {
Harald Welte2d86aff2018-04-17 11:23:04 +0200406 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welted86cdc62017-11-22 00:45:07 +0100407 }
408 case (IPAC_MSGT_ID_GET) {
409 f_ccm_tx(f_ccm_make_id_resp(ccm));
410 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200411 case else {
412 log("Unknown/unsupported IPA CCM message type", ccm);
413 }
414 }
415}
416
417private function f_ccm_rx_server(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
418 select (ccm.msg_type) {
419 case (IPAC_MSGT_PING) {
420 f_ccm_tx(valueof(ts_IPA_PONG));
421 }
422 case (IPAC_MSGT_ID_ACK) {
423 /* the IPA server should at some point receive an ID_ACK from the client,
424 * in case of RSL/OML from nanoBTS, this is actually the first message after
425 * the TCP connection is established. Other implementations may differ.
426 * We currently ignore it completely - but actually we should make sure that
427 * one ID_ACK is received by the server at some point */
Harald Welte2e32e432018-05-24 20:00:00 +0200428 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK));
Harald Welte2d86aff2018-04-17 11:23:04 +0200429 }
Harald Welte3bc387f2018-02-21 12:18:46 +0100430 case (IPAC_MSGT_ID_RESP) {
431 log("IPA ID RESP: ", ccm.u.resp);
Harald Welte2d86aff2018-04-17 11:23:04 +0200432 /* acknowledge any identity that the client may have sent */
433 f_ccm_tx(valueof(ts_IPA_ACK));
Harald Welte3bc387f2018-02-21 12:18:46 +0100434 }
Harald Welted86cdc62017-11-22 00:45:07 +0100435 case else {
436 log("Unknown/unsupported IPA CCM message type", ccm);
437 }
438 }
439}
440
Harald Weltec76f29f2017-11-22 12:46:46 +0100441private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
442 var ASP_IPA_Unitdata ret := {
443 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100444 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100445 payload := ipa_rx.msg
446 }
447 return ret;
448}
449
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100450private function f_from_asp(IPL4asp_Types.ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100451 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
452 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100453 return ret;
454}
Harald Welted86cdc62017-11-22 00:45:07 +0100455
Harald Weltedf277252018-02-20 15:49:30 +0100456#ifdef IPA_EMULATION_RSL
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100457private function f_from_rsl(IPL4asp_Types.ConnectionId connId, ASP_RSL_Unitdata rsl_tx) return IPA_Send {
Harald Welte0d846a72017-12-07 17:58:28 +0100458 var octetstring payload := enc_RSL_Message(rsl_tx.rsl);
459 var IPA_Send ret := valueof(t_IPA_Send(connId, rsl_tx.streamId, payload));
460 return ret;
461}
Harald Weltedf277252018-02-20 15:49:30 +0100462#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100463
Harald Weltec6826662019-02-06 22:26:46 +0100464#ifdef IPA_EMULATION_OML
465private function f_from_oml(IPL4asp_Types.ConnectionId connId, OML_PDU oml_tx) return IPA_Send {
466 var octetstring payload := enc_OML_PDU(oml_tx);
467 var IPA_Send ret := valueof(t_IPA_Send(connId, IPAC_PROTO_OML, payload));
468 return ret;
469}
470#endif
471
Harald Weltebdb63702017-12-09 01:15:44 +0100472/* main function to use for a client-side IPA implementation */
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100473function main_client(charstring remote_host, IPL4asp_Types.PortNumber remote_port,
474 charstring local_host, IPL4asp_Types.PortNumber local_port,
Harald Welte2d86aff2018-04-17 11:23:04 +0200475 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars,
476 boolean ccm_enabled := true) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100477 g_mode := IPA_MODE_CLIENT;
Harald Welte2d86aff2018-04-17 11:23:04 +0200478 g_ccm_enabled := ccm_enabled;
Harald Weltee09921f2017-12-07 17:49:00 +0100479 f_connect(remote_host, remote_port, local_host, local_port, ccm_pars);
Harald Welte2d86aff2018-04-17 11:23:04 +0200480 if (g_ccm_enabled) {
481 /* we're a client: Send ID_ACK immediately after connect */
482 f_ccm_tx(valueof(ts_IPA_ACK));
483 }
Harald Welte03c0e562017-12-09 02:55:12 +0100484 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welteb3414b22017-11-23 18:22:10 +0100485 ScanEvents();
486}
487
Harald Weltebdb63702017-12-09 01:15:44 +0100488/* main function to use for a server-side IPA implementation */
Harald Welte2d86aff2018-04-17 11:23:04 +0200489function main_server(charstring local_host, IPL4asp_Types.PortNumber local_port,
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200490 boolean ccm_enabled := true,
491 IpaInitBehavior init_behavior := IPA_INIT_SEND_IPA_ID_GET)
492runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100493 g_mode := IPA_MODE_SERVER;
Harald Welte2d86aff2018-04-17 11:23:04 +0200494 g_ccm_enabled := ccm_enabled;
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200495 g_init_behavior := init_behavior;
Harald Welteb3414b22017-11-23 18:22:10 +0100496 f_bind(local_host, local_port);
497 ScanEvents();
498}
499
Harald Weltedf277252018-02-20 15:49:30 +0100500private function f_ctrl_to_user(octetstring msg) runs on IPA_Emulation_CT {
501 var charstring msg_ch := oct2char(msg);
502 IPA_CTRL_PORT.send(dec_CtrlMessage(msg_ch));
503}
504
505#ifdef IPA_EMULATION_GSUP
506private function f_gsup_to_user(octetstring msg) runs on IPA_Emulation_CT {
507 var GSUP_PDU gsup := dec_GSUP_PDU(msg);
508 f_gsup_postprocess_decoded(gsup);
509 IPA_GSUP_PORT.send(gsup);
510}
511#endif
512
Harald Welte7460a722018-10-10 12:28:27 +0200513#ifdef IPA_EMULATION_RSPRO
514private function f_rspro_to_user(octetstring msg) runs on IPA_Emulation_CT {
515 var RsproPDU rspro := dec_RsproPDU(msg);
516 IPA_RSPRO_PORT.send(rspro);
517}
518#endif
519
Harald Weltedf277252018-02-20 15:49:30 +0100520#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100521private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
522 var charstring msg_ch := oct2char(msg);
523 if (g_is_bsc_mgw) {
524 log("============");
525 log(msg_ch);
526 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
527 } else {
528 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
529 }
530}
531
Harald Welte92632e12017-11-25 02:31:20 +0100532private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
533 if (mp_ipa_mgcp_uses_osmo_ext) {
534 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
535 } else {
536 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
537 }
538}
Harald Weltedf277252018-02-20 15:49:30 +0100539#endif
Harald Welte92632e12017-11-25 02:31:20 +0100540
Harald Weltebdb63702017-12-09 01:15:44 +0100541/* main loop function for both client and server. 'thread' of the component */
Harald Welteb3414b22017-11-23 18:22:10 +0100542private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100543 var IPA_RecvFrom ipa_rx;
Harald Welteb3414b22017-11-23 18:22:10 +0100544 var ASP_Event asp_evt;
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100545 var Socket_API_Definitions.PortEvent port_evt;
Harald Weltedf277252018-02-20 15:49:30 +0100546 var octetstring payload;
547 var CtrlMessage ctrl_msg;
548 var ASP_IPA_Unitdata ipa_ud;
549#ifdef IPA_EMULATION_SCCP
550 var ASP_MTP3_TRANSFERreq mtp_req;
551#endif
552#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100553 var MgcpCommand mgcp_cmd;
554 var MgcpResponse mgcp_rsp;
Harald Weltedf277252018-02-20 15:49:30 +0100555#endif
556#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100557 var GSUP_PDU gsup_msg;
Harald Weltedf277252018-02-20 15:49:30 +0100558#endif
559#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100560 var ASP_RSL_Unitdata rsl;
Harald Weltedf277252018-02-20 15:49:30 +0100561#endif
Harald Weltec6826662019-02-06 22:26:46 +0100562#ifdef IPA_EMULATION_OML
563 var OML_PDU oml;
564#endif
Harald Welte7460a722018-10-10 12:28:27 +0200565#ifdef IPA_EMULATION_RSPRO
566 var RsproPDU rspro;
567#endif
Harald Welted86cdc62017-11-22 00:45:07 +0100568
Harald Welte3e6ad892017-12-12 14:39:46 +0100569 /* Set function for dissecting the binary */
570 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
571 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
572
Harald Welted86cdc62017-11-22 00:45:07 +0100573 while (true) {
574 alt {
575 /* Received IPA -> up into SCCP stack */
Harald Welte2d86aff2018-04-17 11:23:04 +0200576 [g_ccm_enabled] IPA_PORT.receive(IPA_RecvFrom:{?,IPAC_PROTO_CCM,omit,?}) -> value ipa_rx {
577 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
578 log("CCM Rx:", ccm);
579 select (g_mode) {
580 case (IPA_MODE_CLIENT) {
581 f_ccm_rx_client(ccm);
582 }
583 case (IPA_MODE_SERVER) {
584 f_ccm_rx_server(ccm);
585 }
586 case else {
587 setverdict(fail, "Unknown mode");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200588 mtc.stop;
Harald Welte2d86aff2018-04-17 11:23:04 +0200589 }
Harald Weltedf277252018-02-20 15:49:30 +0100590 }
Harald Welte2d86aff2018-04-17 11:23:04 +0200591 }
592 [] IPA_PORT.receive(IPA_RecvFrom:?) -> value ipa_rx {
593 select (ipa_rx.streamId) {
Harald Weltedf277252018-02-20 15:49:30 +0100594#ifdef IPA_EMULATION_SCCP
595 case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100596 var ASP_MTP3_TRANSFERind mtp;
597 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
598 MTP3_SP_PORT.send(mtp);
Harald Weltedf277252018-02-20 15:49:30 +0100599 }
600#endif
601#ifdef IPA_EMULATION_MGCP
602 case (IPAC_PROTO_MGCP_OLD) {
Harald Weltec82eef42017-11-24 20:40:12 +0100603 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100604 }
605#endif
606#ifdef IPA_EMULATION_RSL
607 case (t_IpaSidRSL) {
Harald Welte0d846a72017-12-07 17:58:28 +0100608 rsl := {
609 streamId := ipa_rx.streamId,
610 rsl := dec_RSL_Message(ipa_rx.msg)
611 };
612 IPA_RSL_PORT.send(rsl);
Harald Weltedf277252018-02-20 15:49:30 +0100613 }
614#endif
Harald Weltec6826662019-02-06 22:26:46 +0100615#ifdef IPA_EMULATION_OML
616 case (IPAC_PROTO_OML) {
617 oml := dec_OML_PDU(ipa_rx.msg)
618 IPA_OML_PORT.send(oml);
619 }
620#endif
Harald Weltedf277252018-02-20 15:49:30 +0100621 case (IPAC_PROTO_OSMO) {
Harald Weltec82eef42017-11-24 20:40:12 +0100622 select (ipa_rx.streamIdExt) {
Harald Weltedf277252018-02-20 15:49:30 +0100623#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100624 case (IPAC_PROTO_EXT_MGCP) {
625 f_mgcp_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100626 }
627#endif
628 case (IPAC_PROTO_EXT_CTRL) {
Harald Weltea76c4bb2017-12-09 02:06:07 +0100629 f_ctrl_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100630 }
631#ifdef IPA_EMULATION_GSUP
632 case (IPAC_PROTO_EXT_GSUP) {
Harald Weltedf327232017-12-28 22:51:51 +0100633 f_gsup_to_user(ipa_rx.msg);
Harald Weltedf277252018-02-20 15:49:30 +0100634 }
635#endif
Harald Welte7460a722018-10-10 12:28:27 +0200636#ifdef IPA_EMULATION_RSPRO
637 case (IPAC_PROTO_EXT_RSPRO) {
638 f_rspro_to_user(ipa_rx.msg);
639 }
640#endif
Harald Weltedf277252018-02-20 15:49:30 +0100641 case else {
Harald Weltec82eef42017-11-24 20:40:12 +0100642 IPA_SP_PORT.send(f_to_asp(ipa_rx));
643 }
Harald Welted86cdc62017-11-22 00:45:07 +0100644 }
Harald Weltedf277252018-02-20 15:49:30 +0100645 }
646 case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100647 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100648 }
649 }
650 }
651
Harald Welteb3414b22017-11-23 18:22:10 +0100652 /* server only */
653 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
654 log("IPA: Connected");
655 g_ipa_conn_id := asp_evt.connOpened.connId;
Harald Welte0d846a72017-12-07 17:58:28 +0100656 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welte2d86aff2018-04-17 11:23:04 +0200657 if (g_mode == IPA_MODE_SERVER and g_ccm_enabled) {
Neels Hofmeyr3bf31d22018-08-24 14:44:32 +0200658 select (g_init_behavior) {
659 case (IPA_INIT_SEND_IPA_ID_GET) {
660 f_ccm_tx(valueof(ts_IPA_ID_GET));
661 }
662 case (IPA_INIT_SEND_IPA_ID_ACK) {
663 f_ccm_tx(valueof(ts_IPA_ACK));
664 }
665 }
Harald Welteb3414b22017-11-23 18:22:10 +0100666 }
667 }
668
669 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
670 log("IPA: Closed");
671 g_ipa_conn_id := -1;
Harald Welte0d846a72017-12-07 17:58:28 +0100672 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
Harald Welteb3414b22017-11-23 18:22:10 +0100673 self.stop;
674 }
675
Stefan Sperling830dc9d2018-02-12 21:08:28 +0100676 [] IPA_PORT.receive(Socket_API_Definitions.PortEvent:{result:={errorCode:=ERROR_SOCKET, connId:=?, os_error_code:=?, os_error_text:=?}}) -> value port_evt {
677 log("PortEvent: ERROR_SOCKET: ", port_evt);
678 g_ipa_conn_id := -1;
679 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
680 self.stop;
681 }
682
Harald Weltedf277252018-02-20 15:49:30 +0100683#ifdef IPA_EMULATION_SCCP
Harald Welted86cdc62017-11-22 00:45:07 +0100684 /* Received SCCP -> down into IPA */
685 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100686 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
687 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100688 IPA_PORT.send(ipa_tx);
689 }
Harald Weltedf277252018-02-20 15:49:30 +0100690#endif
Harald Weltec76f29f2017-11-22 12:46:46 +0100691
Harald Weltedf277252018-02-20 15:49:30 +0100692#ifdef IPA_EMULATION_MGCP
Harald Weltec82eef42017-11-24 20:40:12 +0100693 /* Received MGCP -> down into IPA */
694 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100695 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
696 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100697 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
698 }
699 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100700 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100701 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100702 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
703 }
Harald Weltedf277252018-02-20 15:49:30 +0100704#endif
Harald Weltec82eef42017-11-24 20:40:12 +0100705
Harald Weltea76c4bb2017-12-09 02:06:07 +0100706 [] IPA_CTRL_PORT.receive(CtrlMessage:?) -> value ctrl_msg {
707 payload := char2oct(enc_CtrlMessage(ctrl_msg));
708 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_CTRL));
709 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
710 }
711
Harald Weltedf277252018-02-20 15:49:30 +0100712#ifdef IPA_EMULATION_GSUP
Harald Weltedf327232017-12-28 22:51:51 +0100713 [] IPA_GSUP_PORT.receive(GSUP_PDU:?) -> value gsup_msg {
Harald Welte2f562b12018-01-24 20:52:38 +0100714 f_gsup_preprocess_encoded(gsup_msg);
Harald Weltedf327232017-12-28 22:51:51 +0100715 payload := enc_GSUP_PDU(gsup_msg);
716 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_GSUP));
717 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
718 }
Harald Weltedf277252018-02-20 15:49:30 +0100719#endif
Harald Weltedf327232017-12-28 22:51:51 +0100720
Harald Welte7460a722018-10-10 12:28:27 +0200721#ifdef IPA_EMULATION_RSPRO
722 [] IPA_RSPRO_PORT.receive(RsproPDU:?) -> value rspro {
723 payload := enc_RsproPDU(rspro);
724 ipa_ud := valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_RSPRO));
725 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
726 }
727#endif
728
Harald Weltedf277252018-02-20 15:49:30 +0100729#ifdef IPA_EMULATION_RSL
Harald Welte0d846a72017-12-07 17:58:28 +0100730 /* Received RSL -> down into IPA */
731 [] IPA_RSL_PORT.receive(ASP_RSL_Unitdata:?) -> value rsl {
732 IPA_PORT.send(f_from_rsl(g_ipa_conn_id, rsl));
733 }
Harald Weltedf277252018-02-20 15:49:30 +0100734#endif
Harald Weltec6826662019-02-06 22:26:46 +0100735#ifdef IPA_EMULATION_OML
736 /* Received OML -> down into IPA */
737 [] IPA_OML_PORT.receive(OML_PDU:?) -> value oml {
738 IPA_PORT.send(f_from_oml(g_ipa_conn_id, oml));
739 }
740 [] IPA_OML_PORT.receive(octetstring:?) -> value payload {
741 IPA_PORT.send(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_OML, payload));
742 }
743#endif
Harald Welte0d846a72017-12-07 17:58:28 +0100744 /* Received MISC (OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100745 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
746 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
747 }
748
749
Harald Welted86cdc62017-11-22 00:45:07 +0100750 }
751 }
752}
753
Harald Welte2e32e432018-05-24 20:00:00 +0200754/***********************************************************************
755 * IPA Event waiter component. Wait for ASP_IPA_EVENT_ID_ACK
756 ***********************************************************************/
757
758type component IPA_EventWaiter_CT {
759 port IPA_SP_PT IPA_SP_PORT;
760}
761
762function waiter_main(template ASP_IPA_Event wait_for := t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK))
763runs on IPA_EventWaiter_CT {
764
765 alt {
766 [] IPA_SP_PORT.receive(wait_for) {
767 setverdict(pass);
768 }
769 [] IPA_SP_PORT.receive { repeat; }
770 }
771}
772
773
Harald Welted86cdc62017-11-22 00:45:07 +0100774}