blob: e42ed22e02560341a5fe08a63886312c3e17704a [file] [log] [blame]
Neels Hofmeyr5c5b2762020-10-01 06:35:56 +02001module SMLC_Tests {
2
3/* Integration Tests for OsmoSMLC
4 * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
5 * All rights reserved.
6 *
7 * Released under the terms of GNU General Public License, Version 2 or
8 * (at your option) any later version.
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
12 * This test suite tests OsmoSMLC 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 Misc_Helpers all;
24import from General_Types all;
25import from Osmocom_Types all;
26
27import from BSSAP_LE_Adapter all;
28import from BSSAP_LE_CodecPort all;
29import from BSSAP_LE_Types all;
30import from BSSAP_LE_Emulation all;
31import from BSSMAP_LE_Templates all;
32import from BSSLAP_Types all;
33
34import from BSSAP_Types all;
35import from BSSMAP_Templates all;
36
37import from Osmocom_CTRL_Functions all;
38import from Osmocom_CTRL_Types all;
39import from Osmocom_CTRL_Adapter all;
40
41import from Osmocom_VTY_Functions all;
42import from TELNETasp_PortType all;
43
44import from SCCP_Templates all;
45
46import from SCCPasp_Types all;
47
48import from BSC_ConnectionHandler all;
49
50const integer NUM_BSC := 1;
51
52/* Default list of counters for 'smlc' */
53const CounterNameVals counternames_bsc := {
54 { "foo:bar", 0 }
55};
56
57type component test_CT extends CTRL_Adapter_CT {
58 var BSSAP_LE_Adapter g_bssap_le[NUM_BSC];
59 port BSSAP_LE_CODEC_PT BSSAP_LE;
60
61 port TELNETasp_PT SMLCVTY;
62
63 /* are we initialized yet */
64 var boolean g_initialized := false;
65
66 /*Configure T(tias) over VTY, seconds */
67 var integer g_smlc_sccp_timer_ias := 7 * 60;
68 /*Configure T(tiar) over VTY, seconds */
69 var integer g_smlc_sccp_timer_iar := 15 * 60;
70
71 /* global test case guard timer (actual timeout value is set in f_init()) */
72 timer T_guard := 30.0;
73
74 var CounterNameValsList g_ctr_smlc;
75 var CounterNameValsList g_ctr_bsc;
76
77}
78
79type record of BSSAP_LE_Configuration BSSAP_LE_Configurations;
80
81modulepar {
82 /* IP address at which the SMLC can be reached */
83 charstring mp_smlc_ip := "127.0.0.1";
84 /* port number to which to establish the IPA CTRL connection */
85 integer mp_smlc_ctrl_port := 4272;
86 /* IP address at which the test binds */
87 charstring mp_test_ip := "127.0.0.1";
88
89 BSSAP_LE_Configurations mp_bssap_le_cfg := {
90 {
91 sccp_service_type := "mtp3_itu",
92 sctp_addr := { 23908, "127.0.0.1", 2905, "127.0.0.1" },
93 own_pc := 187, /* 0.23.3 first BSC emulation */
94 own_ssn := 250, /* BSC side SSN */
95 peer_pc := 190, /* 0.23.6 osmo-smlc */
96 peer_ssn := 252, /* SMLC side SSN */
97 sio := '83'O,
98 rctx := 1
99 }
100 };
101}
102
103private function f_gen_test_hdlr_pars(integer bssap_le_idx := 0) return TestHdlrParams {
104
105 var TestHdlrParams pars := valueof(t_def_TestHdlrPars);
106 return pars;
107}
108
109/* Convenience functions for rate counters using g_ctr_bsc. */
110
111private function f_ctrs_smlc_init(integer bscs_count := NUM_BSC, CounterNameVals counternames := counternames_bsc) runs on test_CT {
112 g_ctr_bsc := f_counter_name_vals_get_n(IPA_CTRL, "bsc", bscs_count, counternames);
113 log("initial msc rate counters: ", g_ctr_bsc);
114}
115
116private function f_ctrs_smlc_add(integer msc_nr, charstring countername, integer val := 1) runs on test_CT {
117 f_counter_name_vals_list_add(g_ctr_bsc, msc_nr, countername, val);
118}
119
120/* f_ctrs_smlc_init();
121 * f_do_thing(on_msc := 0);
122 * f_do_thing(on_msc := 0);
123 * f_do_other(on_msc := 1);
124 * f_ctrs_smlc_add(0, "thing", 2);
125 * f_ctrs_smlc_add(1, "other");
126 * f_ctrs_smlc_verify();
127 */
128private function f_ctrs_smlc_verify() runs on test_CT {
129 log("verifying msc rate counters: ", g_ctr_bsc);
130 f_counter_name_vals_expect_n(IPA_CTRL, "bsc", g_ctr_bsc);
131}
132
133/* convenience: f_ctrs_smlc_add() and f_ctrs_smlc_verify() in one call.
134 * f_ctrs_smlc_init();
135 * f_do_thing(on_msc := 0);
136 * f_do_thing(on_msc := 0);
137 * f_do_thing(on_msc := 0);
138 * f_ctrs_smlc_expect(0, "thing", 3);
139 */
140private function f_ctrs_smlc_expect(integer msc_nr, charstring countername, integer val := 1) runs on test_CT {
141 f_ctrs_smlc_add(msc_nr, countername, val);
142 f_ctrs_smlc_verify();
143}
144
145private function f_shutdown_helper() runs on test_CT {
146 all component.stop;
147 setverdict(pass);
148 mtc.stop;
149}
150
151/* global altstep for global guard timer */
152altstep as_Tguard() runs on test_CT {
153 [] T_guard.timeout {
154 setverdict(fail, "Timeout of T_guard");
155 mtc.stop;
156 }
157}
158
159private function f_logp(TELNETasp_PT pt, charstring log_msg)
160{
161 // log on TTCN3 log output
162 log(log_msg);
163 // log in stderr log
164 f_vty_transceive(pt, "logp lglobal notice TTCN3 f_logp(): " & log_msg);
165}
166
167/* global initialization function
168 * \param nr_bts Number of BTSs we should start/bring up
169 * \param handler_mode Start an RSL_Emulation_CT component (true) or not (false).
170 * \param nr_msc Number of virtual MSCs to bring up to connect to osmo-bsc.
171 */
172function f_init(integer nr_bsc := NUM_BSC, float guard_timeout := 30.0) runs on test_CT {
173 var integer bssap_le_idx;
174
175 if (g_initialized) {
176 return;
177 }
178 g_initialized := true;
179
180 T_guard.start(guard_timeout);
181 activate(as_Tguard());
182
183 f_init_vty("VirtBSC");
184
185 for (bssap_le_idx := 0; bssap_le_idx < nr_bsc; bssap_le_idx := bssap_le_idx+1) {
186 f_bssap_le_adapter_init(g_bssap_le[bssap_le_idx], mp_bssap_le_cfg[bssap_le_idx], "VirtBSC", BSC_BssapLeOps);
187 f_bssap_le_adapter_start(g_bssap_le[bssap_le_idx]);
188 }
189}
190
191function f_init_vty(charstring id := "foo") runs on test_CT {
192 if (SMLCVTY.checkstate("Mapped")) {
193 /* skip initialization if already executed once */
194 return;
195 }
196 map(self:SMLCVTY, system:SMLCVTY);
197 f_vty_set_prompts(SMLCVTY);
198 f_vty_transceive(SMLCVTY, "enable");
199 f_cs7_inst_0_cfg(SMLCVTY, {"sccp-timer ias " & int2str(g_smlc_sccp_timer_ias),
200 "sccp-timer iar " & int2str(g_smlc_sccp_timer_iar)});
201}
202
203type function void_fn(charstring id) runs on BSC_ConnHdlr;
204
205private function f_connect_handler(inout BSC_ConnHdlr vc_conn, integer bssap_le_idx := 0) runs on test_CT {
206 connect(vc_conn:BSSAP_LE, g_bssap_le[bssap_le_idx].vc_BSSAP_LE:CLIENT);
207 connect(vc_conn:BSSAP_LE_PROC, g_bssap_le[bssap_le_idx].vc_BSSAP_LE:PROC);
208}
209
210function f_start_handler(void_fn fn, template (omit) TestHdlrParams pars := omit)
211runs on test_CT return BSC_ConnHdlr {
212 var charstring id := testcasename();
213 var BSC_ConnHdlr vc_conn;
214 var integer bssap_le_idx := 0;
215 if (isvalue(pars)) {
216 bssap_le_idx := valueof(pars).bssap_le_idx;
217 }
218 vc_conn := BSC_ConnHdlr.create(id);
219 f_connect_handler(vc_conn, bssap_le_idx);
220 /* Emit a marker to appear in the SUT's own logging output */
221 f_logp(SMLCVTY, testcasename() & "() start");
222 vc_conn.start(f_handler_init(fn, id, pars));
223 return vc_conn;
224}
225
226private function f_handler_init(void_fn fn, charstring id, template (omit) TestHdlrParams pars := omit)
227runs on BSC_ConnHdlr {
228 if (isvalue(pars)) {
229 g_pars := valueof(pars);
230 }
231 fn.apply(id);
232}
233
234type record of charstring Commands;
235
236private function f_cs7_inst_0_cfg(TELNETasp_PT pt, Commands cmds := {})
237{
238 f_vty_enter_cfg_cs7_inst(pt, 0);
239 for (var integer i := 0; i < sizeof(cmds); i := i+1) {
240 f_vty_transceive(pt, cmds[i]);
241 }
242 f_vty_transceive(pt, "end");
243}
244
245template (value) PDU_BSSAP_LE ts_BSSMAP_LE_BSSLAP(template (value) BSSLAP_PDU bsslap)
246 := ts_BSSMAP_LE_ConnInfo(BSSMAP_LE_PROT_BSSLAP, data := enc_BSSLAP_PDU(valueof(bsslap)));
247
248template PDU_BSSAP_LE tr_BSSMAP_LE_BSSLAP(template BSSLAP_PDU bsslap)
249 := tr_BSSMAP_LE_ConnInfo(BSSMAP_LE_PROT_BSSLAP, data := enc_BSSLAP_PDU(valueof(bsslap)));
250
251/* BSC sends Perform Location Request that already contains a TA Layer 3 BSSLAP APDU */
252private function f_tc_smlc_location_request_with_ta_l3(charstring id) runs on BSC_ConnHdlr {
253 f_sleep(1.0);
254
255 f_BscConnHdlr_init();
256 f_bssap_le_register_imsi(g_pars.imsi, omit);
257
258 var uint16_t cell_id := 42;
259 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
260
261 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
262 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi,
263 enc_BSSLAP_PDU(valueof(ts_BSSLAP_TA_Layer3(23)))))));
264 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
265
266 /* SMLC got the TA from the BSC, now responds with geo information data. */
267 /* TODO: implement GAD coding in ttcn */
268 /* Expecting geo:
269 * 0001 .... = Location estimate: Ellipsoid point with uncertainty Circle (1)
270 * 0... .... = Sign of latitude: North (0)
271 * .010 0001 0000 1001 1100 1001 = Degrees of latitude: 2165193 (23.23000 degrees)
272 * 0001 1110 0010 1010 0101 0011 = Degrees of longitude: 1976915 (42.42000 degrees)
273 * .100 1010 = Uncertainty code: 74 (11552.7 m)
274 * [Location OSM URI: https://www.openstreetmap.org/?mlat=23.23000&mlon=42.42000&zoom=12]
275 */
276 var octetstring geo := '102109C91E2A534A'O;
277 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(geo, omit));
278
279 f_sleep(2.0);
280 setverdict(pass);
281}
282testcase TC_smlc_location_request_with_ta_l3() runs on test_CT {
283 var BSC_ConnHdlr vc_conn;
284 var TestHdlrParams pars := f_gen_test_hdlr_pars();
285
286 f_init();
287 f_sleep(1.0);
288
289 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
290 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
291
292 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_with_ta_l3), pars);
293 vc_conn.done;
294}
295
296/* BSC sends Perform Location Request without BSSLAP APDU, SMLC needs to request TA */
297private function f_tc_smlc_location_request_without_ta_l3(charstring id) runs on BSC_ConnHdlr {
298 f_sleep(1.0);
299
300 f_BscConnHdlr_init();
301 f_bssap_le_register_imsi(g_pars.imsi, omit);
302
303 var uint16_t cell_id := 42;
304 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
305
306 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
307 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
308 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
309
310 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
311 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
312
313 /* BSC figures out the TA and sends it back to the SMLC */
314
315 BSSAP_LE.send(ts_BSSMAP_LE_BSSLAP(ts_BSSLAP_TA_Resp(cell_id, 23)));
316
317 /* SMLC got the TA from the BSC, now responds with geo information data. */
318 /* TODO: implement GAD coding in ttcn */
319 /* Expecting geo:
320 * 0001 .... = Location estimate: Ellipsoid point with uncertainty Circle (1)
321 * 0... .... = Sign of latitude: North (0)
322 * .010 0001 0000 1001 1100 1001 = Degrees of latitude: 2165193 (23.23000 degrees)
323 * 0001 1110 0010 1010 0101 0011 = Degrees of longitude: 1976915 (42.42000 degrees)
324 * .100 1010 = Uncertainty code: 74 (11552.7 m)
325 * [Location OSM URI: https://www.openstreetmap.org/?mlat=23.23000&mlon=42.42000&zoom=12]
326 */
327 var octetstring geo := '102109C91E2A534A'O;
328 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(geo, omit));
329
330 f_sleep(2.0);
331 setverdict(pass);
332}
333testcase TC_smlc_location_request_without_ta_l3() runs on test_CT {
334 var BSC_ConnHdlr vc_conn;
335 var TestHdlrParams pars := f_gen_test_hdlr_pars();
336
337 f_init(1);
338 f_sleep(1.0);
339
340 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
341 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
342
343 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_without_ta_l3), pars);
344 vc_conn.done;
345}
346
347/* BSC sends Perform Location Request, halfway the BSC indicates handover via BSSLAP Reset */
348private function f_tc_smlc_location_request_bsslap_reset(charstring id) runs on BSC_ConnHdlr {
349 f_sleep(1.0);
350
351 f_BscConnHdlr_init();
352 f_bssap_le_register_imsi(g_pars.imsi, omit);
353
354 var uint16_t cell_id := 1;
355 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(1, cell_id));
356
357 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
358 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
359 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
360
361 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
362 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
363
364 /* BSC reports a Handover via a BSSLAP Reset */
365 BSSAP_LE.send(ts_BSSMAP_LE_BSSLAP(ts_BSSLAP_Reset(17, 42,
366 valueof(ts_BSSLAP_IE_ChanDesc),
367 BSSLAP_CAUSE_INTRA_BSS_HO)));
368
369 /* SMLC got the TA from the BSC via BSSLAP Reset, now responds with geo information data. */
370 /* TODO: implement GAD coding in ttcn */
371 /* Expecting geo:
372 * 0001 .... = Location estimate: Ellipsoid point with uncertainty Circle (1)
373 * 0... .... = Sign of latitude: North (0)
374 * .000 1011 0011 1000 1011 0100 = Degrees of latitude: 735412 (7.89012 degrees)
375 * 0000 0110 0101 0100 0110 1011 = Degrees of longitude: 414827 (8.90122 degrees)
376 * .101 0001 = Uncertainty code: 81 (22522.4 m)
377 * [Location OSM URI: https://www.openstreetmap.org/?mlat=7.89012&mlon=8.90122&zoom=12]
378 */
379 var octetstring geo := '100B38B406546B51'O;
380 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(geo, omit));
381
382 f_sleep(2.0);
383 setverdict(pass);
384}
385testcase TC_smlc_location_request_bsslap_reset() runs on test_CT {
386 var BSC_ConnHdlr vc_conn;
387 var TestHdlrParams pars := f_gen_test_hdlr_pars();
388
389 f_init(1);
390 f_sleep(1.0);
391
392 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
393 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
394
395 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_bsslap_reset), pars);
396 vc_conn.done;
397}
398
399/* BSC sends Perform Location Request, halfway the BSC aborts the request because of inter-BSC HO */
400private function f_tc_smlc_location_request_abort(charstring id) runs on BSC_ConnHdlr {
401 f_sleep(1.0);
402
403 f_BscConnHdlr_init();
404 f_bssap_le_register_imsi(g_pars.imsi, omit);
405
406 var uint16_t cell_id := 42;
407 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
408
409 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
410 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
411 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
412
413 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
414 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
415
416 /* BSC aborts */
417 BSSAP_LE.send(ts_BSSMAP_LE_PerfLocAbort(BSSMAP_LE_LCS_CAUSE_INTER_BSC_HO));
418
419 var PDU_BSSAP_LE bssap_le;
420 timer nothing := 7.0;
421 nothing.start;
422 alt {
423 [] BSSAP_LE.receive(tr_BSSAP_LE_BSSMAP) -> value(bssap_le) {
424 log("unexpected bssap_le: ", bssap_le);
425 setverdict(fail, "No more messages expected from SMLC");
426 mtc.stop;
427 }
428 [] nothing.timeout {
429 setverdict(pass);
430 break;
431 }
432 }
433
434 f_sleep(2.0);
435 setverdict(pass);
436}
437testcase TC_smlc_location_request_abort() runs on test_CT {
438 var BSC_ConnHdlr vc_conn;
439 var TestHdlrParams pars := f_gen_test_hdlr_pars();
440
441 f_init(1);
442 f_sleep(1.0);
443
444 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
445 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
446
447 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_abort), pars);
448 vc_conn.done;
449}
450
451/* BSC sends Perform Location Request, SMLC asks for TA, halfway the BSC aborts the TA request */
452private function f_tc_smlc_location_request_bsslap_abort(charstring id) runs on BSC_ConnHdlr {
453 f_sleep(1.0);
454
455 f_BscConnHdlr_init();
456 f_bssap_le_register_imsi(g_pars.imsi, omit);
457
458 var uint16_t cell_id := 42;
459 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
460
461 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
462 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
463 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
464
465 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
466 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
467
468 /* BSC aborts the TA Request */
469 BSSAP_LE.send(ts_BSSMAP_LE_BSSLAP(ts_BSSLAP_Abort(BSSLAP_CAUSE_SUPERV_TIMER_EXPIRED)));
470
471 /* Expect response without location, just an LCS Cause indicating abort */
472 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(omit, BSSMAP_LE_LCS_CAUSE_REQUEST_ABORTED));
473
474 f_sleep(2.0);
475 setverdict(pass);
476}
477testcase TC_smlc_location_request_bsslap_abort() runs on test_CT {
478 var BSC_ConnHdlr vc_conn;
479 var TestHdlrParams pars := f_gen_test_hdlr_pars();
480
481 f_init(1);
482 f_sleep(1.0);
483
484 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
485 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
486
487 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_bsslap_abort), pars);
488 vc_conn.done;
489}
490
491control {
492if (true) {
493 execute( TC_smlc_location_request_without_ta_l3() );
494} else {
495 execute( TC_smlc_location_request_with_ta_l3() );
496 execute( TC_smlc_location_request_without_ta_l3() );
497 execute( TC_smlc_location_request_bsslap_reset() );
498 execute( TC_smlc_location_request_bsslap_abort() );
499 execute( TC_smlc_location_request_abort() );
500}
501}
502
503}