blob: 4d4a9884bbb76395bdb004ee3219ffb198578fee [file] [log] [blame]
Harald Welte97cca2f2019-05-30 16:33:38 +02001module BTS_Tests_LAPDm {
Harald Weltef6543322017-07-16 07:35:10 +02002
Harald Welte72c81e72019-05-30 16:36:11 +02003import from GSM_Types all;
4import from Osmocom_Types all;
5import from LAPDm_RAW_PT all;
6import from LAPDm_Types all;
Harald Welte2f2b2b72019-05-31 22:24:57 +02007import from RSL_Types all;
Harald Welte72c81e72019-05-30 16:36:11 +02008import from BTS_Tests all;
Harald Welte2f2b2b72019-05-31 22:24:57 +02009import from Misc_Helpers all;
Harald Welte66110f02017-07-16 21:05:18 +020010
Harald Welte72c81e72019-05-30 16:36:11 +020011/* test that use exclusively only LAPDm over L1CTL */
12type component lapdm_test_CT {
13 port LAPDm_PT LAPDM;
14 var lapdm_CT lapdm_component;
15};
16
17/* contrary to BTS_Tests.ttcn, we use LAPDm_PT here, a convenience wrapper
18 * around L1CTL to perform encode/decode of abstract LAPDm frames */
Harald Welte72c81e72019-05-30 16:36:11 +020019
Harald Welte61332c02019-05-30 16:45:15 +020020/*********************************************************************************
21 * Test using only L1CTL/LAPDm
22 *********************************************************************************/
23
24function f_lapdm_init() runs on lapdm_test_CT {
Harald Welte72c81e72019-05-30 16:36:11 +020025 /* create the LAPDm component */
26 lapdm_component := lapdm_CT.create;
27 /* connect our own LAPDM port to the LAPDM Service Provider of the LAPDm component */
28 connect(self:LAPDM, lapdm_component:LAPDM_SP);
29 /* connect the LAPDm compoent's lower-side port to the system L1CTL port (which is internally
30 * connected to the Unix Domain Socket test port */
31 map(lapdm_component:L1CTL, system:L1CTL);
32
33 /* start the LAPDm parallel component calling it's local function LAPDmStart */
34 lapdm_component.start(LAPDmStart());
35}
36
Harald Welte2f2b2b72019-05-31 22:24:57 +020037function f_lapdm_exit() runs on lapdm_test_CT {
38 lapdm_component.stop;
39 lapdm_component.done;
40 unmap(lapdm_component:L1CTL, system:L1CTL);
41}
42
Harald Welte72c81e72019-05-30 16:36:11 +020043/* master function establishing a dedicated radio channel (takes care of RACH/IMM.ASS handling) */
44function f_establish_dcch() runs on lapdm_test_CT {
Harald Welte2f2b2b72019-05-31 22:24:57 +020045 var BCCH_tune_req tune_req := { arfcn := { false, mp_trx0_arfcn }, combined_ccch := true };
Harald Welte72c81e72019-05-30 16:36:11 +020046 var DCCH_establish_req est_req := { ra := 23 };
47
48 LAPDM.send(tune_req);
49 LAPDM.send(est_req);
50 LAPDM.receive(DCCH_establish_res:?);
51}
52
Harald Welte2f2b2b72019-05-31 22:24:57 +020053/* master function switching to a dedicated radio channel */
54function f_switch_dcch(Arfcn arfcn, RslChannelNr chan_nr, GsmTsc tsc) runs on lapdm_test_CT {
55 var BCCH_tune_req tune_req := { arfcn := arfcn, combined_ccch := true };
56 var DCCH_switch_req sw_req := { arfcn, chan_nr, tsc };
57
58 LAPDM.send(tune_req);
59 LAPDM.send(sw_req);
60 LAPDM.receive(DCCH_switch_res:?);
61}
62
Harald Welte72c81e72019-05-30 16:36:11 +020063/* helper function releasing dedicated radio channel physically (no Um signaling!) */
64function f_release_dcch() runs on lapdm_test_CT {
65 var DCCH_release_req rel_req := {};
66 LAPDM.send(rel_req);
67}
68
69template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
70 sacch := sacch,
71 sapi := sapi,
72 lapdm := frame
73}
Harald Weltec38611b2019-05-30 16:33:58 +020074
Eric Wild74f25ae2019-06-14 11:44:29 +020075function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on ConnHdlr return boolean {
Harald Welte72c81e72019-05-30 16:36:11 +020076 var LAPDm_ph_data phd;
77 var boolean result := false;
78 timer T := 5.0;
79
Eric Wild74f25ae2019-06-14 11:44:29 +020080 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=false, l3:=payload)));
Harald Welte72c81e72019-05-30 16:36:11 +020081 T.start
82 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +020083 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { result := true; }
84 [] RSL.receive {repeat;}
85 [] LAPDM.receive { repeat; }
Harald Welte72c81e72019-05-30 16:36:11 +020086 [] T.timeout { }
87 }
Eric Wild74f25ae2019-06-14 11:44:29 +020088 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MT_CMD, p:=false, nr:=0)));
Harald Welte72c81e72019-05-30 16:36:11 +020089 return result;
90}
91
Eric Wild74f25ae2019-06-14 11:44:29 +020092function f_TC_sabm_ua_dcch_sapi0(charstring id) runs on ConnHdlr {
93 fp_common_init();
94 RSL.clear;
95 LAPDM.clear;
96 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +020097 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
98 setverdict(fail);
99 }
100 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200101 deactivate(d);
102 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200103}
104
Eric Wild74f25ae2019-06-14 11:44:29 +0200105function f_TC_sabm_ua_dcch_sapi0_nopayload(charstring id) runs on ConnHdlr {
106 fp_common_init();
107 RSL.clear;
108 LAPDM.clear;
109 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200110 if (f_test_sabm_results_in_ua(0, false, ''O)) {
111 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
112 }
113 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200114 deactivate(d);
115 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200116}
117
Eric Wild74f25ae2019-06-14 11:44:29 +0200118function f_TC_sabm_ua_dcch_sapi3(charstring id) runs on ConnHdlr {
119 fp_common_init();
120 RSL.clear;
121 LAPDM.clear;
122 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200123 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
124 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
125 }
126 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200127 deactivate(d);
128 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200129}
130
Eric Wild74f25ae2019-06-14 11:44:29 +0200131function f_TC_sabm_ua_dcch_sapi4(charstring id) runs on ConnHdlr {
132 fp_common_init();
133 RSL.clear;
134 LAPDM.clear;
135 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200136 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
137 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
138 }
139 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200140 deactivate(d);
141 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200142}
143
Eric Wild74f25ae2019-06-14 11:44:29 +0200144testcase TC_sabm_ua_dcch_sapi0() runs on test_CT {
145 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
146 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0));
147}
148
149testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on test_CT {
150 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
151 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0_nopayload));
152}
153
154testcase TC_sabm_ua_dcch_sapi3() runs on test_CT {
155 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
156 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi3));
157}
158
159testcase TC_sabm_ua_dcch_sapi4() runs on test_CT {
160 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
161 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi4));
162}
163
164function f_TC_sabm_contention(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200165 var LAPDm_ph_data phd;
166 const octetstring payload := '0102030405'O;
167 const GsmSapi sapi := 0;
168 const boolean use_sacch := false;
169 timer T := 5.0;
170
Eric Wild74f25ae2019-06-14 11:44:29 +0200171 fp_common_init();
172 RSL.clear;
173 LAPDM.clear;
Harald Welte72c81e72019-05-30 16:36:11 +0200174
Harald Welte72c81e72019-05-30 16:36:11 +0200175 /* first frame is our real SABM */
Eric Wild74f25ae2019-06-14 11:44:29 +0200176 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=false, l3:=payload)));
Harald Welte72c81e72019-05-30 16:36:11 +0200177 /* second frame is a SABM with different payload, which BTS has to ignore according to 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200178 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=false, l3:='ABCDEF'O)));
Harald Welte72c81e72019-05-30 16:36:11 +0200179 T.start
180 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +0200181 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { setverdict(pass); repeat; }
182 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=?))) {
Harald Welte72c81e72019-05-30 16:36:11 +0200183 setverdict(fail, "Second SABM was responded to during contention resolution");
Eric Wild74f25ae2019-06-14 11:44:29 +0200184 }
185 [] RSL.receive {repeat;}
Harald Welte72c81e72019-05-30 16:36:11 +0200186 [] LAPDM.receive { repeat };
187 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200188 }
Eric Wild74f25ae2019-06-14 11:44:29 +0200189
190 fp_common_fini();
191}
192
193testcase TC_sabm_contention() runs on test_CT {
194 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
195 f_testmatrix_each_chan(pars, refers(f_TC_sabm_contention));
Harald Welte72c81e72019-05-30 16:36:11 +0200196}
Harald Welte9e4725d2017-07-16 23:18:09 +0200197
Harald Welte72c81e72019-05-30 16:36:11 +0200198/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
199 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200200function f_TC_sabm_retransmit(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200201 const octetstring payload := '00FEFEDEADBEEF'O;
Eric Wild74f25ae2019-06-14 11:44:29 +0200202 fp_common_init();
203 RSL.clear;
204 LAPDM.clear;
205 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200206 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200207 setverdict(fail);
Harald Welte599faa12017-07-17 21:49:24 +0200208 }
Harald Welte72c81e72019-05-30 16:36:11 +0200209 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200210 setverdict(fail);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200211 }
Harald Welte72c81e72019-05-30 16:36:11 +0200212 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200213 deactivate(d);
214 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200215}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200216
Eric Wild74f25ae2019-06-14 11:44:29 +0200217testcase TC_sabm_retransmit() runs on test_CT {
218 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
219 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit));
Harald Welte72c81e72019-05-30 16:36:11 +0200220}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200221
Harald Welte2f2b2b72019-05-31 22:24:57 +0200222/*********************************************************************************
223 * Test using both L1CTL/LAPDm and RSL
224 *********************************************************************************/
225
226private function fp_common_init() runs on ConnHdlr
227{
228 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
229 unmap(self:L1CTL, system:L1CTL);
230 f_lapdm_init();
231 /* activate the channel on the BTS side */
232 f_rsl_chan_act(g_pars.chan_mode, false, {});
233 /* activate the channel on the MS side */
234 f_switch_dcch({false, mp_trx0_arfcn}, g_chan_nr, 7);
235}
236
237private function fp_common_fini() runs on ConnHdlr
238{
239 f_release_dcch();
240 f_rsl_chan_deact();
241 f_lapdm_exit();
242}
243
Harald Welte76771f12019-06-02 22:58:58 +0200244/* Mobile-Originated LAPDm establishment on given Link ID */
245private function f_establish_mo(RslLinkId link_id) runs on ConnHdlr
246{
247 var integer sapi := link_id.sapi;
248 var boolean is_sacch := false;
249 if (link_id.c == SACCH) {
250 is_sacch := true;
251 }
252
253 var octetstring l3_mo := f_rnd_octstring(5);
254
255 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
256 if (is_sacch) {
257 /* no payload permitted, as this is not contention resolution */
258 l3_mo := ''O;
259 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
260 RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
261 } else {
262 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
263 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
264 }
265 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
266 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
267}
268
Harald Welte2f2b2b72019-05-31 22:24:57 +0200269/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
270 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
271private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
272 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
273 fp_common_init();
274
275 LAPDM.clear;
276 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
277
278 timer T := 8.0;
279 var integer sabm_received := 0;
280 T.start;
281 alt {
282 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
283 sabm_received := sabm_received + 1;
284 repeat;
285 }
286 [] LAPDM.receive { repeat; }
287 [] T.timeout { }
288 }
289 if (sabm_received == 0) {
290 setverdict(fail, "No SABM observed at all!");
291 } else if (sabm_received != 6) {
292 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
293 sabm_received);
294 } else {
295 setverdict(pass, "Received ", sabm_received, " SABM");
296 }
297
298 fp_common_fini();
299}
300testcase TC_sabm_retransmit_bts() runs on test_CT {
301 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
302 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
303}
304
305
306type record LapdmNamedFrame {
307 charstring name,
308 LapdmFrame lapdm
309};
310
311/* Test that the BTS will ignore receipt of frames other than a UA when
312 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
313 * Section 25.2.1.1.2.3 */
314private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
315 var integer sapi := err_frame.lapdm.ab.addr.sapi;
316 fp_common_init();
317
318 /* Establish Request via RSL; Expect SABM on LAPDm side */
319 LAPDM.clear;
320 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
321 alt {
322 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
323 [] LAPDM.receive { repeat; }
324 }
325
326 /* send erroneous response to SABM */
327 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
328
329 /* expect a SABM retransmission of the BTS */
330 timer T := 3.0;
331 T.start;
332 alt {
333 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
334 setverdict(pass);
335 }
336 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
337 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
338 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
339 err_frame.name);
340 }
341 [] LAPDM.receive { repeat; }
342 [] T.timeout {
343 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
344 err_frame.name);
345 }
346 }
347
348 fp_common_fini();
349}
350private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
351 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
352 var LapdmNamedFrame err_frame[3] := {
353 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
354 l3 := '01020304'O)) },
355 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
356 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
357 };
358 var integer i;
359
360 for (i := 0; i < lengthof(err_frame); i := i+1) {
361 f_TC_sabm_invalid_resp2(id, err_frame[i])
362 }
363}
364testcase TC_sabm_invalid_resp() runs on test_CT {
365 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
366 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
367}
368
369/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
370 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
371private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
372 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
373 fp_common_init();
374
375 /* Establish Request via RSL; Expect SABM on LAPDm side */
376 LAPDM.clear;
377 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
378 alt {
379 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
380 [] LAPDM.receive { repeat; }
381 }
382
383 /* send DM response to SABM */
384 RSL.clear;
385 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
386 alt {
387 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
388 [] RSL.receive { repeat; }
389 }
390
391 /* expect no SABM retransmission of the BTS */
392 timer T := 3.0;
393 T.start;
394 alt {
395 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
396 setverdict(fail, "Received unexpected SABM retransmission");
397 }
398 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
399 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
400 setverdict(fail, "Received unexpected LAPDm frame");
401 }
402 [] LAPDM.receive { repeat; }
403 [] T.timeout {
404 setverdict(pass);
405 }
406 }
407
408 fp_common_fini();
409}
410testcase TC_sabm_dm() runs on test_CT {
411 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
412 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
413}
414
415/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
416 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
417 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
418private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
419 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
420 var integer num_sabm := 0;
421 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
422 timer T := 3.0;
423
424 fp_common_init();
425
426 /* Establish Request via RSL */
427 LAPDM.clear;
428 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
429 /* Expect two SABM (retransmit) */
430 T.start;
431 alt {
432 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
433 num_sabm := num_sabm + 1;
434 if (num_sabm < 2) {
435 repeat;
436 }
437 }
438 [] LAPDM.receive { repeat; }
439 }
440
441 /* send UA response to SABM */
442 RSL.clear;
443 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
444 alt {
445 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
446 [] RSL.receive { repeat; }
447 }
448
449 /* Send I frame from BTS to MS */
450 var octetstring l3 := f_rnd_octstring(10);
451 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
452 alt {
453 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
454 nr:=0, ns:=0, l3:=l3)));
455 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
456 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
457 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
458 }
459 /* Send RR frame in response */
460 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
461
462 /* expect idle UI Frame from BTS */
463 alt {
464 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
465 setverdict(pass);
466 }
467 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
468 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
469 }
470
471 fp_common_fini();
472}
473testcase TC_establish_ign_first_sabm() runs on test_CT {
474 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
475 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
476}
477
478/* ignore all SACCH frames */
479private altstep as_lapdm_acch() runs on ConnHdlr {
480 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
481}
Harald Welteef6fd442019-06-01 21:41:29 +0200482/* ignore all DCCH frames */
483private altstep as_lapdm_dcch() runs on ConnHdlr {
484 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
485}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200486/* ignore all LAPDm idle frames (UI) */
487private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200488 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200489}
490/* ignore all measurement reports */
491private altstep as_rsl_meas_rep() runs on ConnHdlr {
492 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
493}
494/* fail if we receive an RSL ERROR IND */
495private altstep as_rsl_fail_err() runs on ConnHdlr {
496 var RSL_Message rx_rsl;
497 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
498 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
499 }
500}
501/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200502private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200503 [want_dcch] as_lapdm_acch();
504 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200505 [] as_lapdm_idle();
506 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200507 [not ignore_rsl_errors] as_rsl_fail_err();
508 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200509}
510
511/* Test the operation of Layer 2 sequence numbering.
512 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
513private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
514 const integer sapi := 0;
515 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
516 var octetstring l3 := f_rnd_octstring(18);
517 var default d;
518 timer T := 3.0;
519
520 fp_common_init();
521
522 /* some common altstep for meas res and other background noise */
523 d := activate(as_ignore_background());
524 RSL.clear;
525 LAPDM.clear;
526
Harald Welte76771f12019-06-02 22:58:58 +0200527 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200528
529 var integer last_ns_rx := 0;
530
531 for (var integer i := 0; i < 10; i := i+1) {
532 var octetstring l3_mo := f_rnd_octstring(12);
533 var octetstring l3_mt := f_rnd_octstring(12);
534 var LAPDm_ph_data pd;
535
536 log("Starting iteration ", i);
537 /* MT I frame */
538 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
539 alt {
540 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
541 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
542 nr:=i mod 8))) {
543 log("Ignoring RR in iteration ", i);
544 repeat;
545 }
546 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
547 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
548 nr:=i mod 8, ns:=i mod 8,
549 l3:=l3_mt))) -> value pd {
550 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
551 }
552 }
553 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
554 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
555 nr:=(last_ns_rx+1)mod 8,
556 ns:=i mod 8, l3 := l3_mo)));
557 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
558 }
559 log("Completed iteration");
560
561 deactivate(d);
562 fp_common_fini();
563}
564testcase TC_iframe_seq_and_ack() runs on test_CT {
565 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
566 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
567}
568
569/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
570 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
571
572/*
573 1) The BTS is brought into the multiple frame established state
574 2) The MS sends an L3 Request asking for IMEI to the MS.
575 3) The BTS shall respond with a RR frame though this may be incorporated with
576 the L3 Response I frame. The MS does not respond to the I frame.
577 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
578 with the P bit set to 1.
579 5) The MS then sends a valid L3 Request I frame asking for IMEI which
580 does not acknowledge receipt of the I frame from the BTS.
581On the FACCH the BTS may send an RR frame acknowledging the I frame.
582 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
583 the second I frame from the MS.
584 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
585 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
586*/
587private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
588 const integer sapi := 0;
589 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
590 var default d;
591 timer T := 3.0;
592
593 fp_common_init();
594
595 /* some common altstep for meas res and other background noise */
596 d := activate(as_ignore_background());
597 RSL.clear;
598 LAPDM.clear;
599
600 var octetstring l3_mo := f_rnd_octstring(12);
601 var octetstring l3_mt := f_rnd_octstring(12);
602
603 /* 1) The BTS is brought into the multiple frame established state */
604
605 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
606 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
607 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
608 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
609 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
610
611 /* 2) The MS sends an L3 Request to the BTS */
612 l3_mo := f_rnd_octstring(18);
613 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
614 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
615 nr:=0, ns:=0, l3:=l3_mo)));
616 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
617 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
618 the L3 Response I frame. The MS does not respond to the I frame. */
619 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
620 alt {
621 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
622 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
623 repeat;
624 }
625 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
626 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
627 nr:=1, ns:=0, l3:=l3_mt)));
628 }
629
630 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
631 with the P bit set to 1. */
632 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
633 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
634 nr:=1, ns:=0, l3:=l3_mt)));
635
636 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
637 does not acknowledge receipt of the I frame from the BTS. */
638 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
639 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
640 nr:=0, ns:=1, l3 := l3_mo)));
641 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
642 alt {
643 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
644 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
645 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
646 repeat;
647 }
648 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
649 receipt of the second I frame from the MS. */
650 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
651 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
652 nr:=2, ns:=0, l3:=l3_mt)));
653 }
654
655 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
656 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
657 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
658
659 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
660 l3_mt := f_rnd_octstring(16);
661 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
662 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
663 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
664 nr:=2, ns:=1, l3:=l3_mt)));
665 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
666
667 deactivate(d);
668 fp_common_fini();
669}
670testcase TC_iframe_timer_recovery() runs on test_CT {
671 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
672 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
673}
674
Eric Wild211acc32019-06-11 19:06:38 +0200675/* 25.2.6.1 ns sequence error
676sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
677private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
678 const integer sapi := 0;
679 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
680 var default d;
681 timer T := 3.0;
682
683 fp_common_init();
684
685 /* some common altstep for meas res and other background noise */
686 d := activate(as_ignore_background(ignore_rsl_errors := true));
687 RSL.clear;
688 LAPDM.clear;
689
690 var octetstring l3_mo := f_rnd_octstring(12);
691 var octetstring l3_mt := f_rnd_octstring(12);
692
693 /* 1) The BTS is brought into the multiple frame established state */
694
695 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
696 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
697 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
698 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
699 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
700
701 /* 2) The MS sends an L3 Request to the BTS */
702 l3_mo := f_rnd_octstring(18);
703 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
704 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
705 nr:=0, ns:=0, l3:=l3_mo)));
706 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
707 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
708 the L3 Response I frame. */
709 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
710 alt {
711 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
712 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
713 repeat;
714 }
715 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
716 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
717 nr:=1, ns:=0, l3:=l3_mt)));
718 }
719
720 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
721 but correctly acknowledging the MS's I frame; P bit set to zero. */
722 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
723 nr:=1, ns:=0, l3:=l3_mo)));
724
725 /* no rsl data ind due to wrong ns */
726
727 /* The BTS shall send a REJ frame. */
728 timer T1 := 2.0;
729 T1.start;
730 alt{
731 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
732 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
733 }
734
735 f_sleep(2.0); // T200
736
737 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
738 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
739 nr:=1, ns:=0, l3:=l3_mo)));
740
741 /* The BTS shall respond with a REJ, F bit set to 1. */
742 T1.start;
743 alt{
744 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
745 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
746 }
747
748 deactivate(d);
749 fp_common_fini();
750 setverdict(pass);
751}
752
753testcase TC_ns_seq_error() runs on test_CT {
754 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
755 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
756}
757
758/* 25.2.6.2 nr sequence error */
759private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
760 const integer sapi := 0;
761 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
762 var default d;
763 var integer n201 := 20;
764 if (link_id.c == SACCH) {
765 n201 := 18;
766 }
767
768 fp_common_init();
769
770 /* some common altstep for meas res and other background noise */
771 d := activate(as_ignore_background(ignore_rsl_errors := true));
772 RSL.clear;
773 LAPDM.clear;
774
775 var octetstring l3_mo := f_rnd_octstring(12);
776 var octetstring l3_mt := f_rnd_octstring(12);
777
778 /* 1) The BTS is brought into the multiple frame established state */
779
780 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
781 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
782 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
783 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
784 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
785
786 /* 2) The MS shall send an I frame containing an information field of length N201 and an
787 incorrect receive sequence number. */
788 l3_mo := f_rnd_octstring(n201);
789 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
790 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
791 nr:=1, ns:=0, l3:=l3_mo)));
792
793 /* The BTS may: a) send a DISC frame within N200×T200; */
794 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
795 timer T1 := 2.0;
796 T1.start;
797 alt{
798 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
799 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
800 }
801
802 /* a) the MS shall respond with a UA frame.
803 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
804 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
805
806 deactivate(d);
807 fp_common_fini();
808 setverdict(pass);
809}
810
811testcase TC_nr_seq_error() runs on test_CT {
812 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
813 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
814}
815
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100816private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200817 LAPDM.send(t_PH_DATA(0, false, x));
818 f_sleep(2.0); // T200
819 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100820 timer T1 := 2.0;
821 T1.start;
822 alt {
823 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
824 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
825 }
Eric Wild211acc32019-06-11 19:06:38 +0200826}
827
828/* 25.2.7 Test on receipt of invalid frames
829sends a bunch of different invalid frames, expects the BTS to ignore all of them */
830private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
831 const integer sapi := 0;
832 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
833 var default d;
834 timer T := 3.0;
835
836 fp_common_init();
837
838 /* some common altstep for meas res and other background noise */
839 d := activate(as_ignore_background(ignore_rsl_errors := true));
840 RSL.clear;
841 LAPDM.clear;
842
843 var octetstring l3_mo := f_rnd_octstring(12);
844 var octetstring l3_mt := f_rnd_octstring(12);
845
846 /* 1) The BTS is brought into the multiple frame established state */
847
848 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
849 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100850 T.start
851 alt {
852 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
853 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
854 }
855 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200856 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100857 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
858 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
859 }
Eric Wild211acc32019-06-11 19:06:38 +0200860
861 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
862 RR frame with the Length indicator greater than zero and a faulty N(R); */
863 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
864 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100865 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200866 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
867 EJ frame with the EA bit set to zero and a faulty N(R); */
868 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
869 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100870 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200871 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
872 SABM frame with the EL bit set to zero; */
873 l3_mo := ''O;
874 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
875 x.ab.el := 0;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100876 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200877 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
878 DM frame with the Length indicator greater than zero;*/
879 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
880 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100881 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200882 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
883 DISC frame with the M bit set to 1; */
884 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
885 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100886 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200887 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
888 UA frame with the EA bit set to zero*/
889 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
890 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100891 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200892 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
893 I frame with the Length indicator greater than N201;*/
894 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 6, l3 := f_rnd_octstring(25)))
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100895 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200896 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
897 I frame with the M bit set to 1 and the Length indicator less than N201;*/
898 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
899 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100900 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200901 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
902 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100903 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200904
905 /* command frames with correct Address and Length indicator field and a non-implemented control field */
906 /* 12: One command frame with Control Field = xxx1 1101. */
907 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
908 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100909 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200910 /* 13: One command frame with Control field = xxx1 1011. */
911 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
912 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100913 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200914 /* 14: One command frame with Control field = xxx1 0111. */
915 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
916 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100917 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200918 /* 15: One command frame with Control field = 01x1 1111. */
919 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
920 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100921 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200922 /* 16: One command frame with Control field = 1xx1 1111. */
923 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
924 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100925 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200926 /* 17: One command frame with Control field = 0011 0011. */
927 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
928 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100929 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200930 /* 18: One command frame with Control field = 1xx1 0011. */
931 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
932 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100933 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200934
935 deactivate(d);
936 fp_common_fini();
937 setverdict(pass);
938}
939
940testcase TC_rec_invalid_frame() runs on test_CT {
941 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
942 pars.t_guard := 60.0;
943 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
944}
945
Harald Welte9ea918c2019-06-01 11:46:25 +0200946type record LapdmDlConfig {
947 integer n201,
948 integer t200
949};
950
951type record LapdmDlState {
952 integer v_s,
953 integer v_a,
954 integer v_r
955};
956
957template (value) LapdmDlState t_init_LapdmDlState := {
958 v_s := 0,
959 v_a := 0,
960 v_r := 0
961}
962
963private function inc_mod8(inout integer v)
964{
965 v := (v + 1) mod 8;
966}
967
968private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
969runs on ConnHdlr {
970 var LAPDm_ph_data pd;
971 var integer offset := 0;
972 var integer n201 := 20;
973 var boolean is_sacch := false;
974 if (link_id.c == SACCH) {
975 n201 := 18;
976 is_sacch := true;
977 }
978
979 while (offset < lengthof(l3)) {
980 var integer remain_len := lengthof(l3) - offset;
981 var integer seg_len := remain_len;
982 if (remain_len > n201) {
983 seg_len := n201;
984 }
985 var octetstring segment := substr(l3, offset, seg_len);
986 var boolean more;
987 if (offset + lengthof(segment) < lengthof(l3)) {
988 more := true;
989 } else {
990 more := false;
991 }
992 /* send the next segment */
993 LAPDM.send(t_PH_DATA(0, is_sacch,
994 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
995 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
996 inc_mod8(dls.v_s);
997 offset := offset + lengthof(segment);
998
999 /* wait for it to be acknowledged */
1000 alt {
1001 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1002 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001003 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001004 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
1005 setverdict(fail, "received unexpected LAPDm ", pd);
1006 repeat;
1007 }
1008 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1009 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1010 setverdict(fail, "received RSL DATA IND before message complete");
1011 }
1012 }
1013 }
1014
1015 timer T := 1.0;
1016 T.start;
1017 alt {
1018 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1019 setverdict(pass);
1020 }
1021 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1022 setverdict(fail, "Received RSL DATA IND with wrong payload");
1023 }
1024 [] T.timeout {
1025 setverdict(fail, "Timeout waiting for RSL DATA IND of de-segmented message");
1026 }
1027 }
1028}
1029
1030/* Section 5.8.5 of TS 04.06 */
1031const integer c_TS0406_MAX_L3_OCTETS := 251;
1032
Harald Welteef6fd442019-06-01 21:41:29 +02001033/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1034 * on specified SAPI/channel */
1035private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1036 var integer sapi := link_id.sapi;
1037 var boolean is_sacch := false;
1038 if (link_id.c == SACCH) {
1039 is_sacch := true;
1040 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001041 var default d;
1042 timer T := 3.0;
1043
1044 fp_common_init();
1045
1046 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001047 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001048 RSL.clear;
1049 LAPDM.clear;
1050
Harald Welte76771f12019-06-02 22:58:58 +02001051 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001052
Harald Welte76771f12019-06-02 22:58:58 +02001053 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001054
1055 deactivate(d);
1056
1057 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1058 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1059
1060 fp_common_fini();
1061}
Harald Welteef6fd442019-06-01 21:41:29 +02001062private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1063 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001064}
Harald Welteef6fd442019-06-01 21:41:29 +02001065private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1066 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1067}
1068/* test mobile-originated segmentation/de-segmentation on DCCH */
1069testcase TC_segm_concat_dcch() runs on test_CT {
1070 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1071 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1072}
1073/* test mobile-originated segmentation/de-segmentation on SACCH */
1074testcase TC_segm_concat_sacch() runs on test_CT {
1075 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1076 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1077}
1078
Harald Welteb2a30342019-06-02 22:13:50 +02001079/* TS 04.06 Section 5.8.2.1 */
1080private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1081 /* SACCH irrespective of physical channel type */
1082 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1083 return 5;
1084 }
1085 /* DCCH below */
1086 select (chan_nr) {
1087 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1088 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1089 case (t_RslChanNr_Bm(?)) { return 34; }
1090 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1091 }
1092 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1093 return -1;
1094}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001095
Harald Welteb2a30342019-06-02 22:13:50 +02001096/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1097private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
1098 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1099 var integer sapi := link_id.sapi;
1100 var boolean is_sacch := false;
1101 if (link_id.c == SACCH) {
1102 is_sacch := true;
1103 }
1104 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1105 var integer num_retrans := 0;
1106 timer T := 3.0;
1107 var default d;
1108
1109 fp_common_init();
1110
1111 /* some common altstep for meas res and other background noise */
1112 d := activate(as_ignore_background(true));
1113 RSL.clear;
1114 LAPDM.clear;
1115
Harald Welte76771f12019-06-02 22:58:58 +02001116 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001117
1118 var octetstring l3_mt := f_rnd_octstring(20);
1119 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1120 /* first transmission, P = 0 */
1121 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1122 nr:=0, ns:=0, l3:=l3_mt)));
1123 deactivate(d);
1124
1125 alt {
1126 /* re-transmission, P = 1 */
1127 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1128 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1129 num_retrans := num_retrans + 1;
1130 if (num_retrans < n200) {
1131 repeat;
1132 } else if (num_retrans == n200) {
1133 T.start; /* wait for some more time if there are more retransmissions */
1134 repeat;
1135 } else {
1136 /* break */
1137 }
1138 }
1139 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
1140 setverdict(fail, "Received unexpected I frame");
1141 }
1142 [not is_sacch] as_lapdm_acch();
1143 [is_sacch] as_lapdm_dcch();
1144 [] as_lapdm_idle();
1145 [] as_rsl_meas_rep();
1146 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1147 /* break */
1148 }
1149 [] T.timeout {
1150 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1151 }
1152 }
1153
1154 if (num_retrans == n200) {
1155 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1156 } else if (num_retrans < n200) {
1157 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1158 " on channel ", g_chan_nr, " link ", link_id);
1159 }
1160
1161 fp_common_fini();
1162}
1163testcase TC_t200_n200() runs on test_CT {
1164 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1165 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1166}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001167
Harald Welte7d9f6db2019-06-02 23:14:04 +02001168/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1169 Inspired by TS 51.010-1 25.2.4.3 */
1170private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1171 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1172 var integer sapi := link_id.sapi;
1173 var boolean is_sacch := false;
1174 if (link_id.c == SACCH) {
1175 is_sacch := true;
1176 }
1177 timer T := 3.0;
1178 var default d;
1179
1180 fp_common_init();
1181
1182 /* some common altstep for meas res and other background noise */
1183 d := activate(as_ignore_background(true));
1184 RSL.clear;
1185 LAPDM.clear;
1186
1187 f_establish_mo(link_id);
1188
1189 var octetstring l3_mo := f_rnd_octstring(10);
1190 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1191 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1192 l3:=l3_mo)));
1193 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1194 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1195 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1196
1197 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1198 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1199 l3:=l3_mo)));
1200
1201 T.start;
1202 alt {
1203 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1204 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1205 setverdict(pass);
1206 }
1207 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1208 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1209 setverdict(pass);
1210 }
1211 [] T.timeout {
1212 setverdict(fail, "Timeout waiting for RR or REJ");
1213 }
1214 }
1215
1216 deactivate(d);
1217
1218 fp_common_fini();
1219}
1220testcase TC_rr_response_frame_loss() runs on test_CT {
1221 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1222 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1223}
1224
Harald Welte44479782019-06-02 23:23:45 +02001225/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1226private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1227 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1228 var integer sapi := link_id.sapi;
1229 var boolean is_sacch := false;
1230 if (link_id.c == SACCH) {
1231 is_sacch := true;
1232 }
1233 timer T := 3.0;
1234 var default d;
1235
1236 fp_common_init();
1237
1238 /* some common altstep for meas res and other background noise */
1239 d := activate(as_ignore_background(true));
1240 RSL.clear;
1241 LAPDM.clear;
1242
1243 f_establish_mo(link_id);
1244
1245 var octetstring l3_mo := f_rnd_octstring(10);
1246 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1247 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1248 l3:=l3_mo)));
1249 T.start;
1250 alt {
1251 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1252 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1253 }
1254 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1255 repeat;
1256 }
1257 /* ensure BTS still sends idle frames */
1258 [] as_lapdm_idle() {
1259 setverdict(pass, "still sending idle frames");
1260 }
1261 [] T.timeout {}
1262 }
1263
1264 /* Send RR command P=1 */
1265 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1266
1267 /* The BTS shall respond with a RR response, F bit set to 1. */
1268 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1269
1270 deactivate(d);
1271
1272 fp_common_fini();
1273}
1274testcase TC_incorrect_cr() runs on test_CT {
1275 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1276 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1277}
Harald Weltea39ac752019-06-04 21:46:07 +02001278
1279/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1280 Inspired by TS 51.010-1 25.2.5.2 */
1281private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1282 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1283 var integer sapi := link_id.sapi;
1284 var boolean is_sacch := false;
1285 if (link_id.c == SACCH) {
1286 is_sacch := true;
1287 }
1288 timer T := 3.0;
1289 var default d;
1290
1291 fp_common_init();
1292
1293 /* some common altstep for meas res and other background noise */
1294 d := activate(as_ignore_background(true));
1295 RSL.clear;
1296 LAPDM.clear;
1297
1298 f_establish_mo(link_id);
1299
1300 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1301 var octetstring l3_mo := '010203'O;
1302 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1303 l3:=l3_mo)));
1304 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1305 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1306 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1307 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1308 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1309 /* Expect RSL ERR IND */
1310 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1311 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1312 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1313 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1314 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1315 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1316 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1317
1318 deactivate(d);
1319
1320 fp_common_fini();
1321}
1322testcase TC_sabm_incorrect_c() runs on test_CT {
1323 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1324 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1325}
1326
Harald Welte72c81e72019-05-30 16:36:11 +02001327control {
Harald Welte72c81e72019-05-30 16:36:11 +02001328 execute(TC_sabm_ua_dcch_sapi0());
1329 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1330 execute(TC_sabm_ua_dcch_sapi3());
1331 execute(TC_sabm_ua_dcch_sapi4());
1332 execute(TC_sabm_contention());
1333 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001334 execute(TC_sabm_retransmit_bts());
1335 execute(TC_sabm_invalid_resp());
1336 execute(TC_sabm_dm());
1337 execute(TC_establish_ign_first_sabm());
1338 execute(TC_iframe_seq_and_ack());
1339 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001340 execute(TC_ns_seq_error());
1341 execute(TC_nr_seq_error());
1342 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001343 execute(TC_segm_concat_dcch());
1344 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001345 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001346 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001347 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001348 execute(TC_sabm_incorrect_c());
Harald Welte72c81e72019-05-30 16:36:11 +02001349}
1350
Harald Weltef6543322017-07-16 07:35:10 +02001351}