blob: 2a11047d6d8d0602f9a100fdd8476f8a33c29dd4 [file] [log] [blame]
Harald Welte56db5fd2017-07-14 18:25:59 +02001module Test {
Harald Welteaf549412017-07-15 21:33:21 +02002 import from GSM_Types all;
Harald Welte56db5fd2017-07-14 18:25:59 +02003 import from GSM_SystemInformation all;
Harald Welteb622a3d2017-07-14 22:26:33 +02004 import from GSMTAP_Types all;
5 import from GSMTAP_PortType all;
6 import from IPL4_GSMTAP_CtrlFunct all;
Harald Welte9a907b32017-07-15 10:34:27 +02007 import from TELNETasp_PortType all;
Harald Welte56db5fd2017-07-14 18:25:59 +02008
9 const octetstring si1 := '5506198fb38000000000000000000000000000e504002b'O;
10 const octetstring si2 := '59061a00000000000000000000000000000000ffe50400'O;
11 const octetstring si3 := '49061b000062f22404d2490301275d40e50400392b2b2b'O;
12 const octetstring si4 := '31061c62f22404d25d40e504002b2b2b2b2b2b2b2b2b2b'O;
13
14 type component dummy_CT {
Harald Welteb622a3d2017-07-14 22:26:33 +020015 port GSMTAP_PT GSMTAP;
Harald Welte9a907b32017-07-15 10:34:27 +020016 port TELNETasp_PT BSCVTY;
Harald Welte56db5fd2017-07-14 18:25:59 +020017 };
18
19 testcase TC_si1() runs on dummy_CT {
Harald Welte56db5fd2017-07-14 18:25:59 +020020 log("SI: ", dec_SystemInformation(si1));
21 log("SI: ", dec_SystemInformation(si2));
22 log("SI: ", dec_SystemInformation(si3));
23 log("SI: ", dec_SystemInformation(si4));
24 }
25
Harald Welteb622a3d2017-07-14 22:26:33 +020026 template GsmtapHeader t_GsmtapHeader := {
27 version := GSMTAP_VERSION,
28 hdr_len := 4,
29 msg_type := ?,
30 timeslot := ?,
31 arfcn := ?,
32 signal_dbm := ?,
33 snr_db := ?,
34 frame_number := ?,
35 sub_type := ?,
36 antenna_nr := ?,
37 sub_slot := ?,
38 res := ?
39 }
40
41 template GsmtapHeader t_GsmtapHeaderUm(template GsmtapChannel ch) modifies t_GsmtapHeader := {
42 msg_type := GSMTAP_TYPE_UM,
43 sub_type := ch
44 }
45
Harald Welteb622a3d2017-07-14 22:26:33 +020046 template GsmtapMessage t_bcch := {
47 header := t_GsmtapHeaderUm(GSMTAP_CHANNEL_BCCH),
48 payload := ?
49 }
50
51 template GSMTAP_RecvFrom t_recvfrom(template GsmtapChannel ch) := {
52 connId := ?,
53 remName := ?,
54 remPort := ?,
55 locName := ?,
56 locPort := GSMTAP_PORT,
57 proto := {udp:={}},
58 userData := ?,
59 msg := { header := t_GsmtapHeaderUm(ch), payload := ?}
60 }
61
Harald Welteaf549412017-07-15 21:33:21 +020062 /* tuple of gsmtap header + decoded SI */
63 type record SystemInformationGsmtap {
64 GsmtapHeader gsmtap,
65 SystemInformation si
66 }
67
68 /* an arbitrary-length vector of decoded SI + gsmtap header */
69 type record of SystemInformationGsmtap SystemInformationVector;
70
71 /* an array of SI-vectors indexed by TC value */
72 type SystemInformationVector SystemInformationVectorPerTc[8];
73
74 type record of integer IntegerRecord;
75
76 function f_array_contains(IntegerRecord arr, integer key) return boolean {
77 for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
78 if (arr[i] == key) {
79 return true;
80 }
81 }
82 return false;
83 }
84
85
86 /* compute TC as per 45.002 6.3.1.3 */
87 function f_gsm_compute_tc(integer fn) return integer {
88 return (fn / 51) mod 8;
89 }
90
91 /* determine if a given SI vector contains given SI type at least once */
92 function f_si_vecslot_contains(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean {
93 for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
94 var integer fn_mod51 := arr[i].gsmtap.frame_number mod 51;
95 if (not bcch_ext and fn_mod51 == 2 or
96 bcch_ext and fn_mod51 == 6) {
97 if (arr[i].si.header.message_type == key) {
98 return true;
99 }
100 }
101 }
102 return false;
103 }
104
105 /* check if a given SI vector contains given SI type at least once on any TC */
106 function f_si_vec_contains(SystemInformationVectorPerTc arr, RrMessageType key) return boolean {
107 for (var integer tc:= 0; tc < sizeof(arr); tc := tc + 1) {
108 if (f_si_vecslot_contains(arr[tc], key) or
109 f_si_vecslot_contains(arr[tc], key, true)) {
110 return true;
111 }
112 }
113 return false;
114 }
115
116 /* ensure a given TC slot of the SI vector contains given SI type at least once at TC */
117 function f_ensure_si_vec_contains(SystemInformationVectorPerTc arr, integer tc, RrMessageType key,
118 boolean ext_bcch := false) {
119 if (not f_si_vecslot_contains(arr[tc], key, ext_bcch)) {
120 log("Fail: No ", key, " in TC=", tc, "!");
121 setverdict(fail);
122 }
123 }
124
125 /* SI configuration of cell, against which we validate actual SI messages */
126 type set SystemInformationConfig {
127 boolean bcch_extended,
128 boolean si1_present,
129 boolean si2bis_present,
130 boolean si2ter_present,
131 boolean si2quater_present,
132 boolean si7_present,
133 boolean si8_present,
134 boolean si9_present,
135 boolean si13_present,
136 boolean si13alt_present,
137 boolean si15_present,
138 boolean si16_present,
139 boolean si17_present,
140 boolean si2n_present,
141 boolean si21_present,
142 boolean si22_present
143 }
144
145 /* validate the SI scheduling according to TS 45.002 version 14.1.0 Release 14, Section 6.3.1.3 */
146 function f_validate_si_scheduling(SystemInformationConfig cfg, SystemInformationVectorPerTc si_per_tc) {
147 var integer i;
148 for (i := 0; i < sizeof(si_per_tc); i := i + 1) {
149 if (sizeof(si_per_tc[i]) == 0) {
150 setverdict(fail, "No SI messages for TC=0!");
151 }
152 }
153 if (cfg.si1_present) {
154 /* ii) System Information Type 1 needs to be sent if frequency hopping is in use or
155 * when the NCH is present in a cell. If the MS finds another message on BCCH Norm
156 * when TC = 0, it can assume that System Information Type 1 is not in use. */
157 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_1);
158 /* FIXME: make sure *ALL* contain SI1 */
159 }
160 f_ensure_si_vec_contains(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_2);
161 /* iii) A SI 2 message will be sent at least every time TC = 1 */
162 f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_3);
163 f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_3);
164 f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_4);
165 f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_4);
166
167 /* iii) System information type 2 bis or 2 ter messages are sent if needed, as determined by the
168 * system operator. If only one of them is needed, it is sent when TC = 5. If both are
169 * needed, 2bis is sent when TC = 5 and 2ter is sent at least once within any of 4
170 * consecutive occurrences of TC = 4. */
171 if (cfg.si2bis_present and not cfg.si2ter_present) {
172 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis);
173 } else if (cfg.si2ter_present and not cfg.si2bis_present) {
174 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2ter);
175 } else if (cfg.si2ter_present and cfg.si2bis_present) {
176 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis);
177 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2ter); //FIXME 1/4
178 }
179
180 if (cfg.si7_present or cfg.si8_present) {
181 /* vi) Use of System Information type 7 and 8 is not always necessary. It is necessary
182 * if System Information type 4 does not contain all information needed for cell
183 * selection and reselection. */
184 if (not cfg.bcch_extended) {
185 setverdict(fail, "Error: SI7/SI8 require BCCH Extd.");
186 }
187 if (cfg.si7_present) {
188 f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_7, true);
189 }
190 if (cfg.si8_present) {
191 f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_8, true);
192 }
193 }
194
195 if (cfg.si2quater_present) {
196 /* iii) System information type 2 quater is sent if needed, as determined by the system
197 * operator. If sent on BCCH Norm, it shall be sent when TC = 5 if neither of 2bis
198 * and 2ter are used, otherwise it shall be sent at least once within any of 4
199 * consecutive occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once
200 * within any of 4 consecutive occurrences of TC = 5. */
201 if (not (cfg.bcch_extended)) {
202 if (not (cfg.si2bis_present or cfg.si2ter_present)) {
203 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater);
204 } else {
205 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2quater); // FIXME 1/4
206 }
207 } else {
208 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater, true); // FIXME: 1/4
209 }
210 }
211 if (cfg.si9_present) {
212 /* vi) System Information type 9 is sent in those blocks with TC = 4 which are specified
213 * in system information type 3 as defined in 3GPP TS 44.018. */
214 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_9); // FIXME SI3
215 }
216 if (cfg.si13_present) {
217 /* vii) System Information type 13 is only related to the GPRS service. System Information
218 * Type 13 need only be sent if GPRS support is indicated in one or more of System
219 * Information Type 3 or 4 or 7 or 8 messages. These messages also indicate if the
220 * message is sent on the BCCH Norm or if the message is transmitted on the BCCH Ext.
221 * In the case that the message is sent on the BCCH Norm, it is sent at least once
222 * within any of 4 consecutive occurrences of TC=4. */
223 if (not cfg.bcch_extended) {
224 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13); // FIXME 1/4
225 } else {
226 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13, true);
227 }
228 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13alt)) {
229 setverdict(fail, "Cannot have SI13alt and SI13");
230 }
231 }
232 if (cfg.si16_present or cfg.si17_present) {
233 /* viii) System Information type 16 and 17 are only related to the SoLSA service. They
234 * should not be sent in a cell where network sharing is used (see rule xv). */
235 if (cfg.si22_present) {
236 setverdict(fail, "Error: Cannot have SI16/SI17 and SI22!");
237 }
238 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_22)) {
239 setverdict(fail, "Cannot have SI16/SI17 and SI22!");
240 }
241 if (not cfg.bcch_extended) {
242 setverdict(fail, "Error: SI16/SI17 requires BCCH Extd!");
243 }
244 if (cfg.si16_present) {
245 f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_16, true);
246 }
247 if (cfg.si17_present) {
248 f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_17, true);
249 }
250 }
251
252 /* ix) System Information type 18 and 20 are sent in order to transmit non-GSM
253 * broadcast information. The frequency with which they are sent is determined by the
254 * system operator. System Information type 9 identifies the scheduling of System
255 * Information type 18 and 20 messages. */
256
257 /* x) System Information Type 19 is sent if COMPACT neighbours exist. If System
258 * Information Type 19 is present, then its scheduling shall be indicated in System
259 * Information Type 9. */
260
261 if (cfg.si15_present) {
262 /* xi) System Information Type 15 is broadcast if dynamic ARFCN mapping is used in the
263 * PLMN. If sent on BCCH Norm, it is sent at least once within any of 4 consecutive
264 * occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once within any of
265 * 4 consecutive occurrences of TC = 1. */
266 if (not cfg.bcch_extended) {
267 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_15); // FIXME 1/4
268 } else {
269 f_ensure_si_vec_contains(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_15, true); // FIXME 1/4
270 }
271 }
272 if (cfg.si13alt_present) {
273 /* xii) System Information type 13 alt is only related to the GERAN Iu mode. System
274 * Information Type 13 alt need only be sent if GERAN Iu mode support is indicated in
275 * one or more of System Information Type 3 or 4 or 7 or 8 messages and SI 13 is not
276 * broadcast. These messages also indicate if the message is sent on the BCCH Norm or
277 * if the message is transmitted on the BCCH Ext. In the case that the message is sent
278 * on the BCCH Norm, it is sent at least once within any of 4 consecutive occurrences
279 * of TC = 4. */
280 if (cfg.si13_present) {
281 setverdict(fail, "Error: Cannot have SI13alt and SI13");
282 }
283 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13)) {
284 setverdict(fail, "Cannot have SI13alt and SI13");
285 }
286 if (not cfg.bcch_extended) {
287 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13alt); // FIXME 1/4
288 } else {
289 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13alt, true);
290 }
291 }
292 if (cfg.si2n_present) {
293 /* xiii) System Information Type 2n is optionally sent on BCCH Norm or BCCH Ext if needed,
294 * as determined by the system operator. In the case that the message is sent on the
295 * BCCH Norm, it is sent at least once within any of 4 consecutive occurrences of TC =
296 * 4. If the message is sent on BCCH Ext, it is sent at least once within any of 2
297 * consecutive occurrences of TC = 4. */
298 if (not cfg.bcch_extended) {
299 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n); // FIXME 1/4
300 } else {
301 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n, true); // FIXME 2/4
302 }
303 }
304 if (cfg.si21_present) {
305 /* xiv) System Information Type 21 is optionally sent on BCCH Norm or BCCH Ext, as
306 * determined by the system operator. If Extended Access Barring is in use in the cell
307 * then this message is sent at least once within any of 4 consecutive occurrences of
308 * TC = 4 regardless if it is sent on BCCH Norm or BCCH Ext. If BCCH Ext is used in a
309 * cell then this message shall only be sent on BCCH Ext. */
310 if (not cfg.bcch_extended) {
311 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21); // FIXME 1/4
312 } else {
313 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21, true); // FIXME 1/4
314 if (f_si_vecslot_contains(si_per_tc[4], SYSTEM_INFORMATION_TYPE_21)) {
315 setverdict(fail, "Cannot have SI21 on BCCH Norm if BCCH Extd enabled!");
316 }
317 }
318 }
319 if (cfg.si22_present) {
320 /* xv) System Information Type 22 is sent if network sharing is in use in the cell. It
321 * should not be sent in a cell where SoLSA is used (see rule viii). System
322 * Information Type 22 instances shall be sent on BCCH Ext within any occurrence of TC
323 * =2 and TC=6. */
324 if (cfg.si16_present or cfg.si17_present) {
325 setverdict(fail, "Error: Cannot have SI16/SI17 and SI22!");
326 }
327 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_16) or
328 f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_17)) {
329 setverdict(fail, "Cannot have SI16/SI17 and SI22!");
330 }
331 if (not cfg.bcch_extended) {
332 setverdict(fail, "Error: SI22 requires BCCH Extd!");
333 }
334 }
335 }
336
337
338 function f_gsmtap_sample_si(GSMTAP_PT pt, float duration := 5.0) return SystemInformationVectorPerTc {
339 timer T := duration;
340 var SystemInformationVectorPerTc si_per_tc;
341 var GSMTAP_RecvFrom rf;
342
343 /* initialize all per-TC vectors empty */
344 for (var integer i := 0; i < sizeof(si_per_tc); i := i + 1) {
345 si_per_tc[i] := {};
346 }
347
348 T.start;
349 alt {
350 [] pt.receive(t_recvfrom(GSMTAP_CHANNEL_BCCH)) -> value rf {
351 var SystemInformation si := dec_SystemInformation(rf.msg.payload);
352 var SystemInformationGsmtap sig := { rf.msg.header, si };
353 var integer tc := f_gsm_compute_tc(rf.msg.header.frame_number);
354 log("SI received at TC=", tc, ": ", si);
355 /* append to the per-TC bucket */
356 si_per_tc[tc] := si_per_tc[tc] & { sig };
357 repeat;
358 }
359 [] pt.receive { repeat; };
360 [] T.timeout { };
361 }
362 return si_per_tc;
363 }
364
Harald Welteb622a3d2017-07-14 22:26:33 +0200365 testcase TC_gsmtap() runs on dummy_CT {
Harald Welteaf549412017-07-15 21:33:21 +0200366 var SystemInformationVectorPerTc si_per_tc;
367 var SystemInformationConfig si_cfg := {
368 bcch_extended := false,
369 si1_present := true,
370 si2bis_present := false,
371 si2ter_present := false,
372 si2quater_present := false,
373 si7_present := false,
374 si8_present := false,
375 si9_present := false,
376 si13_present := false,
377 si13alt_present := false,
378 si15_present := false,
379 si16_present := false,
380 si17_present := false,
381 si2n_present := false,
382 si21_present := false,
383 si22_present := false
384 };
385
Harald Welteb622a3d2017-07-14 22:26:33 +0200386 map(self:GSMTAP, system:GSMTAP);
387 IPL4_GSMTAP_CtrlFunct.f_IPL4_listen(GSMTAP, "0.0.0.0", GSMTAP_PORT, {udp := {}});
388
Harald Welteaf549412017-07-15 21:33:21 +0200389 si_per_tc := f_gsmtap_sample_si(GSMTAP);
390 log("SI per TC: ", si_per_tc);
391 f_validate_si_scheduling(si_cfg, si_per_tc);
392 setverdict(pass);
Harald Welteb622a3d2017-07-14 22:26:33 +0200393 }
394
Harald Welte9a907b32017-07-15 10:34:27 +0200395
396
397 /* permitted prompts on VTY */
398 const charstring NORMAL_PROMPT := "OpenBSC> ";
399 const charstring ENABLE_PROMPT := "OpenBSC# ";
400 const charstring CONFIG_PROMPT := "OpenBSC(*)\#";
401
402 const ASP_TelnetDynamicConfig vty_prompt[3] := {
403 {
404 prompt := {
405 id := 1,
406 prompt := NORMAL_PROMPT,
407 has_wildcards := false
408 }
409 }, {
410 prompt := {
411 id := 2,
412 prompt := ENABLE_PROMPT,
413 has_wildcards := false
414 }
415 }, {
416 prompt := {
417 id := 3,
418 prompt := CONFIG_PROMPT,
419 has_wildcards := true
420 }
421 }
422 };
423
424 /* configure prompts in TELNETasp module */
425 function f_vty_set_prompts(TELNETasp_PT pt) {
426 /* set some configuration that isn't possible to express
427 * in the config file due to syntactic restrictions (Who invents config
428 * files that don't permit regular expressions? */
429 for (var integer i := 0; i < sizeof(vty_prompt); i:= i + 1) {
430 pt.send(vty_prompt[i])
431 }
432 }
433
434 /* wait for any of the permitted prompts; buffer + return all intermediate output */
435 function f_vty_wait_for_prompt(TELNETasp_PT pt) return charstring {
436 template charstring config_pattern := pattern CONFIG_PROMPT;
437 var charstring rx, buf := "";
438 timer T := 2.0;
439
440 T.start;
441 alt {
442 [] pt.receive(NORMAL_PROMPT) { };
443 [] pt.receive(ENABLE_PROMPT) { };
444 [] pt.receive(config_pattern) { };
445 [] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat };
Harald Welteaf549412017-07-15 21:33:21 +0200446 [] T.timeout { setverdict(fail, "Timeout"); return ""};
Harald Welte9a907b32017-07-15 10:34:27 +0200447 }
448 T.stop;
449 return buf;
450 }
451
452 /* send a VTY command and obtain response until prompt is received */
453 function f_vty_transceive(TELNETasp_PT pt, charstring tx) return charstring {
454 pt.send(tx);
455 return f_vty_wait_for_prompt(pt);
456 }
457
458 /* enter the'confiugration' mode of the VTY */
459 function f_vty_enter_config(TELNETasp_PT pt) {
460 f_vty_transceive(pt, "enable");
461 f_vty_transceive(pt, "configure terminal")
462 }
463
464 testcase TC_telnet() runs on dummy_CT {
465
466 map(self:BSCVTY, system:BSCVTY);
467 f_vty_set_prompts(BSCVTY)
468
469 f_vty_transceive(BSCVTY, "show network")
470 f_vty_enter_config(BSCVTY)
471 f_vty_transceive(BSCVTY, "network")
472 f_vty_transceive(BSCVTY, "bts 0")
473 }
474
Harald Welte56db5fd2017-07-14 18:25:59 +0200475 control {
476 execute(TC_si1());
Harald Welteb622a3d2017-07-14 22:26:33 +0200477 execute(TC_gsmtap());
Harald Welte9a907b32017-07-15 10:34:27 +0200478 execute(TC_telnet());
Harald Welte56db5fd2017-07-14 18:25:59 +0200479 }
480}