blob: 6835f02f8fb0828595e69dfe3a08161beee0bd06 [file] [log] [blame]
Harald Welte505cf9b2018-09-15 17:47:23 +03001module BTS_Tests_SMSCB {
2
3/* Integration Tests for OsmoBTS
4 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
5 * All rights reserved.
6 *
7 * Released under the terms of GNU General Public License, Version 2 or
8 * (at your option) any later version.
9 *
10 * This test suite tests the SMSCB (Cell Broadcast) related functionality of
11 * OsmoBTS by attaching to the A-bis RSL and Um interface and emulating both
12 * BSC and MS.
13 */
14
15import from Misc_Helpers all;
16import from General_Types all;
17import from Osmocom_Types all;
18import from GSM_Types all;
19import from L1CTL_PortType all;
20import from L1CTL_Types all;
21import from LAPDm_Types all;
22
23import from RSL_Types all;
24
25import from Osmocom_VTY_Functions all;
26
27import from BTS_Tests all;
28
29/***********************************************************************
30 * Cell Broadcast related tests
31 ***********************************************************************/
32
33type record CbchTestPars {
34 boolean use_sdcch4,
35 CbchTestMsgs msgs
36};
37
38type record CbchTestMsg {
39 /* config / input data */
40 RSL_CbCommand rsl_cb_cmd,
41 uint2_t last_block, /* 0..3 */
42 octetstring payload,
43 /* computed / result data */
44 CbchBlocks blocks optional
45};
46type record of CbchTestMsg CbchTestMsgs;
47
48/* a single 22byte block within a CbchTestMsg */
49type record CbchBlock {
50 uint4_t seq_nr, /* as per TS 04.12 */
51 boolean is_last,
52 OCT22 payload,
53 boolean seen_once
54};
55type record of CbchBlock CbchBlocks;
56
57/* compute the expected blocks for given test parameters */
58private function f_cbch_compute_exp_blocks(inout CbchTestPars pars) {
59 var integer i;
60
61 for (i := 0; i < lengthof(pars.msgs); i := i+1) {
62 pars.msgs[i].blocks := f_comp_blocks(pars.msgs[i]);
63 }
64}
65private function f_comp_blocks(in CbchTestMsg msg) return CbchBlocks {
66 var CbchBlocks blocks := {};
67 var integer i;
68
69 for (i := 0; i <= msg.last_block; i := i+1) {
70 var CbchBlock block := {
71 seq_nr := i,
72 is_last := false,
73 payload := substr(msg.payload, 22*i, 22),
74 seen_once := false
75 };
76 if (msg.rsl_cb_cmd == RSL_CB_CMD_SCHEDULE and i == 0) {
77 block.seq_nr := 8;
78 }
79 if (i == msg.last_block) {
80 block.is_last := true;
81 }
82 blocks := blocks & {block};
83 }
84
85 return blocks;
86};
87
88/* TS 48.058 Section 9.3.41 */
89private function f_cbch_block_nr2rsl(uint2_t nr) return uint2_t {
90 select (nr) {
91 case (0) { return 1; }
92 case (1) { return 2; }
93 case (2) { return 3; }
94 case (3) { return 0; }
95 }
96 setverdict(fail, "Invalid block number");
97 mtc.stop;
98}
99
100/* Verify the CBCH TB scheduling rules of TS 05.02 Section 6.5.4 */
101private function f_cbch_fn_verify(uint32_t fn, CBCH_Block cb)
102{
103 var integer tb := (fn/51) mod 8; /* TS 05.02 Section 6.5.4 */
104 if (cb.block_type.seq_nr == 15 /* null */) {
105 /* always permitted */
106 return;
107 } else if (cb.block_type.seq_nr == 8 /* schedule */) {
108 if (tb != 0) {
109 setverdict(fail, "Schedule block at TB=", tb);
110 }
111 } else if (cb.block_type.seq_nr < 4) {
112 if (cb.block_type.seq_nr != tb and cb.block_type.seq_nr+4 != tb) {
113 setverdict(fail, "Normal block at wrong TB=", tb, ": ", cb);
114 }
115 }
116}
117
118/* shared function doing the heavy lifting for most CBCH tests */
119private function f_TC_smscb(CbchTestPars pars) runs on test_CT {
120 var L1ctlDlMessage dl;
121 var boolean cmd_seen_once := false;
122 var integer i, j;
123 timer T := 5.0;
124
125 f_cbch_compute_exp_blocks(pars);
126
127 f_init_vty_bsc();
128 /* ensure that a CBCH is present in channel combination */
129 if (pars.use_sdcch4) {
130 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 0"},
131 "phys_chan_config CCCH+SDCCH4+CBCH");
132 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 6"},
133 "phys_chan_config SDCCH8");
134 } else {
135 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 0"},
136 "phys_chan_config CCCH+SDCCH4");
137 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 6"},
138 "phys_chan_config SDCCH8+CBCH");
139 }
140 f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
141 f_sleep(2.0);
142 f_init(testcasename());
143
144 f_init_l1ctl();
145 f_l1_tune(L1CTL);
146 /* FIXME: switch to dedicated mode for SDCCH/8 */
147
148 /* send SMSCB[s] via RSL */
149 for (i := 0; i < lengthof(pars.msgs); i := i+1) {
150 var CbchTestMsg msg := pars.msgs[i];
151 var uint2_t rsl_last_block := f_cbch_block_nr2rsl(msg.last_block);
152 var RSL_IE_CbCommandType cmd_type :=
153 valueof(ts_RSL_IE_CbCmdType(msg.rsl_cb_cmd, rsl_last_block));
154 RSL_CCHAN.send(ts_RSL_UD(ts_RSL_SMSCB_CMD(cmd_type, msg.payload)));
155 }
156 T.start;
157 /* Expect this to show up exactly once on the basic CBCH (four blocks) */
158 alt {
159 /* FIXME: Channel Nr for SDCCH/8 */
160 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_CBCH(0))) -> value dl {
161 log("CBCH: ", dl);
162 var CBCH_Block cb := dec_CBCH_Block(dl.payload.data_ind.payload);
163 /* detect the proper CBCH messages; check frame number */
164 f_cbch_fn_verify(dl.dl_info.frame_nr, cb);
165 if (not match(cb, tr_CBCH_Block)) {
166 setverdict(fail, "Illegal CBCH Block received: ", cb);
167 } else {
168 var boolean matched := false;
169 /* ignore NULL messages */
170 if (match(cb, tr_CBCH_Block(15, ?, ?))) { repeat; }
171 for (i := 0; i < lengthof(pars.msgs); i := i+1) {
172 for (j := 0; j < lengthof(pars.msgs[i].blocks); j := j+1) {
173 var CbchBlock b := pars.msgs[i].blocks[j];
174 if (match(cb, tr_CBCH_Block(b.seq_nr, b.is_last, b.payload))) {
175 if (not pars.msgs[i].blocks[j].seen_once) {
176 pars.msgs[i].blocks[j].seen_once := true;
177 setverdict(pass);
178 } else {
179 setverdict(fail, "Received SMSCB twice! ", cb);
180 }
181 matched := true;
182 continue;
183 }
184 }
185 }
186 if (not matched) {
187 setverdict(fail, "Received unexpected CBCH block: ", cb);
188 }
189 repeat;
190 }
191 }
192 [] L1CTL.receive { repeat; }
193 [] T.timeout {
194 for (i := 0; i < lengthof(pars.msgs); i := i+1) {
195 for (j := 0; j < lengthof(pars.msgs[i].blocks); j := j+1) {
196 var CbchBlock b := pars.msgs[i].blocks[j];
197 if (not b.seen_once) {
198 setverdict(fail, "Timeout waiting for CBCH");
199 }
200 }
201 }
202 }
203 }
204
205 /* reset timeslot 0 channel combination to default */
206 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 0"},
207 "phys_chan_config CCCH+SDCCH4");
208 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 6"},
209 "phys_chan_config SDCCH8");
210}
211
212private const CbchTestMsgs msgs_1m_1b_norm := {
213 { RSL_CB_CMD_NORMAL, 0, '001000320f1141660c344dd3cba09a0c000000000000'O, omit }
214}
215
216private const CbchTestMsgs msgs_1m_2b_norm := {
217 { RSL_CB_CMD_NORMAL, 1, '001000320f1141660c344dd3cba09a0c000000000000'O &
218 '000102030405060708090a0b0c0d0e0f101213141516'O,
219 omit }
220}
221
222private const CbchTestMsgs msgs_1m_3b_norm := {
223 { RSL_CB_CMD_NORMAL, 2, '001000320f1141660c344dd3cba09a0c000000000000'O &
224 '000102030405060708090a0b0c0d0e0f101213141516'O &
225 '101112131415161718191a1b1c1d1e1f202223242526'O,
226 omit }
227}
228
229private const CbchTestMsgs msgs_1m_4b_norm := {
230 { RSL_CB_CMD_NORMAL, 3, '001000320f1141660c344dd3cba09a0c000000000000'O &
231 '000102030405060708090a0b0c0d0e0f101213141516'O &
232 '101112131415161718191a1b1c1d1e1f202223242526'O &
233 '202122232425262728292a2b2c2d2e2f303233343536'O,
234 omit }
235}
236
237private const CbchTestMsgs msgs_1m_4b_sched := {
238 { RSL_CB_CMD_SCHEDULE, 3, '001000320f1141660c344dd3cba09a0c000000000000'O &
239 '000102030405060708090a0b0c0d0e0f101213141516'O &
240 '101112131415161718191a1b1c1d1e1f202223242526'O &
241 '202122232425262728292a2b2c2d2e2f303233343536'O,
242 omit }
243}
244
Harald Weltee0026c32019-05-20 00:27:30 +0200245private const CbchTestMsgs msgs_3m_4b_norm := {
246 { RSL_CB_CMD_NORMAL, 3, '001000320f1141660c344dd3cba09a0c000000000000'O &
247 '000102030405060708090a0b0c0d0e0f101213141516'O &
248 '101112131415161718191a1b1c1d1e1f202223242526'O &
249 '201122232425262728292a2b2c2d2e2f303233343536'O,
250 omit },
251 { RSL_CB_CMD_NORMAL, 3, '002000320f1141660c344dd3cba09a0c000000000000'O &
252 '002102030405060708090a0b0c0d0e0f101213141516'O &
253 '102112131415161718191a1b1c1d1e1f202223242526'O &
254 '202122232425262728292a2b2c2d2e2f303233343536'O,
255 omit },
256 { RSL_CB_CMD_NORMAL, 3, '003000320f1141660c344dd3cba09a0c000000000000'O &
257 '003102030405060708090a0b0c0d0e0f101213141516'O &
258 '103112131415161718191a1b1c1d1e1f202223242526'O &
259 '203122232425262728292a2b2c2d2e2f303233343536'O,
260 omit }
261}
262
Harald Welte505cf9b2018-09-15 17:47:23 +0300263/* transmit single-block SMSCB COMMAND */
264testcase TC_sms_cb_cmd_sdcch4_1block() runs on test_CT {
265 var CbchTestPars pars := {
266 use_sdcch4 := true,
267 msgs := msgs_1m_1b_norm
268 };
269 f_TC_smscb(pars);
270}
271testcase TC_sms_cb_cmd_sdcch8_1block() runs on test_CT {
272 var CbchTestPars pars := {
273 use_sdcch4 := false,
274 msgs := msgs_1m_1b_norm
275 };
276 f_TC_smscb(pars);
277}
278
279/* transmit dual-block SMSCB COMMAND */
280testcase TC_sms_cb_cmd_sdcch4_2block() runs on test_CT {
281 var CbchTestPars pars := {
282 use_sdcch4 := true,
283 msgs := msgs_1m_2b_norm
284 };
285 f_TC_smscb(pars);
286}
287testcase TC_sms_cb_cmd_sdcch8_2block() runs on test_CT {
288 var CbchTestPars pars := {
289 use_sdcch4 := false,
290 msgs := msgs_1m_2b_norm
291 };
292 f_TC_smscb(pars);
293}
294
295/* transmit triple-block SMSCB COMMAND */
296testcase TC_sms_cb_cmd_sdcch4_3block() runs on test_CT {
297 var CbchTestPars pars := {
298 use_sdcch4 := true,
299 msgs := msgs_1m_3b_norm
300 };
301 f_TC_smscb(pars);
302}
303testcase TC_sms_cb_cmd_sdcch8_3block() runs on test_CT {
304 var CbchTestPars pars := {
305 use_sdcch4 := false,
306 msgs := msgs_1m_3b_norm
307 };
308 f_TC_smscb(pars);
309}
310
311/* transmit quad-block SMSCB COMMAND */
312testcase TC_sms_cb_cmd_sdcch4_4block() runs on test_CT {
313 var CbchTestPars pars := {
314 use_sdcch4 := true,
315 msgs := msgs_1m_4b_norm
316 };
317 f_TC_smscb(pars);
318}
319testcase TC_sms_cb_cmd_sdcch8_4block() runs on test_CT {
320 var CbchTestPars pars := {
321 use_sdcch4 := false,
322 msgs := msgs_1m_4b_norm
323 };
324 f_TC_smscb(pars);
325}
326
Harald Weltee0026c32019-05-20 00:27:30 +0200327/* transmit multiple commands of each 4 blocks */
328testcase TC_sms_cb_cmd_sdcch4_multi() runs on test_CT {
329 var CbchTestPars pars := {
330 use_sdcch4 := true,
331 msgs := msgs_3m_4b_norm
332 };
333 f_TC_smscb(pars);
334}
335testcase TC_sms_cb_cmd_sdcch8_multi() runs on test_CT {
336 var CbchTestPars pars := {
337 use_sdcch4 := false,
338 msgs := msgs_3m_4b_norm
339 };
340 f_TC_smscb(pars);
341}
342
Harald Welte505cf9b2018-09-15 17:47:23 +0300343/* transmit SMSCB COMMAND with SCHEDULE payload */
344testcase TC_sms_cb_cmd_sdcch4_schedule() runs on test_CT {
345 var CbchTestPars pars := {
346 use_sdcch4 := true,
347 msgs := msgs_1m_4b_sched
348 };
349 f_TC_smscb(pars);
350}
351testcase TC_sms_cb_cmd_sdcch8_schedule() runs on test_CT {
352 var CbchTestPars pars := {
353 use_sdcch4 := false,
354 msgs := msgs_1m_4b_sched
355 };
356 f_TC_smscb(pars);
357}
358
359/* SMSCB TODO:
360 * multiple SMS BC CMD at the same time: Ensure all of them are sent exactly once
361 * extended CBCH vs. normal CBCH
362 *
363 */
364
365control {
366 execute( TC_sms_cb_cmd_sdcch4_1block() );
367 execute( TC_sms_cb_cmd_sdcch4_2block() );
368 execute( TC_sms_cb_cmd_sdcch4_3block() );
369 execute( TC_sms_cb_cmd_sdcch4_4block() );
Harald Weltee0026c32019-05-20 00:27:30 +0200370 execute( TC_sms_cb_cmd_sdcch4_multi() );
Harald Welte505cf9b2018-09-15 17:47:23 +0300371 execute( TC_sms_cb_cmd_sdcch4_schedule() );
372 if (false) { /* FIXME: SDCCH/8 support broken, needs trxcon + L1CTL work */
373 execute( TC_sms_cb_cmd_sdcch8_1block() );
374 execute( TC_sms_cb_cmd_sdcch8_2block() );
375 execute( TC_sms_cb_cmd_sdcch8_3block() );
376 execute( TC_sms_cb_cmd_sdcch8_4block() );
Harald Weltee0026c32019-05-20 00:27:30 +0200377 execute( TC_sms_cb_cmd_sdcch8_multi() );
Harald Welte505cf9b2018-09-15 17:47:23 +0300378 execute( TC_sms_cb_cmd_sdcch8_schedule() );
379 }
380}
381
382
383}