blob: e72c0654d33f5e6e8db54ba644094d7ddf59c5ba [file] [log] [blame]
Harald Welte801ed1a2023-04-30 15:07:00 +10001module BSC_Tests_ASCI {
2
3/* Integration Tests for OsmoBSC
4 * (C) 2023 by Harald Welte <laforge@gnumonks.org>
5 * All rights reserved.
6 *
7 * Released under the terms of GNU General Public License, Version 2 or
8 * (at your option) any later version.
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
12 * This test suite tests OsmoBSC while emulating both multiple BTS + MS as
13 * well as the MSC. See README for more details.
14 */
15
16import from General_Types all;
17import from Osmocom_Types all;
18import from GSM_Types all;
19import from Misc_Helpers all;
20
21import from BSC_Tests all;
22import from BSSAP_Types all;
23import from BSSAP_CodecPort all;
24import from BSSMAP_Templates all;
25import from RSL_Types all;
26import from RSL_Emulation all;
27import from MGCP_Emulation all;
28
29import from MobileL3_CommonIE_Types all;
30import from MobileL3_Types all;
31import from L3_Templates all;
32import from GSM_RR_Types all;
33
34import from MSC_ConnectionHandler all;
35import from RAN_Adapter all;
36import from RAN_Emulation all;
37
38const charstring COORD_VGCS_CALL_EST := "VGCS_CALL_EST";
39const charstring COORD_VGCS_CALL_REL := "VGCS_CALL_REL";
40const charstring COORD_VGCS_CHANNEL_REL := "VGCS_CHANNEL_REL";
41const charstring COORD_VGCS_UPLINK_FREE := "VGCS_UPLINK_FREE";
42const charstring COORD_VGCS_UPLINK_BUSY := "VGCS_UPLINK_BUSY";
43const charstring COORD_VGCS_ASSIGN_RES := "VGCS_ASSIGN_RES";
44const charstring COORD_VGCS_ASSIGN_FAIL := "VGCS_ASSIGN_FAIL";
45
46template (value) DescriptiveGroupOrBroadcastCallReference_V
47 ts_BSSMAP_IE_GroupCallRef(integer cr,
48 BIT1 sf,
49 BIT1 af,
50 BIT3 prio,
51 BIT4 ci) := {
52 binaryCodingOfGroupOrBroadcastCallReference := int2bit(cr, 27),
53 sF := sf,
54 aF := af,
55 callPriority := prio,
56 cipheringInformation := ci,
57 spare := '0000'B
58}
59
60function f_gen_asci_ass_req(integer bssap_idx := 0,
61 template (value) BSSMAP_IE_ChannelType ch_type := ts_BSSMAP_IE_ChannelType,
62 template (value) OCT1 ass_requirement := '00'O,
63 template (value) BSSMAP_IE_CellIdentifier cell_id := ts_CellId_CI(0),
64 template (value) GroupCallRef group_call_ref := '0000001000'O,
65 charstring aoip_tla :="1.2.3.4")
66runs on MSC_ConnHdlr return template (value) PDU_BSSAP {
67 if (mp_bssap_cfg[bssap_idx].transport == BSSAP_TRANSPORT_AoIP) {
68 var template (value) BSSMAP_IE_AoIP_TransportLayerAddress tla :=
69 f_ts_BSSMAP_IE_AoIP_TLA(aoip_tla, 2342);
70 var template (value) BSSMAP_IE_SpeechCodecList codec_list :=
71 ts_BSSMAP_IE_CodecList({ts_CodecFR});
72 return ts_BSSMAP_VGCS_VBS_AssignmentReq(ch_type, ass_requirement, cell_id,
73 group_call_ref, omit, tla, omit, codec_list);
74 } else {
75 var template (value) BSSMAP_IE_CircuitIdentityCode cic := ts_BSSMAP_IE_CIC(0,1);
76 return ts_BSSMAP_VGCS_VBS_AssignmentReq(ch_type, ass_requirement, cell_id,
77 group_call_ref, cic, omit, omit, omit);
78 }
79}
80
81/*
82 * VGCS/VBS call controling connection
83 */
84
85private function f_tc_vgcs_vbs_setup(charstring id) runs on MSC_ConnHdlr {
86 var PDU_BSSAP rx_bssap;
87 var template (value) DescriptiveGroupOrBroadcastCallReference_V callref :=
88 ts_BSSMAP_IE_GroupCallRef(11, '1'B, '0'B, '000'B, '0000'B);
89 var template (value) PDU_BSSAP setup_req := ts_BSSMAP_VGCS_VBS_Setup(bit2oct(encvalue(callref)), omit);
90 var boolean uplink_free := false;
91 var boolean uplink_busy := false;
92 var boolean uplink_req := false;
93 var boolean uplink_req_conf := false;
94 var boolean uplink_rel_ind := false;
95 var boolean assign_res := false;
96 var boolean assign_fail := false;
97 /* Note: This timer is used to receive messages after the expected event.
98 * After timeout, the outcome of the test is checked. */
99 timer T := 0.2;
100
101 /* Wait for the COORD ports to be connected. */
102 f_sleep(1.0);
103
104 /* VGCS/VBS SETUP REQ in SCCP CR (must be the first message) */
105 BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc, setup_req));
106 BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND);
107
108 alt {
109 [] BSSAP.receive(tr_BSSMAP_VGCS_VBS_SetupAck) -> value rx_bssap {
110 log("VGCS: got setup ack");
111 if (not g_pars.asci_test.vgcs_setup_ok) {
112 COORD.send(COORD_VGCS_CALL_EST);
113 repeat;
114 }
115 BSSAP.send(ts_BSSMAP_ClearCommand(0));
116 BSSAP.receive(tr_BSSMAP_ClearComplete);
117 BSSAP.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
118 setverdict(pass);
119 return;
120 }
121 [] BSSAP.receive(tr_BSSMAP_VGCS_VBS_SetupRefuse) -> value rx_bssap {
122 log("VGCS: got setup refuse");
123 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
124 "Expected ASCI Setup to succeed, but got fail");
125 return;
126 }
127 [] BSSAP.receive(tr_BSSMAP_UplinkReq) -> value rx_bssap {
128 log("VGCS: received uplink req");
129 uplink_req := true;
130 BSSAP.send(ts_BSSMAP_UplinkReqAck(omit));
131 if (g_pars.asci_test.vgcs_talker_req) {
132 T.start;
133 }
134 repeat;
135 }
136 [] BSSAP.receive(tr_BSSMAP_UplinkReqConf(?, omit, '1234'O)) -> value rx_bssap {
137 log("VGCS: received uplink req confirm");
138 uplink_req_conf := true;
139 if (g_pars.asci_test.vgcs_talker_est) {
140 T.start;
141 }
142 repeat;
143 }
144 [] BSSAP.receive(tr_BSSMAP_UplinkRelInd(GSM0808_CAUSE_CALL_CONTROL, omit)) -> value rx_bssap {
145 log("VGCS: received uplink rel ind");
146 uplink_rel_ind := true;
147 if (g_pars.asci_test.vgcs_talker_rel) {
148 T.start;
149 }
150 repeat;
151 }
152 [] COORD.receive(COORD_VGCS_ASSIGN_RES) {
153 log("VGCS: got assignment result at call control");
154 assign_res := true;
155 if (g_pars.asci_test.vgcs_assign_ok) {
156 T.start;
157 }
158 repeat;
159 }
160 [] COORD.receive(COORD_VGCS_ASSIGN_FAIL) {
161 log("VGCS: got assignment failure at call control");
162 assign_fail := true;
163 if (g_pars.asci_test.vgcs_assign_fail) {
164 T.start;
165 }
166 repeat;
167 }
168 [] COORD.receive(COORD_VGCS_UPLINK_FREE) {
169 log("VGCS: Got UPLINK FREE at call control");
170 uplink_busy := false;
171 uplink_free := true;
172 repeat;
173 }
174 [] COORD.receive(COORD_VGCS_UPLINK_BUSY) {
175 log("VGCS: Got UPLINK BUSY at call control");
176 uplink_busy := true;
177 uplink_free := false;
178 repeat;
179 }
180 [] T.timeout { }
181 }
182
183 /* After timeout: Release Channel and Call and see if the outcome of the test is as expected. */
184 COORD.send(COORD_VGCS_CHANNEL_REL);
185 BSSAP.send(ts_BSSMAP_ClearCommand(0));
186 BSSAP.receive(tr_BSSMAP_ClearComplete);
187 BSSAP.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
188
189 if (g_pars.asci_test.vgcs_assign_ok) {
190 if (not assign_res) {
191 setverdict(fail, "VGCS: Assignment did not pass as expected!");
192 return;
193 }
194 if (not uplink_free) {
195 setverdict(fail, "VGCS: Uplink not free as expected!");
196 return;
197 }
198 log("VGCS: Channel assigned and uplink marked free as expected!");
199 setverdict(pass);
200 return;
201 }
202 if (g_pars.asci_test.vgcs_assign_fail) {
203 if (not assign_fail) {
204 setverdict(fail, "VGCS: Assignment did not fail as expected!");
205 return;
206 }
207 log("VGCS: Channel assignment failed as expected!");
208 setverdict(pass);
209 return;
210 }
211 if (g_pars.asci_test.vgcs_talker_req) {
212 if (not uplink_req) {
213 setverdict(fail, "VGCS: No uplink request as expected!");
214 return;
215 }
216 if (not uplink_busy) {
217 setverdict(fail, "VGCS: Uplink not busy as expected!");
218 return;
219 }
220 log("VGCS: Uplink requested and uplink marked busy as expected!");
221 setverdict(pass);
222 return;
223 }
224 if (g_pars.asci_test.vgcs_talker_est) {
225 if (not uplink_req_conf) {
226 setverdict(fail, "VGCS: No uplink request confirm as expected!");
227 return;
228 }
229 if (not uplink_busy) {
230 setverdict(fail, "VGCS: Uplink not busy as expected!");
231 return;
232 }
233 log("VGCS: Uplink established and uplink marked busy as expected!");
234 setverdict(pass);
235 return;
236 }
237 if (g_pars.asci_test.vgcs_talker_rel) {
238 if (not uplink_rel_ind) {
239 setverdict(fail, "VGCS: No uplink release indication as expected!");
240 return;
241 }
242 if (not uplink_free) {
243 setverdict(fail, "VGCS: Uplink not free as expected!");
244 return;
245 }
246 log("VGCS: Uplink established+released and uplink marked free as expected!");
247 setverdict(pass);
248 return;
249 }
250}
251
252/*
253 * VGCS/VBS resource controling connection
254 */
255
256private altstep as_eat_rsl_data() runs on MSC_ConnHdlr {
Andreas Eversbergc0870e52023-07-07 12:06:24 +0200257 [] RSL.receive(tr_RSL_UNITDATA_REQ(g_chan_nr, ?, ?)) {
258 log("VGCS: Got RSL UNITDATA REQ on channel");
259 repeat;
260 }
Harald Welte801ed1a2023-04-30 15:07:00 +1000261 [] RSL.receive(tr_RSL_DATA_REQ(g_chan_nr, ?, ?)) {
262 log("VGCS: Got RSL DATA REQ on channel");
263 repeat;
264 }
265}
266
267private function f_tc_asci_assignment(charstring id) runs on MSC_ConnHdlr {
268 var PDU_BSSAP rx_bssap;
269 /* Hack: the proper way would be to wait for the BSSMAP VGCS Assignment Result and extract the
270 * actual assigned chan_nr from it. But osmo-bsc starts acting on the lchan even before we get a
271 * chance to evaluate the BSSMAP Handover Request ACK. So we need to assume that osmo-bsc will
272 * activate TS 1 and already set up this lchan's RSL emulation
273 * before we get started. */
274 var RslChannelNr new_chan_nr := valueof(t_RslChanNr0(1, RSL_CHAN_NR_Bm_ACCH));
275 f_rslem_register(0, new_chan_nr);
276 g_chan_nr := new_chan_nr;
277 var uint3_t expect_target_tsc := c_BtsParams[0].tsc;
278 var default eat_rsl_data;
279
280 /* Wait for the COORD ports to be connected. */
281 f_sleep(1.0);
282
283 f_create_mgcp_expect(ExpectCriteria:{omit,omit,omit});
284 f_MscConnHdlr_init(g_pars.media_nr, "127.0.0.2", "127.0.0.3", FR_AMR);
285 var default as_media := activate(as_Media());
286
287 log("VGCS: wait for establishment of call controling connection");
288 COORD.receive(COORD_VGCS_CALL_EST);
289 log("VGCS: got establishment of call controling connection");
290
291 /* TODO: Encryption */
292 var template (value) BSSMAP_IE_ChannelType req_ch_type := ts_BSSMAP_IE_ChannelType;
293 var template BSSMAP_IE_ChannelType res_ch_type := tr_BSSMAP_IE_ChannelType('0001'B, ChRate_TCHF, Spdi_TCHF_FR);
294 var template (value) BSSMAP_IE_CellIdentifier req_cell_id := ts_CellId_CI(0);
295 var template BSSMAP_IE_CellIdentifier res_cell_id := tr_CellId_CI(0);
296 var template (value) DescriptiveGroupOrBroadcastCallReference_V callref :=
297 ts_BSSMAP_IE_GroupCallRef(11, '1'B, '0'B, '000'B, '0000'B);
298 if (g_pars.asci_test.vgcs_assign_fail) {
299 callref := ts_BSSMAP_IE_GroupCallRef(10, '1'B, '0'B, '000'B, '0000'B);
300 }
301 var template (value) PDU_BSSAP ass_req := f_gen_asci_ass_req(ch_type := req_ch_type, cell_id := req_cell_id,
302 group_call_ref := bit2oct(encvalue(callref)));
303 /* VGCS/VBS ASS REQ in SCCP CR (must be the first message) */
304 BSSAP.send(ts_BSSAP_Conn_Req(g_pars.sccp_addr_bsc, g_pars.sccp_addr_msc, ass_req));
305 BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_CONF_IND);
306
307 alt {
308 [] BSSAP.receive(tr_BSSMAP_VGCS_VBS_AssignmentRes(res_ch_type, res_cell_id)) -> value rx_bssap {
309 log("VGCS: got assignment result on channel");
310 COORD.send(COORD_VGCS_ASSIGN_RES);
311 if (g_pars.asci_test.vgcs_talker_req or
312 g_pars.asci_test.vgcs_talker_est or
313 g_pars.asci_test.vgcs_talker_rel) {
314 log("VGCS: sending talker det");
315 RSL.send(ts_RSL_TALKER_DET(g_chan_nr));
316 }
317 if (g_pars.asci_test.vgcs_talker_est or
318 g_pars.asci_test.vgcs_talker_rel) {
319 log("VGCS: sending RSL etabish ind");
320 RSL.send(ts_RSL_EST_IND(g_chan_nr, ts_RslLinkID_DCCH(0), '1234'O));
321 }
322 if (g_pars.asci_test.vgcs_talker_rel) {
323 log("VGCS: sending RSL release ind");
324 RSL.send(ts_RSL_REL_IND(g_chan_nr, ts_RslLinkID_DCCH(0)));
325 }
326 repeat;
327 }
328 [] BSSAP.receive(tr_BSSMAP_VGCS_VBS_AssignmentFail) -> value rx_bssap {
329 log("VGCS: got assignment failure on channel");
330 COORD.send(COORD_VGCS_ASSIGN_FAIL);
331 log("VGCS: got release order after assignment failure");
332 COORD.receive(COORD_VGCS_CHANNEL_REL);
333 BSSAP.send(ts_BSSMAP_ClearCommand(0));
334 BSSAP.receive(tr_BSSMAP_ClearComplete);
335 BSSAP.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
336 return;
337 }
338 [] COORD.receive(COORD_VGCS_CHANNEL_REL) {
339 log("VGCS: got release order of resource controling connection");
340 eat_rsl_data := activate(as_eat_rsl_data());
341 f_perform_clear_no_rr_rel();
342 deactivate(eat_rsl_data);
343 return;
344 }
Andreas Eversbergc0870e52023-07-07 12:06:24 +0200345 [] RSL.receive(tr_RSL_UNITDATA_REQ(g_chan_nr, ?, '082B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O)) {
Harald Welte801ed1a2023-04-30 15:07:00 +1000346 log("VGCS: Got UPLINK FREE on channel");
347 COORD.send(COORD_VGCS_UPLINK_FREE);
348 repeat;
349 }
Andreas Eversbergc0870e52023-07-07 12:06:24 +0200350 [] RSL.receive(tr_RSL_UNITDATA_REQ(g_chan_nr, ?, '062A'O)) {
Harald Welte801ed1a2023-04-30 15:07:00 +1000351 log("VGCS: Got UPLINK BUSY on channel");
352 COORD.send(COORD_VGCS_UPLINK_BUSY);
353 repeat;
354 }
355 }
356
357 /* The RSL Emulation magically accepts the Chan Activ behind the scenes. */
358
359 /* we're sure that the channel activation is done now, verify the parameters in it */
360 var RSL_Message chan_act := f_rslem_get_last_act(RSL_PROC, 0, g_chan_nr);
361 /* TODO: Encryption */
362 f_chan_act_verify_tsc(chan_act, expect_target_tsc);
363
364 if (ispresent(rx_bssap.pdu.bssmap.vGCS_VBSAssignmentResult.speechCodec)) {
365 if (not g_pars.aoip) {
366 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
367 "Expected no Speech Codec (Chosen)");
368 }
369 } else {
370 if (g_pars.aoip) {
371 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
372 "Expected Speech Codec (Chosen)");
373 }
374 }
375
376}
377
378testcase TC_vgcs_vbs_setup_only() runs on test_CT {
379 var MSC_ConnHdlr call_conn;
380 var TestHdlrParams pars := f_gen_test_hdlr_pars();
381
382 f_init(1, true);
383
384 pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
385 pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
386
387 pars.asci_test.vgcs_setup_ok := true;
388
389 call_conn := f_start_handler(refers(f_tc_vgcs_vbs_setup), pars);
390
391 call_conn.done;
392
393 f_shutdown_helper();
394}
395
396testcase TC_vgcs_vbs_assignment() runs on test_CT {
397 var MSC_ConnHdlr call_conn, chan_conn;
398 var TestHdlrParams pars := f_gen_test_hdlr_pars();
399
400 f_init(1, true);
401
402 pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
403 pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
404
405 pars.asci_test.vgcs_assign_ok := true;
406
407 call_conn := f_start_handler(refers(f_tc_vgcs_vbs_setup), pars);
408 chan_conn := f_start_handler(refers(f_tc_asci_assignment), pars);
409 /* Connect COORD ports of both functions. The functions will delay before using them. */
410 connect(call_conn:COORD, chan_conn:COORD);
411
412 call_conn.done;
413 chan_conn.done;
414
415 f_shutdown_helper();
416}
417
418testcase TC_vgcs_vbs_assignment_fail() runs on test_CT {
419 var MSC_ConnHdlr call_conn, chan_conn;
420 var TestHdlrParams pars := f_gen_test_hdlr_pars();
421
422 f_init(1, true);
423
424 pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
425 pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
426
427 pars.asci_test.vgcs_assign_fail := true;
428
429 call_conn := f_start_handler(refers(f_tc_vgcs_vbs_setup), pars);
430 chan_conn := f_start_handler(refers(f_tc_asci_assignment), pars);
431 /* Connect COORD ports of both functions. The functions will delay before using them. */
432 connect(call_conn:COORD, chan_conn:COORD);
433
434 call_conn.done;
435 chan_conn.done;
436
437 f_shutdown_helper();
438}
439
440testcase TC_vgcs_vbs_talker_req() runs on test_CT {
441 var MSC_ConnHdlr call_conn, chan_conn;
442 var TestHdlrParams pars := f_gen_test_hdlr_pars();
443
444 f_init(1, true);
445
446 pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
447 pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
448
449 pars.asci_test.vgcs_talker_req := true;
450
451 call_conn := f_start_handler(refers(f_tc_vgcs_vbs_setup), pars);
452 chan_conn := f_start_handler(refers(f_tc_asci_assignment), pars);
453 /* Connect COORD ports of both functions. The functions will delay before using them. */
454 connect(call_conn:COORD, chan_conn:COORD);
455
456 call_conn.done;
457 chan_conn.done;
458
459 f_shutdown_helper();
460}
461
462testcase TC_vgcs_vbs_talker_est() runs on test_CT {
463 var MSC_ConnHdlr call_conn, chan_conn;
464 var TestHdlrParams pars := f_gen_test_hdlr_pars();
465
466 f_init(1, true);
467
468 pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
469 pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
470
471 pars.asci_test.vgcs_talker_est := true;
472
473 call_conn := f_start_handler(refers(f_tc_vgcs_vbs_setup), pars);
474 chan_conn := f_start_handler(refers(f_tc_asci_assignment), pars);
475 /* Connect COORD ports of both functions. The functions will delay before using them. */
476 connect(call_conn:COORD, chan_conn:COORD);
477
478 call_conn.done;
479 chan_conn.done;
480
481 f_shutdown_helper();
482}
483
484testcase TC_vgcs_vbs_talker_rel() runs on test_CT {
485 var MSC_ConnHdlr call_conn, chan_conn;
486 var TestHdlrParams pars := f_gen_test_hdlr_pars();
487
488 f_init(1, true);
489
490 pars.sccp_addr_msc := g_bssap[0].sccp_addr_own;
491 pars.sccp_addr_bsc := g_bssap[0].sccp_addr_peer;
492
493 pars.asci_test.vgcs_talker_rel := true;
494
495 call_conn := f_start_handler(refers(f_tc_vgcs_vbs_setup), pars);
496 chan_conn := f_start_handler(refers(f_tc_asci_assignment), pars);
497 /* Connect COORD ports of both functions. The functions will delay before using them. */
498 connect(call_conn:COORD, chan_conn:COORD);
499
500 call_conn.done;
501 chan_conn.done;
502
503 f_shutdown_helper();
504}
505
506control {
507 execute( TC_vgcs_vbs_setup_only() );
508 execute( TC_vgcs_vbs_assignment() );
509 execute( TC_vgcs_vbs_assignment_fail() );
510 execute( TC_vgcs_vbs_talker_req() );
511 execute( TC_vgcs_vbs_talker_est() );
512 execute( TC_vgcs_vbs_talker_rel() );
513}
514
515
516}