blob: c56c27833c7375d65e43f71ae0d3fc948e117804 [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
Harald Welte714ded92017-12-08 14:00:22 +010026import from General_Types all;
27import from Osmocom_Types all;
28import from GSM_Types all;
29import from GSM_RR_Types all;
30import from RSL_Types all;
31import from IPA_Types all;
32import from IPA_Emulation all;
33
34
35/* General "base class" component definition, of which specific implementations
36 * derive themselves by means of the "extends" feature */
37type component RSL_DchanHdlr {
38 /* port facing up towards dedicated channel handler */
39 port RSL_DCHAN_PT RSL;
Harald Weltef70df652018-01-29 22:00:23 +010040 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010041 var RslChannelNr g_chan_nr;
Harald Welte421e4d42018-02-12 20:04:50 +010042 /* second BTS / DChan during hand-over */
43 port RSL_DCHAN_PT RSL1;
44 port RSLEM_PROC_PT RSL1_PROC;
Harald Welte714ded92017-12-08 14:00:22 +010045};
46
47type record RSLDC_ChanRqd {
48 OCT1 ra,
49 GsmFrameNumber fn
50};
51
52template RSLDC_ChanRqd ts_RSLDC_ChanRqd(OCT1 ra, GsmFrameNumber fn) := {
53 ra := ra,
54 fn := fn
55}
56
57type port RSL_DCHAN_PT message {
58 inout RSLDC_ChanRqd, RSL_Message;
59} with { extension "internal" };
60
Harald Welte1c02fd12018-02-19 19:20:47 +010061type port RSL_CCHAN_PT message {
Harald Weltebb6aed32018-02-21 12:19:18 +010062 inout ASP_RSL_Unitdata, ASP_IPA_Event;
Harald Welte1c02fd12018-02-19 19:20:47 +010063} with { extension "internal" };
64
65
Harald Weltef70df652018-01-29 22:00:23 +010066signature RSLEM_register(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte1909f462018-01-29 22:29:29 +010067signature RSLEM_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte70b52c92018-02-12 20:47:31 +010068signature RSLEM_suspend(boolean suspend);
Harald Weltead2647b2018-03-22 19:53:55 +010069signature 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 +010070
71type port RSLEM_PROC_PT procedure {
Harald Weltead2647b2018-03-22 19:53:55 +010072 inout RSLEM_register, RSLEM_unregister, RSLEM_suspend, RSLEM_get_last_act;
Harald Weltef70df652018-01-29 22:00:23 +010073} with { extension "internal" };
74
Harald Welte714ded92017-12-08 14:00:22 +010075/***********************************************************************
76 * Client Component for a single dedicated channel
77 ***********************************************************************/
78
79private function f_rx_or_fail(template RSL_Message exp_rx) runs on RSL_DchanHdlr return RSL_Message
80{
81 var RSL_Message rx_rsl;
82 timer T := 10.0;
83
84 /* request a channel to be established */
85 T.start;
86 alt {
87 [] RSL.receive(exp_rx) -> value rx_rsl {
88 T.stop;
89 return rx_rsl;
90 }
91 [] RSL.receive {
92 setverdict(fail, "Unexpected RSL message on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020093 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +010094 }
95 [] T.timeout {
96 setverdict(fail, "Timeout waiting for RSL on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020097 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +010098 }
99 }
100 /* never reached */
101 return rx_rsl;
102}
103
104/* establish a dedicated channel using 'ra' */
105function f_chan_est(OCT1 ra, octetstring est_l3, template RslLinkId link_id, GsmFrameNumber fn := 23)
106runs on RSL_DchanHdlr {
107 var RSL_Message rx_rsl;
108 var GsmRrMessage rr;
109
110 /* request a channel to be established */
111 RSL.send(ts_RSLDC_ChanRqd(ra, fn));
112 /* expect immediate assignment */
113 rx_rsl := f_rx_or_fail(tr_RSL_IMM_ASSIGN);
114 rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
115 g_chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
116 RSL.send(ts_RSL_EST_IND(g_chan_nr, valueof(link_id), est_l3));
117}
118
119function f_deact_chan(RSL_Cause cause) runs on RSL_DchanHdlr
120{
121 var RSL_Message rx_rsl;
122
123 RSL.send(ts_RSL_CONN_FAIL_IND(g_chan_nr, cause));
124 rx_rsl := f_rx_or_fail(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL));
125 /* FIXME RSL.send(ts_RSL_RF_CHAN_REL_ACK()) */
126}
127
128
129
130/***********************************************************************
131 * Main Component
132 ***********************************************************************/
133
134private type record ConnectionData {
135 /* component reference to the client component */
136 RSL_DchanHdlr comp_ref,
137 /* RSL (dedicated) Channel number we're handling */
138 uint8_t trx_nr optional,
139 IpaStreamId stream_id optional,
140 RslChannelNr chan_nr optional,
141 /* Random Reference */
142 OCT1 ra optional,
143 GsmFrameNumber ra_fn optional
144};
145
146private function f_cid_by_comp_ref(RSL_DchanHdlr comp_ref)
147runs on RSL_Emulation_CT return integer {
148 var integer i;
149 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
150 if (ispresent(ConnectionTable[i].comp_ref) and
151 ConnectionTable[i].comp_ref == comp_ref) {
152 return i;
153 }
154 }
155 log("No Dchan handler for ", comp_ref);
156 return -1;
157}
158
159private function f_cid_by_chan_nr(uint8_t trx_nr, RslChannelNr chan_nr)
160runs on RSL_Emulation_CT return integer {
161 var integer i;
162 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
163 if (ispresent(ConnectionTable[i].chan_nr) and
164 ConnectionTable[i].chan_nr == chan_nr and ConnectionTable[i].trx_nr == trx_nr) {
165 return i;
166 }
167 }
168 log("No Dchan handler for ", trx_nr, chan_nr);
169 return -1;
170}
171
172private function f_cid_by_ra_fn(OCT1 ra, GsmFrameNumber fn)
173runs on RSL_Emulation_CT return integer {
174 var integer i;
175 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
176 if (ispresent(ConnectionTable[i].ra) and
177 ConnectionTable[i].ra == ra and ConnectionTable[i].ra_fn == fn) {
178 return i;
179 }
180 }
181 log("No Dchan handler for ", ra, fn);
182 return -1;
183}
184
185/* create an ew client with given RA and FN */
186private function f_cid_create(OCT1 ra, GsmFrameNumber fn, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100187runs on RSL_Emulation_CT {
Harald Welte714ded92017-12-08 14:00:22 +0100188 var integer i;
189 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
Harald Weltef70df652018-01-29 22:00:23 +0100190 if (not ispresent(ConnectionTable[i].ra) and
191 not ispresent(ConnectionTable[i].trx_nr)) {
Harald Welte714ded92017-12-08 14:00:22 +0100192 ConnectionTable[i].ra := ra;
193 ConnectionTable[i].ra_fn := fn;
194 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100195 return;
Harald Welte714ded92017-12-08 14:00:22 +0100196 }
197 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200198 testcase.stop("No free entry in conn table for ", ra, fn);
Harald Welte714ded92017-12-08 14:00:22 +0100199}
200
Harald Weltef70df652018-01-29 22:00:23 +0100201/* create an ew client with given RA and FN */
202private function f_cid_create_cnr(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100203runs on RSL_Emulation_CT {
Harald Weltef70df652018-01-29 22:00:23 +0100204 var integer i;
205 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
206 if (not ispresent(ConnectionTable[i].ra) and
207 not ispresent(ConnectionTable[i].trx_nr)) {
208 ConnectionTable[i].stream_id := f_streamId_by_trx(trx_nr);
209 ConnectionTable[i].trx_nr := trx_nr;
210 ConnectionTable[i].chan_nr := chan_nr;
211 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100212 return;
Harald Weltef70df652018-01-29 22:00:23 +0100213 }
214 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200215 testcase.stop("No free entry in conn table for ", trx_nr, chan_nr, comp_ref);
Harald Weltef70df652018-01-29 22:00:23 +0100216}
217
218
219/* create an ew client with given RA and FN */
220private function f_cid_delete_cnr(IpaStreamId stream_id, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
221runs on RSL_Emulation_CT return integer {
222 var integer i;
223 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
224 if (ConnectionTable[i].comp_ref == null) {
225 continue;
226 }
227 if (ConnectionTable[i].stream_id == stream_id and
228 ConnectionTable[i].chan_nr == chan_nr and
229 ConnectionTable[i].comp_ref == comp_ref) {
230 f_cid_clear(i);
231 }
232 }
233 log("Unable to find entry to delete for ", stream_id, chan_nr, comp_ref);
234 return -1;
235}
236
237
Harald Welte714ded92017-12-08 14:00:22 +0100238private function f_cid_clear(integer cid)
239runs on RSL_Emulation_CT {
240 ConnectionTable[cid].ra := omit;
241 ConnectionTable[cid].ra_fn := omit;
Harald Welte714ded92017-12-08 14:00:22 +0100242 ConnectionTable[cid].trx_nr := omit;
243 ConnectionTable[cid].stream_id := omit;
244 ConnectionTable[cid].chan_nr := omit;
Harald Weltef70df652018-01-29 22:00:23 +0100245 ConnectionTable[cid].comp_ref := null;
Harald Welte714ded92017-12-08 14:00:22 +0100246}
247
Harald Weltead2647b2018-03-22 19:53:55 +0100248/* last activation for a given channel number */
249type record LastActData {
250 uint8_t trx_nr optional,
251 RslChannelNr chan_nr optional,
252 RSL_Message chan_act optional
253}
254
255private function f_store_last_act_data(uint8_t trx_nr, RslChannelNr chan_nr, RSL_Message chan_act)
256runs on RSL_Emulation_CT {
257 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
258 if (not ispresent(LastActTable[i].chan_nr) or
259 (LastActTable[i].chan_nr == chan_nr and LastActTable[i].trx_nr == trx_nr)) {
260 LastActTable[i].trx_nr := trx_nr;
261 LastActTable[i].chan_nr := chan_nr;
262 LastActTable[i].chan_act := chan_act;
263 return;
264 }
265 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200266 testcase.stop("No space left in LastActTable to store chan_act for ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100267}
268
269private function f_lookup_last_act(uint8_t trx_nr, RslChannelNr chan_nr)
270runs on RSL_Emulation_CT return RSL_Message {
271 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
272 if (ispresent(LastActTable[i].chan_nr) and LastActTable[i].chan_nr == chan_nr
273 and LastActTable[i].trx_nr == trx_nr) {
274 return LastActTable[i].chan_act;
275 }
276 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200277 testcase.stop("No LastActTable entry found for TRX ", trx_nr, " ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100278}
279
280private function f_last_act_table_init() runs on RSL_Emulation_CT {
281 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
282 LastActTable[i] := { omit, omit, omit };
283 }
284}
285
Harald Welte714ded92017-12-08 14:00:22 +0100286type component RSL_Emulation_CT {
287 /* port facing down towards IPA emulation */
288 port IPA_RSL_PT IPA_PT;
289 /* port facing up towards dedicated channel handler */
290 port RSL_DCHAN_PT CLIENT_PT;
Harald Weltef70df652018-01-29 22:00:23 +0100291 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +0100292
Harald Welte1c02fd12018-02-19 19:20:47 +0100293 /* port for Common Channel / TRX Management */
294 port RSL_CCHAN_PT CCHAN_PT;
295
Harald Welte714ded92017-12-08 14:00:22 +0100296 /* state of all concurrent connections / dedicated channels */
297 var ConnectionData ConnectionTable[64];
Harald Weltead2647b2018-03-22 19:53:55 +0100298
299 /* last RSL CHAN ACT for each chan_nr */
300 var LastActData LastActTable[64];
Harald Welte714ded92017-12-08 14:00:22 +0100301}
302
303
304/* template for an ASP_RSL_Unitdata as we receive it from the IPA_Emulateion component */
305private template ASP_RSL_Unitdata tr_RSL(template RSL_Message rsl, template IpaStreamId sid := ?) := {
306 streamId := sid,
307 rsl := rsl
308}
309
Harald Welte714ded92017-12-08 14:00:22 +0100310private function f_trx_by_streamId(IpaStreamId id) return integer {
311 return enum2int(id);
312}
313
Harald Weltef70df652018-01-29 22:00:23 +0100314private function f_streamId_by_trx(uint8_t trx_nr) return IpaStreamId {
315 select (trx_nr) {
316 case (0) { return IPAC_PROTO_RSL_TRX0; }
317 case (1) { return IPAC_PROTO_RSL_TRX1; }
318 case (2) { return IPAC_PROTO_RSL_TRX2; }
319 case (3) { return IPAC_PROTO_RSL_TRX3; }
320 }
Daniel Willmanna6ea2ef2018-07-24 09:55:52 +0200321 setverdict(fail, "Unknown stream ID ", trx_nr);
322 mtc.stop;
Harald Weltef70df652018-01-29 22:00:23 +0100323}
324
Harald Welte714ded92017-12-08 14:00:22 +0100325
Harald Welte1c02fd12018-02-19 19:20:47 +0100326function main(boolean bts_role := true) runs on RSL_Emulation_CT {
Harald Weltebb6aed32018-02-21 12:19:18 +0100327 var ASP_IPA_Event evt;
Harald Welte714ded92017-12-08 14:00:22 +0100328 var ASP_RSL_Unitdata rx_rsl;
329 var RSL_Message rx_rsl_msg;
330 var RSLDC_ChanRqd chan_rqd;
331 var RSL_DchanHdlr vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100332 var RslChannelNr chan_nr;
333 var uint8_t trx_nr;
Harald Welte714ded92017-12-08 14:00:22 +0100334 var integer cid;
335 var integer i;
Harald Welte70b52c92018-02-12 20:47:31 +0100336 /* special synchronization handling during hand-over */
337 var boolean dchan_suspended := false;
Harald Welte714ded92017-12-08 14:00:22 +0100338
Daniel Willmann17f970f2018-01-17 12:03:19 +0100339 f_conn_table_init();
Harald Weltead2647b2018-03-22 19:53:55 +0100340 f_last_act_table_init();
Daniel Willmann17f970f2018-01-17 12:03:19 +0100341
Harald Welte714ded92017-12-08 14:00:22 +0100342 while (true) {
343 alt {
Harald Weltebb6aed32018-02-21 12:19:18 +0100344 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) {
345 }
346 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) -> value evt {
347 CCHAN_PT.send(evt);
Harald Welte624f9632017-12-16 19:26:04 +0100348 }
Harald Welte1c02fd12018-02-19 19:20:47 +0100349 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) {
Harald Welte7ae019e2017-12-09 00:54:15 +0100350 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_PAGING_LOAD_IND(23)));
Harald Welte714ded92017-12-08 14:00:22 +0100351 }
Harald Welted879e2f2018-05-27 20:22:13 +0200352 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { }
Harald Welte1c02fd12018-02-19 19:20:47 +0100353 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_IMM_ASSIGN)) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100354 var GsmRrMessage rr;
355 var OCT1 ra;
356 var GsmFrameNumber fn;
Harald Welte714ded92017-12-08 14:00:22 +0100357 rr := dec_GsmRrMessage(rx_rsl.rsl.ies[1].body.full_imm_ass_info.payload);
358 if (ischosen(rr.payload.imm_ass)) {
359 ra := bit2oct(rr.payload.imm_ass.req_ref.ra);
360 fn := 23; //FIXME(rr.payload.imm_ass);
361 /* lookup client based on RA+time, deliver to client */
362 cid := f_cid_by_ra_fn(ra, fn);
363 if (cid == -1) {
364 setverdict(fail, "IMM ASS for unknown DChan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200365 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100366 }
367 /* update client with trx_nr */
368 ConnectionTable[cid].trx_nr := f_trx_by_streamId(rx_rsl.streamId);
369 ConnectionTable[cid].stream_id := rx_rsl.streamId;
370 /* update client with chan_nr */
371 ConnectionTable[cid].chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
372 /* TODO: add timer to time-out ConnectionTable entries which
373 * never get followed-up to */
374 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
375 } else if (ischosen(rr.payload.imm_ass_rej)) {
376 for (i := 0; i < sizeof(rr.payload.imm_ass_rej.payload); i := i + 1) {
377 ra := bit2oct(rr.payload.imm_ass_rej.payload[i].req_ref.ra);
378 fn := 23; //FIXME();
379 /* lookup client based on RA+time, deliver to client */
380 cid := f_cid_by_ra_fn(ra, fn);
381 if (cid != -1) {
382 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
383 /* delete ClientTable entry, as it failed */
384 f_cid_clear(cid);
385 }
386 }
387 }
388 }
389
Harald Welte1c02fd12018-02-19 19:20:47 +0100390 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_PAGING_CMD(?, ?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100391 /* broadcast to all clients? */
392 for (i := 0; i < sizeof(ConnectionTable); i := i + 1) {
393 if (ispresent(ConnectionTable[i].comp_ref)) {
394 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[i].comp_ref;
395 }
396 }
397 }
398
Harald Welte1c02fd12018-02-19 19:20:47 +0100399 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100400 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeT(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100401 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100402 }
403
Harald Welte1c02fd12018-02-19 19:20:47 +0100404 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100405 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeC(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100406 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100407 }
408
409 /* blindly acknowledge all channel activations */
Harald Welte1c02fd12018-02-19 19:20:47 +0100410 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) -> value rx_rsl {
Harald Weltef70df652018-01-29 22:00:23 +0100411 chan_nr := rx_rsl.rsl.ies[0].body.chan_nr;
Harald Weltead2647b2018-03-22 19:53:55 +0100412 trx_nr := f_trx_by_streamId(rx_rsl.streamId);
413 f_store_last_act_data(trx_nr, chan_nr, rx_rsl.rsl);
Harald Welte7ae019e2017-12-09 00:54:15 +0100414 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 +0100415 }
416
Harald Welte70b52c92018-02-12 20:47:31 +0100417 [not dchan_suspended] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeDR(?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100418 /* dispatch to channel based on ChanId */
419 cid := f_cid_by_chan_nr(f_trx_by_streamId(rx_rsl.streamId),
420 rx_rsl.rsl.ies[0].body.chan_nr);
421 if (cid != -1) {
422 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
423 } else {
424 setverdict(fail, "RSL for unknown Dchan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200425 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100426 }
427 }
428
Harald Welte70b52c92018-02-12 20:47:31 +0100429 [not dchan_suspended] IPA_PT.receive {
Harald Welte714ded92017-12-08 14:00:22 +0100430 setverdict(fail, "Received unknown primitive from IPA");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200431 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100432 }
433
Harald Welte1c02fd12018-02-19 19:20:47 +0100434 [bts_role] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
Harald Welte714ded92017-12-08 14:00:22 +0100435 /* Store the knowledge that this sender has requested a certain RQ+time */
436 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100437 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
Harald Welte714ded92017-12-08 14:00:22 +0100438 ts_RSL_CHAN_RQD(chan_rqd.ra, chan_rqd.fn)));
439 }
440
441 [] CLIENT_PT.receive(tr_RSL_MsgType(?)) -> value rx_rsl_msg sender vc_conn {
442 /* forward to BSC */
443 cid := f_cid_by_comp_ref(vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100444 IPA_PT.send(ts_ASP_RSL_UD(ConnectionTable[cid].stream_id, rx_rsl_msg));
Harald Welte714ded92017-12-08 14:00:22 +0100445 }
446
Harald Welte34252c52018-02-24 04:51:50 +0100447 [] CCHAN_PT.receive(tr_RSL(?)) -> value rx_rsl {
448 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl.streamId, rx_rsl.rsl));
449 }
450
Harald Weltef70df652018-01-29 22:00:23 +0100451 /* explicit registration, e.g. in (non-immediate) assignment case */
452 [] RSL_PROC.getcall(RSLEM_register:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
453 f_cid_create_cnr(trx_nr, chan_nr, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200454 RSL_PROC.reply(RSLEM_register:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100455 }
456
Harald Welte1909f462018-01-29 22:29:29 +0100457 [] RSL_PROC.getcall(RSLEM_unregister:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
458 cid := f_cid_by_chan_nr(trx_nr, chan_nr);
459 f_cid_clear(cid);
Harald Weltee32ad992018-05-31 22:17:46 +0200460 RSL_PROC.reply(RSLEM_unregister:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Welte1909f462018-01-29 22:29:29 +0100461 }
462
Harald Weltee32ad992018-05-31 22:17:46 +0200463 [] RSL_PROC.getcall(RSLEM_suspend:{true}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100464 log("Suspending DChan");
465 dchan_suspended := true;
Harald Weltee32ad992018-05-31 22:17:46 +0200466 RSL_PROC.reply(RSLEM_suspend:{true}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100467 }
468
Harald Weltee32ad992018-05-31 22:17:46 +0200469 [] RSL_PROC.getcall(RSLEM_suspend:{false}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100470 log("Resuming DChan");
471 dchan_suspended := false;
Harald Weltee32ad992018-05-31 22:17:46 +0200472 RSL_PROC.reply(RSLEM_suspend:{false}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100473 }
Harald Welte1909f462018-01-29 22:29:29 +0100474
Harald Weltee32ad992018-05-31 22:17:46 +0200475 [] RSL_PROC.getcall(RSLEM_get_last_act:{?,?,?}) -> param(trx_nr, chan_nr) sender vc_conn {
Harald Weltead2647b2018-03-22 19:53:55 +0100476 var RSL_Message last_chan_act := f_lookup_last_act(trx_nr, chan_nr);
Harald Weltee32ad992018-05-31 22:17:46 +0200477 RSL_PROC.reply(RSLEM_get_last_act:{trx_nr, chan_nr, last_chan_act}) to vc_conn;
Harald Weltead2647b2018-03-22 19:53:55 +0100478 }
Harald Welte714ded92017-12-08 14:00:22 +0100479 }
480 }
481}
482
Daniel Willmann17f970f2018-01-17 12:03:19 +0100483private function f_conn_table_init()
484runs on RSL_Emulation_CT {
485 var integer i;
486
487 /* Initialize the ConnectionTable */
488 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
489 f_cid_clear(i);
490 }
491}
Harald Welte714ded92017-12-08 14:00:22 +0100492
Harald Weltef70df652018-01-29 22:00:23 +0100493/* client/conn_hdlr side function to use procedure port to register stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100494function f_rslem_register(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
495runs on RSL_DchanHdlr {
496 PT.call(RSLEM_register:{trx_nr, chan_nr, self}) {
497 [] PT.getreply(RSLEM_register:{?,?,?}) {};
Harald Weltef70df652018-01-29 22:00:23 +0100498 }
499}
500
Harald Welte1909f462018-01-29 22:29:29 +0100501/* client/conn_hdlr side function to use procedure port to unregister stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100502function f_rslem_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
503runs on RSL_DchanHdlr {
504 PT.call(RSLEM_unregister:{trx_nr, chan_nr, self}) {
505 [] PT.getreply(RSLEM_unregister:{?,?,?}) {};
Harald Welte1909f462018-01-29 22:29:29 +0100506 }
507}
508
Harald Welte70b52c92018-02-12 20:47:31 +0100509/* resume handling of RSL DChan messages from IPA until f_rslem_resume() is called */
510function f_rslem_suspend(RSLEM_PROC_PT PT)
511runs on RSL_DchanHdlr {
512 PT.call(RSLEM_suspend:{true}) {
513 [] PT.getreply(RSLEM_suspend:{true}) {};
514 }
515}
516
517/* resume handling of RSL DChan messages after f_rslem_suspend() is called */
518function f_rslem_resume(RSLEM_PROC_PT PT)
519runs on RSL_DchanHdlr {
520 PT.call(RSLEM_suspend:{false}) {
521 [] PT.getreply(RSLEM_suspend:{false}) {};
522 }
523}
524
Harald Weltead2647b2018-03-22 19:53:55 +0100525/* obtain the last RSL_CHAN_ACT message for the given chan_nr */
526function f_rslem_get_last_act(RSLEM_PROC_PT PT, uint8_t trx_nr, RslChannelNr chan_nr)
527runs on RSL_DchanHdlr return RSL_Message {
528 var RSL_Message chan_act;
529 PT.call(RSLEM_get_last_act:{trx_nr, chan_nr, -}) {
530 [] PT.getreply(RSLEM_get_last_act:{trx_nr, chan_nr, ?}) -> param(chan_act) {};
531 }
532 return chan_act;
533}
534
535
Harald Welte70b52c92018-02-12 20:47:31 +0100536
Harald Welte1909f462018-01-29 22:29:29 +0100537
Harald Welte714ded92017-12-08 14:00:22 +0100538}