blob: edd974ba50cdd277c169919d0f7cc41150241f9a [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)));
804
805 /* The BTS may: a) send a DISC frame within N200×T200; */
806 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
807 timer T1 := 2.0;
808 T1.start;
809 alt{
810 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
811 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
812 }
813
814 /* a) the MS shall respond with a UA frame.
815 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
816 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
817
818 deactivate(d);
819 fp_common_fini();
820 setverdict(pass);
821}
822
823testcase TC_nr_seq_error() runs on test_CT {
824 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
825 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
826}
827
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100828private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200829 LAPDM.send(t_PH_DATA(0, false, x));
830 f_sleep(2.0); // T200
831 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 +0100832 timer T1 := 2.0;
833 T1.start;
834 alt {
835 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
836 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
837 }
Eric Wild211acc32019-06-11 19:06:38 +0200838}
839
840/* 25.2.7 Test on receipt of invalid frames
841sends a bunch of different invalid frames, expects the BTS to ignore all of them */
842private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
843 const integer sapi := 0;
844 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
845 var default d;
846 timer T := 3.0;
847
848 fp_common_init();
849
850 /* some common altstep for meas res and other background noise */
851 d := activate(as_ignore_background(ignore_rsl_errors := true));
852 RSL.clear;
853 LAPDM.clear;
854
855 var octetstring l3_mo := f_rnd_octstring(12);
856 var octetstring l3_mt := f_rnd_octstring(12);
857
858 /* 1) The BTS is brought into the multiple frame established state */
859
860 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
861 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 +0100862 T.start
863 alt {
864 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
865 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
866 }
867 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200868 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100869 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
870 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
871 }
Eric Wild211acc32019-06-11 19:06:38 +0200872
873 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
874 RR frame with the Length indicator greater than zero and a faulty N(R); */
875 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
876 x.ab.payload := f_rnd_octstring(5);
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 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
879 EJ frame with the EA bit set to zero and a faulty N(R); */
880 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
881 x.ab.addr.ea := false;
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 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
884 SABM frame with the EL bit set to zero; */
885 l3_mo := ''O;
886 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
887 x.ab.el := 0;
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 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
890 DM frame with the Length indicator greater than zero;*/
891 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
892 x.ab.payload := f_rnd_octstring(5);
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 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
895 DISC frame with the M bit set to 1; */
896 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
897 x.ab.m := true;
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 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
900 UA frame with the EA bit set to zero*/
901 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
902 x.ab.addr.ea := false;
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 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
905 I frame with the Length indicator greater than N201;*/
906 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 +0100907 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200908 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
909 I frame with the M bit set to 1 and the Length indicator less than N201;*/
910 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
911 x.ab.m := true;
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 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
914 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100915 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200916
917 /* command frames with correct Address and Length indicator field and a non-implemented control field */
918 /* 12: One command frame with Control Field = xxx1 1101. */
919 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
920 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100921 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200922 /* 13: One command frame with Control field = xxx1 1011. */
923 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
924 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100925 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200926 /* 14: One command frame with Control field = xxx1 0111. */
927 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
928 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100929 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200930 /* 15: One command frame with Control field = 01x1 1111. */
931 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
932 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100933 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200934 /* 16: One command frame with Control field = 1xx1 1111. */
935 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
936 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100937 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200938 /* 17: One command frame with Control field = 0011 0011. */
939 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
940 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100941 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200942 /* 18: One command frame with Control field = 1xx1 0011. */
943 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
944 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100945 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200946
947 deactivate(d);
948 fp_common_fini();
949 setverdict(pass);
950}
951
952testcase TC_rec_invalid_frame() runs on test_CT {
953 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
954 pars.t_guard := 60.0;
955 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
956}
957
Harald Welte9ea918c2019-06-01 11:46:25 +0200958type record LapdmDlConfig {
959 integer n201,
960 integer t200
961};
962
963type record LapdmDlState {
964 integer v_s,
965 integer v_a,
966 integer v_r
967};
968
969template (value) LapdmDlState t_init_LapdmDlState := {
970 v_s := 0,
971 v_a := 0,
972 v_r := 0
973}
974
975private function inc_mod8(inout integer v)
976{
977 v := (v + 1) mod 8;
978}
979
980private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
981runs on ConnHdlr {
982 var LAPDm_ph_data pd;
983 var integer offset := 0;
984 var integer n201 := 20;
985 var boolean is_sacch := false;
986 if (link_id.c == SACCH) {
987 n201 := 18;
988 is_sacch := true;
989 }
990
991 while (offset < lengthof(l3)) {
992 var integer remain_len := lengthof(l3) - offset;
993 var integer seg_len := remain_len;
994 if (remain_len > n201) {
995 seg_len := n201;
996 }
997 var octetstring segment := substr(l3, offset, seg_len);
998 var boolean more;
999 if (offset + lengthof(segment) < lengthof(l3)) {
1000 more := true;
1001 } else {
1002 more := false;
1003 }
1004 /* send the next segment */
1005 LAPDM.send(t_PH_DATA(0, is_sacch,
1006 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1007 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1008 inc_mod8(dls.v_s);
1009 offset := offset + lengthof(segment);
1010
1011 /* wait for it to be acknowledged */
1012 alt {
1013 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1014 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001015 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001016 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001017 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("received unexpected LAPDm ", pd));
Harald Welte9ea918c2019-06-01 11:46:25 +02001018 }
1019 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1020 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001021 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "received RSL DATA IND before message complete");
Harald Welte9ea918c2019-06-01 11:46:25 +02001022 }
1023 }
1024 }
1025
1026 timer T := 1.0;
1027 T.start;
1028 alt {
1029 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1030 setverdict(pass);
1031 }
1032 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001033 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received RSL DATA IND with wrong payload");
Harald Welte9ea918c2019-06-01 11:46:25 +02001034 }
1035 [] T.timeout {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001036 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RSL DATA IND of de-segmented message");
Harald Welte9ea918c2019-06-01 11:46:25 +02001037 }
1038 }
1039}
1040
1041/* Section 5.8.5 of TS 04.06 */
1042const integer c_TS0406_MAX_L3_OCTETS := 251;
1043
Harald Welteef6fd442019-06-01 21:41:29 +02001044/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1045 * on specified SAPI/channel */
1046private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1047 var integer sapi := link_id.sapi;
1048 var boolean is_sacch := false;
1049 if (link_id.c == SACCH) {
1050 is_sacch := true;
1051 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001052 var default d;
1053 timer T := 3.0;
1054
1055 fp_common_init();
1056
1057 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001058 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001059 RSL.clear;
1060 LAPDM.clear;
1061
Harald Welte76771f12019-06-02 22:58:58 +02001062 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001063
Harald Welte76771f12019-06-02 22:58:58 +02001064 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001065
1066 deactivate(d);
1067
1068 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1069 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1070
1071 fp_common_fini();
1072}
Harald Welteef6fd442019-06-01 21:41:29 +02001073private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1074 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001075}
Harald Welteef6fd442019-06-01 21:41:29 +02001076private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1077 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1078}
1079/* test mobile-originated segmentation/de-segmentation on DCCH */
1080testcase TC_segm_concat_dcch() 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_dcch));
1083}
1084/* test mobile-originated segmentation/de-segmentation on SACCH */
1085testcase TC_segm_concat_sacch() 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_sacch));
1088}
1089
Harald Welteb2a30342019-06-02 22:13:50 +02001090/* TS 04.06 Section 5.8.2.1 */
1091private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1092 /* SACCH irrespective of physical channel type */
1093 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1094 return 5;
1095 }
1096 /* DCCH below */
1097 select (chan_nr) {
1098 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1099 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1100 case (t_RslChanNr_Bm(?)) { return 34; }
1101 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1102 }
1103 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1104 return -1;
1105}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001106
Harald Welteb2a30342019-06-02 22:13:50 +02001107/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1108private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
1109 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1110 var integer sapi := link_id.sapi;
1111 var boolean is_sacch := false;
1112 if (link_id.c == SACCH) {
1113 is_sacch := true;
1114 }
1115 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1116 var integer num_retrans := 0;
1117 timer T := 3.0;
1118 var default d;
1119
1120 fp_common_init();
1121
1122 /* some common altstep for meas res and other background noise */
1123 d := activate(as_ignore_background(true));
1124 RSL.clear;
1125 LAPDM.clear;
1126
Harald Welte76771f12019-06-02 22:58:58 +02001127 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001128
1129 var octetstring l3_mt := f_rnd_octstring(20);
1130 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1131 /* first transmission, P = 0 */
1132 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1133 nr:=0, ns:=0, l3:=l3_mt)));
1134 deactivate(d);
1135
1136 alt {
1137 /* re-transmission, P = 1 */
1138 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1139 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1140 num_retrans := num_retrans + 1;
1141 if (num_retrans < n200) {
1142 repeat;
1143 } else if (num_retrans == n200) {
1144 T.start; /* wait for some more time if there are more retransmissions */
1145 repeat;
1146 } else {
1147 /* break */
1148 }
1149 }
1150 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
1151 setverdict(fail, "Received unexpected I frame");
1152 }
1153 [not is_sacch] as_lapdm_acch();
1154 [is_sacch] as_lapdm_dcch();
1155 [] as_lapdm_idle();
1156 [] as_rsl_meas_rep();
1157 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1158 /* break */
1159 }
1160 [] T.timeout {
1161 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1162 }
1163 }
1164
1165 if (num_retrans == n200) {
1166 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1167 } else if (num_retrans < n200) {
1168 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1169 " on channel ", g_chan_nr, " link ", link_id);
1170 }
1171
1172 fp_common_fini();
1173}
1174testcase TC_t200_n200() runs on test_CT {
1175 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1176 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1177}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001178
Harald Welte7d9f6db2019-06-02 23:14:04 +02001179/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1180 Inspired by TS 51.010-1 25.2.4.3 */
1181private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1182 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1183 var integer sapi := link_id.sapi;
1184 var boolean is_sacch := false;
1185 if (link_id.c == SACCH) {
1186 is_sacch := true;
1187 }
1188 timer T := 3.0;
1189 var default d;
1190
1191 fp_common_init();
1192
1193 /* some common altstep for meas res and other background noise */
1194 d := activate(as_ignore_background(true));
1195 RSL.clear;
1196 LAPDM.clear;
1197
1198 f_establish_mo(link_id);
1199
1200 var octetstring l3_mo := f_rnd_octstring(10);
1201 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1202 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1203 l3:=l3_mo)));
1204 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1205 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1206 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1207
1208 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1209 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1210 l3:=l3_mo)));
1211
1212 T.start;
1213 alt {
1214 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1215 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1216 setverdict(pass);
1217 }
1218 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1219 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1220 setverdict(pass);
1221 }
1222 [] T.timeout {
1223 setverdict(fail, "Timeout waiting for RR or REJ");
1224 }
1225 }
1226
1227 deactivate(d);
1228
1229 fp_common_fini();
1230}
1231testcase TC_rr_response_frame_loss() runs on test_CT {
1232 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1233 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1234}
1235
Harald Welte44479782019-06-02 23:23:45 +02001236/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1237private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1238 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1239 var integer sapi := link_id.sapi;
1240 var boolean is_sacch := false;
1241 if (link_id.c == SACCH) {
1242 is_sacch := true;
1243 }
1244 timer T := 3.0;
1245 var default d;
1246
1247 fp_common_init();
1248
1249 /* some common altstep for meas res and other background noise */
1250 d := activate(as_ignore_background(true));
1251 RSL.clear;
1252 LAPDM.clear;
1253
1254 f_establish_mo(link_id);
1255
1256 var octetstring l3_mo := f_rnd_octstring(10);
1257 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1258 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1259 l3:=l3_mo)));
1260 T.start;
1261 alt {
1262 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1263 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1264 }
1265 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1266 repeat;
1267 }
1268 /* ensure BTS still sends idle frames */
1269 [] as_lapdm_idle() {
1270 setverdict(pass, "still sending idle frames");
1271 }
1272 [] T.timeout {}
1273 }
1274
1275 /* Send RR command P=1 */
1276 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1277
1278 /* The BTS shall respond with a RR response, F bit set to 1. */
1279 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1280
1281 deactivate(d);
1282
1283 fp_common_fini();
1284}
1285testcase TC_incorrect_cr() runs on test_CT {
1286 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1287 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1288}
Harald Weltea39ac752019-06-04 21:46:07 +02001289
1290/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1291 Inspired by TS 51.010-1 25.2.5.2 */
1292private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1293 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1294 var integer sapi := link_id.sapi;
1295 var boolean is_sacch := false;
1296 if (link_id.c == SACCH) {
1297 is_sacch := true;
1298 }
1299 timer T := 3.0;
1300 var default d;
1301
1302 fp_common_init();
1303
1304 /* some common altstep for meas res and other background noise */
1305 d := activate(as_ignore_background(true));
1306 RSL.clear;
1307 LAPDM.clear;
1308
1309 f_establish_mo(link_id);
1310
1311 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1312 var octetstring l3_mo := '010203'O;
1313 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1314 l3:=l3_mo)));
1315 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1316 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1317 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1318 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1319 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1320 /* Expect RSL ERR IND */
1321 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1322 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1323 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1324 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1325 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1326 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1327 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1328
1329 deactivate(d);
1330
1331 fp_common_fini();
1332}
1333testcase TC_sabm_incorrect_c() runs on test_CT {
1334 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1335 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1336}
1337
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001338/* Test procedure for normal reestablishment, as per:
1339 * OS#4819
1340 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1341 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1342 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1343 * */
1344private function f_TC_normal_reestablishment(charstring id) runs on ConnHdlr {
1345 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1346 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1347 var default d;
1348 timer T := 3.0;
1349 var boolean use_sacch := false;
1350 var boolean received_estind := false;
1351 var boolean received_ua := false;
1352
1353 fp_common_init();
1354
1355 /* some common altstep for meas res and other background noise */
1356 d := activate(as_ignore_background(true));
1357 RSL.clear;
1358 LAPDM.clear;
1359
1360 f_establish_mo(link_id);
1361
1362 deactivate(d);
1363
1364 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1365 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1366
1367 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)));
1368 T.start
1369 alt {
1370 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1371 received_ua := true;
1372 if (not received_estind) {
1373 repeat;
1374 }
1375 }
1376 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1377 received_estind := true;
1378 if (not received_ua) {
1379 repeat;
1380 }
1381 }
1382 [] RSL.receive { repeat; }
1383 [] LAPDM.receive { repeat; }
1384 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1385 }
1386
1387 /* Test we can still send data afterwards */
1388 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1389 dls := valueof(t_init_LapdmDlState);
1390 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1391
1392
1393 fp_common_fini();
1394}
1395testcase TC_normal_reestablishment() runs on test_CT {
1396 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1397 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment));
1398}
1399
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001400/* Test procedure for normal reestablishment in state LAPD_STATE_TIMER_RECOV (after T200, waiting for Ack), as per:
1401 * OS#4819
1402 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1403 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1404 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1405 * */
1406private function f_TC_normal_reestablishment_state_unacked(charstring id) runs on ConnHdlr {
1407 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1408 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1409 var octetstring l3_mt := f_rnd_octstring(20);
1410 var LapdmDlState dls;
1411 var default d;
1412 timer T := 3.0;
1413 var boolean use_sacch := false;
1414 var boolean received_estind := false;
1415 var boolean received_ua := false;
1416
1417 fp_common_init();
1418
1419 /* some common altstep for meas res and other background noise */
1420 d := activate(as_ignore_background(true));
1421 RSL.clear;
1422 LAPDM.clear;
1423
1424 f_establish_mo(link_id);
1425 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1426 /* first transmission, P = 0 */
1427 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=false,
1428 nr:=0, ns:=0, l3:=l3_mt)));
1429 /* re-transmission, P = 1 */
1430 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=true,
1431 nr:=0, ns:=0, l3:=l3_mt)));
1432 deactivate(d);
1433
1434 /* We received one retrans, so peer is in LAPD_STATE_TIMER_RECOV state. Now send SABM: */
1435 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)));
1436 T.start
1437 alt {
1438 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1439 received_ua := true;
1440 if (not received_estind) {
1441 repeat;
1442 }
1443 }
1444 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1445 received_estind := true;
1446 if (not received_ua) {
1447 repeat;
1448 }
1449 }
1450 [] RSL.receive { repeat; }
1451 [] LAPDM.receive { repeat; }
1452 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1453 }
1454
1455 /* Test we can still send data afterwards */
1456 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1457 dls := valueof(t_init_LapdmDlState);
1458 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1459
1460 fp_common_fini();
1461}
1462testcase TC_normal_reestablishment_state_unacked() runs on test_CT {
1463 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1464 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment_state_unacked));
1465}
1466
Harald Welte72c81e72019-05-30 16:36:11 +02001467control {
Harald Welte72c81e72019-05-30 16:36:11 +02001468 execute(TC_sabm_ua_dcch_sapi0());
1469 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1470 execute(TC_sabm_ua_dcch_sapi3());
1471 execute(TC_sabm_ua_dcch_sapi4());
1472 execute(TC_sabm_contention());
1473 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001474 execute(TC_sabm_retransmit_bts());
1475 execute(TC_sabm_invalid_resp());
1476 execute(TC_sabm_dm());
1477 execute(TC_establish_ign_first_sabm());
1478 execute(TC_iframe_seq_and_ack());
1479 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001480 execute(TC_ns_seq_error());
1481 execute(TC_nr_seq_error());
1482 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001483 execute(TC_segm_concat_dcch());
1484 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001485 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001486 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001487 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001488 execute(TC_sabm_incorrect_c());
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001489 execute(TC_normal_reestablishment());
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001490 execute(TC_normal_reestablishment_state_unacked());
Harald Welte72c81e72019-05-30 16:36:11 +02001491}
1492
Harald Weltef6543322017-07-16 07:35:10 +02001493}