blob: 67ccecf8de85eba106e7a56f293cd7515e1e475f [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 *
10 * This test suite tests OsmoBSC while emulating both multiple BTS + MS as
11 * well as the MSC. See README for more details.
12 *
13 * There are test cases that run in so-called 'handler mode' and test cases
14 * that run directly on top of the BSSAP and RSL CodecPorts. The "handler mode"
15 * tests abstract the multiplexing/demultiplexing of multiple SCCP connections
16 * and/or RSL channels and are hence suitable for higher-level test cases, while
17 * the "raw" tests directly on top of the CodecPorts are more suitable for lower-
18 * level testing.
19 */
20
21import from General_Types all;
22import from Osmocom_Types all;
23import from GSM_Types all;
24import from IPL4asp_Types all;
25
26import from BSSAP_Types all;
27import from BSSAP_Adapter all;
28import from BSSAP_CodecPort all;
29import from BSSMAP_Templates all;
30import from IPA_Emulation all;
31import from IPA_CodecPort all;
32import from IPA_Types all;
33import from RSL_Types all;
34import from RSL_Emulation all;
35import from MGCP_Types all;
36import from MGCP_Emulation all;
37import from MGCP_Templates all;
38import from SDP_Types all;
Max2253c0b2018-11-06 19:28:05 +010039import from Native_Functions all;
Harald Weltecc0b0142018-05-29 15:19:33 +020040
41import from Osmocom_CTRL_Functions all;
42import from Osmocom_CTRL_Types all;
43import from Osmocom_CTRL_Adapter all;
44
45import from Osmocom_VTY_Functions all;
46import from TELNETasp_PortType all;
47
48import from MobileL3_CommonIE_Types all;
49import from MobileL3_Types all;
50import from L3_Templates all;
51import from GSM_RR_Types all;
52
53import from BSSMAP_Templates all;
54import from BSSMAP_Emulation all;
55
56import from MSC_ConnectionHandler all;
57import from BSC_Tests all;
58
59/* The philosophy of this testsuite is to re-use as much as possible the existing components
60 * and functions that we have in BSC_Tests and its dependencies. However, as opposed to those
61 * normal BSC tests, we here have to run *two* ConnHdlr and synchronize activity between them.
62 *
63 * We do this by adding some special-purpose ports between the main test component running the
64 * test case [lcls_]test_CT and the per-connection [LCLS_]MSC_ConnHdlr.
65 */
66
67
68/* take test_CT from BSC_Tests and extend it with LCLS specific bits */
69type component lcls_test_CT extends test_CT {
70 /* Component references */
71 var LCLS_MSC_ConnHdlr vc_CONN_A;
72 var LCLS_MSC_ConnHdlr vc_CONN_B;
73 /* Ports to the two call legs */
74 port LCLS_InterComp_PT CONN_A;
75 port LCLS_InterComp_PT CONN_B;
76}
77
78/* take MSC_ConnHdlr and extend it with LCLS specific bits */
79type component LCLS_MSC_ConnHdlr extends MSC_ConnHdlr {
80 /* Port back to the controlling lcls_test_CT */
81 port LCLS_InterComp_PT MASTER;
82}
83
84/* port type between lcls_test_CT and LCLS_MSC_ConnHdlr */
85type port LCLS_InterComp_PT message {
86 /* BSSAP from BSSA_ConnHdlr */
87 inout PDU_BSSAP, BSSAP_Conn_Prim, PDU_DTAP_MO, PDU_DTAP_MT,
88 /* RSL from RSL_DchanHdlr */
89 RSLDC_ChanRqd, RSL_Message,
90 /* MGCP from MGCP_ConnHdlr */
91 MgcpCommand, MgcpResponse,
92 LclsCompSync;
93} with { extension "internal" };
94
95type enumerated LclsCompSync {
96 /* ConnHdlr signals to master component that assignment has completed */
97 LCLS_COMP_SYNC_ASS_COMPL
98}
99
100
101/* forward messages between the RSL/MGCP/BSSAP Emulation and the master component */
102private altstep as_lcls_conn_hdlr_proxy() runs on LCLS_MSC_ConnHdlr {
103 var PDU_BSSAP bssap;
104 var BSSAP_Conn_Prim bssap_p;
105 var PDU_DTAP_MO dtap_mo;
106 var PDU_DTAP_MT dtap_mt;
107 var MgcpCommand mgcp_cmd;
108 var MgcpResponse mgcp_rsp;
109 var RSL_Message rsl_msg;
110 /* from ConnHdlr to master process */
111 [] BSSAP.receive(PDU_BSSAP:?) -> value bssap { MASTER.send(bssap); }
112 [] BSSAP.receive(BSSAP_Conn_Prim:?) -> value bssap_p { MASTER.send(bssap_p); }
113 [] BSSAP.receive(PDU_DTAP_MO:?) -> value dtap_mo { MASTER.send(dtap_mo); }
114 [] BSSAP.receive(PDU_DTAP_MT:?) -> value dtap_mt { MASTER.send(dtap_mt); }
115 [] MGCP.receive(MgcpCommand:?) -> value mgcp_cmd { MASTER.send(mgcp_cmd); }
116 [] MGCP.receive(MgcpResponse:?) -> value mgcp_rsp { MASTER.send(mgcp_rsp); }
117 [] RSL.receive(RSL_Message:?) -> value rsl_msg { MASTER.send(rsl_msg); }
118 /* from master process to ConnHdlr */
119 [] MASTER.receive(PDU_BSSAP:?) -> value bssap { BSSAP.send(bssap); }
Harald Welte935fbe32018-06-11 15:20:39 +0200120 [] MASTER.receive(BSSAP_Conn_Prim:?) -> value bssap_p { BSSAP.send(bssap_p); }
Harald Weltecc0b0142018-05-29 15:19:33 +0200121 [] MASTER.receive(PDU_DTAP_MO:?) -> value dtap_mo { BSSAP.send(dtap_mo); }
122 [] MASTER.receive(PDU_DTAP_MT:?) -> value dtap_mt { BSSAP.send(dtap_mt); }
123 [] MASTER.receive(MgcpCommand:?) -> value mgcp_cmd { MGCP.send(mgcp_cmd); }
124 [] MASTER.receive(MgcpResponse:?) -> value mgcp_rsp { MGCP.send(mgcp_rsp); }
125 [] MASTER.receive(RSL_Message:?) -> value rsl_msg { RSL.send(rsl_msg); }
126}
127
128
129private function f_lcls_connhdlr_main(charstring id) runs on LCLS_MSC_ConnHdlr {
130 /* 1) establish the connection between RSL and BSSAP side */
131 var PDU_BSSAP ass_req := f_gen_ass_req();
Philipp Maier61f6b572018-07-06 14:03:38 +0200132
Harald Weltecc0b0142018-05-29 15:19:33 +0200133 var template PDU_BSSAP ass_compl := f_gen_exp_compl();
134 ass_req.pdu.bssmap.assignmentRequest.codecList := g_pars.ass_codec_list;
Philipp Maier61f6b572018-07-06 14:03:38 +0200135 ass_req.pdu.bssmap.assignmentRequest.channelType :=
136 f_BSSMAP_chtype_from_codec(g_pars.ass_codec_list.codecElements[0]);
137
Harald Weltecc0b0142018-05-29 15:19:33 +0200138 f_establish_fully(ass_req, ass_compl);
139
140 /* 2) notify master that assignment has completed */
141 MASTER.send(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
142
143 /* 3) proxy packets between master component and various ports */
144 while (true) {
145 as_lcls_conn_hdlr_proxy();
146 }
147}
148
149type function lcls_void_fn(charstring id) runs on LCLS_MSC_ConnHdlr;
150
151/* first function inside ConnHdlr component; sets g_pars + starts function */
152private function f_handler_init(lcls_void_fn fn, charstring id, template (omit) TestHdlrParams pars := omit)
153runs on LCLS_MSC_ConnHdlr {
154 if (isvalue(pars)) {
155 g_pars := valueof(pars);
156 }
157 fn.apply(id);
158}
159
Harald Welteff579f92018-05-31 22:19:39 +0200160/* helper function to create and connect a MSC_ConnHdlr component */
161/* FIXME: Why can't we use BSC_Tests.f_connect_andler() ?!? */
162private function f_connect_handler(inout LCLS_MSC_ConnHdlr vc_conn) runs on lcls_test_CT {
163 connect(vc_conn:BSSMAPEM, g_bssap.vc_BSSMAP:PROC);
164 connect(vc_conn:MGCP_PROC, vc_MGCP:MGCP_PROC);
165 connect(vc_conn:RSL, bts[0].rsl.vc_RSL:CLIENT_PT);
166 connect(vc_conn:RSL_PROC, bts[0].rsl.vc_RSL:RSL_PROC);
167 if (isvalue(bts[1])) {
168 connect(vc_conn:RSL1, bts[1].rsl.vc_RSL:CLIENT_PT);
169 connect(vc_conn:RSL1_PROC, bts[1].rsl.vc_RSL:RSL_PROC);
170 }
171 connect(vc_conn:BSSAP, g_bssap.vc_BSSMAP:CLIENT);
172 connect(vc_conn:MGCP, vc_MGCP:MGCP_CLIENT);
173}
174
Harald Weltecc0b0142018-05-29 15:19:33 +0200175/* function creating the two ConnHdlrs, connecting them + starting them */
176private function f_lcls_test_init(TestHdlrParams pars_a, TestHdlrParams pars_b) runs on lcls_test_CT {
177 var charstring id_a := testcasename() & "-A";
178 var charstring id_b := testcasename() & "-B";
179
180 pars_b.imsi := '002029876543210'H;
181 pars_b.media_nr := 2;
182
183 /* create and connect the two ConnHandlers */
184 vc_CONN_A := LCLS_MSC_ConnHdlr.create(id_a);
185 f_connect_handler(vc_CONN_A);
186 connect(vc_CONN_A:MASTER, self:CONN_A);
187
188 vc_CONN_B := LCLS_MSC_ConnHdlr.create(id_b);
189 f_connect_handler(vc_CONN_B);
190 connect(vc_CONN_B:MASTER, self:CONN_B);
191
192 /* start the two components */
193 vc_CONN_A.start(f_handler_init(refers(f_lcls_connhdlr_main), id_a, pars_a));
194 f_sleep(3.0);
195 vc_CONN_B.start(f_handler_init(refers(f_lcls_connhdlr_main), id_b, pars_b));
196}
197
198private function f_lcls_test_fini() runs on lcls_test_CT {
199 vc_CONN_A.stop;
200 vc_CONN_B.stop;
201}
202
203/* ignore some messages which we're not interested in evaluating (yet) */
204private altstep as_ignore() runs on lcls_test_CT {
205 [] CONN_A.receive(tr_DLCX) { repeat; }
206 [] CONN_B.receive(tr_DLCX) { repeat; }
207}
208
209/* fail if any notify is being received */
210private altstep as_fail_on_lcls_notify() runs on lcls_test_CT
211{
212 [] CONN_A.receive(tr_BSSMAP_LclsNotification(?, *)) {
213 setverdict(fail, "Unexpected BSSMAP LCLS Notification");
214 }
215 [] CONN_B.receive(tr_BSSMAP_LclsNotification(?, *)) {
216 setverdict(fail, "Unexpected BSSMAP LCLS Notification");
217 }
218}
219
220private function f_wait_fail_notify() runs on lcls_test_CT
221{
222 timer T := 3.0;
223 T.start;
224 alt {
225 [] as_fail_on_lcls_notify();
226 [] T.timeout { }
227 }
228}
229
Max2253c0b2018-11-06 19:28:05 +0100230private function f_lcls_init(boolean bts_mode := false, integer nr_bts := 1) runs on lcls_test_CT
Harald Weltecc0b0142018-05-29 15:19:33 +0200231{
232 var default d;
233
234 d := activate(as_ignore());
235 f_init(nr_bts, true);
236 f_sleep(1.0);
Max2253c0b2018-11-06 19:28:05 +0100237
238 f_init_vty();
239 if (bts_mode == true) {
240 f_vty_config(BSCVTY, "msc", "lcls-mode bts-loop");
241 } else {
242 f_vty_config(BSCVTY, "msc", "lcls-mode mgw-loop");
243 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200244}
245
246
247/* Send an ASSIGNMENT REQ with LCLS GCR only, without LCLS CFG or CSC */
248testcase TC_lcls_gcr_only() runs on lcls_test_CT {
249 var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
250 var MSC_ConnHdlr vc_conn;
251
252 f_lcls_init();
253
254 pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
255 pars.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
256 /* Expect LCLS status to be not reported, as no LCLS config was signalled */
257 pars.lcls.exp_sts := omit;
258
259 f_lcls_test_init(pars, pars);
260 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
261 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
262 f_wait_fail_notify();
263 f_lcls_test_fini();
264}
265
Maxb1599b12018-10-31 19:38:38 +0100266private function f_tc_lcls_recv_ls_exp_mgcp() runs on lcls_test_CT {
267 var MgcpCommand mgcp_cmd;
268
269 interleave {
270 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
271 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_locally_switched));
272 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
273 [] CONN_A.receive(tr_MDCX) -> value mgcp_cmd {
274 CONN_A.send(f_build_mdcx_rsp(mgcp_cmd));
275 }
276 /* not needed, as this MDCX is still handled within MSC_ConnectionHandler
277 [] CONN_B.receive(tr_MDCX) -> value mgcp_cmd {
278 CONN_B.send(f_build_mdcx_rsp(mgcp_cmd));
279 }
280 */
281 }
282}
283
Max2253c0b2018-11-06 19:28:05 +0100284private function f_tc_lcls_ack_rsl_mdcx(RSL_Message rsl_msg, boolean send_on_a) runs on lcls_test_CT {
285 var boolean fixme_unused;
286 var RSL_IE_Body ie;
287 var RslChannelNr chan_nr;
288 var uint16_t conn_id;
289 var uint7_t rtp_pt := 0;
290 var HostName host;
291 var PortNumber port_num;
292
293 if (f_rsl_find_ie(rsl_msg, RSL_IE_CHAN_NR, ie) == true) {
294 chan_nr := ie.chan_nr;
295 } else {
296 log("Unable to find chan# in ", rsl_msg);
297 }
298
299 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_CONN_ID, ie);
300 conn_id := ie.ipa_conn_id;
301
302 /* mandatory fields */
303 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_REMOTE_IP, ie);
304 host := f_inet_ntoa(int2oct(ie.ipa_remote_ip, 4));
305
306 fixme_unused := f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_REMOTE_PORT, ie);
307 port_num := ie.ipa_remote_port;
308 log("LCLS IPA MDCX for lchan ", chan_nr, " connection ID ", conn_id, " host ", host, ":", port_num);
309
310 /* optional */
311 if (f_rsl_find_ie(rsl_msg, RSL_IE_IPAC_RTP_PAYLOAD, ie)) {
312 rtp_pt := ie.ipa_rtp_pt;
313 }
314
315 if (send_on_a == true) {
316 CONN_A.send(ts_RSL_IPA_MDCX_ACK(chan_nr, conn_id, oct2int(f_inet_addr(host)), port_num, rtp_pt));
317 } else {
318 CONN_B.send(ts_RSL_IPA_MDCX_ACK(chan_nr, conn_id, oct2int(f_inet_addr(host)), port_num, rtp_pt));
319 }
320}
321
322private function f_tc_lcls_recv_ls_exp_rsl() runs on lcls_test_CT {
323 var RSL_Message rsl_msg;
324 interleave {
325 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls)) {}
326 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_locally_switched)) {}
327 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL) {}
328 [] CONN_A.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
329 f_tc_lcls_ack_rsl_mdcx(rsl_msg, true)
330 }
331 }
332}
333
334private 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 +0200335 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
336 var TestHdlrParams pars_b;
337 var MSC_ConnHdlr vc_conn;
Harald Weltecc0b0142018-05-29 15:19:33 +0200338
Max2253c0b2018-11-06 19:28:05 +0100339 f_lcls_init(bts_mode);
Harald Weltecc0b0142018-05-29 15:19:33 +0200340
Philipp Maier61f6b572018-07-06 14:03:38 +0200341 if (hr == true) {
342 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR}));
343 } else {
344 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
345 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200346 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
347 pars_a.lcls.cfg := LCLS_CFG_both_way;
348 pars_a.lcls.csc := LCLS_CSC_connect;
Max2253c0b2018-11-06 19:28:05 +0100349 pars_a.lcls.adjust_cx_exp := not bts_mode;
Harald Weltecc0b0142018-05-29 15:19:33 +0200350 pars_b := pars_a;
351
352 /* first call is not possible to be LS (no second leg yet) */
353 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
354 /* second call should then reuslt in LS */
355 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
356
357 f_lcls_test_init(pars_a, pars_b);
Philipp Maier61f6b572018-07-06 14:03:38 +0200358
Harald Weltecc0b0142018-05-29 15:19:33 +0200359 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100360
Max2253c0b2018-11-06 19:28:05 +0100361 if (bts_mode == true) {
362 f_tc_lcls_recv_ls_exp_rsl();
363 } else {
364 f_tc_lcls_recv_ls_exp_mgcp();
365 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200366
367 f_lcls_test_fini();
368}
369
Philipp Maier61f6b572018-07-06 14:03:38 +0200370/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (full rate)*/
371testcase TC_lcls_gcr_bway_connect() runs on lcls_test_CT {
372 f_tc_lcls_gcr_bway_connect(false)
373}
374
375/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (half rate) */
376testcase TC_lcls_gcr_bway_connect_hr() runs on lcls_test_CT {
Max2253c0b2018-11-06 19:28:05 +0100377 f_tc_lcls_gcr_bway_connect(true)
378}
379
380/* BTS-loop: send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (full rate)*/
381testcase TC_lcls_bts_gcr_bway_connect() runs on lcls_test_CT {
382 f_tc_lcls_gcr_bway_connect(false, true)
383}
384
385/* BTS-loop: send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect connect both-way (half rate) */
386testcase TC_lcls_bts_gcr_bway_connect_hr() runs on lcls_test_CT {
387 f_tc_lcls_gcr_bway_connect(true, true)
Philipp Maier61f6b572018-07-06 14:03:38 +0200388}
389
Philipp Maier55f27f52018-07-10 09:15:09 +0200390/* Unless explicitly enabled, osmo-bsc will avoid LCLSs when the codecs or rates
391 * of both legs are different */
392testcase TC_lcls_gcr_bway_codec_mismatch() runs on lcls_test_CT {
393 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
394 var TestHdlrParams pars_b;
395 var MSC_ConnHdlr vc_conn;
396 var MgcpCommand mgcp_cmd;
397
398 f_lcls_init();
399
400 /* First call leg uses full rate */
401 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
402 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
403 pars_a.lcls.cfg := LCLS_CFG_both_way;
404 pars_a.lcls.csc := LCLS_CSC_connect;
405
406 /* The second call leg uses half-rate */
407 pars_b := pars_a;
408 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR}));
409
410 /* first call is not possible to be LS (no second leg yet) */
411 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
412
413 /* second call is also not possible to be LS (codec/rate does not match) */
414 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
415 f_lcls_test_init(pars_a, pars_b);
416
417 interleave {
418 [] CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
419 [] CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
420 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
421 }
422
423 f_lcls_test_fini();
424}
425
Harald Weltecc0b0142018-05-29 15:19:33 +0200426/* Send an ASSIGNMENT REQ with LCLS CFG+CSC enabling LCLS but GCR doesn't match! */
427testcase TC_lcls_gcr_nomatch_bway_connect() runs on lcls_test_CT {
428 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
429 var TestHdlrParams pars_b;
430 var MSC_ConnHdlr vc_conn;
431 var MgcpCommand mgcp_cmd;
432
433 f_lcls_init();
434
435 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
436 pars_a.lcls.cfg := LCLS_CFG_both_way;
437 pars_a.lcls.csc := LCLS_CSC_connect;
438 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
439
440 pars_b := pars_a;
441
442 /* first call is not possible to be LS (no second leg yet) */
443 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
444 pars_b.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090b'O));
445
446 f_lcls_test_init(pars_a, pars_b);
447 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
448 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
449 f_wait_fail_notify();
450 f_lcls_test_fini();
451}
452
Maxb1599b12018-10-31 19:38:38 +0100453/* check for the cases where LCLS is not possible due to some reason */
454private function f_lcls_not_yet_ls() runs on lcls_test_CT {
455 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
456 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
457 CONN_A.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_yet_ls));
458}
Harald Weltecc0b0142018-05-29 15:19:33 +0200459
460/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
461testcase TC_lcls_gcr_bway_dont_connect() runs on lcls_test_CT {
462 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
463 var TestHdlrParams pars_b;
464 var MSC_ConnHdlr vc_conn;
465
466 f_lcls_init();
467
468 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
469 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
470 pars_a.lcls.cfg := LCLS_CFG_both_way;
471 pars_a.lcls.csc := LCLS_CSC_do_not_connect;
472 pars_b := pars_a;
473
474 /* first call is not possible to be LS (no second leg yet) */
475 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
476 /* Expect LCLS is *NOT* established */
477 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
478
479 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100480 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200481 f_wait_fail_notify();
482 f_lcls_test_fini();
483}
484
485/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
486testcase TC_lcls_gcr_unsuppported_cfg() runs on lcls_test_CT {
487 var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
488 var MSC_ConnHdlr vc_conn;
489
490 f_lcls_init();
491
492 pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
493 pars.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
494 pars.lcls.cfg := LCLS_CFG_both_way_and_send_DL;
495 pars.lcls.csc := LCLS_CSC_connect;
496 /* Expect LCLS is *NOT* established with "LCLS_STS_req_lcls_not_supp" */
497 pars.lcls.exp_sts := LCLS_STS_req_lcls_not_supp;
498
499 f_lcls_test_init(pars, pars);
500 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
501 CONN_B.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
502 f_wait_fail_notify();
503 f_lcls_test_fini();
504}
505
506/* Send an ASSIGNMENT REQ with LCLS GCR+CFG+CSC; expect no connect */
507testcase TC_lcls_gcr_unsuppported_csc() runs on lcls_test_CT {
508 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
509 var TestHdlrParams pars_b;
510 var MSC_ConnHdlr vc_conn;
511
512 f_lcls_init();
513
514 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
515 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
516 pars_a.lcls.cfg := LCLS_CFG_both_way;
517 pars_a.lcls.csc := LCLS_CSC_bicast_UL_and_recv_DL_at_handover;
518 pars_b := pars_a;
519
520 /* first call is not possible to be LS (no second leg yet) */
521 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
522 /* Expect LCLS is *NOT* established */
523 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
524
525 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100526 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200527 f_lcls_test_fini();
528}
529
Maxb1599b12018-10-31 19:38:38 +0100530/* Expect given LCLS status alongside with corresponding MDCX commands */
531private function f_lcls_sts_mgcp(BIT4 expected_status) runs on lcls_test_CT {
532 var MgcpCommand mgcp_cmd;
533
534 interleave {
535 [] CONN_B.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(expected_status)));
536 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(expected_status));
537 [] CONN_A.receive(tr_MDCX) -> value mgcp_cmd {
538 CONN_A.send(f_build_mdcx_rsp(mgcp_cmd));
539 }
540 [] CONN_B.receive(tr_MDCX) -> value mgcp_cmd {
541 CONN_B.send(f_build_mdcx_rsp(mgcp_cmd));
542 }
543 }
544}
545
Max2253c0b2018-11-06 19:28:05 +0100546private function f_lcls_sts_rsl(BIT4 expected_status) runs on lcls_test_CT {
547 var RSL_Message rsl_msg;
548
549 interleave {
550 [] CONN_B.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(expected_status)));
551 [] CONN_A.receive(tr_BSSMAP_LclsNotificationSts(expected_status));
552 /*
553 [] CONN_A.receive(RSL_Message:?) -> value rsl_msg {
554 log("f_lcls_sts_rsl CONN_A top RSL is ", rsl_msg)
555 }
556 Ex. placeholder to catch any RSL message */
557 [] CONN_A.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
558 f_tc_lcls_ack_rsl_mdcx(rsl_msg, true)
559 }
560 [] CONN_B.receive(tr_RSL_IPA_MDCX(?, ?)) -> value rsl_msg {
561 f_tc_lcls_ack_rsl_mdcx(rsl_msg, false)
562 }
563 }
564}
565
Harald Weltecc0b0142018-05-29 15:19:33 +0200566/* Send an ASSIGNMENT REQ with "do not connect" and enable later using LCLS CTRL */
567testcase TC_lcls_gcr_bway_dont_connect_csc() runs on lcls_test_CT {
568 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
569 var TestHdlrParams pars_b;
570 var MSC_ConnHdlr vc_conn;
571 var MgcpCommand mgcp_cmd;
572
573 f_lcls_init();
574
575 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
576 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
577 pars_a.lcls.cfg := LCLS_CFG_both_way;
578 pars_a.lcls.csc := LCLS_CSC_do_not_connect;
579 pars_b := pars_a;
580
581 /* first call is not possible to be LS (no second leg yet) */
582 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
583 /* Expect LCLS is *NOT* established */
584 pars_b.lcls.exp_sts := LCLS_STS_not_yet_ls;
585
586 /* start call and expect it to be "not yet" LS */
587 f_lcls_test_init(pars_a, pars_b);
Maxb1599b12018-10-31 19:38:38 +0100588 f_lcls_not_yet_ls();
Harald Weltecc0b0142018-05-29 15:19:33 +0200589 f_sleep(2.0);
590
591 /* send "connect" on A side, expect call to remain in "not yet" */
592 CONN_A.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_connect)));
593 CONN_A.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(LCLS_STS_not_yet_ls)));
594 f_sleep(2.0);
595
596 /* send "connect" on B side, expect call to go LS, with notify to A side */
597 CONN_B.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_connect)));
Maxb1599b12018-10-31 19:38:38 +0100598 f_lcls_sts_mgcp(LCLS_STS_locally_switched);
Harald Weltecc0b0142018-05-29 15:19:33 +0200599 f_wait_fail_notify();
600 f_lcls_test_fini();
601}
602
603private function f_build_mdcx_rsp(MgcpCommand mdcx) return MgcpResponse
604{
605 var MgcpConnectionId conn_id := f_MgcpCmd_extract_conn_id(mdcx);
606 var SDP_Message sdp_in := mdcx.sdp;
607 var MgcpResponse resp;
608 var SDP_Message sdp_out;
609 var integer rtp_pt := str2int(sdp_in.media_list[0].media_field.fmts[0]);
610
611 sdp_out := valueof(ts_SDP(sdp_in.connection.conn_addr.addr, sdp_in.connection.conn_addr.addr,
612 "foo", "21", sdp_in.media_list[0].media_field.ports.port_number,
613 { int2str(rtp_pt) },
614 { valueof(ts_SDP_rtpmap(rtp_pt, "AMR/8000")),
615 valueof(ts_SDP_ptime(20)) } ));
616 return valueof(ts_MDCX_ACK(mdcx.line.trans_id, conn_id, sdp_out));
617}
618
Max2253c0b2018-11-06 19:28:05 +0100619private function f_lcls_connect_break(boolean bts_mode := false) runs on lcls_test_CT {
Harald Weltecc0b0142018-05-29 15:19:33 +0200620 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
621 var TestHdlrParams pars_b;
622 var MSC_ConnHdlr vc_conn;
Harald Weltecc0b0142018-05-29 15:19:33 +0200623
Max2253c0b2018-11-06 19:28:05 +0100624 f_lcls_init(bts_mode);
Harald Weltecc0b0142018-05-29 15:19:33 +0200625
626 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
627 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
628 pars_a.lcls.cfg := LCLS_CFG_both_way;
629 pars_a.lcls.csc := LCLS_CSC_connect;
Max2253c0b2018-11-06 19:28:05 +0100630 pars_a.lcls.adjust_cx_exp := not bts_mode;
Harald Weltecc0b0142018-05-29 15:19:33 +0200631 pars_b := pars_a;
632
633 /* first call is not possible to be LS (no second leg yet) */
634 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
Maxd4e56962018-10-31 19:08:25 +0100635 /* second call should then result in LS */
Harald Weltecc0b0142018-05-29 15:19:33 +0200636 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
637
638 /* Expect LS to be established successfully */
639 f_lcls_test_init(pars_a, pars_b);
640 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100641
Max2253c0b2018-11-06 19:28:05 +0100642 if (bts_mode == true) {
643 f_tc_lcls_recv_ls_exp_rsl();
644 } else {
645 f_tc_lcls_recv_ls_exp_mgcp();
646 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200647
648 /* request LS release on "A" side; call continues to be locally switched */
649 CONN_A.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_release_lcls)));
650 CONN_A.receive(tr_BSSMAP_LclsConnCtrlAck(tr_BSSMAP_IE_LclsSts(LCLS_STS_locally_switched)));
651 f_sleep(2.0);
652
653 /* request LS release on "B" side; call LS is released */
654 CONN_B.send(ts_BSSMAP_LclsConnCtrl(omit, ts_BSSMAP_IE_LclsCsc(LCLS_CSC_release_lcls)));
Maxb1599b12018-10-31 19:38:38 +0100655
Max2253c0b2018-11-06 19:28:05 +0100656 if (bts_mode == true) {
657 f_lcls_sts_rsl(LCLS_STS_no_longer_ls);
658 } else {
659 f_lcls_sts_mgcp(LCLS_STS_no_longer_ls);
660 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200661
662 f_lcls_test_fini();
663}
664
Max2253c0b2018-11-06 19:28:05 +0100665/* Establish LCLS "connect" followed by a MSC-initiated break */
666testcase TC_lcls_connect_break() runs on lcls_test_CT {
667 f_lcls_connect_break()
668}
669
670testcase TC_lcls_bts_connect_break() runs on lcls_test_CT {
671 f_lcls_connect_break(true)
672}
673
Harald Weltecc0b0142018-05-29 15:19:33 +0200674/* Establish LCLS "connect" followed by a SCCP-level release of one leg */
675testcase TC_lcls_connect_clear() runs on lcls_test_CT {
676 var TestHdlrParams pars_a := valueof(t_def_TestHdlrPars);
677 var TestHdlrParams pars_b;
678 var MSC_ConnHdlr vc_conn;
679 var MgcpCommand mgcp_cmd;
680 var RSL_Message rsl;
681
682 f_lcls_init();
683
684 pars_a.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR}));
685 pars_a.lcls.gcr := valueof(ts_GCR('010203'O, '0405'O, '060708090a'O));
686 pars_a.lcls.cfg := LCLS_CFG_both_way;
687 pars_a.lcls.csc := LCLS_CSC_connect;
688 pars_b := pars_a;
689
690 /* first call is not possible to be LS (no second leg yet) */
691 pars_a.lcls.exp_sts := LCLS_STS_not_possible_ls;
692 /* second call should then reuslt in LS */
693 pars_b.lcls.exp_sts := LCLS_STS_locally_switched;
694
695 /* Expect LS to be established successfully */
696 f_lcls_test_init(pars_a, pars_b);
697 CONN_A.receive(LclsCompSync:LCLS_COMP_SYNC_ASS_COMPL);
Maxb1599b12018-10-31 19:38:38 +0100698
699 f_tc_lcls_recv_ls_exp_mgcp();
Harald Weltecc0b0142018-05-29 15:19:33 +0200700
701 /* Perform hard BSSMAP Clear on "A" side, expect no LS on "B" side */
702 var myBSSMAP_Cause cause_val := GSM0808_CAUSE_CALL_CONTROL;
Harald Weltecc0b0142018-05-29 15:19:33 +0200703 CONN_A.send(ts_BSSMAP_ClearCommand(enum2int(cause_val)));
704 interleave {
Harald Welte924b6ea2019-02-04 01:05:34 +0100705 [] CONN_A.receive(tr_RSL_DATA_REQ(?, tr_RslLinkID_DCCH(0), decmatch tr_RRM_RR_RELEASE));
Harald Weltecc0b0142018-05-29 15:19:33 +0200706 [] CONN_A.receive(tr_RSL_DEACT_SACCH(?));
707 [] CONN_A.receive(tr_RSL_RF_CHAN_REL(?)) -> value rsl {
708 var RSL_IE_Body ieb;
Maxfc337ca2018-10-31 19:42:08 +0100709 if (f_rsl_find_ie(rsl, RSL_IE_CHAN_NR, ieb) == true) {
710 CONN_A.send(ts_RSL_RF_CHAN_REL_ACK(ieb.chan_nr));
711 } else {
712 log("Unable to find chan# in RSL_RF_CHAN_REL")
713 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200714 }
Harald Welte935fbe32018-06-11 15:20:39 +0200715 [] CONN_A.receive(tr_BSSMAP_ClearComplete) {
716 CONN_A.send(BSSAP_Conn_Prim:MSC_CONN_PRIM_DISC_REQ);
717 }
Harald Weltecc0b0142018-05-29 15:19:33 +0200718 [] CONN_B.receive(tr_BSSMAP_LclsNotificationSts(LCLS_STS_not_possible_ls));
719 }
720 f_sleep(2.0);
721
722 f_lcls_test_fini();
723}
724
725
726
727
728/* TODO:
729 * verify IP/Port information in LCLS-triggered MDCX
730 * establish with one side connect, then enable using LCLS CTRL
731 * LCLS CTRL for call that doesn't have LCLS enabled
732 * LCLS IEs without GCR in ASS CMD
733 * GCR updates?
734 * Handover related LCLS bits (after we have inter-BSC HO in OsmoBSC)
735*/
736
737
738control {
739
740 execute( TC_lcls_gcr_only() );
741 execute( TC_lcls_gcr_bway_connect() );
Philipp Maier61f6b572018-07-06 14:03:38 +0200742 execute( TC_lcls_gcr_bway_connect_hr() );
Philipp Maier55f27f52018-07-10 09:15:09 +0200743 execute( TC_lcls_gcr_bway_codec_mismatch() );
Harald Weltecc0b0142018-05-29 15:19:33 +0200744 execute( TC_lcls_gcr_nomatch_bway_connect() );
745 execute( TC_lcls_gcr_bway_dont_connect() );
746 execute( TC_lcls_gcr_unsuppported_cfg() );
747 execute( TC_lcls_gcr_unsuppported_csc() );
748 execute( TC_lcls_gcr_bway_dont_connect_csc() );
749 execute( TC_lcls_connect_break() );
750 execute( TC_lcls_connect_clear() );
751
Max2253c0b2018-11-06 19:28:05 +0100752 execute( TC_lcls_bts_gcr_bway_connect() );
753 execute( TC_lcls_bts_gcr_bway_connect_hr() );
754 execute( TC_lcls_bts_connect_break() );
Harald Weltecc0b0142018-05-29 15:19:33 +0200755}
756
757
758}