blob: 7efc2b71d934ad686229f31ebe0102ccbbfbf144 [file] [log] [blame]
Harald Welte78cae922018-03-01 10:12:56 +01001module HLR_Tests {
Harald Weltedf327232017-12-28 22:51:51 +01002
3import from GSUP_Types all;
4import from IPA_Emulation all;
5
Harald Weltec2c52552018-03-01 21:20:39 +01006import from General_Types all;
7import from Osmocom_Types all;
Harald Welte39b82d32018-03-01 10:21:29 +01008import from Osmocom_CTRL_Adapter all;
9
10import from Osmocom_VTY_Functions all;
11import from TELNETasp_PortType all;
12
13type component test_CT extends CTRL_Adapter_CT {
Harald Weltedf327232017-12-28 22:51:51 +010014 var IPA_Emulation_CT vc_IPA;
15 var IPA_CCM_Parameters ccm_pars;
16 port IPA_GSUP_PT GSUP;
Harald Welte39b82d32018-03-01 10:21:29 +010017
18 port TELNETasp_PT VTY;
Harald Weltec2c52552018-03-01 21:20:39 +010019
20 timer g_Tguard := 10.0;
Harald Weltedf327232017-12-28 22:51:51 +010021};
22
23modulepar {
24 charstring mp_hlr_ip := "127.0.0.1";
25 integer mp_hlr_gsup_port := 4222;
26 integer mp_hlr_ctrl_port := 4259;
27};
28
Harald Weltec2c52552018-03-01 21:20:39 +010029type record HlrSubscrAud2G {
30 charstring algo,
31 OCT16 ki
32}
33
34type record HlrSubscrAud3G {
35 charstring algo,
36 OCT16 k,
37 OCT16 op,
38 boolean op_is_opc
39}
40
41type record HlrSubscriber {
42 hexstring imsi,
43 hexstring msisdn,
44 HlrSubscrAud2G aud2g optional,
45 HlrSubscrAud3G aud3g optional
46}
47
48type record of HlrSubscriber HlrSubscriberList;
49
50template (value) HlrSubscriber t_SubNoAuth(hexstring imsi, hexstring msisdn) := {
51 imsi := imsi,
52 msisdn := msisdn,
53 aud2g := omit,
54 aud3g := omit
55}
56
57const OCT16 c_KI_DEFAULT := '000102030405060708090a0b0c0d0e0f'O;
58const OCT16 c_K_DEFAULT := '101112131415161718191a1b1c1d1e1f'O;
59const OCT16 c_OP_DEFAULT := '202122232425262728292a2b2c2d2e2f'O;
60//const OCT16 c_OPC_DEFAULT := '303132333435363738393a3b3c3d3f'O;
61
62template (value) HlrSubscriber t_Sub2G(hexstring imsi, hexstring msisdn, charstring algo) := {
63 imsi := imsi,
64 msisdn := msisdn,
65 aud2g := {
66 algo := algo,
67 ki := c_KI_DEFAULT
68 },
69 aud3g := omit
70}
71
72template (value) HlrSubscriber t_Sub3G(hexstring imsi, hexstring msisdn, charstring algo, boolean is_opc) := {
73 imsi := imsi,
74 msisdn := msisdn,
75 aud2g := omit,
76 aud3g := {
77 algo := algo,
78 k := c_K_DEFAULT,
79 op := c_OP_DEFAULT,
80 op_is_opc := is_opc
81 }
82}
83
84template (value) HlrSubscriber t_Sub2G3G(hexstring imsi, hexstring msisdn, charstring algo2g, charstring algo3g, boolean is_opc) := {
85 imsi := imsi,
86 msisdn := msisdn,
87 aud2g := {
88 algo := algo2g,
89 ki := c_KI_DEFAULT
90 },
91 aud3g := {
92 algo := algo3g,
93 k := c_K_DEFAULT,
94 op := c_OP_DEFAULT,
95 op_is_opc := is_opc
96 }
97}
98
99/* generate a variety of subscribers with different parameters */
100function f_gen_subs() runs on test_CT return HlrSubscriberList {
101 var HlrSubscriber sub;
102 var HlrSubscriberList sl := {};
103
104 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
105 sl := sl & { sub };
106
107 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v2"));
108 sl := sl & { sub };
109
110 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v3"));
111 sl := sl & { sub };
112
113 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "milenage", false));
114 sl := sl & { sub };
115
116 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "milenage", true));
117 sl := sl & { sub };
118
119 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
120 "comp128v1", "milenage", false));
121 sl := sl & { sub };
122
123 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
124 "comp128v2", "milenage", false));
125 sl := sl & { sub };
126
127 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
128 "comp128v3", "milenage", false));
129 sl := sl & { sub };
130
131 return sl;
132}
133
Harald Welte39b82d32018-03-01 10:21:29 +0100134function f_init_vty() runs on test_CT {
135 map(self:VTY, system:VTY);
136 f_vty_set_prompts(VTY);
137 f_vty_transceive(VTY, "enable");
138}
139
Harald Weltec2c52552018-03-01 21:20:39 +0100140private altstep as_Tguard() runs on test_CT {
141 [] g_Tguard.timeout {
142 setverdict(fail, "g_Tguard timeout");
143 self.stop;
144 }
145}
146
Harald Weltedf327232017-12-28 22:51:51 +0100147function f_init() runs on test_CT {
Harald Weltec2c52552018-03-01 21:20:39 +0100148
149 /* activate default guard timer to ensure all tests eventually terminate */
150 g_Tguard.start;
151 activate(as_Tguard());
152
Harald Weltedf327232017-12-28 22:51:51 +0100153 ccm_pars := c_IPA_default_ccm_pars;
154 ccm_pars.name := "Osmocom TTCN-3 GSUP Simulator";
155
156 vc_IPA := IPA_Emulation_CT.create("IPA");
157 map(vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
158 connect(vc_IPA:IPA_GSUP_PORT, self:GSUP);
159 vc_IPA.start(IPA_Emulation.main_client(mp_hlr_ip, mp_hlr_gsup_port, "", -1, ccm_pars));
Harald Welte39b82d32018-03-01 10:21:29 +0100160
Harald Welte79420cc2018-03-01 16:49:29 +0100161 timer T:= 10.0;
162 alt {
163 [] GSUP.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { }
164 [] T.timeout {
165 setverdict(fail, "Timeout waiting for GSUP IPA Link to come up");
166 self.stop;
167 }
168 }
169
Harald Welte39b82d32018-03-01 10:21:29 +0100170 f_init_vty();
171
172 f_ipa_ctrl_start(mp_hlr_ip, mp_hlr_ctrl_port);
Harald Weltedf327232017-12-28 22:51:51 +0100173}
174
Harald Weltec2c52552018-03-01 21:20:39 +0100175function f_vty_transceive_match(TELNETasp_PT pt, charstring cmd, template charstring exp_ret) {
176 var charstring ret := f_vty_transceive_ret(pt, cmd);
177 if (not match(ret, exp_ret)) {
178 setverdict(fail, "Non-matching VTY response: ", ret);
179 self.stop;
Harald Weltedf327232017-12-28 22:51:51 +0100180 }
181}
182
Harald Welte70296062018-03-01 22:42:03 +0100183private template (value) charstring t_subscr_prefix(hexstring imsi) :=
184 "subscriber imsi " & hex2str(imsi) & " ";
185
Harald Weltec2c52552018-03-01 21:20:39 +0100186/* create a given subscriber using the VTY */
187function f_vty_subscr_create(HlrSubscriber sub) runs on test_CT {
Harald Welte70296062018-03-01 22:42:03 +0100188 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100189 f_vty_transceive_match(VTY, prefix & "create", pattern "% Created subscriber *");
190 f_vty_transceive_match(VTY, prefix & "update msisdn " & hex2str(sub.msisdn),
191 pattern "% Updated subscriber *");
192 if (ispresent(sub.aud2g)) {
193 f_vty_transceive_match(VTY, prefix & "update aud2g " & sub.aud2g.algo &
194 " ki " & oct2str(sub.aud2g.ki),
195 pattern "");
196 } else {
197 f_vty_transceive_match(VTY, prefix & "update aud2g none", pattern "");
198 }
199
200 if (ispresent(sub.aud3g)) {
201 var charstring op_mode := "op";
202 if (sub.aud3g.op_is_opc) {
203 op_mode := "opc";
204 }
205 f_vty_transceive_match(VTY, prefix & "update aud3g " & sub.aud3g.algo &
206 " k " & oct2str(sub.aud3g.k) & " " & op_mode & " " &
207 oct2str(sub.aud3g.op), pattern "");
208 } else {
209 f_vty_transceive_match(VTY, prefix & "update aud3g none", pattern "");
210 }
211}
212
Harald Welte09b3c502018-03-01 22:42:22 +0100213function f_vty_subscr_update_msisdn(HlrSubscriber sub, hexstring new_msisdn) runs on test_CT {
214 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
215 f_vty_transceive_match(VTY, prefix & "update msisdn " & hex2str(new_msisdn),
216 pattern "% Updated subscriber *");
217}
218
Harald Weltec2c52552018-03-01 21:20:39 +0100219/* perform 'delete' on subscriber */
220function f_vty_subscr_delete(HlrSubscriber sub) runs on test_CT {
Harald Welte70296062018-03-01 22:42:03 +0100221 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100222 f_vty_transceive_match(VTY, prefix & "delete",
223 pattern "% Deleted subscriber for IMSI *");
224}
225
226/* perform 'show' on subscriber; match result with pattern 'exp' */
227function f_vty_subscr_show(HlrSubscriber sub, template charstring exp) runs on test_CT {
Harald Welte70296062018-03-01 22:42:03 +0100228 var charstring prefix := valueof(t_subscr_prefix(sub.imsi));
Harald Weltec2c52552018-03-01 21:20:39 +0100229 f_vty_transceive_match(VTY, prefix & "show", exp);
230}
231
232
233/* perform SendAuthInfo for given imsi, return the GSUP response/error */
234function f_perform_SAI(hexstring imsi, template (omit) integer exp_err_cause := omit)
235runs on test_CT return GSUP_PDU {
236 var GSUP_PDU ret;
237 timer T := 3.0;
238 var boolean exp_fail := false;
239 if (not istemplatekind(exp_err_cause, "omit")) {
240 exp_fail := true;
241 }
242
243 GSUP.send(valueof(ts_GSUP_SAI_REQ(imsi)));
244 T.start;
245 alt {
246 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, exp_err_cause)) -> value ret {
247 setverdict(pass);
248 }
249 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
250 setverdict(fail, "Unexpected SAI ERROR Cause");
251 }
252 [exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
253 setverdict(fail, "Unexpected SAI.res for unknown IMSI");
254 }
255 [not exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
256 setverdict(fail, "Unexpected SAI ERROR");
257 }
258 [not exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
259 setverdict(pass);
260 }
261 [] GSUP.receive { repeat; }
262 [] T.timeout {
263 setverdict(fail, "Timeout waiting for SAI response");
264 self.stop;
265 }
266 }
267 return ret;
268}
269
270function f_perform_UL(hexstring imsi, template hexstring msisdn,
271 template (omit) integer exp_err_cause := omit)
272runs on test_CT return GSUP_PDU {
273 var GSUP_PDU ret;
274 timer T := 3.0;
275 var boolean exp_fail := false;
276 var boolean isd_done := false;
277 if (not istemplatekind(exp_err_cause, "omit")) {
278 exp_fail := true;
279 }
280
281 GSUP.send(valueof(ts_GSUP_UL_REQ(imsi)));
282 T.start;
283 alt {
284 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause)) -> value ret {
285 setverdict(pass);
286 }
287 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
288 setverdict(fail, "Unexpected UL ERROR Cause");
289 }
290 [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
291 setverdict(fail, "Unexpected UL.res for unknown IMSI");
292 }
293 [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi)) -> value ret {
294 setverdict(fail, "Unexpected ISD.req in error case");
295 }
296 [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
297 setverdict(fail, "Unexpected UL ERROR");
298 }
299 [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn)) -> value ret {
300 GSUP.send(ts_GSUP_ISD_RES(imsi));
301 isd_done := true;
Harald Welte8f0c9332018-03-01 23:38:40 +0100302 repeat;
Harald Weltec2c52552018-03-01 21:20:39 +0100303 }
304 [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
305 setverdict(pass);
306 }
307 [] GSUP.receive { repeat; }
308 [] T.timeout {
309 setverdict(fail, "Timeout waiting for UL response");
310 self.stop;
311 }
312 }
313 return ret;
314}
315
316testcase TC_gsup_sai_err_invalid_imsi() runs on test_CT {
317 var hexstring imsi := '01234'H;
318 var GSUP_PDU res;
319
320 f_init();
321
322 res := f_perform_SAI(imsi, 17);
323 setverdict(pass);
324}
325
326/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
327testcase TC_gsup_sai() runs on test_CT {
328 var HlrSubscriberList sl;
329 var GSUP_PDU res;
330
331 f_init();
332
333 sl := f_gen_subs();
334 for (var integer i := 0; i < sizeof(sl); i := i+1) {
335 var HlrSubscriber sub := sl[i];
336 log("Testing SAI for ", sub);
337 f_vty_subscr_create(sub);
338 res := f_perform_SAI(sub.imsi);
339 /* TODO: match if tuple[s] matches expectation */
340 f_vty_subscr_delete(sub);
341 }
342
343 setverdict(pass);
344}
345
346/* test UL for unknown IMSI */
347testcase TC_gsup_ul_unknown_imsi() runs on test_CT {
348 var hexstring imsi := f_rnd_imsi('26242'H);
349 var GSUP_PDU res;
350
351 f_init();
352
353 res := f_perform_UL(imsi, ?, 2);
354 setverdict(pass);
355}
356
357/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
358testcase TC_gsup_ul() runs on test_CT {
359 var HlrSubscriberList sl;
360 var GSUP_PDU res;
361
362 f_init();
363
364 sl := f_gen_subs();
365 for (var integer i := 0; i < sizeof(sl); i := i+1) {
366 var HlrSubscriber sub := sl[i];
367 log("Testing UL for ", sub);
368 f_vty_subscr_create(sub);
369 res := f_perform_UL(sub.imsi, sub.msisdn);
370 f_vty_subscr_delete(sub);
371 }
372
373 setverdict(pass);
374}
375
376/* Test only the VTY commands */
377testcase TC_vty() runs on test_CT {
378 var HlrSubscriber sub;
379
380 f_init();
381
382 /* we're not using f_gen_subs() here as the expect pattern for the 'show' are different
383 * from case to case */
384 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
385 f_vty_subscr_create(sub);
386 f_vty_subscr_show(sub, pattern "*IMSI: *2G auth: COMP128v1*");
387 f_vty_subscr_delete(sub);
388
389 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
390 "milenage", false));
391 f_vty_subscr_create(sub);
392 f_vty_subscr_show(sub, pattern "*IMSI: *3G auth: MILENAGE*");
393 f_vty_subscr_delete(sub);
394
395 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
396 "comp128v1", "milenage", false));
397 f_vty_subscr_create(sub);
398 f_vty_subscr_show(sub, pattern "*IMSI: *2G auth: COMP128v1*3G auth: MILENAGE*");
399 f_vty_subscr_delete(sub);
400
401 setverdict(pass);
402}
403
Harald Welte09b3c502018-03-01 22:42:22 +0100404/* VTY changes to MSISDN should result in ISD to current VLR */
405testcase TC_vty_msisdn_isd() runs on test_CT {
406 var HlrSubscriber sub;
407 var hexstring new_msisdn;
408 var GSUP_PDU res;
409 timer T := 5.0;
410
411 f_init();
412
413 /* Create Subscriber */
414 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
415 f_vty_subscr_create(sub);
416
417 /* Perform UpdateLocation (VLR now known to HLR) */
418 res := f_perform_UL(sub.imsi, sub.msisdn);
419
420 /* Then change IMSI via VTY */
421 new_msisdn := '49161'H & f_rnd_hexstring(7, 9);
422 f_vty_subscr_update_msisdn(sub, new_msisdn);
423 /* And expect InsertSubscriberData as result */
424 T.start;
425 alt {
426 [] GSUP.receive(tr_GSUP_ISD_REQ(sub.imsi, new_msisdn)) {
427 GSUP.send(ts_GSUP_ISD_RES(sub.imsi));
428 sub.msisdn := new_msisdn;
429 setverdict(pass);
430 }
431 [] GSUP.receive { repeat; }
432 [] T.timeout {
433 setverdict(fail, "Timeout waiting for ISD.req");
434 }
435 }
436}
437
Harald Weltec2c52552018-03-01 21:20:39 +0100438/* TODO:
439 * UL with ISD error
440 * UL with ISD timeout
441 * PURGE MS
442 * LOCATION CANCEL
443 * AUTH FAIL REP
444 * DELETE DATA after hlr_subscr_nam() change
445 * correctness
446 ** wrong message type
447 ** wrong length of PDU
448 ** too short message
449 ** missing IMSI IE
450
451 */
452
Harald Weltedf327232017-12-28 22:51:51 +0100453control {
454 execute( TC_gsup_sai_err_invalid_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +0100455 execute( TC_gsup_sai() );
456 execute( TC_gsup_ul_unknown_imsi() );
457 execute( TC_gsup_ul() );
458 execute( TC_vty() );
Harald Welte09b3c502018-03-01 22:42:22 +0100459 execute( TC_vty_msisdn_isd() );
Harald Weltedf327232017-12-28 22:51:51 +0100460};
461
462};