blob: 580d567d51db5386f61093d09742e707ad04242c [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
40modulepar {
41 /* IP/port on which we run our internal GSUP/HLR emulation */
42 NSConfigurations_SGSN mp_nsconfig_sgsn := {
43 {
Daniel Willmann423d8f42020-09-08 18:58:22 +020044 nsei := 101,
45 role_sgsn := true,
Harald Welte90f19742020-11-06 19:34:40 +010046 handle_sns := false,
47 nsvc := {
48 {
49 provider := {
50 ip := {
51 address_family := AF_INET,
52 local_udp_port := 7777,
53 local_ip := "127.0.0.1",
54 remote_udp_port := 23000,
55 remote_ip := "127.0.0.1"
56 }
57 },
58 nsvci := 101
59 }
60 }
Daniel Willmann423d8f42020-09-08 18:58:22 +020061 }
62 };
63 NSConfigurations_PCU mp_nsconfig_pcu := {
64 {
Daniel Willmann423d8f42020-09-08 18:58:22 +020065 nsei := 96,
66 role_sgsn := false,
Harald Welte90f19742020-11-06 19:34:40 +010067 handle_sns := false,
68 nsvc := {
69 {
70 provider := {
71 ip := {
72 address_family := AF_INET,
73 local_udp_port := 21010,
74 local_ip := "127.0.0.1",
75 remote_udp_port := 23000,
76 remote_ip := "127.0.0.1"
77 }
78 },
79 nsvci := 97
80 }
81 }
Daniel Willmann423d8f42020-09-08 18:58:22 +020082 },
83 {
Daniel Willmann423d8f42020-09-08 18:58:22 +020084 nsei := 97,
85 role_sgsn := false,
Harald Welte90f19742020-11-06 19:34:40 +010086 handle_sns := false,
87 nsvc := {
88 {
89 provider := {
90 ip := {
91 address_family := AF_INET,
92 local_udp_port := 21011,
93 local_ip := "127.0.0.1",
94 remote_udp_port := 23000,
95 remote_ip := "127.0.0.1"
96 }
97 },
98 nsvci := 98
99 }
100 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200101 },
102 {
Daniel Willmann423d8f42020-09-08 18:58:22 +0200103 nsei := 98,
104 role_sgsn := false,
Harald Welte90f19742020-11-06 19:34:40 +0100105 handle_sns := false,
106 nsvc := {
107 {
108 provider := {
109 ip := {
110 address_family := AF_INET,
111 local_udp_port := 21012,
112 local_ip := "127.0.0.1",
113 remote_udp_port := 23000,
114 remote_ip := "127.0.0.1"
115 }
116 },
117 nsvci := 99
118 }
119 }
Daniel Willmann423d8f42020-09-08 18:58:22 +0200120 }
121 };
122};
123
124const integer NUM_BVC_PER_NSE := 3;
125type record GbInstance {
126 NS_CT vc_NS,
127 BSSGP_CT vc_BSSGP,
128 BSSGP_BVC_CT vc_BSSGP_BVC[NUM_BVC_PER_NSE],
129 BssgpConfig cfg
130};
131
132const integer NUM_PCU := 3;
133type record length(NUM_PCU) of GbInstance GbInstances_PCU;
134type record length(NUM_PCU) of NSConfiguration NSConfigurations_PCU;
135type record length(NUM_PCU) of BssgpCellId BssgpCellIds;
136
137const integer NUM_SGSN := 1;
138type record length(NUM_SGSN) of GbInstance GbInstances_SGSN;
139type record length(NUM_SGSN) of NSConfiguration NSConfigurations_SGSN;
140
141type component test_CT {
142 var GbInstances_PCU g_pcu;
143 var GbInstances_SGSN g_sgsn;
144
145 port BSSGP_CT_PROC_PT PROC;
146
147 port TELNETasp_PT GBPVTY;
148
149 var boolean g_initialized := false;
150 var boolean g_use_echo := false;
151};
152
153type component BSSGP_ConnHdlr {
154 port BSSGP_PT PCU[NUM_PCU];
155 port BSSGP_PT PCU_SIG[NUM_PCU];
156 port BSSGP_PROC_PT PCU_PROC[NUM_PCU];
157 port BSSGP_PT SGSN[NUM_SGSN];
158 port BSSGP_PT SGSN_SIG[NUM_SGSN];
159 port BSSGP_PROC_PT SGSN_PROC[NUM_SGSN];
160
161 var BSSGP_ConnHdlrPars g_pars;
162 timer g_Tguard;
163 var LLC_Entities llc;
164}
165
166type record SGSN_ConnHdlrNetworkPars {
167 boolean expect_ptmsi,
168 boolean expect_auth,
169 boolean expect_ciph
170};
171
172type record BSSGP_ConnHdlrPars {
173 /* IMEI of the simulated ME */
174 hexstring imei,
175 /* IMSI of the simulated MS */
176 hexstring imsi,
177 /* MSISDN of the simulated MS (probably unused) */
178 hexstring msisdn,
179 /* P-TMSI allocated to the simulated MS */
180 OCT4 p_tmsi optional,
181 OCT3 p_tmsi_sig optional,
182 /* TLLI of the simulated MS */
183 OCT4 tlli,
184 OCT4 tlli_old optional,
185 RoutingAreaIdentificationV ra optional,
186 BssgpCellIds bssgp_cell_id,
187 float t_guard
188};
189
190private function f_cellid_to_RAI(in BssgpCellId cell_id) return RoutingAreaIdentificationV {
191 /* mcc_mnc is encoded as of 24.008 10.5.5.15 */
192 var BcdMccMnc mcc_mnc := cell_id.ra_id.lai.mcc_mnc;
193
194 var RoutingAreaIdentificationV ret := {
195 mccDigit1 := mcc_mnc[0],
196 mccDigit2 := mcc_mnc[1],
197 mccDigit3 := mcc_mnc[2],
198 mncDigit3 := mcc_mnc[3],
199 mncDigit1 := mcc_mnc[4],
200 mncDigit2 := mcc_mnc[5],
201 lac := int2oct(cell_id.ra_id.lai.lac, 16),
202 rac := int2oct(cell_id.ra_id.rac, 8)
203 }
204 return ret;
205};
206
207private function f_init_gb_pcu(inout GbInstance gb, charstring id, integer offset) runs on test_CT {
208 gb.vc_NS := NS_CT.create(id & "-NS(PCU)" & int2str(offset));
209 gb.vc_BSSGP := BSSGP_CT.create(id & "-BSSGP(PCU)" & int2str(offset));
210 /* connect lower end of BSSGP emulation with NS upper port */
211 connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP);
212
213 gb.vc_NS.start(NSStart(mp_nsconfig_pcu[offset]));
214 gb.vc_BSSGP.start(BssgpStart(gb.cfg, id));
215
216 for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) {
217 connect(self:PROC, gb.vc_BSSGP:PROC);
218 gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC);
219 disconnect(self:PROC, gb.vc_BSSGP:PROC);
220 }
221}
222
223private function f_init_gb_sgsn(inout GbInstance gb, charstring id, integer offset) runs on test_CT {
224 gb.vc_NS := NS_CT.create(id & "-NS(SGSN)" & int2str(offset));
225 gb.vc_BSSGP := BSSGP_CT.create(id & "-BSSGP(SGSN)" & int2str(offset));
226 /* connect lower end of BSSGP emulation with NS upper port */
227 connect(gb.vc_BSSGP:BSCP, gb.vc_NS:NS_SP);
228
229 gb.vc_NS.start(NSStart(mp_nsconfig_sgsn[offset]));
230 gb.vc_BSSGP.start(BssgpStart(gb.cfg, id));
231
232 for (var integer i := 0; i < lengthof(gb.cfg.bvc); i := i + 1) {
233 connect(self:PROC, gb.vc_BSSGP:PROC);
234 gb.vc_BSSGP_BVC[i] := f_bssgp_get_bvci_ct(gb.cfg.bvc[i].bvci, PROC);
235 disconnect(self:PROC, gb.vc_BSSGP:PROC);
236 }
237}
238
239
240private function f_init_vty() runs on test_CT {
241 map(self:GBPVTY, system:GBPVTY);
242 f_vty_set_prompts(GBPVTY);
243 f_vty_transceive(GBPVTY, "enable");
244}
245
246/* mcc_mnc is 24.008 10.5.5.15 encoded. 262 42 */
247function f_init(BcdMccMnc mcc_mnc := '262F42'H) runs on test_CT {
248 var integer i;
249
250 if (g_initialized == true) {
251 return;
252 }
253 g_initialized := true;
254 g_pcu[0].cfg := {
255 nsei := 96,
256 sgsn_role := false,
257 bvc := { {
258 bvci := 196,
259 cell_id := {
260 ra_id := {
261 lai := {
262 mcc_mnc := mcc_mnc, lac := 13135},
263 rac := 0
264 },
265 cell_id := 20960
266 },
267 depth := BSSGP_DECODE_DEPTH_BSSGP
268 } }
269 };
270 g_pcu[1].cfg := {
271 nsei := 97,
272 sgsn_role := false,
273 bvc := { {
274 bvci := 210,
275 cell_id := {
276 ra_id := {
277 lai := {
278 mcc_mnc := mcc_mnc, lac := 13200},
279 rac := 0
280 },
281 cell_id := 20961
282 },
283 depth := BSSGP_DECODE_DEPTH_BSSGP
284 } }
285 };
286 g_pcu[2].cfg := {
287 nsei := 98,
288 sgsn_role := false,
289 bvc := { {
290 bvci := 220,
291 cell_id := {
292 ra_id := {
293 lai := {
294 mcc_mnc := mcc_mnc, lac := 13300},
295 rac := 0
296 },
297 cell_id := 20962
298 },
299 depth := BSSGP_DECODE_DEPTH_BSSGP
300 } }
301 };
302
303 g_sgsn[0].cfg := {
304 nsei := 101,
305 sgsn_role := true,
306 bvc := {
307 {
308 bvci := 196,
309 cell_id := {
310 ra_id := {
311 lai := {
312 mcc_mnc := mcc_mnc, lac := 13135},
313 rac := 0
314 },
315 cell_id := 20960
316 },
317 depth := BSSGP_DECODE_DEPTH_BSSGP
318 },
319 {
320 bvci := 210,
321 cell_id := {
322 ra_id := {
323 lai := {
324 mcc_mnc := mcc_mnc, lac := 13200},
325 rac := 0
326 },
327 cell_id := 20961
328 },
329 depth := BSSGP_DECODE_DEPTH_BSSGP
330 },
331 {
332 bvci := 220,
333 cell_id := {
334 ra_id := {
335 lai := {
336 mcc_mnc := mcc_mnc, lac := 13300},
337 rac := 0
338 },
339 cell_id := 20962
340 },
341 depth := BSSGP_DECODE_DEPTH_BSSGP
342 }
343 }
344 };
345
346 f_init_vty();
347 f_init_gb_sgsn(g_sgsn[0], "GbProxy_Test-SGSN0", 0);
348 f_sleep(4.0);
349 f_init_gb_pcu(g_pcu[0], "GbProxy_Test-PCU0", 0);
350 f_init_gb_pcu(g_pcu[1], "GbProxy_Test-PCU1", 1);
351 f_init_gb_pcu(g_pcu[2], "GbProxy_Test-PCU2", 2);
352}
353
354function f_cleanup() runs on test_CT {
355 self.stop;
356}
357
358type function void_fn(charstring id) runs on BSSGP_ConnHdlr;
359
360/* helper function to create, connect and start a BSSGP_ConnHdlr component */
361function f_start_handler(void_fn fn, charstring id, GbInstances_PCU pcu, GbInstances_SGSN sgsn, integer imsi_suffix,
362 float t_guard := 30.0)
363runs on test_CT return BSSGP_ConnHdlr {
364 var BSSGP_ConnHdlr vc_conn;
365
366 var BSSGP_ConnHdlrPars pars := {
367 imei := f_gen_imei(imsi_suffix),
368 imsi := f_gen_imsi(imsi_suffix),
369 msisdn := f_gen_msisdn(imsi_suffix),
370 p_tmsi := omit,
371 p_tmsi_sig := omit,
372 tlli := f_gprs_tlli_random(),
373 tlli_old := omit,
374 ra := omit,
375 bssgp_cell_id := { pcu[0].cfg.bvc[0].cell_id, pcu[1].cfg.bvc[0].cell_id, pcu[2].cfg.bvc[0].cell_id },
376 t_guard := t_guard
377 };
378
379 vc_conn := BSSGP_ConnHdlr.create(id);
380 // PDU side
381 connect(vc_conn:PCU[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_SP);
382 connect(vc_conn:PCU_SIG[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
383 connect(vc_conn:PCU_PROC[0], pcu[0].vc_BSSGP_BVC[0]:BSSGP_PROC);
384 connect(vc_conn:PCU[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_SP);
385 connect(vc_conn:PCU_SIG[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
386 connect(vc_conn:PCU_PROC[1], pcu[1].vc_BSSGP_BVC[0]:BSSGP_PROC);
387 connect(vc_conn:PCU[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_SP);
388 connect(vc_conn:PCU_SIG[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
389 connect(vc_conn:PCU_PROC[2], pcu[2].vc_BSSGP_BVC[0]:BSSGP_PROC);
390 // SGSN side
391 connect(vc_conn:SGSN[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_SP);
392 connect(vc_conn:SGSN_SIG[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_SP_SIG);
393 connect(vc_conn:SGSN_PROC[0], sgsn[0].vc_BSSGP_BVC[0]:BSSGP_PROC);
394
395 vc_conn.start(f_handler_init(fn, id, pars));
396 return vc_conn;
397}
398
399private altstep as_Tguard() runs on BSSGP_ConnHdlr {
400 [] g_Tguard.timeout {
401 setverdict(fail, "Tguard timeout");
402 mtc.stop;
403 }
404}
405
406/* first function called in every ConnHdlr */
407private function f_handler_init(void_fn fn, charstring id, BSSGP_ConnHdlrPars pars)
408runs on BSSGP_ConnHdlr {
409 /* do some common stuff like setting up g_pars */
410 g_pars := pars;
411
412 llc := f_llc_create(false);
413
414
415 g_Tguard.start(pars.t_guard);
416 activate(as_Tguard());
417
418 /* call the user-supplied test case function */
419 fn.apply(id);
420}
421
422/* TODO:
423 * Detach without Attach
424 * SM procedures without attach / RAU
425 * ATTACH / RAU
426 ** with / without authentication
427 ** with / without P-TMSI allocation
428 * re-transmissions of LLC frames
429 * PDP Context activation
430 ** with different GGSN config in SGSN VTY
431 ** with different PDP context type (v4/v6/v46)
432 ** timeout from GGSN
433 ** multiple / secondary PDP context
434 */
435
436private function f_TC_BVC_bringup(charstring id) runs on BSSGP_ConnHdlr {
437 f_sleep(5.0);
438 setverdict(pass);
439}
440
441testcase TC_BVC_bringup() runs on test_CT {
442 var BSSGP_ConnHdlr vc_conn;
443 f_init();
444
445 vc_conn := f_start_handler(refers(f_TC_BVC_bringup), testcasename(), g_pcu, g_sgsn, 51);
446 vc_conn.done;
447
448 f_cleanup();
449}
450
451friend function f_bssgp_suspend(integer ran_idx := 0) runs on BSSGP_ConnHdlr return OCT1 {
452 timer T := 5.0;
453 var PDU_BSSGP rx_pdu;
454 PCU_SIG[ran_idx].send(ts_BSSGP_SUSPEND(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
455 T.start;
456 alt {
457 [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_ACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, ?)) -> value rx_pdu {
458 return rx_pdu.pDU_BSSGP_SUSPEND_ACK.suspend_Reference_Number.suspend_Reference_Number_value;
459 }
460 [] PCU_SIG[ran_idx].receive(tr_BSSGP_SUSPEND_NACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, ?)) -> value rx_pdu {
461 setverdict(fail, "SUSPEND-NACK in response to SUSPEND for TLLI ", g_pars.tlli);
462 mtc.stop;
463 }
464 [] T.timeout {
465 setverdict(fail, "No SUSPEND-ACK in response to SUSPEND for TLLI ", g_pars.tlli);
466 mtc.stop;
467 }
468 }
469 return '00'O;
470}
471
472friend function f_bssgp_resume(OCT1 susp_ref, integer ran_idx := 0) runs on BSSGP_ConnHdlr {
473 timer T := 5.0;
474 PCU_SIG[ran_idx].send(ts_BSSGP_RESUME(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id, susp_ref));
475 T.start;
476 alt {
477 [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_ACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id));
478 [] PCU_SIG[ran_idx].receive(tr_BSSGP_RESUME_NACK(g_pars.tlli, g_pars.bssgp_cell_id[ran_idx].ra_id,
479?)) {
480 setverdict(fail, "RESUME-NACK in response to RESUME for TLLI ", g_pars.tlli);
481 mtc.stop;
482 }
483 [] T.timeout {
484 setverdict(fail, "No RESUME-ACK in response to SUSPEND for TLLI ", g_pars.tlli);
485 mtc.stop;
486 }
487 }
488}
489
490
491control {
492 execute( TC_BVC_bringup() );
493}
494
495
496}