blob: 2e984d103d06ac3bf49882b65dedf33019f05897 [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 Yanitskiyf54db112020-11-16 18:00:15 +070046 var TrxParsItem trx_pars := mp_trx_pars[g_pars.trx_nr];
47 var GsmBandArfcn arfcn := valueof(ts_GsmBandArfcn(trx_pars.arfcn));
Vadim Yanitskiy1acc7bb2020-11-14 04:24:57 +070048 var BCCH_tune_req tune_req := { arfcn := arfcn, combined_ccch := true };
Vadim Yanitskiyca813922020-09-12 19:08:31 +070049 var DCCH_switch_req sw_req;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070050
51 /* Craft channel description (with or without frequency hopping parameters) */
Vadim Yanitskiyca813922020-09-12 19:08:31 +070052 if (g_pars.fhp.enabled) {
Vadim Yanitskiy42d8bd52020-11-15 20:41:02 +070053 sw_req.chan_desc := valueof(ts_ChanDescH1(g_pars.chan_nr,
Vadim Yanitskiy3191d732020-11-15 20:45:01 +070054 g_pars.fhp.maio_hsn,
55 g_pars.tsc));
Vadim Yanitskiyca813922020-09-12 19:08:31 +070056 sw_req.ma := g_pars.fhp.ma;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070057 } else {
Vadim Yanitskiy42d8bd52020-11-15 20:41:02 +070058 sw_req.chan_desc := valueof(ts_ChanDescH0(g_pars.chan_nr,
Vadim Yanitskiyf54db112020-11-16 18:00:15 +070059 trx_pars.arfcn,
Vadim Yanitskiy3191d732020-11-15 20:45:01 +070060 g_pars.tsc));
Vadim Yanitskiyca813922020-09-12 19:08:31 +070061 sw_req.ma := omit;
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +070062 }
Harald Welte2f2b2b72019-05-31 22:24:57 +020063
64 LAPDM.send(tune_req);
65 LAPDM.send(sw_req);
66 LAPDM.receive(DCCH_switch_res:?);
67}
68
Harald Welte72c81e72019-05-30 16:36:11 +020069/* helper function releasing dedicated radio channel physically (no Um signaling!) */
70function f_release_dcch() runs on lapdm_test_CT {
71 var DCCH_release_req rel_req := {};
72 LAPDM.send(rel_req);
73}
74
75template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
76 sacch := sacch,
77 sapi := sapi,
78 lapdm := frame
79}
Harald Weltec38611b2019-05-30 16:33:58 +020080
Eric Wild74f25ae2019-06-14 11:44:29 +020081function 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 +020082 var LAPDm_ph_data phd;
83 var boolean result := false;
84 timer T := 5.0;
85
Eric Wild74f25ae2019-06-14 11:44:29 +020086 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 +020087 T.start
88 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +020089 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { result := true; }
90 [] RSL.receive {repeat;}
91 [] LAPDM.receive { repeat; }
Harald Welte72c81e72019-05-30 16:36:11 +020092 [] T.timeout { }
93 }
Eric Wild74f25ae2019-06-14 11:44:29 +020094 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 +020095 return result;
96}
97
Eric Wild74f25ae2019-06-14 11:44:29 +020098function f_TC_sabm_ua_dcch_sapi0(charstring id) runs on ConnHdlr {
99 fp_common_init();
100 RSL.clear;
101 LAPDM.clear;
102 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200103 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
104 setverdict(fail);
105 }
106 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200107 deactivate(d);
108 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200109}
110
Eric Wild74f25ae2019-06-14 11:44:29 +0200111function f_TC_sabm_ua_dcch_sapi0_nopayload(charstring id) runs on ConnHdlr {
112 fp_common_init();
113 RSL.clear;
114 LAPDM.clear;
115 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200116 if (f_test_sabm_results_in_ua(0, false, ''O)) {
117 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
118 }
119 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200120 deactivate(d);
121 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200122}
123
Eric Wild74f25ae2019-06-14 11:44:29 +0200124function f_TC_sabm_ua_dcch_sapi3(charstring id) runs on ConnHdlr {
125 fp_common_init();
126 RSL.clear;
127 LAPDM.clear;
128 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200129 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
130 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
131 }
132 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200133 deactivate(d);
134 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200135}
136
Eric Wild74f25ae2019-06-14 11:44:29 +0200137function f_TC_sabm_ua_dcch_sapi4(charstring id) runs on ConnHdlr {
138 fp_common_init();
139 RSL.clear;
140 LAPDM.clear;
141 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200142 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
143 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
144 }
145 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200146 deactivate(d);
147 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200148}
149
Eric Wild74f25ae2019-06-14 11:44:29 +0200150testcase TC_sabm_ua_dcch_sapi0() 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));
153}
154
155testcase TC_sabm_ua_dcch_sapi0_nopayload() 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_sapi0_nopayload));
158}
159
160testcase TC_sabm_ua_dcch_sapi3() 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_sapi3));
163}
164
165testcase TC_sabm_ua_dcch_sapi4() runs on test_CT {
166 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
167 f_testmatrix_each_chan(pars, refers(f_TC_sabm_ua_dcch_sapi4));
168}
169
170function f_TC_sabm_contention(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200171 var LAPDm_ph_data phd;
172 const octetstring payload := '0102030405'O;
173 const GsmSapi sapi := 0;
174 const boolean use_sacch := false;
175 timer T := 5.0;
176
Eric Wild74f25ae2019-06-14 11:44:29 +0200177 fp_common_init();
178 RSL.clear;
179 LAPDM.clear;
Harald Welte72c81e72019-05-30 16:36:11 +0200180
Harald Welte72c81e72019-05-30 16:36:11 +0200181 /* first frame is our real SABM */
Eric Wild74f25ae2019-06-14 11:44:29 +0200182 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 +0200183 /* 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 +0200184 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 +0200185 T.start
186 alt {
Eric Wild74f25ae2019-06-14 11:44:29 +0200187 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=payload))) { setverdict(pass); repeat; }
188 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=false, l3:=?))) {
Harald Welte72c81e72019-05-30 16:36:11 +0200189 setverdict(fail, "Second SABM was responded to during contention resolution");
Eric Wild74f25ae2019-06-14 11:44:29 +0200190 }
191 [] RSL.receive {repeat;}
Harald Welte72c81e72019-05-30 16:36:11 +0200192 [] LAPDM.receive { repeat };
193 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200194 }
Eric Wild74f25ae2019-06-14 11:44:29 +0200195
196 fp_common_fini();
197}
198
199testcase TC_sabm_contention() runs on test_CT {
200 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
201 f_testmatrix_each_chan(pars, refers(f_TC_sabm_contention));
Harald Welte72c81e72019-05-30 16:36:11 +0200202}
Harald Welte9e4725d2017-07-16 23:18:09 +0200203
Harald Welte72c81e72019-05-30 16:36:11 +0200204/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
205 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
Eric Wild74f25ae2019-06-14 11:44:29 +0200206function f_TC_sabm_retransmit(charstring id) runs on ConnHdlr {
Harald Welte72c81e72019-05-30 16:36:11 +0200207 const octetstring payload := '00FEFEDEADBEEF'O;
Eric Wild74f25ae2019-06-14 11:44:29 +0200208 fp_common_init();
209 RSL.clear;
210 LAPDM.clear;
211 var default d := activate(as_ignore_background());
Harald Welte72c81e72019-05-30 16:36:11 +0200212 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200213 setverdict(fail);
Harald Welte599faa12017-07-17 21:49:24 +0200214 }
Harald Welte72c81e72019-05-30 16:36:11 +0200215 if (not f_test_sabm_results_in_ua(0, false, payload)) {
Eric Wild74f25ae2019-06-14 11:44:29 +0200216 setverdict(fail);
Harald Welted4ba7ff2017-07-17 21:00:48 +0200217 }
Harald Welte72c81e72019-05-30 16:36:11 +0200218 setverdict(pass);
Eric Wild74f25ae2019-06-14 11:44:29 +0200219 deactivate(d);
220 fp_common_fini();
Harald Welte72c81e72019-05-30 16:36:11 +0200221}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200222
Eric Wild74f25ae2019-06-14 11:44:29 +0200223testcase TC_sabm_retransmit() runs on test_CT {
224 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
225 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit));
Harald Welte72c81e72019-05-30 16:36:11 +0200226}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200227
Harald Welte2f2b2b72019-05-31 22:24:57 +0200228/*********************************************************************************
229 * Test using both L1CTL/LAPDm and RSL
230 *********************************************************************************/
231
232private function fp_common_init() runs on ConnHdlr
233{
234 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
235 unmap(self:L1CTL, system:L1CTL);
236 f_lapdm_init();
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700237
238 /* Obtain frequency hopping parameters for a given timeslot */
239 if (mp_freq_hop_enabled and mp_transceiver_num > 1) {
Vadim Yanitskiyca813922020-09-12 19:08:31 +0700240 f_resolve_fh_params(g_pars.fhp, g_pars.chan_nr.tn);
Vadim Yanitskiya9894282020-07-14 01:56:15 +0700241 }
242
Harald Welte2f2b2b72019-05-31 22:24:57 +0200243 /* activate the channel on the BTS side */
244 f_rsl_chan_act(g_pars.chan_mode, false, {});
245 /* activate the channel on the MS side */
Vadim Yanitskiyeec14f02020-07-14 19:04:18 +0700246 f_switch_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200247}
248
249private function fp_common_fini() runs on ConnHdlr
250{
251 f_release_dcch();
252 f_rsl_chan_deact();
253 f_lapdm_exit();
254}
255
Harald Welte76771f12019-06-02 22:58:58 +0200256/* Mobile-Originated LAPDm establishment on given Link ID */
257private function f_establish_mo(RslLinkId link_id) runs on ConnHdlr
258{
259 var integer sapi := link_id.sapi;
260 var boolean is_sacch := false;
261 if (link_id.c == SACCH) {
262 is_sacch := true;
263 }
264
265 var octetstring l3_mo := f_rnd_octstring(5);
266
267 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
268 if (is_sacch) {
269 /* no payload permitted, as this is not contention resolution */
270 l3_mo := ''O;
271 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
272 RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
273 } else {
274 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
275 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
276 }
277 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
278 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
279}
280
Harald Welte2f2b2b72019-05-31 22:24:57 +0200281/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
282 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
283private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
284 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
285 fp_common_init();
286
287 LAPDM.clear;
288 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
289
290 timer T := 8.0;
291 var integer sabm_received := 0;
292 T.start;
293 alt {
294 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
295 sabm_received := sabm_received + 1;
296 repeat;
297 }
298 [] LAPDM.receive { repeat; }
299 [] T.timeout { }
300 }
301 if (sabm_received == 0) {
302 setverdict(fail, "No SABM observed at all!");
303 } else if (sabm_received != 6) {
304 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
305 sabm_received);
306 } else {
307 setverdict(pass, "Received ", sabm_received, " SABM");
308 }
309
310 fp_common_fini();
311}
312testcase TC_sabm_retransmit_bts() runs on test_CT {
313 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
314 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
315}
316
317
318type record LapdmNamedFrame {
319 charstring name,
320 LapdmFrame lapdm
321};
322
323/* Test that the BTS will ignore receipt of frames other than a UA when
324 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
325 * Section 25.2.1.1.2.3 */
326private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
327 var integer sapi := err_frame.lapdm.ab.addr.sapi;
328 fp_common_init();
329
330 /* Establish Request via RSL; Expect SABM on LAPDm side */
331 LAPDM.clear;
332 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
333 alt {
334 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
335 [] LAPDM.receive { repeat; }
336 }
337
338 /* send erroneous response to SABM */
339 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
340
341 /* expect a SABM retransmission of the BTS */
342 timer T := 3.0;
343 T.start;
344 alt {
345 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
346 setverdict(pass);
347 }
348 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
349 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
350 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
351 err_frame.name);
352 }
353 [] LAPDM.receive { repeat; }
354 [] T.timeout {
355 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
356 err_frame.name);
357 }
358 }
359
360 fp_common_fini();
361}
362private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
363 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
364 var LapdmNamedFrame err_frame[3] := {
365 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
366 l3 := '01020304'O)) },
367 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
368 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
369 };
370 var integer i;
371
372 for (i := 0; i < lengthof(err_frame); i := i+1) {
373 f_TC_sabm_invalid_resp2(id, err_frame[i])
374 }
375}
376testcase TC_sabm_invalid_resp() runs on test_CT {
377 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
378 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
379}
380
381/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
382 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
383private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
384 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
385 fp_common_init();
386
387 /* Establish Request via RSL; Expect SABM on LAPDm side */
388 LAPDM.clear;
389 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
390 alt {
391 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
392 [] LAPDM.receive { repeat; }
393 }
394
395 /* send DM response to SABM */
396 RSL.clear;
397 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
398 alt {
399 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
400 [] RSL.receive { repeat; }
401 }
402
403 /* expect no SABM retransmission of the BTS */
404 timer T := 3.0;
405 T.start;
406 alt {
407 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
408 setverdict(fail, "Received unexpected SABM retransmission");
409 }
410 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
411 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
412 setverdict(fail, "Received unexpected LAPDm frame");
413 }
414 [] LAPDM.receive { repeat; }
415 [] T.timeout {
416 setverdict(pass);
417 }
418 }
419
420 fp_common_fini();
421}
422testcase TC_sabm_dm() runs on test_CT {
423 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
424 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
425}
426
427/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
428 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
429 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
430private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
431 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
432 var integer num_sabm := 0;
433 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
434 timer T := 3.0;
435
436 fp_common_init();
437
438 /* Establish Request via RSL */
439 LAPDM.clear;
440 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
441 /* Expect two SABM (retransmit) */
442 T.start;
443 alt {
444 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
445 num_sabm := num_sabm + 1;
446 if (num_sabm < 2) {
447 repeat;
448 }
449 }
450 [] LAPDM.receive { repeat; }
451 }
452
453 /* send UA response to SABM */
454 RSL.clear;
455 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
456 alt {
457 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
458 [] RSL.receive { repeat; }
459 }
460
461 /* Send I frame from BTS to MS */
462 var octetstring l3 := f_rnd_octstring(10);
463 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
464 alt {
465 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
466 nr:=0, ns:=0, l3:=l3)));
467 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
468 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
469 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
470 }
471 /* Send RR frame in response */
472 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
473
474 /* expect idle UI Frame from BTS */
475 alt {
476 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
477 setverdict(pass);
478 }
479 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
480 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
481 }
482
483 fp_common_fini();
484}
485testcase TC_establish_ign_first_sabm() runs on test_CT {
486 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
487 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
488}
489
490/* ignore all SACCH frames */
491private altstep as_lapdm_acch() runs on ConnHdlr {
492 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
493}
Harald Welteef6fd442019-06-01 21:41:29 +0200494/* ignore all DCCH frames */
495private altstep as_lapdm_dcch() runs on ConnHdlr {
496 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
497}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200498/* ignore all LAPDm idle frames (UI) */
499private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200500 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200501}
502/* ignore all measurement reports */
503private altstep as_rsl_meas_rep() runs on ConnHdlr {
504 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
505}
506/* fail if we receive an RSL ERROR IND */
507private altstep as_rsl_fail_err() runs on ConnHdlr {
508 var RSL_Message rx_rsl;
509 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
510 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
511 }
512}
513/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200514private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200515 [want_dcch] as_lapdm_acch();
516 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200517 [] as_lapdm_idle();
518 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200519 [not ignore_rsl_errors] as_rsl_fail_err();
520 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200521}
522
523/* Test the operation of Layer 2 sequence numbering.
524 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
525private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
526 const integer sapi := 0;
527 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
528 var octetstring l3 := f_rnd_octstring(18);
529 var default d;
530 timer T := 3.0;
531
532 fp_common_init();
533
534 /* some common altstep for meas res and other background noise */
535 d := activate(as_ignore_background());
536 RSL.clear;
537 LAPDM.clear;
538
Harald Welte76771f12019-06-02 22:58:58 +0200539 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200540
541 var integer last_ns_rx := 0;
542
543 for (var integer i := 0; i < 10; i := i+1) {
544 var octetstring l3_mo := f_rnd_octstring(12);
545 var octetstring l3_mt := f_rnd_octstring(12);
546 var LAPDm_ph_data pd;
547
548 log("Starting iteration ", i);
549 /* MT I frame */
550 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
551 alt {
552 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
553 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
554 nr:=i mod 8))) {
555 log("Ignoring RR in iteration ", i);
556 repeat;
557 }
558 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
559 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
560 nr:=i mod 8, ns:=i mod 8,
561 l3:=l3_mt))) -> value pd {
562 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
563 }
564 }
565 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
566 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
567 nr:=(last_ns_rx+1)mod 8,
568 ns:=i mod 8, l3 := l3_mo)));
569 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
570 }
571 log("Completed iteration");
572
573 deactivate(d);
574 fp_common_fini();
575}
576testcase TC_iframe_seq_and_ack() runs on test_CT {
577 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
578 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
579}
580
581/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
582 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
583
584/*
585 1) The BTS is brought into the multiple frame established state
586 2) The MS sends an L3 Request asking for IMEI to the MS.
587 3) The BTS shall respond with a RR frame though this may be incorporated with
588 the L3 Response I frame. The MS does not respond to the I frame.
589 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
590 with the P bit set to 1.
591 5) The MS then sends a valid L3 Request I frame asking for IMEI which
592 does not acknowledge receipt of the I frame from the BTS.
593On the FACCH the BTS may send an RR frame acknowledging the I frame.
594 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
595 the second I frame from the MS.
596 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
597 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
598*/
599private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
600 const integer sapi := 0;
601 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
602 var default d;
603 timer T := 3.0;
604
605 fp_common_init();
606
607 /* some common altstep for meas res and other background noise */
608 d := activate(as_ignore_background());
609 RSL.clear;
610 LAPDM.clear;
611
612 var octetstring l3_mo := f_rnd_octstring(12);
613 var octetstring l3_mt := f_rnd_octstring(12);
614
615 /* 1) The BTS is brought into the multiple frame established state */
616
617 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
618 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
619 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
620 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
621 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
622
623 /* 2) The MS sends an L3 Request to the BTS */
624 l3_mo := f_rnd_octstring(18);
625 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
626 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
627 nr:=0, ns:=0, l3:=l3_mo)));
628 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
629 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
630 the L3 Response I frame. The MS does not respond to the I frame. */
631 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
632 alt {
633 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
634 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
635 repeat;
636 }
637 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
638 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
639 nr:=1, ns:=0, l3:=l3_mt)));
640 }
641
642 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
643 with the P bit set to 1. */
644 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
645 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
646 nr:=1, ns:=0, l3:=l3_mt)));
647
648 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
649 does not acknowledge receipt of the I frame from the BTS. */
650 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
651 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
652 nr:=0, ns:=1, l3 := l3_mo)));
653 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
654 alt {
655 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
656 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
657 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
658 repeat;
659 }
660 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
661 receipt of the second I frame from the MS. */
662 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
663 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
664 nr:=2, ns:=0, l3:=l3_mt)));
665 }
666
667 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
668 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
669 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
670
671 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
672 l3_mt := f_rnd_octstring(16);
673 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
674 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
675 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
676 nr:=2, ns:=1, l3:=l3_mt)));
677 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
678
679 deactivate(d);
680 fp_common_fini();
681}
682testcase TC_iframe_timer_recovery() runs on test_CT {
683 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
684 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
685}
686
Eric Wild211acc32019-06-11 19:06:38 +0200687/* 25.2.6.1 ns sequence error
688sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
689private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
690 const integer sapi := 0;
691 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
692 var default d;
693 timer T := 3.0;
694
695 fp_common_init();
696
697 /* some common altstep for meas res and other background noise */
698 d := activate(as_ignore_background(ignore_rsl_errors := true));
699 RSL.clear;
700 LAPDM.clear;
701
702 var octetstring l3_mo := f_rnd_octstring(12);
703 var octetstring l3_mt := f_rnd_octstring(12);
704
705 /* 1) The BTS is brought into the multiple frame established state */
706
707 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
708 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
709 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
710 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
711 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
712
713 /* 2) The MS sends an L3 Request to the BTS */
714 l3_mo := f_rnd_octstring(18);
715 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
716 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
717 nr:=0, ns:=0, l3:=l3_mo)));
718 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
719 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
720 the L3 Response I frame. */
721 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
722 alt {
723 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
724 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
725 repeat;
726 }
727 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
728 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
729 nr:=1, ns:=0, l3:=l3_mt)));
730 }
731
732 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
733 but correctly acknowledging the MS's I frame; P bit set to zero. */
734 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
735 nr:=1, ns:=0, l3:=l3_mo)));
736
737 /* no rsl data ind due to wrong ns */
738
739 /* The BTS shall send a REJ frame. */
740 timer T1 := 2.0;
741 T1.start;
742 alt{
743 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
744 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
745 }
746
747 f_sleep(2.0); // T200
748
749 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
750 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
751 nr:=1, ns:=0, l3:=l3_mo)));
752
753 /* The BTS shall respond with a REJ, F bit set to 1. */
754 T1.start;
755 alt{
756 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
757 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
758 }
759
760 deactivate(d);
761 fp_common_fini();
762 setverdict(pass);
763}
764
765testcase TC_ns_seq_error() runs on test_CT {
766 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
767 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
768}
769
770/* 25.2.6.2 nr sequence error */
771private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
772 const integer sapi := 0;
773 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
774 var default d;
775 var integer n201 := 20;
776 if (link_id.c == SACCH) {
777 n201 := 18;
778 }
779
780 fp_common_init();
781
782 /* some common altstep for meas res and other background noise */
783 d := activate(as_ignore_background(ignore_rsl_errors := true));
784 RSL.clear;
785 LAPDM.clear;
786
787 var octetstring l3_mo := f_rnd_octstring(12);
788 var octetstring l3_mt := f_rnd_octstring(12);
789
790 /* 1) The BTS is brought into the multiple frame established state */
791
792 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
793 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
794 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
795 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
796 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
797
798 /* 2) The MS shall send an I frame containing an information field of length N201 and an
799 incorrect receive sequence number. */
800 l3_mo := f_rnd_octstring(n201);
801 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
802 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
803 nr:=1, ns:=0, l3:=l3_mo)));
Andreas Eversberg4aef7982023-10-20 16:12:33 +0200804 /* LAPD indicates the data and then indicates error with sequence error cause. */
805 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
806 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '07'O));
807 /* Release RSL link. */
808 RSL.send(ts_RSL_REL_REQ(g_chan_nr, link_id));
Eric Wild211acc32019-06-11 19:06:38 +0200809
810 /* The BTS may: a) send a DISC frame within N200×T200; */
811 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
812 timer T1 := 2.0;
813 T1.start;
814 alt{
815 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
816 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
817 }
818
819 /* a) the MS shall respond with a UA frame.
820 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
821 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
822
823 deactivate(d);
824 fp_common_fini();
825 setverdict(pass);
826}
827
828testcase TC_nr_seq_error() runs on test_CT {
829 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
830 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
831}
832
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100833private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200834 LAPDM.send(t_PH_DATA(0, false, x));
835 f_sleep(2.0); // T200
836 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 +0100837 timer T1 := 2.0;
838 T1.start;
839 alt {
840 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
841 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
842 }
Eric Wild211acc32019-06-11 19:06:38 +0200843}
844
845/* 25.2.7 Test on receipt of invalid frames
846sends a bunch of different invalid frames, expects the BTS to ignore all of them */
847private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
848 const integer sapi := 0;
849 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
850 var default d;
851 timer T := 3.0;
852
853 fp_common_init();
854
855 /* some common altstep for meas res and other background noise */
856 d := activate(as_ignore_background(ignore_rsl_errors := true));
857 RSL.clear;
858 LAPDM.clear;
859
860 var octetstring l3_mo := f_rnd_octstring(12);
861 var octetstring l3_mt := f_rnd_octstring(12);
862
863 /* 1) The BTS is brought into the multiple frame established state */
864
865 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
866 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 +0100867 T.start
868 alt {
869 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
870 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
871 }
872 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200873 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100874 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
875 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
876 }
Eric Wild211acc32019-06-11 19:06:38 +0200877
878 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
879 RR frame with the Length indicator greater than zero and a faulty N(R); */
880 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
881 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100882 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200883 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
884 EJ frame with the EA bit set to zero and a faulty N(R); */
885 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
886 x.ab.addr.ea := false;
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 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
889 SABM frame with the EL bit set to zero; */
890 l3_mo := ''O;
891 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
892 x.ab.el := 0;
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 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
895 DM frame with the Length indicator greater than zero;*/
896 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
897 x.ab.payload := f_rnd_octstring(5);
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 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
900 DISC frame with the M bit set to 1; */
901 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
902 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100903 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200904 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
905 UA frame with the EA bit set to zero*/
906 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
907 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100908 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200909 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
910 I frame with the Length indicator greater than N201;*/
911 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 +0100912 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200913 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
914 I frame with the M bit set to 1 and the Length indicator less than N201;*/
915 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
916 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100917 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200918 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
919 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
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
922 /* command frames with correct Address and Length indicator field and a non-implemented control field */
923 /* 12: One command frame with Control Field = xxx1 1101. */
924 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
925 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100926 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200927 /* 13: One command frame with Control field = xxx1 1011. */
928 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
929 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100930 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200931 /* 14: One command frame with Control field = xxx1 0111. */
932 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
933 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100934 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200935 /* 15: One command frame with Control field = 01x1 1111. */
936 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
937 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100938 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200939 /* 16: One command frame with Control field = 1xx1 1111. */
940 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
941 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100942 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200943 /* 17: One command frame with Control field = 0011 0011. */
944 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
945 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100946 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200947 /* 18: One command frame with Control field = 1xx1 0011. */
948 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
949 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100950 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200951
952 deactivate(d);
953 fp_common_fini();
954 setverdict(pass);
955}
956
957testcase TC_rec_invalid_frame() runs on test_CT {
958 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
959 pars.t_guard := 60.0;
960 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
961}
962
Harald Welte9ea918c2019-06-01 11:46:25 +0200963type record LapdmDlConfig {
964 integer n201,
965 integer t200
966};
967
968type record LapdmDlState {
969 integer v_s,
970 integer v_a,
971 integer v_r
972};
973
974template (value) LapdmDlState t_init_LapdmDlState := {
975 v_s := 0,
976 v_a := 0,
977 v_r := 0
978}
979
980private function inc_mod8(inout integer v)
981{
982 v := (v + 1) mod 8;
983}
984
985private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
986runs on ConnHdlr {
987 var LAPDm_ph_data pd;
988 var integer offset := 0;
989 var integer n201 := 20;
990 var boolean is_sacch := false;
991 if (link_id.c == SACCH) {
992 n201 := 18;
993 is_sacch := true;
994 }
995
996 while (offset < lengthof(l3)) {
997 var integer remain_len := lengthof(l3) - offset;
998 var integer seg_len := remain_len;
999 if (remain_len > n201) {
1000 seg_len := n201;
1001 }
1002 var octetstring segment := substr(l3, offset, seg_len);
1003 var boolean more;
1004 if (offset + lengthof(segment) < lengthof(l3)) {
1005 more := true;
1006 } else {
1007 more := false;
1008 }
1009 /* send the next segment */
1010 LAPDM.send(t_PH_DATA(0, is_sacch,
1011 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1012 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1013 inc_mod8(dls.v_s);
1014 offset := offset + lengthof(segment);
1015
1016 /* wait for it to be acknowledged */
1017 alt {
1018 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1019 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001020 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001021 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001022 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("received unexpected LAPDm ", pd));
Harald Welte9ea918c2019-06-01 11:46:25 +02001023 }
1024 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1025 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001026 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "received RSL DATA IND before message complete");
Harald Welte9ea918c2019-06-01 11:46:25 +02001027 }
1028 }
1029 }
1030
1031 timer T := 1.0;
1032 T.start;
1033 alt {
1034 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1035 setverdict(pass);
1036 }
1037 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001038 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received RSL DATA IND with wrong payload");
Harald Welte9ea918c2019-06-01 11:46:25 +02001039 }
1040 [] T.timeout {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001041 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RSL DATA IND of de-segmented message");
Harald Welte9ea918c2019-06-01 11:46:25 +02001042 }
1043 }
1044}
1045
1046/* Section 5.8.5 of TS 04.06 */
1047const integer c_TS0406_MAX_L3_OCTETS := 251;
1048
Harald Welteef6fd442019-06-01 21:41:29 +02001049/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1050 * on specified SAPI/channel */
1051private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1052 var integer sapi := link_id.sapi;
1053 var boolean is_sacch := false;
1054 if (link_id.c == SACCH) {
1055 is_sacch := true;
1056 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001057 var default d;
1058 timer T := 3.0;
1059
1060 fp_common_init();
1061
1062 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001063 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001064 RSL.clear;
1065 LAPDM.clear;
1066
Harald Welte76771f12019-06-02 22:58:58 +02001067 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001068
Harald Welte76771f12019-06-02 22:58:58 +02001069 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001070
1071 deactivate(d);
1072
1073 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1074 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1075
1076 fp_common_fini();
1077}
Harald Welteef6fd442019-06-01 21:41:29 +02001078private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1079 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001080}
Harald Welteef6fd442019-06-01 21:41:29 +02001081private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1082 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1083}
1084/* test mobile-originated segmentation/de-segmentation on DCCH */
1085testcase TC_segm_concat_dcch() runs on test_CT {
1086 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1087 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1088}
1089/* test mobile-originated segmentation/de-segmentation on SACCH */
1090testcase TC_segm_concat_sacch() runs on test_CT {
1091 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1092 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1093}
1094
Harald Welteb2a30342019-06-02 22:13:50 +02001095/* TS 04.06 Section 5.8.2.1 */
1096private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1097 /* SACCH irrespective of physical channel type */
1098 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1099 return 5;
1100 }
1101 /* DCCH below */
1102 select (chan_nr) {
1103 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1104 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1105 case (t_RslChanNr_Bm(?)) { return 34; }
1106 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1107 }
1108 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1109 return -1;
1110}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001111
Harald Welteb2a30342019-06-02 22:13:50 +02001112/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1113private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
Andreas Eversberga56058e2023-06-12 09:25:35 +02001114 var RslLinkId link_id := valueof(ts_RslLinkID_SACCH(0));
Harald Welteb2a30342019-06-02 22:13:50 +02001115 var integer sapi := link_id.sapi;
1116 var boolean is_sacch := false;
1117 if (link_id.c == SACCH) {
1118 is_sacch := true;
1119 }
1120 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1121 var integer num_retrans := 0;
1122 timer T := 3.0;
1123 var default d;
1124
1125 fp_common_init();
1126
1127 /* some common altstep for meas res and other background noise */
Andreas Eversberga56058e2023-06-12 09:25:35 +02001128 d := activate(as_ignore_background(not is_sacch));
Harald Welteb2a30342019-06-02 22:13:50 +02001129 RSL.clear;
1130 LAPDM.clear;
1131
Harald Welte76771f12019-06-02 22:58:58 +02001132 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001133
Andreas Eversberga56058e2023-06-12 09:25:35 +02001134 var octetstring l3_mt := f_rnd_octstring(18);
Harald Welteb2a30342019-06-02 22:13:50 +02001135 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1136 /* first transmission, P = 0 */
1137 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1138 nr:=0, ns:=0, l3:=l3_mt)));
1139 deactivate(d);
1140
1141 alt {
1142 /* re-transmission, P = 1 */
1143 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1144 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1145 num_retrans := num_retrans + 1;
1146 if (num_retrans < n200) {
1147 repeat;
1148 } else if (num_retrans == n200) {
1149 T.start; /* wait for some more time if there are more retransmissions */
1150 repeat;
1151 } else {
1152 /* break */
1153 }
1154 }
Andreas Eversberga56058e2023-06-12 09:25:35 +02001155 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
Harald Welteb2a30342019-06-02 22:13:50 +02001156 setverdict(fail, "Received unexpected I frame");
1157 }
1158 [not is_sacch] as_lapdm_acch();
1159 [is_sacch] as_lapdm_dcch();
1160 [] as_lapdm_idle();
1161 [] as_rsl_meas_rep();
1162 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1163 /* break */
1164 }
1165 [] T.timeout {
1166 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1167 }
1168 }
1169
1170 if (num_retrans == n200) {
1171 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1172 } else if (num_retrans < n200) {
1173 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1174 " on channel ", g_chan_nr, " link ", link_id);
1175 }
1176
1177 fp_common_fini();
1178}
1179testcase TC_t200_n200() runs on test_CT {
1180 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1181 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1182}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001183
Harald Welte7d9f6db2019-06-02 23:14:04 +02001184/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1185 Inspired by TS 51.010-1 25.2.4.3 */
1186private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1187 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1188 var integer sapi := link_id.sapi;
1189 var boolean is_sacch := false;
1190 if (link_id.c == SACCH) {
1191 is_sacch := true;
1192 }
1193 timer T := 3.0;
1194 var default d;
1195
1196 fp_common_init();
1197
1198 /* some common altstep for meas res and other background noise */
1199 d := activate(as_ignore_background(true));
1200 RSL.clear;
1201 LAPDM.clear;
1202
1203 f_establish_mo(link_id);
1204
1205 var octetstring l3_mo := f_rnd_octstring(10);
1206 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1207 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1208 l3:=l3_mo)));
1209 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1210 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1211 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1212
1213 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1214 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1215 l3:=l3_mo)));
1216
1217 T.start;
1218 alt {
1219 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1220 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1221 setverdict(pass);
1222 }
1223 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1224 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1225 setverdict(pass);
1226 }
1227 [] T.timeout {
1228 setverdict(fail, "Timeout waiting for RR or REJ");
1229 }
1230 }
1231
1232 deactivate(d);
1233
1234 fp_common_fini();
1235}
1236testcase TC_rr_response_frame_loss() runs on test_CT {
1237 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1238 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1239}
1240
Harald Welte44479782019-06-02 23:23:45 +02001241/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1242private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1243 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1244 var integer sapi := link_id.sapi;
1245 var boolean is_sacch := false;
1246 if (link_id.c == SACCH) {
1247 is_sacch := true;
1248 }
1249 timer T := 3.0;
1250 var default d;
1251
1252 fp_common_init();
1253
1254 /* some common altstep for meas res and other background noise */
1255 d := activate(as_ignore_background(true));
1256 RSL.clear;
1257 LAPDM.clear;
1258
1259 f_establish_mo(link_id);
1260
1261 var octetstring l3_mo := f_rnd_octstring(10);
1262 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1263 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1264 l3:=l3_mo)));
1265 T.start;
1266 alt {
1267 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1268 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1269 }
1270 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1271 repeat;
1272 }
1273 /* ensure BTS still sends idle frames */
1274 [] as_lapdm_idle() {
1275 setverdict(pass, "still sending idle frames");
1276 }
1277 [] T.timeout {}
1278 }
1279
1280 /* Send RR command P=1 */
1281 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1282
1283 /* The BTS shall respond with a RR response, F bit set to 1. */
1284 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1285
1286 deactivate(d);
1287
1288 fp_common_fini();
1289}
1290testcase TC_incorrect_cr() runs on test_CT {
1291 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1292 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1293}
Harald Weltea39ac752019-06-04 21:46:07 +02001294
1295/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1296 Inspired by TS 51.010-1 25.2.5.2 */
1297private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1298 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1299 var integer sapi := link_id.sapi;
1300 var boolean is_sacch := false;
1301 if (link_id.c == SACCH) {
1302 is_sacch := true;
1303 }
1304 timer T := 3.0;
1305 var default d;
1306
1307 fp_common_init();
1308
1309 /* some common altstep for meas res and other background noise */
1310 d := activate(as_ignore_background(true));
1311 RSL.clear;
1312 LAPDM.clear;
1313
1314 f_establish_mo(link_id);
1315
1316 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1317 var octetstring l3_mo := '010203'O;
1318 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1319 l3:=l3_mo)));
1320 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1321 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1322 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1323 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1324 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1325 /* Expect RSL ERR IND */
1326 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1327 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1328 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1329 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1330 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1331 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1332 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1333
1334 deactivate(d);
1335
1336 fp_common_fini();
1337}
1338testcase TC_sabm_incorrect_c() runs on test_CT {
1339 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1340 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1341}
1342
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001343/* Test procedure for normal reestablishment, as per:
1344 * OS#4819
1345 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1346 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1347 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1348 * */
1349private function f_TC_normal_reestablishment(charstring id) runs on ConnHdlr {
1350 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1351 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1352 var default d;
1353 timer T := 3.0;
1354 var boolean use_sacch := false;
1355 var boolean received_estind := false;
1356 var boolean received_ua := false;
1357
1358 fp_common_init();
1359
1360 /* some common altstep for meas res and other background noise */
1361 d := activate(as_ignore_background(true));
1362 RSL.clear;
1363 LAPDM.clear;
1364
1365 f_establish_mo(link_id);
1366
1367 deactivate(d);
1368
1369 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1370 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1371
1372 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)));
1373 T.start
1374 alt {
1375 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1376 received_ua := true;
1377 if (not received_estind) {
1378 repeat;
1379 }
1380 }
1381 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1382 received_estind := true;
1383 if (not received_ua) {
1384 repeat;
1385 }
1386 }
1387 [] RSL.receive { repeat; }
1388 [] LAPDM.receive { repeat; }
1389 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1390 }
1391
1392 /* Test we can still send data afterwards */
1393 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1394 dls := valueof(t_init_LapdmDlState);
1395 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1396
1397
1398 fp_common_fini();
1399}
1400testcase TC_normal_reestablishment() runs on test_CT {
1401 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1402 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment));
1403}
1404
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001405/* Test procedure for normal reestablishment in state LAPD_STATE_TIMER_RECOV (after T200, waiting for Ack), as per:
1406 * OS#4819
1407 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1408 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1409 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1410 * */
1411private function f_TC_normal_reestablishment_state_unacked(charstring id) runs on ConnHdlr {
1412 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1413 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1414 var octetstring l3_mt := f_rnd_octstring(20);
1415 var LapdmDlState dls;
1416 var default d;
1417 timer T := 3.0;
1418 var boolean use_sacch := false;
1419 var boolean received_estind := false;
1420 var boolean received_ua := false;
1421
1422 fp_common_init();
1423
1424 /* some common altstep for meas res and other background noise */
1425 d := activate(as_ignore_background(true));
1426 RSL.clear;
1427 LAPDM.clear;
1428
1429 f_establish_mo(link_id);
1430 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1431 /* first transmission, P = 0 */
1432 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=false,
1433 nr:=0, ns:=0, l3:=l3_mt)));
1434 /* re-transmission, P = 1 */
1435 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=true,
1436 nr:=0, ns:=0, l3:=l3_mt)));
1437 deactivate(d);
1438
1439 /* We received one retrans, so peer is in LAPD_STATE_TIMER_RECOV state. Now send SABM: */
1440 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)));
1441 T.start
1442 alt {
1443 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1444 received_ua := true;
1445 if (not received_estind) {
1446 repeat;
1447 }
1448 }
1449 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1450 received_estind := true;
1451 if (not received_ua) {
1452 repeat;
1453 }
1454 }
1455 [] RSL.receive { repeat; }
1456 [] LAPDM.receive { repeat; }
1457 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1458 }
1459
1460 /* Test we can still send data afterwards */
1461 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1462 dls := valueof(t_init_LapdmDlState);
1463 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1464
1465 fp_common_fini();
1466}
1467testcase TC_normal_reestablishment_state_unacked() runs on test_CT {
1468 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1469 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment_state_unacked));
1470}
1471
Harald Welte72c81e72019-05-30 16:36:11 +02001472control {
Harald Welte72c81e72019-05-30 16:36:11 +02001473 execute(TC_sabm_ua_dcch_sapi0());
1474 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1475 execute(TC_sabm_ua_dcch_sapi3());
1476 execute(TC_sabm_ua_dcch_sapi4());
1477 execute(TC_sabm_contention());
1478 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001479 execute(TC_sabm_retransmit_bts());
1480 execute(TC_sabm_invalid_resp());
1481 execute(TC_sabm_dm());
1482 execute(TC_establish_ign_first_sabm());
1483 execute(TC_iframe_seq_and_ack());
1484 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001485 execute(TC_ns_seq_error());
1486 execute(TC_nr_seq_error());
1487 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001488 execute(TC_segm_concat_dcch());
1489 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001490 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001491 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001492 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001493 execute(TC_sabm_incorrect_c());
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001494 execute(TC_normal_reestablishment());
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001495 execute(TC_normal_reestablishment_state_unacked());
Harald Welte72c81e72019-05-30 16:36:11 +02001496}
1497
Harald Weltef6543322017-07-16 07:35:10 +02001498}