blob: 5d312f7ab54776e02395fd27e0849f011fa03871 [file] [log] [blame]
Daniel Willmann423d8f42020-09-08 18:58:22 +02001module GBProxy_Tests {
2
3/* Osmocom GBProxy test suite in TTCN-3
4 * (C) 2020 sysmocom - s.f.m.c. GmbH
5 * All rights reserved.
6 *
7 * Author: Daniel Willmann <dwillmann@sysmocom.de>
8
9 * Released under the terms of GNU General Public License, Version 2 or
10 * (at your option) any later version.
11 *
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 */
14
15import from General_Types all;
16import from Osmocom_Types all;
17import from GSM_Types all;
18import from Native_Functions all;
19import from NS_Types all;
20import from NS_Emulation all;
21import from BSSGP_Types all;
22import from BSSGP_Emulation all;
23import from SCCPasp_Types all;
24import from Osmocom_Gb_Types all;
25
26import from MobileL3_CommonIE_Types all;
27import from MobileL3_GMM_SM_Types all;
28import from MobileL3_Types all;
29import from L3_Templates all;
30import from L3_Common all;
31
32import from TELNETasp_PortType all;
33import from Osmocom_VTY_Functions all;
34
35import from LLC_Types all;
36import from LLC_Templates all;
37
38import from GSM_RR_Types all;
39
Harald Welte6d63f742020-11-15 19:44:04 +010040/* mcc_mnc is 24.008 10.5.5.15 encoded. 262 42 */
41const BcdMccMnc c_mcc_mnc := '262F42'H;
42
Daniel Willmann423d8f42020-09-08 18:58:22 +020043modulepar {
44 /* IP/port on which we run our internal GSUP/HLR emulation */
Harald Welte6d63f742020-11-15 19:44:04 +010045 NSConfigurations mp_nsconfig_sgsn := {
Daniel Willmann423d8f42020-09-08 18:58:22 +020046 {
Daniel Willmann423d8f42020-09-08 18:58:22 +020047 nsei := 101,
48 role_sgsn := true,
Harald Welte90f19742020-11-06 19:34:40 +010049 handle_sns := false,
50 nsvc := {
51 {
52 provider := {
53 ip := {
54 address_family := AF_INET,
55 local_udp_port := 7777,
56 local_ip := "127.0.0.1",
57 remote_udp_port := 23000,
58 remote_ip := "127.0.0.1"
59 }
60 },
61 nsvci := 101
62 }
63 }
Daniel Willmann423d8f42020-09-08 18:58:22 +020064 }
65 };
Harald Welte6d63f742020-11-15 19:44:04 +010066 NSConfigurations mp_nsconfig_pcu := {
Daniel Willmann423d8f42020-09-08 18:58:22 +020067 {
Daniel Willmann423d8f42020-09-08 18:58:22 +020068 nsei := 96,
69 role_sgsn := false,
Harald Welte90f19742020-11-06 19:34:40 +010070 handle_sns := false,
71 nsvc := {
72 {
73 provider := {
74 ip := {
75 address_family := AF_INET,
76 local_udp_port := 21010,
77 local_ip := "127.0.0.1",
78 remote_udp_port := 23000,
79 remote_ip := "127.0.0.1"
80 }
81 },
82 nsvci := 97
83 }
84 }
Daniel Willmann423d8f42020-09-08 18:58:22 +020085 },
86 {
Daniel Willmann423d8f42020-09-08 18:58:22 +020087 nsei := 97,
88 role_sgsn := false,
Harald Welte90f19742020-11-06 19:34:40 +010089 handle_sns := false,
90 nsvc := {
91 {
92 provider := {
93 ip := {
94 address_family := AF_INET,
95 local_udp_port := 21011,
96 local_ip := "127.0.0.1",
97 remote_udp_port := 23000,
98 remote_ip := "127.0.0.1"
99 }
100 },
101 nsvci := 98
102 }
103 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200104 },
105 {
Daniel Willmann423d8f42020-09-08 18:58:22 +0200106 nsei := 98,
107 role_sgsn := false,
Harald Welte90f19742020-11-06 19:34:40 +0100108 handle_sns := false,
109 nsvc := {
110 {
111 provider := {
112 ip := {
113 address_family := AF_INET,
114 local_udp_port := 21012,
115 local_ip := "127.0.0.1",
116 remote_udp_port := 23000,
117 remote_ip := "127.0.0.1"
118 }
119 },
120 nsvci := 99
121 }
122 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200123 }
124 };
Harald Welte6d63f742020-11-15 19:44:04 +0100125 BssgpConfigs mp_gbconfigs := {
126 {
127 nsei := 96,
128 sgsn_role := false,
129 bvc := {
130 {
131 bvci := 196,
132 cell_id := {
133 ra_id := {
134 lai := {
135 mcc_mnc := c_mcc_mnc,
136 lac := 13135
137 },
138 rac := 0
139 },
140 cell_id := 20960
141 },
142 depth := BSSGP_DECODE_DEPTH_BSSGP,
143 create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
144 }
145 }
146 }, {
147 nsei := 97,
148 sgsn_role := false,
149 bvc := {
150 {
151 bvci := 210,
152 cell_id := {
153 ra_id := {
154 lai := {
155 mcc_mnc := c_mcc_mnc,
156 lac := 13200
157 },
158 rac := 0
159 },
160 cell_id := 20961
161 },
162 depth := BSSGP_DECODE_DEPTH_BSSGP,
163 create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
164 }
165 }
166 }, {
167 nsei := 98,
168 sgsn_role := false,
169 bvc := {
170 {
171 bvci := 220,
172 cell_id := {
173 ra_id := {
174 lai := {
175 mcc_mnc := c_mcc_mnc,
176 lac := 13300
177 },
178 rac := 0
179 },
180 cell_id := 20962
181 },
182 depth := BSSGP_DECODE_DEPTH_BSSGP,
183 create_cb := refers(BSSGP_Emulation.DefaultCreateCallback)
184 }
185 }
186 }
187 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200188};
189
190const integer NUM_BVC_PER_NSE := 3;
191type record GbInstance {
192 NS_CT vc_NS,
193 BSSGP_CT vc_BSSGP,
194 BSSGP_BVC_CT vc_BSSGP_BVC[NUM_BVC_PER_NSE],
195 BssgpConfig cfg
196};
197
198const integer NUM_PCU := 3;
Harald Welte6d63f742020-11-15 19:44:04 +0100199type record of GbInstance GbInstances;
200type record of BssgpConfig BssgpConfigs;
201type record of NSConfiguration NSConfigurations;
202type record of BssgpCellId BssgpCellIds;
Daniel Willmann423d8f42020-09-08 18:58:22 +0200203
204const integer NUM_SGSN := 1;
Daniel Willmann423d8f42020-09-08 18:58:22 +0200205
206type component test_CT {
Harald Welte6d63f742020-11-15 19:44:04 +0100207 var GbInstances g_pcu;
208 var GbInstances g_sgsn;
Daniel Willmann423d8f42020-09-08 18:58:22 +0200209
210 port BSSGP_CT_PROC_PT PROC;
211
212 port TELNETasp_PT GBPVTY;
213
214 var boolean g_initialized := false;
215 var boolean g_use_echo := false;
216};
217
218type component BSSGP_ConnHdlr {
219 port BSSGP_PT PCU[NUM_PCU];
220 port BSSGP_PT PCU_SIG[NUM_PCU];
221 port BSSGP_PROC_PT PCU_PROC[NUM_PCU];
222 port BSSGP_PT SGSN[NUM_SGSN];
223 port BSSGP_PT SGSN_SIG[NUM_SGSN];
224 port BSSGP_PROC_PT SGSN_PROC[NUM_SGSN];
225
226 var BSSGP_ConnHdlrPars g_pars;
227 timer g_Tguard;
228 var LLC_Entities llc;
229}
230
231type record SGSN_ConnHdlrNetworkPars {
232 boolean expect_ptmsi,
233 boolean expect_auth,
234 boolean expect_ciph
235};
236
237type record BSSGP_ConnHdlrPars {
238 /* IMEI of the simulated ME */
239 hexstring imei,
240 /* IMSI of the simulated MS */
241 hexstring imsi,
242 /* MSISDN of the simulated MS (probably unused) */
243 hexstring msisdn,
244 /* P-TMSI allocated to the simulated MS */
245 OCT4 p_tmsi optional,
246 OCT3 p_tmsi_sig optional,
247 /* TLLI of the simulated MS */
248 OCT4 tlli,
249 OCT4 tlli_old optional,
250 RoutingAreaIdentificationV ra optional,
251 BssgpCellIds bssgp_cell_id,
252 float t_guard
253};
254
255private function f_cellid_to_RAI(in BssgpCellId cell_id) return RoutingAreaIdentificationV {
256 /* mcc_mnc is encoded as of 24.008 10.5.5.15 */
257 var BcdMccMnc mcc_mnc := cell_id.ra_id.lai.mcc_mnc;
258
259 var RoutingAreaIdentificationV ret := {
260 mccDigit1 := mcc_mnc[0],
261 mccDigit2 := mcc_mnc[1],
262 mccDigit3 := mcc_mnc[2],
263 mncDigit3 := mcc_mnc[3],
264 mncDigit1 := mcc_mnc[4],
265 mncDigit2 := mcc_mnc[5],
266 lac := int2oct(cell_id.ra_id.lai.lac, 16),
267 rac := int2oct(cell_id.ra_id.rac, 8)
268 }
269 return ret;
270};
271
272private function f_init_gb_pcu(inout GbInstance gb, charstring id, integer offset) runs on test_CT {
Harald Welteb419d0e2020-11-16 16:45:05 +0100273 var charstring ns_id := id & "-NS(PCU[" & int2str(offset) & "])";
274 var charstring bssgp_id := id & "-BSSGP(PCU[" & int2str(offset) & "])";
275 gb.vc_NS := NS_CT.create(ns_id);
276 gb.vc_BSSGP := BSSGP_CT.create(bssgp_id);
Daniel Willmann423d8f42020-09-08 18:58:22 +0200277 /* connect lower end of BSSGP emulation with NS upper port */
278 connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP);
279
Harald Welteb419d0e2020-11-16 16:45:05 +0100280 gb.vc_NS.start(NSStart(mp_nsconfig_pcu[offset], ns_id));
281 gb.vc_BSSGP.start(BssgpStart(gb.cfg, bssgp_id));
Daniel Willmann423d8f42020-09-08 18:58:22 +0200282
283 for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) {
284 connect(self:PROC, gb.vc_BSSGP:PROC);
285 gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC);
286 disconnect(self:PROC, gb.vc_BSSGP:PROC);
287 }
288}
289
290private function f_init_gb_sgsn(inout GbInstance gb, charstring id, integer offset) runs on test_CT {
Harald Welteb419d0e2020-11-16 16:45:05 +0100291 var charstring ns_id := id & "-NS(SGSN[" & int2str(offset) & "])";
292 var charstring bssgp_id := id & "-BSSGP(SGSN[" & int2str(offset) & "])";
293 gb.vc_NS := NS_CT.create(ns_id);
294 gb.vc_BSSGP := BSSGP_CT.create(bssgp_id);
Daniel Willmann423d8f42020-09-08 18:58:22 +0200295 /* connect lower end of BSSGP emulation with NS upper port */
296 connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP);
297
Harald Welteb419d0e2020-11-16 16:45:05 +0100298 gb.vc_NS.start(NSStart(mp_nsconfig_sgsn[offset], ns_id));
299 gb.vc_BSSGP.start(BssgpStart(gb.cfg, bssgp_id));
Daniel Willmann423d8f42020-09-08 18:58:22 +0200300
301 for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) {
302 connect(self:PROC, gb.vc_BSSGP:PROC);
303 gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC);
304 disconnect(self:PROC, gb.vc_BSSGP:PROC);
305 }
306}
307
308
309private function f_init_vty() runs on test_CT {
310 map(self:GBPVTY, system:GBPVTY);
311 f_vty_set_prompts(GBPVTY);
312 f_vty_transceive(GBPVTY, "enable");
313}
314
Harald Welte6d63f742020-11-15 19:44:04 +0100315function f_init() runs on test_CT {
Daniel Willmann423d8f42020-09-08 18:58:22 +0200316 var integer i;
317
318 if (g_initialized == true) {
319 return;
320 }
321 g_initialized := true;
Daniel Willmann423d8f42020-09-08 18:58:22 +0200322
323 g_sgsn[0].cfg := {
Harald Welte6d63f742020-11-15 19:44:04 +0100324 nsei := mp_nsconfig_sgsn[0].nsei,
Daniel Willmann423d8f42020-09-08 18:58:22 +0200325 sgsn_role := true,
Harald Welte6d63f742020-11-15 19:44:04 +0100326 bvc := { }
327 }
328 for (i := 0; i < lengthof(mp_gbconfigs); i := i+1) {
329 g_pcu[i].cfg := mp_gbconfigs[i];
330 /* concatenate all the PCU-side BVCs for the SGSN side */
331 g_sgsn[0].cfg.bvc := g_sgsn[0].cfg.bvc & mp_gbconfigs[i].bvc;
332 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200333
334 f_init_vty();
Harald Welte6d63f742020-11-15 19:44:04 +0100335 for (i := 0; i < lengthof(mp_nsconfig_sgsn); i := i+1) {
Harald Welteb419d0e2020-11-16 16:45:05 +0100336 f_init_gb_sgsn(g_sgsn[0], "GbProxy_Test", 0);
Harald Welte6d63f742020-11-15 19:44:04 +0100337 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200338 f_sleep(4.0);
Harald Welte6d63f742020-11-15 19:44:04 +0100339 for (i := 0; i < lengthof(mp_nsconfig_pcu); i := i+1) {
Harald Welteb419d0e2020-11-16 16:45:05 +0100340 f_init_gb_pcu(g_pcu[i], "GbProxy_Test", i);
Harald Welte6d63f742020-11-15 19:44:04 +0100341 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200342}
343
344function f_cleanup() runs on test_CT {
345 self.stop;
346}
347
348type function void_fn(charstring id) runs on BSSGP_ConnHdlr;
349
350/* helper function to create, connect and start a BSSGP_ConnHdlr component */
Harald Welte6d63f742020-11-15 19:44:04 +0100351function f_start_handler(void_fn fn, charstring id, GbInstances pcu, GbInstances sgsn, integer imsi_suffix,
Daniel Willmann423d8f42020-09-08 18:58:22 +0200352 float t_guard := 30.0)
353runs on test_CT return BSSGP_ConnHdlr {
354 var BSSGP_ConnHdlr vc_conn;
355
356 var BSSGP_ConnHdlrPars pars := {
357 imei := f_gen_imei(imsi_suffix),
358 imsi := f_gen_imsi(imsi_suffix),
359 msisdn := f_gen_msisdn(imsi_suffix),
360 p_tmsi := omit,
361 p_tmsi_sig := omit,
362 tlli := f_gprs_tlli_random(),
363 tlli_old := omit,
364 ra := omit,
365 bssgp_cell_id := { pcu[0].cfg.bvc[0].cell_id, pcu[1].cfg.bvc[0].cell_id, pcu[2].cfg.bvc[0].cell_id },
366 t_guard := t_guard
367 };
368
369 vc_conn := BSSGP_ConnHdlr.create(id);
370 // PDU side
371 connect(vc_conn:PCU[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_SP);
372 connect(vc_conn:PCU_SIG[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
373 connect(vc_conn:PCU_PROC[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_PROC);
374 connect(vc_conn:PCU[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_SP);
375 connect(vc_conn:PCU_SIG[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
376 connect(vc_conn:PCU_PROC[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_PROC);
377 connect(vc_conn:PCU[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_SP);
378 connect(vc_conn:PCU_SIG[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
379 connect(vc_conn:PCU_PROC[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_PROC);
380 // SGSN side
381 connect(vc_conn:SGSN[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_SP);
382 connect(vc_conn:SGSN_SIG[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
383 connect(vc_conn:SGSN_PROC[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_PROC);
384
385 vc_conn.start(f_handler_init(fn, id, pars));
386 return vc_conn;
387}
388
389private altstep as_Tguard() runs on BSSGP_ConnHdlr {
390 [] g_Tguard.timeout {
391 setverdict(fail, "Tguard timeout");
392 mtc.stop;
393 }
394}
395
396/* first function called in every ConnHdlr */
397private function f_handler_init(void_fn fn, charstring id, BSSGP_ConnHdlrPars pars)
398runs on BSSGP_ConnHdlr {
399 /* do some common stuff like setting up g_pars */
400 g_pars := pars;
401
402 llc := f_llc_create(false);
403
404
405 g_Tguard.start(pars.t_guard);
406 activate(as_Tguard());
407
408 /* call the user-supplied test case function */
409 fn.apply(id);
410}
411
412/* TODO:
413 * Detach without Attach
414 * SM procedures without attach / RAU
415 * ATTACH / RAU
416 ** with / without authentication
417 ** with / without P-TMSI allocation
418 * re-transmissions of LLC frames
419 * PDP Context activation
420 ** with different GGSN config in SGSN VTY
421 ** with different PDP context type (v4/v6/v46)
422 ** timeout from GGSN
423 ** multiple / secondary PDP context
424 */
425
426private function f_TC_BVC_bringup(charstring id) runs on BSSGP_ConnHdlr {
427 f_sleep(5.0);
428 setverdict(pass);
429}
430
431testcase TC_BVC_bringup() runs on test_CT {
432 var BSSGP_ConnHdlr vc_conn;
433 f_init();
434
435 vc_conn := f_start_handler(refers(f_TC_BVC_bringup), testcasename(), g_pcu, g_sgsn, 51);
436 vc_conn.done;
437
438 f_cleanup();
439}
440
441friend function f_bssgp_suspend(integer ran_idx := 0) runs on BSSGP_ConnHdlr return OCT1 {
442 timer T := 5.0;
443 var PDU_BSSGP rx_pdu;
444 PCU_SIG[ran_idx].send(ts_BSSGP_SUSPEND(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
445 T.start;
446 alt {
447 [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_ACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, ?)) -> value rx_pdu {
448 return rx_pdu.pDU_BSSGP_SUSPEND_ACK.suspend_Reference_Number.suspend_Reference_Number_value;
449 }
450 [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_NACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, ?)) -> value rx_pdu {
451 setverdict(fail, "SUSPEND-NACK in response to SUSPEND for TLLI ", g_pars.tlli);
452 mtc.stop;
453 }
454 [] T.timeout {
455 setverdict(fail, "No SUSPEND-ACK in response to SUSPEND for TLLI ", g_pars.tlli);
456 mtc.stop;
457 }
458 }
459 return '00'O;
460}
461
462friend function f_bssgp_resume(OCT1 susp_ref, integer ran_idx := 0) runs on BSSGP_ConnHdlr {
463 timer T := 5.0;
464 PCU_SIG[ran_idx].send(ts_BSSGP_RESUME(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, susp_ref));
465 T.start;
466 alt {
467 [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_ACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
468 [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_NACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id,
469?)) {
470 setverdict(fail, "RESUME-NACK in response to RESUME for TLLI ", g_pars.tlli);
471 mtc.stop;
472 }
473 [] T.timeout {
474 setverdict(fail, "No RESUME-ACK in response to SUSPEND for TLLI ", g_pars.tlli);
475 mtc.stop;
476 }
477 }
478}
479
480
481control {
482 execute( TC_BVC_bringup() );
483}
484
485
486}