blob: 9981bbc9a7ed01aa0652d1a7068abb9c0fd56613 [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;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +07009import from GSM_RR_Types all;
Harald Welte2f2b2b72019-05-31 22:24:57 +020010import from Misc_Helpers all;
Harald Welte66110f02017-07-16 21:05:18 +020011
Harald Welte72c81e72019-05-30 16:36:11 +020012/* test that use exclusively only LAPDm over L1CTL */
13type component lapdm_test_CT {
14 port LAPDm_PT LAPDM;
15 var lapdm_CT lapdm_component;
16};
17
18/* contrary to BTS_Tests.ttcn, we use LAPDm_PT here, a convenience wrapper
19 * around L1CTL to perform encode/decode of abstract LAPDm frames */
Harald Welte72c81e72019-05-30 16:36:11 +020020
Harald Welte61332c02019-05-30 16:45:15 +020021/*********************************************************************************
22 * Test using only L1CTL/LAPDm
23 *********************************************************************************/
24
25function f_lapdm_init() runs on lapdm_test_CT {
Harald Welte72c81e72019-05-30 16:36:11 +020026 /* create the LAPDm component */
27 lapdm_component := lapdm_CT.create;
28 /* connect our own LAPDM port to the LAPDM Service Provider of the LAPDm component */
29 connect(self:LAPDM, lapdm_component:LAPDM_SP);
30 /* connect the LAPDm compoent's lower-side port to the system L1CTL port (which is internally
31 * connected to the Unix Domain Socket test port */
32 map(lapdm_component:L1CTL, system:L1CTL);
33
34 /* start the LAPDm parallel component calling it's local function LAPDmStart */
35 lapdm_component.start(LAPDmStart());
36}
37
Harald Welte2f2b2b72019-05-31 22:24:57 +020038function f_lapdm_exit() runs on lapdm_test_CT {
39 lapdm_component.stop;
40 lapdm_component.done;
41 unmap(lapdm_component:L1CTL, system:L1CTL);
42}
43
Harald Welte72c81e72019-05-30 16:36:11 +020044/* master function establishing a dedicated radio channel (takes care of RACH/IMM.ASS handling) */
45function f_establish_dcch() runs on lapdm_test_CT {
Harald Welte2f2b2b72019-05-31 22:24:57 +020046 var BCCH_tune_req tune_req := { arfcn := { false, mp_trx0_arfcn }, combined_ccch := true };
Harald Welte72c81e72019-05-30 16:36:11 +020047 var DCCH_establish_req est_req := { ra := 23 };
48
49 LAPDM.send(tune_req);
50 LAPDM.send(est_req);
51 LAPDM.receive(DCCH_establish_res:?);
52}
53
Harald Welte2f2b2b72019-05-31 22:24:57 +020054/* master function switching to a dedicated radio channel */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070055function f_switch_dcch() runs on ConnHdlr {
56 var BCCH_tune_req tune_req := { arfcn := { false, mp_trx0_arfcn }, combined_ccch := true };
57 var DCCH_switch_req sw_req := { ma := g_pars.ma };
58
59 /* Craft channel description (with or without frequency hopping parameters) */
60 if (ispresent(g_pars.maio_hsn)) {
61 sw_req.chan_desc := valueof(ts_ChanDescH1(g_pars.chan_nr, g_pars.maio_hsn));
62 } else {
63 sw_req.chan_desc := valueof(ts_ChanDescH0(g_pars.chan_nr, mp_trx0_arfcn));
64 }
Harald Welte2f2b2b72019-05-31 22:24:57 +020065
66 LAPDM.send(tune_req);
67 LAPDM.send(sw_req);
68 LAPDM.receive(DCCH_switch_res:?);
69}
70
Harald Welte72c81e72019-05-30 16:36:11 +020071/* helper function releasing dedicated radio channel physically (no Um signaling!) */
72function f_release_dcch() runs on lapdm_test_CT {
73 var DCCH_release_req rel_req := {};
74 LAPDM.send(rel_req);
75}
76
77template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
78 sacch := sacch,
79 sapi := sapi,
80 lapdm := frame
81}
Harald Weltec38611b2019-05-30 16:33:58 +020082
Eric Wild74f25ae2019-06-14 11:44:29 +020083function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on ConnHdlr return boolean {
Harald Welte72c81e72019-05-30 16:36:11 +020084 var LAPDm_ph_data phd;
85 var boolean result := false;
86 timer T := 5.0;
87
Eric Wild74f25ae2019-06-14 11:44:29 +020088 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=false, l3:=payload)));
Harald Welte72c81e72019-05-30 16:36:11 +020089 T.start
90 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +020091 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { result := true; }
92 [] RSL.receive {repeat;}
93 [] LAPDM.receive { repeat; }
Harald Welte72c81e72019-05-30 16:36:11 +020094 [] T.timeout { }
95 }
Eric Wild74f25ae2019-06-14 11:44:29 +020096 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MT_CMD, p:=false, nr:=0)));
Harald Welte72c81e72019-05-30 16:36:11 +020097 return result;
98}
99
Eric Wild74f25ae2019-06-14 11:44:29 +0200100function f_TC_sabm_ua_dcch_sapi0(charstring id) runs on ConnHdlr {
101 fp_common_init();
102 RSL.clear;
103 LAPDM.clear;
104 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200105 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
106 setverdict(fail);
107 }
108 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200109 deactivate(d);
110 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200111}
112
Eric Wild74f25ae2019-06-14 11:44:29 +0200113function f_TC_sabm_ua_dcch_sapi0_nopayload(charstring id) runs on ConnHdlr {
114 fp_common_init();
115 RSL.clear;
116 LAPDM.clear;
117 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200118 if (f_test_sabm_results_in_ua(0, false, ''O)) {
119 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
120 }
121 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200122 deactivate(d);
123 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200124}
125
Eric Wild74f25ae2019-06-14 11:44:29 +0200126function f_TC_sabm_ua_dcch_sapi3(charstring id) runs on ConnHdlr {
127 fp_common_init();
128 RSL.clear;
129 LAPDM.clear;
130 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200131 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
132 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
133 }
134 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200135 deactivate(d);
136 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200137}
138
Eric Wild74f25ae2019-06-14 11:44:29 +0200139function f_TC_sabm_ua_dcch_sapi4(charstring id) runs on ConnHdlr {
140 fp_common_init();
141 RSL.clear;
142 LAPDM.clear;
143 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200144 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
145 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
146 }
147 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200148 deactivate(d);
149 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200150}
151
Eric Wild74f25ae2019-06-14 11:44:29 +0200152testcase TC_sabm_ua_dcch_sapi0() runs on test_CT {
153 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
154 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0));
155}
156
157testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on test_CT {
158 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
159 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0_nopayload));
160}
161
162testcase TC_sabm_ua_dcch_sapi3() runs on test_CT {
163 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
164 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi3));
165}
166
167testcase TC_sabm_ua_dcch_sapi4() runs on test_CT {
168 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
169 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi4));
170}
171
172function f_TC_sabm_contention(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200173 var LAPDm_ph_data phd;
174 const octetstring payload := '0102030405'O;
175 const GsmSapi sapi := 0;
176 const boolean use_sacch := false;
177 timer T := 5.0;
178
Eric Wild74f25ae2019-06-14 11:44:29 +0200179 fp_common_init();
180 RSL.clear;
181 LAPDM.clear;
Harald Welte72c81e72019-05-30 16:36:11 +0200182
Harald Welte72c81e72019-05-30 16:36:11 +0200183 /* first frame is our real SABM */
Eric Wild74f25ae2019-06-14 11:44:29 +0200184 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=false, l3:=payload)));
Harald Welte72c81e72019-05-30 16:36:11 +0200185 /* second frame is a SABM with different payload, which BTS has to ignore according to 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200186 LAPDM.send(t_PH_DATA(sapi, use_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=false, l3:='ABCDEF'O)));
Harald Welte72c81e72019-05-30 16:36:11 +0200187 T.start
188 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +0200189 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { setverdict(pass); repeat; }
190 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=?))) {
Harald Welte72c81e72019-05-30 16:36:11 +0200191 setverdict(fail, "Second SABM was responded to during contention resolution");
Eric Wild74f25ae2019-06-14 11:44:29 +0200192 }
193 [] RSL.receive {repeat;}
Harald Welte72c81e72019-05-30 16:36:11 +0200194 [] LAPDM.receive { repeat };
195 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200196 }
Eric Wild74f25ae2019-06-14 11:44:29 +0200197
198 fp_common_fini();
199}
200
201testcase TC_sabm_contention() runs on test_CT {
202 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
203 f_testmatrix_each_chan(pars, refers(f_TC_sabm_contention));
Harald Welte72c81e72019-05-30 16:36:11 +0200204}
Harald Welte9e4725d2017-07-16 23:18:09 +0200205
Harald Welte72c81e72019-05-30 16:36:11 +0200206/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
207 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200208function f_TC_sabm_retransmit(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200209 const octetstring payload := '00FEFEDEADBEEF'O;
Eric Wild74f25ae2019-06-14 11:44:29 +0200210 fp_common_init();
211 RSL.clear;
212 LAPDM.clear;
213 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200214 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200215 setverdict(fail);
Harald Welte599faa12017-07-17 21:49:24 +0200216 }
Harald Welte72c81e72019-05-30 16:36:11 +0200217 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200218 setverdict(fail);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200219 }
Harald Welte72c81e72019-05-30 16:36:11 +0200220 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200221 deactivate(d);
222 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200223}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200224
Eric Wild74f25ae2019-06-14 11:44:29 +0200225testcase TC_sabm_retransmit() runs on test_CT {
226 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
227 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit));
Harald Welte72c81e72019-05-30 16:36:11 +0200228}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200229
Harald Welte2f2b2b72019-05-31 22:24:57 +0200230/*********************************************************************************
231 * Test using both L1CTL/LAPDm and RSL
232 *********************************************************************************/
233
234private function fp_common_init() runs on ConnHdlr
235{
236 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
237 unmap(self:L1CTL, system:L1CTL);
238 f_lapdm_init();
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700239
240 /* Obtain frequency hopping parameters for a given timeslot */
241 if (mp_freq_hop_enabled and mp_transceiver_num > 1) {
242 f_resolve_fh_params(g_pars);
243 }
244
Harald Welte2f2b2b72019-05-31 22:24:57 +0200245 /* activate the channel on the BTS side */
246 f_rsl_chan_act(g_pars.chan_mode, false, {});
247 /* activate the channel on the MS side */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700248 f_switch_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200249}
250
251private function fp_common_fini() runs on ConnHdlr
252{
253 f_release_dcch();
254 f_rsl_chan_deact();
255 f_lapdm_exit();
256}
257
Harald Welte76771f12019-06-02 22:58:58 +0200258/* Mobile-Originated LAPDm establishment on given Link ID */
259private function f_establish_mo(RslLinkId link_id) runs on ConnHdlr
260{
261 var integer sapi := link_id.sapi;
262 var boolean is_sacch := false;
263 if (link_id.c == SACCH) {
264 is_sacch := true;
265 }
266
267 var octetstring l3_mo := f_rnd_octstring(5);
268
269 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
270 if (is_sacch) {
271 /* no payload permitted, as this is not contention resolution */
272 l3_mo := ''O;
273 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
274 RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
275 } else {
276 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
277 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
278 }
279 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
280 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
281}
282
Harald Welte2f2b2b72019-05-31 22:24:57 +0200283/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
284 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
285private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
286 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
287 fp_common_init();
288
289 LAPDM.clear;
290 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
291
292 timer T := 8.0;
293 var integer sabm_received := 0;
294 T.start;
295 alt {
296 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
297 sabm_received := sabm_received + 1;
298 repeat;
299 }
300 [] LAPDM.receive { repeat; }
301 [] T.timeout { }
302 }
303 if (sabm_received == 0) {
304 setverdict(fail, "No SABM observed at all!");
305 } else if (sabm_received != 6) {
306 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
307 sabm_received);
308 } else {
309 setverdict(pass, "Received ", sabm_received, " SABM");
310 }
311
312 fp_common_fini();
313}
314testcase TC_sabm_retransmit_bts() runs on test_CT {
315 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
316 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
317}
318
319
320type record LapdmNamedFrame {
321 charstring name,
322 LapdmFrame lapdm
323};
324
325/* Test that the BTS will ignore receipt of frames other than a UA when
326 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
327 * Section 25.2.1.1.2.3 */
328private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
329 var integer sapi := err_frame.lapdm.ab.addr.sapi;
330 fp_common_init();
331
332 /* Establish Request via RSL; Expect SABM on LAPDm side */
333 LAPDM.clear;
334 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
335 alt {
336 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
337 [] LAPDM.receive { repeat; }
338 }
339
340 /* send erroneous response to SABM */
341 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
342
343 /* expect a SABM retransmission of the BTS */
344 timer T := 3.0;
345 T.start;
346 alt {
347 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
348 setverdict(pass);
349 }
350 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
351 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
352 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
353 err_frame.name);
354 }
355 [] LAPDM.receive { repeat; }
356 [] T.timeout {
357 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
358 err_frame.name);
359 }
360 }
361
362 fp_common_fini();
363}
364private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
365 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
366 var LapdmNamedFrame err_frame[3] := {
367 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
368 l3 := '01020304'O)) },
369 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
370 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
371 };
372 var integer i;
373
374 for (i := 0; i < lengthof(err_frame); i := i+1) {
375 f_TC_sabm_invalid_resp2(id, err_frame[i])
376 }
377}
378testcase TC_sabm_invalid_resp() runs on test_CT {
379 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
380 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
381}
382
383/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
384 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
385private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
386 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
387 fp_common_init();
388
389 /* Establish Request via RSL; Expect SABM on LAPDm side */
390 LAPDM.clear;
391 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
392 alt {
393 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
394 [] LAPDM.receive { repeat; }
395 }
396
397 /* send DM response to SABM */
398 RSL.clear;
399 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
400 alt {
401 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
402 [] RSL.receive { repeat; }
403 }
404
405 /* expect no SABM retransmission of the BTS */
406 timer T := 3.0;
407 T.start;
408 alt {
409 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
410 setverdict(fail, "Received unexpected SABM retransmission");
411 }
412 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
413 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
414 setverdict(fail, "Received unexpected LAPDm frame");
415 }
416 [] LAPDM.receive { repeat; }
417 [] T.timeout {
418 setverdict(pass);
419 }
420 }
421
422 fp_common_fini();
423}
424testcase TC_sabm_dm() runs on test_CT {
425 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
426 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
427}
428
429/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
430 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
431 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
432private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
433 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
434 var integer num_sabm := 0;
435 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
436 timer T := 3.0;
437
438 fp_common_init();
439
440 /* Establish Request via RSL */
441 LAPDM.clear;
442 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
443 /* Expect two SABM (retransmit) */
444 T.start;
445 alt {
446 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
447 num_sabm := num_sabm + 1;
448 if (num_sabm < 2) {
449 repeat;
450 }
451 }
452 [] LAPDM.receive { repeat; }
453 }
454
455 /* send UA response to SABM */
456 RSL.clear;
457 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
458 alt {
459 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
460 [] RSL.receive { repeat; }
461 }
462
463 /* Send I frame from BTS to MS */
464 var octetstring l3 := f_rnd_octstring(10);
465 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
466 alt {
467 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
468 nr:=0, ns:=0, l3:=l3)));
469 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
470 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
471 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
472 }
473 /* Send RR frame in response */
474 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
475
476 /* expect idle UI Frame from BTS */
477 alt {
478 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
479 setverdict(pass);
480 }
481 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
482 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
483 }
484
485 fp_common_fini();
486}
487testcase TC_establish_ign_first_sabm() runs on test_CT {
488 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
489 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
490}
491
492/* ignore all SACCH frames */
493private altstep as_lapdm_acch() runs on ConnHdlr {
494 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
495}
Harald Welteef6fd442019-06-01 21:41:29 +0200496/* ignore all DCCH frames */
497private altstep as_lapdm_dcch() runs on ConnHdlr {
498 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
499}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200500/* ignore all LAPDm idle frames (UI) */
501private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200502 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200503}
504/* ignore all measurement reports */
505private altstep as_rsl_meas_rep() runs on ConnHdlr {
506 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
507}
508/* fail if we receive an RSL ERROR IND */
509private altstep as_rsl_fail_err() runs on ConnHdlr {
510 var RSL_Message rx_rsl;
511 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
512 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
513 }
514}
515/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200516private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200517 [want_dcch] as_lapdm_acch();
518 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200519 [] as_lapdm_idle();
520 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200521 [not ignore_rsl_errors] as_rsl_fail_err();
522 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200523}
524
525/* Test the operation of Layer 2 sequence numbering.
526 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
527private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
528 const integer sapi := 0;
529 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
530 var octetstring l3 := f_rnd_octstring(18);
531 var default d;
532 timer T := 3.0;
533
534 fp_common_init();
535
536 /* some common altstep for meas res and other background noise */
537 d := activate(as_ignore_background());
538 RSL.clear;
539 LAPDM.clear;
540
Harald Welte76771f12019-06-02 22:58:58 +0200541 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200542
543 var integer last_ns_rx := 0;
544
545 for (var integer i := 0; i < 10; i := i+1) {
546 var octetstring l3_mo := f_rnd_octstring(12);
547 var octetstring l3_mt := f_rnd_octstring(12);
548 var LAPDm_ph_data pd;
549
550 log("Starting iteration ", i);
551 /* MT I frame */
552 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
553 alt {
554 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
555 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
556 nr:=i mod 8))) {
557 log("Ignoring RR in iteration ", i);
558 repeat;
559 }
560 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
561 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
562 nr:=i mod 8, ns:=i mod 8,
563 l3:=l3_mt))) -> value pd {
564 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
565 }
566 }
567 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
568 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
569 nr:=(last_ns_rx+1)mod 8,
570 ns:=i mod 8, l3 := l3_mo)));
571 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
572 }
573 log("Completed iteration");
574
575 deactivate(d);
576 fp_common_fini();
577}
578testcase TC_iframe_seq_and_ack() runs on test_CT {
579 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
580 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
581}
582
583/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
584 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
585
586/*
587 1) The BTS is brought into the multiple frame established state
588 2) The MS sends an L3 Request asking for IMEI to the MS.
589 3) The BTS shall respond with a RR frame though this may be incorporated with
590 the L3 Response I frame. The MS does not respond to the I frame.
591 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
592 with the P bit set to 1.
593 5) The MS then sends a valid L3 Request I frame asking for IMEI which
594 does not acknowledge receipt of the I frame from the BTS.
595On the FACCH the BTS may send an RR frame acknowledging the I frame.
596 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
597 the second I frame from the MS.
598 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
599 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
600*/
601private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
602 const integer sapi := 0;
603 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
604 var default d;
605 timer T := 3.0;
606
607 fp_common_init();
608
609 /* some common altstep for meas res and other background noise */
610 d := activate(as_ignore_background());
611 RSL.clear;
612 LAPDM.clear;
613
614 var octetstring l3_mo := f_rnd_octstring(12);
615 var octetstring l3_mt := f_rnd_octstring(12);
616
617 /* 1) The BTS is brought into the multiple frame established state */
618
619 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
620 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
621 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
622 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
623 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
624
625 /* 2) The MS sends an L3 Request to the BTS */
626 l3_mo := f_rnd_octstring(18);
627 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
628 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
629 nr:=0, ns:=0, l3:=l3_mo)));
630 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
631 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
632 the L3 Response I frame. The MS does not respond to the I frame. */
633 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
634 alt {
635 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
636 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
637 repeat;
638 }
639 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
640 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
641 nr:=1, ns:=0, l3:=l3_mt)));
642 }
643
644 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
645 with the P bit set to 1. */
646 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
647 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
648 nr:=1, ns:=0, l3:=l3_mt)));
649
650 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
651 does not acknowledge receipt of the I frame from the BTS. */
652 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
653 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
654 nr:=0, ns:=1, l3 := l3_mo)));
655 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
656 alt {
657 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
658 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
659 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
660 repeat;
661 }
662 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
663 receipt of the second I frame from the MS. */
664 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
665 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
666 nr:=2, ns:=0, l3:=l3_mt)));
667 }
668
669 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
670 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
671 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
672
673 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
674 l3_mt := f_rnd_octstring(16);
675 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
676 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
677 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
678 nr:=2, ns:=1, l3:=l3_mt)));
679 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
680
681 deactivate(d);
682 fp_common_fini();
683}
684testcase TC_iframe_timer_recovery() runs on test_CT {
685 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
686 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
687}
688
Eric Wild211acc32019-06-11 19:06:38 +0200689/* 25.2.6.1 ns sequence error
690sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
691private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
692 const integer sapi := 0;
693 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
694 var default d;
695 timer T := 3.0;
696
697 fp_common_init();
698
699 /* some common altstep for meas res and other background noise */
700 d := activate(as_ignore_background(ignore_rsl_errors := true));
701 RSL.clear;
702 LAPDM.clear;
703
704 var octetstring l3_mo := f_rnd_octstring(12);
705 var octetstring l3_mt := f_rnd_octstring(12);
706
707 /* 1) The BTS is brought into the multiple frame established state */
708
709 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
710 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
711 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
712 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
713 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
714
715 /* 2) The MS sends an L3 Request to the BTS */
716 l3_mo := f_rnd_octstring(18);
717 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
718 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
719 nr:=0, ns:=0, l3:=l3_mo)));
720 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
721 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
722 the L3 Response I frame. */
723 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
724 alt {
725 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
726 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
727 repeat;
728 }
729 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
730 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
731 nr:=1, ns:=0, l3:=l3_mt)));
732 }
733
734 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
735 but correctly acknowledging the MS's I frame; P bit set to zero. */
736 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
737 nr:=1, ns:=0, l3:=l3_mo)));
738
739 /* no rsl data ind due to wrong ns */
740
741 /* The BTS shall send a REJ frame. */
742 timer T1 := 2.0;
743 T1.start;
744 alt{
745 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
746 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
747 }
748
749 f_sleep(2.0); // T200
750
751 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
752 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
753 nr:=1, ns:=0, l3:=l3_mo)));
754
755 /* The BTS shall respond with a REJ, F bit set to 1. */
756 T1.start;
757 alt{
758 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
759 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
760 }
761
762 deactivate(d);
763 fp_common_fini();
764 setverdict(pass);
765}
766
767testcase TC_ns_seq_error() runs on test_CT {
768 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
769 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
770}
771
772/* 25.2.6.2 nr sequence error */
773private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
774 const integer sapi := 0;
775 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
776 var default d;
777 var integer n201 := 20;
778 if (link_id.c == SACCH) {
779 n201 := 18;
780 }
781
782 fp_common_init();
783
784 /* some common altstep for meas res and other background noise */
785 d := activate(as_ignore_background(ignore_rsl_errors := true));
786 RSL.clear;
787 LAPDM.clear;
788
789 var octetstring l3_mo := f_rnd_octstring(12);
790 var octetstring l3_mt := f_rnd_octstring(12);
791
792 /* 1) The BTS is brought into the multiple frame established state */
793
794 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
795 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
796 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
797 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
798 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
799
800 /* 2) The MS shall send an I frame containing an information field of length N201 and an
801 incorrect receive sequence number. */
802 l3_mo := f_rnd_octstring(n201);
803 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
804 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
805 nr:=1, ns:=0, l3:=l3_mo)));
806
807 /* The BTS may: a) send a DISC frame within N200×T200; */
808 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
809 timer T1 := 2.0;
810 T1.start;
811 alt{
812 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
813 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
814 }
815
816 /* a) the MS shall respond with a UA frame.
817 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
818 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
819
820 deactivate(d);
821 fp_common_fini();
822 setverdict(pass);
823}
824
825testcase TC_nr_seq_error() runs on test_CT {
826 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
827 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
828}
829
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100830private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200831 LAPDM.send(t_PH_DATA(0, false, x));
832 f_sleep(2.0); // T200
833 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100834 timer T1 := 2.0;
835 T1.start;
836 alt {
837 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
838 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
839 }
Eric Wild211acc32019-06-11 19:06:38 +0200840}
841
842/* 25.2.7 Test on receipt of invalid frames
843sends a bunch of different invalid frames, expects the BTS to ignore all of them */
844private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
845 const integer sapi := 0;
846 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
847 var default d;
848 timer T := 3.0;
849
850 fp_common_init();
851
852 /* some common altstep for meas res and other background noise */
853 d := activate(as_ignore_background(ignore_rsl_errors := true));
854 RSL.clear;
855 LAPDM.clear;
856
857 var octetstring l3_mo := f_rnd_octstring(12);
858 var octetstring l3_mt := f_rnd_octstring(12);
859
860 /* 1) The BTS is brought into the multiple frame established state */
861
862 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
863 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100864 T.start
865 alt {
866 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
867 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
868 }
869 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200870 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100871 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
872 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
873 }
Eric Wild211acc32019-06-11 19:06:38 +0200874
875 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
876 RR frame with the Length indicator greater than zero and a faulty N(R); */
877 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
878 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100879 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200880 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
881 EJ frame with the EA bit set to zero and a faulty N(R); */
882 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
883 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100884 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200885 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
886 SABM frame with the EL bit set to zero; */
887 l3_mo := ''O;
888 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
889 x.ab.el := 0;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100890 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200891 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
892 DM frame with the Length indicator greater than zero;*/
893 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
894 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100895 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200896 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
897 DISC frame with the M bit set to 1; */
898 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
899 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100900 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200901 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
902 UA frame with the EA bit set to zero*/
903 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
904 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100905 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200906 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
907 I frame with the Length indicator greater than N201;*/
908 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 6, l3 := f_rnd_octstring(25)))
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100909 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200910 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
911 I frame with the M bit set to 1 and the Length indicator less than N201;*/
912 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
913 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100914 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200915 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
916 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100917 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200918
919 /* command frames with correct Address and Length indicator field and a non-implemented control field */
920 /* 12: One command frame with Control Field = xxx1 1101. */
921 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
922 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100923 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200924 /* 13: One command frame with Control field = xxx1 1011. */
925 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
926 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100927 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200928 /* 14: One command frame with Control field = xxx1 0111. */
929 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
930 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100931 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200932 /* 15: One command frame with Control field = 01x1 1111. */
933 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
934 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100935 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200936 /* 16: One command frame with Control field = 1xx1 1111. */
937 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
938 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100939 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200940 /* 17: One command frame with Control field = 0011 0011. */
941 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
942 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100943 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200944 /* 18: One command frame with Control field = 1xx1 0011. */
945 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
946 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100947 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200948
949 deactivate(d);
950 fp_common_fini();
951 setverdict(pass);
952}
953
954testcase TC_rec_invalid_frame() runs on test_CT {
955 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
956 pars.t_guard := 60.0;
957 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
958}
959
Harald Welte9ea918c2019-06-01 11:46:25 +0200960type record LapdmDlConfig {
961 integer n201,
962 integer t200
963};
964
965type record LapdmDlState {
966 integer v_s,
967 integer v_a,
968 integer v_r
969};
970
971template (value) LapdmDlState t_init_LapdmDlState := {
972 v_s := 0,
973 v_a := 0,
974 v_r := 0
975}
976
977private function inc_mod8(inout integer v)
978{
979 v := (v + 1) mod 8;
980}
981
982private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
983runs on ConnHdlr {
984 var LAPDm_ph_data pd;
985 var integer offset := 0;
986 var integer n201 := 20;
987 var boolean is_sacch := false;
988 if (link_id.c == SACCH) {
989 n201 := 18;
990 is_sacch := true;
991 }
992
993 while (offset < lengthof(l3)) {
994 var integer remain_len := lengthof(l3) - offset;
995 var integer seg_len := remain_len;
996 if (remain_len > n201) {
997 seg_len := n201;
998 }
999 var octetstring segment := substr(l3, offset, seg_len);
1000 var boolean more;
1001 if (offset + lengthof(segment) < lengthof(l3)) {
1002 more := true;
1003 } else {
1004 more := false;
1005 }
1006 /* send the next segment */
1007 LAPDM.send(t_PH_DATA(0, is_sacch,
1008 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1009 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1010 inc_mod8(dls.v_s);
1011 offset := offset + lengthof(segment);
1012
1013 /* wait for it to be acknowledged */
1014 alt {
1015 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1016 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001017 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001018 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
1019 setverdict(fail, "received unexpected LAPDm ", pd);
1020 repeat;
1021 }
1022 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1023 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1024 setverdict(fail, "received RSL DATA IND before message complete");
1025 }
1026 }
1027 }
1028
1029 timer T := 1.0;
1030 T.start;
1031 alt {
1032 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1033 setverdict(pass);
1034 }
1035 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1036 setverdict(fail, "Received RSL DATA IND with wrong payload");
1037 }
1038 [] T.timeout {
1039 setverdict(fail, "Timeout waiting for RSL DATA IND of de-segmented message");
1040 }
1041 }
1042}
1043
1044/* Section 5.8.5 of TS 04.06 */
1045const integer c_TS0406_MAX_L3_OCTETS := 251;
1046
Harald Welteef6fd442019-06-01 21:41:29 +02001047/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1048 * on specified SAPI/channel */
1049private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1050 var integer sapi := link_id.sapi;
1051 var boolean is_sacch := false;
1052 if (link_id.c == SACCH) {
1053 is_sacch := true;
1054 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001055 var default d;
1056 timer T := 3.0;
1057
1058 fp_common_init();
1059
1060 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001061 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001062 RSL.clear;
1063 LAPDM.clear;
1064
Harald Welte76771f12019-06-02 22:58:58 +02001065 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001066
Harald Welte76771f12019-06-02 22:58:58 +02001067 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001068
1069 deactivate(d);
1070
1071 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1072 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1073
1074 fp_common_fini();
1075}
Harald Welteef6fd442019-06-01 21:41:29 +02001076private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1077 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001078}
Harald Welteef6fd442019-06-01 21:41:29 +02001079private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1080 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1081}
1082/* test mobile-originated segmentation/de-segmentation on DCCH */
1083testcase TC_segm_concat_dcch() runs on test_CT {
1084 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1085 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1086}
1087/* test mobile-originated segmentation/de-segmentation on SACCH */
1088testcase TC_segm_concat_sacch() runs on test_CT {
1089 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1090 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1091}
1092
Harald Welteb2a30342019-06-02 22:13:50 +02001093/* TS 04.06 Section 5.8.2.1 */
1094private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1095 /* SACCH irrespective of physical channel type */
1096 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1097 return 5;
1098 }
1099 /* DCCH below */
1100 select (chan_nr) {
1101 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1102 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1103 case (t_RslChanNr_Bm(?)) { return 34; }
1104 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1105 }
1106 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1107 return -1;
1108}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001109
Harald Welteb2a30342019-06-02 22:13:50 +02001110/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1111private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
1112 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1113 var integer sapi := link_id.sapi;
1114 var boolean is_sacch := false;
1115 if (link_id.c == SACCH) {
1116 is_sacch := true;
1117 }
1118 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1119 var integer num_retrans := 0;
1120 timer T := 3.0;
1121 var default d;
1122
1123 fp_common_init();
1124
1125 /* some common altstep for meas res and other background noise */
1126 d := activate(as_ignore_background(true));
1127 RSL.clear;
1128 LAPDM.clear;
1129
Harald Welte76771f12019-06-02 22:58:58 +02001130 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001131
1132 var octetstring l3_mt := f_rnd_octstring(20);
1133 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1134 /* first transmission, P = 0 */
1135 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1136 nr:=0, ns:=0, l3:=l3_mt)));
1137 deactivate(d);
1138
1139 alt {
1140 /* re-transmission, P = 1 */
1141 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1142 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1143 num_retrans := num_retrans + 1;
1144 if (num_retrans < n200) {
1145 repeat;
1146 } else if (num_retrans == n200) {
1147 T.start; /* wait for some more time if there are more retransmissions */
1148 repeat;
1149 } else {
1150 /* break */
1151 }
1152 }
1153 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
1154 setverdict(fail, "Received unexpected I frame");
1155 }
1156 [not is_sacch] as_lapdm_acch();
1157 [is_sacch] as_lapdm_dcch();
1158 [] as_lapdm_idle();
1159 [] as_rsl_meas_rep();
1160 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1161 /* break */
1162 }
1163 [] T.timeout {
1164 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1165 }
1166 }
1167
1168 if (num_retrans == n200) {
1169 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1170 } else if (num_retrans < n200) {
1171 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1172 " on channel ", g_chan_nr, " link ", link_id);
1173 }
1174
1175 fp_common_fini();
1176}
1177testcase TC_t200_n200() runs on test_CT {
1178 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1179 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1180}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001181
Harald Welte7d9f6db2019-06-02 23:14:04 +02001182/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1183 Inspired by TS 51.010-1 25.2.4.3 */
1184private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1185 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1186 var integer sapi := link_id.sapi;
1187 var boolean is_sacch := false;
1188 if (link_id.c == SACCH) {
1189 is_sacch := true;
1190 }
1191 timer T := 3.0;
1192 var default d;
1193
1194 fp_common_init();
1195
1196 /* some common altstep for meas res and other background noise */
1197 d := activate(as_ignore_background(true));
1198 RSL.clear;
1199 LAPDM.clear;
1200
1201 f_establish_mo(link_id);
1202
1203 var octetstring l3_mo := f_rnd_octstring(10);
1204 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1205 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1206 l3:=l3_mo)));
1207 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1208 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1209 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1210
1211 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1212 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1213 l3:=l3_mo)));
1214
1215 T.start;
1216 alt {
1217 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1218 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1219 setverdict(pass);
1220 }
1221 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1222 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1223 setverdict(pass);
1224 }
1225 [] T.timeout {
1226 setverdict(fail, "Timeout waiting for RR or REJ");
1227 }
1228 }
1229
1230 deactivate(d);
1231
1232 fp_common_fini();
1233}
1234testcase TC_rr_response_frame_loss() runs on test_CT {
1235 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1236 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1237}
1238
Harald Welte44479782019-06-02 23:23:45 +02001239/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1240private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1241 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1242 var integer sapi := link_id.sapi;
1243 var boolean is_sacch := false;
1244 if (link_id.c == SACCH) {
1245 is_sacch := true;
1246 }
1247 timer T := 3.0;
1248 var default d;
1249
1250 fp_common_init();
1251
1252 /* some common altstep for meas res and other background noise */
1253 d := activate(as_ignore_background(true));
1254 RSL.clear;
1255 LAPDM.clear;
1256
1257 f_establish_mo(link_id);
1258
1259 var octetstring l3_mo := f_rnd_octstring(10);
1260 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1261 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1262 l3:=l3_mo)));
1263 T.start;
1264 alt {
1265 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1266 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1267 }
1268 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1269 repeat;
1270 }
1271 /* ensure BTS still sends idle frames */
1272 [] as_lapdm_idle() {
1273 setverdict(pass, "still sending idle frames");
1274 }
1275 [] T.timeout {}
1276 }
1277
1278 /* Send RR command P=1 */
1279 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1280
1281 /* The BTS shall respond with a RR response, F bit set to 1. */
1282 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1283
1284 deactivate(d);
1285
1286 fp_common_fini();
1287}
1288testcase TC_incorrect_cr() runs on test_CT {
1289 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1290 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1291}
Harald Weltea39ac752019-06-04 21:46:07 +02001292
1293/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1294 Inspired by TS 51.010-1 25.2.5.2 */
1295private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1296 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1297 var integer sapi := link_id.sapi;
1298 var boolean is_sacch := false;
1299 if (link_id.c == SACCH) {
1300 is_sacch := true;
1301 }
1302 timer T := 3.0;
1303 var default d;
1304
1305 fp_common_init();
1306
1307 /* some common altstep for meas res and other background noise */
1308 d := activate(as_ignore_background(true));
1309 RSL.clear;
1310 LAPDM.clear;
1311
1312 f_establish_mo(link_id);
1313
1314 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1315 var octetstring l3_mo := '010203'O;
1316 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1317 l3:=l3_mo)));
1318 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1319 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1320 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1321 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1322 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1323 /* Expect RSL ERR IND */
1324 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1325 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1326 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1327 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1328 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1329 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1330 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1331
1332 deactivate(d);
1333
1334 fp_common_fini();
1335}
1336testcase TC_sabm_incorrect_c() runs on test_CT {
1337 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1338 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1339}
1340
Harald Welte72c81e72019-05-30 16:36:11 +02001341control {
Harald Welte72c81e72019-05-30 16:36:11 +02001342 execute(TC_sabm_ua_dcch_sapi0());
1343 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1344 execute(TC_sabm_ua_dcch_sapi3());
1345 execute(TC_sabm_ua_dcch_sapi4());
1346 execute(TC_sabm_contention());
1347 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001348 execute(TC_sabm_retransmit_bts());
1349 execute(TC_sabm_invalid_resp());
1350 execute(TC_sabm_dm());
1351 execute(TC_establish_ign_first_sabm());
1352 execute(TC_iframe_seq_and_ack());
1353 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001354 execute(TC_ns_seq_error());
1355 execute(TC_nr_seq_error());
1356 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001357 execute(TC_segm_concat_dcch());
1358 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001359 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001360 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001361 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001362 execute(TC_sabm_incorrect_c());
Harald Welte72c81e72019-05-30 16:36:11 +02001363}
1364
Harald Weltef6543322017-07-16 07:35:10 +02001365}