blob: 6d252e0af054af541fcf4c9a6533f5d8c1209724 [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,
Vadim Yanitskiy3191d732020-11-15 20:45:01 +070053 g_pars.fhp.maio_hsn,
54 g_pars.tsc));
Vadim Yanitskiyca813922020-09-12 19:08:31 +070055 sw_req.ma := g_pars.fhp.ma;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070056 } else {
Vadim Yanitskiy42d8bd52020-11-15 20:41:02 +070057 sw_req.chan_desc := valueof(ts_ChanDescH0(g_pars.chan_nr,
Vadim Yanitskiy3191d732020-11-15 20:45:01 +070058 mp_trx_pars[0].arfcn,
59 g_pars.tsc));
Vadim Yanitskiyca813922020-09-12 19:08:31 +070060 sw_req.ma := omit;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070061 }
Harald Welte2f2b2b72019-05-31 22:24:57 +020062
63 LAPDM.send(tune_req);
64 LAPDM.send(sw_req);
65 LAPDM.receive(DCCH_switch_res:?);
66}
67
Harald Welte72c81e72019-05-30 16:36:11 +020068/* helper function releasing dedicated radio channel physically (no Um signaling!) */
69function f_release_dcch() runs on lapdm_test_CT {
70 var DCCH_release_req rel_req := {};
71 LAPDM.send(rel_req);
72}
73
74template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
75 sacch := sacch,
76 sapi := sapi,
77 lapdm := frame
78}
Harald Weltec38611b2019-05-30 16:33:58 +020079
Eric Wild74f25ae2019-06-14 11:44:29 +020080function 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 +020081 var LAPDm_ph_data phd;
82 var boolean result := false;
83 timer T := 5.0;
84
Eric Wild74f25ae2019-06-14 11:44:29 +020085 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 +020086 T.start
87 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +020088 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { result := true; }
89 [] RSL.receive {repeat;}
90 [] LAPDM.receive { repeat; }
Harald Welte72c81e72019-05-30 16:36:11 +020091 [] T.timeout { }
92 }
Eric Wild74f25ae2019-06-14 11:44:29 +020093 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 +020094 return result;
95}
96
Eric Wild74f25ae2019-06-14 11:44:29 +020097function f_TC_sabm_ua_dcch_sapi0(charstring id) runs on ConnHdlr {
98 fp_common_init();
99 RSL.clear;
100 LAPDM.clear;
101 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200102 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
103 setverdict(fail);
104 }
105 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200106 deactivate(d);
107 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200108}
109
Eric Wild74f25ae2019-06-14 11:44:29 +0200110function f_TC_sabm_ua_dcch_sapi0_nopayload(charstring id) runs on ConnHdlr {
111 fp_common_init();
112 RSL.clear;
113 LAPDM.clear;
114 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200115 if (f_test_sabm_results_in_ua(0, false, ''O)) {
116 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
117 }
118 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200119 deactivate(d);
120 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200121}
122
Eric Wild74f25ae2019-06-14 11:44:29 +0200123function f_TC_sabm_ua_dcch_sapi3(charstring id) runs on ConnHdlr {
124 fp_common_init();
125 RSL.clear;
126 LAPDM.clear;
127 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200128 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
129 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
130 }
131 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200132 deactivate(d);
133 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200134}
135
Eric Wild74f25ae2019-06-14 11:44:29 +0200136function f_TC_sabm_ua_dcch_sapi4(charstring id) runs on ConnHdlr {
137 fp_common_init();
138 RSL.clear;
139 LAPDM.clear;
140 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200141 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
142 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
143 }
144 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200145 deactivate(d);
146 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200147}
148
Eric Wild74f25ae2019-06-14 11:44:29 +0200149testcase TC_sabm_ua_dcch_sapi0() runs on test_CT {
150 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
151 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi0));
152}
153
154testcase TC_sabm_ua_dcch_sapi0_nopayload() 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_nopayload));
157}
158
159testcase TC_sabm_ua_dcch_sapi3() 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_sapi3));
162}
163
164testcase TC_sabm_ua_dcch_sapi4() 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_sapi4));
167}
168
169function f_TC_sabm_contention(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200170 var LAPDm_ph_data phd;
171 const octetstring payload := '0102030405'O;
172 const GsmSapi sapi := 0;
173 const boolean use_sacch := false;
174 timer T := 5.0;
175
Eric Wild74f25ae2019-06-14 11:44:29 +0200176 fp_common_init();
177 RSL.clear;
178 LAPDM.clear;
Harald Welte72c81e72019-05-30 16:36:11 +0200179
Harald Welte72c81e72019-05-30 16:36:11 +0200180 /* first frame is our real SABM */
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:=payload)));
Harald Welte72c81e72019-05-30 16:36:11 +0200182 /* 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 +0200183 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 +0200184 T.start
185 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +0200186 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { setverdict(pass); repeat; }
187 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=?))) {
Harald Welte72c81e72019-05-30 16:36:11 +0200188 setverdict(fail, "Second SABM was responded to during contention resolution");
Eric Wild74f25ae2019-06-14 11:44:29 +0200189 }
190 [] RSL.receive {repeat;}
Harald Welte72c81e72019-05-30 16:36:11 +0200191 [] LAPDM.receive { repeat };
192 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200193 }
Eric Wild74f25ae2019-06-14 11:44:29 +0200194
195 fp_common_fini();
196}
197
198testcase TC_sabm_contention() runs on test_CT {
199 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
200 f_testmatrix_each_chan(pars, refers(f_TC_sabm_contention));
Harald Welte72c81e72019-05-30 16:36:11 +0200201}
Harald Welte9e4725d2017-07-16 23:18:09 +0200202
Harald Welte72c81e72019-05-30 16:36:11 +0200203/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
204 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200205function f_TC_sabm_retransmit(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200206 const octetstring payload := '00FEFEDEADBEEF'O;
Eric Wild74f25ae2019-06-14 11:44:29 +0200207 fp_common_init();
208 RSL.clear;
209 LAPDM.clear;
210 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200211 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200212 setverdict(fail);
Harald Welte599faa12017-07-17 21:49:24 +0200213 }
Harald Welte72c81e72019-05-30 16:36:11 +0200214 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200215 setverdict(fail);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200216 }
Harald Welte72c81e72019-05-30 16:36:11 +0200217 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200218 deactivate(d);
219 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200220}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200221
Eric Wild74f25ae2019-06-14 11:44:29 +0200222testcase TC_sabm_retransmit() runs on test_CT {
223 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
224 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit));
Harald Welte72c81e72019-05-30 16:36:11 +0200225}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200226
Harald Welte2f2b2b72019-05-31 22:24:57 +0200227/*********************************************************************************
228 * Test using both L1CTL/LAPDm and RSL
229 *********************************************************************************/
230
231private function fp_common_init() runs on ConnHdlr
232{
233 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
234 unmap(self:L1CTL, system:L1CTL);
235 f_lapdm_init();
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700236
237 /* Obtain frequency hopping parameters for a given timeslot */
238 if (mp_freq_hop_enabled and mp_transceiver_num > 1) {
Vadim Yanitskiyca813922020-09-12 19:08:31 +0700239 f_resolve_fh_params(g_pars.fhp, g_pars.chan_nr.tn);
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700240 }
241
Harald Welte2f2b2b72019-05-31 22:24:57 +0200242 /* activate the channel on the BTS side */
243 f_rsl_chan_act(g_pars.chan_mode, false, {});
244 /* activate the channel on the MS side */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700245 f_switch_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200246}
247
248private function fp_common_fini() runs on ConnHdlr
249{
250 f_release_dcch();
251 f_rsl_chan_deact();
252 f_lapdm_exit();
253}
254
Harald Welte76771f12019-06-02 22:58:58 +0200255/* Mobile-Originated LAPDm establishment on given Link ID */
256private function f_establish_mo(RslLinkId link_id) runs on ConnHdlr
257{
258 var integer sapi := link_id.sapi;
259 var boolean is_sacch := false;
260 if (link_id.c == SACCH) {
261 is_sacch := true;
262 }
263
264 var octetstring l3_mo := f_rnd_octstring(5);
265
266 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
267 if (is_sacch) {
268 /* no payload permitted, as this is not contention resolution */
269 l3_mo := ''O;
270 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
271 RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
272 } else {
273 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
274 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
275 }
276 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
277 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
278}
279
Harald Welte2f2b2b72019-05-31 22:24:57 +0200280/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
281 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
282private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
283 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
284 fp_common_init();
285
286 LAPDM.clear;
287 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
288
289 timer T := 8.0;
290 var integer sabm_received := 0;
291 T.start;
292 alt {
293 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
294 sabm_received := sabm_received + 1;
295 repeat;
296 }
297 [] LAPDM.receive { repeat; }
298 [] T.timeout { }
299 }
300 if (sabm_received == 0) {
301 setverdict(fail, "No SABM observed at all!");
302 } else if (sabm_received != 6) {
303 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
304 sabm_received);
305 } else {
306 setverdict(pass, "Received ", sabm_received, " SABM");
307 }
308
309 fp_common_fini();
310}
311testcase TC_sabm_retransmit_bts() runs on test_CT {
312 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
313 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
314}
315
316
317type record LapdmNamedFrame {
318 charstring name,
319 LapdmFrame lapdm
320};
321
322/* Test that the BTS will ignore receipt of frames other than a UA when
323 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
324 * Section 25.2.1.1.2.3 */
325private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
326 var integer sapi := err_frame.lapdm.ab.addr.sapi;
327 fp_common_init();
328
329 /* Establish Request via RSL; Expect SABM on LAPDm side */
330 LAPDM.clear;
331 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
332 alt {
333 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
334 [] LAPDM.receive { repeat; }
335 }
336
337 /* send erroneous response to SABM */
338 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
339
340 /* expect a SABM retransmission of the BTS */
341 timer T := 3.0;
342 T.start;
343 alt {
344 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
345 setverdict(pass);
346 }
347 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
348 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
349 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
350 err_frame.name);
351 }
352 [] LAPDM.receive { repeat; }
353 [] T.timeout {
354 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
355 err_frame.name);
356 }
357 }
358
359 fp_common_fini();
360}
361private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
362 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
363 var LapdmNamedFrame err_frame[3] := {
364 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
365 l3 := '01020304'O)) },
366 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
367 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
368 };
369 var integer i;
370
371 for (i := 0; i < lengthof(err_frame); i := i+1) {
372 f_TC_sabm_invalid_resp2(id, err_frame[i])
373 }
374}
375testcase TC_sabm_invalid_resp() runs on test_CT {
376 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
377 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
378}
379
380/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
381 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
382private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
383 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
384 fp_common_init();
385
386 /* Establish Request via RSL; Expect SABM on LAPDm side */
387 LAPDM.clear;
388 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
389 alt {
390 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
391 [] LAPDM.receive { repeat; }
392 }
393
394 /* send DM response to SABM */
395 RSL.clear;
396 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
397 alt {
398 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
399 [] RSL.receive { repeat; }
400 }
401
402 /* expect no SABM retransmission of the BTS */
403 timer T := 3.0;
404 T.start;
405 alt {
406 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
407 setverdict(fail, "Received unexpected SABM retransmission");
408 }
409 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
410 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
411 setverdict(fail, "Received unexpected LAPDm frame");
412 }
413 [] LAPDM.receive { repeat; }
414 [] T.timeout {
415 setverdict(pass);
416 }
417 }
418
419 fp_common_fini();
420}
421testcase TC_sabm_dm() runs on test_CT {
422 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
423 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
424}
425
426/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
427 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
428 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
429private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
430 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
431 var integer num_sabm := 0;
432 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
433 timer T := 3.0;
434
435 fp_common_init();
436
437 /* Establish Request via RSL */
438 LAPDM.clear;
439 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
440 /* Expect two SABM (retransmit) */
441 T.start;
442 alt {
443 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
444 num_sabm := num_sabm + 1;
445 if (num_sabm < 2) {
446 repeat;
447 }
448 }
449 [] LAPDM.receive { repeat; }
450 }
451
452 /* send UA response to SABM */
453 RSL.clear;
454 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
455 alt {
456 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
457 [] RSL.receive { repeat; }
458 }
459
460 /* Send I frame from BTS to MS */
461 var octetstring l3 := f_rnd_octstring(10);
462 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
463 alt {
464 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
465 nr:=0, ns:=0, l3:=l3)));
466 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
467 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
468 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
469 }
470 /* Send RR frame in response */
471 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
472
473 /* expect idle UI Frame from BTS */
474 alt {
475 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
476 setverdict(pass);
477 }
478 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
479 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
480 }
481
482 fp_common_fini();
483}
484testcase TC_establish_ign_first_sabm() runs on test_CT {
485 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
486 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
487}
488
489/* ignore all SACCH frames */
490private altstep as_lapdm_acch() runs on ConnHdlr {
491 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
492}
Harald Welteef6fd442019-06-01 21:41:29 +0200493/* ignore all DCCH frames */
494private altstep as_lapdm_dcch() runs on ConnHdlr {
495 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
496}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200497/* ignore all LAPDm idle frames (UI) */
498private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200499 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200500}
501/* ignore all measurement reports */
502private altstep as_rsl_meas_rep() runs on ConnHdlr {
503 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
504}
505/* fail if we receive an RSL ERROR IND */
506private altstep as_rsl_fail_err() runs on ConnHdlr {
507 var RSL_Message rx_rsl;
508 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
509 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
510 }
511}
512/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200513private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200514 [want_dcch] as_lapdm_acch();
515 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200516 [] as_lapdm_idle();
517 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200518 [not ignore_rsl_errors] as_rsl_fail_err();
519 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200520}
521
522/* Test the operation of Layer 2 sequence numbering.
523 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
524private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
525 const integer sapi := 0;
526 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
527 var octetstring l3 := f_rnd_octstring(18);
528 var default d;
529 timer T := 3.0;
530
531 fp_common_init();
532
533 /* some common altstep for meas res and other background noise */
534 d := activate(as_ignore_background());
535 RSL.clear;
536 LAPDM.clear;
537
Harald Welte76771f12019-06-02 22:58:58 +0200538 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200539
540 var integer last_ns_rx := 0;
541
542 for (var integer i := 0; i < 10; i := i+1) {
543 var octetstring l3_mo := f_rnd_octstring(12);
544 var octetstring l3_mt := f_rnd_octstring(12);
545 var LAPDm_ph_data pd;
546
547 log("Starting iteration ", i);
548 /* MT I frame */
549 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
550 alt {
551 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
552 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
553 nr:=i mod 8))) {
554 log("Ignoring RR in iteration ", i);
555 repeat;
556 }
557 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
558 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
559 nr:=i mod 8, ns:=i mod 8,
560 l3:=l3_mt))) -> value pd {
561 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
562 }
563 }
564 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
565 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
566 nr:=(last_ns_rx+1)mod 8,
567 ns:=i mod 8, l3 := l3_mo)));
568 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
569 }
570 log("Completed iteration");
571
572 deactivate(d);
573 fp_common_fini();
574}
575testcase TC_iframe_seq_and_ack() runs on test_CT {
576 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
577 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
578}
579
580/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
581 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
582
583/*
584 1) The BTS is brought into the multiple frame established state
585 2) The MS sends an L3 Request asking for IMEI to the MS.
586 3) The BTS shall respond with a RR frame though this may be incorporated with
587 the L3 Response I frame. The MS does not respond to the I frame.
588 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
589 with the P bit set to 1.
590 5) The MS then sends a valid L3 Request I frame asking for IMEI which
591 does not acknowledge receipt of the I frame from the BTS.
592On the FACCH the BTS may send an RR frame acknowledging the I frame.
593 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
594 the second I frame from the MS.
595 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
596 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
597*/
598private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
599 const integer sapi := 0;
600 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
601 var default d;
602 timer T := 3.0;
603
604 fp_common_init();
605
606 /* some common altstep for meas res and other background noise */
607 d := activate(as_ignore_background());
608 RSL.clear;
609 LAPDM.clear;
610
611 var octetstring l3_mo := f_rnd_octstring(12);
612 var octetstring l3_mt := f_rnd_octstring(12);
613
614 /* 1) The BTS is brought into the multiple frame established state */
615
616 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
617 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
618 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
619 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
620 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
621
622 /* 2) The MS sends an L3 Request to the BTS */
623 l3_mo := f_rnd_octstring(18);
624 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
625 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
626 nr:=0, ns:=0, l3:=l3_mo)));
627 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
628 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
629 the L3 Response I frame. The MS does not respond to the I frame. */
630 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
631 alt {
632 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
633 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
634 repeat;
635 }
636 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
637 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
638 nr:=1, ns:=0, l3:=l3_mt)));
639 }
640
641 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
642 with the P bit set to 1. */
643 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
644 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
645 nr:=1, ns:=0, l3:=l3_mt)));
646
647 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
648 does not acknowledge receipt of the I frame from the BTS. */
649 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
650 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
651 nr:=0, ns:=1, l3 := l3_mo)));
652 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
653 alt {
654 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
655 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
656 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
657 repeat;
658 }
659 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
660 receipt of the second I frame from the MS. */
661 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
662 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
663 nr:=2, ns:=0, l3:=l3_mt)));
664 }
665
666 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
667 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
668 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
669
670 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
671 l3_mt := f_rnd_octstring(16);
672 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
673 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
674 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
675 nr:=2, ns:=1, l3:=l3_mt)));
676 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
677
678 deactivate(d);
679 fp_common_fini();
680}
681testcase TC_iframe_timer_recovery() runs on test_CT {
682 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
683 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
684}
685
Eric Wild211acc32019-06-11 19:06:38 +0200686/* 25.2.6.1 ns sequence error
687sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
688private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
689 const integer sapi := 0;
690 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
691 var default d;
692 timer T := 3.0;
693
694 fp_common_init();
695
696 /* some common altstep for meas res and other background noise */
697 d := activate(as_ignore_background(ignore_rsl_errors := true));
698 RSL.clear;
699 LAPDM.clear;
700
701 var octetstring l3_mo := f_rnd_octstring(12);
702 var octetstring l3_mt := f_rnd_octstring(12);
703
704 /* 1) The BTS is brought into the multiple frame established state */
705
706 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
707 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
708 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
709 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
710 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
711
712 /* 2) The MS sends an L3 Request to the BTS */
713 l3_mo := f_rnd_octstring(18);
714 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
715 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
716 nr:=0, ns:=0, l3:=l3_mo)));
717 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
718 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
719 the L3 Response I frame. */
720 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
721 alt {
722 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
723 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
724 repeat;
725 }
726 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
727 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
728 nr:=1, ns:=0, l3:=l3_mt)));
729 }
730
731 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
732 but correctly acknowledging the MS's I frame; P bit set to zero. */
733 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
734 nr:=1, ns:=0, l3:=l3_mo)));
735
736 /* no rsl data ind due to wrong ns */
737
738 /* The BTS shall send a REJ frame. */
739 timer T1 := 2.0;
740 T1.start;
741 alt{
742 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
743 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
744 }
745
746 f_sleep(2.0); // T200
747
748 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
749 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
750 nr:=1, ns:=0, l3:=l3_mo)));
751
752 /* The BTS shall respond with a REJ, F bit set to 1. */
753 T1.start;
754 alt{
755 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
756 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
757 }
758
759 deactivate(d);
760 fp_common_fini();
761 setverdict(pass);
762}
763
764testcase TC_ns_seq_error() runs on test_CT {
765 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
766 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
767}
768
769/* 25.2.6.2 nr sequence error */
770private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
771 const integer sapi := 0;
772 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
773 var default d;
774 var integer n201 := 20;
775 if (link_id.c == SACCH) {
776 n201 := 18;
777 }
778
779 fp_common_init();
780
781 /* some common altstep for meas res and other background noise */
782 d := activate(as_ignore_background(ignore_rsl_errors := true));
783 RSL.clear;
784 LAPDM.clear;
785
786 var octetstring l3_mo := f_rnd_octstring(12);
787 var octetstring l3_mt := f_rnd_octstring(12);
788
789 /* 1) The BTS is brought into the multiple frame established state */
790
791 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
792 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
793 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
794 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
795 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
796
797 /* 2) The MS shall send an I frame containing an information field of length N201 and an
798 incorrect receive sequence number. */
799 l3_mo := f_rnd_octstring(n201);
800 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
801 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
802 nr:=1, ns:=0, l3:=l3_mo)));
803
804 /* The BTS may: a) send a DISC frame within N200×T200; */
805 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
806 timer T1 := 2.0;
807 T1.start;
808 alt{
809 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
810 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
811 }
812
813 /* a) the MS shall respond with a UA frame.
814 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
815 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
816
817 deactivate(d);
818 fp_common_fini();
819 setverdict(pass);
820}
821
822testcase TC_nr_seq_error() runs on test_CT {
823 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
824 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
825}
826
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100827private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200828 LAPDM.send(t_PH_DATA(0, false, x));
829 f_sleep(2.0); // T200
830 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 +0100831 timer T1 := 2.0;
832 T1.start;
833 alt {
834 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
835 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
836 }
Eric Wild211acc32019-06-11 19:06:38 +0200837}
838
839/* 25.2.7 Test on receipt of invalid frames
840sends a bunch of different invalid frames, expects the BTS to ignore all of them */
841private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
842 const integer sapi := 0;
843 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
844 var default d;
845 timer T := 3.0;
846
847 fp_common_init();
848
849 /* some common altstep for meas res and other background noise */
850 d := activate(as_ignore_background(ignore_rsl_errors := true));
851 RSL.clear;
852 LAPDM.clear;
853
854 var octetstring l3_mo := f_rnd_octstring(12);
855 var octetstring l3_mt := f_rnd_octstring(12);
856
857 /* 1) The BTS is brought into the multiple frame established state */
858
859 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
860 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 +0100861 T.start
862 alt {
863 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
864 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
865 }
866 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200867 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100868 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
869 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
870 }
Eric Wild211acc32019-06-11 19:06:38 +0200871
872 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
873 RR frame with the Length indicator greater than zero and a faulty N(R); */
874 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
875 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100876 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200877 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
878 EJ frame with the EA bit set to zero and a faulty N(R); */
879 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
880 x.ab.addr.ea := false;
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 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
883 SABM frame with the EL bit set to zero; */
884 l3_mo := ''O;
885 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
886 x.ab.el := 0;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100887 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200888 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
889 DM frame with the Length indicator greater than zero;*/
890 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
891 x.ab.payload := f_rnd_octstring(5);
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 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
894 DISC frame with the M bit set to 1; */
895 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
896 x.ab.m := true;
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 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
899 UA frame with the EA bit set to zero*/
900 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
901 x.ab.addr.ea := false;
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 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
904 I frame with the Length indicator greater than N201;*/
905 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 +0100906 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200907 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
908 I frame with the M bit set to 1 and the Length indicator less than N201;*/
909 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
910 x.ab.m := true;
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 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
913 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100914 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200915
916 /* command frames with correct Address and Length indicator field and a non-implemented control field */
917 /* 12: One command frame with Control Field = xxx1 1101. */
918 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
919 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100920 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200921 /* 13: One command frame with Control field = xxx1 1011. */
922 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
923 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100924 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200925 /* 14: One command frame with Control field = xxx1 0111. */
926 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
927 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100928 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200929 /* 15: One command frame with Control field = 01x1 1111. */
930 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
931 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100932 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200933 /* 16: One command frame with Control field = 1xx1 1111. */
934 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
935 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100936 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200937 /* 17: One command frame with Control field = 0011 0011. */
938 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
939 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100940 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200941 /* 18: One command frame with Control field = 1xx1 0011. */
942 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
943 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100944 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200945
946 deactivate(d);
947 fp_common_fini();
948 setverdict(pass);
949}
950
951testcase TC_rec_invalid_frame() runs on test_CT {
952 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
953 pars.t_guard := 60.0;
954 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
955}
956
Harald Welte9ea918c2019-06-01 11:46:25 +0200957type record LapdmDlConfig {
958 integer n201,
959 integer t200
960};
961
962type record LapdmDlState {
963 integer v_s,
964 integer v_a,
965 integer v_r
966};
967
968template (value) LapdmDlState t_init_LapdmDlState := {
969 v_s := 0,
970 v_a := 0,
971 v_r := 0
972}
973
974private function inc_mod8(inout integer v)
975{
976 v := (v + 1) mod 8;
977}
978
979private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
980runs on ConnHdlr {
981 var LAPDm_ph_data pd;
982 var integer offset := 0;
983 var integer n201 := 20;
984 var boolean is_sacch := false;
985 if (link_id.c == SACCH) {
986 n201 := 18;
987 is_sacch := true;
988 }
989
990 while (offset < lengthof(l3)) {
991 var integer remain_len := lengthof(l3) - offset;
992 var integer seg_len := remain_len;
993 if (remain_len > n201) {
994 seg_len := n201;
995 }
996 var octetstring segment := substr(l3, offset, seg_len);
997 var boolean more;
998 if (offset + lengthof(segment) < lengthof(l3)) {
999 more := true;
1000 } else {
1001 more := false;
1002 }
1003 /* send the next segment */
1004 LAPDM.send(t_PH_DATA(0, is_sacch,
1005 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1006 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1007 inc_mod8(dls.v_s);
1008 offset := offset + lengthof(segment);
1009
1010 /* wait for it to be acknowledged */
1011 alt {
1012 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1013 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001014 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001015 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001016 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("received unexpected LAPDm ", pd));
Harald Welte9ea918c2019-06-01 11:46:25 +02001017 }
1018 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1019 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001020 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "received RSL DATA IND before message complete");
Harald Welte9ea918c2019-06-01 11:46:25 +02001021 }
1022 }
1023 }
1024
1025 timer T := 1.0;
1026 T.start;
1027 alt {
1028 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1029 setverdict(pass);
1030 }
1031 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001032 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received RSL DATA IND with wrong payload");
Harald Welte9ea918c2019-06-01 11:46:25 +02001033 }
1034 [] T.timeout {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001035 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RSL DATA IND of de-segmented message");
Harald Welte9ea918c2019-06-01 11:46:25 +02001036 }
1037 }
1038}
1039
1040/* Section 5.8.5 of TS 04.06 */
1041const integer c_TS0406_MAX_L3_OCTETS := 251;
1042
Harald Welteef6fd442019-06-01 21:41:29 +02001043/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1044 * on specified SAPI/channel */
1045private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1046 var integer sapi := link_id.sapi;
1047 var boolean is_sacch := false;
1048 if (link_id.c == SACCH) {
1049 is_sacch := true;
1050 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001051 var default d;
1052 timer T := 3.0;
1053
1054 fp_common_init();
1055
1056 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001057 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001058 RSL.clear;
1059 LAPDM.clear;
1060
Harald Welte76771f12019-06-02 22:58:58 +02001061 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001062
Harald Welte76771f12019-06-02 22:58:58 +02001063 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001064
1065 deactivate(d);
1066
1067 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1068 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1069
1070 fp_common_fini();
1071}
Harald Welteef6fd442019-06-01 21:41:29 +02001072private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1073 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001074}
Harald Welteef6fd442019-06-01 21:41:29 +02001075private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1076 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1077}
1078/* test mobile-originated segmentation/de-segmentation on DCCH */
1079testcase TC_segm_concat_dcch() runs on test_CT {
1080 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1081 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1082}
1083/* test mobile-originated segmentation/de-segmentation on SACCH */
1084testcase TC_segm_concat_sacch() runs on test_CT {
1085 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1086 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1087}
1088
Harald Welteb2a30342019-06-02 22:13:50 +02001089/* TS 04.06 Section 5.8.2.1 */
1090private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1091 /* SACCH irrespective of physical channel type */
1092 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1093 return 5;
1094 }
1095 /* DCCH below */
1096 select (chan_nr) {
1097 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1098 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1099 case (t_RslChanNr_Bm(?)) { return 34; }
1100 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1101 }
1102 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1103 return -1;
1104}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001105
Harald Welteb2a30342019-06-02 22:13:50 +02001106/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1107private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
1108 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1109 var integer sapi := link_id.sapi;
1110 var boolean is_sacch := false;
1111 if (link_id.c == SACCH) {
1112 is_sacch := true;
1113 }
1114 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1115 var integer num_retrans := 0;
1116 timer T := 3.0;
1117 var default d;
1118
1119 fp_common_init();
1120
1121 /* some common altstep for meas res and other background noise */
1122 d := activate(as_ignore_background(true));
1123 RSL.clear;
1124 LAPDM.clear;
1125
Harald Welte76771f12019-06-02 22:58:58 +02001126 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001127
1128 var octetstring l3_mt := f_rnd_octstring(20);
1129 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1130 /* first transmission, P = 0 */
1131 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1132 nr:=0, ns:=0, l3:=l3_mt)));
1133 deactivate(d);
1134
1135 alt {
1136 /* re-transmission, P = 1 */
1137 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1138 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1139 num_retrans := num_retrans + 1;
1140 if (num_retrans < n200) {
1141 repeat;
1142 } else if (num_retrans == n200) {
1143 T.start; /* wait for some more time if there are more retransmissions */
1144 repeat;
1145 } else {
1146 /* break */
1147 }
1148 }
1149 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
1150 setverdict(fail, "Received unexpected I frame");
1151 }
1152 [not is_sacch] as_lapdm_acch();
1153 [is_sacch] as_lapdm_dcch();
1154 [] as_lapdm_idle();
1155 [] as_rsl_meas_rep();
1156 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1157 /* break */
1158 }
1159 [] T.timeout {
1160 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1161 }
1162 }
1163
1164 if (num_retrans == n200) {
1165 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1166 } else if (num_retrans < n200) {
1167 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1168 " on channel ", g_chan_nr, " link ", link_id);
1169 }
1170
1171 fp_common_fini();
1172}
1173testcase TC_t200_n200() runs on test_CT {
1174 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1175 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1176}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001177
Harald Welte7d9f6db2019-06-02 23:14:04 +02001178/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1179 Inspired by TS 51.010-1 25.2.4.3 */
1180private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1181 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1182 var integer sapi := link_id.sapi;
1183 var boolean is_sacch := false;
1184 if (link_id.c == SACCH) {
1185 is_sacch := true;
1186 }
1187 timer T := 3.0;
1188 var default d;
1189
1190 fp_common_init();
1191
1192 /* some common altstep for meas res and other background noise */
1193 d := activate(as_ignore_background(true));
1194 RSL.clear;
1195 LAPDM.clear;
1196
1197 f_establish_mo(link_id);
1198
1199 var octetstring l3_mo := f_rnd_octstring(10);
1200 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1201 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1202 l3:=l3_mo)));
1203 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1204 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1205 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1206
1207 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1208 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1209 l3:=l3_mo)));
1210
1211 T.start;
1212 alt {
1213 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1214 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1215 setverdict(pass);
1216 }
1217 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1218 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1219 setverdict(pass);
1220 }
1221 [] T.timeout {
1222 setverdict(fail, "Timeout waiting for RR or REJ");
1223 }
1224 }
1225
1226 deactivate(d);
1227
1228 fp_common_fini();
1229}
1230testcase TC_rr_response_frame_loss() runs on test_CT {
1231 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1232 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1233}
1234
Harald Welte44479782019-06-02 23:23:45 +02001235/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1236private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1237 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1238 var integer sapi := link_id.sapi;
1239 var boolean is_sacch := false;
1240 if (link_id.c == SACCH) {
1241 is_sacch := true;
1242 }
1243 timer T := 3.0;
1244 var default d;
1245
1246 fp_common_init();
1247
1248 /* some common altstep for meas res and other background noise */
1249 d := activate(as_ignore_background(true));
1250 RSL.clear;
1251 LAPDM.clear;
1252
1253 f_establish_mo(link_id);
1254
1255 var octetstring l3_mo := f_rnd_octstring(10);
1256 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1257 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1258 l3:=l3_mo)));
1259 T.start;
1260 alt {
1261 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1262 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1263 }
1264 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1265 repeat;
1266 }
1267 /* ensure BTS still sends idle frames */
1268 [] as_lapdm_idle() {
1269 setverdict(pass, "still sending idle frames");
1270 }
1271 [] T.timeout {}
1272 }
1273
1274 /* Send RR command P=1 */
1275 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1276
1277 /* The BTS shall respond with a RR response, F bit set to 1. */
1278 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1279
1280 deactivate(d);
1281
1282 fp_common_fini();
1283}
1284testcase TC_incorrect_cr() runs on test_CT {
1285 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1286 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1287}
Harald Weltea39ac752019-06-04 21:46:07 +02001288
1289/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1290 Inspired by TS 51.010-1 25.2.5.2 */
1291private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1292 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1293 var integer sapi := link_id.sapi;
1294 var boolean is_sacch := false;
1295 if (link_id.c == SACCH) {
1296 is_sacch := true;
1297 }
1298 timer T := 3.0;
1299 var default d;
1300
1301 fp_common_init();
1302
1303 /* some common altstep for meas res and other background noise */
1304 d := activate(as_ignore_background(true));
1305 RSL.clear;
1306 LAPDM.clear;
1307
1308 f_establish_mo(link_id);
1309
1310 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1311 var octetstring l3_mo := '010203'O;
1312 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1313 l3:=l3_mo)));
1314 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1315 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1316 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1317 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1318 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1319 /* Expect RSL ERR IND */
1320 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1321 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1322 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1323 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1324 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1325 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1326 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1327
1328 deactivate(d);
1329
1330 fp_common_fini();
1331}
1332testcase TC_sabm_incorrect_c() runs on test_CT {
1333 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1334 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1335}
1336
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001337/* Test procedure for normal reestablishment, as per:
1338 * OS#4819
1339 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1340 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1341 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1342 * */
1343private function f_TC_normal_reestablishment(charstring id) runs on ConnHdlr {
1344 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1345 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1346 var default d;
1347 timer T := 3.0;
1348 var boolean use_sacch := false;
1349 var boolean received_estind := false;
1350 var boolean received_ua := false;
1351
1352 fp_common_init();
1353
1354 /* some common altstep for meas res and other background noise */
1355 d := activate(as_ignore_background(true));
1356 RSL.clear;
1357 LAPDM.clear;
1358
1359 f_establish_mo(link_id);
1360
1361 deactivate(d);
1362
1363 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1364 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1365
1366 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)));
1367 T.start
1368 alt {
1369 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1370 received_ua := true;
1371 if (not received_estind) {
1372 repeat;
1373 }
1374 }
1375 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1376 received_estind := true;
1377 if (not received_ua) {
1378 repeat;
1379 }
1380 }
1381 [] RSL.receive { repeat; }
1382 [] LAPDM.receive { repeat; }
1383 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1384 }
1385
1386 /* Test we can still send data afterwards */
1387 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1388 dls := valueof(t_init_LapdmDlState);
1389 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1390
1391
1392 fp_common_fini();
1393}
1394testcase TC_normal_reestablishment() runs on test_CT {
1395 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1396 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment));
1397}
1398
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001399/* Test procedure for normal reestablishment in state LAPD_STATE_TIMER_RECOV (after T200, waiting for Ack), as per:
1400 * OS#4819
1401 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1402 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1403 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1404 * */
1405private function f_TC_normal_reestablishment_state_unacked(charstring id) runs on ConnHdlr {
1406 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1407 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1408 var octetstring l3_mt := f_rnd_octstring(20);
1409 var LapdmDlState dls;
1410 var default d;
1411 timer T := 3.0;
1412 var boolean use_sacch := false;
1413 var boolean received_estind := false;
1414 var boolean received_ua := false;
1415
1416 fp_common_init();
1417
1418 /* some common altstep for meas res and other background noise */
1419 d := activate(as_ignore_background(true));
1420 RSL.clear;
1421 LAPDM.clear;
1422
1423 f_establish_mo(link_id);
1424 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1425 /* first transmission, P = 0 */
1426 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=false,
1427 nr:=0, ns:=0, l3:=l3_mt)));
1428 /* re-transmission, P = 1 */
1429 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=true,
1430 nr:=0, ns:=0, l3:=l3_mt)));
1431 deactivate(d);
1432
1433 /* We received one retrans, so peer is in LAPD_STATE_TIMER_RECOV state. Now send SABM: */
1434 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)));
1435 T.start
1436 alt {
1437 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1438 received_ua := true;
1439 if (not received_estind) {
1440 repeat;
1441 }
1442 }
1443 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1444 received_estind := true;
1445 if (not received_ua) {
1446 repeat;
1447 }
1448 }
1449 [] RSL.receive { repeat; }
1450 [] LAPDM.receive { repeat; }
1451 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1452 }
1453
1454 /* Test we can still send data afterwards */
1455 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1456 dls := valueof(t_init_LapdmDlState);
1457 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1458
1459 fp_common_fini();
1460}
1461testcase TC_normal_reestablishment_state_unacked() runs on test_CT {
1462 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1463 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment_state_unacked));
1464}
1465
Harald Welte72c81e72019-05-30 16:36:11 +02001466control {
Harald Welte72c81e72019-05-30 16:36:11 +02001467 execute(TC_sabm_ua_dcch_sapi0());
1468 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1469 execute(TC_sabm_ua_dcch_sapi3());
1470 execute(TC_sabm_ua_dcch_sapi4());
1471 execute(TC_sabm_contention());
1472 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001473 execute(TC_sabm_retransmit_bts());
1474 execute(TC_sabm_invalid_resp());
1475 execute(TC_sabm_dm());
1476 execute(TC_establish_ign_first_sabm());
1477 execute(TC_iframe_seq_and_ack());
1478 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001479 execute(TC_ns_seq_error());
1480 execute(TC_nr_seq_error());
1481 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001482 execute(TC_segm_concat_dcch());
1483 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001484 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001485 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001486 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001487 execute(TC_sabm_incorrect_c());
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001488 execute(TC_normal_reestablishment());
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001489 execute(TC_normal_reestablishment_state_unacked());
Harald Welte72c81e72019-05-30 16:36:11 +02001490}
1491
Harald Weltef6543322017-07-16 07:35:10 +02001492}