blob: ae87e6d345a599c27e881536fcf1806d393d9d3e [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}
74/* template for a valid SABM frame */
75template LapdmFrame LAPDm_B_SABM(template GsmSapi sapi, octetstring payload) := {
76 ab := {
77 addr := tr_LapdmAddr(sapi, false),
78 ctrl := tr_LapdmCtrlSABM(true),
79 len := lengthof(payload),
80 m := false,
81 el := 1,
82 payload := payload
Harald Weltec38611b2019-05-30 16:33:58 +020083 }
Harald Welte72c81e72019-05-30 16:36:11 +020084}
Harald Weltec38611b2019-05-30 16:33:58 +020085
Harald Welte72c81e72019-05-30 16:36:11 +020086/* template for a valid UA frame */
87template LapdmFrame tr_LAPDm_B_UA(template GsmSapi sapi, template octetstring payload) := {
88 ab := {
89 addr := tr_LapdmAddr(sapi, false),
90 ctrl := tr_LapdmCtrlUA(true),
91 len := ?,
92 m := false,
93 el := 1,
94 payload := payload
Harald Welte52c713c2017-07-16 15:44:44 +020095 }
Harald Welte72c81e72019-05-30 16:36:11 +020096}
Harald Welte52c713c2017-07-16 15:44:44 +020097
Harald Welte72c81e72019-05-30 16:36:11 +020098/* template for a valid UA frame */
99template LapdmFrame LAPDm_B_UA(template GsmSapi sapi, octetstring payload) := {
100 ab := {
101 addr := tr_LapdmAddr(sapi, false),
102 ctrl := tr_LapdmCtrlUA(true),
103 len := lengthof(payload),
104 m := false,
105 el := 1,
106 payload := payload
Harald Welte9e4725d2017-07-16 23:18:09 +0200107 }
Harald Welte72c81e72019-05-30 16:36:11 +0200108}
Harald Welte66110f02017-07-16 21:05:18 +0200109
Harald Welte72c81e72019-05-30 16:36:11 +0200110/* template for a valid UI frame */
111template LapdmFrame LAPDm_B_UI(template GsmSapi sapi, octetstring payload) := {
112 ab := {
113 addr := tr_LapdmAddr(sapi, true),
114 ctrl := tr_LapdmCtrlUI(false),
115 len := lengthof(payload),
116 m := false,
117 el := 1,
118 payload := payload
Harald Welte9e4725d2017-07-16 23:18:09 +0200119 }
Harald Welte72c81e72019-05-30 16:36:11 +0200120}
Harald Welte9e4725d2017-07-16 23:18:09 +0200121
Harald Welte72c81e72019-05-30 16:36:11 +0200122template LapdmFrame t_nopayload(template GsmSapi sapi) := {
123 ab := {
124 addr := tr_LapdmAddr(sapi, true),
125 ctrl := ?,
126 len := 0,
127 m := false,
128 el := 1,
129 payload := ''O
Harald Welted4ba7ff2017-07-17 21:00:48 +0200130 }
Harald Welte72c81e72019-05-30 16:36:11 +0200131}
132
133template LapdmFrame LAPDm_B_DISC(template GsmSapi sapi) modifies t_nopayload := {
134 ab := {
135 ctrl := tr_LapdmCtrlDISC(true)
136 }
137}
138
139template LapdmFrame LAPDm_B_RR(template GsmSapi sapi, template uint3_t nr) modifies t_nopayload := {
140 ab := {
141 ctrl := tr_LapdmCtrlRR(nr, false)
142 }
143}
144
145
146function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on lapdm_test_CT return boolean {
147 var LAPDm_ph_data phd;
148 var boolean result := false;
149 timer T := 5.0;
150
151 f_establish_dcch();
152 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload)));
153 log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload)));
154 T.start
155 alt {
156 [] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { result := true; }
157 [] LAPDM.receive(t_PH_DATA(?, use_sacch, ?)) -> value phd { log("Other msg on DCH: ", phd); repeat; }
158 [] LAPDM.receive(t_PH_DATA(?, ?, ?)) -> value phd { log("Other PH-DATA: ", phd); repeat; }
159 [] T.timeout { }
160 }
161 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_RR(sapi, 0)));
162 f_release_dcch();
163 return result;
164}
165
166testcase TC_sabm_ua_dcch_sapi0() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200167 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200168 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
169 setverdict(fail);
170 }
171 setverdict(pass);
172}
173
174testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200175 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200176 if (f_test_sabm_results_in_ua(0, false, ''O)) {
177 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
178 }
179 setverdict(pass);
180}
181
182testcase TC_sabm_ua_dcch_sapi3() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200183 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200184 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
185 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
186 }
187 setverdict(pass);
188}
189
190testcase TC_sabm_ua_dcch_sapi4() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200191 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200192 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
193 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
194 }
195 setverdict(pass);
196}
197
198testcase TC_sabm_contention() runs on lapdm_test_CT {
199 var LAPDm_ph_data phd;
200 const octetstring payload := '0102030405'O;
201 const GsmSapi sapi := 0;
202 const boolean use_sacch := false;
203 timer T := 5.0;
204
Harald Welte61332c02019-05-30 16:45:15 +0200205 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200206
207 f_establish_dcch();
208 /* first frame is our real SABM */
209 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload)));
210 /* second frame is a SABM with different payload, which BTS has to ignore according to 8.4.1.4 */
211 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, 'ABCDEF'O)));
212 log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload)));
213 T.start
214 alt {
215 [] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { setverdict(pass); repeat; }
216 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_B_UA(sapi, ?))) {
217 setverdict(fail, "Second SABM was responded to during contention resolution");
Harald Welted4ba7ff2017-07-17 21:00:48 +0200218 }
Harald Welte72c81e72019-05-30 16:36:11 +0200219 [] LAPDM.receive { repeat };
220 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200221 }
Harald Welte72c81e72019-05-30 16:36:11 +0200222 f_release_dcch();
223}
Harald Welte9e4725d2017-07-16 23:18:09 +0200224
Harald Welte72c81e72019-05-30 16:36:11 +0200225/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
226 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
227testcase TC_sabm_retransmit() runs on lapdm_test_CT {
228 const octetstring payload := '00FEFEDEADBEEF'O;
Harald Welte61332c02019-05-30 16:45:15 +0200229 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200230 if (not f_test_sabm_results_in_ua(0, false, payload)) {
231 setverdict(fail, "UA not received for first SABM");
Harald Welte599faa12017-07-17 21:49:24 +0200232 }
Harald Welte72c81e72019-05-30 16:36:11 +0200233 if (not f_test_sabm_results_in_ua(0, false, payload)) {
234 setverdict(fail, "UA not received for second SABM");
Harald Welted4ba7ff2017-07-17 21:00:48 +0200235 }
Harald Welte72c81e72019-05-30 16:36:11 +0200236 setverdict(pass);
237}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200238
Harald Welte72c81e72019-05-30 16:36:11 +0200239testcase TC_foo() runs on lapdm_test_CT {
240 var LapdmFrame lf;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200241/*
Harald Welte72c81e72019-05-30 16:36:11 +0200242 var LapdmFrame lf := valueof(LAPDm_B_UA(0, ''O));
243 log("ENC UA: ", enc_LapdmFrame(lf));
244 lf := valueof(LAPDm_B_UI(0, ''O));
245 log("ENC UI B: ", enc_LapdmFrame(lf));
246 log("ENC UI B: ", enc_LapdmFrameB(lf.b));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200247
Harald Welte72c81e72019-05-30 16:36:11 +0200248 log("DEC UI AF: ", dec_LapdmAddressField('03'O));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200249*/
Harald Welteffcad682017-07-30 22:51:04 +0200250
Harald Welte72c81e72019-05-30 16:36:11 +0200251 lf := valueof(LAPDm_B_RR(0, 0));
252 log("ENC RR: ", enc_LapdmFrame(lf));
Harald Welteffcad682017-07-30 22:51:04 +0200253
Harald Welte72c81e72019-05-30 16:36:11 +0200254 lf := valueof(LAPDm_B_UA(0, ''O));
255 log("ENC UA: ", enc_LapdmFrame(lf));
Harald Welteffcad682017-07-30 22:51:04 +0200256
Harald Welte72c81e72019-05-30 16:36:11 +0200257 lf := valueof(LAPDm_B_UI(0, ''O));
258 log("ENC UI: ", enc_LapdmFrame(lf));
Harald Welteffcad682017-07-30 22:51:04 +0200259
Harald Welte72c81e72019-05-30 16:36:11 +0200260 log("DEC UI CU: ", dec_LapdmCtrlU('03'O));
261 log("DEC UI CT: ", dec_LapdmCtrl('03'O));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200262
Harald Welte72c81e72019-05-30 16:36:11 +0200263 log("DEC UA: ", dec_LapdmFrameAB('017301'O));
264 log("DEC UI: ", dec_LapdmFrameAB('030301'O));
265 log("DEC I: ", dec_LapdmFrameAB('030001'O));
266 log("DEC S: ", dec_LapdmFrameAB('030101'O));
267 log("DEC: ", dec_LapdmFrameAB('030301'O));
268 log("DEC: ", dec_LapdmFrameAB('0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O));
269}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200270
Harald Welte2f2b2b72019-05-31 22:24:57 +0200271/*********************************************************************************
272 * Test using both L1CTL/LAPDm and RSL
273 *********************************************************************************/
274
275private function fp_common_init() runs on ConnHdlr
276{
277 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
278 unmap(self:L1CTL, system:L1CTL);
279 f_lapdm_init();
280 /* activate the channel on the BTS side */
281 f_rsl_chan_act(g_pars.chan_mode, false, {});
282 /* activate the channel on the MS side */
283 f_switch_dcch({false, mp_trx0_arfcn}, g_chan_nr, 7);
284}
285
286private function fp_common_fini() runs on ConnHdlr
287{
288 f_release_dcch();
289 f_rsl_chan_deact();
290 f_lapdm_exit();
291}
292
Harald Welte76771f12019-06-02 22:58:58 +0200293/* Mobile-Originated LAPDm establishment on given Link ID */
294private function f_establish_mo(RslLinkId link_id) runs on ConnHdlr
295{
296 var integer sapi := link_id.sapi;
297 var boolean is_sacch := false;
298 if (link_id.c == SACCH) {
299 is_sacch := true;
300 }
301
302 var octetstring l3_mo := f_rnd_octstring(5);
303
304 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
305 if (is_sacch) {
306 /* no payload permitted, as this is not contention resolution */
307 l3_mo := ''O;
308 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
309 RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
310 } else {
311 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
312 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
313 }
314 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
315 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
316}
317
Harald Welte2f2b2b72019-05-31 22:24:57 +0200318/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
319 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
320private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
321 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
322 fp_common_init();
323
324 LAPDM.clear;
325 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
326
327 timer T := 8.0;
328 var integer sabm_received := 0;
329 T.start;
330 alt {
331 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
332 sabm_received := sabm_received + 1;
333 repeat;
334 }
335 [] LAPDM.receive { repeat; }
336 [] T.timeout { }
337 }
338 if (sabm_received == 0) {
339 setverdict(fail, "No SABM observed at all!");
340 } else if (sabm_received != 6) {
341 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
342 sabm_received);
343 } else {
344 setverdict(pass, "Received ", sabm_received, " SABM");
345 }
346
347 fp_common_fini();
348}
349testcase TC_sabm_retransmit_bts() runs on test_CT {
350 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
351 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
352}
353
354
355type record LapdmNamedFrame {
356 charstring name,
357 LapdmFrame lapdm
358};
359
360/* Test that the BTS will ignore receipt of frames other than a UA when
361 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
362 * Section 25.2.1.1.2.3 */
363private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
364 var integer sapi := err_frame.lapdm.ab.addr.sapi;
365 fp_common_init();
366
367 /* Establish Request via RSL; Expect SABM on LAPDm side */
368 LAPDM.clear;
369 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
370 alt {
371 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
372 [] LAPDM.receive { repeat; }
373 }
374
375 /* send erroneous response to SABM */
376 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
377
378 /* expect a SABM retransmission of the BTS */
379 timer T := 3.0;
380 T.start;
381 alt {
382 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
383 setverdict(pass);
384 }
385 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
386 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
387 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
388 err_frame.name);
389 }
390 [] LAPDM.receive { repeat; }
391 [] T.timeout {
392 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
393 err_frame.name);
394 }
395 }
396
397 fp_common_fini();
398}
399private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
400 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
401 var LapdmNamedFrame err_frame[3] := {
402 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
403 l3 := '01020304'O)) },
404 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
405 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
406 };
407 var integer i;
408
409 for (i := 0; i < lengthof(err_frame); i := i+1) {
410 f_TC_sabm_invalid_resp2(id, err_frame[i])
411 }
412}
413testcase TC_sabm_invalid_resp() runs on test_CT {
414 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
415 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
416}
417
418/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
419 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
420private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
421 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
422 fp_common_init();
423
424 /* Establish Request via RSL; Expect SABM on LAPDm side */
425 LAPDM.clear;
426 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
427 alt {
428 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
429 [] LAPDM.receive { repeat; }
430 }
431
432 /* send DM response to SABM */
433 RSL.clear;
434 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
435 alt {
436 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
437 [] RSL.receive { repeat; }
438 }
439
440 /* expect no SABM retransmission of the BTS */
441 timer T := 3.0;
442 T.start;
443 alt {
444 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
445 setverdict(fail, "Received unexpected SABM retransmission");
446 }
447 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
448 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
449 setverdict(fail, "Received unexpected LAPDm frame");
450 }
451 [] LAPDM.receive { repeat; }
452 [] T.timeout {
453 setverdict(pass);
454 }
455 }
456
457 fp_common_fini();
458}
459testcase TC_sabm_dm() runs on test_CT {
460 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
461 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
462}
463
464/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
465 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
466 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
467private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
468 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
469 var integer num_sabm := 0;
470 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
471 timer T := 3.0;
472
473 fp_common_init();
474
475 /* Establish Request via RSL */
476 LAPDM.clear;
477 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
478 /* Expect two SABM (retransmit) */
479 T.start;
480 alt {
481 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
482 num_sabm := num_sabm + 1;
483 if (num_sabm < 2) {
484 repeat;
485 }
486 }
487 [] LAPDM.receive { repeat; }
488 }
489
490 /* send UA response to SABM */
491 RSL.clear;
492 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
493 alt {
494 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
495 [] RSL.receive { repeat; }
496 }
497
498 /* Send I frame from BTS to MS */
499 var octetstring l3 := f_rnd_octstring(10);
500 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
501 alt {
502 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
503 nr:=0, ns:=0, l3:=l3)));
504 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
505 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
506 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
507 }
508 /* Send RR frame in response */
509 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
510
511 /* expect idle UI Frame from BTS */
512 alt {
513 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
514 setverdict(pass);
515 }
516 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
517 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
518 }
519
520 fp_common_fini();
521}
522testcase TC_establish_ign_first_sabm() runs on test_CT {
523 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
524 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
525}
526
527/* ignore all SACCH frames */
528private altstep as_lapdm_acch() runs on ConnHdlr {
529 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
530}
Harald Welteef6fd442019-06-01 21:41:29 +0200531/* ignore all DCCH frames */
532private altstep as_lapdm_dcch() runs on ConnHdlr {
533 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
534}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200535/* ignore all LAPDm idle frames (UI) */
536private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200537 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200538}
539/* ignore all measurement reports */
540private altstep as_rsl_meas_rep() runs on ConnHdlr {
541 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
542}
543/* fail if we receive an RSL ERROR IND */
544private altstep as_rsl_fail_err() runs on ConnHdlr {
545 var RSL_Message rx_rsl;
546 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
547 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
548 }
549}
550/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200551private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200552 [want_dcch] as_lapdm_acch();
553 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200554 [] as_lapdm_idle();
555 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200556 [not ignore_rsl_errors] as_rsl_fail_err();
557 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200558}
559
560/* Test the operation of Layer 2 sequence numbering.
561 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
562private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
563 const integer sapi := 0;
564 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
565 var octetstring l3 := f_rnd_octstring(18);
566 var default d;
567 timer T := 3.0;
568
569 fp_common_init();
570
571 /* some common altstep for meas res and other background noise */
572 d := activate(as_ignore_background());
573 RSL.clear;
574 LAPDM.clear;
575
Harald Welte76771f12019-06-02 22:58:58 +0200576 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200577
578 var integer last_ns_rx := 0;
579
580 for (var integer i := 0; i < 10; i := i+1) {
581 var octetstring l3_mo := f_rnd_octstring(12);
582 var octetstring l3_mt := f_rnd_octstring(12);
583 var LAPDm_ph_data pd;
584
585 log("Starting iteration ", i);
586 /* MT I frame */
587 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
588 alt {
589 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
590 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
591 nr:=i mod 8))) {
592 log("Ignoring RR in iteration ", i);
593 repeat;
594 }
595 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
596 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
597 nr:=i mod 8, ns:=i mod 8,
598 l3:=l3_mt))) -> value pd {
599 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
600 }
601 }
602 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
603 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
604 nr:=(last_ns_rx+1)mod 8,
605 ns:=i mod 8, l3 := l3_mo)));
606 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
607 }
608 log("Completed iteration");
609
610 deactivate(d);
611 fp_common_fini();
612}
613testcase TC_iframe_seq_and_ack() runs on test_CT {
614 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
615 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
616}
617
618/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
619 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
620
621/*
622 1) The BTS is brought into the multiple frame established state
623 2) The MS sends an L3 Request asking for IMEI to the MS.
624 3) The BTS shall respond with a RR frame though this may be incorporated with
625 the L3 Response I frame. The MS does not respond to the I frame.
626 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
627 with the P bit set to 1.
628 5) The MS then sends a valid L3 Request I frame asking for IMEI which
629 does not acknowledge receipt of the I frame from the BTS.
630On the FACCH the BTS may send an RR frame acknowledging the I frame.
631 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
632 the second I frame from the MS.
633 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
634 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
635*/
636private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
637 const integer sapi := 0;
638 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
639 var default d;
640 timer T := 3.0;
641
642 fp_common_init();
643
644 /* some common altstep for meas res and other background noise */
645 d := activate(as_ignore_background());
646 RSL.clear;
647 LAPDM.clear;
648
649 var octetstring l3_mo := f_rnd_octstring(12);
650 var octetstring l3_mt := f_rnd_octstring(12);
651
652 /* 1) The BTS is brought into the multiple frame established state */
653
654 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
655 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
656 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
657 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
658 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
659
660 /* 2) The MS sends an L3 Request to the BTS */
661 l3_mo := f_rnd_octstring(18);
662 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
663 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
664 nr:=0, ns:=0, l3:=l3_mo)));
665 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
666 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
667 the L3 Response I frame. The MS does not respond to the I frame. */
668 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
669 alt {
670 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
671 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
672 repeat;
673 }
674 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
675 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
676 nr:=1, ns:=0, l3:=l3_mt)));
677 }
678
679 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
680 with the P bit set to 1. */
681 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
682 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
683 nr:=1, ns:=0, l3:=l3_mt)));
684
685 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
686 does not acknowledge receipt of the I frame from the BTS. */
687 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
688 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
689 nr:=0, ns:=1, l3 := l3_mo)));
690 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
691 alt {
692 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
693 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
694 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
695 repeat;
696 }
697 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
698 receipt of the second I frame from the MS. */
699 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
700 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
701 nr:=2, ns:=0, l3:=l3_mt)));
702 }
703
704 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
705 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
706 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
707
708 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
709 l3_mt := f_rnd_octstring(16);
710 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
711 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
712 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
713 nr:=2, ns:=1, l3:=l3_mt)));
714 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
715
716 deactivate(d);
717 fp_common_fini();
718}
719testcase TC_iframe_timer_recovery() runs on test_CT {
720 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
721 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
722}
723
Eric Wild211acc32019-06-11 19:06:38 +0200724/* 25.2.6.1 ns sequence error
725sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
726private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
727 const integer sapi := 0;
728 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
729 var default d;
730 timer T := 3.0;
731
732 fp_common_init();
733
734 /* some common altstep for meas res and other background noise */
735 d := activate(as_ignore_background(ignore_rsl_errors := true));
736 RSL.clear;
737 LAPDM.clear;
738
739 var octetstring l3_mo := f_rnd_octstring(12);
740 var octetstring l3_mt := f_rnd_octstring(12);
741
742 /* 1) The BTS is brought into the multiple frame established state */
743
744 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
745 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
746 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
747 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
748 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
749
750 /* 2) The MS sends an L3 Request to the BTS */
751 l3_mo := f_rnd_octstring(18);
752 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
753 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
754 nr:=0, ns:=0, l3:=l3_mo)));
755 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
756 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
757 the L3 Response I frame. */
758 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
759 alt {
760 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
761 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
762 repeat;
763 }
764 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
765 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
766 nr:=1, ns:=0, l3:=l3_mt)));
767 }
768
769 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
770 but correctly acknowledging the MS's I frame; P bit set to zero. */
771 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
772 nr:=1, ns:=0, l3:=l3_mo)));
773
774 /* no rsl data ind due to wrong ns */
775
776 /* The BTS shall send a REJ frame. */
777 timer T1 := 2.0;
778 T1.start;
779 alt{
780 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
781 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
782 }
783
784 f_sleep(2.0); // T200
785
786 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
787 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
788 nr:=1, ns:=0, l3:=l3_mo)));
789
790 /* The BTS shall respond with a REJ, F bit set to 1. */
791 T1.start;
792 alt{
793 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
794 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
795 }
796
797 deactivate(d);
798 fp_common_fini();
799 setverdict(pass);
800}
801
802testcase TC_ns_seq_error() runs on test_CT {
803 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
804 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
805}
806
807/* 25.2.6.2 nr sequence error */
808private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
809 const integer sapi := 0;
810 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
811 var default d;
812 var integer n201 := 20;
813 if (link_id.c == SACCH) {
814 n201 := 18;
815 }
816
817 fp_common_init();
818
819 /* some common altstep for meas res and other background noise */
820 d := activate(as_ignore_background(ignore_rsl_errors := true));
821 RSL.clear;
822 LAPDM.clear;
823
824 var octetstring l3_mo := f_rnd_octstring(12);
825 var octetstring l3_mt := f_rnd_octstring(12);
826
827 /* 1) The BTS is brought into the multiple frame established state */
828
829 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
830 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
831 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
832 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
833 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
834
835 /* 2) The MS shall send an I frame containing an information field of length N201 and an
836 incorrect receive sequence number. */
837 l3_mo := f_rnd_octstring(n201);
838 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
839 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
840 nr:=1, ns:=0, l3:=l3_mo)));
841
842 /* The BTS may: a) send a DISC frame within N200×T200; */
843 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
844 timer T1 := 2.0;
845 T1.start;
846 alt{
847 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
848 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
849 }
850
851 /* a) the MS shall respond with a UA frame.
852 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
853 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
854
855 deactivate(d);
856 fp_common_fini();
857 setverdict(pass);
858}
859
860testcase TC_nr_seq_error() runs on test_CT {
861 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
862 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
863}
864
865private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x) runs on ConnHdlr {
866 LAPDM.send(t_PH_DATA(0, false, x));
867 f_sleep(2.0); // T200
868 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
869 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0)));
870}
871
872/* 25.2.7 Test on receipt of invalid frames
873sends a bunch of different invalid frames, expects the BTS to ignore all of them */
874private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
875 const integer sapi := 0;
876 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
877 var default d;
878 timer T := 3.0;
879
880 fp_common_init();
881
882 /* some common altstep for meas res and other background noise */
883 d := activate(as_ignore_background(ignore_rsl_errors := true));
884 RSL.clear;
885 LAPDM.clear;
886
887 var octetstring l3_mo := f_rnd_octstring(12);
888 var octetstring l3_mt := f_rnd_octstring(12);
889
890 /* 1) The BTS is brought into the multiple frame established state */
891
892 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
893 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
894 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
895 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
896 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
897
898
899 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
900 RR frame with the Length indicator greater than zero and a faulty N(R); */
901 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
902 x.ab.payload := f_rnd_octstring(5);
903 f_TC_rec_invalid_frame_txrx(0, x);
904 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
905 EJ frame with the EA bit set to zero and a faulty N(R); */
906 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
907 x.ab.addr.ea := false;
908 f_TC_rec_invalid_frame_txrx(0, x);
909 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
910 SABM frame with the EL bit set to zero; */
911 l3_mo := ''O;
912 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
913 x.ab.el := 0;
914 f_TC_rec_invalid_frame_txrx(0, x);
915 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
916 DM frame with the Length indicator greater than zero;*/
917 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
918 x.ab.payload := f_rnd_octstring(5);
919 f_TC_rec_invalid_frame_txrx(0, x);
920 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
921 DISC frame with the M bit set to 1; */
922 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
923 x.ab.m := true;
924 f_TC_rec_invalid_frame_txrx(0, x);
925 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
926 UA frame with the EA bit set to zero*/
927 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
928 x.ab.addr.ea := false;
929 f_TC_rec_invalid_frame_txrx(0, x);
930 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
931 I frame with the Length indicator greater than N201;*/
932 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 6, l3 := f_rnd_octstring(25)))
933 f_TC_rec_invalid_frame_txrx(0, x);
934 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
935 I frame with the M bit set to 1 and the Length indicator less than N201;*/
936 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
937 x.ab.m := true;
938 f_TC_rec_invalid_frame_txrx(0, x);
939 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
940 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
941 f_TC_rec_invalid_frame_txrx(0, x);
942
943 /* command frames with correct Address and Length indicator field and a non-implemented control field */
944 /* 12: One command frame with Control Field = xxx1 1101. */
945 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
946 x.ab.ctrl.other := bit2int('00011101'B);
947 f_TC_rec_invalid_frame_txrx(0, x);
948 /* 13: One command frame with Control field = xxx1 1011. */
949 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
950 x.ab.ctrl.other := bit2int('00011011'B);
951 f_TC_rec_invalid_frame_txrx(0, x);
952 /* 14: One command frame with Control field = xxx1 0111. */
953 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
954 x.ab.ctrl.other := bit2int('00010001'B);
955 f_TC_rec_invalid_frame_txrx(0, x);
956 /* 15: One command frame with Control field = 01x1 1111. */
957 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
958 x.ab.ctrl.other := bit2int('01011111'B);
959 f_TC_rec_invalid_frame_txrx(0, x);
960 /* 16: One command frame with Control field = 1xx1 1111. */
961 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
962 x.ab.ctrl.other := bit2int('10011111'B);
963 f_TC_rec_invalid_frame_txrx(0, x);
964 /* 17: One command frame with Control field = 0011 0011. */
965 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
966 x.ab.ctrl.other := bit2int('00110011'B);
967 f_TC_rec_invalid_frame_txrx(0, x);
968 /* 18: One command frame with Control field = 1xx1 0011. */
969 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
970 x.ab.ctrl.other := bit2int('10010011'B);
971 f_TC_rec_invalid_frame_txrx(0, x);
972
973 deactivate(d);
974 fp_common_fini();
975 setverdict(pass);
976}
977
978testcase TC_rec_invalid_frame() runs on test_CT {
979 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
980 pars.t_guard := 60.0;
981 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
982}
983
Harald Welte9ea918c2019-06-01 11:46:25 +0200984type record LapdmDlConfig {
985 integer n201,
986 integer t200
987};
988
989type record LapdmDlState {
990 integer v_s,
991 integer v_a,
992 integer v_r
993};
994
995template (value) LapdmDlState t_init_LapdmDlState := {
996 v_s := 0,
997 v_a := 0,
998 v_r := 0
999}
1000
1001private function inc_mod8(inout integer v)
1002{
1003 v := (v + 1) mod 8;
1004}
1005
1006private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
1007runs on ConnHdlr {
1008 var LAPDm_ph_data pd;
1009 var integer offset := 0;
1010 var integer n201 := 20;
1011 var boolean is_sacch := false;
1012 if (link_id.c == SACCH) {
1013 n201 := 18;
1014 is_sacch := true;
1015 }
1016
1017 while (offset < lengthof(l3)) {
1018 var integer remain_len := lengthof(l3) - offset;
1019 var integer seg_len := remain_len;
1020 if (remain_len > n201) {
1021 seg_len := n201;
1022 }
1023 var octetstring segment := substr(l3, offset, seg_len);
1024 var boolean more;
1025 if (offset + lengthof(segment) < lengthof(l3)) {
1026 more := true;
1027 } else {
1028 more := false;
1029 }
1030 /* send the next segment */
1031 LAPDM.send(t_PH_DATA(0, is_sacch,
1032 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1033 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1034 inc_mod8(dls.v_s);
1035 offset := offset + lengthof(segment);
1036
1037 /* wait for it to be acknowledged */
1038 alt {
1039 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1040 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001041 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001042 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
1043 setverdict(fail, "received unexpected LAPDm ", pd);
1044 repeat;
1045 }
1046 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1047 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1048 setverdict(fail, "received RSL DATA IND before message complete");
1049 }
1050 }
1051 }
1052
1053 timer T := 1.0;
1054 T.start;
1055 alt {
1056 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1057 setverdict(pass);
1058 }
1059 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1060 setverdict(fail, "Received RSL DATA IND with wrong payload");
1061 }
1062 [] T.timeout {
1063 setverdict(fail, "Timeout waiting for RSL DATA IND of de-segmented message");
1064 }
1065 }
1066}
1067
1068/* Section 5.8.5 of TS 04.06 */
1069const integer c_TS0406_MAX_L3_OCTETS := 251;
1070
Harald Welteef6fd442019-06-01 21:41:29 +02001071/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1072 * on specified SAPI/channel */
1073private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1074 var integer sapi := link_id.sapi;
1075 var boolean is_sacch := false;
1076 if (link_id.c == SACCH) {
1077 is_sacch := true;
1078 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001079 var default d;
1080 timer T := 3.0;
1081
1082 fp_common_init();
1083
1084 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001085 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001086 RSL.clear;
1087 LAPDM.clear;
1088
Harald Welte76771f12019-06-02 22:58:58 +02001089 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001090
Harald Welte76771f12019-06-02 22:58:58 +02001091 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001092
1093 deactivate(d);
1094
1095 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1096 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1097
1098 fp_common_fini();
1099}
Harald Welteef6fd442019-06-01 21:41:29 +02001100private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1101 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001102}
Harald Welteef6fd442019-06-01 21:41:29 +02001103private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1104 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1105}
1106/* test mobile-originated segmentation/de-segmentation on DCCH */
1107testcase TC_segm_concat_dcch() runs on test_CT {
1108 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1109 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1110}
1111/* test mobile-originated segmentation/de-segmentation on SACCH */
1112testcase TC_segm_concat_sacch() runs on test_CT {
1113 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1114 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1115}
1116
Harald Welteb2a30342019-06-02 22:13:50 +02001117/* TS 04.06 Section 5.8.2.1 */
1118private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1119 /* SACCH irrespective of physical channel type */
1120 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1121 return 5;
1122 }
1123 /* DCCH below */
1124 select (chan_nr) {
1125 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1126 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1127 case (t_RslChanNr_Bm(?)) { return 34; }
1128 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1129 }
1130 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1131 return -1;
1132}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001133
Harald Welteb2a30342019-06-02 22:13:50 +02001134/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1135private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
1136 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1137 var integer sapi := link_id.sapi;
1138 var boolean is_sacch := false;
1139 if (link_id.c == SACCH) {
1140 is_sacch := true;
1141 }
1142 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1143 var integer num_retrans := 0;
1144 timer T := 3.0;
1145 var default d;
1146
1147 fp_common_init();
1148
1149 /* some common altstep for meas res and other background noise */
1150 d := activate(as_ignore_background(true));
1151 RSL.clear;
1152 LAPDM.clear;
1153
Harald Welte76771f12019-06-02 22:58:58 +02001154 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001155
1156 var octetstring l3_mt := f_rnd_octstring(20);
1157 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1158 /* first transmission, P = 0 */
1159 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1160 nr:=0, ns:=0, l3:=l3_mt)));
1161 deactivate(d);
1162
1163 alt {
1164 /* re-transmission, P = 1 */
1165 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1166 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1167 num_retrans := num_retrans + 1;
1168 if (num_retrans < n200) {
1169 repeat;
1170 } else if (num_retrans == n200) {
1171 T.start; /* wait for some more time if there are more retransmissions */
1172 repeat;
1173 } else {
1174 /* break */
1175 }
1176 }
1177 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
1178 setverdict(fail, "Received unexpected I frame");
1179 }
1180 [not is_sacch] as_lapdm_acch();
1181 [is_sacch] as_lapdm_dcch();
1182 [] as_lapdm_idle();
1183 [] as_rsl_meas_rep();
1184 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1185 /* break */
1186 }
1187 [] T.timeout {
1188 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1189 }
1190 }
1191
1192 if (num_retrans == n200) {
1193 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1194 } else if (num_retrans < n200) {
1195 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1196 " on channel ", g_chan_nr, " link ", link_id);
1197 }
1198
1199 fp_common_fini();
1200}
1201testcase TC_t200_n200() runs on test_CT {
1202 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1203 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1204}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001205
Harald Welte7d9f6db2019-06-02 23:14:04 +02001206/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1207 Inspired by TS 51.010-1 25.2.4.3 */
1208private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1209 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1210 var integer sapi := link_id.sapi;
1211 var boolean is_sacch := false;
1212 if (link_id.c == SACCH) {
1213 is_sacch := true;
1214 }
1215 timer T := 3.0;
1216 var default d;
1217
1218 fp_common_init();
1219
1220 /* some common altstep for meas res and other background noise */
1221 d := activate(as_ignore_background(true));
1222 RSL.clear;
1223 LAPDM.clear;
1224
1225 f_establish_mo(link_id);
1226
1227 var octetstring l3_mo := f_rnd_octstring(10);
1228 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1229 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1230 l3:=l3_mo)));
1231 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1232 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1233 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1234
1235 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1236 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1237 l3:=l3_mo)));
1238
1239 T.start;
1240 alt {
1241 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1242 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1243 setverdict(pass);
1244 }
1245 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1246 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1247 setverdict(pass);
1248 }
1249 [] T.timeout {
1250 setverdict(fail, "Timeout waiting for RR or REJ");
1251 }
1252 }
1253
1254 deactivate(d);
1255
1256 fp_common_fini();
1257}
1258testcase TC_rr_response_frame_loss() runs on test_CT {
1259 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1260 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1261}
1262
Harald Welte44479782019-06-02 23:23:45 +02001263/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1264private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1265 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1266 var integer sapi := link_id.sapi;
1267 var boolean is_sacch := false;
1268 if (link_id.c == SACCH) {
1269 is_sacch := true;
1270 }
1271 timer T := 3.0;
1272 var default d;
1273
1274 fp_common_init();
1275
1276 /* some common altstep for meas res and other background noise */
1277 d := activate(as_ignore_background(true));
1278 RSL.clear;
1279 LAPDM.clear;
1280
1281 f_establish_mo(link_id);
1282
1283 var octetstring l3_mo := f_rnd_octstring(10);
1284 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1285 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1286 l3:=l3_mo)));
1287 T.start;
1288 alt {
1289 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1290 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1291 }
1292 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1293 repeat;
1294 }
1295 /* ensure BTS still sends idle frames */
1296 [] as_lapdm_idle() {
1297 setverdict(pass, "still sending idle frames");
1298 }
1299 [] T.timeout {}
1300 }
1301
1302 /* Send RR command P=1 */
1303 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1304
1305 /* The BTS shall respond with a RR response, F bit set to 1. */
1306 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1307
1308 deactivate(d);
1309
1310 fp_common_fini();
1311}
1312testcase TC_incorrect_cr() runs on test_CT {
1313 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1314 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1315}
Harald Weltea39ac752019-06-04 21:46:07 +02001316
1317/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1318 Inspired by TS 51.010-1 25.2.5.2 */
1319private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1320 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1321 var integer sapi := link_id.sapi;
1322 var boolean is_sacch := false;
1323 if (link_id.c == SACCH) {
1324 is_sacch := true;
1325 }
1326 timer T := 3.0;
1327 var default d;
1328
1329 fp_common_init();
1330
1331 /* some common altstep for meas res and other background noise */
1332 d := activate(as_ignore_background(true));
1333 RSL.clear;
1334 LAPDM.clear;
1335
1336 f_establish_mo(link_id);
1337
1338 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1339 var octetstring l3_mo := '010203'O;
1340 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1341 l3:=l3_mo)));
1342 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1343 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1344 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1345 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1346 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1347 /* Expect RSL ERR IND */
1348 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1349 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1350 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1351 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1352 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1353 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1354 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1355
1356 deactivate(d);
1357
1358 fp_common_fini();
1359}
1360testcase TC_sabm_incorrect_c() runs on test_CT {
1361 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1362 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1363}
1364
Harald Welte72c81e72019-05-30 16:36:11 +02001365control {
1366 execute(TC_foo());
1367 execute(TC_sabm_ua_dcch_sapi0());
1368 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1369 execute(TC_sabm_ua_dcch_sapi3());
1370 execute(TC_sabm_ua_dcch_sapi4());
1371 execute(TC_sabm_contention());
1372 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001373 execute(TC_sabm_retransmit_bts());
1374 execute(TC_sabm_invalid_resp());
1375 execute(TC_sabm_dm());
1376 execute(TC_establish_ign_first_sabm());
1377 execute(TC_iframe_seq_and_ack());
1378 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001379 execute(TC_ns_seq_error());
1380 execute(TC_nr_seq_error());
1381 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001382 execute(TC_segm_concat_dcch());
1383 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001384 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001385 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001386 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001387 execute(TC_sabm_incorrect_c());
Harald Welte72c81e72019-05-30 16:36:11 +02001388}
1389
Harald Weltef6543322017-07-16 07:35:10 +02001390}