blob: 48233ed05290b8a50794b96436d27da3fb5573e9 [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 Weltec2c52552018-03-01 21:20:39 +0100183/* create a given subscriber using the VTY */
184function f_vty_subscr_create(HlrSubscriber sub) runs on test_CT {
185 var charstring prefix := "subscriber imsi " & hex2str(sub.imsi) & " ";
186 f_vty_transceive_match(VTY, prefix & "create", pattern "% Created subscriber *");
187 f_vty_transceive_match(VTY, prefix & "update msisdn " & hex2str(sub.msisdn),
188 pattern "% Updated subscriber *");
189 if (ispresent(sub.aud2g)) {
190 f_vty_transceive_match(VTY, prefix & "update aud2g " & sub.aud2g.algo &
191 " ki " & oct2str(sub.aud2g.ki),
192 pattern "");
193 } else {
194 f_vty_transceive_match(VTY, prefix & "update aud2g none", pattern "");
195 }
196
197 if (ispresent(sub.aud3g)) {
198 var charstring op_mode := "op";
199 if (sub.aud3g.op_is_opc) {
200 op_mode := "opc";
201 }
202 f_vty_transceive_match(VTY, prefix & "update aud3g " & sub.aud3g.algo &
203 " k " & oct2str(sub.aud3g.k) & " " & op_mode & " " &
204 oct2str(sub.aud3g.op), pattern "");
205 } else {
206 f_vty_transceive_match(VTY, prefix & "update aud3g none", pattern "");
207 }
208}
209
210/* perform 'delete' on subscriber */
211function f_vty_subscr_delete(HlrSubscriber sub) runs on test_CT {
212 var charstring prefix := "subscriber imsi " & hex2str(sub.imsi) & " ";
213 f_vty_transceive_match(VTY, prefix & "delete",
214 pattern "% Deleted subscriber for IMSI *");
215}
216
217/* perform 'show' on subscriber; match result with pattern 'exp' */
218function f_vty_subscr_show(HlrSubscriber sub, template charstring exp) runs on test_CT {
219 var charstring prefix := "subscriber imsi " & hex2str(sub.imsi) & " ";
220 f_vty_transceive_match(VTY, prefix & "show", exp);
221}
222
223
224/* perform SendAuthInfo for given imsi, return the GSUP response/error */
225function f_perform_SAI(hexstring imsi, template (omit) integer exp_err_cause := omit)
226runs on test_CT return GSUP_PDU {
227 var GSUP_PDU ret;
228 timer T := 3.0;
229 var boolean exp_fail := false;
230 if (not istemplatekind(exp_err_cause, "omit")) {
231 exp_fail := true;
232 }
233
234 GSUP.send(valueof(ts_GSUP_SAI_REQ(imsi)));
235 T.start;
236 alt {
237 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, exp_err_cause)) -> value ret {
238 setverdict(pass);
239 }
240 [exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
241 setverdict(fail, "Unexpected SAI ERROR Cause");
242 }
243 [exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
244 setverdict(fail, "Unexpected SAI.res for unknown IMSI");
245 }
246 [not exp_fail] GSUP.receive(tr_GSUP_SAI_ERR(imsi, ?)) -> value ret {
247 setverdict(fail, "Unexpected SAI ERROR");
248 }
249 [not exp_fail] GSUP.receive(tr_GSUP_SAI_RES(imsi)) -> value ret {
250 setverdict(pass);
251 }
252 [] GSUP.receive { repeat; }
253 [] T.timeout {
254 setverdict(fail, "Timeout waiting for SAI response");
255 self.stop;
256 }
257 }
258 return ret;
259}
260
261function f_perform_UL(hexstring imsi, template hexstring msisdn,
262 template (omit) integer exp_err_cause := omit)
263runs on test_CT return GSUP_PDU {
264 var GSUP_PDU ret;
265 timer T := 3.0;
266 var boolean exp_fail := false;
267 var boolean isd_done := false;
268 if (not istemplatekind(exp_err_cause, "omit")) {
269 exp_fail := true;
270 }
271
272 GSUP.send(valueof(ts_GSUP_UL_REQ(imsi)));
273 T.start;
274 alt {
275 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, exp_err_cause)) -> value ret {
276 setverdict(pass);
277 }
278 [exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
279 setverdict(fail, "Unexpected UL ERROR Cause");
280 }
281 [exp_fail] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
282 setverdict(fail, "Unexpected UL.res for unknown IMSI");
283 }
284 [exp_fail] GSUP.receive(tr_GSUP_ISD_REQ(imsi)) -> value ret {
285 setverdict(fail, "Unexpected ISD.req in error case");
286 }
287 [not exp_fail] GSUP.receive(tr_GSUP_UL_ERR(imsi, ?)) -> value ret {
288 setverdict(fail, "Unexpected UL ERROR");
289 }
290 [not exp_fail and not isd_done] GSUP.receive(tr_GSUP_ISD_REQ(imsi, msisdn)) -> value ret {
291 GSUP.send(ts_GSUP_ISD_RES(imsi));
292 isd_done := true;
293 }
294 [not exp_fail and isd_done] GSUP.receive(tr_GSUP_UL_RES(imsi)) -> value ret {
295 setverdict(pass);
296 }
297 [] GSUP.receive { repeat; }
298 [] T.timeout {
299 setverdict(fail, "Timeout waiting for UL response");
300 self.stop;
301 }
302 }
303 return ret;
304}
305
306testcase TC_gsup_sai_err_invalid_imsi() runs on test_CT {
307 var hexstring imsi := '01234'H;
308 var GSUP_PDU res;
309
310 f_init();
311
312 res := f_perform_SAI(imsi, 17);
313 setverdict(pass);
314}
315
316/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
317testcase TC_gsup_sai() runs on test_CT {
318 var HlrSubscriberList sl;
319 var GSUP_PDU res;
320
321 f_init();
322
323 sl := f_gen_subs();
324 for (var integer i := 0; i < sizeof(sl); i := i+1) {
325 var HlrSubscriber sub := sl[i];
326 log("Testing SAI for ", sub);
327 f_vty_subscr_create(sub);
328 res := f_perform_SAI(sub.imsi);
329 /* TODO: match if tuple[s] matches expectation */
330 f_vty_subscr_delete(sub);
331 }
332
333 setverdict(pass);
334}
335
336/* test UL for unknown IMSI */
337testcase TC_gsup_ul_unknown_imsi() runs on test_CT {
338 var hexstring imsi := f_rnd_imsi('26242'H);
339 var GSUP_PDU res;
340
341 f_init();
342
343 res := f_perform_UL(imsi, ?, 2);
344 setverdict(pass);
345}
346
347/* test SAI for a number of different subscriber cases (algo, 2g/3g, ...) */
348testcase TC_gsup_ul() runs on test_CT {
349 var HlrSubscriberList sl;
350 var GSUP_PDU res;
351
352 f_init();
353
354 sl := f_gen_subs();
355 for (var integer i := 0; i < sizeof(sl); i := i+1) {
356 var HlrSubscriber sub := sl[i];
357 log("Testing UL for ", sub);
358 f_vty_subscr_create(sub);
359 res := f_perform_UL(sub.imsi, sub.msisdn);
360 f_vty_subscr_delete(sub);
361 }
362
363 setverdict(pass);
364}
365
366/* Test only the VTY commands */
367testcase TC_vty() runs on test_CT {
368 var HlrSubscriber sub;
369
370 f_init();
371
372 /* we're not using f_gen_subs() here as the expect pattern for the 'show' are different
373 * from case to case */
374 sub := valueof(t_Sub2G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9), "comp128v1"));
375 f_vty_subscr_create(sub);
376 f_vty_subscr_show(sub, pattern "*IMSI: *2G auth: COMP128v1*");
377 f_vty_subscr_delete(sub);
378
379 sub := valueof(t_Sub3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
380 "milenage", false));
381 f_vty_subscr_create(sub);
382 f_vty_subscr_show(sub, pattern "*IMSI: *3G auth: MILENAGE*");
383 f_vty_subscr_delete(sub);
384
385 sub := valueof(t_Sub2G3G(f_rnd_imsi('26242'H), '49161'H & f_rnd_hexstring(7, 9),
386 "comp128v1", "milenage", false));
387 f_vty_subscr_create(sub);
388 f_vty_subscr_show(sub, pattern "*IMSI: *2G auth: COMP128v1*3G auth: MILENAGE*");
389 f_vty_subscr_delete(sub);
390
391 setverdict(pass);
392}
393
394/* TODO:
395 * UL with ISD error
396 * UL with ISD timeout
397 * PURGE MS
398 * LOCATION CANCEL
399 * AUTH FAIL REP
400 * DELETE DATA after hlr_subscr_nam() change
401 * correctness
402 ** wrong message type
403 ** wrong length of PDU
404 ** too short message
405 ** missing IMSI IE
406
407 */
408
Harald Weltedf327232017-12-28 22:51:51 +0100409control {
410 execute( TC_gsup_sai_err_invalid_imsi() );
Harald Weltec2c52552018-03-01 21:20:39 +0100411 execute( TC_gsup_sai() );
412 execute( TC_gsup_ul_unknown_imsi() );
413 execute( TC_gsup_ul() );
414 execute( TC_vty() );
Harald Weltedf327232017-12-28 22:51:51 +0100415};
416
417};