blob: e58515b7e5f4b0a74924f155bc92b2fb6c2b2c22 [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
577
Harald Welte958f8b42018-03-01 23:40:17 +0100578
Harald Welteed380d12018-06-14 13:42:11 +0200579/***********************************************************************
580 * Testcases
581 ***********************************************************************/
582
583/* 23.003 Section 2.2 clearly states that an IMSI with less
584 * than 5 digits is impossible. Even 5 digits is still questionable */
585private function f_TC_gsup_sai_err_invalid_imsi() runs on HLR_ConnHdlr {
Harald Weltec2c52552018-03-01 21:20:39 +0100586 var GSUP_PDU res;
Harald Welteed380d12018-06-14 13:42:11 +0200587 res := f_perform_SAI(g_pars.sub.imsi, 96); /* Invalid Mandatory information */
588 setverdict(pass);
589}
590testcase TC_gsup_sai_err_invalid_imsi() runs on test_CT {
591 var HLR_ConnHdlr vc_conn;
592 var HLR_ConnHdlrPars pars := valueof(t_Pars('0123'H));
593 f_init(false);
594 vc_conn := f_start_handler(refers(f_TC_gsup_sai_err_invalid_imsi), pars);
595 vc_conn.done;
596}
Harald Weltec2c52552018-03-01 21:20:39 +0100597
Harald Weltec2c52552018-03-01 21:20:39 +0100598
Harald Welteed380d12018-06-14 13:42:11 +0200599private function f_TC_gsup_sai_err_unknown_imsi() runs on HLR_ConnHdlr {
600 var GSUP_PDU res;
601 res := f_perform_SAI(g_pars.sub.imsi, 2);
Harald Weltec2c52552018-03-01 21:20:39 +0100602 setverdict(pass);
603}
604
Harald Welte3f662762018-03-02 10:48:20 +0100605testcase TC_gsup_sai_err_unknown_imsi() runs on test_CT {
Harald Welteed380d12018-06-14 13:42:11 +0200606 var HLR_ConnHdlr vc_conn;
607 var HLR_ConnHdlrPars pars := valueof(t_Pars(f_rnd_imsi('26242'H)));
608 f_init(false);
609 vc_conn := f_start_handler(refers(f_TC_gsup_sai_err_unknown_imsi), pars);
610 vc_conn.done;
Harald Welte3f662762018-03-02 10:48:20 +0100611}
612
Harald Welteed380d12018-06-14 13:42:11 +0200613function f_start_handler_per_sub(void_fn fn, HlrSubscriberList sl) runs on test_CT {
614 for (var integer i := 0; i < sizeof(sl); i := i+1) {
615 var HlrSubscriber sub := sl[i];
616 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sub));
617 var HLR_ConnHdlr vc_conn;
618
619 f_vty_subscr_create(VTY, sub);
620 vc_conn := f_start_handler(fn, pars);
621 vc_conn.done;
622 f_vty_subscr_delete(VTY, sub);
623 }
624}
Harald Welte3f662762018-03-02 10:48:20 +0100625
Harald Weltec2c52552018-03-01 21:20:39 +0100626/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
Harald Welteed380d12018-06-14 13:42:11 +0200627private function f_TC_gsup_sai() runs on HLR_ConnHdlr {
628 var GSUP_PDU res;
629 res := f_perform_SAI(g_pars.sub.imsi);
630 /* TODO: match if tuple[s] matches expectation */
631 setverdict(pass);
632}
Harald Weltec2c52552018-03-01 21:20:39 +0100633testcase TC_gsup_sai() runs on test_CT {
634 var HlrSubscriberList sl;
635 var GSUP_PDU res;
636
Harald Welteed380d12018-06-14 13:42:11 +0200637 f_init(false);
Harald Weltec2c52552018-03-01 21:20:39 +0100638
639 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200640 f_start_handler_per_sub(refers(f_TC_gsup_sai), sl);
Harald Weltec2c52552018-03-01 21:20:39 +0100641
642 setverdict(pass);
643}
644
645/* test UL for unknown IMSI */
Harald Welteed380d12018-06-14 13:42:11 +0200646private function f_TC_ul_unknown_imsi() runs on HLR_ConnHdlr {
Harald Weltec2c52552018-03-01 21:20:39 +0100647 var GSUP_PDU res;
Harald Welteed380d12018-06-14 13:42:11 +0200648 res := f_perform_UL(g_pars.sub.imsi, ?, 2);
Harald Weltec2c52552018-03-01 21:20:39 +0100649 setverdict(pass);
650}
Harald Welteed380d12018-06-14 13:42:11 +0200651testcase TC_gsup_ul_unknown_imsi() runs on test_CT {
652 var hexstring imsi := f_rnd_imsi('26242'H);
653 var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
654 var HLR_ConnHdlr vc_conn;
Harald Weltec2c52552018-03-01 21:20:39 +0100655
Harald Welteed380d12018-06-14 13:42:11 +0200656 f_init(false);
657 vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
658 vc_conn.done;
659}
660
661/* test UL for a number of different subscriber cases (algo, 2g/3g, ...) */
662private function f_TC_gsup_ul() runs on HLR_ConnHdlr {
663 var GSUP_PDU res;
664 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
665 setverdict(pass);
666}
Harald Weltec2c52552018-03-01 21:20:39 +0100667testcase TC_gsup_ul() runs on test_CT {
668 var HlrSubscriberList sl;
669 var GSUP_PDU res;
670
Harald Welteed380d12018-06-14 13:42:11 +0200671 f_init(false);
Harald Weltec2c52552018-03-01 21:20:39 +0100672 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200673 f_start_handler_per_sub(refers(f_TC_gsup_ul), sl);
Harald Weltec2c52552018-03-01 21:20:39 +0100674
675 setverdict(pass);
676}
677
678/* Test only the VTY commands */
679testcase TC_vty() runs on test_CT {
680 var HlrSubscriber sub;
681
682 f_init();
683
684 /* we're not using f_gen_subs() here as the expect pattern for the 'show' are different
685 * from case to case */
686 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
Harald Welteed380d12018-06-14 13:42:11 +0200687 f_vty_subscr_create(VTY, sub);
688 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *2G auth: COMP128v1*");
689 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100690
691 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
692 "milenage", false));
Harald Welteed380d12018-06-14 13:42:11 +0200693 f_vty_subscr_create(VTY, sub);
694 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *3G auth: MILENAGE*");
695 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100696
697 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
698 "comp128v1", "milenage", false));
Harald Welteed380d12018-06-14 13:42:11 +0200699 f_vty_subscr_create(VTY, sub);
700 f_vty_subscr_show(VTY, sub, pattern "*IMSI: *2G auth: COMP128v1*3G auth: MILENAGE*");
701 f_vty_subscr_delete(VTY, sub);
Harald Weltec2c52552018-03-01 21:20:39 +0100702
703 setverdict(pass);
704}
705
Harald Welte09b3c502018-03-01 22:42:22 +0100706/* VTY changes to MSISDN should result in ISD to current VLR */
Harald Welteed380d12018-06-14 13:42:11 +0200707private function f_TC_vty_msisdn_isd() runs on HLR_ConnHdlr {
Harald Welte09b3c502018-03-01 22:42:22 +0100708 var hexstring new_msisdn;
709 var GSUP_PDU res;
710 timer T := 5.0;
711
Harald Welte09b3c502018-03-01 22:42:22 +0100712 /* Create Subscriber */
Harald Welteed380d12018-06-14 13:42:11 +0200713 f_vty_subscr_create(VTY, g_pars.sub);
Harald Welte09b3c502018-03-01 22:42:22 +0100714
715 /* Perform UpdateLocation (VLR now known to HLR) */
Harald Welteed380d12018-06-14 13:42:11 +0200716 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
Harald Welte09b3c502018-03-01 22:42:22 +0100717
718 /* Then change IMSI via VTY */
719 new_msisdn := '49161'H & f_rnd_hexstring(7, 9);
Harald Welteed380d12018-06-14 13:42:11 +0200720 f_vty_subscr_update_msisdn(VTY, g_pars.sub, new_msisdn);
Harald Welte09b3c502018-03-01 22:42:22 +0100721 /* And expect InsertSubscriberData as result */
722 T.start;
723 alt {
Harald Welteed380d12018-06-14 13:42:11 +0200724 [] GSUP.receive(tr_GSUP_ISD_REQ(g_pars.sub.imsi, new_msisdn)) {
725 GSUP.send(ts_GSUP_ISD_RES(g_pars.sub.imsi));
726 g_pars.sub.msisdn := new_msisdn;
Harald Welte09b3c502018-03-01 22:42:22 +0100727 setverdict(pass);
728 }
Harald Welteed380d12018-06-14 13:42:11 +0200729 [] GSUP.receive(tr_GSUP_ISD_REQ(g_pars.sub.imsi, g_pars.sub.msisdn)) {
Stefan Sperling7c096872018-04-09 11:24:22 +0200730 log("received ISD req with old MSISDN");
731 setverdict(fail);
732 }
Harald Welte09b3c502018-03-01 22:42:22 +0100733 [] GSUP.receive { repeat; }
734 [] T.timeout {
735 setverdict(fail, "Timeout waiting for ISD.req");
736 }
737 }
738}
Harald Welteed380d12018-06-14 13:42:11 +0200739testcase TC_vty_msisdn_isd() runs on test_CT {
740 var HlrSubscriber sub;
741 var HLR_ConnHdlr vc_conn;
742
743 f_init(false);
744
745 /* Create Subscriber */
746 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
747
748 vc_conn := f_start_handler(refers(f_TC_vty_msisdn_isd), valueof(t_Pars_sub(sub)));
749 vc_conn.done;
750}
Harald Welte09b3c502018-03-01 22:42:22 +0100751
Harald Welte958f8b42018-03-01 23:40:17 +0100752/* Test PURGE MS for CS services */
Harald Welteed380d12018-06-14 13:42:11 +0200753private function f_TC_gsup_purge_cs() runs on HLR_ConnHdlr {
754 var GSUP_PDU res;
755 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
756 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS);
757}
Harald Welte958f8b42018-03-01 23:40:17 +0100758testcase TC_gsup_purge_cs() runs on test_CT {
759 var HlrSubscriberList sl;
760 var GSUP_PDU res;
761
Harald Welteed380d12018-06-14 13:42:11 +0200762 f_init(false);
Harald Welte958f8b42018-03-01 23:40:17 +0100763 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200764 f_start_handler_per_sub(refers(f_TC_gsup_purge_cs), sl);
Harald Welte958f8b42018-03-01 23:40:17 +0100765
766 setverdict(pass);
767}
768
769/* Test PURGE MS for PS services */
Harald Welteed380d12018-06-14 13:42:11 +0200770private function f_TC_gsup_purge_ps() runs on HLR_ConnHdlr {
771 var GSUP_PDU res;
772 res := f_perform_UL(g_pars.sub.imsi, g_pars.sub.msisdn);
773 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_PS);
774}
Harald Welte958f8b42018-03-01 23:40:17 +0100775testcase TC_gsup_purge_ps() runs on test_CT {
776 var HlrSubscriberList sl;
Harald Welte958f8b42018-03-01 23:40:17 +0100777
Harald Welteed380d12018-06-14 13:42:11 +0200778 f_init(false);
Harald Welte958f8b42018-03-01 23:40:17 +0100779 sl := f_gen_subs();
Harald Welteed380d12018-06-14 13:42:11 +0200780 f_start_handler_per_sub(refers(f_TC_gsup_purge_ps), sl);
Harald Welte958f8b42018-03-01 23:40:17 +0100781
782 setverdict(pass);
783}
784
785/* Test PURGEG MS procedure for unknown IMSI */
Harald Welteed380d12018-06-14 13:42:11 +0200786
787private function f_TC_gsup_purge_unknown() runs on HLR_ConnHdlr {
788 var GSUP_PDU res;
789 res := f_perform_PURGE(g_pars.sub.imsi, OSMO_GSUP_CN_DOMAIN_CS, 2);
790}
Harald Welte958f8b42018-03-01 23:40:17 +0100791testcase TC_gsup_purge_unknown() runs on test_CT {
792 var hexstring imsi := '2345743413463'H;
Harald Welteed380d12018-06-14 13:42:11 +0200793 var HLR_ConnHdlrPars pars := valueof(t_Pars(imsi));
794 var HLR_ConnHdlr vc_conn;
Harald Welte958f8b42018-03-01 23:40:17 +0100795
Harald Welteed380d12018-06-14 13:42:11 +0200796 f_init(false);
797 vc_conn := f_start_handler(refers(f_TC_ul_unknown_imsi), pars);
798 vc_conn.done;
Harald Welte958f8b42018-03-01 23:40:17 +0100799
800 setverdict(pass);
801}
802
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200803import from HLR_EUSE all;
804
805/* Test for USSD request to undefined/unrouted short-code. Expect ss-NotAvailable(18) */
806private function f_TC_mo_ussd_unknown() runs on HLR_ConnHdlr {
807 var GSUP_PDU res;
808 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
809 op_code := SS_OP_CODE_PROCESS_USS_REQ,
810 ussd_string := "*#200#");
811 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
812 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700813 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
814 OSMO_GSUP_SESSION_STATE_END,
815 tr_SS_FACILITY_RETURN_ERROR(1, 18));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200816}
817testcase TC_mo_ussd_unknown() runs on test_CT {
818 var HlrSubscriberList sl;
819 var HLR_ConnHdlr vc_conn;
820
821 f_init(false);
822 sl := f_gen_subs();
823 for (var integer i := 0; i < sizeof(sl); i := i+1) {
824 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
825 pars.ussd.sid := f_rnd_octstring(4);
826 f_vty_subscr_create(VTY, pars.sub);
827 vc_conn := f_start_handler(refers(f_TC_mo_ussd_unknown), pars);
828 vc_conn.done;
829 }
830}
831
832/* Test for USSD request to currently disconnected EUSE. Expect ss-SystemFailure(34) */
833private function f_TC_mo_ussd_euse_disc() runs on HLR_ConnHdlr {
834 var GSUP_PDU res;
835 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
836 op_code := SS_OP_CODE_PROCESS_USS_REQ,
837 ussd_string := "*100#");
838 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
839 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700840 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
841 OSMO_GSUP_SESSION_STATE_END,
842 tr_SS_FACILITY_RETURN_ERROR(1, 34));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200843}
844testcase TC_mo_ussd_euse_disc() runs on test_CT {
845 var HlrSubscriberList sl;
846 var HLR_ConnHdlr vc_conn;
847
848 f_init(false);
849 sl := f_gen_subs();
850 for (var integer i := 0; i < sizeof(sl); i := i+1) {
851 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
852 pars.ussd.sid := f_rnd_octstring(4);
853 f_vty_subscr_create(VTY, pars.sub);
854 vc_conn := f_start_handler(refers(f_TC_mo_ussd_euse_disc), pars);
855 vc_conn.done;
856 }
857}
858
859/* Test for USSD request to internal own-imsi IUSE. */
860private function f_TC_mo_ussd_iuse_imsi() runs on HLR_ConnHdlr {
861 var GSUP_PDU res;
862 var charstring resp_str;
863 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
864 op_code := SS_OP_CODE_PROCESS_USS_REQ,
865 ussd_string := "*#101#");
866 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
867 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
868 resp_str := "Your IMSI is " & hex2str(g_pars.sub.imsi);
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700869 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
870 OSMO_GSUP_SESSION_STATE_END,
871 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
872 f_encGSM7bit(resp_str)));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200873}
874testcase TC_mo_ussd_iuse_imsi() runs on test_CT {
875 var HlrSubscriberList sl;
876 var HLR_ConnHdlr vc_conn;
877
878 f_init(false);
879 sl := f_gen_subs();
880 for (var integer i := 0; i < sizeof(sl); i := i+1) {
881 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
882 pars.ussd.sid := f_rnd_octstring(4);
883 f_vty_subscr_create(VTY, pars.sub);
884 vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_imsi), pars);
885 vc_conn.done;
886 }
887}
888
889/* Test for USSD request to internal own-msisdn IUSE. */
890private function f_TC_mo_ussd_iuse_msisdn() runs on HLR_ConnHdlr {
891 var GSUP_PDU res;
892 var charstring resp_str;
893 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
894 op_code := SS_OP_CODE_PROCESS_USS_REQ,
895 ussd_string := "*#100#");
896 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
897 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
898 resp_str := "Your extension is " & hex2str(g_pars.sub.msisdn);
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700899 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
900 OSMO_GSUP_SESSION_STATE_END,
901 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
902 f_encGSM7bit(resp_str)));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200903}
904testcase TC_mo_ussd_iuse_msisdn() runs on test_CT {
905 var HlrSubscriberList sl;
906 var HLR_ConnHdlr vc_conn;
907
908 f_init(false);
909 sl := f_gen_subs();
910 for (var integer i := 0; i < sizeof(sl); i := i+1) {
911 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
912 pars.ussd.sid := f_rnd_octstring(4);
913 f_vty_subscr_create(VTY, pars.sub);
914 vc_conn := f_start_handler(refers(f_TC_mo_ussd_iuse_msisdn), pars);
915 vc_conn.done;
916 }
917}
918
919/* Test routing of USSD to EUSE by a specific route */
920private function f_TC_mo_ussd_100() runs on HLR_ConnHdlr {
921 var GSUP_PDU res;
922 /* invoke / invoke id 1 / processUSS-req */
923 //var octetstring ss := 'a11202010102013b300a04010f0405aa180c3602'O;
924 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
925 op_code := SS_OP_CODE_PROCESS_USS_REQ,
926 ussd_string := "*100#");
927 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
928 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700929 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
930 OSMO_GSUP_SESSION_STATE_END,
931 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
932 f_encGSM7bit("*100#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200933}
934testcase TC_mo_ussd_euse() runs on test_CT {
935 var HlrSubscriberList sl;
936 var HLR_ConnHdlr vc_conn;
937
938 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
939 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar", refers(f_ss_echo)));
940
941 f_init(false);
942 sl := f_gen_subs();
943 for (var integer i := 0; i < sizeof(sl); i := i+1) {
944 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
945 pars.ussd.sid := f_rnd_octstring(4);
946 f_vty_subscr_create(VTY, pars.sub);
947 vc_conn := f_start_handler(refers(f_TC_mo_ussd_100), pars);
948 vc_conn.done;
949 }
950
951 vc_EUSE.stop;
952}
953
954/* Test routing of USSD to EUSE by a specific route, with CONTINUE */
955private function f_TC_mo_ussd_100_continue() runs on HLR_ConnHdlr {
956 var GSUP_PDU res;
957 /* Simulate BEGIN from MS/MSC */
958 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(op_code := SS_OP_CODE_PROCESS_USS_REQ,
959 ussd_string := "*100#");
960 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
961 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
962 /* expect echo response from EUSE */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700963 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
964 OSMO_GSUP_SESSION_STATE_CONTINUE,
965 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
966 f_encGSM7bit("*100#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200967
968 /* Simulate CONTINUE from MS/MSC */
969 ss := f_USSD_FACILITY_IE_INVOKE(op_code := SS_OP_CODE_PROCESS_USS_REQ,
970 ussd_string := "mahlzeit");
971 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
972 OSMO_GSUP_SESSION_STATE_CONTINUE, ss)));
973
974 /* expect echo response from EUSE */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +0700975 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
976 OSMO_GSUP_SESSION_STATE_END,
977 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
978 f_encGSM7bit("mahlzeit")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +0200979}
980testcase TC_mo_ussd_euse_continue() runs on test_CT {
981 var HlrSubscriberList sl;
982 var HLR_ConnHdlr vc_conn;
983
984 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
985 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar",
986 refers(f_ss_echo_continue)));
987
988 f_init(false);
989 sl := f_gen_subs();
990 for (var integer i := 0; i < sizeof(sl); i := i+1) {
991 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
992 pars.ussd.sid := f_rnd_octstring(4);
993 f_vty_subscr_create(VTY, pars.sub);
994 vc_conn := f_start_handler(refers(f_TC_mo_ussd_100_continue), pars);
995 vc_conn.done;
996 }
997
998 vc_EUSE.stop;
999}
1000
1001
1002/* Test routing of USSD to EUSE by default-route */
1003private function f_TC_mo_ussd_999() runs on HLR_ConnHdlr {
1004 var GSUP_PDU res;
1005 var octetstring ss := f_USSD_FACILITY_IE_INVOKE(
1006 op_code := SS_OP_CODE_PROCESS_USS_REQ,
1007 ussd_string := "*999#");
1008 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(g_pars.sub.imsi, g_pars.ussd.sid,
1009 OSMO_GSUP_SESSION_STATE_BEGIN, ss)));
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001010 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
1011 OSMO_GSUP_SESSION_STATE_END,
1012 tr_SS_USSD_FACILITY_RETURN_RESULT(1, 59, SS_USSD_DEFAULT_DCS,
1013 f_encGSM7bit("*999#")));
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001014}
1015testcase TC_mo_ussd_euse_defaultroute() runs on test_CT {
1016 var HlrSubscriberList sl;
1017 var HLR_ConnHdlr vc_conn;
1018
1019 var HLR_EUSE_CT vc_EUSE := HLR_EUSE_CT.create("EUSE-" & testcasename());
1020 vc_EUSE.start(HLR_EUSE.f_main_mo(mp_hlr_ip, mp_hlr_gsup_port, "foobar", refers(f_ss_echo)));
1021
1022 f_init(false);
1023 f_vty_config(VTY, "hlr", "ussd default-route external foobar");
1024
1025 sl := f_gen_subs();
1026 for (var integer i := 0; i < sizeof(sl); i := i+1) {
1027 var HLR_ConnHdlrPars pars := valueof(t_Pars_sub(sl[i]));
1028 pars.ussd.sid := f_rnd_octstring(4);
1029 f_vty_subscr_create(VTY, pars.sub);
1030 vc_conn := f_start_handler(refers(f_TC_mo_ussd_999), pars);
1031 vc_conn.done;
1032 }
1033
1034 f_vty_config(VTY, "hlr", "no ussd default-route");
1035 vc_EUSE.stop;
1036}
1037
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001038/**
1039 * Test "Structured" Supplementary Services
1040 *
1041 * NOTE: at the moment, OsmoHLR doesn't support "structured" SS,
1042 * so such requests are being rejected (actually ReturnError
1043 * with GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED).
1044 */
1045private function f_TC_mo_sss_reject() runs on HLR_ConnHdlr {
1046 var SS_FacilityInformation ss_req;
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001047 var GSUP_PDU res;
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001048
1049 /* Prepare '*#21#' SS request */
1050 ss_req := valueof(ts_SS_FACILITY_INVOKE(
1051 invoke_id := 0,
1052 op_code := SS_OP_CODE_INTERROGATE_SS,
1053 ss_code := '21'O));
1054
1055 /* Send it towards HLR */
1056 GSUP.send(valueof(ts_GSUP_PROC_SS_REQ(
1057 g_pars.sub.imsi,
1058 g_pars.ussd.sid,
1059 OSMO_GSUP_SESSION_STATE_BEGIN,
1060 enc_SS_FacilityInformation(ss_req))));
1061
1062 /* Expect ReturnError with FACILITY_NOT_SUPPORTED */
Vadim Yanitskiy06e53c52019-03-28 15:08:24 +07001063 res := f_SS_expect(g_pars.sub.imsi, g_pars.ussd.sid,
1064 OSMO_GSUP_SESSION_STATE_END,
1065 tr_SS_FACILITY_RETURN_ERROR(0, 21));
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001066}
1067testcase TC_mo_sss_reject() runs on test_CT {
1068 var HLR_ConnHdlrPars pars;
1069 var HLR_ConnHdlr vc_conn;
1070 var HlrSubscriber sub;
1071
1072 f_init(false);
1073
1074 /* Create a random subscriber */
1075 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H),
1076 '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
1077 pars := valueof(t_Pars_sub(sub));
1078 pars.ussd.sid := f_rnd_octstring(4);
1079
1080 f_vty_subscr_create(VTY, sub);
1081 vc_conn := f_start_handler(refers(f_TC_mo_sss_reject), pars);
1082 vc_conn.done;
1083 f_vty_subscr_delete(VTY, sub);
1084}
1085
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001086
1087/* TODO USSD:
1088 * MO USSD for IMSI of non-existant subscriber
1089 * MT USSD from EUSE
1090 * timeout cases
1091 */
1092
Harald Weltec2c52552018-03-01 21:20:39 +01001093/* TODO:
1094 * UL with ISD error
1095 * UL with ISD timeout
Harald Weltec2c52552018-03-01 21:20:39 +01001096 * LOCATION CANCEL
1097 * AUTH FAIL REP
1098 * DELETE DATA after hlr_subscr_nam() change
1099 * correctness
1100 ** wrong message type
1101 ** wrong length of PDU
1102 ** too short message
1103 ** missing IMSI IE
1104
1105 */
1106
Harald Weltedf327232017-12-28 22:51:51 +01001107control {
1108 execute( TC_gsup_sai_err_invalid_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +01001109 execute( TC_gsup_sai() );
1110 execute( TC_gsup_ul_unknown_imsi() );
Harald Welte3f662762018-03-02 10:48:20 +01001111 execute( TC_gsup_sai_err_unknown_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +01001112 execute( TC_gsup_ul() );
1113 execute( TC_vty() );
Harald Welte09b3c502018-03-01 22:42:22 +01001114 execute( TC_vty_msisdn_isd() );
Harald Welte958f8b42018-03-01 23:40:17 +01001115 execute( TC_gsup_purge_cs() );
1116 execute( TC_gsup_purge_ps() );
1117 execute( TC_gsup_purge_unknown() );
Harald Welte4ea1f8a2018-06-12 09:26:10 +02001118
1119 execute( TC_mo_ussd_unknown() );
1120 execute( TC_mo_ussd_euse_disc() );
1121 execute( TC_mo_ussd_iuse_imsi() );
1122 execute( TC_mo_ussd_iuse_msisdn() );
1123 execute( TC_mo_ussd_euse() );
1124 execute( TC_mo_ussd_euse_continue() );
1125 execute( TC_mo_ussd_euse_defaultroute() );
Vadim Yanitskiyeffab7c2018-11-28 06:02:22 +07001126
1127 /* "Structured" Supplementary Services */
1128 execute( TC_mo_sss_reject() );
Harald Weltedf327232017-12-28 22:51:51 +01001129};
1130
1131};