blob: 4c158fd968d7dc34d047ad8cbe230be74492d5eb [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
Oliver Smith141620d2019-06-07 12:27:33 +0200305function f_vty_transceive_nomatch(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
306 var charstring ret := f_vty_transceive_ret(pt, cmd);
307 if (match(ret, exp_ret)) {
308 setverdict(fail, "Matching VTY response: ", ret, ", should *not* have matched: ", exp_ret);
309 mtc.stop;
310 }
311}
312
Harald Welte70296062018-03-01 22:42:03 +0100313private template (value) charstring t_subscr_prefix(hexstring imsi) :=
314 "subscriber imsi " & hex2str(imsi) & " ";
315
Harald Weltec2c52552018-03-01 21:20:39 +0100316/* create a given subscriber using the VTY */
Harald Welteed380d12018-06-14 13:42:11 +0200317function f_vty_subscr_create(TELNETasp_PT VTY, HlrSubscriber sub) {
Harald Welte70296062018-03-01 22:42:03 +0100318 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100319 f_vty_transceive_match(VTY, prefix & "create", pattern "% Created subscriber *");
320 f_vty_transceive_match(VTY, prefix & "update msisdn " & hex2str(sub.msisdn),
321 pattern "% Updated subscriber *");
322 if (ispresent(sub.aud2g)) {
323 f_vty_transceive_match(VTY, prefix & "update aud2g " & sub.aud2g.algo &
324 " ki " & oct2str(sub.aud2g.ki),
325 pattern "");
326 } else {
327 f_vty_transceive_match(VTY, prefix & "update aud2g none", pattern "");
328 }
329
330 if (ispresent(sub.aud3g)) {
331 var charstring op_mode := "op";
332 if (sub.aud3g.op_is_opc) {
333 op_mode := "opc";
334 }
335 f_vty_transceive_match(VTY, prefix & "update aud3g " & sub.aud3g.algo &
336 " k " & oct2str(sub.aud3g.k) & " " & op_mode & " " &
337 oct2str(sub.aud3g.op), pattern "");
338 } else {
339 f_vty_transceive_match(VTY, prefix & "update aud3g none", pattern "");
340 }
341}
342
Harald Welteed380d12018-06-14 13:42:11 +0200343function f_vty_subscr_update_msisdn(TELNETasp_PT VTY, HlrSubscriber sub, hexstring new_msisdn) {
Harald Welte09b3c502018-03-01 22:42:22 +0100344 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
345 f_vty_transceive_match(VTY, prefix & "update msisdn " & hex2str(new_msisdn),
346 pattern "% Updated subscriber *");
347}
348
Harald Weltec2c52552018-03-01 21:20:39 +0100349/* perform 'delete' on subscriber */
Harald Welteed380d12018-06-14 13:42:11 +0200350function f_vty_subscr_delete(TELNETasp_PT VTY, HlrSubscriber sub) {
Harald Welte70296062018-03-01 22:42:03 +0100351 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100352 f_vty_transceive_match(VTY, prefix & "delete",
353 pattern "% Deleted subscriber for IMSI *");
354}
355
356/* perform 'show' on subscriber; match result with pattern 'exp' */
Harald Welteed380d12018-06-14 13:42:11 +0200357function f_vty_subscr_show(TELNETasp_PT VTY, HlrSubscriber sub, template charstring exp) {
Harald Welte70296062018-03-01 22:42:03 +0100358 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100359 f_vty_transceive_match(VTY, prefix & "show", exp);
360}
361
Oliver Smith141620d2019-06-07 12:27:33 +0200362/* perform 'show' on subscriber; result must not match with pattern 'exp' */
363function f_vty_subscr_show_nomatch(TELNETasp_PT VTY, HlrSubscriber sub, template charstring exp) {
364 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
365 f_vty_transceive_nomatch(VTY, prefix & "show", exp);
366}
Harald Weltec2c52552018-03-01 21:20:39 +0100367
Harald Welteed380d12018-06-14 13:42:11 +0200368/***********************************************************************
369 * Helper functions for ConnHdlr
370 ***********************************************************************/
371
Harald Weltec2c52552018-03-01 21:20:39 +0100372/* perform SendAuthInfo for given imsi, return the GSUP response/error */
373function f_perform_SAI(hexstring imsi, template (omit) integer exp_err_cause := omit)
Harald Welteed380d12018-06-14 13:42:11 +0200374runs on HLR_ConnHdlr return GSUP_PDU {
Harald Weltec2c52552018-03-01 21:20:39 +0100375 var GSUP_PDU ret;
376 timer T := 3.0;
377 var boolean exp_fail := false;
378 if (not istemplatekind(exp_err_cause, "omit")) {
379 exp_fail := true;
380 }
381
382 GSUP.send(valueof(ts_GSUP_SAI_REQ(imsi)));
383 T.start;
384 alt {
385 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, exp_err_cause)) -> value ret {
386 setverdict(pass);
387 }
388 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
389 setverdict(fail, "Unexpected SAI ERROR Cause");
390 }
391 [exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
392 setverdict(fail, "Unexpected SAI.res for unknown IMSI");
393 }
394 [not exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
395 setverdict(fail, "Unexpected SAI ERROR");
396 }
397 [not exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
398 setverdict(pass);
399 }
400 [] GSUP.receive { repeat; }
401 [] T.timeout {
402 setverdict(fail, "Timeout waiting for SAI response");
Daniel Willmannafce8662018-07-06 23:11:32 +0200403 mtc.stop;
Harald Weltec2c52552018-03-01 21:20:39 +0100404 }
405 }
406 return ret;
407}
408
409function f_perform_UL(hexstring imsi, template hexstring msisdn,
410 template (omit) integer exp_err_cause := omit)
Harald Welteed380d12018-06-14 13:42:11 +0200411runs on HLR_ConnHdlr return GSUP_PDU {
Harald Weltec2c52552018-03-01 21:20:39 +0100412 var GSUP_PDU ret;
413 timer T := 3.0;
414 var boolean exp_fail := false;
415 var boolean isd_done := false;
416 if (not istemplatekind(exp_err_cause, "omit")) {
417 exp_fail := true;
418 }
419
420 GSUP.send(valueof(ts_GSUP_UL_REQ(imsi)));
421 T.start;
422 alt {
423 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause)) -> value ret {
424 setverdict(pass);
425 }
426 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
427 setverdict(fail, "Unexpected UL ERROR Cause");
428 }
429 [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
430 setverdict(fail, "Unexpected UL.res for unknown IMSI");
431 }
432 [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi)) -> value ret {
433 setverdict(fail, "Unexpected ISD.req in error case");
434 }
435 [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
436 setverdict(fail, "Unexpected UL ERROR");
437 }
438 [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn)) -> value ret {
439 GSUP.send(ts_GSUP_ISD_RES(imsi));
440 isd_done := true;
Harald Welte8f0c9332018-03-01 23:38:40 +0100441 repeat;
Harald Weltec2c52552018-03-01 21:20:39 +0100442 }
443 [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
444 setverdict(pass);
445 }
446 [] GSUP.receive { repeat; }
447 [] T.timeout {
448 setverdict(fail, "Timeout waiting for UL response");
Daniel Willmannafce8662018-07-06 23:11:32 +0200449 mtc.stop;
Harald Weltec2c52552018-03-01 21:20:39 +0100450 }
451 }
452 return ret;
453}
454
Harald Welte958f8b42018-03-01 23:40:17 +0100455/* perform PurgeMS for given imsi, return the GSUP response/error */
456function f_perform_PURGE(hexstring imsi, GSUP_CnDomain cn_dom,
457 template (omit) integer exp_err_cause := omit)
Harald Welteed380d12018-06-14 13:42:11 +0200458runs on HLR_ConnHdlr return GSUP_PDU {
Harald Welte958f8b42018-03-01 23:40:17 +0100459 var GSUP_PDU ret;
460 timer T := 3.0;
461 var boolean exp_fail := false;
462 if (not istemplatekind(exp_err_cause, "omit")) {
463 exp_fail := true;
464 }
465
466 GSUP.send(valueof(ts_GSUP_PURGE_MS_REQ(imsi, cn_dom)));
467 T.start;
468 alt {
469 [exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_ERR(imsi, exp_err_cause)) -> value ret {
470 setverdict(pass);
471 }
472 [exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_ERR(imsi, ?)) -> value ret {
473 setverdict(fail, "Unexpected PURGE ERROR Cause");
474 }
475 [exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_RES(imsi)) -> value ret {
476 setverdict(fail, "Unexpected PURGE.res for unknown IMSI");
477 }
478 [not exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_ERR(imsi, ?)) -> value ret {
479 setverdict(fail, "Unexpected PURGE ERROR");
480 }
481 [not exp_fail] GSUP.receive(tr_GSUP_PURGE_MS_RES(imsi)) -> value ret {
482 setverdict(pass);
483 }
484 [] GSUP.receive { repeat; }
485 [] T.timeout {
486 setverdict(fail, "Timeout waiting for PURGE response");
Daniel Willmannafce8662018-07-06 23:11:32 +0200487 mtc.stop;
Harald Welte958f8b42018-03-01 23:40:17 +0100488 }
489 }
490 return ret;
491}
492
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200493function f_SS_xceive(hexstring imsi, OCT4 sid, GSUP_SessionState state, octetstring ss,
494 template (omit) integer exp_err_cause := omit)
495runs on HLR_ConnHdlr return GSUP_PDU {
496 var GSUP_PDU ret;
497 timer T := 3.0;
498 var boolean exp_fail := false;
499 if (not istemplatekind(exp_err_cause, "omit")) {
500 exp_fail := true;
501 }
502
503 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(imsi, sid, state, ss)));
504 T.start;
505 alt {
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700506 [exp_fail] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, exp_err_cause)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200507 setverdict(pass);
508 }
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700509 [exp_fail] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, ?)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200510 setverdict(fail, "Unexpected PROC_SS ERROR Cause");
511 }
512 [exp_fail] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, ?, ?)) -> value ret {
513 setverdict(fail, "Unexpected PROC_SS.res for unknown IMSI");
514 }
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700515 [not exp_fail] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, ?)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200516 setverdict(fail, "Unexpected PROC_SS ERROR");
517 }
518 [not exp_fail] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, ?, ?)) -> value ret {
519 setverdict(pass);
520 }
521 [] GSUP.receive { repeat; }
522 [] T.timeout {
523 setverdict(fail, "Timeout waiting for PROC_SS response");
524 self.stop;
525 }
526 }
527 return ret;
528}
529
530private function f_SS_expect(hexstring imsi, OCT4 sid, GSUP_SessionState state,
531 template SS_FacilityInformation facility := *)
532runs on HLR_ConnHdlr return GSUP_PDU {
533 var GSUP_PDU ret;
534 timer T := 3.0;
535 var boolean exp_ss := true;
536 if (istemplatekind(facility, "omit")) {
537 exp_ss := false;
538 }
539 T.start;
540 alt {
Vadim Yanitskiy21c42332018-11-29 00:18:05 +0700541 [] GSUP.receive(tr_GSUP_PROC_SS_ERR(imsi, sid, ?, ?)) -> value ret {
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200542 setverdict(fail, "Unexpected PROC_SS ERROR Cause");
543 }
544 [not exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, omit)) -> value ret {
545 setverdict(pass);
546 }
547 [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, omit)) -> value ret {
548 setverdict(fail, "Unexpected PROC_SS.res without SS IE");
549 }
550/*
551 [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, decmatch facility)) -> value ret {
552 setverdict(pass);
553 }
554*/
555
556 [exp_ss] GSUP.receive(tr_GSUP_PROC_SS_RES(imsi, sid, state, ?)) -> value ret {
557 var GSUP_IeValue ss_ie;
558 f_gsup_find_ie(ret, OSMO_GSUP_SS_INFO_IE, ss_ie);
559 var SS_FacilityInformation dec_fac := dec_SS_FacilityInformation(ss_ie.ss_info);
560 log("pattern: ", facility);
561 if (match(dec_fac, facility)) {
562 setverdict(pass);
563 } else {
564 setverdict(fail, "Unexpected PROC_SS.res with non-matching facility IE");
565 }
566 }
567 [] GSUP.receive { repeat; }
568 [] T.timeout {
569 setverdict(fail, "Timeout waiting for PROC_SS response");
570 self.stop;
571 }
572 }
573
574 return ret;
575}
576
Oliver Smith936dbe62019-06-04 15:54:17 +0200577function f_perform_CHECK_IMEI(hexstring imsi, hexstring imei,
578 template (omit) integer exp_err_cause := omit,
579 template (omit) GSUP_IMEIResult result := omit)
580runs on HLR_ConnHdlr {
581 var GSUP_PDU pdu;
582 timer T := 3.0;
583 var boolean exp_fail := false;
584 if (not istemplatekind(exp_err_cause, "omit")) {
585 exp_fail := true;
586 }
587
588 GSUP.send(valueof(ts_GSUP_CHECK_IMEI_REQ(imsi, imei)));
589 T.start;
590 alt {
591 [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, exp_err_cause)) -> value pdu {
592 setverdict(pass);
593 }
594 [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, ?)) -> value pdu {
595 setverdict(fail, "Unexpected CHECK IMEI ERROR Cause: ", pdu);
596 }
597 [exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, ?)) -> value pdu {
598 setverdict(fail, "Unexpected CHECK IMEI RES instead of ERR");
599 }
600 [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_ERR(imsi, ?)) -> value pdu {
601 setverdict(fail, "Unexpected CHECK IMEI ERROR");
602 }
603 [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, result)) -> value pdu {
604 setverdict(pass);
605 }
606 [not exp_fail] GSUP.receive(tr_GSUP_CHECK_IMEI_RES(imsi, ?)) -> value pdu {
607 setverdict(fail, "Unexpected CHECK IMEI RES");
608 }
609 [] GSUP.receive { repeat; }
610 [] T.timeout {
611 setverdict(fail, "Timeout waiting for CHECK IMEI response");
612 mtc.stop;
613 }
614 }
615}
616
617
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200618
Harald Welte958f8b42018-03-01 23:40:17 +0100619
Harald Welteed380d12018-06-14 13:42:11 +0200620/***********************************************************************
621 * Testcases
622 ***********************************************************************/
623
624/* 23.003 Section 2.2 clearly states that an IMSI with less
625 * than 5 digits is impossible. Even 5 digits is still questionable */
626private function f_TC_gsup_sai_err_invalid_imsi() runs on HLR_ConnHdlr {
Harald Weltec2c52552018-03-01 21:20:39 +0100627 var GSUP_PDU res;
Harald Welteed380d12018-06-14 13:42:11 +0200628 res := f_perform_SAI(g_pars.sub.imsi, 96); /* Invalid Mandatory information */
629 setverdict(pass);
630}
631testcase TC_gsup_sai_err_invalid_imsi() runs on test_CT {
632 var HLR_ConnHdlr vc_conn;
633 var HLR_ConnHdlrPars pars := valueof(t_Pars('0123'H));
634 f_init(false);
635 vc_conn := f_start_handler(refers(f_TC_gsup_sai_err_invalid_imsi), pars);
636 vc_conn.done;
637}
Harald Weltec2c52552018-03-01 21:20:39 +0100638
Harald Weltec2c52552018-03-01 21:20:39 +0100639
Harald Welteed380d12018-06-14 13:42:11 +0200640private function f_TC_gsup_sai_err_unknown_imsi() runs on HLR_ConnHdlr {
641 var GSUP_PDU res;
642 res := f_perform_SAI(g_pars.sub.imsi, 2);
Harald Weltec2c52552018-03-01 21:20:39 +0100643 setverdict(pass);
644}
645
Harald Welte3f662762018-03-02 10:48:20 +0100646testcase TC_gsup_sai_err_unknown_imsi() runs on test_CT {
Harald Welteed380d12018-06-14 13:42:11 +0200647 var HLR_ConnHdlr vc_conn;
648 var HLR_ConnHdlrPars pars := valueof(t_Pars(f_rnd_imsi('26242'H)));
649 f_init(false);
650 vc_conn := f_start_handler(refers(f_TC_gsup_sai_err_unknown_imsi), pars);
651 vc_conn.done;
Harald Welte3f662762018-03-02 10:48:20 +0100652}
653
Harald Welteed380d12018-06-14 13:42:11 +0200654function f_start_handler_per_sub(void_fn fn, HlrSubscriberList sl) runs on test_CT {
655 for (var integer i := 0; i < sizeof(sl); i := i+1) {
656 var HlrSubscriber sub := sl[i];
657 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sub));
658 var HLR_ConnHdlr vc_conn;
659
660 f_vty_subscr_create(VTY, sub);
661 vc_conn := f_start_handler(fn, pars);
662 vc_conn.done;
663 f_vty_subscr_delete(VTY, sub);
664 }
665}
Harald Welte3f662762018-03-02 10:48:20 +0100666
Harald Weltec2c52552018-03-01 21:20:39 +0100667/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
Harald Welteed380d12018-06-14 13:42:11 +0200668private function f_TC_gsup_sai() runs on HLR_ConnHdlr {
669 var GSUP_PDU res;
670 res := f_perform_SAI(g_pars.sub.imsi);
671 /* TODO: match if tuple[s] matches expectation */
672 setverdict(pass);
673}
Harald Weltec2c52552018-03-01 21:20:39 +0100674testcase TC_gsup_sai() runs on test_CT {
675 var HlrSubscriberList sl;
676 var GSUP_PDU res;
677
Harald Welteed380d12018-06-14 13:42:11 +0200678 f_init(false);
Harald Weltec2c52552018-03-01 21:20:39 +0100679
680 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200681 f_start_handler_per_sub(refers(f_TC_gsup_sai), sl);
Harald Weltec2c52552018-03-01 21:20:39 +0100682
683 setverdict(pass);
684}
685
686/* test UL for unknown IMSI */
Harald Welteed380d12018-06-14 13:42:11 +0200687private function f_TC_ul_unknown_imsi() runs on HLR_ConnHdlr {
Harald Weltec2c52552018-03-01 21:20:39 +0100688 var GSUP_PDU res;
Harald Welteed380d12018-06-14 13:42:11 +0200689 res := f_perform_UL(g_pars.sub.imsi, ?, 2);
Harald Weltec2c52552018-03-01 21:20:39 +0100690 setverdict(pass);
691}
Harald Welteed380d12018-06-14 13:42:11 +0200692testcase TC_gsup_ul_unknown_imsi() runs on test_CT {
693 var hexstring imsi := f_rnd_imsi('26242'H);
694 var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
695 var HLR_ConnHdlr vc_conn;
Harald Weltec2c52552018-03-01 21:20:39 +0100696
Harald Welteed380d12018-06-14 13:42:11 +0200697 f_init(false);
698 vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
699 vc_conn.done;
700}
701
702/* test UL for a number of different subscriber cases (algo, 2g/3g, ...) */
703private function f_TC_gsup_ul() runs on HLR_ConnHdlr {
704 var GSUP_PDU res;
705 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
706 setverdict(pass);
707}
Harald Weltec2c52552018-03-01 21:20:39 +0100708testcase TC_gsup_ul() runs on test_CT {
709 var HlrSubscriberList sl;
710 var GSUP_PDU res;
711
Harald Welteed380d12018-06-14 13:42:11 +0200712 f_init(false);
Harald Weltec2c52552018-03-01 21:20:39 +0100713 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200714 f_start_handler_per_sub(refers(f_TC_gsup_ul), sl);
Harald Weltec2c52552018-03-01 21:20:39 +0100715
716 setverdict(pass);
717}
718
719/* Test only the VTY commands */
720testcase TC_vty() runs on test_CT {
721 var HlrSubscriber sub;
722
723 f_init();
724
725 /* we're not using f_gen_subs() here as the expect pattern for the 'show' are different
726 * from case to case */
727 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
Harald Welteed380d12018-06-14 13:42:11 +0200728 f_vty_subscr_create(VTY, sub);
729 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *2G auth: COMP128v1*");
730 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100731
732 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
733 "milenage", false));
Harald Welteed380d12018-06-14 13:42:11 +0200734 f_vty_subscr_create(VTY, sub);
735 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *3G auth: MILENAGE*");
736 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100737
738 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
739 "comp128v1", "milenage", false));
Harald Welteed380d12018-06-14 13:42:11 +0200740 f_vty_subscr_create(VTY, sub);
741 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *2G auth: COMP128v1*3G auth: MILENAGE*");
742 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100743
744 setverdict(pass);
745}
746
Harald Welte09b3c502018-03-01 22:42:22 +0100747/* VTY changes to MSISDN should result in ISD to current VLR */
Harald Welteed380d12018-06-14 13:42:11 +0200748private function f_TC_vty_msisdn_isd() runs on HLR_ConnHdlr {
Harald Welte09b3c502018-03-01 22:42:22 +0100749 var hexstring new_msisdn;
750 var GSUP_PDU res;
751 timer T := 5.0;
752
Harald Welte09b3c502018-03-01 22:42:22 +0100753 /* Create Subscriber */
Harald Welteed380d12018-06-14 13:42:11 +0200754 f_vty_subscr_create(VTY, g_pars.sub);
Harald Welte09b3c502018-03-01 22:42:22 +0100755
756 /* Perform UpdateLocation (VLR now known to HLR) */
Harald Welteed380d12018-06-14 13:42:11 +0200757 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
Harald Welte09b3c502018-03-01 22:42:22 +0100758
759 /* Then change IMSI via VTY */
760 new_msisdn := '49161'H & f_rnd_hexstring(7, 9);
Harald Welteed380d12018-06-14 13:42:11 +0200761 f_vty_subscr_update_msisdn(VTY, g_pars.sub, new_msisdn);
Harald Welte09b3c502018-03-01 22:42:22 +0100762 /* And expect InsertSubscriberData as result */
763 T.start;
764 alt {
Harald Welteed380d12018-06-14 13:42:11 +0200765 [] GSUP.receive(tr_GSUP_ISD_REQ(g_pars.sub.imsi, new_msisdn)) {
766 GSUP.send(ts_GSUP_ISD_RES(g_pars.sub.imsi));
767 g_pars.sub.msisdn := new_msisdn;
Harald Welte09b3c502018-03-01 22:42:22 +0100768 setverdict(pass);
769 }
Harald Welteed380d12018-06-14 13:42:11 +0200770 [] GSUP.receive(tr_GSUP_ISD_REQ(g_pars.sub.imsi, g_pars.sub.msisdn)) {
Stefan Sperling7c096872018-04-09 11:24:22 +0200771 log("received ISD req with old MSISDN");
772 setverdict(fail);
773 }
Harald Welte09b3c502018-03-01 22:42:22 +0100774 [] GSUP.receive { repeat; }
775 [] T.timeout {
776 setverdict(fail, "Timeout waiting for ISD.req");
777 }
778 }
779}
Harald Welteed380d12018-06-14 13:42:11 +0200780testcase TC_vty_msisdn_isd() runs on test_CT {
781 var HlrSubscriber sub;
782 var HLR_ConnHdlr vc_conn;
783
784 f_init(false);
785
786 /* Create Subscriber */
787 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
788
789 vc_conn := f_start_handler(refers(f_TC_vty_msisdn_isd), valueof(t_Pars_sub(sub)));
790 vc_conn.done;
791}
Harald Welte09b3c502018-03-01 22:42:22 +0100792
Harald Welte958f8b42018-03-01 23:40:17 +0100793/* Test PURGE MS for CS services */
Harald Welteed380d12018-06-14 13:42:11 +0200794private function f_TC_gsup_purge_cs() runs on HLR_ConnHdlr {
795 var GSUP_PDU res;
796 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
797 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS);
798}
Harald Welte958f8b42018-03-01 23:40:17 +0100799testcase TC_gsup_purge_cs() runs on test_CT {
800 var HlrSubscriberList sl;
801 var GSUP_PDU res;
802
Harald Welteed380d12018-06-14 13:42:11 +0200803 f_init(false);
Harald Welte958f8b42018-03-01 23:40:17 +0100804 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200805 f_start_handler_per_sub(refers(f_TC_gsup_purge_cs), sl);
Harald Welte958f8b42018-03-01 23:40:17 +0100806
807 setverdict(pass);
808}
809
810/* Test PURGE MS for PS services */
Harald Welteed380d12018-06-14 13:42:11 +0200811private function f_TC_gsup_purge_ps() runs on HLR_ConnHdlr {
812 var GSUP_PDU res;
813 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
814 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_PS);
815}
Harald Welte958f8b42018-03-01 23:40:17 +0100816testcase TC_gsup_purge_ps() runs on test_CT {
817 var HlrSubscriberList sl;
Harald Welte958f8b42018-03-01 23:40:17 +0100818
Harald Welteed380d12018-06-14 13:42:11 +0200819 f_init(false);
Harald Welte958f8b42018-03-01 23:40:17 +0100820 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200821 f_start_handler_per_sub(refers(f_TC_gsup_purge_ps), sl);
Harald Welte958f8b42018-03-01 23:40:17 +0100822
823 setverdict(pass);
824}
825
826/* Test PURGEG MS procedure for unknown IMSI */
Harald Welteed380d12018-06-14 13:42:11 +0200827
828private function f_TC_gsup_purge_unknown() runs on HLR_ConnHdlr {
829 var GSUP_PDU res;
830 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS, 2);
831}
Harald Welte958f8b42018-03-01 23:40:17 +0100832testcase TC_gsup_purge_unknown() runs on test_CT {
833 var hexstring imsi := '2345743413463'H;
Harald Welteed380d12018-06-14 13:42:11 +0200834 var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
835 var HLR_ConnHdlr vc_conn;
Harald Welte958f8b42018-03-01 23:40:17 +0100836
Harald Welteed380d12018-06-14 13:42:11 +0200837 f_init(false);
838 vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
839 vc_conn.done;
Harald Welte958f8b42018-03-01 23:40:17 +0100840
841 setverdict(pass);
842}
843
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200844import from HLR_EUSE all;
845
846/* Test for USSD request to undefined/unrouted short-code. Expect ss-NotAvailable(18) */
847private function f_TC_mo_ussd_unknown() runs on HLR_ConnHdlr {
848 var GSUP_PDU res;
849 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
850 op_code := SS_OP_CODE_PROCESS_USS_REQ,
851 ussd_string := "*#200#");
852 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
853 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700854 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
855 OSMO_GSUP_SESSION_STATE_END,
856 tr_SS_FACILITY_RETURN_ERROR(1, 18));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200857}
858testcase TC_mo_ussd_unknown() runs on test_CT {
859 var HlrSubscriberList sl;
860 var HLR_ConnHdlr vc_conn;
861
862 f_init(false);
863 sl := f_gen_subs();
864 for (var integer i := 0; i < sizeof(sl); i := i+1) {
865 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
866 pars.ussd.sid := f_rnd_octstring(4);
867 f_vty_subscr_create(VTY, pars.sub);
868 vc_conn := f_start_handler(refers(f_TC_mo_ussd_unknown), pars);
869 vc_conn.done;
870 }
871}
872
873/* Test for USSD request to currently disconnected EUSE. Expect ss-SystemFailure(34) */
874private function f_TC_mo_ussd_euse_disc() runs on HLR_ConnHdlr {
875 var GSUP_PDU res;
876 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
877 op_code := SS_OP_CODE_PROCESS_USS_REQ,
878 ussd_string := "*100#");
879 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
880 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700881 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
882 OSMO_GSUP_SESSION_STATE_END,
883 tr_SS_FACILITY_RETURN_ERROR(1, 34));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200884}
885testcase TC_mo_ussd_euse_disc() runs on test_CT {
886 var HlrSubscriberList sl;
887 var HLR_ConnHdlr vc_conn;
888
889 f_init(false);
890 sl := f_gen_subs();
891 for (var integer i := 0; i < sizeof(sl); i := i+1) {
892 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
893 pars.ussd.sid := f_rnd_octstring(4);
894 f_vty_subscr_create(VTY, pars.sub);
895 vc_conn := f_start_handler(refers(f_TC_mo_ussd_euse_disc), pars);
896 vc_conn.done;
897 }
898}
899
900/* Test for USSD request to internal own-imsi IUSE. */
901private function f_TC_mo_ussd_iuse_imsi() runs on HLR_ConnHdlr {
902 var GSUP_PDU res;
903 var charstring resp_str;
904 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
905 op_code := SS_OP_CODE_PROCESS_USS_REQ,
906 ussd_string := "*#101#");
907 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
908 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
909 resp_str := "Your IMSI is " & hex2str(g_pars.sub.imsi);
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700910 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
911 OSMO_GSUP_SESSION_STATE_END,
912 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
913 f_encGSM7bit(resp_str)));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200914}
915testcase TC_mo_ussd_iuse_imsi() runs on test_CT {
916 var HlrSubscriberList sl;
917 var HLR_ConnHdlr vc_conn;
918
919 f_init(false);
920 sl := f_gen_subs();
921 for (var integer i := 0; i < sizeof(sl); i := i+1) {
922 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
923 pars.ussd.sid := f_rnd_octstring(4);
924 f_vty_subscr_create(VTY, pars.sub);
925 vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_imsi), pars);
926 vc_conn.done;
927 }
928}
929
930/* Test for USSD request to internal own-msisdn IUSE. */
931private function f_TC_mo_ussd_iuse_msisdn() runs on HLR_ConnHdlr {
932 var GSUP_PDU res;
933 var charstring resp_str;
934 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
935 op_code := SS_OP_CODE_PROCESS_USS_REQ,
936 ussd_string := "*#100#");
937 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
938 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
939 resp_str := "Your extension is " & hex2str(g_pars.sub.msisdn);
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700940 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
941 OSMO_GSUP_SESSION_STATE_END,
942 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
943 f_encGSM7bit(resp_str)));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200944}
945testcase TC_mo_ussd_iuse_msisdn() runs on test_CT {
946 var HlrSubscriberList sl;
947 var HLR_ConnHdlr vc_conn;
948
949 f_init(false);
950 sl := f_gen_subs();
951 for (var integer i := 0; i < sizeof(sl); i := i+1) {
952 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
953 pars.ussd.sid := f_rnd_octstring(4);
954 f_vty_subscr_create(VTY, pars.sub);
955 vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_msisdn), pars);
956 vc_conn.done;
957 }
958}
959
960/* Test routing of USSD to EUSE by a specific route */
961private function f_TC_mo_ussd_100() runs on HLR_ConnHdlr {
962 var GSUP_PDU res;
963 /* invoke / invoke id 1 / processUSS-req */
964 //var octetstring ss := 'a11202010102013b300a04010f0405aa180c3602'O;
965 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
966 op_code := SS_OP_CODE_PROCESS_USS_REQ,
967 ussd_string := "*100#");
968 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
969 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700970 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
971 OSMO_GSUP_SESSION_STATE_END,
972 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
973 f_encGSM7bit("*100#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200974}
975testcase TC_mo_ussd_euse() runs on test_CT {
976 var HlrSubscriberList sl;
977 var HLR_ConnHdlr vc_conn;
978
979 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
980 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar", refers(f_ss_echo)));
981
982 f_init(false);
983 sl := f_gen_subs();
984 for (var integer i := 0; i < sizeof(sl); i := i+1) {
985 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
986 pars.ussd.sid := f_rnd_octstring(4);
987 f_vty_subscr_create(VTY, pars.sub);
988 vc_conn := f_start_handler(refers(f_TC_mo_ussd_100), pars);
989 vc_conn.done;
990 }
991
992 vc_EUSE.stop;
993}
994
995/* Test routing of USSD to EUSE by a specific route, with CONTINUE */
996private function f_TC_mo_ussd_100_continue() runs on HLR_ConnHdlr {
997 var GSUP_PDU res;
998 /* Simulate BEGIN from MS/MSC */
999 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(op_code := SS_OP_CODE_PROCESS_USS_REQ,
1000 ussd_string := "*100#");
1001 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
1002 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
1003 /* expect echo response from EUSE */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001004 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
1005 OSMO_GSUP_SESSION_STATE_CONTINUE,
1006 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
1007 f_encGSM7bit("*100#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001008
1009 /* Simulate CONTINUE from MS/MSC */
1010 ss := f_USSD_FACILITY_IE_INVOKE(op_code := SS_OP_CODE_PROCESS_USS_REQ,
1011 ussd_string := "mahlzeit");
1012 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
1013 OSMO_GSUP_SESSION_STATE_CONTINUE, ss)));
1014
1015 /* expect echo response from EUSE */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001016 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
1017 OSMO_GSUP_SESSION_STATE_END,
1018 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
1019 f_encGSM7bit("mahlzeit")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001020}
1021testcase TC_mo_ussd_euse_continue() runs on test_CT {
1022 var HlrSubscriberList sl;
1023 var HLR_ConnHdlr vc_conn;
1024
1025 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
1026 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar",
1027 refers(f_ss_echo_continue)));
1028
1029 f_init(false);
1030 sl := f_gen_subs();
1031 for (var integer i := 0; i < sizeof(sl); i := i+1) {
1032 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
1033 pars.ussd.sid := f_rnd_octstring(4);
1034 f_vty_subscr_create(VTY, pars.sub);
1035 vc_conn := f_start_handler(refers(f_TC_mo_ussd_100_continue), pars);
1036 vc_conn.done;
1037 }
1038
1039 vc_EUSE.stop;
1040}
1041
1042
1043/* Test routing of USSD to EUSE by default-route */
1044private function f_TC_mo_ussd_999() runs on HLR_ConnHdlr {
1045 var GSUP_PDU res;
1046 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
1047 op_code := SS_OP_CODE_PROCESS_USS_REQ,
1048 ussd_string := "*999#");
1049 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
1050 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001051 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
1052 OSMO_GSUP_SESSION_STATE_END,
1053 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
1054 f_encGSM7bit("*999#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001055}
1056testcase TC_mo_ussd_euse_defaultroute() runs on test_CT {
1057 var HlrSubscriberList sl;
1058 var HLR_ConnHdlr vc_conn;
1059
1060 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
1061 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar", refers(f_ss_echo)));
1062
1063 f_init(false);
1064 f_vty_config(VTY, "hlr", "ussd default-route external foobar");
1065
1066 sl := f_gen_subs();
1067 for (var integer i := 0; i < sizeof(sl); i := i+1) {
1068 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
1069 pars.ussd.sid := f_rnd_octstring(4);
1070 f_vty_subscr_create(VTY, pars.sub);
1071 vc_conn := f_start_handler(refers(f_TC_mo_ussd_999), pars);
1072 vc_conn.done;
1073 }
1074
1075 f_vty_config(VTY, "hlr", "no ussd default-route");
1076 vc_EUSE.stop;
1077}
1078
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001079/**
1080 * Test "Structured" Supplementary Services
1081 *
1082 * NOTE: at the moment, OsmoHLR doesn't support "structured" SS,
1083 * so such requests are being rejected (actually ReturnError
1084 * with GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED).
1085 */
1086private function f_TC_mo_sss_reject() runs on HLR_ConnHdlr {
1087 var SS_FacilityInformation ss_req;
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001088 var GSUP_PDU res;
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001089
1090 /* Prepare '*#21#' SS request */
1091 ss_req := valueof(ts_SS_FACILITY_INVOKE(
1092 invoke_id := 0,
1093 op_code := SS_OP_CODE_INTERROGATE_SS,
1094 ss_code := '21'O));
1095
1096 /* Send it towards HLR */
1097 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(
1098 g_pars.sub.imsi,
1099 g_pars.ussd.sid,
1100 OSMO_GSUP_SESSION_STATE_BEGIN,
1101 enc_SS_FacilityInformation(ss_req))));
1102
1103 /* Expect ReturnError with FACILITY_NOT_SUPPORTED */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001104 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
1105 OSMO_GSUP_SESSION_STATE_END,
1106 tr_SS_FACILITY_RETURN_ERROR(0, 21));
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001107}
1108testcase TC_mo_sss_reject() runs on test_CT {
1109 var HLR_ConnHdlrPars pars;
1110 var HLR_ConnHdlr vc_conn;
1111 var HlrSubscriber sub;
1112
1113 f_init(false);
1114
1115 /* Create a random subscriber */
1116 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H),
1117 '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
1118 pars := valueof(t_Pars_sub(sub));
1119 pars.ussd.sid := f_rnd_octstring(4);
1120
1121 f_vty_subscr_create(VTY, sub);
1122 vc_conn := f_start_handler(refers(f_TC_mo_sss_reject), pars);
1123 vc_conn.done;
1124 f_vty_subscr_delete(VTY, sub);
1125}
1126
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001127
1128/* TODO USSD:
1129 * MO USSD for IMSI of non-existant subscriber
1130 * MT USSD from EUSE
1131 * timeout cases
1132 */
1133
Oliver Smith936dbe62019-06-04 15:54:17 +02001134
1135/* Test Check IMEI */
1136private function f_TC_gsup_check_imei() runs on HLR_ConnHdlr {
1137 /* store-imei disabled */
1138 f_vty_config(VTY, "hlr", "no store-imei");
1139 f_perform_CHECK_IMEI(g_pars.sub.imsi, '12345678901234'H, result := OSMO_GSUP_IMEI_RESULT_ACK);
1140 f_vty_subscr_show_nomatch(VTY, g_pars.sub, pattern "*IMEI: *12345678901234*");
1141
1142 /* store-imei enabled */
1143 f_vty_config(VTY, "hlr", "store-imei");
1144 f_perform_CHECK_IMEI(g_pars.sub.imsi, '12345678901234'H, result := OSMO_GSUP_IMEI_RESULT_ACK);
1145 f_vty_subscr_show(VTY, g_pars.sub, pattern "*IMEI: *12345678901234*");
1146}
1147testcase TC_gsup_check_imei() runs on test_CT {
1148 var HlrSubscriberList sl;
1149
1150 f_init(false);
1151 sl := f_gen_subs();
1152 f_start_handler_per_sub(refers(f_TC_gsup_check_imei), sl);
1153
1154 setverdict(pass);
1155}
1156
1157/* Test Check IMEI with invalid IMEI length */
1158private function f_TC_gsup_check_imei_invalid_len() runs on HLR_ConnHdlr {
1159 /* IMEI too long */
1160 f_perform_CHECK_IMEI(g_pars.sub.imsi, '111456789012345F'H, 96 /* Invalid Mandatory Information */);
1161 f_perform_CHECK_IMEI(g_pars.sub.imsi, '2224567890123456'H, 96 /* Invalid Mandatory Information */);
1162
1163 /* IMEI too short */
1164 f_perform_CHECK_IMEI(g_pars.sub.imsi, '3334567890123F'H, 96 /* Invalid Mandatory Information */);
1165 f_perform_CHECK_IMEI(g_pars.sub.imsi, '444456789012'H, 96 /* Invalid Mandatory Information */);
1166 f_perform_CHECK_IMEI(g_pars.sub.imsi, ''H, 96 /* Invalid Mandatory Information */);
1167}
1168testcase TC_gsup_check_imei_invalid_len() runs on test_CT {
1169 var HlrSubscriberList sl;
1170
1171 f_init(false);
1172 sl := f_gen_subs();
1173 f_start_handler_per_sub(refers(f_TC_gsup_check_imei_invalid_len), sl);
1174
1175 setverdict(pass);
1176}
1177
1178/* Test Check IMEI with unknown IMSI */
1179private function f_TC_gsup_check_imei_unknown_imsi() runs on HLR_ConnHdlr {
1180 f_vty_config(VTY, "hlr", "no store-imei");
1181 f_perform_CHECK_IMEI(g_pars.sub.imsi, '22245678901234'H, 96 /* Invalid Mandatory Information */);
1182
1183 /* Check again with store-imei set (different code path) */
1184 f_vty_config(VTY, "hlr", "store-imei");
1185 f_perform_CHECK_IMEI(g_pars.sub.imsi, '22245678901234'H, 96 /* Invalid Mandatory Information */);
1186
1187 setverdict(pass);
1188}
1189testcase TC_gsup_check_imei_unknown_imsi() runs on test_CT {
1190 var hexstring imsi := f_rnd_imsi('26242'H);
1191 var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
1192 var HLR_ConnHdlr vc_conn;
1193
1194 f_init(false);
1195 vc_conn := f_start_handler(refers(f_TC_gsup_check_imei_unknown_imsi), pars);
1196 vc_conn.done;
1197}
1198
Harald Weltec2c52552018-03-01 21:20:39 +01001199/* TODO:
1200 * UL with ISD error
1201 * UL with ISD timeout
Harald Weltec2c52552018-03-01 21:20:39 +01001202 * LOCATION CANCEL
1203 * AUTH FAIL REP
1204 * DELETE DATA after hlr_subscr_nam() change
1205 * correctness
1206 ** wrong message type
1207 ** wrong length of PDU
1208 ** too short message
1209 ** missing IMSI IE
1210
1211 */
1212
Harald Weltedf327232017-12-28 22:51:51 +01001213control {
1214 execute( TC_gsup_sai_err_invalid_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +01001215 execute( TC_gsup_sai() );
1216 execute( TC_gsup_ul_unknown_imsi() );
Harald Welte3f662762018-03-02 10:48:20 +01001217 execute( TC_gsup_sai_err_unknown_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +01001218 execute( TC_gsup_ul() );
1219 execute( TC_vty() );
Harald Welte09b3c502018-03-01 22:42:22 +01001220 execute( TC_vty_msisdn_isd() );
Harald Welte958f8b42018-03-01 23:40:17 +01001221 execute( TC_gsup_purge_cs() );
1222 execute( TC_gsup_purge_ps() );
1223 execute( TC_gsup_purge_unknown() );
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001224
1225 execute( TC_mo_ussd_unknown() );
1226 execute( TC_mo_ussd_euse_disc() );
1227 execute( TC_mo_ussd_iuse_imsi() );
1228 execute( TC_mo_ussd_iuse_msisdn() );
1229 execute( TC_mo_ussd_euse() );
1230 execute( TC_mo_ussd_euse_continue() );
1231 execute( TC_mo_ussd_euse_defaultroute() );
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001232
1233 /* "Structured" Supplementary Services */
1234 execute( TC_mo_sss_reject() );
Oliver Smith936dbe62019-06-04 15:54:17 +02001235
1236 execute( TC_gsup_check_imei() );
1237 execute( TC_gsup_check_imei_invalid_len() );
1238 execute( TC_gsup_check_imei_unknown_imsi() );
Harald Weltedf327232017-12-28 22:51:51 +01001239};
1240
1241};