blob: cf02d00cd5f59b5d31093429039ca1d80e8e951f [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.
24 */
25
Pau Espin Pedrola07cfd92018-10-22 15:54:41 +020026import from Misc_Helpers all;
Harald Welte714ded92017-12-08 14:00:22 +010027import from General_Types all;
28import from Osmocom_Types all;
29import from GSM_Types all;
30import from GSM_RR_Types all;
31import from RSL_Types all;
32import from IPA_Types all;
33import from IPA_Emulation all;
34
35
36/* General "base class" component definition, of which specific implementations
37 * derive themselves by means of the "extends" feature */
38type component RSL_DchanHdlr {
39 /* port facing up towards dedicated channel handler */
40 port RSL_DCHAN_PT RSL;
Harald Weltef70df652018-01-29 22:00:23 +010041 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010042 var RslChannelNr g_chan_nr;
Harald Welte421e4d42018-02-12 20:04:50 +010043 /* second BTS / DChan during hand-over */
44 port RSL_DCHAN_PT RSL1;
45 port RSLEM_PROC_PT RSL1_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010046};
47
48type record RSLDC_ChanRqd {
49 OCT1 ra,
50 GsmFrameNumber fn
51};
52
53template RSLDC_ChanRqd ts_RSLDC_ChanRqd(OCT1 ra, GsmFrameNumber fn) := {
54 ra := ra,
55 fn := fn
56}
57
58type port RSL_DCHAN_PT message {
59 inout RSLDC_ChanRqd, RSL_Message;
60} with { extension "internal" };
61
Harald Welte1c02fd12018-02-19 19:20:47 +010062type port RSL_CCHAN_PT message {
Harald Weltebb6aed32018-02-21 12:19:18 +010063 inout ASP_RSL_Unitdata, ASP_IPA_Event;
Harald Welte1c02fd12018-02-19 19:20:47 +010064} with { extension "internal" };
65
66
Harald Weltef70df652018-01-29 22:00:23 +010067signature RSLEM_register(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte1909f462018-01-29 22:29:29 +010068signature RSLEM_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte70b52c92018-02-12 20:47:31 +010069signature RSLEM_suspend(boolean suspend);
Harald Weltead2647b2018-03-22 19:53:55 +010070signature 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 +010071
72type port RSLEM_PROC_PT procedure {
Harald Weltead2647b2018-03-22 19:53:55 +010073 inout RSLEM_register, RSLEM_unregister, RSLEM_suspend, RSLEM_get_last_act;
Harald Weltef70df652018-01-29 22:00:23 +010074} with { extension "internal" };
75
Harald Welte714ded92017-12-08 14:00:22 +010076/***********************************************************************
77 * Client Component for a single dedicated channel
78 ***********************************************************************/
79
80private function f_rx_or_fail(template RSL_Message exp_rx) runs on RSL_DchanHdlr return RSL_Message
81{
82 var RSL_Message rx_rsl;
83 timer T := 10.0;
84
85 /* request a channel to be established */
86 T.start;
87 alt {
88 [] RSL.receive(exp_rx) -> value rx_rsl {
89 T.stop;
90 return rx_rsl;
91 }
92 [] RSL.receive {
93 setverdict(fail, "Unexpected RSL message on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020094 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +010095 }
96 [] T.timeout {
97 setverdict(fail, "Timeout waiting for RSL on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020098 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +010099 }
100 }
101 /* never reached */
102 return rx_rsl;
103}
104
105/* establish a dedicated channel using 'ra' */
106function f_chan_est(OCT1 ra, octetstring est_l3, template RslLinkId link_id, GsmFrameNumber fn := 23)
107runs on RSL_DchanHdlr {
108 var RSL_Message rx_rsl;
109 var GsmRrMessage rr;
110
111 /* request a channel to be established */
112 RSL.send(ts_RSLDC_ChanRqd(ra, fn));
113 /* expect immediate assignment */
114 rx_rsl := f_rx_or_fail(tr_RSL_IMM_ASSIGN);
115 rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
116 g_chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
117 RSL.send(ts_RSL_EST_IND(g_chan_nr, valueof(link_id), est_l3));
118}
119
120function f_deact_chan(RSL_Cause cause) runs on RSL_DchanHdlr
121{
122 var RSL_Message rx_rsl;
123
124 RSL.send(ts_RSL_CONN_FAIL_IND(g_chan_nr, cause));
125 rx_rsl := f_rx_or_fail(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL));
126 /* FIXME RSL.send(ts_RSL_RF_CHAN_REL_ACK()) */
127}
128
129
130
131/***********************************************************************
132 * Main Component
133 ***********************************************************************/
134
135private type record ConnectionData {
136 /* component reference to the client component */
137 RSL_DchanHdlr comp_ref,
138 /* RSL (dedicated) Channel number we're handling */
139 uint8_t trx_nr optional,
140 IpaStreamId stream_id optional,
141 RslChannelNr chan_nr optional,
142 /* Random Reference */
143 OCT1 ra optional,
144 GsmFrameNumber ra_fn optional
145};
146
147private function f_cid_by_comp_ref(RSL_DchanHdlr comp_ref)
148runs on RSL_Emulation_CT return integer {
149 var integer i;
150 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
151 if (ispresent(ConnectionTable[i].comp_ref) and
152 ConnectionTable[i].comp_ref == comp_ref) {
153 return i;
154 }
155 }
156 log("No Dchan handler for ", comp_ref);
157 return -1;
158}
159
160private function f_cid_by_chan_nr(uint8_t trx_nr, RslChannelNr chan_nr)
161runs on RSL_Emulation_CT return integer {
162 var integer i;
163 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
164 if (ispresent(ConnectionTable[i].chan_nr) and
165 ConnectionTable[i].chan_nr == chan_nr and ConnectionTable[i].trx_nr == trx_nr) {
166 return i;
167 }
168 }
169 log("No Dchan handler for ", trx_nr, chan_nr);
170 return -1;
171}
172
173private function f_cid_by_ra_fn(OCT1 ra, GsmFrameNumber fn)
174runs on RSL_Emulation_CT return integer {
175 var integer i;
176 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
177 if (ispresent(ConnectionTable[i].ra) and
178 ConnectionTable[i].ra == ra and ConnectionTable[i].ra_fn == fn) {
179 return i;
180 }
181 }
182 log("No Dchan handler for ", ra, fn);
183 return -1;
184}
185
186/* create an ew client with given RA and FN */
187private function f_cid_create(OCT1 ra, GsmFrameNumber fn, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100188runs on RSL_Emulation_CT {
Harald Welte714ded92017-12-08 14:00:22 +0100189 var integer i;
190 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
Harald Weltef70df652018-01-29 22:00:23 +0100191 if (not ispresent(ConnectionTable[i].ra) and
192 not ispresent(ConnectionTable[i].trx_nr)) {
Harald Welte714ded92017-12-08 14:00:22 +0100193 ConnectionTable[i].ra := ra;
194 ConnectionTable[i].ra_fn := fn;
195 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100196 return;
Harald Welte714ded92017-12-08 14:00:22 +0100197 }
198 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200199 testcase.stop("No free entry in conn table for ", ra, fn);
Harald Welte714ded92017-12-08 14:00:22 +0100200}
201
Harald Weltef70df652018-01-29 22:00:23 +0100202/* create an ew client with given RA and FN */
203private function f_cid_create_cnr(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100204runs on RSL_Emulation_CT {
Harald Weltef70df652018-01-29 22:00:23 +0100205 var integer i;
206 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
207 if (not ispresent(ConnectionTable[i].ra) and
208 not ispresent(ConnectionTable[i].trx_nr)) {
209 ConnectionTable[i].stream_id := f_streamId_by_trx(trx_nr);
210 ConnectionTable[i].trx_nr := trx_nr;
211 ConnectionTable[i].chan_nr := chan_nr;
212 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100213 return;
Harald Weltef70df652018-01-29 22:00:23 +0100214 }
215 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200216 testcase.stop("No free entry in conn table for ", trx_nr, chan_nr, comp_ref);
Harald Weltef70df652018-01-29 22:00:23 +0100217}
218
219
220/* create an ew client with given RA and FN */
221private function f_cid_delete_cnr(IpaStreamId stream_id, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
222runs on RSL_Emulation_CT return integer {
223 var integer i;
224 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
225 if (ConnectionTable[i].comp_ref == null) {
226 continue;
227 }
228 if (ConnectionTable[i].stream_id == stream_id and
229 ConnectionTable[i].chan_nr == chan_nr and
230 ConnectionTable[i].comp_ref == comp_ref) {
231 f_cid_clear(i);
232 }
233 }
234 log("Unable to find entry to delete for ", stream_id, chan_nr, comp_ref);
235 return -1;
236}
237
238
Harald Welte714ded92017-12-08 14:00:22 +0100239private function f_cid_clear(integer cid)
240runs on RSL_Emulation_CT {
241 ConnectionTable[cid].ra := omit;
242 ConnectionTable[cid].ra_fn := omit;
Harald Welte714ded92017-12-08 14:00:22 +0100243 ConnectionTable[cid].trx_nr := omit;
244 ConnectionTable[cid].stream_id := omit;
245 ConnectionTable[cid].chan_nr := omit;
Harald Weltef70df652018-01-29 22:00:23 +0100246 ConnectionTable[cid].comp_ref := null;
Harald Welte714ded92017-12-08 14:00:22 +0100247}
248
Harald Weltead2647b2018-03-22 19:53:55 +0100249/* last activation for a given channel number */
250type record LastActData {
251 uint8_t trx_nr optional,
252 RslChannelNr chan_nr optional,
253 RSL_Message chan_act optional
254}
255
256private function f_store_last_act_data(uint8_t trx_nr, RslChannelNr chan_nr, RSL_Message chan_act)
257runs on RSL_Emulation_CT {
258 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
259 if (not ispresent(LastActTable[i].chan_nr) or
260 (LastActTable[i].chan_nr == chan_nr and LastActTable[i].trx_nr == trx_nr)) {
261 LastActTable[i].trx_nr := trx_nr;
262 LastActTable[i].chan_nr := chan_nr;
263 LastActTable[i].chan_act := chan_act;
264 return;
265 }
266 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200267 testcase.stop("No space left in LastActTable to store chan_act for ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100268}
269
270private function f_lookup_last_act(uint8_t trx_nr, RslChannelNr chan_nr)
271runs on RSL_Emulation_CT return RSL_Message {
272 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
273 if (ispresent(LastActTable[i].chan_nr) and LastActTable[i].chan_nr == chan_nr
274 and LastActTable[i].trx_nr == trx_nr) {
275 return LastActTable[i].chan_act;
276 }
277 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200278 testcase.stop("No LastActTable entry found for TRX ", trx_nr, " ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100279}
280
281private function f_last_act_table_init() runs on RSL_Emulation_CT {
282 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
283 LastActTable[i] := { omit, omit, omit };
284 }
285}
286
Harald Welte714ded92017-12-08 14:00:22 +0100287type component RSL_Emulation_CT {
288 /* port facing down towards IPA emulation */
289 port IPA_RSL_PT IPA_PT;
290 /* port facing up towards dedicated channel handler */
291 port RSL_DCHAN_PT CLIENT_PT;
Harald Weltef70df652018-01-29 22:00:23 +0100292 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +0100293
Harald Welte1c02fd12018-02-19 19:20:47 +0100294 /* port for Common Channel / TRX Management */
295 port RSL_CCHAN_PT CCHAN_PT;
296
Harald Welte714ded92017-12-08 14:00:22 +0100297 /* state of all concurrent connections / dedicated channels */
298 var ConnectionData ConnectionTable[64];
Harald Weltead2647b2018-03-22 19:53:55 +0100299
300 /* last RSL CHAN ACT for each chan_nr */
301 var LastActData LastActTable[64];
Harald Welte714ded92017-12-08 14:00:22 +0100302}
303
304
305/* template for an ASP_RSL_Unitdata as we receive it from the IPA_Emulateion component */
306private template ASP_RSL_Unitdata tr_RSL(template RSL_Message rsl, template IpaStreamId sid := ?) := {
307 streamId := sid,
308 rsl := rsl
309}
310
Harald Welte714ded92017-12-08 14:00:22 +0100311private function f_trx_by_streamId(IpaStreamId id) return integer {
312 return enum2int(id);
313}
314
Harald Weltef70df652018-01-29 22:00:23 +0100315private function f_streamId_by_trx(uint8_t trx_nr) return IpaStreamId {
316 select (trx_nr) {
317 case (0) { return IPAC_PROTO_RSL_TRX0; }
318 case (1) { return IPAC_PROTO_RSL_TRX1; }
319 case (2) { return IPAC_PROTO_RSL_TRX2; }
320 case (3) { return IPAC_PROTO_RSL_TRX3; }
321 }
Daniel Willmanna6ea2ef2018-07-24 09:55:52 +0200322 setverdict(fail, "Unknown stream ID ", trx_nr);
323 mtc.stop;
Harald Weltef70df652018-01-29 22:00:23 +0100324}
325
Harald Welte714ded92017-12-08 14:00:22 +0100326
Harald Welte1c02fd12018-02-19 19:20:47 +0100327function main(boolean bts_role := true) runs on RSL_Emulation_CT {
Harald Weltebb6aed32018-02-21 12:19:18 +0100328 var ASP_IPA_Event evt;
Harald Welte714ded92017-12-08 14:00:22 +0100329 var ASP_RSL_Unitdata rx_rsl;
330 var RSL_Message rx_rsl_msg;
331 var RSLDC_ChanRqd chan_rqd;
332 var RSL_DchanHdlr vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100333 var RslChannelNr chan_nr;
334 var uint8_t trx_nr;
Harald Welte714ded92017-12-08 14:00:22 +0100335 var integer cid;
336 var integer i;
Harald Welte70b52c92018-02-12 20:47:31 +0100337 /* special synchronization handling during hand-over */
338 var boolean dchan_suspended := false;
Harald Welte714ded92017-12-08 14:00:22 +0100339
Daniel Willmann17f970f2018-01-17 12:03:19 +0100340 f_conn_table_init();
Harald Weltead2647b2018-03-22 19:53:55 +0100341 f_last_act_table_init();
Daniel Willmann17f970f2018-01-17 12:03:19 +0100342
Harald Welte714ded92017-12-08 14:00:22 +0100343 while (true) {
344 alt {
Harald Weltebb6aed32018-02-21 12:19:18 +0100345 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) {
346 }
347 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) -> value evt {
348 CCHAN_PT.send(evt);
Harald Welte624f9632017-12-16 19:26:04 +0100349 }
Pau Espin Pedrola07cfd92018-10-22 15:54:41 +0200350 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_DOWN}) {
351 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
352
353 }
354 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_DOWN}) {
355 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
356 }
Harald Welte1c02fd12018-02-19 19:20:47 +0100357 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) {
Harald Welte7ae019e2017-12-09 00:54:15 +0100358 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_PAGING_LOAD_IND(23)));
Harald Welte714ded92017-12-08 14:00:22 +0100359 }
Harald Welted879e2f2018-05-27 20:22:13 +0200360 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { }
Harald Welte1c02fd12018-02-19 19:20:47 +0100361 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_IMM_ASSIGN)) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100362 var GsmRrMessage rr;
363 var OCT1 ra;
364 var GsmFrameNumber fn;
Harald Welte714ded92017-12-08 14:00:22 +0100365 rr := dec_GsmRrMessage(rx_rsl.rsl.ies[1].body.full_imm_ass_info.payload);
366 if (ischosen(rr.payload.imm_ass)) {
367 ra := bit2oct(rr.payload.imm_ass.req_ref.ra);
368 fn := 23; //FIXME(rr.payload.imm_ass);
369 /* lookup client based on RA+time, deliver to client */
370 cid := f_cid_by_ra_fn(ra, fn);
371 if (cid == -1) {
372 setverdict(fail, "IMM ASS for unknown DChan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200373 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100374 }
375 /* update client with trx_nr */
376 ConnectionTable[cid].trx_nr := f_trx_by_streamId(rx_rsl.streamId);
377 ConnectionTable[cid].stream_id := rx_rsl.streamId;
378 /* update client with chan_nr */
379 ConnectionTable[cid].chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
380 /* TODO: add timer to time-out ConnectionTable entries which
381 * never get followed-up to */
382 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
383 } else if (ischosen(rr.payload.imm_ass_rej)) {
384 for (i := 0; i < sizeof(rr.payload.imm_ass_rej.payload); i := i + 1) {
385 ra := bit2oct(rr.payload.imm_ass_rej.payload[i].req_ref.ra);
386 fn := 23; //FIXME();
387 /* lookup client based on RA+time, deliver to client */
388 cid := f_cid_by_ra_fn(ra, fn);
389 if (cid != -1) {
390 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
391 /* delete ClientTable entry, as it failed */
392 f_cid_clear(cid);
393 }
394 }
395 }
396 }
397
Harald Welte1c02fd12018-02-19 19:20:47 +0100398 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_PAGING_CMD(?, ?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100399 /* broadcast to all clients? */
400 for (i := 0; i < sizeof(ConnectionTable); i := i + 1) {
401 if (ispresent(ConnectionTable[i].comp_ref)) {
402 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[i].comp_ref;
403 }
404 }
405 }
406
Harald Welte1c02fd12018-02-19 19:20:47 +0100407 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100408 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeT(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100409 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100410 }
411
Harald Welte1c02fd12018-02-19 19:20:47 +0100412 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100413 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeC(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100414 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100415 }
416
417 /* blindly acknowledge all channel activations */
Harald Welte1c02fd12018-02-19 19:20:47 +0100418 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) -> value rx_rsl {
Harald Weltef70df652018-01-29 22:00:23 +0100419 chan_nr := rx_rsl.rsl.ies[0].body.chan_nr;
Harald Weltead2647b2018-03-22 19:53:55 +0100420 trx_nr := f_trx_by_streamId(rx_rsl.streamId);
421 f_store_last_act_data(trx_nr, chan_nr, rx_rsl.rsl);
Harald Welte7ae019e2017-12-09 00:54:15 +0100422 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 +0100423 }
424
Harald Welte70b52c92018-02-12 20:47:31 +0100425 [not dchan_suspended] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeDR(?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100426 /* dispatch to channel based on ChanId */
427 cid := f_cid_by_chan_nr(f_trx_by_streamId(rx_rsl.streamId),
428 rx_rsl.rsl.ies[0].body.chan_nr);
429 if (cid != -1) {
430 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
431 } else {
432 setverdict(fail, "RSL for unknown Dchan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200433 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100434 }
435 }
436
Harald Welte70b52c92018-02-12 20:47:31 +0100437 [not dchan_suspended] IPA_PT.receive {
Harald Welte714ded92017-12-08 14:00:22 +0100438 setverdict(fail, "Received unknown primitive from IPA");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200439 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100440 }
441
Harald Welte1c02fd12018-02-19 19:20:47 +0100442 [bts_role] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
Harald Welte714ded92017-12-08 14:00:22 +0100443 /* Store the knowledge that this sender has requested a certain RQ+time */
444 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100445 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
Harald Welte714ded92017-12-08 14:00:22 +0100446 ts_RSL_CHAN_RQD(chan_rqd.ra, chan_rqd.fn)));
447 }
448
449 [] CLIENT_PT.receive(tr_RSL_MsgType(?)) -> value rx_rsl_msg sender vc_conn {
450 /* forward to BSC */
451 cid := f_cid_by_comp_ref(vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100452 IPA_PT.send(ts_ASP_RSL_UD(ConnectionTable[cid].stream_id, rx_rsl_msg));
Harald Welte714ded92017-12-08 14:00:22 +0100453 }
454
Harald Welte34252c52018-02-24 04:51:50 +0100455 [] CCHAN_PT.receive(tr_RSL(?)) -> value rx_rsl {
456 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl.streamId, rx_rsl.rsl));
457 }
458
Harald Weltef70df652018-01-29 22:00:23 +0100459 /* explicit registration, e.g. in (non-immediate) assignment case */
460 [] RSL_PROC.getcall(RSLEM_register:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
461 f_cid_create_cnr(trx_nr, chan_nr, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200462 RSL_PROC.reply(RSLEM_register:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100463 }
464
Harald Welte1909f462018-01-29 22:29:29 +0100465 [] RSL_PROC.getcall(RSLEM_unregister:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
466 cid := f_cid_by_chan_nr(trx_nr, chan_nr);
467 f_cid_clear(cid);
Harald Weltee32ad992018-05-31 22:17:46 +0200468 RSL_PROC.reply(RSLEM_unregister:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Welte1909f462018-01-29 22:29:29 +0100469 }
470
Harald Weltee32ad992018-05-31 22:17:46 +0200471 [] RSL_PROC.getcall(RSLEM_suspend:{true}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100472 log("Suspending DChan");
473 dchan_suspended := true;
Harald Weltee32ad992018-05-31 22:17:46 +0200474 RSL_PROC.reply(RSLEM_suspend:{true}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100475 }
476
Harald Weltee32ad992018-05-31 22:17:46 +0200477 [] RSL_PROC.getcall(RSLEM_suspend:{false}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100478 log("Resuming DChan");
479 dchan_suspended := false;
Harald Weltee32ad992018-05-31 22:17:46 +0200480 RSL_PROC.reply(RSLEM_suspend:{false}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100481 }
Harald Welte1909f462018-01-29 22:29:29 +0100482
Harald Weltee32ad992018-05-31 22:17:46 +0200483 [] RSL_PROC.getcall(RSLEM_get_last_act:{?,?,?}) -> param(trx_nr, chan_nr) sender vc_conn {
Harald Weltead2647b2018-03-22 19:53:55 +0100484 var RSL_Message last_chan_act := f_lookup_last_act(trx_nr, chan_nr);
Harald Weltee32ad992018-05-31 22:17:46 +0200485 RSL_PROC.reply(RSLEM_get_last_act:{trx_nr, chan_nr, last_chan_act}) to vc_conn;
Harald Weltead2647b2018-03-22 19:53:55 +0100486 }
Harald Welte714ded92017-12-08 14:00:22 +0100487 }
488 }
489}
490
Daniel Willmann17f970f2018-01-17 12:03:19 +0100491private function f_conn_table_init()
492runs on RSL_Emulation_CT {
493 var integer i;
494
495 /* Initialize the ConnectionTable */
496 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
497 f_cid_clear(i);
498 }
499}
Harald Welte714ded92017-12-08 14:00:22 +0100500
Harald Weltef70df652018-01-29 22:00:23 +0100501/* client/conn_hdlr side function to use procedure port to register stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100502function f_rslem_register(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
503runs on RSL_DchanHdlr {
504 PT.call(RSLEM_register:{trx_nr, chan_nr, self}) {
505 [] PT.getreply(RSLEM_register:{?,?,?}) {};
Harald Weltef70df652018-01-29 22:00:23 +0100506 }
507}
508
Harald Welte1909f462018-01-29 22:29:29 +0100509/* client/conn_hdlr side function to use procedure port to unregister stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100510function f_rslem_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
511runs on RSL_DchanHdlr {
512 PT.call(RSLEM_unregister:{trx_nr, chan_nr, self}) {
513 [] PT.getreply(RSLEM_unregister:{?,?,?}) {};
Harald Welte1909f462018-01-29 22:29:29 +0100514 }
515}
516
Harald Welte70b52c92018-02-12 20:47:31 +0100517/* resume handling of RSL DChan messages from IPA until f_rslem_resume() is called */
518function f_rslem_suspend(RSLEM_PROC_PT PT)
519runs on RSL_DchanHdlr {
520 PT.call(RSLEM_suspend:{true}) {
521 [] PT.getreply(RSLEM_suspend:{true}) {};
522 }
523}
524
525/* resume handling of RSL DChan messages after f_rslem_suspend() is called */
526function f_rslem_resume(RSLEM_PROC_PT PT)
527runs on RSL_DchanHdlr {
528 PT.call(RSLEM_suspend:{false}) {
529 [] PT.getreply(RSLEM_suspend:{false}) {};
530 }
531}
532
Harald Weltead2647b2018-03-22 19:53:55 +0100533/* obtain the last RSL_CHAN_ACT message for the given chan_nr */
534function f_rslem_get_last_act(RSLEM_PROC_PT PT, uint8_t trx_nr, RslChannelNr chan_nr)
535runs on RSL_DchanHdlr return RSL_Message {
536 var RSL_Message chan_act;
537 PT.call(RSLEM_get_last_act:{trx_nr, chan_nr, -}) {
538 [] PT.getreply(RSLEM_get_last_act:{trx_nr, chan_nr, ?}) -> param(chan_act) {};
539 }
540 return chan_act;
541}
542
543
Harald Welte70b52c92018-02-12 20:47:31 +0100544
Harald Welte1909f462018-01-29 22:29:29 +0100545
Harald Welte714ded92017-12-08 14:00:22 +0100546}