blob: 12f24ebaa359f39f025444fa4fa0e16a14cdcb1c [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 */
Harald Welteef6fd442019-06-01 21:41:29 +0200551private altstep as_ignore_background(boolean want_dcch := true) runs on ConnHdlr {
552 [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();
556 [] as_rsl_fail_err();
557}
558
559/* Test the operation of Layer 2 sequence numbering.
560 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
561private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
562 const integer sapi := 0;
563 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
564 var octetstring l3 := f_rnd_octstring(18);
565 var default d;
566 timer T := 3.0;
567
568 fp_common_init();
569
570 /* some common altstep for meas res and other background noise */
571 d := activate(as_ignore_background());
572 RSL.clear;
573 LAPDM.clear;
574
Harald Welte76771f12019-06-02 22:58:58 +0200575 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200576
577 var integer last_ns_rx := 0;
578
579 for (var integer i := 0; i < 10; i := i+1) {
580 var octetstring l3_mo := f_rnd_octstring(12);
581 var octetstring l3_mt := f_rnd_octstring(12);
582 var LAPDm_ph_data pd;
583
584 log("Starting iteration ", i);
585 /* MT I frame */
586 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
587 alt {
588 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
589 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
590 nr:=i mod 8))) {
591 log("Ignoring RR in iteration ", i);
592 repeat;
593 }
594 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
595 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
596 nr:=i mod 8, ns:=i mod 8,
597 l3:=l3_mt))) -> value pd {
598 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
599 }
600 }
601 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
602 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
603 nr:=(last_ns_rx+1)mod 8,
604 ns:=i mod 8, l3 := l3_mo)));
605 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
606 }
607 log("Completed iteration");
608
609 deactivate(d);
610 fp_common_fini();
611}
612testcase TC_iframe_seq_and_ack() runs on test_CT {
613 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
614 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
615}
616
617/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
618 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
619
620/*
621 1) The BTS is brought into the multiple frame established state
622 2) The MS sends an L3 Request asking for IMEI to the MS.
623 3) The BTS shall respond with a RR frame though this may be incorporated with
624 the L3 Response I frame. The MS does not respond to the I frame.
625 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
626 with the P bit set to 1.
627 5) The MS then sends a valid L3 Request I frame asking for IMEI which
628 does not acknowledge receipt of the I frame from the BTS.
629On the FACCH the BTS may send an RR frame acknowledging the I frame.
630 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
631 the second I frame from the MS.
632 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
633 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
634*/
635private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
636 const integer sapi := 0;
637 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
638 var default d;
639 timer T := 3.0;
640
641 fp_common_init();
642
643 /* some common altstep for meas res and other background noise */
644 d := activate(as_ignore_background());
645 RSL.clear;
646 LAPDM.clear;
647
648 var octetstring l3_mo := f_rnd_octstring(12);
649 var octetstring l3_mt := f_rnd_octstring(12);
650
651 /* 1) The BTS is brought into the multiple frame established state */
652
653 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
654 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
655 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
656 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
657 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
658
659 /* 2) The MS sends an L3 Request to the BTS */
660 l3_mo := f_rnd_octstring(18);
661 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
662 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
663 nr:=0, ns:=0, l3:=l3_mo)));
664 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
665 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
666 the L3 Response I frame. The MS does not respond to the I frame. */
667 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
668 alt {
669 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
670 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
671 repeat;
672 }
673 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
674 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
675 nr:=1, ns:=0, l3:=l3_mt)));
676 }
677
678 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
679 with the P bit set to 1. */
680 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
681 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
682 nr:=1, ns:=0, l3:=l3_mt)));
683
684 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
685 does not acknowledge receipt of the I frame from the BTS. */
686 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
687 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
688 nr:=0, ns:=1, l3 := l3_mo)));
689 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
690 alt {
691 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
692 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
693 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
694 repeat;
695 }
696 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
697 receipt of the second I frame from the MS. */
698 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
699 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
700 nr:=2, ns:=0, l3:=l3_mt)));
701 }
702
703 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
704 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
705 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
706
707 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
708 l3_mt := f_rnd_octstring(16);
709 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
710 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
711 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
712 nr:=2, ns:=1, l3:=l3_mt)));
713 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
714
715 deactivate(d);
716 fp_common_fini();
717}
718testcase TC_iframe_timer_recovery() runs on test_CT {
719 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
720 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
721}
722
Harald Welte9ea918c2019-06-01 11:46:25 +0200723type record LapdmDlConfig {
724 integer n201,
725 integer t200
726};
727
728type record LapdmDlState {
729 integer v_s,
730 integer v_a,
731 integer v_r
732};
733
734template (value) LapdmDlState t_init_LapdmDlState := {
735 v_s := 0,
736 v_a := 0,
737 v_r := 0
738}
739
740private function inc_mod8(inout integer v)
741{
742 v := (v + 1) mod 8;
743}
744
745private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
746runs on ConnHdlr {
747 var LAPDm_ph_data pd;
748 var integer offset := 0;
749 var integer n201 := 20;
750 var boolean is_sacch := false;
751 if (link_id.c == SACCH) {
752 n201 := 18;
753 is_sacch := true;
754 }
755
756 while (offset < lengthof(l3)) {
757 var integer remain_len := lengthof(l3) - offset;
758 var integer seg_len := remain_len;
759 if (remain_len > n201) {
760 seg_len := n201;
761 }
762 var octetstring segment := substr(l3, offset, seg_len);
763 var boolean more;
764 if (offset + lengthof(segment) < lengthof(l3)) {
765 more := true;
766 } else {
767 more := false;
768 }
769 /* send the next segment */
770 LAPDM.send(t_PH_DATA(0, is_sacch,
771 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
772 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
773 inc_mod8(dls.v_s);
774 offset := offset + lengthof(segment);
775
776 /* wait for it to be acknowledged */
777 alt {
778 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
779 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +0200780 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +0200781 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
782 setverdict(fail, "received unexpected LAPDm ", pd);
783 repeat;
784 }
785 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
786 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
787 setverdict(fail, "received RSL DATA IND before message complete");
788 }
789 }
790 }
791
792 timer T := 1.0;
793 T.start;
794 alt {
795 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
796 setverdict(pass);
797 }
798 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
799 setverdict(fail, "Received RSL DATA IND with wrong payload");
800 }
801 [] T.timeout {
802 setverdict(fail, "Timeout waiting for RSL DATA IND of de-segmented message");
803 }
804 }
805}
806
807/* Section 5.8.5 of TS 04.06 */
808const integer c_TS0406_MAX_L3_OCTETS := 251;
809
Harald Welteef6fd442019-06-01 21:41:29 +0200810/* test segmentation and de-segmentation (concatenation) of a large message in uplink
811 * on specified SAPI/channel */
812private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
813 var integer sapi := link_id.sapi;
814 var boolean is_sacch := false;
815 if (link_id.c == SACCH) {
816 is_sacch := true;
817 }
Harald Welte9ea918c2019-06-01 11:46:25 +0200818 var default d;
819 timer T := 3.0;
820
821 fp_common_init();
822
823 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +0200824 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +0200825 RSL.clear;
826 LAPDM.clear;
827
Harald Welte76771f12019-06-02 22:58:58 +0200828 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +0200829
Harald Welte76771f12019-06-02 22:58:58 +0200830 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +0200831
832 deactivate(d);
833
834 var LapdmDlState dls := valueof(t_init_LapdmDlState);
835 f_lapdm_transceive_mo(dls, link_id, l3_mo);
836
837 fp_common_fini();
838}
Harald Welteef6fd442019-06-01 21:41:29 +0200839private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
840 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +0200841}
Harald Welteef6fd442019-06-01 21:41:29 +0200842private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
843 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
844}
845/* test mobile-originated segmentation/de-segmentation on DCCH */
846testcase TC_segm_concat_dcch() runs on test_CT {
847 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
848 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
849}
850/* test mobile-originated segmentation/de-segmentation on SACCH */
851testcase TC_segm_concat_sacch() runs on test_CT {
852 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
853 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
854}
855
Harald Welteb2a30342019-06-02 22:13:50 +0200856/* TS 04.06 Section 5.8.2.1 */
857private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
858 /* SACCH irrespective of physical channel type */
859 if (match(link_id, tr_RslLinkID_SACCH(?))) {
860 return 5;
861 }
862 /* DCCH below */
863 select (chan_nr) {
864 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
865 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
866 case (t_RslChanNr_Bm(?)) { return 34; }
867 case (t_RslChanNr_Lm(?, ?)) { return 29; }
868 }
869 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
870 return -1;
871}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200872
Harald Welteb2a30342019-06-02 22:13:50 +0200873/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
874private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
875 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
876 var integer sapi := link_id.sapi;
877 var boolean is_sacch := false;
878 if (link_id.c == SACCH) {
879 is_sacch := true;
880 }
881 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
882 var integer num_retrans := 0;
883 timer T := 3.0;
884 var default d;
885
886 fp_common_init();
887
888 /* some common altstep for meas res and other background noise */
889 d := activate(as_ignore_background(true));
890 RSL.clear;
891 LAPDM.clear;
892
Harald Welte76771f12019-06-02 22:58:58 +0200893 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +0200894
895 var octetstring l3_mt := f_rnd_octstring(20);
896 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
897 /* first transmission, P = 0 */
898 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
899 nr:=0, ns:=0, l3:=l3_mt)));
900 deactivate(d);
901
902 alt {
903 /* re-transmission, P = 1 */
904 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
905 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
906 num_retrans := num_retrans + 1;
907 if (num_retrans < n200) {
908 repeat;
909 } else if (num_retrans == n200) {
910 T.start; /* wait for some more time if there are more retransmissions */
911 repeat;
912 } else {
913 /* break */
914 }
915 }
916 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
917 setverdict(fail, "Received unexpected I frame");
918 }
919 [not is_sacch] as_lapdm_acch();
920 [is_sacch] as_lapdm_dcch();
921 [] as_lapdm_idle();
922 [] as_rsl_meas_rep();
923 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
924 /* break */
925 }
926 [] T.timeout {
927 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
928 }
929 }
930
931 if (num_retrans == n200) {
932 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
933 } else if (num_retrans < n200) {
934 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
935 " on channel ", g_chan_nr, " link ", link_id);
936 }
937
938 fp_common_fini();
939}
940testcase TC_t200_n200() runs on test_CT {
941 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
942 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
943}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200944
Harald Welte7d9f6db2019-06-02 23:14:04 +0200945/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
946 Inspired by TS 51.010-1 25.2.4.3 */
947private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
948 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
949 var integer sapi := link_id.sapi;
950 var boolean is_sacch := false;
951 if (link_id.c == SACCH) {
952 is_sacch := true;
953 }
954 timer T := 3.0;
955 var default d;
956
957 fp_common_init();
958
959 /* some common altstep for meas res and other background noise */
960 d := activate(as_ignore_background(true));
961 RSL.clear;
962 LAPDM.clear;
963
964 f_establish_mo(link_id);
965
966 var octetstring l3_mo := f_rnd_octstring(10);
967 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
968 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
969 l3:=l3_mo)));
970 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
971 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
972 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
973
974 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
975 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
976 l3:=l3_mo)));
977
978 T.start;
979 alt {
980 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
981 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
982 setverdict(pass);
983 }
984 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
985 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
986 setverdict(pass);
987 }
988 [] T.timeout {
989 setverdict(fail, "Timeout waiting for RR or REJ");
990 }
991 }
992
993 deactivate(d);
994
995 fp_common_fini();
996}
997testcase TC_rr_response_frame_loss() runs on test_CT {
998 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
999 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1000}
1001
Harald Welte44479782019-06-02 23:23:45 +02001002/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1003private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1004 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1005 var integer sapi := link_id.sapi;
1006 var boolean is_sacch := false;
1007 if (link_id.c == SACCH) {
1008 is_sacch := true;
1009 }
1010 timer T := 3.0;
1011 var default d;
1012
1013 fp_common_init();
1014
1015 /* some common altstep for meas res and other background noise */
1016 d := activate(as_ignore_background(true));
1017 RSL.clear;
1018 LAPDM.clear;
1019
1020 f_establish_mo(link_id);
1021
1022 var octetstring l3_mo := f_rnd_octstring(10);
1023 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1024 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1025 l3:=l3_mo)));
1026 T.start;
1027 alt {
1028 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1029 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1030 }
1031 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1032 repeat;
1033 }
1034 /* ensure BTS still sends idle frames */
1035 [] as_lapdm_idle() {
1036 setverdict(pass, "still sending idle frames");
1037 }
1038 [] T.timeout {}
1039 }
1040
1041 /* Send RR command P=1 */
1042 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1043
1044 /* The BTS shall respond with a RR response, F bit set to 1. */
1045 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1046
1047 deactivate(d);
1048
1049 fp_common_fini();
1050}
1051testcase TC_incorrect_cr() runs on test_CT {
1052 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1053 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1054}
Harald Welte72c81e72019-05-30 16:36:11 +02001055control {
1056 execute(TC_foo());
1057 execute(TC_sabm_ua_dcch_sapi0());
1058 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1059 execute(TC_sabm_ua_dcch_sapi3());
1060 execute(TC_sabm_ua_dcch_sapi4());
1061 execute(TC_sabm_contention());
1062 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001063 execute(TC_sabm_retransmit_bts());
1064 execute(TC_sabm_invalid_resp());
1065 execute(TC_sabm_dm());
1066 execute(TC_establish_ign_first_sabm());
1067 execute(TC_iframe_seq_and_ack());
1068 execute(TC_iframe_timer_recovery());
Harald Welteef6fd442019-06-01 21:41:29 +02001069 execute(TC_segm_concat_dcch());
1070 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001071 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001072 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001073 execute(TC_incorrect_cr());
Harald Welte72c81e72019-05-30 16:36:11 +02001074}
1075
Harald Weltef6543322017-07-16 07:35:10 +02001076}