blob: 66cc4dc12f4473327ba2771674c5c77e3bd8607e [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 *
Harald Weltead2647b2018-03-22 19:53:55 +010013 * in case we're emulating the BTS-side of RSL: We have no clue as to which particular logical
14 * channel the BSC may decide to activate at which point, so we have to blindly acknowledge all
15 * channel activations. Still, a test case might be interested in the exact assignment message to
16 * determine the type of activation, encryption, codec flags etc. at some later point, when it's
17 * clear for which transaction this activation happened. We keep this in the LastChanAct table.
18 *
19 * (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
Harald Welte35bb7162018-01-03 21:07:52 +010020 * All rights reserved.
21 *
22 * Released under the terms of GNU General Public License, Version 2 or
23 * (at your option) any later version.
Harald Welte34b5a952019-05-27 11:54:11 +020024 *
25 * SPDX-License-Identifier: GPL-2.0-or-later
Harald Welte35bb7162018-01-03 21:07:52 +010026 */
27
Pau Espin Pedrola07cfd92018-10-22 15:54:41 +020028import from Misc_Helpers all;
Harald Welte714ded92017-12-08 14:00:22 +010029import from General_Types all;
30import from Osmocom_Types all;
31import from GSM_Types all;
32import from GSM_RR_Types all;
33import from RSL_Types all;
34import from IPA_Types all;
35import from IPA_Emulation all;
36
37
Vadim Yanitskiy82af0b52020-06-09 20:21:43 +070038modulepar {
39 /* Work around switch for ttcn3-bts-test-latest, enables patching of IPA
40 * stream ID in the "BSC" mode. See I5927f59a49724170a63e87be604973f7c9d5d8be. */
41 boolean mp_rslem_patch_ipa_cid := false;
42};
43
Harald Welte714ded92017-12-08 14:00:22 +010044/* General "base class" component definition, of which specific implementations
45 * derive themselves by means of the "extends" feature */
46type component RSL_DchanHdlr {
47 /* port facing up towards dedicated channel handler */
48 port RSL_DCHAN_PT RSL;
Harald Weltef70df652018-01-29 22:00:23 +010049 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010050 var RslChannelNr g_chan_nr;
Harald Welte421e4d42018-02-12 20:04:50 +010051 /* second BTS / DChan during hand-over */
52 port RSL_DCHAN_PT RSL1;
53 port RSLEM_PROC_PT RSL1_PROC;
Neels Hofmeyr91401012019-07-11 00:42:35 +020054 port RSL_DCHAN_PT RSL2;
55 port RSLEM_PROC_PT RSL2_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010056};
57
58type record RSLDC_ChanRqd {
59 OCT1 ra,
Pau Espin Pedrol6451b042018-10-24 20:36:16 +020060 GsmFrameNumber fn optional
Harald Welte714ded92017-12-08 14:00:22 +010061};
62
Pau Espin Pedrol6451b042018-10-24 20:36:16 +020063template (value) RSLDC_ChanRqd ts_RSLDC_ChanRqd(OCT1 ra, GsmFrameNumber fn) := {
Harald Welte714ded92017-12-08 14:00:22 +010064 ra := ra,
65 fn := fn
66}
67
Pau Espin Pedrol6451b042018-10-24 20:36:16 +020068template (value) RSLDC_ChanRqd ts_RSLDC_ChanRqd_anyFN(OCT1 ra) := {
69 ra := ra,
70 fn := omit
71}
72
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +070073type enumerated RSLEm_EventType {
74 RSLEM_EV_TRX_UP,
75 RSLEM_EV_TRX_DOWN
76};
77
78type record RSLEm_Event {
79 RSLEm_EventType ev_type,
80 IpaStreamId sid
81};
82
83template (value) RSLEm_Event ts_RSLEm_EV(RSLEm_EventType ev_type,
84 IpaStreamId sid) := {
85 ev_type := ev_type,
86 sid := sid
87};
88template RSLEm_Event tr_RSLEm_EV(template RSLEm_EventType ev_type,
89 template IpaStreamId sid := ?) := {
90 ev_type := ev_type,
91 sid := sid
92};
93
Harald Welte714ded92017-12-08 14:00:22 +010094type port RSL_DCHAN_PT message {
95 inout RSLDC_ChanRqd, RSL_Message;
96} with { extension "internal" };
97
Harald Welte1c02fd12018-02-19 19:20:47 +010098type port RSL_CCHAN_PT message {
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +070099 inout ASP_RSL_Unitdata, RSLEm_Event;
Harald Welte1c02fd12018-02-19 19:20:47 +0100100} with { extension "internal" };
101
102
Harald Weltef70df652018-01-29 22:00:23 +0100103signature RSLEM_register(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte1909f462018-01-29 22:29:29 +0100104signature RSLEM_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte70b52c92018-02-12 20:47:31 +0100105signature RSLEM_suspend(boolean suspend);
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700106signature RSLEM_wait_queue(boolean enable);
Harald Weltead2647b2018-03-22 19:53:55 +0100107signature RSLEM_get_last_act(in uint8_t trx_nr, in RslChannelNr chan_nr, out RSL_Message chan_act);
Harald Weltef70df652018-01-29 22:00:23 +0100108
109type port RSLEM_PROC_PT procedure {
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700110 inout RSLEM_register, RSLEM_unregister,
111 RSLEM_suspend, RSLEM_wait_queue,
112 RSLEM_get_last_act;
Harald Weltef70df652018-01-29 22:00:23 +0100113} with { extension "internal" };
114
Harald Welte714ded92017-12-08 14:00:22 +0100115/***********************************************************************
116 * Client Component for a single dedicated channel
117 ***********************************************************************/
118
119private function f_rx_or_fail(template RSL_Message exp_rx) runs on RSL_DchanHdlr return RSL_Message
120{
121 var RSL_Message rx_rsl;
122 timer T := 10.0;
123
124 /* request a channel to be established */
125 T.start;
126 alt {
127 [] RSL.receive(exp_rx) -> value rx_rsl {
128 T.stop;
129 return rx_rsl;
130 }
131 [] RSL.receive {
132 setverdict(fail, "Unexpected RSL message on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200133 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100134 }
135 [] T.timeout {
136 setverdict(fail, "Timeout waiting for RSL on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200137 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100138 }
139 }
140 /* never reached */
141 return rx_rsl;
142}
143
144/* establish a dedicated channel using 'ra' */
145function f_chan_est(OCT1 ra, octetstring est_l3, template RslLinkId link_id, GsmFrameNumber fn := 23)
146runs on RSL_DchanHdlr {
147 var RSL_Message rx_rsl;
148 var GsmRrMessage rr;
149
150 /* request a channel to be established */
151 RSL.send(ts_RSLDC_ChanRqd(ra, fn));
152 /* expect immediate assignment */
153 rx_rsl := f_rx_or_fail(tr_RSL_IMM_ASSIGN);
154 rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
155 g_chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
156 RSL.send(ts_RSL_EST_IND(g_chan_nr, valueof(link_id), est_l3));
157}
158
159function f_deact_chan(RSL_Cause cause) runs on RSL_DchanHdlr
160{
161 var RSL_Message rx_rsl;
162
163 RSL.send(ts_RSL_CONN_FAIL_IND(g_chan_nr, cause));
164 rx_rsl := f_rx_or_fail(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL));
165 /* FIXME RSL.send(ts_RSL_RF_CHAN_REL_ACK()) */
166}
167
168
169
170/***********************************************************************
171 * Main Component
172 ***********************************************************************/
173
174private type record ConnectionData {
175 /* component reference to the client component */
176 RSL_DchanHdlr comp_ref,
177 /* RSL (dedicated) Channel number we're handling */
178 uint8_t trx_nr optional,
179 IpaStreamId stream_id optional,
180 RslChannelNr chan_nr optional,
181 /* Random Reference */
182 OCT1 ra optional,
183 GsmFrameNumber ra_fn optional
184};
185
186private function f_cid_by_comp_ref(RSL_DchanHdlr comp_ref)
187runs on RSL_Emulation_CT return integer {
188 var integer i;
189 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
Pau Espin Pedrol70965092020-06-23 14:29:56 +0200190 if (ispresent(ConnectionTable[i].comp_ref) and
Harald Welte714ded92017-12-08 14:00:22 +0100191 ConnectionTable[i].comp_ref == comp_ref) {
192 return i;
193 }
194 }
Vadim Yanitskiyf79d9362020-06-03 04:06:18 +0700195 log("No Dchan handler for comp_ref=", comp_ref);
Harald Welte714ded92017-12-08 14:00:22 +0100196 return -1;
197}
198
199private function f_cid_by_chan_nr(uint8_t trx_nr, RslChannelNr chan_nr)
200runs on RSL_Emulation_CT return integer {
201 var integer i;
202 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
Pau Espin Pedrol70965092020-06-23 14:29:56 +0200203 if (ispresent(ConnectionTable[i].chan_nr) and
Harald Welte714ded92017-12-08 14:00:22 +0100204 ConnectionTable[i].chan_nr == chan_nr and ConnectionTable[i].trx_nr == trx_nr) {
205 return i;
206 }
207 }
Vadim Yanitskiyf79d9362020-06-03 04:06:18 +0700208 log("No Dchan handler for trx_nr=", trx_nr, " and chan_nr=", chan_nr);
Harald Welte714ded92017-12-08 14:00:22 +0100209 return -1;
210}
211
212private function f_cid_by_ra_fn(OCT1 ra, GsmFrameNumber fn)
213runs on RSL_Emulation_CT return integer {
214 var integer i;
215 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
216 if (ispresent(ConnectionTable[i].ra) and
217 ConnectionTable[i].ra == ra and ConnectionTable[i].ra_fn == fn) {
218 return i;
219 }
220 }
Vadim Yanitskiyf79d9362020-06-03 04:06:18 +0700221 log("No Dchan handler for ra=", ra, " and fn=", fn);
Harald Welte714ded92017-12-08 14:00:22 +0100222 return -1;
223}
224
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200225/* Matches by only RA if FN is ommited in one of the connections allocated */
226private function f_cid_by_ra_fn2(OCT1 ra, RSL_IE_FrameNumber fn)
227runs on RSL_Emulation_CT return integer {
228 var integer i;
229 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
230 if (ispresent(ConnectionTable[i].ra) and
231 ConnectionTable[i].ra == ra) {
232 if (not ispresent(ConnectionTable[i].ra_fn) or
233 fn == valueof(ts_RSL_IE_FrameNumber(ConnectionTable[i].ra_fn))) {
234 return i;
235 }
236 }
237 }
Vadim Yanitskiyf79d9362020-06-03 04:06:18 +0700238 log("No Dchan handler for ra=", ra, " and fn=", fn);
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200239 return -1;
240}
241
Harald Welte714ded92017-12-08 14:00:22 +0100242/* create an ew client with given RA and FN */
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200243private function f_cid_create(OCT1 ra, template (omit) GsmFrameNumber fn, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100244runs on RSL_Emulation_CT {
Harald Welte714ded92017-12-08 14:00:22 +0100245 var integer i;
246 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
Harald Weltef70df652018-01-29 22:00:23 +0100247 if (not ispresent(ConnectionTable[i].ra) and
248 not ispresent(ConnectionTable[i].trx_nr)) {
Harald Welte714ded92017-12-08 14:00:22 +0100249 ConnectionTable[i].ra := ra;
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200250 if (ispresent(fn)) {
251 ConnectionTable[i].ra_fn := valueof(fn);
252 } else {
253 ConnectionTable[i].ra_fn := omit;
254 }
Harald Welte714ded92017-12-08 14:00:22 +0100255 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100256 return;
Harald Welte714ded92017-12-08 14:00:22 +0100257 }
258 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200259 testcase.stop("No free entry in conn table for ", ra, fn);
Harald Welte714ded92017-12-08 14:00:22 +0100260}
261
Vadim Yanitskiyefc94132020-05-24 04:26:45 +0700262/* create a new client with given RA and FN */
Harald Weltef70df652018-01-29 22:00:23 +0100263private function f_cid_create_cnr(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100264runs on RSL_Emulation_CT {
Harald Weltef70df652018-01-29 22:00:23 +0100265 var integer i;
266 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
267 if (not ispresent(ConnectionTable[i].ra) and
268 not ispresent(ConnectionTable[i].trx_nr)) {
269 ConnectionTable[i].stream_id := f_streamId_by_trx(trx_nr);
270 ConnectionTable[i].trx_nr := trx_nr;
271 ConnectionTable[i].chan_nr := chan_nr;
272 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100273 return;
Harald Weltef70df652018-01-29 22:00:23 +0100274 }
275 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200276 testcase.stop("No free entry in conn table for ", trx_nr, chan_nr, comp_ref);
Harald Weltef70df652018-01-29 22:00:23 +0100277}
278
279
Vadim Yanitskiyefc94132020-05-24 04:26:45 +0700280/* delete client with given RA and FN */
Harald Weltef70df652018-01-29 22:00:23 +0100281private function f_cid_delete_cnr(IpaStreamId stream_id, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
282runs on RSL_Emulation_CT return integer {
283 var integer i;
284 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
285 if (ConnectionTable[i].comp_ref == null) {
286 continue;
287 }
288 if (ConnectionTable[i].stream_id == stream_id and
289 ConnectionTable[i].chan_nr == chan_nr and
290 ConnectionTable[i].comp_ref == comp_ref) {
291 f_cid_clear(i);
292 }
293 }
294 log("Unable to find entry to delete for ", stream_id, chan_nr, comp_ref);
295 return -1;
296}
297
298
Harald Welte714ded92017-12-08 14:00:22 +0100299private function f_cid_clear(integer cid)
300runs on RSL_Emulation_CT {
301 ConnectionTable[cid].ra := omit;
302 ConnectionTable[cid].ra_fn := omit;
Harald Welte714ded92017-12-08 14:00:22 +0100303 ConnectionTable[cid].trx_nr := omit;
304 ConnectionTable[cid].stream_id := omit;
305 ConnectionTable[cid].chan_nr := omit;
Harald Weltef70df652018-01-29 22:00:23 +0100306 ConnectionTable[cid].comp_ref := null;
Harald Welte714ded92017-12-08 14:00:22 +0100307}
308
Harald Weltead2647b2018-03-22 19:53:55 +0100309/* last activation for a given channel number */
310type record LastActData {
311 uint8_t trx_nr optional,
312 RslChannelNr chan_nr optional,
313 RSL_Message chan_act optional
314}
315
316private function f_store_last_act_data(uint8_t trx_nr, RslChannelNr chan_nr, RSL_Message chan_act)
317runs on RSL_Emulation_CT {
318 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
319 if (not ispresent(LastActTable[i].chan_nr) or
320 (LastActTable[i].chan_nr == chan_nr and LastActTable[i].trx_nr == trx_nr)) {
321 LastActTable[i].trx_nr := trx_nr;
322 LastActTable[i].chan_nr := chan_nr;
323 LastActTable[i].chan_act := chan_act;
324 return;
325 }
326 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200327 testcase.stop("No space left in LastActTable to store chan_act for ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100328}
329
330private function f_lookup_last_act(uint8_t trx_nr, RslChannelNr chan_nr)
331runs on RSL_Emulation_CT return RSL_Message {
332 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
333 if (ispresent(LastActTable[i].chan_nr) and LastActTable[i].chan_nr == chan_nr
334 and LastActTable[i].trx_nr == trx_nr) {
335 return LastActTable[i].chan_act;
336 }
337 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200338 testcase.stop("No LastActTable entry found for TRX ", trx_nr, " ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100339}
340
341private function f_last_act_table_init() runs on RSL_Emulation_CT {
342 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
343 LastActTable[i] := { omit, omit, omit };
344 }
345}
346
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700347private function f_trx_conn_map_init()
348runs on RSL_Emulation_CT {
349 for (var integer i := 0; i < sizeof(TrxConnMap); i := i + 1) {
350 TrxConnMap[i] := -1;
351 }
352}
353
354private function f_trx_conn_map_register(integer conn_id, in IpaCcmIdResp id_resp)
355runs on RSL_Emulation_CT return IpaStreamId {
356 var template charstring unit_id_fmt := pattern "(\d+)/(\d+)/(\d+)";
357 var charstring unit_id;
358 var integer trx_nr;
359 var integer idx;
360
361 /* Check if we have room for a new connection */
362 if (TrxConnNum >= sizeof(TrxConnMap)) {
363 testcase.stop("We cannot handle more than ", sizeof(TrxConnMap), " transceivers");
364 }
365
366 /* Find IPAC_IDTAG_UNITID in the IPA IDENTITY RESPONSE */
367 idx := f_ipa_id_resp_find_ie(id_resp, IPAC_IDTAG_UNITID);
368 if (idx < 0) {
369 testcase.stop("IPA IDENTITY RESPONSE contains no unit-id");
370 }
371
372 /* Make sure that IPA unit-id is valid */
373 unit_id := oct2char(id_resp[idx].data);
374 if (not match(unit_id, unit_id_fmt)) {
375 testcase.stop("IPA unit-id has unknown/unexpected format");
376 }
377
378 /* Parse transceiver number (site/bts/trx).
379 * TODO: implement and use declaratice types. */
380 unit_id := regexp(unit_id, unit_id_fmt, 2);
381 trx_nr := str2int(unit_id);
382
383 if (trx_nr >= sizeof(TrxConnMap)) {
384 testcase.stop("Transceiver #", trx_nr, " does not fit");
385 } else if (TrxConnMap[trx_nr] != -1) {
386 testcase.stop("Transceiver #", trx_nr, " is already connected?!?");
387 }
388
389 /* Finally, store the connection ID */
390 log("Mapped TRX#", trx_nr, " to TCP/IP conn_id=", conn_id);
391 TrxConnMap[trx_nr] := conn_id;
392 TrxConnNum := TrxConnNum + 1;
393
394 return f_streamId_by_trx(trx_nr);
395}
396
397private function f_trx_conn_map_resolve(IpaStreamId id)
398runs on RSL_Emulation_CT return integer {
399 var integer trx_nr := f_trx_by_streamId(id);
400
401 if (TrxConnMap[trx_nr] == -1) {
402 testcase.stop("Transceiver #", trx_nr, " is not connected");
403 }
404
405 return TrxConnMap[trx_nr];
406}
407
Vadim Yanitskiy82af0b52020-06-09 20:21:43 +0700408/* Work around for a bug in osmo-bts when all transceivers use IPAC_PROTO_RSL_TRX0 */
409private function f_trx_conn_map_patch_ud(inout ASP_RSL_Unitdata ud)
410runs on RSL_Emulation_CT {
411 for (var integer i := 0; i < sizeof(TrxConnMap); i := i + 1) {
412 if (ud.conn_id == TrxConnMap[i]) {
413 ud.streamId := f_streamId_by_trx(i);
414 return; /* We're done */
415 }
416 }
417
418 testcase.stop("Failed to patch IPA stream ID in ASP RSL UD: ", ud);
419}
420
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700421private type record of ASP_RSL_Unitdata ASP_RSL_UDList;
422
Harald Welte714ded92017-12-08 14:00:22 +0100423type component RSL_Emulation_CT {
424 /* port facing down towards IPA emulation */
425 port IPA_RSL_PT IPA_PT;
426 /* port facing up towards dedicated channel handler */
427 port RSL_DCHAN_PT CLIENT_PT;
Harald Weltef70df652018-01-29 22:00:23 +0100428 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +0100429
Harald Welte1c02fd12018-02-19 19:20:47 +0100430 /* port for Common Channel / TRX Management */
431 port RSL_CCHAN_PT CCHAN_PT;
432
Harald Welte714ded92017-12-08 14:00:22 +0100433 /* state of all concurrent connections / dedicated channels */
434 var ConnectionData ConnectionTable[64];
Harald Weltead2647b2018-03-22 19:53:55 +0100435
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700436 /* RSL messages for which no handler is currently registered */
437 var ASP_RSL_UDList WaitingQueue := { };
438
Harald Weltead2647b2018-03-22 19:53:55 +0100439 /* last RSL CHAN ACT for each chan_nr */
440 var LastActData LastActTable[64];
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700441
442 /* IPA stream ID -> TCP/IP connection ID mapping for transceivers */
443 var integer TrxConnNum := 0; /* number of connected transceivers */
444 var integer TrxConnMap[4]; /* up to 4 transceivers for now */
Harald Welte714ded92017-12-08 14:00:22 +0100445}
446
447
Harald Welte714ded92017-12-08 14:00:22 +0100448private function f_trx_by_streamId(IpaStreamId id) return integer {
449 return enum2int(id);
450}
451
Harald Weltef70df652018-01-29 22:00:23 +0100452private function f_streamId_by_trx(uint8_t trx_nr) return IpaStreamId {
453 select (trx_nr) {
454 case (0) { return IPAC_PROTO_RSL_TRX0; }
455 case (1) { return IPAC_PROTO_RSL_TRX1; }
456 case (2) { return IPAC_PROTO_RSL_TRX2; }
457 case (3) { return IPAC_PROTO_RSL_TRX3; }
458 }
Daniel Willmanna6ea2ef2018-07-24 09:55:52 +0200459 setverdict(fail, "Unknown stream ID ", trx_nr);
460 mtc.stop;
Harald Weltef70df652018-01-29 22:00:23 +0100461}
462
Harald Welte714ded92017-12-08 14:00:22 +0100463
Harald Welte1c02fd12018-02-19 19:20:47 +0100464function main(boolean bts_role := true) runs on RSL_Emulation_CT {
Harald Weltebb6aed32018-02-21 12:19:18 +0100465 var ASP_IPA_Event evt;
Harald Welte714ded92017-12-08 14:00:22 +0100466 var ASP_RSL_Unitdata rx_rsl;
467 var RSL_Message rx_rsl_msg;
468 var RSLDC_ChanRqd chan_rqd;
469 var RSL_DchanHdlr vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100470 var RslChannelNr chan_nr;
471 var uint8_t trx_nr;
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700472 var integer conn_id;
Harald Welte714ded92017-12-08 14:00:22 +0100473 var integer cid;
474 var integer i;
Harald Welte70b52c92018-02-12 20:47:31 +0100475 /* special synchronization handling during hand-over */
476 var boolean dchan_suspended := false;
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700477 /* Whether to keep RSL messages, for which no handler is found in ConnectionTable,
478 * in a queue. These messages will remain in the queue until the appropriate
479 * connection handler is registered. */
480 var boolean wait_queue_enabled := false;
Harald Welte714ded92017-12-08 14:00:22 +0100481
Daniel Willmann17f970f2018-01-17 12:03:19 +0100482 f_conn_table_init();
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700483 f_trx_conn_map_init();
Harald Weltead2647b2018-03-22 19:53:55 +0100484 f_last_act_table_init();
Daniel Willmann17f970f2018-01-17 12:03:19 +0100485
Harald Welte714ded92017-12-08 14:00:22 +0100486 while (true) {
487 alt {
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +0700488 [bts_role] IPA_PT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) {
Harald Weltebb6aed32018-02-21 12:19:18 +0100489 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +0700490 [not bts_role] IPA_PT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) -> value evt {
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700491 log("A new IPA/RSL connection has been established (conn_id=",
492 evt.conn_id, "), waiting for IDENTITY RESPONSE...");
493 }
494 [not bts_role] IPA_PT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_RESP)) -> value evt {
495 log("Got IDENTITY RESPONSE (conn_id=", evt.conn_id, "): ", evt.id_resp);
496 /* Update [ IPA stream ID -> TCP/IP connection ID ] mapping */
497 var IpaStreamId sid := f_trx_conn_map_register(evt.conn_id, evt.id_resp);
498 /* Notify the upper layers about a new connection */
499 CCHAN_PT.send(ts_RSLEm_EV(RSLEM_EV_TRX_UP, sid));
Harald Welte624f9632017-12-16 19:26:04 +0100500 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +0700501 [bts_role] IPA_PT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN)) {
Pau Espin Pedrola07cfd92018-10-22 15:54:41 +0200502 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
503
504 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +0700505 [not bts_role] IPA_PT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN)) {
Pau Espin Pedrola07cfd92018-10-22 15:54:41 +0200506 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
507 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +0700508 [bts_role] IPA_PT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) {
Vadim Yanitskiy9b4e3562020-05-25 21:40:52 +0700509 IPA_PT.send(ts_ASP_RSL_UD(ts_RSL_PAGING_LOAD_IND(23)));
Harald Welte714ded92017-12-08 14:00:22 +0100510 }
Vadim Yanitskiya2afacc2020-05-18 21:16:19 +0700511 [not bts_role] IPA_PT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_ID_ACK)) { }
Vadim Yanitskiya60e5cf2020-05-26 01:46:31 +0700512 [bts_role] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_IMM_ASSIGN, sid := ?)) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100513 var GsmRrMessage rr;
514 var OCT1 ra;
515 var GsmFrameNumber fn;
Harald Welte714ded92017-12-08 14:00:22 +0100516 rr := dec_GsmRrMessage(rx_rsl.rsl.ies[1].body.full_imm_ass_info.payload);
517 if (ischosen(rr.payload.imm_ass)) {
518 ra := bit2oct(rr.payload.imm_ass.req_ref.ra);
519 fn := 23; //FIXME(rr.payload.imm_ass);
520 /* lookup client based on RA+time, deliver to client */
521 cid := f_cid_by_ra_fn(ra, fn);
522 if (cid == -1) {
523 setverdict(fail, "IMM ASS for unknown DChan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200524 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100525 }
526 /* update client with trx_nr */
527 ConnectionTable[cid].trx_nr := f_trx_by_streamId(rx_rsl.streamId);
528 ConnectionTable[cid].stream_id := rx_rsl.streamId;
529 /* update client with chan_nr */
530 ConnectionTable[cid].chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
531 /* TODO: add timer to time-out ConnectionTable entries which
532 * never get followed-up to */
533 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
534 } else if (ischosen(rr.payload.imm_ass_rej)) {
535 for (i := 0; i < sizeof(rr.payload.imm_ass_rej.payload); i := i + 1) {
536 ra := bit2oct(rr.payload.imm_ass_rej.payload[i].req_ref.ra);
537 fn := 23; //FIXME();
538 /* lookup client based on RA+time, deliver to client */
539 cid := f_cid_by_ra_fn(ra, fn);
540 if (cid != -1) {
541 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
542 /* delete ClientTable entry, as it failed */
543 f_cid_clear(cid);
544 }
545 }
546 }
547 }
Vadim Yanitskiya60e5cf2020-05-26 01:46:31 +0700548 [not bts_role] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(?), sid := ?)) -> value rx_rsl {
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200549 var RSL_IE_RequestRef req_ref;
550 req_ref := rx_rsl.rsl.ies[1].body.req_ref;
551 cid := f_cid_by_ra_fn2(req_ref.ra, req_ref.frame_nr);
552 if (cid != -1) {
553 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
554 f_cid_clear(cid);
555 } else {
556 CCHAN_PT.send(rx_rsl);
557 }
558 }
Harald Welte714ded92017-12-08 14:00:22 +0100559
Vadim Yanitskiya60e5cf2020-05-26 01:46:31 +0700560 [bts_role] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_CMD(?, ?), sid := ?)) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100561 /* broadcast to all clients? */
562 for (i := 0; i < sizeof(ConnectionTable); i := i + 1) {
Neels Hofmeyrd7eabd62020-06-08 22:30:54 +0200563 if (ispresent(ConnectionTable[i].comp_ref) and ConnectionTable[i].comp_ref != null) {
Harald Welte714ded92017-12-08 14:00:22 +0100564 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[i].comp_ref;
565 }
566 }
567 }
568
Harald Welte1c02fd12018-02-19 19:20:47 +0100569 /* Forward common channel management to the special port for it */
Vadim Yanitskiya60e5cf2020-05-26 01:46:31 +0700570 [] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeT(?), sid := ?)) -> value rx_rsl {
Vadim Yanitskiy82af0b52020-06-09 20:21:43 +0700571 if (not bts_role and mp_rslem_patch_ipa_cid) {
572 f_trx_conn_map_patch_ud(rx_rsl);
573 }
Harald Welte1c02fd12018-02-19 19:20:47 +0100574 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100575 }
576
Harald Welte1c02fd12018-02-19 19:20:47 +0100577 /* Forward common channel management to the special port for it */
Vadim Yanitskiya60e5cf2020-05-26 01:46:31 +0700578 [] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeC(?), sid := ?)) -> value rx_rsl {
Vadim Yanitskiy82af0b52020-06-09 20:21:43 +0700579 if (not bts_role and mp_rslem_patch_ipa_cid) {
580 f_trx_conn_map_patch_ud(rx_rsl);
581 }
Harald Welte1c02fd12018-02-19 19:20:47 +0100582 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100583 }
584
585 /* blindly acknowledge all channel activations */
Vadim Yanitskiya60e5cf2020-05-26 01:46:31 +0700586 [bts_role] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV), sid := ?)) -> value rx_rsl {
Harald Weltef70df652018-01-29 22:00:23 +0100587 chan_nr := rx_rsl.rsl.ies[0].body.chan_nr;
Harald Weltead2647b2018-03-22 19:53:55 +0100588 trx_nr := f_trx_by_streamId(rx_rsl.streamId);
589 f_store_last_act_data(trx_nr, chan_nr, rx_rsl.rsl);
Vadim Yanitskiy9b4e3562020-05-25 21:40:52 +0700590 IPA_PT.send(ts_ASP_RSL_UD(ts_RSL_CHAN_ACT_ACK(chan_nr, 23), rx_rsl.streamId));
Harald Welte714ded92017-12-08 14:00:22 +0100591 }
592
Vadim Yanitskiya60e5cf2020-05-26 01:46:31 +0700593 [not dchan_suspended] IPA_PT.receive(tr_ASP_RSL_UD(tr_RSL_MsgTypeDR(?), sid := ?)) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100594 /* dispatch to channel based on ChanId */
595 cid := f_cid_by_chan_nr(f_trx_by_streamId(rx_rsl.streamId),
596 rx_rsl.rsl.ies[0].body.chan_nr);
597 if (cid != -1) {
598 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700599 } else if (wait_queue_enabled) {
600 log("Storing an RSL message in the waiting queue");
601 WaitingQueue := WaitingQueue & { rx_rsl };
Harald Welte714ded92017-12-08 14:00:22 +0100602 } else {
603 setverdict(fail, "RSL for unknown Dchan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200604 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100605 }
606 }
607
Harald Welte70b52c92018-02-12 20:47:31 +0100608 [not dchan_suspended] IPA_PT.receive {
Harald Welte714ded92017-12-08 14:00:22 +0100609 setverdict(fail, "Received unknown primitive from IPA");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200610 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100611 }
612
Harald Welte1c02fd12018-02-19 19:20:47 +0100613 [bts_role] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
Harald Welte714ded92017-12-08 14:00:22 +0100614 /* Store the knowledge that this sender has requested a certain RQ+time */
615 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
Vadim Yanitskiy9b4e3562020-05-25 21:40:52 +0700616 IPA_PT.send(ts_ASP_RSL_UD(ts_RSL_CHAN_RQD(chan_rqd.ra, chan_rqd.fn)));
Harald Welte714ded92017-12-08 14:00:22 +0100617 }
618
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200619 [not bts_role] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
620 /* Store the knowledge that this sender has requested a certain RQ+time */
621 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
622 }
623
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700624 /* RSL message from a component that runs on RSL_DchanHdlr */
625 [bts_role] CLIENT_PT.receive(tr_RSL_MsgType(?)) -> value rx_rsl_msg sender vc_conn {
Harald Welte714ded92017-12-08 14:00:22 +0100626 cid := f_cid_by_comp_ref(vc_conn);
Vadim Yanitskiy9b4e3562020-05-25 21:40:52 +0700627 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl_msg, ConnectionTable[cid].stream_id));
Harald Welte714ded92017-12-08 14:00:22 +0100628 }
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700629 [not bts_role] CLIENT_PT.receive(tr_RSL_MsgType(?)) -> value rx_rsl_msg sender vc_conn {
630 cid := f_cid_by_comp_ref(vc_conn);
631 conn_id := f_trx_conn_map_resolve(ConnectionTable[cid].stream_id);
632 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl_msg, ConnectionTable[cid].stream_id, conn_id));
633 }
Harald Welte714ded92017-12-08 14:00:22 +0100634
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700635 /* RSL message from MTC */
636 [bts_role] CCHAN_PT.receive(tr_ASP_RSL_UD(?, sid := ?)) -> value rx_rsl {
Vadim Yanitskiy9b4e3562020-05-25 21:40:52 +0700637 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl.rsl, rx_rsl.streamId));
Harald Welte34252c52018-02-24 04:51:50 +0100638 }
Vadim Yanitskiy6de2fcb2020-05-25 19:40:45 +0700639 [not bts_role] CCHAN_PT.receive(tr_ASP_RSL_UD(?, sid := ?)) -> value rx_rsl {
640 conn_id := f_trx_conn_map_resolve(rx_rsl.streamId);
641 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl.rsl, rx_rsl.streamId, conn_id));
642 }
Harald Welte34252c52018-02-24 04:51:50 +0100643
Harald Weltef70df652018-01-29 22:00:23 +0100644 /* explicit registration, e.g. in (non-immediate) assignment case */
645 [] RSL_PROC.getcall(RSLEM_register:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
646 f_cid_create_cnr(trx_nr, chan_nr, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200647 RSL_PROC.reply(RSLEM_register:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100648 }
649
Harald Welte1909f462018-01-29 22:29:29 +0100650 [] RSL_PROC.getcall(RSLEM_unregister:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
651 cid := f_cid_by_chan_nr(trx_nr, chan_nr);
652 f_cid_clear(cid);
Harald Weltee32ad992018-05-31 22:17:46 +0200653 RSL_PROC.reply(RSLEM_unregister:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Welte1909f462018-01-29 22:29:29 +0100654 }
655
Harald Weltee32ad992018-05-31 22:17:46 +0200656 [] RSL_PROC.getcall(RSLEM_suspend:{true}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100657 log("Suspending DChan");
658 dchan_suspended := true;
Harald Weltee32ad992018-05-31 22:17:46 +0200659 RSL_PROC.reply(RSLEM_suspend:{true}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100660 }
661
Harald Weltee32ad992018-05-31 22:17:46 +0200662 [] RSL_PROC.getcall(RSLEM_suspend:{false}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100663 log("Resuming DChan");
664 dchan_suspended := false;
Harald Weltee32ad992018-05-31 22:17:46 +0200665 RSL_PROC.reply(RSLEM_suspend:{false}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100666 }
Harald Welte1909f462018-01-29 22:29:29 +0100667
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700668 [not wait_queue_enabled] RSL_PROC.getcall(RSLEM_wait_queue:{true}) -> sender vc_conn {
669 wait_queue_enabled := true;
670 log("Enabled queueing of DChan messages");
671 RSL_PROC.reply(RSLEM_wait_queue:{wait_queue_enabled}) to vc_conn;
672 }
673
674 [wait_queue_enabled] RSL_PROC.getcall(RSLEM_wait_queue:{false}) -> sender vc_conn {
675 /* Dispatch stalled messages (if any) */
676 f_WaitingQueue_dispatch();
677
678 wait_queue_enabled := false;
679 log("Disabled queueing of DChan messages");
680 RSL_PROC.reply(RSLEM_wait_queue:{wait_queue_enabled}) to vc_conn;
681 }
682
683 [] RSL_PROC.getcall(RSLEM_wait_queue:{?}) -> sender vc_conn {
684 log("Queueing of DChan messages is already enabled/disabled");
685 RSL_PROC.reply(RSLEM_wait_queue:{wait_queue_enabled}) to vc_conn;
686 }
687
Harald Weltee32ad992018-05-31 22:17:46 +0200688 [] RSL_PROC.getcall(RSLEM_get_last_act:{?,?,?}) -> param(trx_nr, chan_nr) sender vc_conn {
Harald Weltead2647b2018-03-22 19:53:55 +0100689 var RSL_Message last_chan_act := f_lookup_last_act(trx_nr, chan_nr);
Harald Weltee32ad992018-05-31 22:17:46 +0200690 RSL_PROC.reply(RSLEM_get_last_act:{trx_nr, chan_nr, last_chan_act}) to vc_conn;
Harald Weltead2647b2018-03-22 19:53:55 +0100691 }
Harald Welte714ded92017-12-08 14:00:22 +0100692 }
693 }
694}
695
Daniel Willmann17f970f2018-01-17 12:03:19 +0100696private function f_conn_table_init()
697runs on RSL_Emulation_CT {
698 var integer i;
699
700 /* Initialize the ConnectionTable */
701 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
702 f_cid_clear(i);
703 }
704}
Harald Welte714ded92017-12-08 14:00:22 +0100705
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700706private function f_WaitingQueue_dispatch()
707runs on RSL_Emulation_CT {
708 var integer cid;
709
710 for (var integer i := 0; i < lengthof(WaitingQueue); i := i + 1) {
711 cid := f_cid_by_chan_nr(f_trx_by_streamId(WaitingQueue[i].streamId),
712 WaitingQueue[i].rsl.ies[0].body.chan_nr);
713 if (cid == -1) {
714 setverdict(fail, "No Dchan handler found for: ", WaitingQueue[i]);
715 mtc.stop;
716 break;
717 }
718
719 /* Dispatch a stalled message to the appropriate handler */
720 CLIENT_PT.send(WaitingQueue[i].rsl) to ConnectionTable[cid].comp_ref;
721 }
722
723 /* All messages dispatched, clear the queue */
724 WaitingQueue := { };
725}
726
Harald Weltef70df652018-01-29 22:00:23 +0100727/* client/conn_hdlr side function to use procedure port to register stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100728function f_rslem_register(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
729runs on RSL_DchanHdlr {
730 PT.call(RSLEM_register:{trx_nr, chan_nr, self}) {
731 [] PT.getreply(RSLEM_register:{?,?,?}) {};
Harald Weltef70df652018-01-29 22:00:23 +0100732 }
733}
734
Harald Welte1909f462018-01-29 22:29:29 +0100735/* client/conn_hdlr side function to use procedure port to unregister stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100736function f_rslem_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
737runs on RSL_DchanHdlr {
738 PT.call(RSLEM_unregister:{trx_nr, chan_nr, self}) {
739 [] PT.getreply(RSLEM_unregister:{?,?,?}) {};
Harald Welte1909f462018-01-29 22:29:29 +0100740 }
741}
742
Vadim Yanitskiya38c2652020-06-21 19:47:00 +0700743/* suspend handling of RSL DChan messages from IPA until f_rslem_resume() is called */
Harald Welte70b52c92018-02-12 20:47:31 +0100744function f_rslem_suspend(RSLEM_PROC_PT PT)
745runs on RSL_DchanHdlr {
746 PT.call(RSLEM_suspend:{true}) {
747 [] PT.getreply(RSLEM_suspend:{true}) {};
748 }
749}
750
751/* resume handling of RSL DChan messages after f_rslem_suspend() is called */
752function f_rslem_resume(RSLEM_PROC_PT PT)
753runs on RSL_DchanHdlr {
754 PT.call(RSLEM_suspend:{false}) {
755 [] PT.getreply(RSLEM_suspend:{false}) {};
756 }
757}
758
Vadim Yanitskiye9c06352020-06-20 01:30:58 +0700759/* Enable queueing of RSL DChan messages from IPA until f_rslem_dchan_queue_disable() is called. */
760function f_rslem_dchan_queue_enable(RSLEM_PROC_PT PT := RSL_PROC)
761runs on RSL_DchanHdlr {
762 PT.call(RSLEM_wait_queue:{true}) {
763 [] PT.getreply(RSLEM_wait_queue:{true}) {};
764 }
765}
766
767/* Disable queueing of RSL DChan messages after f_rslem_dchan_queue_enable() is called.
768 * Dispatch all stalled messages to the registered handlers. Make sure that no
769 * messages for which there is no handler are left in the queue (mtc.stop if so). */
770function f_rslem_dchan_queue_dispatch(RSLEM_PROC_PT PT := RSL_PROC)
771runs on RSL_DchanHdlr {
772 PT.call(RSLEM_wait_queue:{false}) {
773 [] PT.getreply(RSLEM_wait_queue:{false}) {};
774 }
775}
776
Harald Weltead2647b2018-03-22 19:53:55 +0100777/* obtain the last RSL_CHAN_ACT message for the given chan_nr */
778function f_rslem_get_last_act(RSLEM_PROC_PT PT, uint8_t trx_nr, RslChannelNr chan_nr)
779runs on RSL_DchanHdlr return RSL_Message {
780 var RSL_Message chan_act;
781 PT.call(RSLEM_get_last_act:{trx_nr, chan_nr, -}) {
782 [] PT.getreply(RSLEM_get_last_act:{trx_nr, chan_nr, ?}) -> param(chan_act) {};
783 }
784 return chan_act;
785}
786
787
Harald Welte70b52c92018-02-12 20:47:31 +0100788
Harald Welte1909f462018-01-29 22:29:29 +0100789
Harald Welte714ded92017-12-08 14:00:22 +0100790}