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