blob: bf6686a245f304125a14bec9fcbd459cbc0a3af0 [file] [log] [blame]
Harald Welte714ded92017-12-08 14:00:22 +01001module RSL_Emulation {
2
Harald Welte35bb7162018-01-03 21:07:52 +01003/* RSL Emulation, runs on top of IPA_Emulation. It multiplexes/demultiplexes
4 * the individual connections (logical channels), so there can be separate TTCN-3 components
5 * handling each of the connections.
6 *
7 * The RSL_Emulation.main() function processes RSL messages from the IPA demultiplex
8 * stack via the IPA_RSL_PT, and dispatches them to the per-connection components.
9 *
10 * Outbound RSL connections are initiated by sending a RSLDC_ChanRqd primitive
11 * to the component running the RSL_Emulation.main() function.
12 *
13 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
14 * All rights reserved.
15 *
16 * Released under the terms of GNU General Public License, Version 2 or
17 * (at your option) any later version.
18 */
19
Harald Welte714ded92017-12-08 14:00:22 +010020import from General_Types all;
21import from Osmocom_Types all;
22import from GSM_Types all;
23import from GSM_RR_Types all;
24import from RSL_Types all;
25import from IPA_Types all;
26import from IPA_Emulation all;
27
28
29/* General "base class" component definition, of which specific implementations
30 * derive themselves by means of the "extends" feature */
31type component RSL_DchanHdlr {
32 /* port facing up towards dedicated channel handler */
33 port RSL_DCHAN_PT RSL;
Harald Weltef70df652018-01-29 22:00:23 +010034 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010035 var RslChannelNr g_chan_nr;
Harald Welte421e4d42018-02-12 20:04:50 +010036 /* second BTS / DChan during hand-over */
37 port RSL_DCHAN_PT RSL1;
38 port RSLEM_PROC_PT RSL1_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010039};
40
41type record RSLDC_ChanRqd {
42 OCT1 ra,
43 GsmFrameNumber fn
44};
45
46template RSLDC_ChanRqd ts_RSLDC_ChanRqd(OCT1 ra, GsmFrameNumber fn) := {
47 ra := ra,
48 fn := fn
49}
50
51type port RSL_DCHAN_PT message {
52 inout RSLDC_ChanRqd, RSL_Message;
53} with { extension "internal" };
54
Harald Welte1c02fd12018-02-19 19:20:47 +010055type port RSL_CCHAN_PT message {
Harald Weltebb6aed32018-02-21 12:19:18 +010056 inout ASP_RSL_Unitdata, ASP_IPA_Event;
Harald Welte1c02fd12018-02-19 19:20:47 +010057} with { extension "internal" };
58
59
Harald Weltef70df652018-01-29 22:00:23 +010060signature RSLEM_register(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte1909f462018-01-29 22:29:29 +010061signature RSLEM_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte70b52c92018-02-12 20:47:31 +010062signature RSLEM_suspend(boolean suspend);
Harald Weltef70df652018-01-29 22:00:23 +010063
64type port RSLEM_PROC_PT procedure {
Harald Welte70b52c92018-02-12 20:47:31 +010065 inout RSLEM_register, RSLEM_unregister, RSLEM_suspend;
Harald Weltef70df652018-01-29 22:00:23 +010066} with { extension "internal" };
67
Harald Welte714ded92017-12-08 14:00:22 +010068/***********************************************************************
69 * Client Component for a single dedicated channel
70 ***********************************************************************/
71
72private function f_rx_or_fail(template RSL_Message exp_rx) runs on RSL_DchanHdlr return RSL_Message
73{
74 var RSL_Message rx_rsl;
75 timer T := 10.0;
76
77 /* request a channel to be established */
78 T.start;
79 alt {
80 [] RSL.receive(exp_rx) -> value rx_rsl {
81 T.stop;
82 return rx_rsl;
83 }
84 [] RSL.receive {
85 setverdict(fail, "Unexpected RSL message on DCHAN");
86 self.stop;
87 }
88 [] T.timeout {
89 setverdict(fail, "Timeout waiting for RSL on DCHAN");
90 self.stop;
91 }
92 }
93 /* never reached */
94 return rx_rsl;
95}
96
97/* establish a dedicated channel using 'ra' */
98function f_chan_est(OCT1 ra, octetstring est_l3, template RslLinkId link_id, GsmFrameNumber fn := 23)
99runs on RSL_DchanHdlr {
100 var RSL_Message rx_rsl;
101 var GsmRrMessage rr;
102
103 /* request a channel to be established */
104 RSL.send(ts_RSLDC_ChanRqd(ra, fn));
105 /* expect immediate assignment */
106 rx_rsl := f_rx_or_fail(tr_RSL_IMM_ASSIGN);
107 rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
108 g_chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
109 RSL.send(ts_RSL_EST_IND(g_chan_nr, valueof(link_id), est_l3));
110}
111
112function f_deact_chan(RSL_Cause cause) runs on RSL_DchanHdlr
113{
114 var RSL_Message rx_rsl;
115
116 RSL.send(ts_RSL_CONN_FAIL_IND(g_chan_nr, cause));
117 rx_rsl := f_rx_or_fail(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL));
118 /* FIXME RSL.send(ts_RSL_RF_CHAN_REL_ACK()) */
119}
120
121
122
123/***********************************************************************
124 * Main Component
125 ***********************************************************************/
126
127private type record ConnectionData {
128 /* component reference to the client component */
129 RSL_DchanHdlr comp_ref,
130 /* RSL (dedicated) Channel number we're handling */
131 uint8_t trx_nr optional,
132 IpaStreamId stream_id optional,
133 RslChannelNr chan_nr optional,
134 /* Random Reference */
135 OCT1 ra optional,
136 GsmFrameNumber ra_fn optional
137};
138
139private function f_cid_by_comp_ref(RSL_DchanHdlr comp_ref)
140runs on RSL_Emulation_CT return integer {
141 var integer i;
142 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
143 if (ispresent(ConnectionTable[i].comp_ref) and
144 ConnectionTable[i].comp_ref == comp_ref) {
145 return i;
146 }
147 }
148 log("No Dchan handler for ", comp_ref);
149 return -1;
150}
151
152private function f_cid_by_chan_nr(uint8_t trx_nr, RslChannelNr chan_nr)
153runs on RSL_Emulation_CT return integer {
154 var integer i;
155 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
156 if (ispresent(ConnectionTable[i].chan_nr) and
157 ConnectionTable[i].chan_nr == chan_nr and ConnectionTable[i].trx_nr == trx_nr) {
158 return i;
159 }
160 }
161 log("No Dchan handler for ", trx_nr, chan_nr);
162 return -1;
163}
164
165private function f_cid_by_ra_fn(OCT1 ra, GsmFrameNumber fn)
166runs on RSL_Emulation_CT return integer {
167 var integer i;
168 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
169 if (ispresent(ConnectionTable[i].ra) and
170 ConnectionTable[i].ra == ra and ConnectionTable[i].ra_fn == fn) {
171 return i;
172 }
173 }
174 log("No Dchan handler for ", ra, fn);
175 return -1;
176}
177
178/* create an ew client with given RA and FN */
179private function f_cid_create(OCT1 ra, GsmFrameNumber fn, RSL_DchanHdlr comp_ref)
180runs on RSL_Emulation_CT return integer {
181 var integer i;
182 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
Harald Weltef70df652018-01-29 22:00:23 +0100183 if (not ispresent(ConnectionTable[i].ra) and
184 not ispresent(ConnectionTable[i].trx_nr)) {
Harald Welte714ded92017-12-08 14:00:22 +0100185 ConnectionTable[i].ra := ra;
186 ConnectionTable[i].ra_fn := fn;
187 ConnectionTable[i].comp_ref := comp_ref;
188 return i;
189 }
190 }
191 log("No free entry in conn table for ", ra, fn);
192 return -1;
193}
194
Harald Weltef70df652018-01-29 22:00:23 +0100195/* create an ew client with given RA and FN */
196private function f_cid_create_cnr(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
197runs on RSL_Emulation_CT return integer {
198 var integer i;
199 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
200 if (not ispresent(ConnectionTable[i].ra) and
201 not ispresent(ConnectionTable[i].trx_nr)) {
202 ConnectionTable[i].stream_id := f_streamId_by_trx(trx_nr);
203 ConnectionTable[i].trx_nr := trx_nr;
204 ConnectionTable[i].chan_nr := chan_nr;
205 ConnectionTable[i].comp_ref := comp_ref;
206 return i;
207 }
208 }
209 log("No free entry in conn table for ", trx_nr, chan_nr, comp_ref);
210 return -1;
211}
212
213
214/* create an ew client with given RA and FN */
215private function f_cid_delete_cnr(IpaStreamId stream_id, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
216runs on RSL_Emulation_CT return integer {
217 var integer i;
218 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
219 if (ConnectionTable[i].comp_ref == null) {
220 continue;
221 }
222 if (ConnectionTable[i].stream_id == stream_id and
223 ConnectionTable[i].chan_nr == chan_nr and
224 ConnectionTable[i].comp_ref == comp_ref) {
225 f_cid_clear(i);
226 }
227 }
228 log("Unable to find entry to delete for ", stream_id, chan_nr, comp_ref);
229 return -1;
230}
231
232
Harald Welte714ded92017-12-08 14:00:22 +0100233private function f_cid_clear(integer cid)
234runs on RSL_Emulation_CT {
235 ConnectionTable[cid].ra := omit;
236 ConnectionTable[cid].ra_fn := omit;
Harald Welte714ded92017-12-08 14:00:22 +0100237 ConnectionTable[cid].trx_nr := omit;
238 ConnectionTable[cid].stream_id := omit;
239 ConnectionTable[cid].chan_nr := omit;
Harald Weltef70df652018-01-29 22:00:23 +0100240 ConnectionTable[cid].comp_ref := null;
Harald Welte714ded92017-12-08 14:00:22 +0100241}
242
243type component RSL_Emulation_CT {
244 /* port facing down towards IPA emulation */
245 port IPA_RSL_PT IPA_PT;
246 /* port facing up towards dedicated channel handler */
247 port RSL_DCHAN_PT CLIENT_PT;
Harald Weltef70df652018-01-29 22:00:23 +0100248 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +0100249
Harald Welte1c02fd12018-02-19 19:20:47 +0100250 /* port for Common Channel / TRX Management */
251 port RSL_CCHAN_PT CCHAN_PT;
252
Harald Welte714ded92017-12-08 14:00:22 +0100253 /* state of all concurrent connections / dedicated channels */
254 var ConnectionData ConnectionTable[64];
255}
256
257
258/* template for an ASP_RSL_Unitdata as we receive it from the IPA_Emulateion component */
259private template ASP_RSL_Unitdata tr_RSL(template RSL_Message rsl, template IpaStreamId sid := ?) := {
260 streamId := sid,
261 rsl := rsl
262}
263
Harald Welte714ded92017-12-08 14:00:22 +0100264private function f_trx_by_streamId(IpaStreamId id) return integer {
265 return enum2int(id);
266}
267
Harald Weltef70df652018-01-29 22:00:23 +0100268private function f_streamId_by_trx(uint8_t trx_nr) return IpaStreamId {
269 select (trx_nr) {
270 case (0) { return IPAC_PROTO_RSL_TRX0; }
271 case (1) { return IPAC_PROTO_RSL_TRX1; }
272 case (2) { return IPAC_PROTO_RSL_TRX2; }
273 case (3) { return IPAC_PROTO_RSL_TRX3; }
274 }
275 self.stop;
276}
277
Harald Welte714ded92017-12-08 14:00:22 +0100278
Harald Welte1c02fd12018-02-19 19:20:47 +0100279function main(boolean bts_role := true) runs on RSL_Emulation_CT {
Harald Weltebb6aed32018-02-21 12:19:18 +0100280 var ASP_IPA_Event evt;
Harald Welte714ded92017-12-08 14:00:22 +0100281 var ASP_RSL_Unitdata rx_rsl;
282 var RSL_Message rx_rsl_msg;
283 var RSLDC_ChanRqd chan_rqd;
284 var RSL_DchanHdlr vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100285 var RslChannelNr chan_nr;
286 var uint8_t trx_nr;
Harald Welte714ded92017-12-08 14:00:22 +0100287 var integer cid;
288 var integer i;
Harald Welte70b52c92018-02-12 20:47:31 +0100289 /* special synchronization handling during hand-over */
290 var boolean dchan_suspended := false;
Harald Welte714ded92017-12-08 14:00:22 +0100291
Daniel Willmann17f970f2018-01-17 12:03:19 +0100292 f_conn_table_init();
293
Harald Welte714ded92017-12-08 14:00:22 +0100294 while (true) {
295 alt {
Harald Weltebb6aed32018-02-21 12:19:18 +0100296 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) {
297 }
298 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) -> value evt {
299 CCHAN_PT.send(evt);
Harald Welte624f9632017-12-16 19:26:04 +0100300 }
Harald Welte1c02fd12018-02-19 19:20:47 +0100301 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) {
Harald Welte7ae019e2017-12-09 00:54:15 +0100302 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_PAGING_LOAD_IND(23)));
Harald Welte714ded92017-12-08 14:00:22 +0100303 }
Harald Welte1c02fd12018-02-19 19:20:47 +0100304 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_IMM_ASSIGN)) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100305 var GsmRrMessage rr;
306 var OCT1 ra;
307 var GsmFrameNumber fn;
308 log("IMM ASS INFO ", rx_rsl.rsl.ies[1].body);
309 rr := dec_GsmRrMessage(rx_rsl.rsl.ies[1].body.full_imm_ass_info.payload);
310 if (ischosen(rr.payload.imm_ass)) {
311 ra := bit2oct(rr.payload.imm_ass.req_ref.ra);
312 fn := 23; //FIXME(rr.payload.imm_ass);
313 /* lookup client based on RA+time, deliver to client */
314 cid := f_cid_by_ra_fn(ra, fn);
315 if (cid == -1) {
316 setverdict(fail, "IMM ASS for unknown DChan");
Harald Weltef70df652018-01-29 22:00:23 +0100317 self.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100318 }
319 /* update client with trx_nr */
320 ConnectionTable[cid].trx_nr := f_trx_by_streamId(rx_rsl.streamId);
321 ConnectionTable[cid].stream_id := rx_rsl.streamId;
322 /* update client with chan_nr */
323 ConnectionTable[cid].chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
324 /* TODO: add timer to time-out ConnectionTable entries which
325 * never get followed-up to */
326 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
327 } else if (ischosen(rr.payload.imm_ass_rej)) {
328 for (i := 0; i < sizeof(rr.payload.imm_ass_rej.payload); i := i + 1) {
329 ra := bit2oct(rr.payload.imm_ass_rej.payload[i].req_ref.ra);
330 fn := 23; //FIXME();
331 /* lookup client based on RA+time, deliver to client */
332 cid := f_cid_by_ra_fn(ra, fn);
333 if (cid != -1) {
334 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
335 /* delete ClientTable entry, as it failed */
336 f_cid_clear(cid);
337 }
338 }
339 }
340 }
341
Harald Welte1c02fd12018-02-19 19:20:47 +0100342 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_PAGING_CMD(?, ?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100343 log("PAGING IDENTITY ", rx_rsl.rsl.ies[2].body.other);
344 /* broadcast to all clients? */
345 for (i := 0; i < sizeof(ConnectionTable); i := i + 1) {
346 if (ispresent(ConnectionTable[i].comp_ref)) {
347 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[i].comp_ref;
348 }
349 }
350 }
351
Harald Welte1c02fd12018-02-19 19:20:47 +0100352 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100353 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeT(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100354 log("Forwarding TRX Mgmt ", rx_rsl.rsl);
355 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100356 }
357
Harald Welte1c02fd12018-02-19 19:20:47 +0100358 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100359 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeC(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100360 log("Forwarding Common Channel Mgmt ", rx_rsl.rsl);
361 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100362 }
363
364 /* blindly acknowledge all channel activations */
Harald Welte1c02fd12018-02-19 19:20:47 +0100365 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) -> value rx_rsl {
Harald Weltef70df652018-01-29 22:00:23 +0100366 chan_nr := rx_rsl.rsl.ies[0].body.chan_nr;
Harald Welte7ae019e2017-12-09 00:54:15 +0100367 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl.streamId, ts_RSL_CHAN_ACT_ACK(chan_nr, 23)));
Harald Welte714ded92017-12-08 14:00:22 +0100368 }
369
Harald Welte70b52c92018-02-12 20:47:31 +0100370 [not dchan_suspended] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeDR(?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100371 /* dispatch to channel based on ChanId */
372 cid := f_cid_by_chan_nr(f_trx_by_streamId(rx_rsl.streamId),
373 rx_rsl.rsl.ies[0].body.chan_nr);
374 if (cid != -1) {
375 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
376 } else {
377 setverdict(fail, "RSL for unknown Dchan");
378 }
379 }
380
Harald Welte70b52c92018-02-12 20:47:31 +0100381 [not dchan_suspended] IPA_PT.receive {
Harald Welte714ded92017-12-08 14:00:22 +0100382 setverdict(fail, "Received unknown primitive from IPA");
383 self.stop;
384 }
385
Harald Welte1c02fd12018-02-19 19:20:47 +0100386 [bts_role] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
Harald Welte714ded92017-12-08 14:00:22 +0100387 /* Store the knowledge that this sender has requested a certain RQ+time */
388 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100389 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
Harald Welte714ded92017-12-08 14:00:22 +0100390 ts_RSL_CHAN_RQD(chan_rqd.ra, chan_rqd.fn)));
391 }
392
393 [] CLIENT_PT.receive(tr_RSL_MsgType(?)) -> value rx_rsl_msg sender vc_conn {
394 /* forward to BSC */
395 cid := f_cid_by_comp_ref(vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100396 IPA_PT.send(ts_ASP_RSL_UD(ConnectionTable[cid].stream_id, rx_rsl_msg));
Harald Welte714ded92017-12-08 14:00:22 +0100397 }
398
Harald Weltef70df652018-01-29 22:00:23 +0100399 /* explicit registration, e.g. in (non-immediate) assignment case */
400 [] RSL_PROC.getcall(RSLEM_register:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
401 f_cid_create_cnr(trx_nr, chan_nr, vc_conn);
402 RSL_PROC.reply(RSLEM_register:{trx_nr, chan_nr, vc_conn});
403 }
404
Harald Welte1909f462018-01-29 22:29:29 +0100405 [] RSL_PROC.getcall(RSLEM_unregister:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
406 cid := f_cid_by_chan_nr(trx_nr, chan_nr);
407 f_cid_clear(cid);
408 RSL_PROC.reply(RSLEM_unregister:{trx_nr, chan_nr, vc_conn});
409 }
410
Harald Welte70b52c92018-02-12 20:47:31 +0100411 [] RSL_PROC.getcall(RSLEM_suspend:{true}) {
412 log("Suspending DChan");
413 dchan_suspended := true;
414 RSL_PROC.reply(RSLEM_suspend:{true});
415 }
416
417 [] RSL_PROC.getcall(RSLEM_suspend:{false}) {
418 log("Resuming DChan");
419 dchan_suspended := false;
420 RSL_PROC.reply(RSLEM_suspend:{false});
421 }
Harald Welte1909f462018-01-29 22:29:29 +0100422
Harald Welte714ded92017-12-08 14:00:22 +0100423 }
424 }
425}
426
Daniel Willmann17f970f2018-01-17 12:03:19 +0100427private function f_conn_table_init()
428runs on RSL_Emulation_CT {
429 var integer i;
430
431 /* Initialize the ConnectionTable */
432 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
433 f_cid_clear(i);
434 }
435}
Harald Welte714ded92017-12-08 14:00:22 +0100436
Harald Weltef70df652018-01-29 22:00:23 +0100437/* client/conn_hdlr side function to use procedure port to register stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100438function f_rslem_register(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
439runs on RSL_DchanHdlr {
440 PT.call(RSLEM_register:{trx_nr, chan_nr, self}) {
441 [] PT.getreply(RSLEM_register:{?,?,?}) {};
Harald Weltef70df652018-01-29 22:00:23 +0100442 }
443}
444
Harald Welte1909f462018-01-29 22:29:29 +0100445/* client/conn_hdlr side function to use procedure port to unregister stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100446function f_rslem_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
447runs on RSL_DchanHdlr {
448 PT.call(RSLEM_unregister:{trx_nr, chan_nr, self}) {
449 [] PT.getreply(RSLEM_unregister:{?,?,?}) {};
Harald Welte1909f462018-01-29 22:29:29 +0100450 }
451}
452
Harald Welte70b52c92018-02-12 20:47:31 +0100453/* resume handling of RSL DChan messages from IPA until f_rslem_resume() is called */
454function f_rslem_suspend(RSLEM_PROC_PT PT)
455runs on RSL_DchanHdlr {
456 PT.call(RSLEM_suspend:{true}) {
457 [] PT.getreply(RSLEM_suspend:{true}) {};
458 }
459}
460
461/* resume handling of RSL DChan messages after f_rslem_suspend() is called */
462function f_rslem_resume(RSLEM_PROC_PT PT)
463runs on RSL_DchanHdlr {
464 PT.call(RSLEM_suspend:{false}) {
465 [] PT.getreply(RSLEM_suspend:{false}) {};
466 }
467}
468
469
Harald Welte1909f462018-01-29 22:29:29 +0100470
Harald Welte714ded92017-12-08 14:00:22 +0100471}