blob: 6cb257c71adf2857216a45fa8a00f68d849380c4 [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
245/* transmit single-block SMSCB COMMAND */
246testcase TC_sms_cb_cmd_sdcch4_1block() runs on test_CT {
247 var CbchTestPars pars := {
248 use_sdcch4 := true,
249 msgs := msgs_1m_1b_norm
250 };
251 f_TC_smscb(pars);
252}
253testcase TC_sms_cb_cmd_sdcch8_1block() runs on test_CT {
254 var CbchTestPars pars := {
255 use_sdcch4 := false,
256 msgs := msgs_1m_1b_norm
257 };
258 f_TC_smscb(pars);
259}
260
261/* transmit dual-block SMSCB COMMAND */
262testcase TC_sms_cb_cmd_sdcch4_2block() runs on test_CT {
263 var CbchTestPars pars := {
264 use_sdcch4 := true,
265 msgs := msgs_1m_2b_norm
266 };
267 f_TC_smscb(pars);
268}
269testcase TC_sms_cb_cmd_sdcch8_2block() runs on test_CT {
270 var CbchTestPars pars := {
271 use_sdcch4 := false,
272 msgs := msgs_1m_2b_norm
273 };
274 f_TC_smscb(pars);
275}
276
277/* transmit triple-block SMSCB COMMAND */
278testcase TC_sms_cb_cmd_sdcch4_3block() runs on test_CT {
279 var CbchTestPars pars := {
280 use_sdcch4 := true,
281 msgs := msgs_1m_3b_norm
282 };
283 f_TC_smscb(pars);
284}
285testcase TC_sms_cb_cmd_sdcch8_3block() runs on test_CT {
286 var CbchTestPars pars := {
287 use_sdcch4 := false,
288 msgs := msgs_1m_3b_norm
289 };
290 f_TC_smscb(pars);
291}
292
293/* transmit quad-block SMSCB COMMAND */
294testcase TC_sms_cb_cmd_sdcch4_4block() runs on test_CT {
295 var CbchTestPars pars := {
296 use_sdcch4 := true,
297 msgs := msgs_1m_4b_norm
298 };
299 f_TC_smscb(pars);
300}
301testcase TC_sms_cb_cmd_sdcch8_4block() runs on test_CT {
302 var CbchTestPars pars := {
303 use_sdcch4 := false,
304 msgs := msgs_1m_4b_norm
305 };
306 f_TC_smscb(pars);
307}
308
309/* transmit SMSCB COMMAND with SCHEDULE payload */
310testcase TC_sms_cb_cmd_sdcch4_schedule() runs on test_CT {
311 var CbchTestPars pars := {
312 use_sdcch4 := true,
313 msgs := msgs_1m_4b_sched
314 };
315 f_TC_smscb(pars);
316}
317testcase TC_sms_cb_cmd_sdcch8_schedule() runs on test_CT {
318 var CbchTestPars pars := {
319 use_sdcch4 := false,
320 msgs := msgs_1m_4b_sched
321 };
322 f_TC_smscb(pars);
323}
324
325/* SMSCB TODO:
326 * multiple SMS BC CMD at the same time: Ensure all of them are sent exactly once
327 * extended CBCH vs. normal CBCH
328 *
329 */
330
331control {
332 execute( TC_sms_cb_cmd_sdcch4_1block() );
333 execute( TC_sms_cb_cmd_sdcch4_2block() );
334 execute( TC_sms_cb_cmd_sdcch4_3block() );
335 execute( TC_sms_cb_cmd_sdcch4_4block() );
336 execute( TC_sms_cb_cmd_sdcch4_schedule() );
337 if (false) { /* FIXME: SDCCH/8 support broken, needs trxcon + L1CTL work */
338 execute( TC_sms_cb_cmd_sdcch8_1block() );
339 execute( TC_sms_cb_cmd_sdcch8_2block() );
340 execute( TC_sms_cb_cmd_sdcch8_3block() );
341 execute( TC_sms_cb_cmd_sdcch8_4block() );
342 execute( TC_sms_cb_cmd_sdcch8_schedule() );
343 }
344}
345
346
347}