blob: 2b9886b8a614256f2836e2204b3eeae7f1e9cc81 [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;
Pau Espin Pedrol1158cc62024-03-21 17:21:35 +010041import from SDP_Templates all;
Max2253c0b2018-11-06 19:28:05 +010042import from Native_Functions all;
Harald Weltecc0b0142018-05-29 15:19:33 +020043
44import from Osmocom_CTRL_Functions all;
45import from Osmocom_CTRL_Types all;
46import from Osmocom_CTRL_Adapter all;
47
48import from Osmocom_VTY_Functions all;
49import from TELNETasp_PortType all;
50
51import from MobileL3_CommonIE_Types all;
52import from MobileL3_Types all;
53import from L3_Templates all;
54import from GSM_RR_Types all;
55
56import from BSSMAP_Templates all;
Harald Welte6811d102019-04-14 22:23:14 +020057import from RAN_Emulation all;
Harald Weltecc0b0142018-05-29 15:19:33 +020058
59import from MSC_ConnectionHandler all;
60import from BSC_Tests all;
61
62/* The philosophy of this testsuite is to re-use as much as possible the existing components
63 * and functions that we have in BSC_Tests and its dependencies. However, as opposed to those
64 * normal BSC tests, we here have to run *two* ConnHdlr and synchronize activity between them.
65 *
66 * We do this by adding some special-purpose ports between the main test component running the
67 * test case [lcls_]test_CT and the per-connection [LCLS_]MSC_ConnHdlr.
68 */
69
70
71/* take test_CT from BSC_Tests and extend it with LCLS specific bits */
72type component lcls_test_CT extends test_CT {
73 /* Component references */
74 var LCLS_MSC_ConnHdlr vc_CONN_A;
75 var LCLS_MSC_ConnHdlr vc_CONN_B;
76 /* Ports to the two call legs */
77 port LCLS_InterComp_PT CONN_A;
78 port LCLS_InterComp_PT CONN_B;
79}
80
81/* take MSC_ConnHdlr and extend it with LCLS specific bits */
82type component LCLS_MSC_ConnHdlr extends MSC_ConnHdlr {
83 /* Port back to the controlling lcls_test_CT */
84 port LCLS_InterComp_PT MASTER;
85}
86
87/* port type between lcls_test_CT and LCLS_MSC_ConnHdlr */
88type port LCLS_InterComp_PT message {
89 /* BSSAP from BSSA_ConnHdlr */
Harald Welte6811d102019-04-14 22:23:14 +020090 inout PDU_BSSAP, RAN_Conn_Prim, PDU_DTAP_MO, PDU_DTAP_MT,
Harald Weltecc0b0142018-05-29 15:19:33 +020091 /* RSL from RSL_DchanHdlr */
92 RSLDC_ChanRqd, RSL_Message,
93 /* MGCP from MGCP_ConnHdlr */
94 MgcpCommand, MgcpResponse,
95 LclsCompSync;
96} with { extension "internal" };
97
98type enumerated LclsCompSync {
99 /* ConnHdlr signals to master component that assignment has completed */
100 LCLS_COMP_SYNC_ASS_COMPL
101}
102
103
104/* forward messages between the RSL/MGCP/BSSAP Emulation and the master component */
105private altstep as_lcls_conn_hdlr_proxy() runs on LCLS_MSC_ConnHdlr {
106 var PDU_BSSAP bssap;
Harald Welte6811d102019-04-14 22:23:14 +0200107 var RAN_Conn_Prim bssap_p;
Harald Weltecc0b0142018-05-29 15:19:33 +0200108 var PDU_DTAP_MO dtap_mo;
109 var PDU_DTAP_MT dtap_mt;
110 var MgcpCommand mgcp_cmd;
111 var MgcpResponse mgcp_rsp;
112 var RSL_Message rsl_msg;
113 /* from ConnHdlr to master process */
114 [] BSSAP.receive(PDU_BSSAP:?) -> value bssap { MASTER.send(bssap); }
Harald Welte6811d102019-04-14 22:23:14 +0200115 [] BSSAP.receive(RAN_Conn_Prim:?) -> value bssap_p { MASTER.send(bssap_p); }
Harald Weltecc0b0142018-05-29 15:19:33 +0200116 [] BSSAP.receive(PDU_DTAP_MO:?) -> value dtap_mo { MASTER.send(dtap_mo); }
117 [] BSSAP.receive(PDU_DTAP_MT:?) -> value dtap_mt { MASTER.send(dtap_mt); }
118 [] MGCP.receive(MgcpCommand:?) -> value mgcp_cmd { MASTER.send(mgcp_cmd); }
119 [] MGCP.receive(MgcpResponse:?) -> value mgcp_rsp { MASTER.send(mgcp_rsp); }
120 [] RSL.receive(RSL_Message:?) -> value rsl_msg { MASTER.send(rsl_msg); }
121 /* from master process to ConnHdlr */
122 [] MASTER.receive(PDU_BSSAP:?) -> value bssap { BSSAP.send(bssap); }
Harald Welte6811d102019-04-14 22:23:14 +0200123 [] MASTER.receive(RAN_Conn_Prim:?) -> value bssap_p { BSSAP.send(bssap_p); }
Harald Weltecc0b0142018-05-29 15:19:33 +0200124 [] MASTER.receive(PDU_DTAP_MO:?) -> value dtap_mo { BSSAP.send(dtap_mo); }
125 [] MASTER.receive(PDU_DTAP_MT:?) -> value dtap_mt { BSSAP.send(dtap_mt); }
126 [] MASTER.receive(MgcpCommand:?) -> value mgcp_cmd { MGCP.send(mgcp_cmd); }
127 [] MASTER.receive(MgcpResponse:?) -> value mgcp_rsp { MGCP.send(mgcp_rsp); }
128 [] MASTER.receive(RSL_Message:?) -> value rsl_msg { RSL.send(rsl_msg); }
129}
130
131
132private function f_lcls_connhdlr_main(charstring id) runs on LCLS_MSC_ConnHdlr {
133 /* 1) establish the connection between RSL and BSSAP side */
134 var PDU_BSSAP ass_req := f_gen_ass_req();
Philipp Maier61f6b572018-07-06 14:03:38 +0200135
Harald Weltecc0b0142018-05-29 15:19:33 +0200136 var template PDU_BSSAP ass_compl := f_gen_exp_compl();
137 ass_req.pdu.bssmap.assignmentRequest.codecList := g_pars.ass_codec_list;
Philipp Maier61f6b572018-07-06 14:03:38 +0200138 ass_req.pdu.bssmap.assignmentRequest.channelType :=
139 f_BSSMAP_chtype_from_codec(g_pars.ass_codec_list.codecElements[0]);
140
Harald Weltecc0b0142018-05-29 15:19:33 +0200141 f_establish_fully(ass_req, ass_compl);
142
143 /* 2) notify master that assignment has completed */
144 MASTER.send(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
145
146 /* 3) proxy packets between master component and various ports */
147 while (true) {
148 as_lcls_conn_hdlr_proxy();
149 }
150}
151
152type function lcls_void_fn(charstring id) runs on LCLS_MSC_ConnHdlr;
153
154/* first function inside ConnHdlr component; sets g_pars + starts function */
155private function f_handler_init(lcls_void_fn fn, charstring id, template (omit) TestHdlrParams pars := omit)
156runs on LCLS_MSC_ConnHdlr {
157 if (isvalue(pars)) {
158 g_pars := valueof(pars);
159 }
160 fn.apply(id);
161}
162
Harald Welteff579f92018-05-31 22:19:39 +0200163/* helper function to create and connect a MSC_ConnHdlr component */
Vadim Yanitskiye5d393c2022-05-29 16:55:42 +0600164/* FIXME: Why can't we use BSC_Tests.f_connect_andler() ?!?
165 * TODO: allow connecting to TRX1..N, not only TRX0 */
Pau Espin Pedrol3c630532022-10-20 19:00:11 +0200166private function f_connect_handler(inout LCLS_MSC_ConnHdlr vc_conn, integer bssap_idx := 0, integer mgwpool_idx := 0) runs on lcls_test_CT {
Neels Hofmeyrf246a922020-05-13 02:27:10 +0200167 connect(vc_conn:RAN, g_bssap[bssap_idx].vc_RAN: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);
Pau Espin Pedrol3c630532022-10-20 19:00:11 +0200175 connect(vc_conn:MGCP_PROC, vc_MGCP[mgwpool_idx]:MGCP_PROC);
176 connect(vc_conn:MGCP, vc_MGCP[mgwpool_idx]:MGCP_CLIENT);
Harald Welteff579f92018-05-31 22:19:39 +0200177}
178
Harald Weltecc0b0142018-05-29 15:19:33 +0200179/* function creating the two ConnHdlrs, connecting them + starting them */
180private function f_lcls_test_init(TestHdlrParams pars_a, TestHdlrParams pars_b) runs on lcls_test_CT {
181 var charstring id_a := testcasename() & "-A";
182 var charstring id_b := testcasename() & "-B";
183
184 pars_b.imsi := '002029876543210'H;
185 pars_b.media_nr := 2;
186
187 /* create and connect the two ConnHandlers */
188 vc_CONN_A := LCLS_MSC_ConnHdlr.create(id_a);
189 f_connect_handler(vc_CONN_A);
190 connect(vc_CONN_A:MASTER, self:CONN_A);
191
192 vc_CONN_B := LCLS_MSC_ConnHdlr.create(id_b);
193 f_connect_handler(vc_CONN_B);
194 connect(vc_CONN_B:MASTER, self:CONN_B);
195
196 /* start the two components */
197 vc_CONN_A.start(f_handler_init(refers(f_lcls_connhdlr_main), id_a, pars_a));
198 f_sleep(3.0);
199 vc_CONN_B.start(f_handler_init(refers(f_lcls_connhdlr_main), id_b, pars_b));
200}
201
202private function f_lcls_test_fini() runs on lcls_test_CT {
203 vc_CONN_A.stop;
204 vc_CONN_B.stop;
205}
206
207/* ignore some messages which we're not interested in evaluating (yet) */
208private altstep as_ignore() runs on lcls_test_CT {
209 [] CONN_A.receive(tr_DLCX) { repeat; }
210 [] CONN_B.receive(tr_DLCX) { repeat; }
211}
212
213/* fail if any notify is being received */
214private altstep as_fail_on_lcls_notify() runs on lcls_test_CT
215{
216 [] CONN_A.receive(tr_BSSMAP_LclsNotification(?, *)) {
217 setverdict(fail, "Unexpected BSSMAP LCLS Notification");
218 }
219 [] CONN_B.receive(tr_BSSMAP_LclsNotification(?, *)) {
220 setverdict(fail, "Unexpected BSSMAP LCLS Notification");
221 }
222}
223
224private function f_wait_fail_notify() runs on lcls_test_CT
225{
226 timer T := 3.0;
227 T.start;
228 alt {
229 [] as_fail_on_lcls_notify();
230 [] T.timeout { }
231 }
232}
233
Max2253c0b2018-11-06 19:28:05 +0100234private function f_lcls_init(boolean bts_mode := false, integer nr_bts := 1) runs on lcls_test_CT
Harald Weltecc0b0142018-05-29 15:19:33 +0200235{
236 var default d;
237
238 d := activate(as_ignore());
239 f_init(nr_bts, true);
240 f_sleep(1.0);
Max2253c0b2018-11-06 19:28:05 +0100241
242 f_init_vty();
243 if (bts_mode == true) {
244 f_vty_config(BSCVTY, "msc", "lcls-mode bts-loop");
245 } else {
246 f_vty_config(BSCVTY, "msc", "lcls-mode mgw-loop");
247 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200248}
249
250
251/* Send an ASSIGNMENT REQ with LCLS GCR only, without LCLS CFG or CSC */
252testcase TC_lcls_gcr_only() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700253 var TestHdlrParams pars := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200254 var MSC_ConnHdlr vc_conn;
255
256 f_lcls_init();
257
258 pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
259 pars.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
260 /* Expect LCLS status to be not reported, as no LCLS config was signalled */
261 pars.lcls.exp_sts := omit;
262
263 f_lcls_test_init(pars, pars);
264 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
265 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
266 f_wait_fail_notify();
267 f_lcls_test_fini();
268}
269
Maxb1599b12018-10-31 19:38:38 +0100270private function f_tc_lcls_recv_ls_exp_mgcp() runs on lcls_test_CT {
271 var MgcpCommand mgcp_cmd;
272
273 interleave {
274 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
275 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_locally_switched));
276 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
277 [] CONN_A.receive(tr_MDCX) -> value mgcp_cmd {
278 CONN_A.send(f_build_mdcx_rsp(mgcp_cmd));
279 }
280 /* not needed, as this MDCX is still handled within MSC_ConnectionHandler
281 [] CONN_B.receive(tr_MDCX) -> value mgcp_cmd {
282 CONN_B.send(f_build_mdcx_rsp(mgcp_cmd));
283 }
284 */
285 }
286}
287
Max2253c0b2018-11-06 19:28:05 +0100288private function f_tc_lcls_ack_rsl_mdcx(RSL_Message rsl_msg, boolean send_on_a) runs on lcls_test_CT {
289 var boolean fixme_unused;
290 var RSL_IE_Body ie;
291 var RslChannelNr chan_nr;
292 var uint16_t conn_id;
293 var uint7_t rtp_pt := 0;
294 var HostName host;
295 var PortNumber port_num;
296
297 if (f_rsl_find_ie(rsl_msg, RSL_IE_CHAN_NR, ie) == true) {
298 chan_nr := ie.chan_nr;
299 } else {
300 log("Unable to find chan# in ", rsl_msg);
301 }
302
303 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_CONN_ID, ie);
304 conn_id := ie.ipa_conn_id;
305
306 /* mandatory fields */
307 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_REMOTE_IP, ie);
Vadim Yanitskiyfc631642021-07-03 02:42:45 +0200308 host := f_inet_ntoa(ie.ipa_remote_ip);
Max2253c0b2018-11-06 19:28:05 +0100309
310 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_REMOTE_PORT, ie);
311 port_num := ie.ipa_remote_port;
312 log("LCLS IPA MDCX for lchan ", chan_nr, " connection ID ", conn_id, " host ", host, ":", port_num);
313
314 /* optional */
315 if (f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_RTP_PAYLOAD, ie)) {
316 rtp_pt := ie.ipa_rtp_pt;
317 }
318
319 if (send_on_a == true) {
Vadim Yanitskiyfc631642021-07-03 02:42:45 +0200320 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 +0100321 } else {
Vadim Yanitskiyfc631642021-07-03 02:42:45 +0200322 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 +0100323 }
324}
325
326private function f_tc_lcls_recv_ls_exp_rsl() runs on lcls_test_CT {
327 var RSL_Message rsl_msg;
328 interleave {
329 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls)) {}
330 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_locally_switched)) {}
331 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL) {}
332 [] CONN_A.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
333 f_tc_lcls_ack_rsl_mdcx(rsl_msg, true)
334 }
335 }
336}
337
338private function f_tc_lcls_gcr_bway_connect(boolean hr, boolean bts_mode := false) runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700339 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200340 var TestHdlrParams pars_b;
341 var MSC_ConnHdlr vc_conn;
Harald Weltecc0b0142018-05-29 15:19:33 +0200342
Max2253c0b2018-11-06 19:28:05 +0100343 f_lcls_init(bts_mode);
Harald Weltecc0b0142018-05-29 15:19:33 +0200344
Philipp Maier61f6b572018-07-06 14:03:38 +0200345 if (hr == true) {
346 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR}));
347 } else {
348 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
349 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200350 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
351 pars_a.lcls.cfg := LCLS_CFG_both_way;
352 pars_a.lcls.csc := LCLS_CSC_connect;
Max2253c0b2018-11-06 19:28:05 +0100353 pars_a.lcls.adjust_cx_exp := not bts_mode;
Harald Weltecc0b0142018-05-29 15:19:33 +0200354 pars_b := pars_a;
355
356 /* first call is not possible to be LS (no second leg yet) */
357 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
358 /* second call should then reuslt in LS */
359 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
360
361 f_lcls_test_init(pars_a, pars_b);
Philipp Maier61f6b572018-07-06 14:03:38 +0200362
Harald Weltecc0b0142018-05-29 15:19:33 +0200363 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100364
Max2253c0b2018-11-06 19:28:05 +0100365 if (bts_mode == true) {
366 f_tc_lcls_recv_ls_exp_rsl();
367 } else {
368 f_tc_lcls_recv_ls_exp_mgcp();
369 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200370
371 f_lcls_test_fini();
372}
373
Philipp Maier61f6b572018-07-06 14:03:38 +0200374/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (full rate)*/
375testcase TC_lcls_gcr_bway_connect() runs on lcls_test_CT {
376 f_tc_lcls_gcr_bway_connect(false)
377}
378
379/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (half rate) */
380testcase TC_lcls_gcr_bway_connect_hr() runs on lcls_test_CT {
Max2253c0b2018-11-06 19:28:05 +0100381 f_tc_lcls_gcr_bway_connect(true)
382}
383
384/* BTS-loop: send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (full rate)*/
385testcase TC_lcls_bts_gcr_bway_connect() runs on lcls_test_CT {
386 f_tc_lcls_gcr_bway_connect(false, true)
387}
388
389/* BTS-loop: send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (half rate) */
390testcase TC_lcls_bts_gcr_bway_connect_hr() runs on lcls_test_CT {
391 f_tc_lcls_gcr_bway_connect(true, true)
Philipp Maier61f6b572018-07-06 14:03:38 +0200392}
393
Philipp Maier55f27f52018-07-10 09:15:09 +0200394/* Unless explicitly enabled, osmo-bsc will avoid LCLSs when the codecs or rates
395 * of both legs are different */
396testcase TC_lcls_gcr_bway_codec_mismatch() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700397 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Philipp Maier55f27f52018-07-10 09:15:09 +0200398 var TestHdlrParams pars_b;
399 var MSC_ConnHdlr vc_conn;
400 var MgcpCommand mgcp_cmd;
401
402 f_lcls_init();
403
404 /* First call leg uses full rate */
405 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
406 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
407 pars_a.lcls.cfg := LCLS_CFG_both_way;
408 pars_a.lcls.csc := LCLS_CSC_connect;
409
410 /* The second call leg uses half-rate */
411 pars_b := pars_a;
412 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR}));
413
414 /* first call is not possible to be LS (no second leg yet) */
415 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
416
417 /* second call is also not possible to be LS (codec/rate does not match) */
418 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
419 f_lcls_test_init(pars_a, pars_b);
420
421 interleave {
422 [] CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
423 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
424 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
425 }
426
427 f_lcls_test_fini();
428}
429
Harald Weltecc0b0142018-05-29 15:19:33 +0200430/* Send an ASSIGNMENT REQ with LCLS CFG+CSC enabling LCLS but GCR doesn't match! */
431testcase TC_lcls_gcr_nomatch_bway_connect() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700432 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200433 var TestHdlrParams pars_b;
434 var MSC_ConnHdlr vc_conn;
435 var MgcpCommand mgcp_cmd;
436
437 f_lcls_init();
438
439 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
440 pars_a.lcls.cfg := LCLS_CFG_both_way;
441 pars_a.lcls.csc := LCLS_CSC_connect;
442 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
443
444 pars_b := pars_a;
445
446 /* first call is not possible to be LS (no second leg yet) */
447 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
448 pars_b.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090b'O));
449
450 f_lcls_test_init(pars_a, pars_b);
451 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
452 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
453 f_wait_fail_notify();
454 f_lcls_test_fini();
455}
456
Maxb1599b12018-10-31 19:38:38 +0100457/* check for the cases where LCLS is not possible due to some reason */
458private function f_lcls_not_yet_ls() runs on lcls_test_CT {
459 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
460 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
461 CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
462}
Harald Weltecc0b0142018-05-29 15:19:33 +0200463
464/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
465testcase TC_lcls_gcr_bway_dont_connect() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700466 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200467 var TestHdlrParams pars_b;
468 var MSC_ConnHdlr vc_conn;
469
470 f_lcls_init();
471
472 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
473 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
474 pars_a.lcls.cfg := LCLS_CFG_both_way;
475 pars_a.lcls.csc := LCLS_CSC_do_not_connect;
476 pars_b := pars_a;
477
478 /* first call is not possible to be LS (no second leg yet) */
479 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
480 /* Expect LCLS is *NOT* established */
481 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
482
483 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100484 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200485 f_wait_fail_notify();
486 f_lcls_test_fini();
487}
488
489/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
490testcase TC_lcls_gcr_unsuppported_cfg() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700491 var TestHdlrParams pars := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200492 var MSC_ConnHdlr vc_conn;
493
494 f_lcls_init();
495
496 pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
497 pars.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
498 pars.lcls.cfg := LCLS_CFG_both_way_and_send_DL;
499 pars.lcls.csc := LCLS_CSC_connect;
500 /* Expect LCLS is *NOT* established with "LCLS_STS_req_lcls_not_supp" */
501 pars.lcls.exp_sts := LCLS_STS_req_lcls_not_supp;
502
503 f_lcls_test_init(pars, pars);
504 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
505 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
506 f_wait_fail_notify();
507 f_lcls_test_fini();
508}
509
510/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
511testcase TC_lcls_gcr_unsuppported_csc() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700512 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200513 var TestHdlrParams pars_b;
514 var MSC_ConnHdlr vc_conn;
515
516 f_lcls_init();
517
518 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
519 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
520 pars_a.lcls.cfg := LCLS_CFG_both_way;
521 pars_a.lcls.csc := LCLS_CSC_bicast_UL_and_recv_DL_at_handover;
522 pars_b := pars_a;
523
524 /* first call is not possible to be LS (no second leg yet) */
525 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
526 /* Expect LCLS is *NOT* established */
527 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
528
529 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100530 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200531 f_lcls_test_fini();
532}
533
Maxb1599b12018-10-31 19:38:38 +0100534/* Expect given LCLS status alongside with corresponding MDCX commands */
535private function f_lcls_sts_mgcp(BIT4 expected_status) runs on lcls_test_CT {
536 var MgcpCommand mgcp_cmd;
537
538 interleave {
539 [] CONN_B.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(expected_status)));
540 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(expected_status));
541 [] CONN_A.receive(tr_MDCX) -> value mgcp_cmd {
542 CONN_A.send(f_build_mdcx_rsp(mgcp_cmd));
543 }
544 [] CONN_B.receive(tr_MDCX) -> value mgcp_cmd {
545 CONN_B.send(f_build_mdcx_rsp(mgcp_cmd));
546 }
547 }
548}
549
Max2253c0b2018-11-06 19:28:05 +0100550private function f_lcls_sts_rsl(BIT4 expected_status) runs on lcls_test_CT {
551 var RSL_Message rsl_msg;
552
553 interleave {
554 [] CONN_B.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(expected_status)));
555 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(expected_status));
556 /*
557 [] CONN_A.receive(RSL_Message:?) -> value rsl_msg {
558 log("f_lcls_sts_rsl CONN_A top RSL is ", rsl_msg)
559 }
560 Ex. placeholder to catch any RSL message */
561 [] CONN_A.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
562 f_tc_lcls_ack_rsl_mdcx(rsl_msg, true)
563 }
564 [] CONN_B.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
565 f_tc_lcls_ack_rsl_mdcx(rsl_msg, false)
566 }
567 }
568}
569
Harald Weltecc0b0142018-05-29 15:19:33 +0200570/* Send an ASSIGNMENT REQ with "do not connect" and enable later using LCLS CTRL */
571testcase TC_lcls_gcr_bway_dont_connect_csc() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700572 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200573 var TestHdlrParams pars_b;
574 var MSC_ConnHdlr vc_conn;
575 var MgcpCommand mgcp_cmd;
576
577 f_lcls_init();
578
579 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
580 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
581 pars_a.lcls.cfg := LCLS_CFG_both_way;
582 pars_a.lcls.csc := LCLS_CSC_do_not_connect;
583 pars_b := pars_a;
584
585 /* first call is not possible to be LS (no second leg yet) */
586 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
587 /* Expect LCLS is *NOT* established */
588 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
589
590 /* start call and expect it to be "not yet" LS */
591 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100592 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200593 f_sleep(2.0);
594
595 /* send "connect" on A side, expect call to remain in "not yet" */
596 CONN_A.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_connect)));
597 CONN_A.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(LCLS_STS_not_yet_ls)));
598 f_sleep(2.0);
599
600 /* send "connect" on B side, expect call to go LS, with notify to A side */
601 CONN_B.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_connect)));
Maxb1599b12018-10-31 19:38:38 +0100602 f_lcls_sts_mgcp(LCLS_STS_locally_switched);
Harald Weltecc0b0142018-05-29 15:19:33 +0200603 f_wait_fail_notify();
604 f_lcls_test_fini();
605}
606
607private function f_build_mdcx_rsp(MgcpCommand mdcx) return MgcpResponse
608{
609 var MgcpConnectionId conn_id := f_MgcpCmd_extract_conn_id(mdcx);
610 var SDP_Message sdp_in := mdcx.sdp;
611 var MgcpResponse resp;
612 var SDP_Message sdp_out;
613 var integer rtp_pt := str2int(sdp_in.media_list[0].media_field.fmts[0]);
614
615 sdp_out := valueof(ts_SDP(sdp_in.connection.conn_addr.addr, sdp_in.connection.conn_addr.addr,
616 "foo", "21", sdp_in.media_list[0].media_field.ports.port_number,
617 { int2str(rtp_pt) },
618 { valueof(ts_SDP_rtpmap(rtp_pt, "AMR/8000")),
619 valueof(ts_SDP_ptime(20)) } ));
620 return valueof(ts_MDCX_ACK(mdcx.line.trans_id, conn_id, sdp_out));
621}
622
Max2253c0b2018-11-06 19:28:05 +0100623private function f_lcls_connect_break(boolean bts_mode := false) runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700624 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200625 var TestHdlrParams pars_b;
626 var MSC_ConnHdlr vc_conn;
Harald Weltecc0b0142018-05-29 15:19:33 +0200627
Max2253c0b2018-11-06 19:28:05 +0100628 f_lcls_init(bts_mode);
Harald Weltecc0b0142018-05-29 15:19:33 +0200629
630 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
631 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
632 pars_a.lcls.cfg := LCLS_CFG_both_way;
633 pars_a.lcls.csc := LCLS_CSC_connect;
Max2253c0b2018-11-06 19:28:05 +0100634 pars_a.lcls.adjust_cx_exp := not bts_mode;
Harald Weltecc0b0142018-05-29 15:19:33 +0200635 pars_b := pars_a;
636
637 /* first call is not possible to be LS (no second leg yet) */
638 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
Maxd4e56962018-10-31 19:08:25 +0100639 /* second call should then result in LS */
Harald Weltecc0b0142018-05-29 15:19:33 +0200640 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
641
642 /* Expect LS to be established successfully */
643 f_lcls_test_init(pars_a, pars_b);
644 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100645
Max2253c0b2018-11-06 19:28:05 +0100646 if (bts_mode == true) {
647 f_tc_lcls_recv_ls_exp_rsl();
648 } else {
649 f_tc_lcls_recv_ls_exp_mgcp();
650 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200651
652 /* request LS release on "A" side; call continues to be locally switched */
653 CONN_A.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_release_lcls)));
654 CONN_A.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(LCLS_STS_locally_switched)));
655 f_sleep(2.0);
656
657 /* request LS release on "B" side; call LS is released */
658 CONN_B.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_release_lcls)));
Maxb1599b12018-10-31 19:38:38 +0100659
Max2253c0b2018-11-06 19:28:05 +0100660 if (bts_mode == true) {
661 f_lcls_sts_rsl(LCLS_STS_no_longer_ls);
662 } else {
663 f_lcls_sts_mgcp(LCLS_STS_no_longer_ls);
664 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200665
666 f_lcls_test_fini();
667}
668
Max2253c0b2018-11-06 19:28:05 +0100669/* Establish LCLS "connect" followed by a MSC-initiated break */
670testcase TC_lcls_connect_break() runs on lcls_test_CT {
671 f_lcls_connect_break()
672}
673
674testcase TC_lcls_bts_connect_break() runs on lcls_test_CT {
675 f_lcls_connect_break(true)
676}
677
Harald Weltecc0b0142018-05-29 15:19:33 +0200678/* Establish LCLS "connect" followed by a SCCP-level release of one leg */
679testcase TC_lcls_connect_clear() runs on lcls_test_CT {
Vadim Yanitskiy3cc065b2023-01-06 21:35:12 +0700680 var TestHdlrParams pars_a := f_gen_test_hdlr_pars();
Harald Weltecc0b0142018-05-29 15:19:33 +0200681 var TestHdlrParams pars_b;
682 var MSC_ConnHdlr vc_conn;
683 var MgcpCommand mgcp_cmd;
684 var RSL_Message rsl;
685
686 f_lcls_init();
687
688 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
689 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
690 pars_a.lcls.cfg := LCLS_CFG_both_way;
691 pars_a.lcls.csc := LCLS_CSC_connect;
692 pars_b := pars_a;
693
694 /* first call is not possible to be LS (no second leg yet) */
695 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
696 /* second call should then reuslt in LS */
697 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
698
699 /* Expect LS to be established successfully */
700 f_lcls_test_init(pars_a, pars_b);
701 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100702
703 f_tc_lcls_recv_ls_exp_mgcp();
Harald Weltecc0b0142018-05-29 15:19:33 +0200704
705 /* Perform hard BSSMAP Clear on "A" side, expect no LS on "B" side */
706 var myBSSMAP_Cause cause_val := GSM0808_CAUSE_CALL_CONTROL;
Harald Weltecc0b0142018-05-29 15:19:33 +0200707 CONN_A.send(ts_BSSMAP_ClearCommand(enum2int(cause_val)));
708 interleave {
Harald Welte924b6ea2019-02-04 01:05:34 +0100709 [] CONN_A.receive(tr_RSL_DATA_REQ(?, tr_RslLinkID_DCCH(0), decmatch tr_RRM_RR_RELEASE));
Harald Weltecc0b0142018-05-29 15:19:33 +0200710 [] CONN_A.receive(tr_RSL_DEACT_SACCH(?));
711 [] CONN_A.receive(tr_RSL_RF_CHAN_REL(?)) -> value rsl {
712 var RSL_IE_Body ieb;
Maxfc337ca2018-10-31 19:42:08 +0100713 if (f_rsl_find_ie(rsl, RSL_IE_CHAN_NR, ieb) == true) {
714 CONN_A.send(ts_RSL_RF_CHAN_REL_ACK(ieb.chan_nr));
715 } else {
716 log("Unable to find chan# in RSL_RF_CHAN_REL")
717 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200718 }
Harald Welte935fbe32018-06-11 15:20:39 +0200719 [] CONN_A.receive(tr_BSSMAP_ClearComplete) {
Harald Welte6811d102019-04-14 22:23:14 +0200720 CONN_A.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
Harald Welte935fbe32018-06-11 15:20:39 +0200721 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200722 [] CONN_B.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_possible_ls));
723 }
724 f_sleep(2.0);
725
726 f_lcls_test_fini();
727}
728
729
730
731
732/* TODO:
733 * verify IP/Port information in LCLS-triggered MDCX
734 * establish with one side connect, then enable using LCLS CTRL
735 * LCLS CTRL for call that doesn't have LCLS enabled
736 * LCLS IEs without GCR in ASS CMD
737 * GCR updates?
738 * Handover related LCLS bits (after we have inter-BSC HO in OsmoBSC)
739*/
740
741
742control {
743
744 execute( TC_lcls_gcr_only() );
745 execute( TC_lcls_gcr_bway_connect() );
Philipp Maier61f6b572018-07-06 14:03:38 +0200746 execute( TC_lcls_gcr_bway_connect_hr() );
Philipp Maier55f27f52018-07-10 09:15:09 +0200747 execute( TC_lcls_gcr_bway_codec_mismatch() );
Harald Weltecc0b0142018-05-29 15:19:33 +0200748 execute( TC_lcls_gcr_nomatch_bway_connect() );
749 execute( TC_lcls_gcr_bway_dont_connect() );
750 execute( TC_lcls_gcr_unsuppported_cfg() );
751 execute( TC_lcls_gcr_unsuppported_csc() );
752 execute( TC_lcls_gcr_bway_dont_connect_csc() );
753 execute( TC_lcls_connect_break() );
754 execute( TC_lcls_connect_clear() );
755
Max2253c0b2018-11-06 19:28:05 +0100756 execute( TC_lcls_bts_gcr_bway_connect() );
757 execute( TC_lcls_bts_gcr_bway_connect_hr() );
758 execute( TC_lcls_bts_connect_break() );
Harald Weltecc0b0142018-05-29 15:19:33 +0200759}
760
761
762}