blob: 82f6b1148413f238d7e676853bd962899030cb07 [file] [log] [blame]
Harald Weltecc0b0142018-05-29 15:19:33 +02001module BSC_Tests_LCLS {
2
3/* Integration Tests for OsmoBSC
4 * (C) 2018 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 *
Harald Welte34b5a952019-05-27 11:54:11 +020010 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
Harald Weltecc0b0142018-05-29 15:19:33 +020012 * This test suite tests OsmoBSC while emulating both multiple BTS + MS as
13 * well as the MSC. See README for more details.
14 *
15 * There are test cases that run in so-called 'handler mode' and test cases
16 * that run directly on top of the BSSAP and RSL CodecPorts. The "handler mode"
17 * tests abstract the multiplexing/demultiplexing of multiple SCCP connections
18 * and/or RSL channels and are hence suitable for higher-level test cases, while
19 * the "raw" tests directly on top of the CodecPorts are more suitable for lower-
20 * level testing.
21 */
22
23import from General_Types all;
24import from Osmocom_Types all;
25import from GSM_Types all;
26import from IPL4asp_Types all;
27
28import from BSSAP_Types all;
Harald Welte6811d102019-04-14 22:23:14 +020029import from RAN_Adapter all;
Harald Weltecc0b0142018-05-29 15:19:33 +020030import from BSSAP_CodecPort all;
31import from BSSMAP_Templates all;
32import from IPA_Emulation all;
33import from IPA_CodecPort all;
34import from IPA_Types all;
35import from RSL_Types all;
36import from RSL_Emulation all;
37import from MGCP_Types all;
38import from MGCP_Emulation all;
39import from MGCP_Templates all;
40import from SDP_Types all;
Max2253c0b2018-11-06 19:28:05 +010041import from Native_Functions all;
Harald Weltecc0b0142018-05-29 15:19:33 +020042
43import from Osmocom_CTRL_Functions all;
44import from Osmocom_CTRL_Types all;
45import from Osmocom_CTRL_Adapter all;
46
47import from Osmocom_VTY_Functions all;
48import from TELNETasp_PortType all;
49
50import from MobileL3_CommonIE_Types all;
51import from MobileL3_Types all;
52import from L3_Templates all;
53import from GSM_RR_Types all;
54
55import from BSSMAP_Templates all;
Harald Welte6811d102019-04-14 22:23:14 +020056import from RAN_Emulation all;
Harald Weltecc0b0142018-05-29 15:19:33 +020057
58import from MSC_ConnectionHandler all;
59import from BSC_Tests all;
60
61/* The philosophy of this testsuite is to re-use as much as possible the existing components
62 * and functions that we have in BSC_Tests and its dependencies. However, as opposed to those
63 * normal BSC tests, we here have to run *two* ConnHdlr and synchronize activity between them.
64 *
65 * We do this by adding some special-purpose ports between the main test component running the
66 * test case [lcls_]test_CT and the per-connection [LCLS_]MSC_ConnHdlr.
67 */
68
69
70/* take test_CT from BSC_Tests and extend it with LCLS specific bits */
71type component lcls_test_CT extends test_CT {
72 /* Component references */
73 var LCLS_MSC_ConnHdlr vc_CONN_A;
74 var LCLS_MSC_ConnHdlr vc_CONN_B;
75 /* Ports to the two call legs */
76 port LCLS_InterComp_PT CONN_A;
77 port LCLS_InterComp_PT CONN_B;
78}
79
80/* take MSC_ConnHdlr and extend it with LCLS specific bits */
81type component LCLS_MSC_ConnHdlr extends MSC_ConnHdlr {
82 /* Port back to the controlling lcls_test_CT */
83 port LCLS_InterComp_PT MASTER;
84}
85
86/* port type between lcls_test_CT and LCLS_MSC_ConnHdlr */
87type port LCLS_InterComp_PT message {
88 /* BSSAP from BSSA_ConnHdlr */
Harald Welte6811d102019-04-14 22:23:14 +020089 inout PDU_BSSAP, RAN_Conn_Prim, PDU_DTAP_MO, PDU_DTAP_MT,
Harald Weltecc0b0142018-05-29 15:19:33 +020090 /* RSL from RSL_DchanHdlr */
91 RSLDC_ChanRqd, RSL_Message,
92 /* MGCP from MGCP_ConnHdlr */
93 MgcpCommand, MgcpResponse,
94 LclsCompSync;
95} with { extension "internal" };
96
97type enumerated LclsCompSync {
98 /* ConnHdlr signals to master component that assignment has completed */
99 LCLS_COMP_SYNC_ASS_COMPL
100}
101
102
103/* forward messages between the RSL/MGCP/BSSAP Emulation and the master component */
104private altstep as_lcls_conn_hdlr_proxy() runs on LCLS_MSC_ConnHdlr {
105 var PDU_BSSAP bssap;
Harald Welte6811d102019-04-14 22:23:14 +0200106 var RAN_Conn_Prim bssap_p;
Harald Weltecc0b0142018-05-29 15:19:33 +0200107 var PDU_DTAP_MO dtap_mo;
108 var PDU_DTAP_MT dtap_mt;
109 var MgcpCommand mgcp_cmd;
110 var MgcpResponse mgcp_rsp;
111 var RSL_Message rsl_msg;
112 /* from ConnHdlr to master process */
113 [] BSSAP.receive(PDU_BSSAP:?) -> value bssap { MASTER.send(bssap); }
Harald Welte6811d102019-04-14 22:23:14 +0200114 [] BSSAP.receive(RAN_Conn_Prim:?) -> value bssap_p { MASTER.send(bssap_p); }
Harald Weltecc0b0142018-05-29 15:19:33 +0200115 [] BSSAP.receive(PDU_DTAP_MO:?) -> value dtap_mo { MASTER.send(dtap_mo); }
116 [] BSSAP.receive(PDU_DTAP_MT:?) -> value dtap_mt { MASTER.send(dtap_mt); }
117 [] MGCP.receive(MgcpCommand:?) -> value mgcp_cmd { MASTER.send(mgcp_cmd); }
118 [] MGCP.receive(MgcpResponse:?) -> value mgcp_rsp { MASTER.send(mgcp_rsp); }
119 [] RSL.receive(RSL_Message:?) -> value rsl_msg { MASTER.send(rsl_msg); }
120 /* from master process to ConnHdlr */
121 [] MASTER.receive(PDU_BSSAP:?) -> value bssap { BSSAP.send(bssap); }
Harald Welte6811d102019-04-14 22:23:14 +0200122 [] MASTER.receive(RAN_Conn_Prim:?) -> value bssap_p { BSSAP.send(bssap_p); }
Harald Weltecc0b0142018-05-29 15:19:33 +0200123 [] MASTER.receive(PDU_DTAP_MO:?) -> value dtap_mo { BSSAP.send(dtap_mo); }
124 [] MASTER.receive(PDU_DTAP_MT:?) -> value dtap_mt { BSSAP.send(dtap_mt); }
125 [] MASTER.receive(MgcpCommand:?) -> value mgcp_cmd { MGCP.send(mgcp_cmd); }
126 [] MASTER.receive(MgcpResponse:?) -> value mgcp_rsp { MGCP.send(mgcp_rsp); }
127 [] MASTER.receive(RSL_Message:?) -> value rsl_msg { RSL.send(rsl_msg); }
128}
129
130
131private function f_lcls_connhdlr_main(charstring id) runs on LCLS_MSC_ConnHdlr {
132 /* 1) establish the connection between RSL and BSSAP side */
133 var PDU_BSSAP ass_req := f_gen_ass_req();
Philipp Maier61f6b572018-07-06 14:03:38 +0200134
Harald Weltecc0b0142018-05-29 15:19:33 +0200135 var template PDU_BSSAP ass_compl := f_gen_exp_compl();
136 ass_req.pdu.bssmap.assignmentRequest.codecList := g_pars.ass_codec_list;
Philipp Maier61f6b572018-07-06 14:03:38 +0200137 ass_req.pdu.bssmap.assignmentRequest.channelType :=
138 f_BSSMAP_chtype_from_codec(g_pars.ass_codec_list.codecElements[0]);
139
Harald Weltecc0b0142018-05-29 15:19:33 +0200140 f_establish_fully(ass_req, ass_compl);
141
142 /* 2) notify master that assignment has completed */
143 MASTER.send(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
144
145 /* 3) proxy packets between master component and various ports */
146 while (true) {
147 as_lcls_conn_hdlr_proxy();
148 }
149}
150
151type function lcls_void_fn(charstring id) runs on LCLS_MSC_ConnHdlr;
152
153/* first function inside ConnHdlr component; sets g_pars + starts function */
154private function f_handler_init(lcls_void_fn fn, charstring id, template (omit) TestHdlrParams pars := omit)
155runs on LCLS_MSC_ConnHdlr {
156 if (isvalue(pars)) {
157 g_pars := valueof(pars);
158 }
159 fn.apply(id);
160}
161
Harald Welteff579f92018-05-31 22:19:39 +0200162/* helper function to create and connect a MSC_ConnHdlr component */
Vadim Yanitskiye5d393c2022-05-29 16:55:42 +0600163/* FIXME: Why can't we use BSC_Tests.f_connect_andler() ?!?
164 * TODO: allow connecting to TRX1..N, not only TRX0 */
Neels Hofmeyrf246a922020-05-13 02:27:10 +0200165private function f_connect_handler(inout LCLS_MSC_ConnHdlr vc_conn, integer bssap_idx := 0) runs on lcls_test_CT {
166 connect(vc_conn:RAN, g_bssap[bssap_idx].vc_RAN:PROC);
Harald Welteff579f92018-05-31 22:19:39 +0200167 connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC);
Vadim Yanitskiye5d393c2022-05-29 16:55:42 +0600168 connect(vc_conn:RSL, bts[0][0].rsl.vc_RSL:CLIENT_PT);
169 connect(vc_conn:RSL_PROC, bts[0][0].rsl.vc_RSL:RSL_PROC);
170 if (isvalue(bts[1][0])) {
171 connect(vc_conn:RSL1, bts[1][0].rsl.vc_RSL:CLIENT_PT);
172 connect(vc_conn:RSL1_PROC, bts[1][0].rsl.vc_RSL:RSL_PROC);
Harald Welteff579f92018-05-31 22:19:39 +0200173 }
Neels Hofmeyrf246a922020-05-13 02:27:10 +0200174 connect(vc_conn:BSSAP, g_bssap[bssap_idx].vc_RAN:CLIENT);
Harald Welteff579f92018-05-31 22:19:39 +0200175 connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT);
176}
177
Harald Weltecc0b0142018-05-29 15:19:33 +0200178/* function creating the two ConnHdlrs, connecting them + starting them */
179private function f_lcls_test_init(TestHdlrParams pars_a, TestHdlrParams pars_b) runs on lcls_test_CT {
180 var charstring id_a := testcasename() & "-A";
181 var charstring id_b := testcasename() & "-B";
182
183 pars_b.imsi := '002029876543210'H;
184 pars_b.media_nr := 2;
185
186 /* create and connect the two ConnHandlers */
187 vc_CONN_A := LCLS_MSC_ConnHdlr.create(id_a);
188 f_connect_handler(vc_CONN_A);
189 connect(vc_CONN_A:MASTER, self:CONN_A);
190
191 vc_CONN_B := LCLS_MSC_ConnHdlr.create(id_b);
192 f_connect_handler(vc_CONN_B);
193 connect(vc_CONN_B:MASTER, self:CONN_B);
194
195 /* start the two components */
196 vc_CONN_A.start(f_handler_init(refers(f_lcls_connhdlr_main), id_a, pars_a));
197 f_sleep(3.0);
198 vc_CONN_B.start(f_handler_init(refers(f_lcls_connhdlr_main), id_b, pars_b));
199}
200
201private function f_lcls_test_fini() runs on lcls_test_CT {
202 vc_CONN_A.stop;
203 vc_CONN_B.stop;
204}
205
206/* ignore some messages which we're not interested in evaluating (yet) */
207private altstep as_ignore() runs on lcls_test_CT {
208 [] CONN_A.receive(tr_DLCX) { repeat; }
209 [] CONN_B.receive(tr_DLCX) { repeat; }
210}
211
212/* fail if any notify is being received */
213private altstep as_fail_on_lcls_notify() runs on lcls_test_CT
214{
215 [] CONN_A.receive(tr_BSSMAP_LclsNotification(?, *)) {
216 setverdict(fail, "Unexpected BSSMAP LCLS Notification");
217 }
218 [] CONN_B.receive(tr_BSSMAP_LclsNotification(?, *)) {
219 setverdict(fail, "Unexpected BSSMAP LCLS Notification");
220 }
221}
222
223private function f_wait_fail_notify() runs on lcls_test_CT
224{
225 timer T := 3.0;
226 T.start;
227 alt {
228 [] as_fail_on_lcls_notify();
229 [] T.timeout { }
230 }
231}
232
Max2253c0b2018-11-06 19:28:05 +0100233private function f_lcls_init(boolean bts_mode := false, integer nr_bts := 1) runs on lcls_test_CT
Harald Weltecc0b0142018-05-29 15:19:33 +0200234{
235 var default d;
236
237 d := activate(as_ignore());
238 f_init(nr_bts, true);
239 f_sleep(1.0);
Max2253c0b2018-11-06 19:28:05 +0100240
241 f_init_vty();
242 if (bts_mode == true) {
243 f_vty_config(BSCVTY, "msc", "lcls-mode bts-loop");
244 } else {
245 f_vty_config(BSCVTY, "msc", "lcls-mode mgw-loop");
246 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200247}
248
249
250/* Send an ASSIGNMENT REQ with LCLS GCR only, without LCLS CFG or CSC */
251testcase TC_lcls_gcr_only() runs on lcls_test_CT {
252 var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
253 var MSC_ConnHdlr vc_conn;
254
255 f_lcls_init();
256
257 pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
258 pars.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
259 /* Expect LCLS status to be not reported, as no LCLS config was signalled */
260 pars.lcls.exp_sts := omit;
261
262 f_lcls_test_init(pars, pars);
263 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
264 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
265 f_wait_fail_notify();
266 f_lcls_test_fini();
267}
268
Maxb1599b12018-10-31 19:38:38 +0100269private function f_tc_lcls_recv_ls_exp_mgcp() runs on lcls_test_CT {
270 var MgcpCommand mgcp_cmd;
271
272 interleave {
273 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
274 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_locally_switched));
275 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
276 [] CONN_A.receive(tr_MDCX) -> value mgcp_cmd {
277 CONN_A.send(f_build_mdcx_rsp(mgcp_cmd));
278 }
279 /* not needed, as this MDCX is still handled within MSC_ConnectionHandler
280 [] CONN_B.receive(tr_MDCX) -> value mgcp_cmd {
281 CONN_B.send(f_build_mdcx_rsp(mgcp_cmd));
282 }
283 */
284 }
285}
286
Max2253c0b2018-11-06 19:28:05 +0100287private function f_tc_lcls_ack_rsl_mdcx(RSL_Message rsl_msg, boolean send_on_a) runs on lcls_test_CT {
288 var boolean fixme_unused;
289 var RSL_IE_Body ie;
290 var RslChannelNr chan_nr;
291 var uint16_t conn_id;
292 var uint7_t rtp_pt := 0;
293 var HostName host;
294 var PortNumber port_num;
295
296 if (f_rsl_find_ie(rsl_msg, RSL_IE_CHAN_NR, ie) == true) {
297 chan_nr := ie.chan_nr;
298 } else {
299 log("Unable to find chan# in ", rsl_msg);
300 }
301
302 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_CONN_ID, ie);
303 conn_id := ie.ipa_conn_id;
304
305 /* mandatory fields */
306 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_REMOTE_IP, ie);
Vadim Yanitskiyfc631642021-07-03 02:42:45 +0200307 host := f_inet_ntoa(ie.ipa_remote_ip);
Max2253c0b2018-11-06 19:28:05 +0100308
309 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_REMOTE_PORT, ie);
310 port_num := ie.ipa_remote_port;
311 log("LCLS IPA MDCX for lchan ", chan_nr, " connection ID ", conn_id, " host ", host, ":", port_num);
312
313 /* optional */
314 if (f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_RTP_PAYLOAD, ie)) {
315 rtp_pt := ie.ipa_rtp_pt;
316 }
317
318 if (send_on_a == true) {
Vadim Yanitskiyfc631642021-07-03 02:42:45 +0200319 CONN_A.send(ts_RSL_IPA_MDCX_ACK(chan_nr, conn_id, f_inet_addr(host), port_num, rtp_pt));
Max2253c0b2018-11-06 19:28:05 +0100320 } else {
Vadim Yanitskiyfc631642021-07-03 02:42:45 +0200321 CONN_B.send(ts_RSL_IPA_MDCX_ACK(chan_nr, conn_id, f_inet_addr(host), port_num, rtp_pt));
Max2253c0b2018-11-06 19:28:05 +0100322 }
323}
324
325private function f_tc_lcls_recv_ls_exp_rsl() runs on lcls_test_CT {
326 var RSL_Message rsl_msg;
327 interleave {
328 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls)) {}
329 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_locally_switched)) {}
330 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL) {}
331 [] CONN_A.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
332 f_tc_lcls_ack_rsl_mdcx(rsl_msg, true)
333 }
334 }
335}
336
337private function f_tc_lcls_gcr_bway_connect(boolean hr, boolean bts_mode := false) runs on lcls_test_CT {
Harald Weltecc0b0142018-05-29 15:19:33 +0200338 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
339 var TestHdlrParams pars_b;
340 var MSC_ConnHdlr vc_conn;
Harald Weltecc0b0142018-05-29 15:19:33 +0200341
Max2253c0b2018-11-06 19:28:05 +0100342 f_lcls_init(bts_mode);
Harald Weltecc0b0142018-05-29 15:19:33 +0200343
Philipp Maier61f6b572018-07-06 14:03:38 +0200344 if (hr == true) {
345 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR}));
346 } else {
347 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
348 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200349 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
350 pars_a.lcls.cfg := LCLS_CFG_both_way;
351 pars_a.lcls.csc := LCLS_CSC_connect;
Max2253c0b2018-11-06 19:28:05 +0100352 pars_a.lcls.adjust_cx_exp := not bts_mode;
Harald Weltecc0b0142018-05-29 15:19:33 +0200353 pars_b := pars_a;
354
355 /* first call is not possible to be LS (no second leg yet) */
356 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
357 /* second call should then reuslt in LS */
358 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
359
360 f_lcls_test_init(pars_a, pars_b);
Philipp Maier61f6b572018-07-06 14:03:38 +0200361
Harald Weltecc0b0142018-05-29 15:19:33 +0200362 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100363
Max2253c0b2018-11-06 19:28:05 +0100364 if (bts_mode == true) {
365 f_tc_lcls_recv_ls_exp_rsl();
366 } else {
367 f_tc_lcls_recv_ls_exp_mgcp();
368 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200369
370 f_lcls_test_fini();
371}
372
Philipp Maier61f6b572018-07-06 14:03:38 +0200373/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (full rate)*/
374testcase TC_lcls_gcr_bway_connect() runs on lcls_test_CT {
375 f_tc_lcls_gcr_bway_connect(false)
376}
377
378/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (half rate) */
379testcase TC_lcls_gcr_bway_connect_hr() runs on lcls_test_CT {
Max2253c0b2018-11-06 19:28:05 +0100380 f_tc_lcls_gcr_bway_connect(true)
381}
382
383/* BTS-loop: send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (full rate)*/
384testcase TC_lcls_bts_gcr_bway_connect() runs on lcls_test_CT {
385 f_tc_lcls_gcr_bway_connect(false, true)
386}
387
388/* BTS-loop: send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (half rate) */
389testcase TC_lcls_bts_gcr_bway_connect_hr() runs on lcls_test_CT {
390 f_tc_lcls_gcr_bway_connect(true, true)
Philipp Maier61f6b572018-07-06 14:03:38 +0200391}
392
Philipp Maier55f27f52018-07-10 09:15:09 +0200393/* Unless explicitly enabled, osmo-bsc will avoid LCLSs when the codecs or rates
394 * of both legs are different */
395testcase TC_lcls_gcr_bway_codec_mismatch() runs on lcls_test_CT {
396 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
397 var TestHdlrParams pars_b;
398 var MSC_ConnHdlr vc_conn;
399 var MgcpCommand mgcp_cmd;
400
401 f_lcls_init();
402
403 /* First call leg uses full rate */
404 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
405 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
406 pars_a.lcls.cfg := LCLS_CFG_both_way;
407 pars_a.lcls.csc := LCLS_CSC_connect;
408
409 /* The second call leg uses half-rate */
410 pars_b := pars_a;
411 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR}));
412
413 /* first call is not possible to be LS (no second leg yet) */
414 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
415
416 /* second call is also not possible to be LS (codec/rate does not match) */
417 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
418 f_lcls_test_init(pars_a, pars_b);
419
420 interleave {
421 [] CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
422 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
423 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
424 }
425
426 f_lcls_test_fini();
427}
428
Harald Weltecc0b0142018-05-29 15:19:33 +0200429/* Send an ASSIGNMENT REQ with LCLS CFG+CSC enabling LCLS but GCR doesn't match! */
430testcase TC_lcls_gcr_nomatch_bway_connect() runs on lcls_test_CT {
431 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
432 var TestHdlrParams pars_b;
433 var MSC_ConnHdlr vc_conn;
434 var MgcpCommand mgcp_cmd;
435
436 f_lcls_init();
437
438 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
439 pars_a.lcls.cfg := LCLS_CFG_both_way;
440 pars_a.lcls.csc := LCLS_CSC_connect;
441 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
442
443 pars_b := pars_a;
444
445 /* first call is not possible to be LS (no second leg yet) */
446 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
447 pars_b.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090b'O));
448
449 f_lcls_test_init(pars_a, pars_b);
450 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
451 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
452 f_wait_fail_notify();
453 f_lcls_test_fini();
454}
455
Maxb1599b12018-10-31 19:38:38 +0100456/* check for the cases where LCLS is not possible due to some reason */
457private function f_lcls_not_yet_ls() runs on lcls_test_CT {
458 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
459 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
460 CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
461}
Harald Weltecc0b0142018-05-29 15:19:33 +0200462
463/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
464testcase TC_lcls_gcr_bway_dont_connect() runs on lcls_test_CT {
465 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
466 var TestHdlrParams pars_b;
467 var MSC_ConnHdlr vc_conn;
468
469 f_lcls_init();
470
471 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
472 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
473 pars_a.lcls.cfg := LCLS_CFG_both_way;
474 pars_a.lcls.csc := LCLS_CSC_do_not_connect;
475 pars_b := pars_a;
476
477 /* first call is not possible to be LS (no second leg yet) */
478 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
479 /* Expect LCLS is *NOT* established */
480 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
481
482 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100483 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200484 f_wait_fail_notify();
485 f_lcls_test_fini();
486}
487
488/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
489testcase TC_lcls_gcr_unsuppported_cfg() runs on lcls_test_CT {
490 var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
491 var MSC_ConnHdlr vc_conn;
492
493 f_lcls_init();
494
495 pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
496 pars.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
497 pars.lcls.cfg := LCLS_CFG_both_way_and_send_DL;
498 pars.lcls.csc := LCLS_CSC_connect;
499 /* Expect LCLS is *NOT* established with "LCLS_STS_req_lcls_not_supp" */
500 pars.lcls.exp_sts := LCLS_STS_req_lcls_not_supp;
501
502 f_lcls_test_init(pars, pars);
503 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
504 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
505 f_wait_fail_notify();
506 f_lcls_test_fini();
507}
508
509/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
510testcase TC_lcls_gcr_unsuppported_csc() runs on lcls_test_CT {
511 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
512 var TestHdlrParams pars_b;
513 var MSC_ConnHdlr vc_conn;
514
515 f_lcls_init();
516
517 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
518 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
519 pars_a.lcls.cfg := LCLS_CFG_both_way;
520 pars_a.lcls.csc := LCLS_CSC_bicast_UL_and_recv_DL_at_handover;
521 pars_b := pars_a;
522
523 /* first call is not possible to be LS (no second leg yet) */
524 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
525 /* Expect LCLS is *NOT* established */
526 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
527
528 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100529 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200530 f_lcls_test_fini();
531}
532
Maxb1599b12018-10-31 19:38:38 +0100533/* Expect given LCLS status alongside with corresponding MDCX commands */
534private function f_lcls_sts_mgcp(BIT4 expected_status) runs on lcls_test_CT {
535 var MgcpCommand mgcp_cmd;
536
537 interleave {
538 [] CONN_B.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(expected_status)));
539 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(expected_status));
540 [] CONN_A.receive(tr_MDCX) -> value mgcp_cmd {
541 CONN_A.send(f_build_mdcx_rsp(mgcp_cmd));
542 }
543 [] CONN_B.receive(tr_MDCX) -> value mgcp_cmd {
544 CONN_B.send(f_build_mdcx_rsp(mgcp_cmd));
545 }
546 }
547}
548
Max2253c0b2018-11-06 19:28:05 +0100549private function f_lcls_sts_rsl(BIT4 expected_status) runs on lcls_test_CT {
550 var RSL_Message rsl_msg;
551
552 interleave {
553 [] CONN_B.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(expected_status)));
554 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(expected_status));
555 /*
556 [] CONN_A.receive(RSL_Message:?) -> value rsl_msg {
557 log("f_lcls_sts_rsl CONN_A top RSL is ", rsl_msg)
558 }
559 Ex. placeholder to catch any RSL message */
560 [] CONN_A.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
561 f_tc_lcls_ack_rsl_mdcx(rsl_msg, true)
562 }
563 [] CONN_B.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
564 f_tc_lcls_ack_rsl_mdcx(rsl_msg, false)
565 }
566 }
567}
568
Harald Weltecc0b0142018-05-29 15:19:33 +0200569/* Send an ASSIGNMENT REQ with "do not connect" and enable later using LCLS CTRL */
570testcase TC_lcls_gcr_bway_dont_connect_csc() runs on lcls_test_CT {
571 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
572 var TestHdlrParams pars_b;
573 var MSC_ConnHdlr vc_conn;
574 var MgcpCommand mgcp_cmd;
575
576 f_lcls_init();
577
578 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
579 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
580 pars_a.lcls.cfg := LCLS_CFG_both_way;
581 pars_a.lcls.csc := LCLS_CSC_do_not_connect;
582 pars_b := pars_a;
583
584 /* first call is not possible to be LS (no second leg yet) */
585 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
586 /* Expect LCLS is *NOT* established */
587 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
588
589 /* start call and expect it to be "not yet" LS */
590 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100591 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200592 f_sleep(2.0);
593
594 /* send "connect" on A side, expect call to remain in "not yet" */
595 CONN_A.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_connect)));
596 CONN_A.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(LCLS_STS_not_yet_ls)));
597 f_sleep(2.0);
598
599 /* send "connect" on B side, expect call to go LS, with notify to A side */
600 CONN_B.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_connect)));
Maxb1599b12018-10-31 19:38:38 +0100601 f_lcls_sts_mgcp(LCLS_STS_locally_switched);
Harald Weltecc0b0142018-05-29 15:19:33 +0200602 f_wait_fail_notify();
603 f_lcls_test_fini();
604}
605
606private function f_build_mdcx_rsp(MgcpCommand mdcx) return MgcpResponse
607{
608 var MgcpConnectionId conn_id := f_MgcpCmd_extract_conn_id(mdcx);
609 var SDP_Message sdp_in := mdcx.sdp;
610 var MgcpResponse resp;
611 var SDP_Message sdp_out;
612 var integer rtp_pt := str2int(sdp_in.media_list[0].media_field.fmts[0]);
613
614 sdp_out := valueof(ts_SDP(sdp_in.connection.conn_addr.addr, sdp_in.connection.conn_addr.addr,
615 "foo", "21", sdp_in.media_list[0].media_field.ports.port_number,
616 { int2str(rtp_pt) },
617 { valueof(ts_SDP_rtpmap(rtp_pt, "AMR/8000")),
618 valueof(ts_SDP_ptime(20)) } ));
619 return valueof(ts_MDCX_ACK(mdcx.line.trans_id, conn_id, sdp_out));
620}
621
Max2253c0b2018-11-06 19:28:05 +0100622private function f_lcls_connect_break(boolean bts_mode := false) runs on lcls_test_CT {
Harald Weltecc0b0142018-05-29 15:19:33 +0200623 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
624 var TestHdlrParams pars_b;
625 var MSC_ConnHdlr vc_conn;
Harald Weltecc0b0142018-05-29 15:19:33 +0200626
Max2253c0b2018-11-06 19:28:05 +0100627 f_lcls_init(bts_mode);
Harald Weltecc0b0142018-05-29 15:19:33 +0200628
629 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
630 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
631 pars_a.lcls.cfg := LCLS_CFG_both_way;
632 pars_a.lcls.csc := LCLS_CSC_connect;
Max2253c0b2018-11-06 19:28:05 +0100633 pars_a.lcls.adjust_cx_exp := not bts_mode;
Harald Weltecc0b0142018-05-29 15:19:33 +0200634 pars_b := pars_a;
635
636 /* first call is not possible to be LS (no second leg yet) */
637 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
Maxd4e56962018-10-31 19:08:25 +0100638 /* second call should then result in LS */
Harald Weltecc0b0142018-05-29 15:19:33 +0200639 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
640
641 /* Expect LS to be established successfully */
642 f_lcls_test_init(pars_a, pars_b);
643 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100644
Max2253c0b2018-11-06 19:28:05 +0100645 if (bts_mode == true) {
646 f_tc_lcls_recv_ls_exp_rsl();
647 } else {
648 f_tc_lcls_recv_ls_exp_mgcp();
649 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200650
651 /* request LS release on "A" side; call continues to be locally switched */
652 CONN_A.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_release_lcls)));
653 CONN_A.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(LCLS_STS_locally_switched)));
654 f_sleep(2.0);
655
656 /* request LS release on "B" side; call LS is released */
657 CONN_B.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_release_lcls)));
Maxb1599b12018-10-31 19:38:38 +0100658
Max2253c0b2018-11-06 19:28:05 +0100659 if (bts_mode == true) {
660 f_lcls_sts_rsl(LCLS_STS_no_longer_ls);
661 } else {
662 f_lcls_sts_mgcp(LCLS_STS_no_longer_ls);
663 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200664
665 f_lcls_test_fini();
666}
667
Max2253c0b2018-11-06 19:28:05 +0100668/* Establish LCLS "connect" followed by a MSC-initiated break */
669testcase TC_lcls_connect_break() runs on lcls_test_CT {
670 f_lcls_connect_break()
671}
672
673testcase TC_lcls_bts_connect_break() runs on lcls_test_CT {
674 f_lcls_connect_break(true)
675}
676
Harald Weltecc0b0142018-05-29 15:19:33 +0200677/* Establish LCLS "connect" followed by a SCCP-level release of one leg */
678testcase TC_lcls_connect_clear() runs on lcls_test_CT {
679 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
680 var TestHdlrParams pars_b;
681 var MSC_ConnHdlr vc_conn;
682 var MgcpCommand mgcp_cmd;
683 var RSL_Message rsl;
684
685 f_lcls_init();
686
687 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
688 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
689 pars_a.lcls.cfg := LCLS_CFG_both_way;
690 pars_a.lcls.csc := LCLS_CSC_connect;
691 pars_b := pars_a;
692
693 /* first call is not possible to be LS (no second leg yet) */
694 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
695 /* second call should then reuslt in LS */
696 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
697
698 /* Expect LS to be established successfully */
699 f_lcls_test_init(pars_a, pars_b);
700 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100701
702 f_tc_lcls_recv_ls_exp_mgcp();
Harald Weltecc0b0142018-05-29 15:19:33 +0200703
704 /* Perform hard BSSMAP Clear on "A" side, expect no LS on "B" side */
705 var myBSSMAP_Cause cause_val := GSM0808_CAUSE_CALL_CONTROL;
Harald Weltecc0b0142018-05-29 15:19:33 +0200706 CONN_A.send(ts_BSSMAP_ClearCommand(enum2int(cause_val)));
707 interleave {
Harald Welte924b6ea2019-02-04 01:05:34 +0100708 [] CONN_A.receive(tr_RSL_DATA_REQ(?, tr_RslLinkID_DCCH(0), decmatch tr_RRM_RR_RELEASE));
Harald Weltecc0b0142018-05-29 15:19:33 +0200709 [] CONN_A.receive(tr_RSL_DEACT_SACCH(?));
710 [] CONN_A.receive(tr_RSL_RF_CHAN_REL(?)) -> value rsl {
711 var RSL_IE_Body ieb;
Maxfc337ca2018-10-31 19:42:08 +0100712 if (f_rsl_find_ie(rsl, RSL_IE_CHAN_NR, ieb) == true) {
713 CONN_A.send(ts_RSL_RF_CHAN_REL_ACK(ieb.chan_nr));
714 } else {
715 log("Unable to find chan# in RSL_RF_CHAN_REL")
716 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200717 }
Harald Welte935fbe32018-06-11 15:20:39 +0200718 [] CONN_A.receive(tr_BSSMAP_ClearComplete) {
Harald Welte6811d102019-04-14 22:23:14 +0200719 CONN_A.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
Harald Welte935fbe32018-06-11 15:20:39 +0200720 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200721 [] CONN_B.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_possible_ls));
722 }
723 f_sleep(2.0);
724
725 f_lcls_test_fini();
726}
727
728
729
730
731/* TODO:
732 * verify IP/Port information in LCLS-triggered MDCX
733 * establish with one side connect, then enable using LCLS CTRL
734 * LCLS CTRL for call that doesn't have LCLS enabled
735 * LCLS IEs without GCR in ASS CMD
736 * GCR updates?
737 * Handover related LCLS bits (after we have inter-BSC HO in OsmoBSC)
738*/
739
740
741control {
742
743 execute( TC_lcls_gcr_only() );
744 execute( TC_lcls_gcr_bway_connect() );
Philipp Maier61f6b572018-07-06 14:03:38 +0200745 execute( TC_lcls_gcr_bway_connect_hr() );
Philipp Maier55f27f52018-07-10 09:15:09 +0200746 execute( TC_lcls_gcr_bway_codec_mismatch() );
Harald Weltecc0b0142018-05-29 15:19:33 +0200747 execute( TC_lcls_gcr_nomatch_bway_connect() );
748 execute( TC_lcls_gcr_bway_dont_connect() );
749 execute( TC_lcls_gcr_unsuppported_cfg() );
750 execute( TC_lcls_gcr_unsuppported_csc() );
751 execute( TC_lcls_gcr_bway_dont_connect_csc() );
752 execute( TC_lcls_connect_break() );
753 execute( TC_lcls_connect_clear() );
754
Max2253c0b2018-11-06 19:28:05 +0100755 execute( TC_lcls_bts_gcr_bway_connect() );
756 execute( TC_lcls_bts_gcr_bway_connect_hr() );
757 execute( TC_lcls_bts_connect_break() );
Harald Weltecc0b0142018-05-29 15:19:33 +0200758}
759
760
761}