blob: a4fa2e8b218fae4e43e56f342b28fc56f35994cb [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 Welte2f2b2b72019-05-31 22:24:57 +020044/* master function switching to a dedicated radio channel */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070045function f_switch_dcch() runs on ConnHdlr {
Vadim Yanitskiy42d8bd52020-11-15 20:41:02 +070046 var GsmBandArfcn arfcn := valueof(ts_GsmBandArfcn(mp_trx_pars[0].arfcn));
Vadim Yanitskiy1acc7bb2020-11-14 04:24:57 +070047 var BCCH_tune_req tune_req := { arfcn := arfcn, combined_ccch := true };
Vadim Yanitskiyca813922020-09-12 19:08:31 +070048 var DCCH_switch_req sw_req;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070049
50 /* Craft channel description (with or without frequency hopping parameters) */
Vadim Yanitskiyca813922020-09-12 19:08:31 +070051 if (g_pars.fhp.enabled) {
Vadim Yanitskiy42d8bd52020-11-15 20:41:02 +070052 sw_req.chan_desc := valueof(ts_ChanDescH1(g_pars.chan_nr,
53 g_pars.fhp.maio_hsn));
Vadim Yanitskiyca813922020-09-12 19:08:31 +070054 sw_req.ma := g_pars.fhp.ma;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070055 } else {
Vadim Yanitskiy42d8bd52020-11-15 20:41:02 +070056 sw_req.chan_desc := valueof(ts_ChanDescH0(g_pars.chan_nr,
57 mp_trx_pars[0].arfcn));
Vadim Yanitskiyca813922020-09-12 19:08:31 +070058 sw_req.ma := omit;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070059 }
Harald Welte2f2b2b72019-05-31 22:24:57 +020060
61 LAPDM.send(tune_req);
62 LAPDM.send(sw_req);
63 LAPDM.receive(DCCH_switch_res:?);
64}
65
Harald Welte72c81e72019-05-30 16:36:11 +020066/* helper function releasing dedicated radio channel physically (no Um signaling!) */
67function f_release_dcch() runs on lapdm_test_CT {
68 var DCCH_release_req rel_req := {};
69 LAPDM.send(rel_req);
70}
71
72template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
73 sacch := sacch,
74 sapi := sapi,
75 lapdm := frame
76}
Harald Weltec38611b2019-05-30 16:33:58 +020077
Eric Wild74f25ae2019-06-14 11:44:29 +020078function 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 +020079 var LAPDm_ph_data phd;
80 var boolean result := false;
81 timer T := 5.0;
82
Eric Wild74f25ae2019-06-14 11:44:29 +020083 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 +020084 T.start
85 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +020086 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { result := true; }
87 [] RSL.receive {repeat;}
88 [] LAPDM.receive { repeat; }
Harald Welte72c81e72019-05-30 16:36:11 +020089 [] T.timeout { }
90 }
Eric Wild74f25ae2019-06-14 11:44:29 +020091 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 +020092 return result;
93}
94
Eric Wild74f25ae2019-06-14 11:44:29 +020095function f_TC_sabm_ua_dcch_sapi0(charstring id) runs on ConnHdlr {
96 fp_common_init();
97 RSL.clear;
98 LAPDM.clear;
99 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200100 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
101 setverdict(fail);
102 }
103 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200104 deactivate(d);
105 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200106}
107
Eric Wild74f25ae2019-06-14 11:44:29 +0200108function f_TC_sabm_ua_dcch_sapi0_nopayload(charstring id) runs on ConnHdlr {
109 fp_common_init();
110 RSL.clear;
111 LAPDM.clear;
112 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200113 if (f_test_sabm_results_in_ua(0, false, ''O)) {
114 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
115 }
116 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200117 deactivate(d);
118 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200119}
120
Eric Wild74f25ae2019-06-14 11:44:29 +0200121function f_TC_sabm_ua_dcch_sapi3(charstring id) runs on ConnHdlr {
122 fp_common_init();
123 RSL.clear;
124 LAPDM.clear;
125 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200126 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
127 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
128 }
129 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200130 deactivate(d);
131 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200132}
133
Eric Wild74f25ae2019-06-14 11:44:29 +0200134function f_TC_sabm_ua_dcch_sapi4(charstring id) runs on ConnHdlr {
135 fp_common_init();
136 RSL.clear;
137 LAPDM.clear;
138 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200139 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
140 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
141 }
142 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200143 deactivate(d);
144 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200145}
146
Eric Wild74f25ae2019-06-14 11:44:29 +0200147testcase TC_sabm_ua_dcch_sapi0() runs on test_CT {
148 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
149 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0));
150}
151
152testcase TC_sabm_ua_dcch_sapi0_nopayload() 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_nopayload));
155}
156
157testcase TC_sabm_ua_dcch_sapi3() 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_sapi3));
160}
161
162testcase TC_sabm_ua_dcch_sapi4() 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_sapi4));
165}
166
167function f_TC_sabm_contention(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200168 var LAPDm_ph_data phd;
169 const octetstring payload := '0102030405'O;
170 const GsmSapi sapi := 0;
171 const boolean use_sacch := false;
172 timer T := 5.0;
173
Eric Wild74f25ae2019-06-14 11:44:29 +0200174 fp_common_init();
175 RSL.clear;
176 LAPDM.clear;
Harald Welte72c81e72019-05-30 16:36:11 +0200177
Harald Welte72c81e72019-05-30 16:36:11 +0200178 /* first frame is our real SABM */
Eric Wild74f25ae2019-06-14 11:44:29 +0200179 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 +0200180 /* 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 +0200181 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 +0200182 T.start
183 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +0200184 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { setverdict(pass); repeat; }
185 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=?))) {
Harald Welte72c81e72019-05-30 16:36:11 +0200186 setverdict(fail, "Second SABM was responded to during contention resolution");
Eric Wild74f25ae2019-06-14 11:44:29 +0200187 }
188 [] RSL.receive {repeat;}
Harald Welte72c81e72019-05-30 16:36:11 +0200189 [] LAPDM.receive { repeat };
190 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200191 }
Eric Wild74f25ae2019-06-14 11:44:29 +0200192
193 fp_common_fini();
194}
195
196testcase TC_sabm_contention() runs on test_CT {
197 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
198 f_testmatrix_each_chan(pars, refers(f_TC_sabm_contention));
Harald Welte72c81e72019-05-30 16:36:11 +0200199}
Harald Welte9e4725d2017-07-16 23:18:09 +0200200
Harald Welte72c81e72019-05-30 16:36:11 +0200201/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
202 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200203function f_TC_sabm_retransmit(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200204 const octetstring payload := '00FEFEDEADBEEF'O;
Eric Wild74f25ae2019-06-14 11:44:29 +0200205 fp_common_init();
206 RSL.clear;
207 LAPDM.clear;
208 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200209 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200210 setverdict(fail);
Harald Welte599faa12017-07-17 21:49:24 +0200211 }
Harald Welte72c81e72019-05-30 16:36:11 +0200212 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200213 setverdict(fail);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200214 }
Harald Welte72c81e72019-05-30 16:36:11 +0200215 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200216 deactivate(d);
217 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200218}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200219
Eric Wild74f25ae2019-06-14 11:44:29 +0200220testcase TC_sabm_retransmit() runs on test_CT {
221 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
222 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit));
Harald Welte72c81e72019-05-30 16:36:11 +0200223}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200224
Harald Welte2f2b2b72019-05-31 22:24:57 +0200225/*********************************************************************************
226 * Test using both L1CTL/LAPDm and RSL
227 *********************************************************************************/
228
229private function fp_common_init() runs on ConnHdlr
230{
231 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
232 unmap(self:L1CTL, system:L1CTL);
233 f_lapdm_init();
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700234
235 /* Obtain frequency hopping parameters for a given timeslot */
236 if (mp_freq_hop_enabled and mp_transceiver_num > 1) {
Vadim Yanitskiyca813922020-09-12 19:08:31 +0700237 f_resolve_fh_params(g_pars.fhp, g_pars.chan_nr.tn);
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700238 }
239
Harald Welte2f2b2b72019-05-31 22:24:57 +0200240 /* activate the channel on the BTS side */
241 f_rsl_chan_act(g_pars.chan_mode, false, {});
242 /* activate the channel on the MS side */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700243 f_switch_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200244}
245
246private function fp_common_fini() runs on ConnHdlr
247{
248 f_release_dcch();
249 f_rsl_chan_deact();
250 f_lapdm_exit();
251}
252
Harald Welte76771f12019-06-02 22:58:58 +0200253/* Mobile-Originated LAPDm establishment on given Link ID */
254private function f_establish_mo(RslLinkId link_id) runs on ConnHdlr
255{
256 var integer sapi := link_id.sapi;
257 var boolean is_sacch := false;
258 if (link_id.c == SACCH) {
259 is_sacch := true;
260 }
261
262 var octetstring l3_mo := f_rnd_octstring(5);
263
264 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
265 if (is_sacch) {
266 /* no payload permitted, as this is not contention resolution */
267 l3_mo := ''O;
268 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
269 RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
270 } else {
271 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
272 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
273 }
274 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
275 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
276}
277
Harald Welte2f2b2b72019-05-31 22:24:57 +0200278/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
279 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
280private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
281 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
282 fp_common_init();
283
284 LAPDM.clear;
285 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
286
287 timer T := 8.0;
288 var integer sabm_received := 0;
289 T.start;
290 alt {
291 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
292 sabm_received := sabm_received + 1;
293 repeat;
294 }
295 [] LAPDM.receive { repeat; }
296 [] T.timeout { }
297 }
298 if (sabm_received == 0) {
299 setverdict(fail, "No SABM observed at all!");
300 } else if (sabm_received != 6) {
301 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
302 sabm_received);
303 } else {
304 setverdict(pass, "Received ", sabm_received, " SABM");
305 }
306
307 fp_common_fini();
308}
309testcase TC_sabm_retransmit_bts() runs on test_CT {
310 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
311 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
312}
313
314
315type record LapdmNamedFrame {
316 charstring name,
317 LapdmFrame lapdm
318};
319
320/* Test that the BTS will ignore receipt of frames other than a UA when
321 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
322 * Section 25.2.1.1.2.3 */
323private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
324 var integer sapi := err_frame.lapdm.ab.addr.sapi;
325 fp_common_init();
326
327 /* Establish Request via RSL; Expect SABM on LAPDm side */
328 LAPDM.clear;
329 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
330 alt {
331 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
332 [] LAPDM.receive { repeat; }
333 }
334
335 /* send erroneous response to SABM */
336 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
337
338 /* expect a SABM retransmission of the BTS */
339 timer T := 3.0;
340 T.start;
341 alt {
342 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
343 setverdict(pass);
344 }
345 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
346 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
347 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
348 err_frame.name);
349 }
350 [] LAPDM.receive { repeat; }
351 [] T.timeout {
352 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
353 err_frame.name);
354 }
355 }
356
357 fp_common_fini();
358}
359private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
360 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
361 var LapdmNamedFrame err_frame[3] := {
362 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
363 l3 := '01020304'O)) },
364 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
365 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
366 };
367 var integer i;
368
369 for (i := 0; i < lengthof(err_frame); i := i+1) {
370 f_TC_sabm_invalid_resp2(id, err_frame[i])
371 }
372}
373testcase TC_sabm_invalid_resp() runs on test_CT {
374 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
375 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
376}
377
378/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
379 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
380private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
381 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
382 fp_common_init();
383
384 /* Establish Request via RSL; Expect SABM on LAPDm side */
385 LAPDM.clear;
386 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
387 alt {
388 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
389 [] LAPDM.receive { repeat; }
390 }
391
392 /* send DM response to SABM */
393 RSL.clear;
394 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
395 alt {
396 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
397 [] RSL.receive { repeat; }
398 }
399
400 /* expect no SABM retransmission of the BTS */
401 timer T := 3.0;
402 T.start;
403 alt {
404 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
405 setverdict(fail, "Received unexpected SABM retransmission");
406 }
407 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
408 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
409 setverdict(fail, "Received unexpected LAPDm frame");
410 }
411 [] LAPDM.receive { repeat; }
412 [] T.timeout {
413 setverdict(pass);
414 }
415 }
416
417 fp_common_fini();
418}
419testcase TC_sabm_dm() runs on test_CT {
420 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
421 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
422}
423
424/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
425 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
426 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
427private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
428 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
429 var integer num_sabm := 0;
430 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
431 timer T := 3.0;
432
433 fp_common_init();
434
435 /* Establish Request via RSL */
436 LAPDM.clear;
437 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
438 /* Expect two SABM (retransmit) */
439 T.start;
440 alt {
441 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
442 num_sabm := num_sabm + 1;
443 if (num_sabm < 2) {
444 repeat;
445 }
446 }
447 [] LAPDM.receive { repeat; }
448 }
449
450 /* send UA response to SABM */
451 RSL.clear;
452 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
453 alt {
454 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
455 [] RSL.receive { repeat; }
456 }
457
458 /* Send I frame from BTS to MS */
459 var octetstring l3 := f_rnd_octstring(10);
460 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
461 alt {
462 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
463 nr:=0, ns:=0, l3:=l3)));
464 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
465 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
466 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
467 }
468 /* Send RR frame in response */
469 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
470
471 /* expect idle UI Frame from BTS */
472 alt {
473 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
474 setverdict(pass);
475 }
476 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
477 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
478 }
479
480 fp_common_fini();
481}
482testcase TC_establish_ign_first_sabm() runs on test_CT {
483 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
484 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
485}
486
487/* ignore all SACCH frames */
488private altstep as_lapdm_acch() runs on ConnHdlr {
489 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
490}
Harald Welteef6fd442019-06-01 21:41:29 +0200491/* ignore all DCCH frames */
492private altstep as_lapdm_dcch() runs on ConnHdlr {
493 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
494}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200495/* ignore all LAPDm idle frames (UI) */
496private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200497 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200498}
499/* ignore all measurement reports */
500private altstep as_rsl_meas_rep() runs on ConnHdlr {
501 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
502}
503/* fail if we receive an RSL ERROR IND */
504private altstep as_rsl_fail_err() runs on ConnHdlr {
505 var RSL_Message rx_rsl;
506 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
507 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
508 }
509}
510/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200511private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200512 [want_dcch] as_lapdm_acch();
513 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200514 [] as_lapdm_idle();
515 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200516 [not ignore_rsl_errors] as_rsl_fail_err();
517 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200518}
519
520/* Test the operation of Layer 2 sequence numbering.
521 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
522private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
523 const integer sapi := 0;
524 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
525 var octetstring l3 := f_rnd_octstring(18);
526 var default d;
527 timer T := 3.0;
528
529 fp_common_init();
530
531 /* some common altstep for meas res and other background noise */
532 d := activate(as_ignore_background());
533 RSL.clear;
534 LAPDM.clear;
535
Harald Welte76771f12019-06-02 22:58:58 +0200536 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200537
538 var integer last_ns_rx := 0;
539
540 for (var integer i := 0; i < 10; i := i+1) {
541 var octetstring l3_mo := f_rnd_octstring(12);
542 var octetstring l3_mt := f_rnd_octstring(12);
543 var LAPDm_ph_data pd;
544
545 log("Starting iteration ", i);
546 /* MT I frame */
547 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
548 alt {
549 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
550 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
551 nr:=i mod 8))) {
552 log("Ignoring RR in iteration ", i);
553 repeat;
554 }
555 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
556 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
557 nr:=i mod 8, ns:=i mod 8,
558 l3:=l3_mt))) -> value pd {
559 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
560 }
561 }
562 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
563 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
564 nr:=(last_ns_rx+1)mod 8,
565 ns:=i mod 8, l3 := l3_mo)));
566 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
567 }
568 log("Completed iteration");
569
570 deactivate(d);
571 fp_common_fini();
572}
573testcase TC_iframe_seq_and_ack() runs on test_CT {
574 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
575 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
576}
577
578/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
579 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
580
581/*
582 1) The BTS is brought into the multiple frame established state
583 2) The MS sends an L3 Request asking for IMEI to the MS.
584 3) The BTS shall respond with a RR frame though this may be incorporated with
585 the L3 Response I frame. The MS does not respond to the I frame.
586 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
587 with the P bit set to 1.
588 5) The MS then sends a valid L3 Request I frame asking for IMEI which
589 does not acknowledge receipt of the I frame from the BTS.
590On the FACCH the BTS may send an RR frame acknowledging the I frame.
591 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
592 the second I frame from the MS.
593 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
594 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
595*/
596private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
597 const integer sapi := 0;
598 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
599 var default d;
600 timer T := 3.0;
601
602 fp_common_init();
603
604 /* some common altstep for meas res and other background noise */
605 d := activate(as_ignore_background());
606 RSL.clear;
607 LAPDM.clear;
608
609 var octetstring l3_mo := f_rnd_octstring(12);
610 var octetstring l3_mt := f_rnd_octstring(12);
611
612 /* 1) The BTS is brought into the multiple frame established state */
613
614 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
615 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
616 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
617 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
618 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
619
620 /* 2) The MS sends an L3 Request to the BTS */
621 l3_mo := f_rnd_octstring(18);
622 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
623 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
624 nr:=0, ns:=0, l3:=l3_mo)));
625 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
626 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
627 the L3 Response I frame. The MS does not respond to the I frame. */
628 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
629 alt {
630 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
631 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
632 repeat;
633 }
634 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
635 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
636 nr:=1, ns:=0, l3:=l3_mt)));
637 }
638
639 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
640 with the P bit set to 1. */
641 /* SAPI = 0, C = 0, P = 1, 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:=true,
643 nr:=1, ns:=0, l3:=l3_mt)));
644
645 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
646 does not acknowledge receipt of the I frame from the BTS. */
647 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
648 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
649 nr:=0, ns:=1, l3 := l3_mo)));
650 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
651 alt {
652 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
653 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
654 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
655 repeat;
656 }
657 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
658 receipt of the second I frame from the MS. */
659 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
660 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
661 nr:=2, ns:=0, l3:=l3_mt)));
662 }
663
664 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
665 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
666 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
667
668 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
669 l3_mt := f_rnd_octstring(16);
670 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
671 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
672 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
673 nr:=2, ns:=1, l3:=l3_mt)));
674 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
675
676 deactivate(d);
677 fp_common_fini();
678}
679testcase TC_iframe_timer_recovery() runs on test_CT {
680 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
681 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
682}
683
Eric Wild211acc32019-06-11 19:06:38 +0200684/* 25.2.6.1 ns sequence error
685sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
686private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
687 const integer sapi := 0;
688 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
689 var default d;
690 timer T := 3.0;
691
692 fp_common_init();
693
694 /* some common altstep for meas res and other background noise */
695 d := activate(as_ignore_background(ignore_rsl_errors := true));
696 RSL.clear;
697 LAPDM.clear;
698
699 var octetstring l3_mo := f_rnd_octstring(12);
700 var octetstring l3_mt := f_rnd_octstring(12);
701
702 /* 1) The BTS is brought into the multiple frame established state */
703
704 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
705 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
706 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
707 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
708 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
709
710 /* 2) The MS sends an L3 Request to the BTS */
711 l3_mo := f_rnd_octstring(18);
712 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
713 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
714 nr:=0, ns:=0, l3:=l3_mo)));
715 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
716 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
717 the L3 Response I frame. */
718 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
719 alt {
720 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
721 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
722 repeat;
723 }
724 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
725 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
726 nr:=1, ns:=0, l3:=l3_mt)));
727 }
728
729 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
730 but correctly acknowledging the MS's I frame; P bit set to zero. */
731 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
732 nr:=1, ns:=0, l3:=l3_mo)));
733
734 /* no rsl data ind due to wrong ns */
735
736 /* The BTS shall send a REJ frame. */
737 timer T1 := 2.0;
738 T1.start;
739 alt{
740 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
741 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
742 }
743
744 f_sleep(2.0); // T200
745
746 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
747 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
748 nr:=1, ns:=0, l3:=l3_mo)));
749
750 /* The BTS shall respond with a REJ, F bit set to 1. */
751 T1.start;
752 alt{
753 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
754 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
755 }
756
757 deactivate(d);
758 fp_common_fini();
759 setverdict(pass);
760}
761
762testcase TC_ns_seq_error() runs on test_CT {
763 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
764 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
765}
766
767/* 25.2.6.2 nr sequence error */
768private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
769 const integer sapi := 0;
770 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
771 var default d;
772 var integer n201 := 20;
773 if (link_id.c == SACCH) {
774 n201 := 18;
775 }
776
777 fp_common_init();
778
779 /* some common altstep for meas res and other background noise */
780 d := activate(as_ignore_background(ignore_rsl_errors := true));
781 RSL.clear;
782 LAPDM.clear;
783
784 var octetstring l3_mo := f_rnd_octstring(12);
785 var octetstring l3_mt := f_rnd_octstring(12);
786
787 /* 1) The BTS is brought into the multiple frame established state */
788
789 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
790 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
791 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
792 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
793 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
794
795 /* 2) The MS shall send an I frame containing an information field of length N201 and an
796 incorrect receive sequence number. */
797 l3_mo := f_rnd_octstring(n201);
798 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
799 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
800 nr:=1, ns:=0, l3:=l3_mo)));
801
802 /* The BTS may: a) send a DISC frame within N200×T200; */
803 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
804 timer T1 := 2.0;
805 T1.start;
806 alt{
807 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
808 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
809 }
810
811 /* a) the MS shall respond with a UA frame.
812 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
813 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
814
815 deactivate(d);
816 fp_common_fini();
817 setverdict(pass);
818}
819
820testcase TC_nr_seq_error() runs on test_CT {
821 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
822 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
823}
824
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100825private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200826 LAPDM.send(t_PH_DATA(0, false, x));
827 f_sleep(2.0); // T200
828 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 +0100829 timer T1 := 2.0;
830 T1.start;
831 alt {
832 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
833 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
834 }
Eric Wild211acc32019-06-11 19:06:38 +0200835}
836
837/* 25.2.7 Test on receipt of invalid frames
838sends a bunch of different invalid frames, expects the BTS to ignore all of them */
839private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
840 const integer sapi := 0;
841 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
842 var default d;
843 timer T := 3.0;
844
845 fp_common_init();
846
847 /* some common altstep for meas res and other background noise */
848 d := activate(as_ignore_background(ignore_rsl_errors := true));
849 RSL.clear;
850 LAPDM.clear;
851
852 var octetstring l3_mo := f_rnd_octstring(12);
853 var octetstring l3_mt := f_rnd_octstring(12);
854
855 /* 1) The BTS is brought into the multiple frame established state */
856
857 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
858 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 +0100859 T.start
860 alt {
861 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
862 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
863 }
864 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200865 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100866 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
867 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
868 }
Eric Wild211acc32019-06-11 19:06:38 +0200869
870 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
871 RR frame with the Length indicator greater than zero and a faulty N(R); */
872 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
873 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100874 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200875 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
876 EJ frame with the EA bit set to zero and a faulty N(R); */
877 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
878 x.ab.addr.ea := false;
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 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
881 SABM frame with the EL bit set to zero; */
882 l3_mo := ''O;
883 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
884 x.ab.el := 0;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100885 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200886 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
887 DM frame with the Length indicator greater than zero;*/
888 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
889 x.ab.payload := f_rnd_octstring(5);
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 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
892 DISC frame with the M bit set to 1; */
893 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
894 x.ab.m := true;
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 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
897 UA frame with the EA bit set to zero*/
898 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
899 x.ab.addr.ea := false;
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 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
902 I frame with the Length indicator greater than N201;*/
903 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 +0100904 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200905 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
906 I frame with the M bit set to 1 and the Length indicator less than N201;*/
907 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
908 x.ab.m := true;
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 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
911 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100912 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200913
914 /* command frames with correct Address and Length indicator field and a non-implemented control field */
915 /* 12: One command frame with Control Field = xxx1 1101. */
916 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
917 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100918 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200919 /* 13: One command frame with Control field = xxx1 1011. */
920 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
921 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100922 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200923 /* 14: One command frame with Control field = xxx1 0111. */
924 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
925 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100926 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200927 /* 15: One command frame with Control field = 01x1 1111. */
928 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
929 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100930 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200931 /* 16: One command frame with Control field = 1xx1 1111. */
932 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
933 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100934 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200935 /* 17: One command frame with Control field = 0011 0011. */
936 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
937 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100938 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200939 /* 18: One command frame with Control field = 1xx1 0011. */
940 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
941 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100942 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200943
944 deactivate(d);
945 fp_common_fini();
946 setverdict(pass);
947}
948
949testcase TC_rec_invalid_frame() runs on test_CT {
950 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
951 pars.t_guard := 60.0;
952 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
953}
954
Harald Welte9ea918c2019-06-01 11:46:25 +0200955type record LapdmDlConfig {
956 integer n201,
957 integer t200
958};
959
960type record LapdmDlState {
961 integer v_s,
962 integer v_a,
963 integer v_r
964};
965
966template (value) LapdmDlState t_init_LapdmDlState := {
967 v_s := 0,
968 v_a := 0,
969 v_r := 0
970}
971
972private function inc_mod8(inout integer v)
973{
974 v := (v + 1) mod 8;
975}
976
977private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
978runs on ConnHdlr {
979 var LAPDm_ph_data pd;
980 var integer offset := 0;
981 var integer n201 := 20;
982 var boolean is_sacch := false;
983 if (link_id.c == SACCH) {
984 n201 := 18;
985 is_sacch := true;
986 }
987
988 while (offset < lengthof(l3)) {
989 var integer remain_len := lengthof(l3) - offset;
990 var integer seg_len := remain_len;
991 if (remain_len > n201) {
992 seg_len := n201;
993 }
994 var octetstring segment := substr(l3, offset, seg_len);
995 var boolean more;
996 if (offset + lengthof(segment) < lengthof(l3)) {
997 more := true;
998 } else {
999 more := false;
1000 }
1001 /* send the next segment */
1002 LAPDM.send(t_PH_DATA(0, is_sacch,
1003 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1004 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1005 inc_mod8(dls.v_s);
1006 offset := offset + lengthof(segment);
1007
1008 /* wait for it to be acknowledged */
1009 alt {
1010 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1011 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001012 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001013 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001014 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("received unexpected LAPDm ", pd));
Harald Welte9ea918c2019-06-01 11:46:25 +02001015 }
1016 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1017 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001018 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "received RSL DATA IND before message complete");
Harald Welte9ea918c2019-06-01 11:46:25 +02001019 }
1020 }
1021 }
1022
1023 timer T := 1.0;
1024 T.start;
1025 alt {
1026 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1027 setverdict(pass);
1028 }
1029 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001030 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received RSL DATA IND with wrong payload");
Harald Welte9ea918c2019-06-01 11:46:25 +02001031 }
1032 [] T.timeout {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001033 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RSL DATA IND of de-segmented message");
Harald Welte9ea918c2019-06-01 11:46:25 +02001034 }
1035 }
1036}
1037
1038/* Section 5.8.5 of TS 04.06 */
1039const integer c_TS0406_MAX_L3_OCTETS := 251;
1040
Harald Welteef6fd442019-06-01 21:41:29 +02001041/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1042 * on specified SAPI/channel */
1043private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1044 var integer sapi := link_id.sapi;
1045 var boolean is_sacch := false;
1046 if (link_id.c == SACCH) {
1047 is_sacch := true;
1048 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001049 var default d;
1050 timer T := 3.0;
1051
1052 fp_common_init();
1053
1054 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001055 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001056 RSL.clear;
1057 LAPDM.clear;
1058
Harald Welte76771f12019-06-02 22:58:58 +02001059 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001060
Harald Welte76771f12019-06-02 22:58:58 +02001061 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001062
1063 deactivate(d);
1064
1065 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1066 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1067
1068 fp_common_fini();
1069}
Harald Welteef6fd442019-06-01 21:41:29 +02001070private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1071 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001072}
Harald Welteef6fd442019-06-01 21:41:29 +02001073private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1074 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1075}
1076/* test mobile-originated segmentation/de-segmentation on DCCH */
1077testcase TC_segm_concat_dcch() runs on test_CT {
1078 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1079 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1080}
1081/* test mobile-originated segmentation/de-segmentation on SACCH */
1082testcase TC_segm_concat_sacch() runs on test_CT {
1083 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1084 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1085}
1086
Harald Welteb2a30342019-06-02 22:13:50 +02001087/* TS 04.06 Section 5.8.2.1 */
1088private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1089 /* SACCH irrespective of physical channel type */
1090 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1091 return 5;
1092 }
1093 /* DCCH below */
1094 select (chan_nr) {
1095 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1096 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1097 case (t_RslChanNr_Bm(?)) { return 34; }
1098 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1099 }
1100 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1101 return -1;
1102}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001103
Harald Welteb2a30342019-06-02 22:13:50 +02001104/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1105private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
1106 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1107 var integer sapi := link_id.sapi;
1108 var boolean is_sacch := false;
1109 if (link_id.c == SACCH) {
1110 is_sacch := true;
1111 }
1112 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1113 var integer num_retrans := 0;
1114 timer T := 3.0;
1115 var default d;
1116
1117 fp_common_init();
1118
1119 /* some common altstep for meas res and other background noise */
1120 d := activate(as_ignore_background(true));
1121 RSL.clear;
1122 LAPDM.clear;
1123
Harald Welte76771f12019-06-02 22:58:58 +02001124 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001125
1126 var octetstring l3_mt := f_rnd_octstring(20);
1127 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1128 /* first transmission, P = 0 */
1129 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1130 nr:=0, ns:=0, l3:=l3_mt)));
1131 deactivate(d);
1132
1133 alt {
1134 /* re-transmission, P = 1 */
1135 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1136 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1137 num_retrans := num_retrans + 1;
1138 if (num_retrans < n200) {
1139 repeat;
1140 } else if (num_retrans == n200) {
1141 T.start; /* wait for some more time if there are more retransmissions */
1142 repeat;
1143 } else {
1144 /* break */
1145 }
1146 }
1147 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
1148 setverdict(fail, "Received unexpected I frame");
1149 }
1150 [not is_sacch] as_lapdm_acch();
1151 [is_sacch] as_lapdm_dcch();
1152 [] as_lapdm_idle();
1153 [] as_rsl_meas_rep();
1154 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1155 /* break */
1156 }
1157 [] T.timeout {
1158 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1159 }
1160 }
1161
1162 if (num_retrans == n200) {
1163 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1164 } else if (num_retrans < n200) {
1165 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1166 " on channel ", g_chan_nr, " link ", link_id);
1167 }
1168
1169 fp_common_fini();
1170}
1171testcase TC_t200_n200() runs on test_CT {
1172 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1173 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1174}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001175
Harald Welte7d9f6db2019-06-02 23:14:04 +02001176/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1177 Inspired by TS 51.010-1 25.2.4.3 */
1178private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1179 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1180 var integer sapi := link_id.sapi;
1181 var boolean is_sacch := false;
1182 if (link_id.c == SACCH) {
1183 is_sacch := true;
1184 }
1185 timer T := 3.0;
1186 var default d;
1187
1188 fp_common_init();
1189
1190 /* some common altstep for meas res and other background noise */
1191 d := activate(as_ignore_background(true));
1192 RSL.clear;
1193 LAPDM.clear;
1194
1195 f_establish_mo(link_id);
1196
1197 var octetstring l3_mo := f_rnd_octstring(10);
1198 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1199 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1200 l3:=l3_mo)));
1201 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1202 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1203 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1204
1205 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1206 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1207 l3:=l3_mo)));
1208
1209 T.start;
1210 alt {
1211 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1212 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1213 setverdict(pass);
1214 }
1215 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1216 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1217 setverdict(pass);
1218 }
1219 [] T.timeout {
1220 setverdict(fail, "Timeout waiting for RR or REJ");
1221 }
1222 }
1223
1224 deactivate(d);
1225
1226 fp_common_fini();
1227}
1228testcase TC_rr_response_frame_loss() runs on test_CT {
1229 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1230 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1231}
1232
Harald Welte44479782019-06-02 23:23:45 +02001233/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1234private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1235 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1236 var integer sapi := link_id.sapi;
1237 var boolean is_sacch := false;
1238 if (link_id.c == SACCH) {
1239 is_sacch := true;
1240 }
1241 timer T := 3.0;
1242 var default d;
1243
1244 fp_common_init();
1245
1246 /* some common altstep for meas res and other background noise */
1247 d := activate(as_ignore_background(true));
1248 RSL.clear;
1249 LAPDM.clear;
1250
1251 f_establish_mo(link_id);
1252
1253 var octetstring l3_mo := f_rnd_octstring(10);
1254 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1255 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1256 l3:=l3_mo)));
1257 T.start;
1258 alt {
1259 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1260 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1261 }
1262 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1263 repeat;
1264 }
1265 /* ensure BTS still sends idle frames */
1266 [] as_lapdm_idle() {
1267 setverdict(pass, "still sending idle frames");
1268 }
1269 [] T.timeout {}
1270 }
1271
1272 /* Send RR command P=1 */
1273 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1274
1275 /* The BTS shall respond with a RR response, F bit set to 1. */
1276 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1277
1278 deactivate(d);
1279
1280 fp_common_fini();
1281}
1282testcase TC_incorrect_cr() runs on test_CT {
1283 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1284 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1285}
Harald Weltea39ac752019-06-04 21:46:07 +02001286
1287/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1288 Inspired by TS 51.010-1 25.2.5.2 */
1289private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1290 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1291 var integer sapi := link_id.sapi;
1292 var boolean is_sacch := false;
1293 if (link_id.c == SACCH) {
1294 is_sacch := true;
1295 }
1296 timer T := 3.0;
1297 var default d;
1298
1299 fp_common_init();
1300
1301 /* some common altstep for meas res and other background noise */
1302 d := activate(as_ignore_background(true));
1303 RSL.clear;
1304 LAPDM.clear;
1305
1306 f_establish_mo(link_id);
1307
1308 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1309 var octetstring l3_mo := '010203'O;
1310 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1311 l3:=l3_mo)));
1312 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1313 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1314 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1315 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1316 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1317 /* Expect RSL ERR IND */
1318 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1319 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1320 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1321 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1322 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1323 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1324 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1325
1326 deactivate(d);
1327
1328 fp_common_fini();
1329}
1330testcase TC_sabm_incorrect_c() runs on test_CT {
1331 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1332 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1333}
1334
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001335/* Test procedure for normal reestablishment, as per:
1336 * OS#4819
1337 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1338 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1339 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1340 * */
1341private function f_TC_normal_reestablishment(charstring id) runs on ConnHdlr {
1342 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1343 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1344 var default d;
1345 timer T := 3.0;
1346 var boolean use_sacch := false;
1347 var boolean received_estind := false;
1348 var boolean received_ua := false;
1349
1350 fp_common_init();
1351
1352 /* some common altstep for meas res and other background noise */
1353 d := activate(as_ignore_background(true));
1354 RSL.clear;
1355 LAPDM.clear;
1356
1357 f_establish_mo(link_id);
1358
1359 deactivate(d);
1360
1361 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1362 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1363
1364 LAPDM.send(t_PH_DATA(link_id.sapi, use_sacch, ts_LAPDm_SABM(link_id.sapi, c_r:=cr_MO_CMD, p:=true, l3:=''O)));
1365 T.start
1366 alt {
1367 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1368 received_ua := true;
1369 if (not received_estind) {
1370 repeat;
1371 }
1372 }
1373 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1374 received_estind := true;
1375 if (not received_ua) {
1376 repeat;
1377 }
1378 }
1379 [] RSL.receive { repeat; }
1380 [] LAPDM.receive { repeat; }
1381 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1382 }
1383
1384 /* Test we can still send data afterwards */
1385 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1386 dls := valueof(t_init_LapdmDlState);
1387 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1388
1389
1390 fp_common_fini();
1391}
1392testcase TC_normal_reestablishment() runs on test_CT {
1393 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1394 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment));
1395}
1396
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001397/* Test procedure for normal reestablishment in state LAPD_STATE_TIMER_RECOV (after T200, waiting for Ack), as per:
1398 * OS#4819
1399 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1400 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1401 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1402 * */
1403private function f_TC_normal_reestablishment_state_unacked(charstring id) runs on ConnHdlr {
1404 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1405 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1406 var octetstring l3_mt := f_rnd_octstring(20);
1407 var LapdmDlState dls;
1408 var default d;
1409 timer T := 3.0;
1410 var boolean use_sacch := false;
1411 var boolean received_estind := false;
1412 var boolean received_ua := false;
1413
1414 fp_common_init();
1415
1416 /* some common altstep for meas res and other background noise */
1417 d := activate(as_ignore_background(true));
1418 RSL.clear;
1419 LAPDM.clear;
1420
1421 f_establish_mo(link_id);
1422 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1423 /* first transmission, P = 0 */
1424 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=false,
1425 nr:=0, ns:=0, l3:=l3_mt)));
1426 /* re-transmission, P = 1 */
1427 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=true,
1428 nr:=0, ns:=0, l3:=l3_mt)));
1429 deactivate(d);
1430
1431 /* We received one retrans, so peer is in LAPD_STATE_TIMER_RECOV state. Now send SABM: */
1432 LAPDM.send(t_PH_DATA(link_id.sapi, use_sacch, ts_LAPDm_SABM(link_id.sapi, c_r:=cr_MO_CMD, p:=true, l3:=''O)));
1433 T.start
1434 alt {
1435 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1436 received_ua := true;
1437 if (not received_estind) {
1438 repeat;
1439 }
1440 }
1441 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1442 received_estind := true;
1443 if (not received_ua) {
1444 repeat;
1445 }
1446 }
1447 [] RSL.receive { repeat; }
1448 [] LAPDM.receive { repeat; }
1449 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1450 }
1451
1452 /* Test we can still send data afterwards */
1453 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1454 dls := valueof(t_init_LapdmDlState);
1455 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1456
1457 fp_common_fini();
1458}
1459testcase TC_normal_reestablishment_state_unacked() runs on test_CT {
1460 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1461 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment_state_unacked));
1462}
1463
Harald Welte72c81e72019-05-30 16:36:11 +02001464control {
Harald Welte72c81e72019-05-30 16:36:11 +02001465 execute(TC_sabm_ua_dcch_sapi0());
1466 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1467 execute(TC_sabm_ua_dcch_sapi3());
1468 execute(TC_sabm_ua_dcch_sapi4());
1469 execute(TC_sabm_contention());
1470 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001471 execute(TC_sabm_retransmit_bts());
1472 execute(TC_sabm_invalid_resp());
1473 execute(TC_sabm_dm());
1474 execute(TC_establish_ign_first_sabm());
1475 execute(TC_iframe_seq_and_ack());
1476 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001477 execute(TC_ns_seq_error());
1478 execute(TC_nr_seq_error());
1479 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001480 execute(TC_segm_concat_dcch());
1481 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001482 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001483 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001484 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001485 execute(TC_sabm_incorrect_c());
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001486 execute(TC_normal_reestablishment());
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001487 execute(TC_normal_reestablishment_state_unacked());
Harald Welte72c81e72019-05-30 16:36:11 +02001488}
1489
Harald Weltef6543322017-07-16 07:35:10 +02001490}