blob: b6bd1adcf4dd6435b1228b03287ca323c32d48ee [file] [log] [blame]
Harald Welte78cae922018-03-01 10:12:56 +01001module HLR_Tests {
Harald Weltedf327232017-12-28 22:51:51 +01002
Harald Welte34b5a952019-05-27 11:54:11 +02003/* HLR test suite in TTCN-3
4 * (C) 2017-2018 Harald Welte <laforge@gnumonks.org>
5 * (C) 2018 sysmocom - s.f.m.c. GmbH
6 * (C) 2018 Vadim Yanitskiy <axilirator@gmail.com>
7 * All rights reserved.
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
15
16
Harald Weltedf327232017-12-28 22:51:51 +010017import from GSUP_Types all;
Harald Welteed380d12018-06-14 13:42:11 +020018import from GSUP_Emulation all;
Harald Weltedf327232017-12-28 22:51:51 +010019import from IPA_Emulation all;
20
Harald Weltec2c52552018-03-01 21:20:39 +010021import from General_Types all;
22import from Osmocom_Types all;
Harald Welte39b82d32018-03-01 10:21:29 +010023import from Osmocom_CTRL_Adapter all;
24
Harald Welte4ea1f8a2018-06-12 09:26:10 +020025import from TCCEncoding_Functions all;
26import from SS_Types all;
27import from SS_Templates all;
28import from MAP_Errors all;
29import from USSD_Helpers all;
30
Harald Welte39b82d32018-03-01 10:21:29 +010031import from Osmocom_VTY_Functions all;
32import from TELNETasp_PortType all;
33
34type component test_CT extends CTRL_Adapter_CT {
Harald Weltedf327232017-12-28 22:51:51 +010035 var IPA_Emulation_CT vc_IPA;
36 var IPA_CCM_Parameters ccm_pars;
Harald Welteed380d12018-06-14 13:42:11 +020037 /* legacy tests without ConnHdlr */
Harald Weltedf327232017-12-28 22:51:51 +010038 port IPA_GSUP_PT GSUP;
Harald Welteed380d12018-06-14 13:42:11 +020039 /* new tests using ConnHdlr + GSUP_Emulation */
40 var GSUP_Emulation_CT vc_GSUP;
41 /* only to get events from IPA underneath GSUP */
42 port IPA_CTRL_PT GSUP_IPA_EVENT;
Harald Welte39b82d32018-03-01 10:21:29 +010043
44 port TELNETasp_PT VTY;
Harald Weltec2c52552018-03-01 21:20:39 +010045
46 timer g_Tguard := 10.0;
Harald Weltedf327232017-12-28 22:51:51 +010047};
48
49modulepar {
50 charstring mp_hlr_ip := "127.0.0.1";
51 integer mp_hlr_gsup_port := 4222;
52 integer mp_hlr_ctrl_port := 4259;
53};
54
Harald Weltec2c52552018-03-01 21:20:39 +010055type record HlrSubscrAud2G {
56 charstring algo,
57 OCT16 ki
58}
59
60type record HlrSubscrAud3G {
61 charstring algo,
62 OCT16 k,
63 OCT16 op,
64 boolean op_is_opc
65}
66
67type record HlrSubscriber {
68 hexstring imsi,
69 hexstring msisdn,
70 HlrSubscrAud2G aud2g optional,
71 HlrSubscrAud3G aud3g optional
72}
73
74type record of HlrSubscriber HlrSubscriberList;
75
Harald Welteed380d12018-06-14 13:42:11 +020076type component HLR_ConnHdlr extends GSUP_ConnHdlr {
77 timer g_Tguard := 10.0;
78 var HLR_ConnHdlrPars g_pars;
79 port TELNETasp_PT VTY;
80}
81
82type record HLR_ConnHdlrPars {
Harald Welte4ea1f8a2018-06-12 09:26:10 +020083 HlrSubscriber sub,
84 HLR_ConnHdlrParsUssd ussd optional
85}
86
87type record HLR_ConnHdlrParsUssd {
88 OCT4 sid
Harald Welteed380d12018-06-14 13:42:11 +020089}
90
91template (value) HLR_ConnHdlrPars t_Pars(hexstring imsi, hexstring msisdn := ''H) := {
92 sub := {
93 imsi := imsi,
94 msisdn := msisdn,
95 aud2g := omit,
96 aud3g := omit
Harald Welte4ea1f8a2018-06-12 09:26:10 +020097 },
98 ussd := omit
Harald Welteed380d12018-06-14 13:42:11 +020099}
100
101template (value) HLR_ConnHdlrPars t_Pars_sub(HlrSubscriber sub) := {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200102 sub := sub,
103 ussd := omit
Harald Welteed380d12018-06-14 13:42:11 +0200104}
105
106type function void_fn() runs on HLR_ConnHdlr;
107
108/***********************************************************************
109 * Main Component
110 ***********************************************************************/
111
112function f_init_vty() runs on test_CT {
113 map(self:VTY, system:VTY);
114 f_vty_set_prompts(VTY);
115 f_vty_transceive(VTY, "enable");
116}
117
118private altstep as_Tguard() runs on test_CT {
119 [] g_Tguard.timeout {
120 setverdict(fail, "g_Tguard timeout");
Daniel Willmannafce8662018-07-06 23:11:32 +0200121 mtc.stop;
Harald Welteed380d12018-06-14 13:42:11 +0200122 }
123}
124
125function f_init_gsup(charstring id, boolean legacy) runs on test_CT {
126 id := id & "-GSUP";
127 var GsupOps ops := {
128 create_cb := refers(GSUP_Emulation.ExpectedCreateCallback)
129 }
130
131 ccm_pars := c_IPA_default_ccm_pars;
132 ccm_pars.name := "Osmocom TTCN-3 GSUP Simulator";
Harald Welte4a3242e2018-06-24 22:28:53 +0200133 ccm_pars.ser_nr := "MSC-00-00-00-00-00-00";
Harald Welteed380d12018-06-14 13:42:11 +0200134
135 vc_IPA := IPA_Emulation_CT.create(id & "-IPA");
136 log("legacy= ", legacy);
137 if (not legacy) {
138 log("in not legacy case 1");
139 vc_GSUP := GSUP_Emulation_CT.create(id);
140 }
141
142 map(vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
143 if (not legacy) {
144 log("in not legacy case 2");
145 connect(vc_GSUP:GSUP, vc_IPA:IPA_GSUP_PORT);
146 connect(vc_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT);
147 vc_GSUP.start(GSUP_Emulation.main(ops, id));
148 } else {
149 connect(vc_IPA:IPA_GSUP_PORT, self:GSUP);
150 }
151
152 vc_IPA.start(IPA_Emulation.main_client(mp_hlr_ip, mp_hlr_gsup_port, "", -1, ccm_pars));
153
154 /* wait for incoming connection to GSUP port before proceeding */
155 timer T := 10.0;
156 T.start;
157 alt {
158 [not legacy] GSUP_IPA_EVENT.receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)) { }
159 [legacy] GSUP.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { }
160 [] T.timeout {
161 setverdict(fail, "No connection to GSUP Port");
Daniel Willmannafce8662018-07-06 23:11:32 +0200162 mtc.stop;
Harald Welteed380d12018-06-14 13:42:11 +0200163 }
164 }
165}
166
167function f_init(boolean legacy := true) runs on test_CT {
168
169 /* activate default guard timer to ensure all tests eventually terminate */
170 g_Tguard.start;
171 activate(as_Tguard());
172
173 f_init_gsup("HLR_Test", legacy);
174 f_init_vty();
175
176 f_ipa_ctrl_start(mp_hlr_ip, mp_hlr_ctrl_port);
177}
178
179function f_start_handler(void_fn fn, HLR_ConnHdlrPars pars) runs on test_CT return HLR_ConnHdlr {
180 var HLR_ConnHdlr vc_conn;
181 var charstring id := testcasename();
182
183 vc_conn := HLR_ConnHdlr.create(id);
184 connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
185 connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
186
187 vc_conn.start(f_handler_init(fn, id, pars));
188 return vc_conn;
189}
190
191private function f_handler_init_vty() runs on HLR_ConnHdlr {
192 map(self:VTY, system:VTY);
193 f_vty_set_prompts(VTY);
194 f_vty_transceive(VTY, "enable");
195}
196
197/* first function inside ConnHdlr component; sets g_pars + starts function */
198function f_handler_init(void_fn fn, charstring id, template (omit) HLR_ConnHdlrPars pars := omit)
199runs on HLR_ConnHdlr
200{
201 if (isvalue(pars)) {
202 g_pars := valueof(pars);
203 f_create_gsup_expect(hex2str(g_pars.sub.imsi));
204 }
205 f_handler_init_vty();
206 fn.apply();
207}
208
209/***********************************************************************
210 * Subscriber creation via VTY
211 ***********************************************************************/
212
Harald Weltec2c52552018-03-01 21:20:39 +0100213template (value) HlrSubscriber t_SubNoAuth(hexstring imsi, hexstring msisdn) := {
214 imsi := imsi,
215 msisdn := msisdn,
216 aud2g := omit,
217 aud3g := omit
218}
219
220const OCT16 c_KI_DEFAULT := '000102030405060708090a0b0c0d0e0f'O;
221const OCT16 c_K_DEFAULT := '101112131415161718191a1b1c1d1e1f'O;
222const OCT16 c_OP_DEFAULT := '202122232425262728292a2b2c2d2e2f'O;
223//const OCT16 c_OPC_DEFAULT := '303132333435363738393a3b3c3d3f'O;
224
225template (value) HlrSubscriber t_Sub2G(hexstring imsi, hexstring msisdn, charstring algo) := {
226 imsi := imsi,
227 msisdn := msisdn,
228 aud2g := {
229 algo := algo,
230 ki := c_KI_DEFAULT
231 },
232 aud3g := omit
233}
234
235template (value) HlrSubscriber t_Sub3G(hexstring imsi, hexstring msisdn, charstring algo, boolean is_opc) := {
236 imsi := imsi,
237 msisdn := msisdn,
238 aud2g := omit,
239 aud3g := {
240 algo := algo,
241 k := c_K_DEFAULT,
242 op := c_OP_DEFAULT,
243 op_is_opc := is_opc
244 }
245}
246
247template (value) HlrSubscriber t_Sub2G3G(hexstring imsi, hexstring msisdn, charstring algo2g, charstring algo3g, boolean is_opc) := {
248 imsi := imsi,
249 msisdn := msisdn,
250 aud2g := {
251 algo := algo2g,
252 ki := c_KI_DEFAULT
253 },
254 aud3g := {
255 algo := algo3g,
256 k := c_K_DEFAULT,
257 op := c_OP_DEFAULT,
258 op_is_opc := is_opc
259 }
260}
261
262/* generate a variety of subscribers with different parameters */
263function f_gen_subs() runs on test_CT return HlrSubscriberList {
264 var HlrSubscriber sub;
265 var HlrSubscriberList sl := {};
266
267 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
268 sl := sl & { sub };
269
270 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v2"));
271 sl := sl & { sub };
272
273 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v3"));
274 sl := sl & { sub };
275
276 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "milenage", false));
277 sl := sl & { sub };
278
279 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "milenage", true));
280 sl := sl & { sub };
281
282 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
283 "comp128v1", "milenage", false));
284 sl := sl & { sub };
285
286 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
287 "comp128v2", "milenage", false));
288 sl := sl & { sub };
289
290 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
291 "comp128v3", "milenage", false));
292 sl := sl & { sub };
293
294 return sl;
295}
296
Harald Welteed380d12018-06-14 13:42:11 +0200297function f_vty_transceive_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
298 var charstring ret := f_vty_transceive_ret(pt, cmd);
299 if (not match(ret, exp_ret)) {
300 setverdict(fail, "Non-matching VTY response: ", ret);
Daniel Willmannafce8662018-07-06 23:11:32 +0200301 mtc.stop;
Harald Weltec2c52552018-03-01 21:20:39 +0100302 }
303}
304
Harald Welte70296062018-03-01 22:42:03 +0100305private template (value) charstring t_subscr_prefix(hexstring imsi) :=
306 "subscriber imsi " & hex2str(imsi) & " ";
307
Harald Weltec2c52552018-03-01 21:20:39 +0100308/* create a given subscriber using the VTY */
Harald Welteed380d12018-06-14 13:42:11 +0200309function f_vty_subscr_create(TELNETasp_PT VTY, HlrSubscriber sub) {
Harald Welte70296062018-03-01 22:42:03 +0100310 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100311 f_vty_transceive_match(VTY, prefix & "create", pattern "% Created subscriber *");
312 f_vty_transceive_match(VTY, prefix & "update msisdn " & hex2str(sub.msisdn),
313 pattern "% Updated subscriber *");
314 if (ispresent(sub.aud2g)) {
315 f_vty_transceive_match(VTY, prefix & "update aud2g " & sub.aud2g.algo &
316 " ki " & oct2str(sub.aud2g.ki),
317 pattern "");
318 } else {
319 f_vty_transceive_match(VTY, prefix & "update aud2g none", pattern "");
320 }
321
322 if (ispresent(sub.aud3g)) {
323 var charstring op_mode := "op";
324 if (sub.aud3g.op_is_opc) {
325 op_mode := "opc";
326 }
327 f_vty_transceive_match(VTY, prefix & "update aud3g " & sub.aud3g.algo &
328 " k " & oct2str(sub.aud3g.k) & " " & op_mode & " " &
329 oct2str(sub.aud3g.op), pattern "");
330 } else {
331 f_vty_transceive_match(VTY, prefix & "update aud3g none", pattern "");
332 }
333}
334
Harald Welteed380d12018-06-14 13:42:11 +0200335function f_vty_subscr_update_msisdn(TELNETasp_PT VTY, HlrSubscriber sub, hexstring new_msisdn) {
Harald Welte09b3c502018-03-01 22:42:22 +0100336 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
337 f_vty_transceive_match(VTY, prefix & "update msisdn " & hex2str(new_msisdn),
338 pattern "% Updated subscriber *");
339}
340
Harald Weltec2c52552018-03-01 21:20:39 +0100341/* perform 'delete' on subscriber */
Harald Welteed380d12018-06-14 13:42:11 +0200342function f_vty_subscr_delete(TELNETasp_PT VTY, HlrSubscriber sub) {
Harald Welte70296062018-03-01 22:42:03 +0100343 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100344 f_vty_transceive_match(VTY, prefix & "delete",
345 pattern "% Deleted subscriber for IMSI *");
346}
347
348/* perform 'show' on subscriber; match result with pattern 'exp' */
Harald Welteed380d12018-06-14 13:42:11 +0200349function f_vty_subscr_show(TELNETasp_PT VTY, HlrSubscriber sub, template charstring exp) {
Harald Welte70296062018-03-01 22:42:03 +0100350 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100351 f_vty_transceive_match(VTY, prefix & "show", exp);
352}
353
354
Harald Welteed380d12018-06-14 13:42:11 +0200355/***********************************************************************
356 * Helper functions for ConnHdlr
357 ***********************************************************************/
358
Harald Weltec2c52552018-03-01 21:20:39 +0100359/* perform SendAuthInfo for given imsi, return the GSUP response/error */
360function f_perform_SAI(hexstring imsi, template (omit) integer exp_err_cause := omit)
Harald Welteed380d12018-06-14 13:42:11 +0200361runs on HLR_ConnHdlr return GSUP_PDU {
Harald Weltec2c52552018-03-01 21:20:39 +0100362 var GSUP_PDU ret;
363 timer T := 3.0;
364 var boolean exp_fail := false;
365 if (not istemplatekind(exp_err_cause, "omit")) {
366 exp_fail := true;
367 }
368
369 GSUP.send(valueof(ts_GSUP_SAI_REQ(imsi)));
370 T.start;
371 alt {
372 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, exp_err_cause)) -> value ret {
373 setverdict(pass);
374 }
375 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
376 setverdict(fail, "Unexpected SAI ERROR Cause");
377 }
378 [exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
379 setverdict(fail, "Unexpected SAI.res for unknown IMSI");
380 }
381 [not exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
382 setverdict(fail, "Unexpected SAI ERROR");
383 }
384 [not exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
385 setverdict(pass);
386 }
387 [] GSUP.receive { repeat; }
388 [] T.timeout {
389 setverdict(fail, "Timeout waiting for SAI response");
Daniel Willmannafce8662018-07-06 23:11:32 +0200390 mtc.stop;
Harald Weltec2c52552018-03-01 21:20:39 +0100391 }
392 }
393 return ret;
394}
395
396function f_perform_UL(hexstring imsi, template hexstring msisdn,
397 template (omit) integer exp_err_cause := omit)
Harald Welteed380d12018-06-14 13:42:11 +0200398runs on HLR_ConnHdlr return GSUP_PDU {
Harald Weltec2c52552018-03-01 21:20:39 +0100399 var GSUP_PDU ret;
400 timer T := 3.0;
401 var boolean exp_fail := false;
402 var boolean isd_done := false;
403 if (not istemplatekind(exp_err_cause, "omit")) {
404 exp_fail := true;
405 }
406
407 GSUP.send(valueof(ts_GSUP_UL_REQ(imsi)));
408 T.start;
409 alt {
410 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause)) -> value ret {
411 setverdict(pass);
412 }
413 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
414 setverdict(fail, "Unexpected UL ERROR Cause");
415 }
416 [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
417 setverdict(fail, "Unexpected UL.res for unknown IMSI");
418 }
419 [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi)) -> value ret {
420 setverdict(fail, "Unexpected ISD.req in error case");
421 }
422 [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
423 setverdict(fail, "Unexpected UL ERROR");
424 }
425 [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn)) -> value ret {
426 GSUP.send(ts_GSUP_ISD_RES(imsi));
427 isd_done := true;
Harald Welte8f0c9332018-03-01 23:38:40 +0100428 repeat;
Harald Weltec2c52552018-03-01 21:20:39 +0100429 }
430 [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
431 setverdict(pass);
432 }
433 [] GSUP.receive { repeat; }
434 [] T.timeout {
435 setverdict(fail, "Timeout waiting for UL response");
Daniel Willmannafce8662018-07-06 23:11:32 +0200436 mtc.stop;
Harald Weltec2c52552018-03-01 21:20:39 +0100437 }
438 }
439 return ret;
440}
441
Harald Welte958f8b42018-03-01 23:40:17 +0100442/* perform PurgeMS for given imsi, return the GSUP response/error */
443function f_perform_PURGE(hexstring imsi, GSUP_CnDomain cn_dom,
444 template (omit) integer exp_err_cause := omit)
Harald Welteed380d12018-06-14 13:42:11 +0200445runs on HLR_ConnHdlr return GSUP_PDU {
Harald Welte958f8b42018-03-01 23:40:17 +0100446 var GSUP_PDU ret;
447 timer T := 3.0;
448 var boolean exp_fail := false;
449 if (not istemplatekind(exp_err_cause, "omit")) {
450 exp_fail := true;
451 }
452
453 GSUP.send(valueof(ts_GSUP_PURGE_MS_REQ(imsi, cn_dom)));
454 T.start;
455 alt {
456 [exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_ERR(imsi, exp_err_cause)) -> value ret {
457 setverdict(pass);
458 }
459 [exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_ERR(imsi, ?)) -> value ret {
460 setverdict(fail, "Unexpected PURGE ERROR Cause");
461 }
462 [exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_RES(imsi)) -> value ret {
463 setverdict(fail, "Unexpected PURGE.res for unknown IMSI");
464 }
465 [not exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_ERR(imsi, ?)) -> value ret {
466 setverdict(fail, "Unexpected PURGE ERROR");
467 }
468 [not exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_RES(imsi)) -> value ret {
469 setverdict(pass);
470 }
471 [] GSUP.receive { repeat; }
472 [] T.timeout {
473 setverdict(fail, "Timeout waiting for PURGE response");
Daniel Willmannafce8662018-07-06 23:11:32 +0200474 mtc.stop;
Harald Welte958f8b42018-03-01 23:40:17 +0100475 }
476 }
477 return ret;
478}
479
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200480function f_SS_xceive(hexstring imsi, OCT4 sid, GSUP_SessionState state, octetstring ss,
481 template (omit) integer exp_err_cause := omit)
482runs on HLR_ConnHdlr return GSUP_PDU {
483 var GSUP_PDU ret;
484 timer T := 3.0;
485 var boolean exp_fail := false;
486 if (not istemplatekind(exp_err_cause, "omit")) {
487 exp_fail := true;
488 }
489
490 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(imsi, sid, state, ss)));
491 T.start;
492 alt {
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700493 [exp_fail] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, exp_err_cause)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200494 setverdict(pass);
495 }
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700496 [exp_fail] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, ?)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200497 setverdict(fail, "Unexpected PROC_SS ERROR Cause");
498 }
499 [exp_fail] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, ?, ?)) -> value ret {
500 setverdict(fail, "Unexpected PROC_SS.res for unknown IMSI");
501 }
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700502 [not exp_fail] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, ?)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200503 setverdict(fail, "Unexpected PROC_SS ERROR");
504 }
505 [not exp_fail] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, ?, ?)) -> value ret {
506 setverdict(pass);
507 }
508 [] GSUP.receive { repeat; }
509 [] T.timeout {
510 setverdict(fail, "Timeout waiting for PROC_SS response");
511 self.stop;
512 }
513 }
514 return ret;
515}
516
517private function f_SS_expect(hexstring imsi, OCT4 sid, GSUP_SessionState state,
518 template SS_FacilityInformation facility := *)
519runs on HLR_ConnHdlr return GSUP_PDU {
520 var GSUP_PDU ret;
521 timer T := 3.0;
522 var boolean exp_ss := true;
523 if (istemplatekind(facility, "omit")) {
524 exp_ss := false;
525 }
526 T.start;
527 alt {
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700528 [] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, ?)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200529 setverdict(fail, "Unexpected PROC_SS ERROR Cause");
530 }
531 [not exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, omit)) -> value ret {
532 setverdict(pass);
533 }
534 [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, omit)) -> value ret {
535 setverdict(fail, "Unexpected PROC_SS.res without SS IE");
536 }
537/*
538 [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, decmatch facility)) -> value ret {
539 setverdict(pass);
540 }
541*/
542
543 [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, ?)) -> value ret {
544 var GSUP_IeValue ss_ie;
545 f_gsup_find_ie(ret, OSMO_GSUP_SS_INFO_IE, ss_ie);
546 var SS_FacilityInformation dec_fac := dec_SS_FacilityInformation(ss_ie.ss_info);
547 log("pattern: ", facility);
548 if (match(dec_fac, facility)) {
549 setverdict(pass);
550 } else {
551 setverdict(fail, "Unexpected PROC_SS.res with non-matching facility IE");
552 }
553 }
554 [] GSUP.receive { repeat; }
555 [] T.timeout {
556 setverdict(fail, "Timeout waiting for PROC_SS response");
557 self.stop;
558 }
559 }
560
561 return ret;
562}
563
564
Harald Welte958f8b42018-03-01 23:40:17 +0100565
Harald Welteed380d12018-06-14 13:42:11 +0200566/***********************************************************************
567 * Testcases
568 ***********************************************************************/
569
570/* 23.003 Section 2.2 clearly states that an IMSI with less
571 * than 5 digits is impossible. Even 5 digits is still questionable */
572private function f_TC_gsup_sai_err_invalid_imsi() runs on HLR_ConnHdlr {
Harald Weltec2c52552018-03-01 21:20:39 +0100573 var GSUP_PDU res;
Harald Welteed380d12018-06-14 13:42:11 +0200574 res := f_perform_SAI(g_pars.sub.imsi, 96); /* Invalid Mandatory information */
575 setverdict(pass);
576}
577testcase TC_gsup_sai_err_invalid_imsi() runs on test_CT {
578 var HLR_ConnHdlr vc_conn;
579 var HLR_ConnHdlrPars pars := valueof(t_Pars('0123'H));
580 f_init(false);
581 vc_conn := f_start_handler(refers(f_TC_gsup_sai_err_invalid_imsi), pars);
582 vc_conn.done;
583}
Harald Weltec2c52552018-03-01 21:20:39 +0100584
Harald Weltec2c52552018-03-01 21:20:39 +0100585
Harald Welteed380d12018-06-14 13:42:11 +0200586private function f_TC_gsup_sai_err_unknown_imsi() runs on HLR_ConnHdlr {
587 var GSUP_PDU res;
588 res := f_perform_SAI(g_pars.sub.imsi, 2);
Harald Weltec2c52552018-03-01 21:20:39 +0100589 setverdict(pass);
590}
591
Harald Welte3f662762018-03-02 10:48:20 +0100592testcase TC_gsup_sai_err_unknown_imsi() runs on test_CT {
Harald Welteed380d12018-06-14 13:42:11 +0200593 var HLR_ConnHdlr vc_conn;
594 var HLR_ConnHdlrPars pars := valueof(t_Pars(f_rnd_imsi('26242'H)));
595 f_init(false);
596 vc_conn := f_start_handler(refers(f_TC_gsup_sai_err_unknown_imsi), pars);
597 vc_conn.done;
Harald Welte3f662762018-03-02 10:48:20 +0100598}
599
Harald Welteed380d12018-06-14 13:42:11 +0200600function f_start_handler_per_sub(void_fn fn, HlrSubscriberList sl) runs on test_CT {
601 for (var integer i := 0; i < sizeof(sl); i := i+1) {
602 var HlrSubscriber sub := sl[i];
603 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sub));
604 var HLR_ConnHdlr vc_conn;
605
606 f_vty_subscr_create(VTY, sub);
607 vc_conn := f_start_handler(fn, pars);
608 vc_conn.done;
609 f_vty_subscr_delete(VTY, sub);
610 }
611}
Harald Welte3f662762018-03-02 10:48:20 +0100612
Harald Weltec2c52552018-03-01 21:20:39 +0100613/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
Harald Welteed380d12018-06-14 13:42:11 +0200614private function f_TC_gsup_sai() runs on HLR_ConnHdlr {
615 var GSUP_PDU res;
616 res := f_perform_SAI(g_pars.sub.imsi);
617 /* TODO: match if tuple[s] matches expectation */
618 setverdict(pass);
619}
Harald Weltec2c52552018-03-01 21:20:39 +0100620testcase TC_gsup_sai() runs on test_CT {
621 var HlrSubscriberList sl;
622 var GSUP_PDU res;
623
Harald Welteed380d12018-06-14 13:42:11 +0200624 f_init(false);
Harald Weltec2c52552018-03-01 21:20:39 +0100625
626 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200627 f_start_handler_per_sub(refers(f_TC_gsup_sai), sl);
Harald Weltec2c52552018-03-01 21:20:39 +0100628
629 setverdict(pass);
630}
631
632/* test UL for unknown IMSI */
Harald Welteed380d12018-06-14 13:42:11 +0200633private function f_TC_ul_unknown_imsi() runs on HLR_ConnHdlr {
Harald Weltec2c52552018-03-01 21:20:39 +0100634 var GSUP_PDU res;
Harald Welteed380d12018-06-14 13:42:11 +0200635 res := f_perform_UL(g_pars.sub.imsi, ?, 2);
Harald Weltec2c52552018-03-01 21:20:39 +0100636 setverdict(pass);
637}
Harald Welteed380d12018-06-14 13:42:11 +0200638testcase TC_gsup_ul_unknown_imsi() runs on test_CT {
639 var hexstring imsi := f_rnd_imsi('26242'H);
640 var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
641 var HLR_ConnHdlr vc_conn;
Harald Weltec2c52552018-03-01 21:20:39 +0100642
Harald Welteed380d12018-06-14 13:42:11 +0200643 f_init(false);
644 vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
645 vc_conn.done;
646}
647
648/* test UL for a number of different subscriber cases (algo, 2g/3g, ...) */
649private function f_TC_gsup_ul() runs on HLR_ConnHdlr {
650 var GSUP_PDU res;
651 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
652 setverdict(pass);
653}
Harald Weltec2c52552018-03-01 21:20:39 +0100654testcase TC_gsup_ul() runs on test_CT {
655 var HlrSubscriberList sl;
656 var GSUP_PDU res;
657
Harald Welteed380d12018-06-14 13:42:11 +0200658 f_init(false);
Harald Weltec2c52552018-03-01 21:20:39 +0100659 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200660 f_start_handler_per_sub(refers(f_TC_gsup_ul), sl);
Harald Weltec2c52552018-03-01 21:20:39 +0100661
662 setverdict(pass);
663}
664
665/* Test only the VTY commands */
666testcase TC_vty() runs on test_CT {
667 var HlrSubscriber sub;
668
669 f_init();
670
671 /* we're not using f_gen_subs() here as the expect pattern for the 'show' are different
672 * from case to case */
673 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
Harald Welteed380d12018-06-14 13:42:11 +0200674 f_vty_subscr_create(VTY, sub);
675 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *2G auth: COMP128v1*");
676 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100677
678 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
679 "milenage", false));
Harald Welteed380d12018-06-14 13:42:11 +0200680 f_vty_subscr_create(VTY, sub);
681 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *3G auth: MILENAGE*");
682 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100683
684 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
685 "comp128v1", "milenage", false));
Harald Welteed380d12018-06-14 13:42:11 +0200686 f_vty_subscr_create(VTY, sub);
687 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *2G auth: COMP128v1*3G auth: MILENAGE*");
688 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100689
690 setverdict(pass);
691}
692
Harald Welte09b3c502018-03-01 22:42:22 +0100693/* VTY changes to MSISDN should result in ISD to current VLR */
Harald Welteed380d12018-06-14 13:42:11 +0200694private function f_TC_vty_msisdn_isd() runs on HLR_ConnHdlr {
Harald Welte09b3c502018-03-01 22:42:22 +0100695 var hexstring new_msisdn;
696 var GSUP_PDU res;
697 timer T := 5.0;
698
Harald Welte09b3c502018-03-01 22:42:22 +0100699 /* Create Subscriber */
Harald Welteed380d12018-06-14 13:42:11 +0200700 f_vty_subscr_create(VTY, g_pars.sub);
Harald Welte09b3c502018-03-01 22:42:22 +0100701
702 /* Perform UpdateLocation (VLR now known to HLR) */
Harald Welteed380d12018-06-14 13:42:11 +0200703 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
Harald Welte09b3c502018-03-01 22:42:22 +0100704
705 /* Then change IMSI via VTY */
706 new_msisdn := '49161'H & f_rnd_hexstring(7, 9);
Harald Welteed380d12018-06-14 13:42:11 +0200707 f_vty_subscr_update_msisdn(VTY, g_pars.sub, new_msisdn);
Harald Welte09b3c502018-03-01 22:42:22 +0100708 /* And expect InsertSubscriberData as result */
709 T.start;
710 alt {
Harald Welteed380d12018-06-14 13:42:11 +0200711 [] GSUP.receive(tr_GSUP_ISD_REQ(g_pars.sub.imsi, new_msisdn)) {
712 GSUP.send(ts_GSUP_ISD_RES(g_pars.sub.imsi));
713 g_pars.sub.msisdn := new_msisdn;
Harald Welte09b3c502018-03-01 22:42:22 +0100714 setverdict(pass);
715 }
Harald Welteed380d12018-06-14 13:42:11 +0200716 [] GSUP.receive(tr_GSUP_ISD_REQ(g_pars.sub.imsi, g_pars.sub.msisdn)) {
Stefan Sperling7c096872018-04-09 11:24:22 +0200717 log("received ISD req with old MSISDN");
718 setverdict(fail);
719 }
Harald Welte09b3c502018-03-01 22:42:22 +0100720 [] GSUP.receive { repeat; }
721 [] T.timeout {
722 setverdict(fail, "Timeout waiting for ISD.req");
723 }
724 }
725}
Harald Welteed380d12018-06-14 13:42:11 +0200726testcase TC_vty_msisdn_isd() runs on test_CT {
727 var HlrSubscriber sub;
728 var HLR_ConnHdlr vc_conn;
729
730 f_init(false);
731
732 /* Create Subscriber */
733 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
734
735 vc_conn := f_start_handler(refers(f_TC_vty_msisdn_isd), valueof(t_Pars_sub(sub)));
736 vc_conn.done;
737}
Harald Welte09b3c502018-03-01 22:42:22 +0100738
Harald Welte958f8b42018-03-01 23:40:17 +0100739/* Test PURGE MS for CS services */
Harald Welteed380d12018-06-14 13:42:11 +0200740private function f_TC_gsup_purge_cs() runs on HLR_ConnHdlr {
741 var GSUP_PDU res;
742 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
743 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS);
744}
Harald Welte958f8b42018-03-01 23:40:17 +0100745testcase TC_gsup_purge_cs() runs on test_CT {
746 var HlrSubscriberList sl;
747 var GSUP_PDU res;
748
Harald Welteed380d12018-06-14 13:42:11 +0200749 f_init(false);
Harald Welte958f8b42018-03-01 23:40:17 +0100750 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200751 f_start_handler_per_sub(refers(f_TC_gsup_purge_cs), sl);
Harald Welte958f8b42018-03-01 23:40:17 +0100752
753 setverdict(pass);
754}
755
756/* Test PURGE MS for PS services */
Harald Welteed380d12018-06-14 13:42:11 +0200757private function f_TC_gsup_purge_ps() runs on HLR_ConnHdlr {
758 var GSUP_PDU res;
759 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
760 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_PS);
761}
Harald Welte958f8b42018-03-01 23:40:17 +0100762testcase TC_gsup_purge_ps() runs on test_CT {
763 var HlrSubscriberList sl;
Harald Welte958f8b42018-03-01 23:40:17 +0100764
Harald Welteed380d12018-06-14 13:42:11 +0200765 f_init(false);
Harald Welte958f8b42018-03-01 23:40:17 +0100766 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200767 f_start_handler_per_sub(refers(f_TC_gsup_purge_ps), sl);
Harald Welte958f8b42018-03-01 23:40:17 +0100768
769 setverdict(pass);
770}
771
772/* Test PURGEG MS procedure for unknown IMSI */
Harald Welteed380d12018-06-14 13:42:11 +0200773
774private function f_TC_gsup_purge_unknown() runs on HLR_ConnHdlr {
775 var GSUP_PDU res;
776 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS, 2);
777}
Harald Welte958f8b42018-03-01 23:40:17 +0100778testcase TC_gsup_purge_unknown() runs on test_CT {
779 var hexstring imsi := '2345743413463'H;
Harald Welteed380d12018-06-14 13:42:11 +0200780 var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
781 var HLR_ConnHdlr vc_conn;
Harald Welte958f8b42018-03-01 23:40:17 +0100782
Harald Welteed380d12018-06-14 13:42:11 +0200783 f_init(false);
784 vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
785 vc_conn.done;
Harald Welte958f8b42018-03-01 23:40:17 +0100786
787 setverdict(pass);
788}
789
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200790import from HLR_EUSE all;
791
792/* Test for USSD request to undefined/unrouted short-code. Expect ss-NotAvailable(18) */
793private function f_TC_mo_ussd_unknown() runs on HLR_ConnHdlr {
794 var GSUP_PDU res;
795 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
796 op_code := SS_OP_CODE_PROCESS_USS_REQ,
797 ussd_string := "*#200#");
798 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
799 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700800 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
801 OSMO_GSUP_SESSION_STATE_END,
802 tr_SS_FACILITY_RETURN_ERROR(1, 18));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200803}
804testcase TC_mo_ussd_unknown() runs on test_CT {
805 var HlrSubscriberList sl;
806 var HLR_ConnHdlr vc_conn;
807
808 f_init(false);
809 sl := f_gen_subs();
810 for (var integer i := 0; i < sizeof(sl); i := i+1) {
811 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
812 pars.ussd.sid := f_rnd_octstring(4);
813 f_vty_subscr_create(VTY, pars.sub);
814 vc_conn := f_start_handler(refers(f_TC_mo_ussd_unknown), pars);
815 vc_conn.done;
816 }
817}
818
819/* Test for USSD request to currently disconnected EUSE. Expect ss-SystemFailure(34) */
820private function f_TC_mo_ussd_euse_disc() runs on HLR_ConnHdlr {
821 var GSUP_PDU res;
822 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
823 op_code := SS_OP_CODE_PROCESS_USS_REQ,
824 ussd_string := "*100#");
825 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
826 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700827 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
828 OSMO_GSUP_SESSION_STATE_END,
829 tr_SS_FACILITY_RETURN_ERROR(1, 34));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200830}
831testcase TC_mo_ussd_euse_disc() runs on test_CT {
832 var HlrSubscriberList sl;
833 var HLR_ConnHdlr vc_conn;
834
835 f_init(false);
836 sl := f_gen_subs();
837 for (var integer i := 0; i < sizeof(sl); i := i+1) {
838 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
839 pars.ussd.sid := f_rnd_octstring(4);
840 f_vty_subscr_create(VTY, pars.sub);
841 vc_conn := f_start_handler(refers(f_TC_mo_ussd_euse_disc), pars);
842 vc_conn.done;
843 }
844}
845
846/* Test for USSD request to internal own-imsi IUSE. */
847private function f_TC_mo_ussd_iuse_imsi() runs on HLR_ConnHdlr {
848 var GSUP_PDU res;
849 var charstring resp_str;
850 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
851 op_code := SS_OP_CODE_PROCESS_USS_REQ,
852 ussd_string := "*#101#");
853 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
854 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
855 resp_str := "Your IMSI is " & hex2str(g_pars.sub.imsi);
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700856 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
857 OSMO_GSUP_SESSION_STATE_END,
858 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
859 f_encGSM7bit(resp_str)));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200860}
861testcase TC_mo_ussd_iuse_imsi() runs on test_CT {
862 var HlrSubscriberList sl;
863 var HLR_ConnHdlr vc_conn;
864
865 f_init(false);
866 sl := f_gen_subs();
867 for (var integer i := 0; i < sizeof(sl); i := i+1) {
868 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
869 pars.ussd.sid := f_rnd_octstring(4);
870 f_vty_subscr_create(VTY, pars.sub);
871 vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_imsi), pars);
872 vc_conn.done;
873 }
874}
875
876/* Test for USSD request to internal own-msisdn IUSE. */
877private function f_TC_mo_ussd_iuse_msisdn() runs on HLR_ConnHdlr {
878 var GSUP_PDU res;
879 var charstring resp_str;
880 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
881 op_code := SS_OP_CODE_PROCESS_USS_REQ,
882 ussd_string := "*#100#");
883 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
884 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
885 resp_str := "Your extension is " & hex2str(g_pars.sub.msisdn);
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700886 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
887 OSMO_GSUP_SESSION_STATE_END,
888 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
889 f_encGSM7bit(resp_str)));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200890}
891testcase TC_mo_ussd_iuse_msisdn() runs on test_CT {
892 var HlrSubscriberList sl;
893 var HLR_ConnHdlr vc_conn;
894
895 f_init(false);
896 sl := f_gen_subs();
897 for (var integer i := 0; i < sizeof(sl); i := i+1) {
898 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
899 pars.ussd.sid := f_rnd_octstring(4);
900 f_vty_subscr_create(VTY, pars.sub);
901 vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_msisdn), pars);
902 vc_conn.done;
903 }
904}
905
906/* Test routing of USSD to EUSE by a specific route */
907private function f_TC_mo_ussd_100() runs on HLR_ConnHdlr {
908 var GSUP_PDU res;
909 /* invoke / invoke id 1 / processUSS-req */
910 //var octetstring ss := 'a11202010102013b300a04010f0405aa180c3602'O;
911 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
912 op_code := SS_OP_CODE_PROCESS_USS_REQ,
913 ussd_string := "*100#");
914 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
915 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700916 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
917 OSMO_GSUP_SESSION_STATE_END,
918 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
919 f_encGSM7bit("*100#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200920}
921testcase TC_mo_ussd_euse() runs on test_CT {
922 var HlrSubscriberList sl;
923 var HLR_ConnHdlr vc_conn;
924
925 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
926 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar", refers(f_ss_echo)));
927
928 f_init(false);
929 sl := f_gen_subs();
930 for (var integer i := 0; i < sizeof(sl); i := i+1) {
931 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
932 pars.ussd.sid := f_rnd_octstring(4);
933 f_vty_subscr_create(VTY, pars.sub);
934 vc_conn := f_start_handler(refers(f_TC_mo_ussd_100), pars);
935 vc_conn.done;
936 }
937
938 vc_EUSE.stop;
939}
940
941/* Test routing of USSD to EUSE by a specific route, with CONTINUE */
942private function f_TC_mo_ussd_100_continue() runs on HLR_ConnHdlr {
943 var GSUP_PDU res;
944 /* Simulate BEGIN from MS/MSC */
945 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(op_code := SS_OP_CODE_PROCESS_USS_REQ,
946 ussd_string := "*100#");
947 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
948 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
949 /* expect echo response from EUSE */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700950 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
951 OSMO_GSUP_SESSION_STATE_CONTINUE,
952 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
953 f_encGSM7bit("*100#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200954
955 /* Simulate CONTINUE from MS/MSC */
956 ss := f_USSD_FACILITY_IE_INVOKE(op_code := SS_OP_CODE_PROCESS_USS_REQ,
957 ussd_string := "mahlzeit");
958 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
959 OSMO_GSUP_SESSION_STATE_CONTINUE, ss)));
960
961 /* expect echo response from EUSE */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700962 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
963 OSMO_GSUP_SESSION_STATE_END,
964 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
965 f_encGSM7bit("mahlzeit")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200966}
967testcase TC_mo_ussd_euse_continue() runs on test_CT {
968 var HlrSubscriberList sl;
969 var HLR_ConnHdlr vc_conn;
970
971 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
972 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar",
973 refers(f_ss_echo_continue)));
974
975 f_init(false);
976 sl := f_gen_subs();
977 for (var integer i := 0; i < sizeof(sl); i := i+1) {
978 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
979 pars.ussd.sid := f_rnd_octstring(4);
980 f_vty_subscr_create(VTY, pars.sub);
981 vc_conn := f_start_handler(refers(f_TC_mo_ussd_100_continue), pars);
982 vc_conn.done;
983 }
984
985 vc_EUSE.stop;
986}
987
988
989/* Test routing of USSD to EUSE by default-route */
990private function f_TC_mo_ussd_999() runs on HLR_ConnHdlr {
991 var GSUP_PDU res;
992 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
993 op_code := SS_OP_CODE_PROCESS_USS_REQ,
994 ussd_string := "*999#");
995 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
996 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700997 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
998 OSMO_GSUP_SESSION_STATE_END,
999 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
1000 f_encGSM7bit("*999#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001001}
1002testcase TC_mo_ussd_euse_defaultroute() runs on test_CT {
1003 var HlrSubscriberList sl;
1004 var HLR_ConnHdlr vc_conn;
1005
1006 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
1007 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar", refers(f_ss_echo)));
1008
1009 f_init(false);
1010 f_vty_config(VTY, "hlr", "ussd default-route external foobar");
1011
1012 sl := f_gen_subs();
1013 for (var integer i := 0; i < sizeof(sl); i := i+1) {
1014 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
1015 pars.ussd.sid := f_rnd_octstring(4);
1016 f_vty_subscr_create(VTY, pars.sub);
1017 vc_conn := f_start_handler(refers(f_TC_mo_ussd_999), pars);
1018 vc_conn.done;
1019 }
1020
1021 f_vty_config(VTY, "hlr", "no ussd default-route");
1022 vc_EUSE.stop;
1023}
1024
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001025/**
1026 * Test "Structured" Supplementary Services
1027 *
1028 * NOTE: at the moment, OsmoHLR doesn't support "structured" SS,
1029 * so such requests are being rejected (actually ReturnError
1030 * with GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED).
1031 */
1032private function f_TC_mo_sss_reject() runs on HLR_ConnHdlr {
1033 var SS_FacilityInformation ss_req;
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001034 var GSUP_PDU res;
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001035
1036 /* Prepare '*#21#' SS request */
1037 ss_req := valueof(ts_SS_FACILITY_INVOKE(
1038 invoke_id := 0,
1039 op_code := SS_OP_CODE_INTERROGATE_SS,
1040 ss_code := '21'O));
1041
1042 /* Send it towards HLR */
1043 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(
1044 g_pars.sub.imsi,
1045 g_pars.ussd.sid,
1046 OSMO_GSUP_SESSION_STATE_BEGIN,
1047 enc_SS_FacilityInformation(ss_req))));
1048
1049 /* Expect ReturnError with FACILITY_NOT_SUPPORTED */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001050 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
1051 OSMO_GSUP_SESSION_STATE_END,
1052 tr_SS_FACILITY_RETURN_ERROR(0, 21));
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001053}
1054testcase TC_mo_sss_reject() runs on test_CT {
1055 var HLR_ConnHdlrPars pars;
1056 var HLR_ConnHdlr vc_conn;
1057 var HlrSubscriber sub;
1058
1059 f_init(false);
1060
1061 /* Create a random subscriber */
1062 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H),
1063 '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
1064 pars := valueof(t_Pars_sub(sub));
1065 pars.ussd.sid := f_rnd_octstring(4);
1066
1067 f_vty_subscr_create(VTY, sub);
1068 vc_conn := f_start_handler(refers(f_TC_mo_sss_reject), pars);
1069 vc_conn.done;
1070 f_vty_subscr_delete(VTY, sub);
1071}
1072
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001073
1074/* TODO USSD:
1075 * MO USSD for IMSI of non-existant subscriber
1076 * MT USSD from EUSE
1077 * timeout cases
1078 */
1079
Harald Weltec2c52552018-03-01 21:20:39 +01001080/* TODO:
1081 * UL with ISD error
1082 * UL with ISD timeout
Harald Weltec2c52552018-03-01 21:20:39 +01001083 * LOCATION CANCEL
1084 * AUTH FAIL REP
1085 * DELETE DATA after hlr_subscr_nam() change
1086 * correctness
1087 ** wrong message type
1088 ** wrong length of PDU
1089 ** too short message
1090 ** missing IMSI IE
1091
1092 */
1093
Harald Weltedf327232017-12-28 22:51:51 +01001094control {
1095 execute( TC_gsup_sai_err_invalid_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +01001096 execute( TC_gsup_sai() );
1097 execute( TC_gsup_ul_unknown_imsi() );
Harald Welte3f662762018-03-02 10:48:20 +01001098 execute( TC_gsup_sai_err_unknown_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +01001099 execute( TC_gsup_ul() );
1100 execute( TC_vty() );
Harald Welte09b3c502018-03-01 22:42:22 +01001101 execute( TC_vty_msisdn_isd() );
Harald Welte958f8b42018-03-01 23:40:17 +01001102 execute( TC_gsup_purge_cs() );
1103 execute( TC_gsup_purge_ps() );
1104 execute( TC_gsup_purge_unknown() );
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001105
1106 execute( TC_mo_ussd_unknown() );
1107 execute( TC_mo_ussd_euse_disc() );
1108 execute( TC_mo_ussd_iuse_imsi() );
1109 execute( TC_mo_ussd_iuse_msisdn() );
1110 execute( TC_mo_ussd_euse() );
1111 execute( TC_mo_ussd_euse_continue() );
1112 execute( TC_mo_ussd_euse_defaultroute() );
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001113
1114 /* "Structured" Supplementary Services */
1115 execute( TC_mo_sss_reject() );
Harald Weltedf327232017-12-28 22:51:51 +01001116};
1117
1118};