blob: 2a5066619458315961e083d59e4f558c91ae1d4e [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
Neels Hofmeyr5c5b2762020-10-01 06:35:56 +0200159/* global initialization function
160 * \param nr_bts Number of BTSs we should start/bring up
161 * \param handler_mode Start an RSL_Emulation_CT component (true) or not (false).
162 * \param nr_msc Number of virtual MSCs to bring up to connect to osmo-bsc.
163 */
164function f_init(integer nr_bsc := NUM_BSC, float guard_timeout := 30.0) runs on test_CT {
165 var integer bssap_le_idx;
166
167 if (g_initialized) {
168 return;
169 }
170 g_initialized := true;
171
172 T_guard.start(guard_timeout);
173 activate(as_Tguard());
174
175 f_init_vty("VirtBSC");
176
177 for (bssap_le_idx := 0; bssap_le_idx < nr_bsc; bssap_le_idx := bssap_le_idx+1) {
178 f_bssap_le_adapter_init(g_bssap_le[bssap_le_idx], mp_bssap_le_cfg[bssap_le_idx], "VirtBSC", BSC_BssapLeOps);
179 f_bssap_le_adapter_start(g_bssap_le[bssap_le_idx]);
180 }
181}
182
183function f_init_vty(charstring id := "foo") runs on test_CT {
184 if (SMLCVTY.checkstate("Mapped")) {
185 /* skip initialization if already executed once */
186 return;
187 }
188 map(self:SMLCVTY, system:SMLCVTY);
189 f_vty_set_prompts(SMLCVTY);
190 f_vty_transceive(SMLCVTY, "enable");
191 f_cs7_inst_0_cfg(SMLCVTY, {"sccp-timer ias " & int2str(g_smlc_sccp_timer_ias),
192 "sccp-timer iar " & int2str(g_smlc_sccp_timer_iar)});
193}
194
195type function void_fn(charstring id) runs on BSC_ConnHdlr;
196
197private function f_connect_handler(inout BSC_ConnHdlr vc_conn, integer bssap_le_idx := 0) runs on test_CT {
198 connect(vc_conn:BSSAP_LE, g_bssap_le[bssap_le_idx].vc_BSSAP_LE:CLIENT);
199 connect(vc_conn:BSSAP_LE_PROC, g_bssap_le[bssap_le_idx].vc_BSSAP_LE:PROC);
200}
201
202function f_start_handler(void_fn fn, template (omit) TestHdlrParams pars := omit)
203runs on test_CT return BSC_ConnHdlr {
204 var charstring id := testcasename();
205 var BSC_ConnHdlr vc_conn;
206 var integer bssap_le_idx := 0;
207 if (isvalue(pars)) {
208 bssap_le_idx := valueof(pars).bssap_le_idx;
209 }
210 vc_conn := BSC_ConnHdlr.create(id);
211 f_connect_handler(vc_conn, bssap_le_idx);
212 /* Emit a marker to appear in the SUT's own logging output */
213 f_logp(SMLCVTY, testcasename() & "() start");
214 vc_conn.start(f_handler_init(fn, id, pars));
215 return vc_conn;
216}
217
218private function f_handler_init(void_fn fn, charstring id, template (omit) TestHdlrParams pars := omit)
219runs on BSC_ConnHdlr {
220 if (isvalue(pars)) {
221 g_pars := valueof(pars);
222 }
223 fn.apply(id);
224}
225
226type record of charstring Commands;
227
228private function f_cs7_inst_0_cfg(TELNETasp_PT pt, Commands cmds := {})
229{
230 f_vty_enter_cfg_cs7_inst(pt, 0);
231 for (var integer i := 0; i < sizeof(cmds); i := i+1) {
232 f_vty_transceive(pt, cmds[i]);
233 }
234 f_vty_transceive(pt, "end");
235}
236
237template (value) PDU_BSSAP_LE ts_BSSMAP_LE_BSSLAP(template (value) BSSLAP_PDU bsslap)
238 := ts_BSSMAP_LE_ConnInfo(BSSMAP_LE_PROT_BSSLAP, data := enc_BSSLAP_PDU(valueof(bsslap)));
239
240template PDU_BSSAP_LE tr_BSSMAP_LE_BSSLAP(template BSSLAP_PDU bsslap)
241 := tr_BSSMAP_LE_ConnInfo(BSSMAP_LE_PROT_BSSLAP, data := enc_BSSLAP_PDU(valueof(bsslap)));
242
243/* BSC sends Perform Location Request that already contains a TA Layer 3 BSSLAP APDU */
244private function f_tc_smlc_location_request_with_ta_l3(charstring id) runs on BSC_ConnHdlr {
245 f_sleep(1.0);
246
247 f_BscConnHdlr_init();
248 f_bssap_le_register_imsi(g_pars.imsi, omit);
249
250 var uint16_t cell_id := 42;
251 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
252
253 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
254 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi,
255 enc_BSSLAP_PDU(valueof(ts_BSSLAP_TA_Layer3(23)))))));
256 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
257
258 /* SMLC got the TA from the BSC, now responds with geo information data. */
259 /* TODO: implement GAD coding in ttcn */
260 /* Expecting geo:
261 * 0001 .... = Location estimate: Ellipsoid point with uncertainty Circle (1)
262 * 0... .... = Sign of latitude: North (0)
263 * .010 0001 0000 1001 1100 1001 = Degrees of latitude: 2165193 (23.23000 degrees)
264 * 0001 1110 0010 1010 0101 0011 = Degrees of longitude: 1976915 (42.42000 degrees)
265 * .100 1010 = Uncertainty code: 74 (11552.7 m)
266 * [Location OSM URI: https://www.openstreetmap.org/?mlat=23.23000&mlon=42.42000&zoom=12]
267 */
268 var octetstring geo := '102109C91E2A534A'O;
269 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(geo, omit));
270
271 f_sleep(2.0);
272 setverdict(pass);
273}
274testcase TC_smlc_location_request_with_ta_l3() runs on test_CT {
275 var BSC_ConnHdlr vc_conn;
276 var TestHdlrParams pars := f_gen_test_hdlr_pars();
277
278 f_init();
279 f_sleep(1.0);
280
281 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
282 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
283
284 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_with_ta_l3), pars);
285 vc_conn.done;
286}
287
288/* BSC sends Perform Location Request without BSSLAP APDU, SMLC needs to request TA */
289private function f_tc_smlc_location_request_without_ta_l3(charstring id) runs on BSC_ConnHdlr {
290 f_sleep(1.0);
291
292 f_BscConnHdlr_init();
293 f_bssap_le_register_imsi(g_pars.imsi, omit);
294
295 var uint16_t cell_id := 42;
296 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
297
298 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
299 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
300 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
301
302 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
303 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
304
305 /* BSC figures out the TA and sends it back to the SMLC */
306
307 BSSAP_LE.send(ts_BSSMAP_LE_BSSLAP(ts_BSSLAP_TA_Resp(cell_id, 23)));
308
309 /* SMLC got the TA from the BSC, now responds with geo information data. */
310 /* TODO: implement GAD coding in ttcn */
311 /* Expecting geo:
312 * 0001 .... = Location estimate: Ellipsoid point with uncertainty Circle (1)
313 * 0... .... = Sign of latitude: North (0)
314 * .010 0001 0000 1001 1100 1001 = Degrees of latitude: 2165193 (23.23000 degrees)
315 * 0001 1110 0010 1010 0101 0011 = Degrees of longitude: 1976915 (42.42000 degrees)
316 * .100 1010 = Uncertainty code: 74 (11552.7 m)
317 * [Location OSM URI: https://www.openstreetmap.org/?mlat=23.23000&mlon=42.42000&zoom=12]
318 */
319 var octetstring geo := '102109C91E2A534A'O;
320 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(geo, omit));
321
322 f_sleep(2.0);
323 setverdict(pass);
324}
325testcase TC_smlc_location_request_without_ta_l3() runs on test_CT {
326 var BSC_ConnHdlr vc_conn;
327 var TestHdlrParams pars := f_gen_test_hdlr_pars();
328
329 f_init(1);
330 f_sleep(1.0);
331
332 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
333 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
334
335 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_without_ta_l3), pars);
336 vc_conn.done;
337}
338
339/* BSC sends Perform Location Request, halfway the BSC indicates handover via BSSLAP Reset */
340private function f_tc_smlc_location_request_bsslap_reset(charstring id) runs on BSC_ConnHdlr {
341 f_sleep(1.0);
342
343 f_BscConnHdlr_init();
344 f_bssap_le_register_imsi(g_pars.imsi, omit);
345
346 var uint16_t cell_id := 1;
347 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(1, cell_id));
348
349 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
350 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
351 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
352
353 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
354 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
355
356 /* BSC reports a Handover via a BSSLAP Reset */
357 BSSAP_LE.send(ts_BSSMAP_LE_BSSLAP(ts_BSSLAP_Reset(17, 42,
358 valueof(ts_BSSLAP_IE_ChanDesc),
359 BSSLAP_CAUSE_INTRA_BSS_HO)));
360
361 /* SMLC got the TA from the BSC via BSSLAP Reset, now responds with geo information data. */
362 /* TODO: implement GAD coding in ttcn */
363 /* Expecting geo:
364 * 0001 .... = Location estimate: Ellipsoid point with uncertainty Circle (1)
365 * 0... .... = Sign of latitude: North (0)
366 * .000 1011 0011 1000 1011 0100 = Degrees of latitude: 735412 (7.89012 degrees)
367 * 0000 0110 0101 0100 0110 1011 = Degrees of longitude: 414827 (8.90122 degrees)
368 * .101 0001 = Uncertainty code: 81 (22522.4 m)
369 * [Location OSM URI: https://www.openstreetmap.org/?mlat=7.89012&mlon=8.90122&zoom=12]
370 */
371 var octetstring geo := '100B38B406546B51'O;
372 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(geo, omit));
373
374 f_sleep(2.0);
375 setverdict(pass);
376}
377testcase TC_smlc_location_request_bsslap_reset() runs on test_CT {
378 var BSC_ConnHdlr vc_conn;
379 var TestHdlrParams pars := f_gen_test_hdlr_pars();
380
381 f_init(1);
382 f_sleep(1.0);
383
384 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
385 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
386
387 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_bsslap_reset), pars);
388 vc_conn.done;
389}
390
391/* BSC sends Perform Location Request, halfway the BSC aborts the request because of inter-BSC HO */
392private function f_tc_smlc_location_request_abort(charstring id) runs on BSC_ConnHdlr {
393 f_sleep(1.0);
394
395 f_BscConnHdlr_init();
396 f_bssap_le_register_imsi(g_pars.imsi, omit);
397
398 var uint16_t cell_id := 42;
399 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
400
401 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
402 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
403 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
404
405 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
406 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
407
408 /* BSC aborts */
409 BSSAP_LE.send(ts_BSSMAP_LE_PerfLocAbort(BSSMAP_LE_LCS_CAUSE_INTER_BSC_HO));
410
411 var PDU_BSSAP_LE bssap_le;
412 timer nothing := 7.0;
413 nothing.start;
414 alt {
415 [] BSSAP_LE.receive(tr_BSSAP_LE_BSSMAP) -> value(bssap_le) {
416 log("unexpected bssap_le: ", bssap_le);
417 setverdict(fail, "No more messages expected from SMLC");
418 mtc.stop;
419 }
420 [] nothing.timeout {
421 setverdict(pass);
422 break;
423 }
424 }
425
426 f_sleep(2.0);
427 setverdict(pass);
428}
429testcase TC_smlc_location_request_abort() runs on test_CT {
430 var BSC_ConnHdlr vc_conn;
431 var TestHdlrParams pars := f_gen_test_hdlr_pars();
432
433 f_init(1);
434 f_sleep(1.0);
435
436 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
437 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
438
439 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_abort), pars);
440 vc_conn.done;
441}
442
443/* BSC sends Perform Location Request, SMLC asks for TA, halfway the BSC aborts the TA request */
444private function f_tc_smlc_location_request_bsslap_abort(charstring id) runs on BSC_ConnHdlr {
445 f_sleep(1.0);
446
447 f_BscConnHdlr_init();
448 f_bssap_le_register_imsi(g_pars.imsi, omit);
449
450 var uint16_t cell_id := 42;
451 var BSSMAP_IE_CellIdentifier cell_ident := valueof(ts_CellID_LAC_CI(23, cell_id));
452
453 BSSAP_LE.send(ts_BSSAP_LE_Conn_Req(g_pars.sccp_addr_smlc, g_pars.sccp_addr_bsc,
454 valueof(ts_BSSMAP_LE_PerfLocReq(BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC_LOC, cell_ident, g_pars.imsi))));
455 BSSAP_LE.receive(BSSAP_LE_Conn_Prim:CONN_PRIM_CONF_IND);
456
457 /* SMLC wants to ask the TA from the SMLC explicitly in a BSSLAP TA Request message */
458 BSSAP_LE.receive(tr_BSSMAP_LE_BSSLAP(tr_BSSLAP_TA_Req));
459
460 /* BSC aborts the TA Request */
461 BSSAP_LE.send(ts_BSSMAP_LE_BSSLAP(ts_BSSLAP_Abort(BSSLAP_CAUSE_SUPERV_TIMER_EXPIRED)));
462
463 /* Expect response without location, just an LCS Cause indicating abort */
464 BSSAP_LE.receive(tr_BSSMAP_LE_PerfLocResp(omit, BSSMAP_LE_LCS_CAUSE_REQUEST_ABORTED));
465
466 f_sleep(2.0);
467 setverdict(pass);
468}
469testcase TC_smlc_location_request_bsslap_abort() runs on test_CT {
470 var BSC_ConnHdlr vc_conn;
471 var TestHdlrParams pars := f_gen_test_hdlr_pars();
472
473 f_init(1);
474 f_sleep(1.0);
475
476 pars.sccp_addr_bsc := g_bssap_le[0].sccp_addr_own;
477 pars.sccp_addr_smlc := g_bssap_le[0].sccp_addr_peer;
478
479 vc_conn := f_start_handler(refers(f_tc_smlc_location_request_bsslap_abort), pars);
480 vc_conn.done;
481}
482
483control {
Neels Hofmeyr5c5b2762020-10-01 06:35:56 +0200484 execute( TC_smlc_location_request_with_ta_l3() );
485 execute( TC_smlc_location_request_without_ta_l3() );
486 execute( TC_smlc_location_request_bsslap_reset() );
487 execute( TC_smlc_location_request_bsslap_abort() );
488 execute( TC_smlc_location_request_abort() );
489}
Neels Hofmeyr5c5b2762020-10-01 06:35:56 +0200490
491}