blob: cdeca7468210dc7ed318e86e5317c97d2e5568b8 [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,
Pau Espin Pedrol6451b042018-10-24 20:36:16 +020050 GsmFrameNumber fn optional
Harald Welte714ded92017-12-08 14:00:22 +010051};
52
Pau Espin Pedrol6451b042018-10-24 20:36:16 +020053template (value) RSLDC_ChanRqd ts_RSLDC_ChanRqd(OCT1 ra, GsmFrameNumber fn) := {
Harald Welte714ded92017-12-08 14:00:22 +010054 ra := ra,
55 fn := fn
56}
57
Pau Espin Pedrol6451b042018-10-24 20:36:16 +020058template (value) RSLDC_ChanRqd ts_RSLDC_ChanRqd_anyFN(OCT1 ra) := {
59 ra := ra,
60 fn := omit
61}
62
Harald Welte714ded92017-12-08 14:00:22 +010063type port RSL_DCHAN_PT message {
64 inout RSLDC_ChanRqd, RSL_Message;
65} with { extension "internal" };
66
Harald Welte1c02fd12018-02-19 19:20:47 +010067type port RSL_CCHAN_PT message {
Harald Weltebb6aed32018-02-21 12:19:18 +010068 inout ASP_RSL_Unitdata, ASP_IPA_Event;
Harald Welte1c02fd12018-02-19 19:20:47 +010069} with { extension "internal" };
70
71
Harald Weltef70df652018-01-29 22:00:23 +010072signature RSLEM_register(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte1909f462018-01-29 22:29:29 +010073signature RSLEM_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr hdlr);
Harald Welte70b52c92018-02-12 20:47:31 +010074signature RSLEM_suspend(boolean suspend);
Harald Weltead2647b2018-03-22 19:53:55 +010075signature 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 +010076
77type port RSLEM_PROC_PT procedure {
Harald Weltead2647b2018-03-22 19:53:55 +010078 inout RSLEM_register, RSLEM_unregister, RSLEM_suspend, RSLEM_get_last_act;
Harald Weltef70df652018-01-29 22:00:23 +010079} with { extension "internal" };
80
Harald Welte714ded92017-12-08 14:00:22 +010081/***********************************************************************
82 * Client Component for a single dedicated channel
83 ***********************************************************************/
84
85private function f_rx_or_fail(template RSL_Message exp_rx) runs on RSL_DchanHdlr return RSL_Message
86{
87 var RSL_Message rx_rsl;
88 timer T := 10.0;
89
90 /* request a channel to be established */
91 T.start;
92 alt {
93 [] RSL.receive(exp_rx) -> value rx_rsl {
94 T.stop;
95 return rx_rsl;
96 }
97 [] RSL.receive {
98 setverdict(fail, "Unexpected RSL message on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020099 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100100 }
101 [] T.timeout {
102 setverdict(fail, "Timeout waiting for RSL on DCHAN");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200103 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100104 }
105 }
106 /* never reached */
107 return rx_rsl;
108}
109
110/* establish a dedicated channel using 'ra' */
111function f_chan_est(OCT1 ra, octetstring est_l3, template RslLinkId link_id, GsmFrameNumber fn := 23)
112runs on RSL_DchanHdlr {
113 var RSL_Message rx_rsl;
114 var GsmRrMessage rr;
115
116 /* request a channel to be established */
117 RSL.send(ts_RSLDC_ChanRqd(ra, fn));
118 /* expect immediate assignment */
119 rx_rsl := f_rx_or_fail(tr_RSL_IMM_ASSIGN);
120 rr := dec_GsmRrMessage(rx_rsl.ies[1].body.full_imm_ass_info.payload);
121 g_chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
122 RSL.send(ts_RSL_EST_IND(g_chan_nr, valueof(link_id), est_l3));
123}
124
125function f_deact_chan(RSL_Cause cause) runs on RSL_DchanHdlr
126{
127 var RSL_Message rx_rsl;
128
129 RSL.send(ts_RSL_CONN_FAIL_IND(g_chan_nr, cause));
130 rx_rsl := f_rx_or_fail(tr_RSL_MsgTypeD(RSL_MT_RF_CHAN_REL));
131 /* FIXME RSL.send(ts_RSL_RF_CHAN_REL_ACK()) */
132}
133
134
135
136/***********************************************************************
137 * Main Component
138 ***********************************************************************/
139
140private type record ConnectionData {
141 /* component reference to the client component */
142 RSL_DchanHdlr comp_ref,
143 /* RSL (dedicated) Channel number we're handling */
144 uint8_t trx_nr optional,
145 IpaStreamId stream_id optional,
146 RslChannelNr chan_nr optional,
147 /* Random Reference */
148 OCT1 ra optional,
149 GsmFrameNumber ra_fn optional
150};
151
152private function f_cid_by_comp_ref(RSL_DchanHdlr comp_ref)
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].comp_ref) and
157 ConnectionTable[i].comp_ref == comp_ref) {
158 return i;
159 }
160 }
161 log("No Dchan handler for ", comp_ref);
162 return -1;
163}
164
165private function f_cid_by_chan_nr(uint8_t trx_nr, RslChannelNr chan_nr)
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].chan_nr) and
170 ConnectionTable[i].chan_nr == chan_nr and ConnectionTable[i].trx_nr == trx_nr) {
171 return i;
172 }
173 }
174 log("No Dchan handler for ", trx_nr, chan_nr);
175 return -1;
176}
177
178private function f_cid_by_ra_fn(OCT1 ra, GsmFrameNumber fn)
179runs on RSL_Emulation_CT return integer {
180 var integer i;
181 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
182 if (ispresent(ConnectionTable[i].ra) and
183 ConnectionTable[i].ra == ra and ConnectionTable[i].ra_fn == fn) {
184 return i;
185 }
186 }
187 log("No Dchan handler for ", ra, fn);
188 return -1;
189}
190
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200191/* Matches by only RA if FN is ommited in one of the connections allocated */
192private function f_cid_by_ra_fn2(OCT1 ra, RSL_IE_FrameNumber fn)
193runs on RSL_Emulation_CT return integer {
194 var integer i;
195 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
196 if (ispresent(ConnectionTable[i].ra) and
197 ConnectionTable[i].ra == ra) {
198 if (not ispresent(ConnectionTable[i].ra_fn) or
199 fn == valueof(ts_RSL_IE_FrameNumber(ConnectionTable[i].ra_fn))) {
200 return i;
201 }
202 }
203 }
204 log("No Dchan handler for ", ra, fn);
205 return -1;
206}
207
Harald Welte714ded92017-12-08 14:00:22 +0100208/* create an ew client with given RA and FN */
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200209private function f_cid_create(OCT1 ra, template (omit) GsmFrameNumber fn, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100210runs on RSL_Emulation_CT {
Harald Welte714ded92017-12-08 14:00:22 +0100211 var integer i;
212 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
Harald Weltef70df652018-01-29 22:00:23 +0100213 if (not ispresent(ConnectionTable[i].ra) and
214 not ispresent(ConnectionTable[i].trx_nr)) {
Harald Welte714ded92017-12-08 14:00:22 +0100215 ConnectionTable[i].ra := ra;
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200216 if (ispresent(fn)) {
217 ConnectionTable[i].ra_fn := valueof(fn);
218 } else {
219 ConnectionTable[i].ra_fn := omit;
220 }
Harald Welte714ded92017-12-08 14:00:22 +0100221 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100222 return;
Harald Welte714ded92017-12-08 14:00:22 +0100223 }
224 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200225 testcase.stop("No free entry in conn table for ", ra, fn);
Harald Welte714ded92017-12-08 14:00:22 +0100226}
227
Harald Weltef70df652018-01-29 22:00:23 +0100228/* create an ew client with given RA and FN */
229private function f_cid_create_cnr(uint8_t trx_nr, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
Harald Welte930d0a72018-03-22 22:08:40 +0100230runs on RSL_Emulation_CT {
Harald Weltef70df652018-01-29 22:00:23 +0100231 var integer i;
232 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
233 if (not ispresent(ConnectionTable[i].ra) and
234 not ispresent(ConnectionTable[i].trx_nr)) {
235 ConnectionTable[i].stream_id := f_streamId_by_trx(trx_nr);
236 ConnectionTable[i].trx_nr := trx_nr;
237 ConnectionTable[i].chan_nr := chan_nr;
238 ConnectionTable[i].comp_ref := comp_ref;
Harald Welte930d0a72018-03-22 22:08:40 +0100239 return;
Harald Weltef70df652018-01-29 22:00:23 +0100240 }
241 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200242 testcase.stop("No free entry in conn table for ", trx_nr, chan_nr, comp_ref);
Harald Weltef70df652018-01-29 22:00:23 +0100243}
244
245
246/* create an ew client with given RA and FN */
247private function f_cid_delete_cnr(IpaStreamId stream_id, RslChannelNr chan_nr, RSL_DchanHdlr comp_ref)
248runs on RSL_Emulation_CT return integer {
249 var integer i;
250 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
251 if (ConnectionTable[i].comp_ref == null) {
252 continue;
253 }
254 if (ConnectionTable[i].stream_id == stream_id and
255 ConnectionTable[i].chan_nr == chan_nr and
256 ConnectionTable[i].comp_ref == comp_ref) {
257 f_cid_clear(i);
258 }
259 }
260 log("Unable to find entry to delete for ", stream_id, chan_nr, comp_ref);
261 return -1;
262}
263
264
Harald Welte714ded92017-12-08 14:00:22 +0100265private function f_cid_clear(integer cid)
266runs on RSL_Emulation_CT {
267 ConnectionTable[cid].ra := omit;
268 ConnectionTable[cid].ra_fn := omit;
Harald Welte714ded92017-12-08 14:00:22 +0100269 ConnectionTable[cid].trx_nr := omit;
270 ConnectionTable[cid].stream_id := omit;
271 ConnectionTable[cid].chan_nr := omit;
Harald Weltef70df652018-01-29 22:00:23 +0100272 ConnectionTable[cid].comp_ref := null;
Harald Welte714ded92017-12-08 14:00:22 +0100273}
274
Harald Weltead2647b2018-03-22 19:53:55 +0100275/* last activation for a given channel number */
276type record LastActData {
277 uint8_t trx_nr optional,
278 RslChannelNr chan_nr optional,
279 RSL_Message chan_act optional
280}
281
282private function f_store_last_act_data(uint8_t trx_nr, RslChannelNr chan_nr, RSL_Message chan_act)
283runs on RSL_Emulation_CT {
284 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
285 if (not ispresent(LastActTable[i].chan_nr) or
286 (LastActTable[i].chan_nr == chan_nr and LastActTable[i].trx_nr == trx_nr)) {
287 LastActTable[i].trx_nr := trx_nr;
288 LastActTable[i].chan_nr := chan_nr;
289 LastActTable[i].chan_act := chan_act;
290 return;
291 }
292 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200293 testcase.stop("No space left in LastActTable to store chan_act for ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100294}
295
296private function f_lookup_last_act(uint8_t trx_nr, RslChannelNr chan_nr)
297runs on RSL_Emulation_CT return RSL_Message {
298 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
299 if (ispresent(LastActTable[i].chan_nr) and LastActTable[i].chan_nr == chan_nr
300 and LastActTable[i].trx_nr == trx_nr) {
301 return LastActTable[i].chan_act;
302 }
303 }
Daniel Willmann8273fb92018-07-05 17:31:20 +0200304 testcase.stop("No LastActTable entry found for TRX ", trx_nr, " ", chan_nr);
Harald Weltead2647b2018-03-22 19:53:55 +0100305}
306
307private function f_last_act_table_init() runs on RSL_Emulation_CT {
308 for (var integer i := 0; i < sizeof(LastActTable); i := i+1) {
309 LastActTable[i] := { omit, omit, omit };
310 }
311}
312
Harald Welte714ded92017-12-08 14:00:22 +0100313type component RSL_Emulation_CT {
314 /* port facing down towards IPA emulation */
315 port IPA_RSL_PT IPA_PT;
316 /* port facing up towards dedicated channel handler */
317 port RSL_DCHAN_PT CLIENT_PT;
Harald Weltef70df652018-01-29 22:00:23 +0100318 port RSLEM_PROC_PT RSL_PROC;
Harald Welte714ded92017-12-08 14:00:22 +0100319
Harald Welte1c02fd12018-02-19 19:20:47 +0100320 /* port for Common Channel / TRX Management */
321 port RSL_CCHAN_PT CCHAN_PT;
322
Harald Welte714ded92017-12-08 14:00:22 +0100323 /* state of all concurrent connections / dedicated channels */
324 var ConnectionData ConnectionTable[64];
Harald Weltead2647b2018-03-22 19:53:55 +0100325
326 /* last RSL CHAN ACT for each chan_nr */
327 var LastActData LastActTable[64];
Harald Welte714ded92017-12-08 14:00:22 +0100328}
329
330
331/* template for an ASP_RSL_Unitdata as we receive it from the IPA_Emulateion component */
332private template ASP_RSL_Unitdata tr_RSL(template RSL_Message rsl, template IpaStreamId sid := ?) := {
333 streamId := sid,
334 rsl := rsl
335}
336
Harald Welte714ded92017-12-08 14:00:22 +0100337private function f_trx_by_streamId(IpaStreamId id) return integer {
338 return enum2int(id);
339}
340
Harald Weltef70df652018-01-29 22:00:23 +0100341private function f_streamId_by_trx(uint8_t trx_nr) return IpaStreamId {
342 select (trx_nr) {
343 case (0) { return IPAC_PROTO_RSL_TRX0; }
344 case (1) { return IPAC_PROTO_RSL_TRX1; }
345 case (2) { return IPAC_PROTO_RSL_TRX2; }
346 case (3) { return IPAC_PROTO_RSL_TRX3; }
347 }
Daniel Willmanna6ea2ef2018-07-24 09:55:52 +0200348 setverdict(fail, "Unknown stream ID ", trx_nr);
349 mtc.stop;
Harald Weltef70df652018-01-29 22:00:23 +0100350}
351
Harald Welte714ded92017-12-08 14:00:22 +0100352
Harald Welte1c02fd12018-02-19 19:20:47 +0100353function main(boolean bts_role := true) runs on RSL_Emulation_CT {
Harald Weltebb6aed32018-02-21 12:19:18 +0100354 var ASP_IPA_Event evt;
Harald Welte714ded92017-12-08 14:00:22 +0100355 var ASP_RSL_Unitdata rx_rsl;
356 var RSL_Message rx_rsl_msg;
357 var RSLDC_ChanRqd chan_rqd;
358 var RSL_DchanHdlr vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100359 var RslChannelNr chan_nr;
360 var uint8_t trx_nr;
Harald Welte714ded92017-12-08 14:00:22 +0100361 var integer cid;
362 var integer i;
Harald Welte70b52c92018-02-12 20:47:31 +0100363 /* special synchronization handling during hand-over */
364 var boolean dchan_suspended := false;
Harald Welte714ded92017-12-08 14:00:22 +0100365
Daniel Willmann17f970f2018-01-17 12:03:19 +0100366 f_conn_table_init();
Harald Weltead2647b2018-03-22 19:53:55 +0100367 f_last_act_table_init();
Daniel Willmann17f970f2018-01-17 12:03:19 +0100368
Harald Welte714ded92017-12-08 14:00:22 +0100369 while (true) {
370 alt {
Harald Weltebb6aed32018-02-21 12:19:18 +0100371 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) {
372 }
373 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) -> value evt {
374 CCHAN_PT.send(evt);
Harald Welte624f9632017-12-16 19:26:04 +0100375 }
Pau Espin Pedrola07cfd92018-10-22 15:54:41 +0200376 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_DOWN}) {
377 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
378
379 }
380 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_DOWN}) {
381 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Lost IPA connection!");
382 }
Harald Welte1c02fd12018-02-19 19:20:47 +0100383 [bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) {
Harald Welte7ae019e2017-12-09 00:54:15 +0100384 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,ts_RSL_PAGING_LOAD_IND(23)));
Harald Welte714ded92017-12-08 14:00:22 +0100385 }
Harald Welted879e2f2018-05-27 20:22:13 +0200386 [not bts_role] IPA_PT.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { }
Harald Welte1c02fd12018-02-19 19:20:47 +0100387 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_IMM_ASSIGN)) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100388 var GsmRrMessage rr;
389 var OCT1 ra;
390 var GsmFrameNumber fn;
Harald Welte714ded92017-12-08 14:00:22 +0100391 rr := dec_GsmRrMessage(rx_rsl.rsl.ies[1].body.full_imm_ass_info.payload);
392 if (ischosen(rr.payload.imm_ass)) {
393 ra := bit2oct(rr.payload.imm_ass.req_ref.ra);
394 fn := 23; //FIXME(rr.payload.imm_ass);
395 /* lookup client based on RA+time, deliver to client */
396 cid := f_cid_by_ra_fn(ra, fn);
397 if (cid == -1) {
398 setverdict(fail, "IMM ASS for unknown DChan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200399 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100400 }
401 /* update client with trx_nr */
402 ConnectionTable[cid].trx_nr := f_trx_by_streamId(rx_rsl.streamId);
403 ConnectionTable[cid].stream_id := rx_rsl.streamId;
404 /* update client with chan_nr */
405 ConnectionTable[cid].chan_nr := rr.payload.imm_ass.chan_desc.chan_nr;
406 /* TODO: add timer to time-out ConnectionTable entries which
407 * never get followed-up to */
408 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
409 } else if (ischosen(rr.payload.imm_ass_rej)) {
410 for (i := 0; i < sizeof(rr.payload.imm_ass_rej.payload); i := i + 1) {
411 ra := bit2oct(rr.payload.imm_ass_rej.payload[i].req_ref.ra);
412 fn := 23; //FIXME();
413 /* lookup client based on RA+time, deliver to client */
414 cid := f_cid_by_ra_fn(ra, fn);
415 if (cid != -1) {
416 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
417 /* delete ClientTable entry, as it failed */
418 f_cid_clear(cid);
419 }
420 }
421 }
422 }
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200423 [not bts_role] IPA_PT.receive(tr_RSL(tr_RSL_CHAN_RQD(?))) -> value rx_rsl {
424 var RSL_IE_RequestRef req_ref;
425 req_ref := rx_rsl.rsl.ies[1].body.req_ref;
426 cid := f_cid_by_ra_fn2(req_ref.ra, req_ref.frame_nr);
427 if (cid != -1) {
428 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
429 f_cid_clear(cid);
430 } else {
431 CCHAN_PT.send(rx_rsl);
432 }
433 }
Harald Welte714ded92017-12-08 14:00:22 +0100434
Harald Welte1c02fd12018-02-19 19:20:47 +0100435 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_PAGING_CMD(?, ?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100436 /* broadcast to all clients? */
437 for (i := 0; i < sizeof(ConnectionTable); i := i + 1) {
438 if (ispresent(ConnectionTable[i].comp_ref)) {
439 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[i].comp_ref;
440 }
441 }
442 }
443
Harald Welte1c02fd12018-02-19 19:20:47 +0100444 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100445 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeT(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100446 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100447 }
448
Harald Welte1c02fd12018-02-19 19:20:47 +0100449 /* Forward common channel management to the special port for it */
Harald Welte714ded92017-12-08 14:00:22 +0100450 [] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeC(?))) -> value rx_rsl {
Harald Welte1c02fd12018-02-19 19:20:47 +0100451 CCHAN_PT.send(rx_rsl);
Harald Welte714ded92017-12-08 14:00:22 +0100452 }
453
454 /* blindly acknowledge all channel activations */
Harald Welte1c02fd12018-02-19 19:20:47 +0100455 [bts_role] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV))) -> value rx_rsl {
Harald Weltef70df652018-01-29 22:00:23 +0100456 chan_nr := rx_rsl.rsl.ies[0].body.chan_nr;
Harald Weltead2647b2018-03-22 19:53:55 +0100457 trx_nr := f_trx_by_streamId(rx_rsl.streamId);
458 f_store_last_act_data(trx_nr, chan_nr, rx_rsl.rsl);
Harald Welte7ae019e2017-12-09 00:54:15 +0100459 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 +0100460 }
461
Harald Welte70b52c92018-02-12 20:47:31 +0100462 [not dchan_suspended] IPA_PT.receive(tr_RSL(tr_RSL_MsgTypeDR(?))) -> value rx_rsl {
Harald Welte714ded92017-12-08 14:00:22 +0100463 /* dispatch to channel based on ChanId */
464 cid := f_cid_by_chan_nr(f_trx_by_streamId(rx_rsl.streamId),
465 rx_rsl.rsl.ies[0].body.chan_nr);
466 if (cid != -1) {
467 CLIENT_PT.send(rx_rsl.rsl) to ConnectionTable[cid].comp_ref;
468 } else {
469 setverdict(fail, "RSL for unknown Dchan");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200470 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100471 }
472 }
473
Harald Welte70b52c92018-02-12 20:47:31 +0100474 [not dchan_suspended] IPA_PT.receive {
Harald Welte714ded92017-12-08 14:00:22 +0100475 setverdict(fail, "Received unknown primitive from IPA");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200476 mtc.stop;
Harald Welte714ded92017-12-08 14:00:22 +0100477 }
478
Harald Welte1c02fd12018-02-19 19:20:47 +0100479 [bts_role] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
Harald Welte714ded92017-12-08 14:00:22 +0100480 /* Store the knowledge that this sender has requested a certain RQ+time */
481 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100482 IPA_PT.send(ts_ASP_RSL_UD(IPAC_PROTO_RSL_TRX0,
Harald Welte714ded92017-12-08 14:00:22 +0100483 ts_RSL_CHAN_RQD(chan_rqd.ra, chan_rqd.fn)));
484 }
485
Pau Espin Pedrol6451b042018-10-24 20:36:16 +0200486 [not bts_role] CLIENT_PT.receive(RSLDC_ChanRqd:?) -> value chan_rqd sender vc_conn {
487 /* Store the knowledge that this sender has requested a certain RQ+time */
488 f_cid_create(chan_rqd.ra, chan_rqd.fn, vc_conn);
489 }
490
Harald Welte714ded92017-12-08 14:00:22 +0100491 [] CLIENT_PT.receive(tr_RSL_MsgType(?)) -> value rx_rsl_msg sender vc_conn {
492 /* forward to BSC */
493 cid := f_cid_by_comp_ref(vc_conn);
Harald Welte7ae019e2017-12-09 00:54:15 +0100494 IPA_PT.send(ts_ASP_RSL_UD(ConnectionTable[cid].stream_id, rx_rsl_msg));
Harald Welte714ded92017-12-08 14:00:22 +0100495 }
496
Harald Welte34252c52018-02-24 04:51:50 +0100497 [] CCHAN_PT.receive(tr_RSL(?)) -> value rx_rsl {
498 IPA_PT.send(ts_ASP_RSL_UD(rx_rsl.streamId, rx_rsl.rsl));
499 }
500
Harald Weltef70df652018-01-29 22:00:23 +0100501 /* explicit registration, e.g. in (non-immediate) assignment case */
502 [] RSL_PROC.getcall(RSLEM_register:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
503 f_cid_create_cnr(trx_nr, chan_nr, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200504 RSL_PROC.reply(RSLEM_register:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Weltef70df652018-01-29 22:00:23 +0100505 }
506
Harald Welte1909f462018-01-29 22:29:29 +0100507 [] RSL_PROC.getcall(RSLEM_unregister:{?,?,?}) -> param(trx_nr, chan_nr, vc_conn) {
508 cid := f_cid_by_chan_nr(trx_nr, chan_nr);
509 f_cid_clear(cid);
Harald Weltee32ad992018-05-31 22:17:46 +0200510 RSL_PROC.reply(RSLEM_unregister:{trx_nr, chan_nr, vc_conn}) to vc_conn;
Harald Welte1909f462018-01-29 22:29:29 +0100511 }
512
Harald Weltee32ad992018-05-31 22:17:46 +0200513 [] RSL_PROC.getcall(RSLEM_suspend:{true}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100514 log("Suspending DChan");
515 dchan_suspended := true;
Harald Weltee32ad992018-05-31 22:17:46 +0200516 RSL_PROC.reply(RSLEM_suspend:{true}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100517 }
518
Harald Weltee32ad992018-05-31 22:17:46 +0200519 [] RSL_PROC.getcall(RSLEM_suspend:{false}) -> sender vc_conn {
Harald Welte70b52c92018-02-12 20:47:31 +0100520 log("Resuming DChan");
521 dchan_suspended := false;
Harald Weltee32ad992018-05-31 22:17:46 +0200522 RSL_PROC.reply(RSLEM_suspend:{false}) to vc_conn;
Harald Welte70b52c92018-02-12 20:47:31 +0100523 }
Harald Welte1909f462018-01-29 22:29:29 +0100524
Harald Weltee32ad992018-05-31 22:17:46 +0200525 [] RSL_PROC.getcall(RSLEM_get_last_act:{?,?,?}) -> param(trx_nr, chan_nr) sender vc_conn {
Harald Weltead2647b2018-03-22 19:53:55 +0100526 var RSL_Message last_chan_act := f_lookup_last_act(trx_nr, chan_nr);
Harald Weltee32ad992018-05-31 22:17:46 +0200527 RSL_PROC.reply(RSLEM_get_last_act:{trx_nr, chan_nr, last_chan_act}) to vc_conn;
Harald Weltead2647b2018-03-22 19:53:55 +0100528 }
Harald Welte714ded92017-12-08 14:00:22 +0100529 }
530 }
531}
532
Daniel Willmann17f970f2018-01-17 12:03:19 +0100533private function f_conn_table_init()
534runs on RSL_Emulation_CT {
535 var integer i;
536
537 /* Initialize the ConnectionTable */
538 for (i := 0; i < sizeof(ConnectionTable); i := i+1) {
539 f_cid_clear(i);
540 }
541}
Harald Welte714ded92017-12-08 14:00:22 +0100542
Harald Weltef70df652018-01-29 22:00:23 +0100543/* client/conn_hdlr side function to use procedure port to register stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100544function f_rslem_register(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
545runs on RSL_DchanHdlr {
546 PT.call(RSLEM_register:{trx_nr, chan_nr, self}) {
547 [] PT.getreply(RSLEM_register:{?,?,?}) {};
Harald Weltef70df652018-01-29 22:00:23 +0100548 }
549}
550
Harald Welte1909f462018-01-29 22:29:29 +0100551/* client/conn_hdlr side function to use procedure port to unregister stream_id/chan_nr */
Harald Welte421e4d42018-02-12 20:04:50 +0100552function f_rslem_unregister(uint8_t trx_nr, RslChannelNr chan_nr, RSLEM_PROC_PT PT := RSL_PROC)
553runs on RSL_DchanHdlr {
554 PT.call(RSLEM_unregister:{trx_nr, chan_nr, self}) {
555 [] PT.getreply(RSLEM_unregister:{?,?,?}) {};
Harald Welte1909f462018-01-29 22:29:29 +0100556 }
557}
558
Harald Welte70b52c92018-02-12 20:47:31 +0100559/* resume handling of RSL DChan messages from IPA until f_rslem_resume() is called */
560function f_rslem_suspend(RSLEM_PROC_PT PT)
561runs on RSL_DchanHdlr {
562 PT.call(RSLEM_suspend:{true}) {
563 [] PT.getreply(RSLEM_suspend:{true}) {};
564 }
565}
566
567/* resume handling of RSL DChan messages after f_rslem_suspend() is called */
568function f_rslem_resume(RSLEM_PROC_PT PT)
569runs on RSL_DchanHdlr {
570 PT.call(RSLEM_suspend:{false}) {
571 [] PT.getreply(RSLEM_suspend:{false}) {};
572 }
573}
574
Harald Weltead2647b2018-03-22 19:53:55 +0100575/* obtain the last RSL_CHAN_ACT message for the given chan_nr */
576function f_rslem_get_last_act(RSLEM_PROC_PT PT, uint8_t trx_nr, RslChannelNr chan_nr)
577runs on RSL_DchanHdlr return RSL_Message {
578 var RSL_Message chan_act;
579 PT.call(RSLEM_get_last_act:{trx_nr, chan_nr, -}) {
580 [] PT.getreply(RSLEM_get_last_act:{trx_nr, chan_nr, ?}) -> param(chan_act) {};
581 }
582 return chan_act;
583}
584
585
Harald Welte70b52c92018-02-12 20:47:31 +0100586
Harald Welte1909f462018-01-29 22:29:29 +0100587
Harald Welte714ded92017-12-08 14:00:22 +0100588}