blob: 0e27ad14f7e3622cf9098fedec63122f6b1063b4 [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 };
Vadim Yanitskiyca813922020-09-12 19:08:31 +070057 var DCCH_switch_req sw_req;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070058
59 /* Craft channel description (with or without frequency hopping parameters) */
Vadim Yanitskiyca813922020-09-12 19:08:31 +070060 if (g_pars.fhp.enabled) {
61 sw_req.chan_desc := valueof(ts_ChanDescH1(g_pars.chan_nr, g_pars.fhp.maio_hsn));
62 sw_req.ma := g_pars.fhp.ma;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070063 } else {
64 sw_req.chan_desc := valueof(ts_ChanDescH0(g_pars.chan_nr, mp_trx0_arfcn));
Vadim Yanitskiyca813922020-09-12 19:08:31 +070065 sw_req.ma := omit;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070066 }
Harald Welte2f2b2b72019-05-31 22:24:57 +020067
68 LAPDM.send(tune_req);
69 LAPDM.send(sw_req);
70 LAPDM.receive(DCCH_switch_res:?);
71}
72
Harald Welte72c81e72019-05-30 16:36:11 +020073/* helper function releasing dedicated radio channel physically (no Um signaling!) */
74function f_release_dcch() runs on lapdm_test_CT {
75 var DCCH_release_req rel_req := {};
76 LAPDM.send(rel_req);
77}
78
79template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
80 sacch := sacch,
81 sapi := sapi,
82 lapdm := frame
83}
Harald Weltec38611b2019-05-30 16:33:58 +020084
Eric Wild74f25ae2019-06-14 11:44:29 +020085function 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 +020086 var LAPDm_ph_data phd;
87 var boolean result := false;
88 timer T := 5.0;
89
Eric Wild74f25ae2019-06-14 11:44:29 +020090 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 +020091 T.start
92 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +020093 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { result := true; }
94 [] RSL.receive {repeat;}
95 [] LAPDM.receive { repeat; }
Harald Welte72c81e72019-05-30 16:36:11 +020096 [] T.timeout { }
97 }
Eric Wild74f25ae2019-06-14 11:44:29 +020098 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 +020099 return result;
100}
101
Eric Wild74f25ae2019-06-14 11:44:29 +0200102function f_TC_sabm_ua_dcch_sapi0(charstring id) runs on ConnHdlr {
103 fp_common_init();
104 RSL.clear;
105 LAPDM.clear;
106 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200107 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
108 setverdict(fail);
109 }
110 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200111 deactivate(d);
112 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200113}
114
Eric Wild74f25ae2019-06-14 11:44:29 +0200115function f_TC_sabm_ua_dcch_sapi0_nopayload(charstring id) runs on ConnHdlr {
116 fp_common_init();
117 RSL.clear;
118 LAPDM.clear;
119 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200120 if (f_test_sabm_results_in_ua(0, false, ''O)) {
121 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
122 }
123 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200124 deactivate(d);
125 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200126}
127
Eric Wild74f25ae2019-06-14 11:44:29 +0200128function f_TC_sabm_ua_dcch_sapi3(charstring id) runs on ConnHdlr {
129 fp_common_init();
130 RSL.clear;
131 LAPDM.clear;
132 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200133 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
134 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
135 }
136 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200137 deactivate(d);
138 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200139}
140
Eric Wild74f25ae2019-06-14 11:44:29 +0200141function f_TC_sabm_ua_dcch_sapi4(charstring id) runs on ConnHdlr {
142 fp_common_init();
143 RSL.clear;
144 LAPDM.clear;
145 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200146 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
147 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
148 }
149 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200150 deactivate(d);
151 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200152}
153
Eric Wild74f25ae2019-06-14 11:44:29 +0200154testcase TC_sabm_ua_dcch_sapi0() runs on test_CT {
155 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
156 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0));
157}
158
159testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on test_CT {
160 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
161 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0_nopayload));
162}
163
164testcase TC_sabm_ua_dcch_sapi3() runs on test_CT {
165 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
166 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi3));
167}
168
169testcase TC_sabm_ua_dcch_sapi4() runs on test_CT {
170 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
171 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi4));
172}
173
174function f_TC_sabm_contention(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200175 var LAPDm_ph_data phd;
176 const octetstring payload := '0102030405'O;
177 const GsmSapi sapi := 0;
178 const boolean use_sacch := false;
179 timer T := 5.0;
180
Eric Wild74f25ae2019-06-14 11:44:29 +0200181 fp_common_init();
182 RSL.clear;
183 LAPDM.clear;
Harald Welte72c81e72019-05-30 16:36:11 +0200184
Harald Welte72c81e72019-05-30 16:36:11 +0200185 /* first frame is our real SABM */
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:=payload)));
Harald Welte72c81e72019-05-30 16:36:11 +0200187 /* 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 +0200188 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 +0200189 T.start
190 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +0200191 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { setverdict(pass); repeat; }
192 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=?))) {
Harald Welte72c81e72019-05-30 16:36:11 +0200193 setverdict(fail, "Second SABM was responded to during contention resolution");
Eric Wild74f25ae2019-06-14 11:44:29 +0200194 }
195 [] RSL.receive {repeat;}
Harald Welte72c81e72019-05-30 16:36:11 +0200196 [] LAPDM.receive { repeat };
197 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200198 }
Eric Wild74f25ae2019-06-14 11:44:29 +0200199
200 fp_common_fini();
201}
202
203testcase TC_sabm_contention() runs on test_CT {
204 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
205 f_testmatrix_each_chan(pars, refers(f_TC_sabm_contention));
Harald Welte72c81e72019-05-30 16:36:11 +0200206}
Harald Welte9e4725d2017-07-16 23:18:09 +0200207
Harald Welte72c81e72019-05-30 16:36:11 +0200208/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
209 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200210function f_TC_sabm_retransmit(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200211 const octetstring payload := '00FEFEDEADBEEF'O;
Eric Wild74f25ae2019-06-14 11:44:29 +0200212 fp_common_init();
213 RSL.clear;
214 LAPDM.clear;
215 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200216 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200217 setverdict(fail);
Harald Welte599faa12017-07-17 21:49:24 +0200218 }
Harald Welte72c81e72019-05-30 16:36:11 +0200219 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200220 setverdict(fail);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200221 }
Harald Welte72c81e72019-05-30 16:36:11 +0200222 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200223 deactivate(d);
224 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200225}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200226
Eric Wild74f25ae2019-06-14 11:44:29 +0200227testcase TC_sabm_retransmit() runs on test_CT {
228 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
229 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit));
Harald Welte72c81e72019-05-30 16:36:11 +0200230}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200231
Harald Welte2f2b2b72019-05-31 22:24:57 +0200232/*********************************************************************************
233 * Test using both L1CTL/LAPDm and RSL
234 *********************************************************************************/
235
236private function fp_common_init() runs on ConnHdlr
237{
238 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
239 unmap(self:L1CTL, system:L1CTL);
240 f_lapdm_init();
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700241
242 /* Obtain frequency hopping parameters for a given timeslot */
243 if (mp_freq_hop_enabled and mp_transceiver_num > 1) {
Vadim Yanitskiyca813922020-09-12 19:08:31 +0700244 f_resolve_fh_params(g_pars.fhp, g_pars.chan_nr.tn);
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700245 }
246
Harald Welte2f2b2b72019-05-31 22:24:57 +0200247 /* activate the channel on the BTS side */
248 f_rsl_chan_act(g_pars.chan_mode, false, {});
249 /* activate the channel on the MS side */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700250 f_switch_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200251}
252
253private function fp_common_fini() runs on ConnHdlr
254{
255 f_release_dcch();
256 f_rsl_chan_deact();
257 f_lapdm_exit();
258}
259
Harald Welte76771f12019-06-02 22:58:58 +0200260/* Mobile-Originated LAPDm establishment on given Link ID */
261private function f_establish_mo(RslLinkId link_id) runs on ConnHdlr
262{
263 var integer sapi := link_id.sapi;
264 var boolean is_sacch := false;
265 if (link_id.c == SACCH) {
266 is_sacch := true;
267 }
268
269 var octetstring l3_mo := f_rnd_octstring(5);
270
271 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
272 if (is_sacch) {
273 /* no payload permitted, as this is not contention resolution */
274 l3_mo := ''O;
275 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
276 RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
277 } else {
278 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
279 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
280 }
281 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
282 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
283}
284
Harald Welte2f2b2b72019-05-31 22:24:57 +0200285/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
286 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
287private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
288 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
289 fp_common_init();
290
291 LAPDM.clear;
292 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
293
294 timer T := 8.0;
295 var integer sabm_received := 0;
296 T.start;
297 alt {
298 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
299 sabm_received := sabm_received + 1;
300 repeat;
301 }
302 [] LAPDM.receive { repeat; }
303 [] T.timeout { }
304 }
305 if (sabm_received == 0) {
306 setverdict(fail, "No SABM observed at all!");
307 } else if (sabm_received != 6) {
308 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
309 sabm_received);
310 } else {
311 setverdict(pass, "Received ", sabm_received, " SABM");
312 }
313
314 fp_common_fini();
315}
316testcase TC_sabm_retransmit_bts() runs on test_CT {
317 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
318 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
319}
320
321
322type record LapdmNamedFrame {
323 charstring name,
324 LapdmFrame lapdm
325};
326
327/* Test that the BTS will ignore receipt of frames other than a UA when
328 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
329 * Section 25.2.1.1.2.3 */
330private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
331 var integer sapi := err_frame.lapdm.ab.addr.sapi;
332 fp_common_init();
333
334 /* Establish Request via RSL; Expect SABM on LAPDm side */
335 LAPDM.clear;
336 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
337 alt {
338 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
339 [] LAPDM.receive { repeat; }
340 }
341
342 /* send erroneous response to SABM */
343 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
344
345 /* expect a SABM retransmission of the BTS */
346 timer T := 3.0;
347 T.start;
348 alt {
349 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
350 setverdict(pass);
351 }
352 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
353 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
354 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
355 err_frame.name);
356 }
357 [] LAPDM.receive { repeat; }
358 [] T.timeout {
359 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
360 err_frame.name);
361 }
362 }
363
364 fp_common_fini();
365}
366private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
367 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
368 var LapdmNamedFrame err_frame[3] := {
369 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
370 l3 := '01020304'O)) },
371 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
372 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
373 };
374 var integer i;
375
376 for (i := 0; i < lengthof(err_frame); i := i+1) {
377 f_TC_sabm_invalid_resp2(id, err_frame[i])
378 }
379}
380testcase TC_sabm_invalid_resp() runs on test_CT {
381 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
382 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
383}
384
385/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
386 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
387private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
388 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
389 fp_common_init();
390
391 /* Establish Request via RSL; Expect SABM on LAPDm side */
392 LAPDM.clear;
393 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
394 alt {
395 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
396 [] LAPDM.receive { repeat; }
397 }
398
399 /* send DM response to SABM */
400 RSL.clear;
401 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
402 alt {
403 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
404 [] RSL.receive { repeat; }
405 }
406
407 /* expect no SABM retransmission of the BTS */
408 timer T := 3.0;
409 T.start;
410 alt {
411 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
412 setverdict(fail, "Received unexpected SABM retransmission");
413 }
414 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
415 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
416 setverdict(fail, "Received unexpected LAPDm frame");
417 }
418 [] LAPDM.receive { repeat; }
419 [] T.timeout {
420 setverdict(pass);
421 }
422 }
423
424 fp_common_fini();
425}
426testcase TC_sabm_dm() runs on test_CT {
427 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
428 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
429}
430
431/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
432 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
433 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
434private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
435 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
436 var integer num_sabm := 0;
437 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
438 timer T := 3.0;
439
440 fp_common_init();
441
442 /* Establish Request via RSL */
443 LAPDM.clear;
444 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
445 /* Expect two SABM (retransmit) */
446 T.start;
447 alt {
448 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
449 num_sabm := num_sabm + 1;
450 if (num_sabm < 2) {
451 repeat;
452 }
453 }
454 [] LAPDM.receive { repeat; }
455 }
456
457 /* send UA response to SABM */
458 RSL.clear;
459 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
460 alt {
461 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
462 [] RSL.receive { repeat; }
463 }
464
465 /* Send I frame from BTS to MS */
466 var octetstring l3 := f_rnd_octstring(10);
467 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
468 alt {
469 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
470 nr:=0, ns:=0, l3:=l3)));
471 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
472 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
473 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
474 }
475 /* Send RR frame in response */
476 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
477
478 /* expect idle UI Frame from BTS */
479 alt {
480 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
481 setverdict(pass);
482 }
483 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
484 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
485 }
486
487 fp_common_fini();
488}
489testcase TC_establish_ign_first_sabm() runs on test_CT {
490 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
491 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
492}
493
494/* ignore all SACCH frames */
495private altstep as_lapdm_acch() runs on ConnHdlr {
496 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
497}
Harald Welteef6fd442019-06-01 21:41:29 +0200498/* ignore all DCCH frames */
499private altstep as_lapdm_dcch() runs on ConnHdlr {
500 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
501}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200502/* ignore all LAPDm idle frames (UI) */
503private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200504 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200505}
506/* ignore all measurement reports */
507private altstep as_rsl_meas_rep() runs on ConnHdlr {
508 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
509}
510/* fail if we receive an RSL ERROR IND */
511private altstep as_rsl_fail_err() runs on ConnHdlr {
512 var RSL_Message rx_rsl;
513 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
514 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
515 }
516}
517/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200518private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200519 [want_dcch] as_lapdm_acch();
520 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200521 [] as_lapdm_idle();
522 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200523 [not ignore_rsl_errors] as_rsl_fail_err();
524 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200525}
526
527/* Test the operation of Layer 2 sequence numbering.
528 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
529private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
530 const integer sapi := 0;
531 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
532 var octetstring l3 := f_rnd_octstring(18);
533 var default d;
534 timer T := 3.0;
535
536 fp_common_init();
537
538 /* some common altstep for meas res and other background noise */
539 d := activate(as_ignore_background());
540 RSL.clear;
541 LAPDM.clear;
542
Harald Welte76771f12019-06-02 22:58:58 +0200543 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200544
545 var integer last_ns_rx := 0;
546
547 for (var integer i := 0; i < 10; i := i+1) {
548 var octetstring l3_mo := f_rnd_octstring(12);
549 var octetstring l3_mt := f_rnd_octstring(12);
550 var LAPDm_ph_data pd;
551
552 log("Starting iteration ", i);
553 /* MT I frame */
554 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
555 alt {
556 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
557 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
558 nr:=i mod 8))) {
559 log("Ignoring RR in iteration ", i);
560 repeat;
561 }
562 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
563 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
564 nr:=i mod 8, ns:=i mod 8,
565 l3:=l3_mt))) -> value pd {
566 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
567 }
568 }
569 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
570 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
571 nr:=(last_ns_rx+1)mod 8,
572 ns:=i mod 8, l3 := l3_mo)));
573 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
574 }
575 log("Completed iteration");
576
577 deactivate(d);
578 fp_common_fini();
579}
580testcase TC_iframe_seq_and_ack() runs on test_CT {
581 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
582 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
583}
584
585/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
586 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
587
588/*
589 1) The BTS is brought into the multiple frame established state
590 2) The MS sends an L3 Request asking for IMEI to the MS.
591 3) The BTS shall respond with a RR frame though this may be incorporated with
592 the L3 Response I frame. The MS does not respond to the I frame.
593 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
594 with the P bit set to 1.
595 5) The MS then sends a valid L3 Request I frame asking for IMEI which
596 does not acknowledge receipt of the I frame from the BTS.
597On the FACCH the BTS may send an RR frame acknowledging the I frame.
598 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
599 the second I frame from the MS.
600 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
601 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
602*/
603private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
604 const integer sapi := 0;
605 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
606 var default d;
607 timer T := 3.0;
608
609 fp_common_init();
610
611 /* some common altstep for meas res and other background noise */
612 d := activate(as_ignore_background());
613 RSL.clear;
614 LAPDM.clear;
615
616 var octetstring l3_mo := f_rnd_octstring(12);
617 var octetstring l3_mt := f_rnd_octstring(12);
618
619 /* 1) The BTS is brought into the multiple frame established state */
620
621 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
622 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
623 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
624 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
625 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
626
627 /* 2) The MS sends an L3 Request to the BTS */
628 l3_mo := f_rnd_octstring(18);
629 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
630 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
631 nr:=0, ns:=0, l3:=l3_mo)));
632 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
633 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
634 the L3 Response I frame. The MS does not respond to the I frame. */
635 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
636 alt {
637 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
638 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
639 repeat;
640 }
641 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
642 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
643 nr:=1, ns:=0, l3:=l3_mt)));
644 }
645
646 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
647 with the P bit set to 1. */
648 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
649 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
650 nr:=1, ns:=0, l3:=l3_mt)));
651
652 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
653 does not acknowledge receipt of the I frame from the BTS. */
654 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
655 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
656 nr:=0, ns:=1, l3 := l3_mo)));
657 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
658 alt {
659 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
660 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
661 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
662 repeat;
663 }
664 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
665 receipt of the second I frame from the MS. */
666 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
667 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
668 nr:=2, ns:=0, l3:=l3_mt)));
669 }
670
671 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
672 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
673 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
674
675 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
676 l3_mt := f_rnd_octstring(16);
677 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
678 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
679 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
680 nr:=2, ns:=1, l3:=l3_mt)));
681 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
682
683 deactivate(d);
684 fp_common_fini();
685}
686testcase TC_iframe_timer_recovery() runs on test_CT {
687 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
688 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
689}
690
Eric Wild211acc32019-06-11 19:06:38 +0200691/* 25.2.6.1 ns sequence error
692sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
693private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
694 const integer sapi := 0;
695 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
696 var default d;
697 timer T := 3.0;
698
699 fp_common_init();
700
701 /* some common altstep for meas res and other background noise */
702 d := activate(as_ignore_background(ignore_rsl_errors := true));
703 RSL.clear;
704 LAPDM.clear;
705
706 var octetstring l3_mo := f_rnd_octstring(12);
707 var octetstring l3_mt := f_rnd_octstring(12);
708
709 /* 1) The BTS is brought into the multiple frame established state */
710
711 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
712 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
713 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
714 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
715 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
716
717 /* 2) The MS sends an L3 Request to the BTS */
718 l3_mo := f_rnd_octstring(18);
719 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
720 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
721 nr:=0, ns:=0, l3:=l3_mo)));
722 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
723 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
724 the L3 Response I frame. */
725 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
726 alt {
727 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
728 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
729 repeat;
730 }
731 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
732 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
733 nr:=1, ns:=0, l3:=l3_mt)));
734 }
735
736 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
737 but correctly acknowledging the MS's I frame; P bit set to zero. */
738 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
739 nr:=1, ns:=0, l3:=l3_mo)));
740
741 /* no rsl data ind due to wrong ns */
742
743 /* The BTS shall send a REJ frame. */
744 timer T1 := 2.0;
745 T1.start;
746 alt{
747 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
748 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
749 }
750
751 f_sleep(2.0); // T200
752
753 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
754 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
755 nr:=1, ns:=0, l3:=l3_mo)));
756
757 /* The BTS shall respond with a REJ, F bit set to 1. */
758 T1.start;
759 alt{
760 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
761 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
762 }
763
764 deactivate(d);
765 fp_common_fini();
766 setverdict(pass);
767}
768
769testcase TC_ns_seq_error() runs on test_CT {
770 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
771 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
772}
773
774/* 25.2.6.2 nr sequence error */
775private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
776 const integer sapi := 0;
777 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
778 var default d;
779 var integer n201 := 20;
780 if (link_id.c == SACCH) {
781 n201 := 18;
782 }
783
784 fp_common_init();
785
786 /* some common altstep for meas res and other background noise */
787 d := activate(as_ignore_background(ignore_rsl_errors := true));
788 RSL.clear;
789 LAPDM.clear;
790
791 var octetstring l3_mo := f_rnd_octstring(12);
792 var octetstring l3_mt := f_rnd_octstring(12);
793
794 /* 1) The BTS is brought into the multiple frame established state */
795
796 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
797 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
798 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
799 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
800 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
801
802 /* 2) The MS shall send an I frame containing an information field of length N201 and an
803 incorrect receive sequence number. */
804 l3_mo := f_rnd_octstring(n201);
805 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
806 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
807 nr:=1, ns:=0, l3:=l3_mo)));
808
809 /* The BTS may: a) send a DISC frame within N200×T200; */
810 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
811 timer T1 := 2.0;
812 T1.start;
813 alt{
814 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
815 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
816 }
817
818 /* a) the MS shall respond with a UA frame.
819 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
820 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
821
822 deactivate(d);
823 fp_common_fini();
824 setverdict(pass);
825}
826
827testcase TC_nr_seq_error() runs on test_CT {
828 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
829 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
830}
831
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100832private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200833 LAPDM.send(t_PH_DATA(0, false, x));
834 f_sleep(2.0); // T200
835 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 +0100836 timer T1 := 2.0;
837 T1.start;
838 alt {
839 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
840 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
841 }
Eric Wild211acc32019-06-11 19:06:38 +0200842}
843
844/* 25.2.7 Test on receipt of invalid frames
845sends a bunch of different invalid frames, expects the BTS to ignore all of them */
846private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
847 const integer sapi := 0;
848 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
849 var default d;
850 timer T := 3.0;
851
852 fp_common_init();
853
854 /* some common altstep for meas res and other background noise */
855 d := activate(as_ignore_background(ignore_rsl_errors := true));
856 RSL.clear;
857 LAPDM.clear;
858
859 var octetstring l3_mo := f_rnd_octstring(12);
860 var octetstring l3_mt := f_rnd_octstring(12);
861
862 /* 1) The BTS is brought into the multiple frame established state */
863
864 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
865 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 +0100866 T.start
867 alt {
868 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
869 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
870 }
871 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200872 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100873 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
874 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
875 }
Eric Wild211acc32019-06-11 19:06:38 +0200876
877 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
878 RR frame with the Length indicator greater than zero and a faulty N(R); */
879 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
880 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100881 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200882 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
883 EJ frame with the EA bit set to zero and a faulty N(R); */
884 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
885 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100886 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200887 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
888 SABM frame with the EL bit set to zero; */
889 l3_mo := ''O;
890 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
891 x.ab.el := 0;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100892 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200893 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
894 DM frame with the Length indicator greater than zero;*/
895 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
896 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100897 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200898 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
899 DISC frame with the M bit set to 1; */
900 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
901 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100902 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200903 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
904 UA frame with the EA bit set to zero*/
905 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
906 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100907 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200908 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
909 I frame with the Length indicator greater than N201;*/
910 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 +0100911 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200912 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
913 I frame with the M bit set to 1 and the Length indicator less than N201;*/
914 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
915 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100916 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200917 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
918 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100919 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200920
921 /* command frames with correct Address and Length indicator field and a non-implemented control field */
922 /* 12: One command frame with Control Field = xxx1 1101. */
923 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
924 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100925 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200926 /* 13: One command frame with Control field = xxx1 1011. */
927 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
928 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100929 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200930 /* 14: One command frame with Control field = xxx1 0111. */
931 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
932 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100933 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200934 /* 15: One command frame with Control field = 01x1 1111. */
935 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
936 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100937 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200938 /* 16: One command frame with Control field = 1xx1 1111. */
939 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
940 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100941 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200942 /* 17: One command frame with Control field = 0011 0011. */
943 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
944 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100945 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200946 /* 18: One command frame with Control field = 1xx1 0011. */
947 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
948 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100949 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200950
951 deactivate(d);
952 fp_common_fini();
953 setverdict(pass);
954}
955
956testcase TC_rec_invalid_frame() runs on test_CT {
957 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
958 pars.t_guard := 60.0;
959 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
960}
961
Harald Welte9ea918c2019-06-01 11:46:25 +0200962type record LapdmDlConfig {
963 integer n201,
964 integer t200
965};
966
967type record LapdmDlState {
968 integer v_s,
969 integer v_a,
970 integer v_r
971};
972
973template (value) LapdmDlState t_init_LapdmDlState := {
974 v_s := 0,
975 v_a := 0,
976 v_r := 0
977}
978
979private function inc_mod8(inout integer v)
980{
981 v := (v + 1) mod 8;
982}
983
984private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
985runs on ConnHdlr {
986 var LAPDm_ph_data pd;
987 var integer offset := 0;
988 var integer n201 := 20;
989 var boolean is_sacch := false;
990 if (link_id.c == SACCH) {
991 n201 := 18;
992 is_sacch := true;
993 }
994
995 while (offset < lengthof(l3)) {
996 var integer remain_len := lengthof(l3) - offset;
997 var integer seg_len := remain_len;
998 if (remain_len > n201) {
999 seg_len := n201;
1000 }
1001 var octetstring segment := substr(l3, offset, seg_len);
1002 var boolean more;
1003 if (offset + lengthof(segment) < lengthof(l3)) {
1004 more := true;
1005 } else {
1006 more := false;
1007 }
1008 /* send the next segment */
1009 LAPDM.send(t_PH_DATA(0, is_sacch,
1010 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1011 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1012 inc_mod8(dls.v_s);
1013 offset := offset + lengthof(segment);
1014
1015 /* wait for it to be acknowledged */
1016 alt {
1017 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1018 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001019 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001020 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
1021 setverdict(fail, "received unexpected LAPDm ", pd);
1022 repeat;
1023 }
1024 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1025 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1026 setverdict(fail, "received RSL DATA IND before message complete");
1027 }
1028 }
1029 }
1030
1031 timer T := 1.0;
1032 T.start;
1033 alt {
1034 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1035 setverdict(pass);
1036 }
1037 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
1038 setverdict(fail, "Received RSL DATA IND with wrong payload");
1039 }
1040 [] T.timeout {
1041 setverdict(fail, "Timeout waiting for RSL DATA IND of de-segmented message");
1042 }
1043 }
1044}
1045
1046/* Section 5.8.5 of TS 04.06 */
1047const integer c_TS0406_MAX_L3_OCTETS := 251;
1048
Harald Welteef6fd442019-06-01 21:41:29 +02001049/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1050 * on specified SAPI/channel */
1051private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1052 var integer sapi := link_id.sapi;
1053 var boolean is_sacch := false;
1054 if (link_id.c == SACCH) {
1055 is_sacch := true;
1056 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001057 var default d;
1058 timer T := 3.0;
1059
1060 fp_common_init();
1061
1062 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001063 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001064 RSL.clear;
1065 LAPDM.clear;
1066
Harald Welte76771f12019-06-02 22:58:58 +02001067 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001068
Harald Welte76771f12019-06-02 22:58:58 +02001069 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001070
1071 deactivate(d);
1072
1073 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1074 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1075
1076 fp_common_fini();
1077}
Harald Welteef6fd442019-06-01 21:41:29 +02001078private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1079 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001080}
Harald Welteef6fd442019-06-01 21:41:29 +02001081private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1082 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1083}
1084/* test mobile-originated segmentation/de-segmentation on DCCH */
1085testcase TC_segm_concat_dcch() runs on test_CT {
1086 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1087 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1088}
1089/* test mobile-originated segmentation/de-segmentation on SACCH */
1090testcase TC_segm_concat_sacch() runs on test_CT {
1091 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1092 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1093}
1094
Harald Welteb2a30342019-06-02 22:13:50 +02001095/* TS 04.06 Section 5.8.2.1 */
1096private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1097 /* SACCH irrespective of physical channel type */
1098 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1099 return 5;
1100 }
1101 /* DCCH below */
1102 select (chan_nr) {
1103 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1104 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1105 case (t_RslChanNr_Bm(?)) { return 34; }
1106 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1107 }
1108 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1109 return -1;
1110}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001111
Harald Welteb2a30342019-06-02 22:13:50 +02001112/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1113private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
1114 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1115 var integer sapi := link_id.sapi;
1116 var boolean is_sacch := false;
1117 if (link_id.c == SACCH) {
1118 is_sacch := true;
1119 }
1120 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1121 var integer num_retrans := 0;
1122 timer T := 3.0;
1123 var default d;
1124
1125 fp_common_init();
1126
1127 /* some common altstep for meas res and other background noise */
1128 d := activate(as_ignore_background(true));
1129 RSL.clear;
1130 LAPDM.clear;
1131
Harald Welte76771f12019-06-02 22:58:58 +02001132 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001133
1134 var octetstring l3_mt := f_rnd_octstring(20);
1135 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1136 /* first transmission, P = 0 */
1137 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1138 nr:=0, ns:=0, l3:=l3_mt)));
1139 deactivate(d);
1140
1141 alt {
1142 /* re-transmission, P = 1 */
1143 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1144 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1145 num_retrans := num_retrans + 1;
1146 if (num_retrans < n200) {
1147 repeat;
1148 } else if (num_retrans == n200) {
1149 T.start; /* wait for some more time if there are more retransmissions */
1150 repeat;
1151 } else {
1152 /* break */
1153 }
1154 }
1155 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
1156 setverdict(fail, "Received unexpected I frame");
1157 }
1158 [not is_sacch] as_lapdm_acch();
1159 [is_sacch] as_lapdm_dcch();
1160 [] as_lapdm_idle();
1161 [] as_rsl_meas_rep();
1162 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1163 /* break */
1164 }
1165 [] T.timeout {
1166 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1167 }
1168 }
1169
1170 if (num_retrans == n200) {
1171 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1172 } else if (num_retrans < n200) {
1173 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1174 " on channel ", g_chan_nr, " link ", link_id);
1175 }
1176
1177 fp_common_fini();
1178}
1179testcase TC_t200_n200() runs on test_CT {
1180 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1181 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1182}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001183
Harald Welte7d9f6db2019-06-02 23:14:04 +02001184/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1185 Inspired by TS 51.010-1 25.2.4.3 */
1186private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1187 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1188 var integer sapi := link_id.sapi;
1189 var boolean is_sacch := false;
1190 if (link_id.c == SACCH) {
1191 is_sacch := true;
1192 }
1193 timer T := 3.0;
1194 var default d;
1195
1196 fp_common_init();
1197
1198 /* some common altstep for meas res and other background noise */
1199 d := activate(as_ignore_background(true));
1200 RSL.clear;
1201 LAPDM.clear;
1202
1203 f_establish_mo(link_id);
1204
1205 var octetstring l3_mo := f_rnd_octstring(10);
1206 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1207 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1208 l3:=l3_mo)));
1209 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1210 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1211 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1212
1213 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1214 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1215 l3:=l3_mo)));
1216
1217 T.start;
1218 alt {
1219 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1220 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1221 setverdict(pass);
1222 }
1223 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1224 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1225 setverdict(pass);
1226 }
1227 [] T.timeout {
1228 setverdict(fail, "Timeout waiting for RR or REJ");
1229 }
1230 }
1231
1232 deactivate(d);
1233
1234 fp_common_fini();
1235}
1236testcase TC_rr_response_frame_loss() runs on test_CT {
1237 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1238 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1239}
1240
Harald Welte44479782019-06-02 23:23:45 +02001241/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1242private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1243 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1244 var integer sapi := link_id.sapi;
1245 var boolean is_sacch := false;
1246 if (link_id.c == SACCH) {
1247 is_sacch := true;
1248 }
1249 timer T := 3.0;
1250 var default d;
1251
1252 fp_common_init();
1253
1254 /* some common altstep for meas res and other background noise */
1255 d := activate(as_ignore_background(true));
1256 RSL.clear;
1257 LAPDM.clear;
1258
1259 f_establish_mo(link_id);
1260
1261 var octetstring l3_mo := f_rnd_octstring(10);
1262 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1263 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1264 l3:=l3_mo)));
1265 T.start;
1266 alt {
1267 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1268 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1269 }
1270 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1271 repeat;
1272 }
1273 /* ensure BTS still sends idle frames */
1274 [] as_lapdm_idle() {
1275 setverdict(pass, "still sending idle frames");
1276 }
1277 [] T.timeout {}
1278 }
1279
1280 /* Send RR command P=1 */
1281 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1282
1283 /* The BTS shall respond with a RR response, F bit set to 1. */
1284 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1285
1286 deactivate(d);
1287
1288 fp_common_fini();
1289}
1290testcase TC_incorrect_cr() runs on test_CT {
1291 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1292 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1293}
Harald Weltea39ac752019-06-04 21:46:07 +02001294
1295/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1296 Inspired by TS 51.010-1 25.2.5.2 */
1297private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1298 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1299 var integer sapi := link_id.sapi;
1300 var boolean is_sacch := false;
1301 if (link_id.c == SACCH) {
1302 is_sacch := true;
1303 }
1304 timer T := 3.0;
1305 var default d;
1306
1307 fp_common_init();
1308
1309 /* some common altstep for meas res and other background noise */
1310 d := activate(as_ignore_background(true));
1311 RSL.clear;
1312 LAPDM.clear;
1313
1314 f_establish_mo(link_id);
1315
1316 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1317 var octetstring l3_mo := '010203'O;
1318 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1319 l3:=l3_mo)));
1320 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1321 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1322 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1323 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1324 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1325 /* Expect RSL ERR IND */
1326 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1327 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1328 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1329 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1330 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1331 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1332 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1333
1334 deactivate(d);
1335
1336 fp_common_fini();
1337}
1338testcase TC_sabm_incorrect_c() runs on test_CT {
1339 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1340 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1341}
1342
Harald Welte72c81e72019-05-30 16:36:11 +02001343control {
Harald Welte72c81e72019-05-30 16:36:11 +02001344 execute(TC_sabm_ua_dcch_sapi0());
1345 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1346 execute(TC_sabm_ua_dcch_sapi3());
1347 execute(TC_sabm_ua_dcch_sapi4());
1348 execute(TC_sabm_contention());
1349 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001350 execute(TC_sabm_retransmit_bts());
1351 execute(TC_sabm_invalid_resp());
1352 execute(TC_sabm_dm());
1353 execute(TC_establish_ign_first_sabm());
1354 execute(TC_iframe_seq_and_ack());
1355 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001356 execute(TC_ns_seq_error());
1357 execute(TC_nr_seq_error());
1358 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001359 execute(TC_segm_concat_dcch());
1360 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001361 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001362 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001363 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001364 execute(TC_sabm_incorrect_c());
Harald Welte72c81e72019-05-30 16:36:11 +02001365}
1366
Harald Weltef6543322017-07-16 07:35:10 +02001367}