blob: 7dda8b884e0528024b66fa7c6ad1deee91a82751 [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
Andreas Eversberg412e9ab2023-11-17 11:55:35 +0100290 timer T := 20.0;
Harald Welte2f2b2b72019-05-31 22:24:57 +0200291 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));
Andreas Eversberg412e9ab2023-11-17 11:55:35 +0100314 pars.t_guard := 30.0;
Harald Welte2f2b2b72019-05-31 22:24:57 +0200315 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
316}
317
318
319type record LapdmNamedFrame {
320 charstring name,
321 LapdmFrame lapdm
322};
323
324/* Test that the BTS will ignore receipt of frames other than a UA when
325 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
326 * Section 25.2.1.1.2.3 */
327private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
328 var integer sapi := err_frame.lapdm.ab.addr.sapi;
329 fp_common_init();
330
331 /* Establish Request via RSL; Expect SABM on LAPDm side */
332 LAPDM.clear;
333 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
334 alt {
335 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
336 [] LAPDM.receive { repeat; }
337 }
338
339 /* send erroneous response to SABM */
340 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
341
342 /* expect a SABM retransmission of the BTS */
343 timer T := 3.0;
344 T.start;
345 alt {
346 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
347 setverdict(pass);
348 }
349 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
350 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
351 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
352 err_frame.name);
353 }
354 [] LAPDM.receive { repeat; }
355 [] T.timeout {
356 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
357 err_frame.name);
358 }
359 }
360
361 fp_common_fini();
362}
363private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
364 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
365 var LapdmNamedFrame err_frame[3] := {
366 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
367 l3 := '01020304'O)) },
368 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
369 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
370 };
371 var integer i;
372
373 for (i := 0; i < lengthof(err_frame); i := i+1) {
374 f_TC_sabm_invalid_resp2(id, err_frame[i])
375 }
376}
377testcase TC_sabm_invalid_resp() runs on test_CT {
378 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
379 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
380}
381
382/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
383 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
384private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
385 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
386 fp_common_init();
387
388 /* Establish Request via RSL; Expect SABM on LAPDm side */
389 LAPDM.clear;
390 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
391 alt {
392 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
393 [] LAPDM.receive { repeat; }
394 }
395
396 /* send DM response to SABM */
397 RSL.clear;
398 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
399 alt {
400 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
401 [] RSL.receive { repeat; }
402 }
403
404 /* expect no SABM retransmission of the BTS */
405 timer T := 3.0;
406 T.start;
407 alt {
408 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
409 setverdict(fail, "Received unexpected SABM retransmission");
410 }
411 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
412 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
413 setverdict(fail, "Received unexpected LAPDm frame");
414 }
415 [] LAPDM.receive { repeat; }
416 [] T.timeout {
417 setverdict(pass);
418 }
419 }
420
421 fp_common_fini();
422}
423testcase TC_sabm_dm() runs on test_CT {
424 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
425 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
426}
427
428/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
429 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
430 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
431private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
432 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
433 var integer num_sabm := 0;
434 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
435 timer T := 3.0;
436
437 fp_common_init();
438
439 /* Establish Request via RSL */
440 LAPDM.clear;
441 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
442 /* Expect two SABM (retransmit) */
443 T.start;
444 alt {
445 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
446 num_sabm := num_sabm + 1;
447 if (num_sabm < 2) {
448 repeat;
449 }
450 }
451 [] LAPDM.receive { repeat; }
452 }
453
454 /* send UA response to SABM */
455 RSL.clear;
456 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
457 alt {
458 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
459 [] RSL.receive { repeat; }
460 }
461
462 /* Send I frame from BTS to MS */
463 var octetstring l3 := f_rnd_octstring(10);
464 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
465 alt {
466 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
467 nr:=0, ns:=0, l3:=l3)));
468 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
469 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
470 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
471 }
472 /* Send RR frame in response */
473 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
474
475 /* expect idle UI Frame from BTS */
476 alt {
477 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
478 setverdict(pass);
479 }
480 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
481 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
482 }
483
484 fp_common_fini();
485}
486testcase TC_establish_ign_first_sabm() runs on test_CT {
487 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
488 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
489}
490
491/* ignore all SACCH frames */
492private altstep as_lapdm_acch() runs on ConnHdlr {
493 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
494}
Harald Welteef6fd442019-06-01 21:41:29 +0200495/* ignore all DCCH frames */
496private altstep as_lapdm_dcch() runs on ConnHdlr {
497 [] LAPDM.receive(t_PH_DATA(0, false, ?)) { repeat; }
498}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200499/* ignore all LAPDm idle frames (UI) */
500private altstep as_lapdm_idle() runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200501 [] LAPDM.receive(t_PH_DATA(0, ?, tr_LAPDm_UI(?, ?, ''O))) { repeat; }
Harald Welte2f2b2b72019-05-31 22:24:57 +0200502}
503/* ignore all measurement reports */
504private altstep as_rsl_meas_rep() runs on ConnHdlr {
505 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
506}
507/* fail if we receive an RSL ERROR IND */
508private altstep as_rsl_fail_err() runs on ConnHdlr {
509 var RSL_Message rx_rsl;
510 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
511 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
512 }
513}
514/* all of the above */
Eric Wild211acc32019-06-11 19:06:38 +0200515private altstep as_ignore_background(boolean want_dcch := true, boolean ignore_rsl_errors := false) runs on ConnHdlr {
Harald Welteef6fd442019-06-01 21:41:29 +0200516 [want_dcch] as_lapdm_acch();
517 [not want_dcch] as_lapdm_dcch();
Harald Welte2f2b2b72019-05-31 22:24:57 +0200518 [] as_lapdm_idle();
519 [] as_rsl_meas_rep();
Eric Wild211acc32019-06-11 19:06:38 +0200520 [not ignore_rsl_errors] as_rsl_fail_err();
521 [ignore_rsl_errors] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) { repeat;}
Harald Welte2f2b2b72019-05-31 22:24:57 +0200522}
523
524/* Test the operation of Layer 2 sequence numbering.
525 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
526private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
527 const integer sapi := 0;
528 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
529 var octetstring l3 := f_rnd_octstring(18);
530 var default d;
531 timer T := 3.0;
532
533 fp_common_init();
534
535 /* some common altstep for meas res and other background noise */
536 d := activate(as_ignore_background());
537 RSL.clear;
538 LAPDM.clear;
539
Harald Welte76771f12019-06-02 22:58:58 +0200540 f_establish_mo(link_id);
Harald Welte2f2b2b72019-05-31 22:24:57 +0200541
542 var integer last_ns_rx := 0;
543
544 for (var integer i := 0; i < 10; i := i+1) {
545 var octetstring l3_mo := f_rnd_octstring(12);
546 var octetstring l3_mt := f_rnd_octstring(12);
547 var LAPDm_ph_data pd;
548
549 log("Starting iteration ", i);
550 /* MT I frame */
551 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
552 alt {
553 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
554 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
555 nr:=i mod 8))) {
556 log("Ignoring RR in iteration ", i);
557 repeat;
558 }
559 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
560 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
561 nr:=i mod 8, ns:=i mod 8,
562 l3:=l3_mt))) -> value pd {
563 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
564 }
565 }
566 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
567 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
568 nr:=(last_ns_rx+1)mod 8,
569 ns:=i mod 8, l3 := l3_mo)));
570 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
571 }
572 log("Completed iteration");
573
574 deactivate(d);
575 fp_common_fini();
576}
577testcase TC_iframe_seq_and_ack() runs on test_CT {
578 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
579 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
580}
581
582/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
583 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
584
585/*
586 1) The BTS is brought into the multiple frame established state
587 2) The MS sends an L3 Request asking for IMEI to the MS.
588 3) The BTS shall respond with a RR frame though this may be incorporated with
589 the L3 Response I frame. The MS does not respond to the I frame.
590 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
591 with the P bit set to 1.
592 5) The MS then sends a valid L3 Request I frame asking for IMEI which
593 does not acknowledge receipt of the I frame from the BTS.
594On the FACCH the BTS may send an RR frame acknowledging the I frame.
595 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
596 the second I frame from the MS.
597 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
598 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
599*/
600private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
601 const integer sapi := 0;
602 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
603 var default d;
604 timer T := 3.0;
605
606 fp_common_init();
607
608 /* some common altstep for meas res and other background noise */
609 d := activate(as_ignore_background());
610 RSL.clear;
611 LAPDM.clear;
612
613 var octetstring l3_mo := f_rnd_octstring(12);
614 var octetstring l3_mt := f_rnd_octstring(12);
615
616 /* 1) The BTS is brought into the multiple frame established state */
617
618 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
619 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
620 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
621 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
622 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
623
624 /* 2) The MS sends an L3 Request to the BTS */
625 l3_mo := f_rnd_octstring(18);
626 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
627 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
628 nr:=0, ns:=0, l3:=l3_mo)));
629 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
630 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
631 the L3 Response I frame. The MS does not respond to the I frame. */
632 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
633 alt {
634 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
635 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
636 repeat;
637 }
638 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
639 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
640 nr:=1, ns:=0, l3:=l3_mt)));
641 }
642
643 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
644 with the P bit set to 1. */
645 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
646 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
647 nr:=1, ns:=0, l3:=l3_mt)));
648
649 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
650 does not acknowledge receipt of the I frame from the BTS. */
651 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
652 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
653 nr:=0, ns:=1, l3 := l3_mo)));
654 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
655 alt {
656 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
657 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
658 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
659 repeat;
660 }
661 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
662 receipt of the second I frame from the MS. */
663 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
664 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
665 nr:=2, ns:=0, l3:=l3_mt)));
666 }
667
668 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
669 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
670 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
671
672 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
673 l3_mt := f_rnd_octstring(16);
674 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
675 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
676 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
677 nr:=2, ns:=1, l3:=l3_mt)));
678 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
679
680 deactivate(d);
681 fp_common_fini();
682}
683testcase TC_iframe_timer_recovery() runs on test_CT {
684 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
685 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
686}
687
Eric Wild211acc32019-06-11 19:06:38 +0200688/* 25.2.6.1 ns sequence error
689sends wrong N(S), expects REJ, sends wrong N(S) with P=1, expects REJ with F=1 */
690private function f_TC_ns_seq_error(charstring id) runs on ConnHdlr {
691 const integer sapi := 0;
692 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
693 var default d;
694 timer T := 3.0;
695
696 fp_common_init();
697
698 /* some common altstep for meas res and other background noise */
699 d := activate(as_ignore_background(ignore_rsl_errors := true));
700 RSL.clear;
701 LAPDM.clear;
702
703 var octetstring l3_mo := f_rnd_octstring(12);
704 var octetstring l3_mt := f_rnd_octstring(12);
705
706 /* 1) The BTS is brought into the multiple frame established state */
707
708 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
709 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
710 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
711 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
712 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
713
714 /* 2) The MS sends an L3 Request to the BTS */
715 l3_mo := f_rnd_octstring(18);
716 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
717 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
718 nr:=0, ns:=0, l3:=l3_mo)));
719 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
720 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
721 the L3 Response I frame. */
722 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
723 alt {
724 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
725 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
726 repeat;
727 }
728 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
729 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
730 nr:=1, ns:=0, l3:=l3_mt)));
731 }
732
733 /* 4) The MS shall then send an I frame containing Identity Request with incorrect N(S)
734 but correctly acknowledging the MS's I frame; P bit set to zero. */
735 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
736 nr:=1, ns:=0, l3:=l3_mo)));
737
738 /* no rsl data ind due to wrong ns */
739
740 /* The BTS shall send a REJ frame. */
741 timer T1 := 2.0;
742 T1.start;
743 alt{
744 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
745 [] T1.timeout{ setverdict(fail, "Missing first REJ")}
746 }
747
748 f_sleep(2.0); // T200
749
750 /* The MS shall, after T200, send another I frame with incorrect N(S), P bit set to 1 this time. */
751 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true,
752 nr:=1, ns:=0, l3:=l3_mo)));
753
754 /* The BTS shall respond with a REJ, F bit set to 1. */
755 T1.start;
756 alt{
757 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
758 [] T1.timeout{ setverdict(fail, "Missing second REJ")}
759 }
760
761 deactivate(d);
762 fp_common_fini();
763 setverdict(pass);
764}
765
766testcase TC_ns_seq_error() runs on test_CT {
767 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
768 f_testmatrix_each_chan(pars, refers(f_TC_ns_seq_error));
769}
770
771/* 25.2.6.2 nr sequence error */
772private function f_TC_nr_seq_error(charstring id) runs on ConnHdlr {
773 const integer sapi := 0;
774 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
775 var default d;
776 var integer n201 := 20;
777 if (link_id.c == SACCH) {
778 n201 := 18;
779 }
780
781 fp_common_init();
782
783 /* some common altstep for meas res and other background noise */
784 d := activate(as_ignore_background(ignore_rsl_errors := true));
785 RSL.clear;
786 LAPDM.clear;
787
788 var octetstring l3_mo := f_rnd_octstring(12);
789 var octetstring l3_mt := f_rnd_octstring(12);
790
791 /* 1) The BTS is brought into the multiple frame established state */
792
793 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
794 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
795 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
796 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
797 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
798
799 /* 2) The MS shall send an I frame containing an information field of length N201 and an
800 incorrect receive sequence number. */
801 l3_mo := f_rnd_octstring(n201);
802 /* SAPI = 0, C = 1, P = 0, M = 0, L = N201, N(S) = 0, N(R) = 1. * */
803 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
804 nr:=1, ns:=0, l3:=l3_mo)));
Andreas Eversberg4aef7982023-10-20 16:12:33 +0200805 /* LAPD indicates the data and then indicates error with sequence error cause. */
806 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
807 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '07'O));
808 /* Release RSL link. */
809 RSL.send(ts_RSL_REL_REQ(g_chan_nr, link_id));
Eric Wild211acc32019-06-11 19:06:38 +0200810
811 /* The BTS may: a) send a DISC frame within N200×T200; */
812 /* DISC SAPI = 0, C = 0, P = 1, M = 0, L = 0. */
813 timer T1 := 2.0;
814 T1.start;
815 alt{
816 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_DISC(sapi, c_r:=cr_MT_CMD, p:=true)));
817 [] T1.timeout{ setverdict(fail, "Missing DISC from BTS")}
818 }
819
820 /* a) the MS shall respond with a UA frame.
821 SAPI = 0, R = 0, F = 1, M = 0, L = 0. */
822 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=true, l3:=l3_mo)));
823
824 deactivate(d);
825 fp_common_fini();
826 setverdict(pass);
827}
828
829testcase TC_nr_seq_error() runs on test_CT {
830 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
831 f_testmatrix_each_chan(pars, refers(f_TC_nr_seq_error));
832}
833
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100834private function f_TC_rec_invalid_frame_txrx(integer sapi, LapdmFrame x, integer line_nr) runs on ConnHdlr {
Eric Wild211acc32019-06-11 19:06:38 +0200835 LAPDM.send(t_PH_DATA(0, false, x));
836 f_sleep(2.0); // T200
837 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 +0100838 timer T1 := 2.0;
839 T1.start;
840 alt {
841 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true , nr := 0))) { T1.stop; }
842 [] T1.timeout{ Misc_Helpers.f_shutdown(__BFILE__, line_nr, fail, "Missing LAPDm_RR RSP"); }
843 }
Eric Wild211acc32019-06-11 19:06:38 +0200844}
845
846/* 25.2.7 Test on receipt of invalid frames
847sends a bunch of different invalid frames, expects the BTS to ignore all of them */
848private function f_TC_rec_invalid_frame(charstring id) runs on ConnHdlr {
849 const integer sapi := 0;
850 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
851 var default d;
852 timer T := 3.0;
853
854 fp_common_init();
855
856 /* some common altstep for meas res and other background noise */
857 d := activate(as_ignore_background(ignore_rsl_errors := true));
858 RSL.clear;
859 LAPDM.clear;
860
861 var octetstring l3_mo := f_rnd_octstring(12);
862 var octetstring l3_mt := f_rnd_octstring(12);
863
864 /* 1) The BTS is brought into the multiple frame established state */
865
866 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
867 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 +0100868 T.start
869 alt {
870 [] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo)) {}
871 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing RSL EST IND"); }
872 }
873 alt {
Eric Wild211acc32019-06-11 19:06:38 +0200874 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100875 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo))) { T.stop; }
876 [] T.timeout{ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Missing LAPDm UA RSP"); }
877 }
Eric Wild211acc32019-06-11 19:06:38 +0200878
879 /* 1: One RR frame: SAPI = 0, R = 0, F = 0, M = 0, L > 0, N(R) = 1.
880 RR frame with the Length indicator greater than zero and a faulty N(R); */
881 var LapdmFrame x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
882 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100883 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200884 /* 3: One REJ frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, N(R) = 1, EA = 0.
885 EJ frame with the EA bit set to zero and a faulty N(R); */
886 x:= valueof(ts_LAPDm_REJ(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
887 x.ab.addr.ea := false;
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 /* 4: One SABM frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, EL = 0.
890 SABM frame with the EL bit set to zero; */
891 l3_mo := ''O;
892 x:= valueof(ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo));
893 x.ab.el := 0;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100894 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200895 /* 5: One DM frame: SAPI = 0, R = 0, F = 1, M = 0, L > 0.
896 DM frame with the Length indicator greater than zero;*/
897 x:= valueof(ts_LAPDm_DM(sapi, c_r:=cr_MO_CMD, f:=true));
898 x.ab.payload := f_rnd_octstring(5);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100899 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200900 /* 6: One DISC frame: SAPI = 0, C = 1, P = 1, M = 1, L = 0.
901 DISC frame with the M bit set to 1; */
902 x:= valueof(ts_LAPDm_DISC(sapi, c_r:=cr_MO_CMD, p:=true));
903 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100904 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200905 /* 7: One UA frame: SAPI = 0, R = 0, F = 0, M = 0, L = 0, EA = 0.
906 UA frame with the EA bit set to zero*/
907 x:= valueof(ts_LAPDm_UA(sapi, c_r:=cr_MO_CMD, f:=false, l3:=''O));
908 x.ab.addr.ea := false;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100909 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200910 /* 8: One I frame: SAPI = 0, C = 1, P = 0, M = 0, L > N201, N(R) = 0, N(S) = 6.
911 I frame with the Length indicator greater than N201;*/
912 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 +0100913 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200914 /* 9: One I frame: SAPI = 0, C = 1, P = 0, M = 1, L < N201, N(R) = 0, N(S) = 7.
915 I frame with the M bit set to 1 and the Length indicator less than N201;*/
916 x:= valueof(ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr := 0, ns := 7, l3 := f_rnd_octstring(5)))
917 x.ab.m := true;
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100918 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200919 /* 10: One RR frame: SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0. */
920 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0));
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
923 /* command frames with correct Address and Length indicator field and a non-implemented control field */
924 /* 12: One command frame with Control Field = xxx1 1101. */
925 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
926 x.ab.ctrl.other := bit2int('00011101'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100927 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200928 /* 13: One command frame with Control field = xxx1 1011. */
929 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
930 x.ab.ctrl.other := bit2int('00011011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100931 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200932 /* 14: One command frame with Control field = xxx1 0111. */
933 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
934 x.ab.ctrl.other := bit2int('00010001'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100935 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200936 /* 15: One command frame with Control field = 01x1 1111. */
937 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
938 x.ab.ctrl.other := bit2int('01011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100939 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200940 /* 16: One command frame with Control field = 1xx1 1111. */
941 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
942 x.ab.ctrl.other := bit2int('10011111'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100943 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200944 /* 17: One command frame with Control field = 0011 0011. */
945 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
946 x.ab.ctrl.other := bit2int('00110011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100947 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200948 /* 18: One command frame with Control field = 1xx1 0011. */
949 x:= valueof(ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=false, nr:=1));
950 x.ab.ctrl.other := bit2int('10010011'B);
Pau Espin Pedrol26b562c2019-12-10 14:35:30 +0100951 f_TC_rec_invalid_frame_txrx(0, x, __LINE__);
Eric Wild211acc32019-06-11 19:06:38 +0200952
953 deactivate(d);
954 fp_common_fini();
955 setverdict(pass);
956}
957
958testcase TC_rec_invalid_frame() runs on test_CT {
959 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
960 pars.t_guard := 60.0;
961 f_testmatrix_each_chan(pars, refers(f_TC_rec_invalid_frame));
962}
963
Harald Welte9ea918c2019-06-01 11:46:25 +0200964type record LapdmDlConfig {
965 integer n201,
966 integer t200
967};
968
969type record LapdmDlState {
970 integer v_s,
971 integer v_a,
972 integer v_r
973};
974
975template (value) LapdmDlState t_init_LapdmDlState := {
976 v_s := 0,
977 v_a := 0,
978 v_r := 0
979}
980
981private function inc_mod8(inout integer v)
982{
983 v := (v + 1) mod 8;
984}
985
986private function f_lapdm_transceive_mo(inout LapdmDlState dls, RslLinkId link_id, octetstring l3)
987runs on ConnHdlr {
988 var LAPDm_ph_data pd;
989 var integer offset := 0;
990 var integer n201 := 20;
991 var boolean is_sacch := false;
992 if (link_id.c == SACCH) {
993 n201 := 18;
994 is_sacch := true;
995 }
996
997 while (offset < lengthof(l3)) {
998 var integer remain_len := lengthof(l3) - offset;
999 var integer seg_len := remain_len;
1000 if (remain_len > n201) {
1001 seg_len := n201;
1002 }
1003 var octetstring segment := substr(l3, offset, seg_len);
1004 var boolean more;
1005 if (offset + lengthof(segment) < lengthof(l3)) {
1006 more := true;
1007 } else {
1008 more := false;
1009 }
1010 /* send the next segment */
1011 LAPDM.send(t_PH_DATA(0, is_sacch,
1012 ts_LAPDm_I(link_id.sapi, c_r:=cr_MO_CMD, p:=false,
1013 nr:=dls.v_a, ns:=dls.v_s, l3:=segment, m:=more)));
1014 inc_mod8(dls.v_s);
1015 offset := offset + lengthof(segment);
1016
1017 /* wait for it to be acknowledged */
1018 alt {
1019 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(link_id.sapi, c_r:=cr_MT_RSP,
1020 p:=false, nr:=(dls.v_s) mod 8)));
Harald Welteef6fd442019-06-01 21:41:29 +02001021 [] as_ignore_background(not is_sacch);
Harald Welte9ea918c2019-06-01 11:46:25 +02001022 [] LAPDM.receive(t_PH_DATA(0, is_sacch, ?)) -> value pd {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001023 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("received unexpected LAPDm ", pd));
Harald Welte9ea918c2019-06-01 11:46:25 +02001024 }
1025 [] LAPDM.receive(t_PH_DATA(0, ?, ?)) { repeat; }
1026 [offset < lengthof(l3)] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001027 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "received RSL DATA IND before message complete");
Harald Welte9ea918c2019-06-01 11:46:25 +02001028 }
1029 }
1030 }
1031
1032 timer T := 1.0;
1033 T.start;
1034 alt {
1035 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
1036 setverdict(pass);
1037 }
1038 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, ?)) {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001039 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received RSL DATA IND with wrong payload");
Harald Welte9ea918c2019-06-01 11:46:25 +02001040 }
1041 [] T.timeout {
Pau Espin Pedrold6d69b52020-10-20 18:46:28 +02001042 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RSL DATA IND of de-segmented message");
Harald Welte9ea918c2019-06-01 11:46:25 +02001043 }
1044 }
1045}
1046
1047/* Section 5.8.5 of TS 04.06 */
1048const integer c_TS0406_MAX_L3_OCTETS := 251;
1049
Harald Welteef6fd442019-06-01 21:41:29 +02001050/* test segmentation and de-segmentation (concatenation) of a large message in uplink
1051 * on specified SAPI/channel */
1052private function f_TC_segm_concat(charstring id, RslLinkId link_id) runs on ConnHdlr {
1053 var integer sapi := link_id.sapi;
1054 var boolean is_sacch := false;
1055 if (link_id.c == SACCH) {
1056 is_sacch := true;
1057 }
Harald Welte9ea918c2019-06-01 11:46:25 +02001058 var default d;
1059 timer T := 3.0;
1060
1061 fp_common_init();
1062
1063 /* some common altstep for meas res and other background noise */
Harald Welteef6fd442019-06-01 21:41:29 +02001064 d := activate(as_ignore_background(not is_sacch));
Harald Welte9ea918c2019-06-01 11:46:25 +02001065 RSL.clear;
1066 LAPDM.clear;
1067
Harald Welte76771f12019-06-02 22:58:58 +02001068 f_establish_mo(link_id);
Harald Welte9ea918c2019-06-01 11:46:25 +02001069
Harald Welte76771f12019-06-02 22:58:58 +02001070 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
Harald Welte9ea918c2019-06-01 11:46:25 +02001071
1072 deactivate(d);
1073
1074 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1075 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1076
1077 fp_common_fini();
1078}
Harald Welteef6fd442019-06-01 21:41:29 +02001079private function f_TC_segm_concat_dcch(charstring id) runs on ConnHdlr {
1080 f_TC_segm_concat(id, valueof(ts_RslLinkID_DCCH(0)));
Harald Welte9ea918c2019-06-01 11:46:25 +02001081}
Harald Welteef6fd442019-06-01 21:41:29 +02001082private function f_TC_segm_concat_sacch(charstring id) runs on ConnHdlr {
1083 f_TC_segm_concat(id, link_id :=valueof(ts_RslLinkID_SACCH(0)));
1084}
1085/* test mobile-originated segmentation/de-segmentation on DCCH */
1086testcase TC_segm_concat_dcch() runs on test_CT {
1087 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1088 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_dcch));
1089}
1090/* test mobile-originated segmentation/de-segmentation on SACCH */
1091testcase TC_segm_concat_sacch() runs on test_CT {
1092 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1093 f_testmatrix_each_chan(pars, refers(f_TC_segm_concat_sacch));
1094}
1095
Harald Welteb2a30342019-06-02 22:13:50 +02001096/* TS 04.06 Section 5.8.2.1 */
1097private function f_n200_by_chan_nr(RslChannelNr chan_nr, RslLinkId link_id) return integer {
1098 /* SACCH irrespective of physical channel type */
1099 if (match(link_id, tr_RslLinkID_SACCH(?))) {
1100 return 5;
1101 }
1102 /* DCCH below */
1103 select (chan_nr) {
1104 case (t_RslChanNr_SDCCH4(?, ?)) { return 23; }
1105 case (t_RslChanNr_SDCCH8(?, ?)) { return 23; }
1106 case (t_RslChanNr_Bm(?)) { return 34; }
1107 case (t_RslChanNr_Lm(?, ?)) { return 29; }
1108 }
1109 setverdict(fail, "Unknown chan_nr ", chan_nr, " or link_id ", link_id);
1110 return -1;
1111}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001112
Harald Welteb2a30342019-06-02 22:13:50 +02001113/* Test if there are exactly N200+1 transmissions of I frames; inspired by 25.2.4.1 */
1114private function f_TC_t200_n200(charstring id) runs on ConnHdlr {
Andreas Eversberga56058e2023-06-12 09:25:35 +02001115 var RslLinkId link_id := valueof(ts_RslLinkID_SACCH(0));
Harald Welteb2a30342019-06-02 22:13:50 +02001116 var integer sapi := link_id.sapi;
1117 var boolean is_sacch := false;
1118 if (link_id.c == SACCH) {
1119 is_sacch := true;
1120 }
1121 var integer n200 := f_n200_by_chan_nr(g_chan_nr, link_id);
1122 var integer num_retrans := 0;
1123 timer T := 3.0;
1124 var default d;
1125
1126 fp_common_init();
1127
1128 /* some common altstep for meas res and other background noise */
Andreas Eversberga56058e2023-06-12 09:25:35 +02001129 d := activate(as_ignore_background(not is_sacch));
Harald Welteb2a30342019-06-02 22:13:50 +02001130 RSL.clear;
1131 LAPDM.clear;
1132
Harald Welte76771f12019-06-02 22:58:58 +02001133 f_establish_mo(link_id);
Harald Welteb2a30342019-06-02 22:13:50 +02001134
Andreas Eversberga56058e2023-06-12 09:25:35 +02001135 var octetstring l3_mt := f_rnd_octstring(18);
Harald Welteb2a30342019-06-02 22:13:50 +02001136 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1137 /* first transmission, P = 0 */
1138 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
1139 nr:=0, ns:=0, l3:=l3_mt)));
1140 deactivate(d);
1141
1142 alt {
1143 /* re-transmission, P = 1 */
1144 [] LAPDM.receive(t_PH_DATA(0, is_sacch,
1145 tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true, nr:=0, ns:=0, l3:=l3_mt))) {
1146 num_retrans := num_retrans + 1;
1147 if (num_retrans < n200) {
1148 repeat;
1149 } else if (num_retrans == n200) {
1150 T.start; /* wait for some more time if there are more retransmissions */
1151 repeat;
1152 } else {
1153 /* break */
1154 }
1155 }
Andreas Eversberga56058e2023-06-12 09:25:35 +02001156 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_I(sapi, ?, ?, ?, ?, ?))) {
Harald Welteb2a30342019-06-02 22:13:50 +02001157 setverdict(fail, "Received unexpected I frame");
1158 }
1159 [not is_sacch] as_lapdm_acch();
1160 [is_sacch] as_lapdm_dcch();
1161 [] as_lapdm_idle();
1162 [] as_rsl_meas_rep();
1163 [num_retrans == n200] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '01'O)) {
1164 /* break */
1165 }
1166 [] T.timeout {
1167 setverdict(fail, "Missing RSL RLL ERROR INDICATION");
1168 }
1169 }
1170
1171 if (num_retrans == n200) {
1172 setverdict(pass, "Received ", num_retrans, " on channel ", g_chan_nr, " link ", link_id);
1173 } else if (num_retrans < n200) {
1174 setverdict(fail, "Too few retransmissions (", num_retrans, "); N200=", n200,
1175 " on channel ", g_chan_nr, " link ", link_id);
1176 }
1177
1178 fp_common_fini();
1179}
1180testcase TC_t200_n200() runs on test_CT {
1181 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1182 f_testmatrix_each_chan(pars, refers(f_TC_t200_n200));
1183}
Harald Welte2f2b2b72019-05-31 22:24:57 +02001184
Harald Welte7d9f6db2019-06-02 23:14:04 +02001185/* Ensure BTS repeats RR frame after retransmitting I frame to emulate RR loss;
1186 Inspired by TS 51.010-1 25.2.4.3 */
1187private function f_TC_rr_response_frame_loss(charstring id) runs on ConnHdlr {
1188 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1189 var integer sapi := link_id.sapi;
1190 var boolean is_sacch := false;
1191 if (link_id.c == SACCH) {
1192 is_sacch := true;
1193 }
1194 timer T := 3.0;
1195 var default d;
1196
1197 fp_common_init();
1198
1199 /* some common altstep for meas res and other background noise */
1200 d := activate(as_ignore_background(true));
1201 RSL.clear;
1202 LAPDM.clear;
1203
1204 f_establish_mo(link_id);
1205
1206 var octetstring l3_mo := f_rnd_octstring(10);
1207 /* Send an I frame to the BTS: SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1208 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1209 l3:=l3_mo)));
1210 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1211 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
1212 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1213
1214 /* Re-send I frame: SAPI = 0, C = 1, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0. */
1215 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0, ns:=0,
1216 l3:=l3_mo)));
1217
1218 T.start;
1219 alt {
1220 /* RR: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1221 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1222 setverdict(pass);
1223 }
1224 /* REJ: SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1. */
1225 [] LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_REJ(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1))) {
1226 setverdict(pass);
1227 }
1228 [] T.timeout {
1229 setverdict(fail, "Timeout waiting for RR or REJ");
1230 }
1231 }
1232
1233 deactivate(d);
1234
1235 fp_common_fini();
1236}
1237testcase TC_rr_response_frame_loss() runs on test_CT {
1238 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1239 f_testmatrix_each_chan(pars, refers(f_TC_rr_response_frame_loss));
1240}
1241
Harald Welte44479782019-06-02 23:23:45 +02001242/* Ensure BTS ignores I frames with wrong C/R bit; Inspired by TS 51.010-1 25.2.5.1 */
1243private function f_TC_incorrect_cr(charstring id) runs on ConnHdlr {
1244 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1245 var integer sapi := link_id.sapi;
1246 var boolean is_sacch := false;
1247 if (link_id.c == SACCH) {
1248 is_sacch := true;
1249 }
1250 timer T := 3.0;
1251 var default d;
1252
1253 fp_common_init();
1254
1255 /* some common altstep for meas res and other background noise */
1256 d := activate(as_ignore_background(true));
1257 RSL.clear;
1258 LAPDM.clear;
1259
1260 f_establish_mo(link_id);
1261
1262 var octetstring l3_mo := f_rnd_octstring(10);
1263 /* Send an I frame to the BTS: SAPI = 0, C = 0, P = 1, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1264 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_RSP, p:=true, nr:=0, ns:=0,
1265 l3:=l3_mo)));
1266 T.start;
1267 alt {
1268 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo)) {
1269 setverdict(fail, "BTS didn't ignore I frame with wrong C/R bit");
1270 }
1271 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O)) {
1272 repeat;
1273 }
1274 /* ensure BTS still sends idle frames */
1275 [] as_lapdm_idle() {
1276 setverdict(pass, "still sending idle frames");
1277 }
1278 [] T.timeout {}
1279 }
1280
1281 /* Send RR command P=1 */
1282 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1283
1284 /* The BTS shall respond with a RR response, F bit set to 1. */
1285 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=0)));
1286
1287 deactivate(d);
1288
1289 fp_common_fini();
1290}
1291testcase TC_incorrect_cr() runs on test_CT {
1292 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1293 f_testmatrix_each_chan(pars, refers(f_TC_incorrect_cr));
1294}
Harald Weltea39ac752019-06-04 21:46:07 +02001295
1296/* test that the BTS will take no action when it receives an SABM frame with the C bit set wrong (R)
1297 Inspired by TS 51.010-1 25.2.5.2 */
1298private function f_TC_sabm_incorrect_c(charstring id) runs on ConnHdlr {
1299 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
1300 var integer sapi := link_id.sapi;
1301 var boolean is_sacch := false;
1302 if (link_id.c == SACCH) {
1303 is_sacch := true;
1304 }
1305 timer T := 3.0;
1306 var default d;
1307
1308 fp_common_init();
1309
1310 /* some common altstep for meas res and other background noise */
1311 d := activate(as_ignore_background(true));
1312 RSL.clear;
1313 LAPDM.clear;
1314
1315 f_establish_mo(link_id);
1316
1317 /* Send I-frame SAPI = 0, C = 1, P = 0, M = 0, L = 3, N(S) = 0, N(R) = 0 */
1318 var octetstring l3_mo := '010203'O;
1319 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false, nr:=0, ns:=0,
1320 l3:=l3_mo)));
1321 /* Expect RR SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1 */
1322 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1)));
1323 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
1324 /* Send SABM SAPI = 0, C = 0, P = 1, M = 0, L = 0 */
1325 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_SABM(sapi, c_r:=cr_MO_RSP, p:=true, l3:=''O)));
1326 /* Expect RSL ERR IND */
1327 RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, '0C'O));
1328 /* Expect fill frame C = 0, P = 0, M = 0, L = 0 */
1329 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_UI(0, ?, ''O)));
1330 /* Send RR command (P=1) SAPI = 0, C = 1, P = 1, M = 0, L = 0, N(R) = 0 */
1331 LAPDM.send(t_PH_DATA(0, is_sacch, ts_LAPDm_RR(sapi, c_r:=cr_MO_CMD, p:=true, nr:=0)));
1332 /* Expect RR response (F=1) SAPI = 0, R = 1, F = 1, M = 0, L = 0, N(R) = 1 */
1333 LAPDM.receive(t_PH_DATA(0, is_sacch, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=true, nr:=1)));
1334
1335 deactivate(d);
1336
1337 fp_common_fini();
1338}
1339testcase TC_sabm_incorrect_c() runs on test_CT {
1340 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1341 f_testmatrix_each_chan(pars, refers(f_TC_sabm_incorrect_c));
1342}
1343
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001344/* Test procedure for normal reestablishment, as per:
1345 * OS#4819
1346 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1347 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1348 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1349 * */
1350private function f_TC_normal_reestablishment(charstring id) runs on ConnHdlr {
1351 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1352 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1353 var default d;
1354 timer T := 3.0;
1355 var boolean use_sacch := false;
1356 var boolean received_estind := false;
1357 var boolean received_ua := false;
1358
1359 fp_common_init();
1360
1361 /* some common altstep for meas res and other background noise */
1362 d := activate(as_ignore_background(true));
1363 RSL.clear;
1364 LAPDM.clear;
1365
1366 f_establish_mo(link_id);
1367
1368 deactivate(d);
1369
1370 var LapdmDlState dls := valueof(t_init_LapdmDlState);
1371 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1372
1373 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)));
1374 T.start
1375 alt {
1376 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1377 received_ua := true;
1378 if (not received_estind) {
1379 repeat;
1380 }
1381 }
1382 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1383 received_estind := true;
1384 if (not received_ua) {
1385 repeat;
1386 }
1387 }
1388 [] RSL.receive { repeat; }
1389 [] LAPDM.receive { repeat; }
1390 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1391 }
1392
1393 /* Test we can still send data afterwards */
1394 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1395 dls := valueof(t_init_LapdmDlState);
1396 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1397
1398
1399 fp_common_fini();
1400}
1401testcase TC_normal_reestablishment() runs on test_CT {
1402 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1403 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment));
1404}
1405
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001406/* Test procedure for normal reestablishment in state LAPD_STATE_TIMER_RECOV (after T200, waiting for Ack), as per:
1407 * OS#4819
1408 * 3GPP TS 44.006 8.4.1.2 "Normal establishment procedure"
1409 * 3GPP TS 44.006 8.4.2.1 "General requirements"
1410 * 3GPP TS 44.006 8.6.3 "Procedures for re-establishment"
1411 * */
1412private function f_TC_normal_reestablishment_state_unacked(charstring id) runs on ConnHdlr {
1413 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0))
1414 var octetstring l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1415 var octetstring l3_mt := f_rnd_octstring(20);
1416 var LapdmDlState dls;
1417 var default d;
1418 timer T := 3.0;
1419 var boolean use_sacch := false;
1420 var boolean received_estind := false;
1421 var boolean received_ua := false;
1422
1423 fp_common_init();
1424
1425 /* some common altstep for meas res and other background noise */
1426 d := activate(as_ignore_background(true));
1427 RSL.clear;
1428 LAPDM.clear;
1429
1430 f_establish_mo(link_id);
1431 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
1432 /* first transmission, P = 0 */
1433 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=false,
1434 nr:=0, ns:=0, l3:=l3_mt)));
1435 /* re-transmission, P = 1 */
1436 LAPDM.receive(t_PH_DATA(0, use_sacch, tr_LAPDm_I(link_id.sapi, c_r:=cr_MT_CMD, p:=true,
1437 nr:=0, ns:=0, l3:=l3_mt)));
1438 deactivate(d);
1439
1440 /* We received one retrans, so peer is in LAPD_STATE_TIMER_RECOV state. Now send SABM: */
1441 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)));
1442 T.start
1443 alt {
1444 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_UA(link_id.sapi, cr_MT_RSP, f:=true, l3:=''O))) {
1445 received_ua := true;
1446 if (not received_estind) {
1447 repeat;
1448 }
1449 }
1450 [] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id)) {
1451 received_estind := true;
1452 if (not received_ua) {
1453 repeat;
1454 }
1455 }
1456 [] RSL.receive { repeat; }
1457 [] LAPDM.receive { repeat; }
1458 [] T.timeout { setverdict(fail, "Timeout waiting for UA"); }
1459 }
1460
1461 /* Test we can still send data afterwards */
1462 l3_mo := f_rnd_octstring(c_TS0406_MAX_L3_OCTETS);
1463 dls := valueof(t_init_LapdmDlState);
1464 f_lapdm_transceive_mo(dls, link_id, l3_mo);
1465
1466 fp_common_fini();
1467}
1468testcase TC_normal_reestablishment_state_unacked() runs on test_CT {
1469 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
1470 f_testmatrix_each_chan(pars, refers(f_TC_normal_reestablishment_state_unacked));
1471}
1472
Harald Welte72c81e72019-05-30 16:36:11 +02001473control {
Harald Welte72c81e72019-05-30 16:36:11 +02001474 execute(TC_sabm_ua_dcch_sapi0());
1475 execute(TC_sabm_ua_dcch_sapi0_nopayload());
1476 execute(TC_sabm_ua_dcch_sapi3());
1477 execute(TC_sabm_ua_dcch_sapi4());
1478 execute(TC_sabm_contention());
1479 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +02001480 execute(TC_sabm_retransmit_bts());
1481 execute(TC_sabm_invalid_resp());
1482 execute(TC_sabm_dm());
1483 execute(TC_establish_ign_first_sabm());
1484 execute(TC_iframe_seq_and_ack());
1485 execute(TC_iframe_timer_recovery());
Eric Wild211acc32019-06-11 19:06:38 +02001486 execute(TC_ns_seq_error());
1487 execute(TC_nr_seq_error());
1488 execute(TC_rec_invalid_frame());
Harald Welteef6fd442019-06-01 21:41:29 +02001489 execute(TC_segm_concat_dcch());
1490 execute(TC_segm_concat_sacch());
Harald Welteb2a30342019-06-02 22:13:50 +02001491 execute(TC_t200_n200());
Harald Welte7d9f6db2019-06-02 23:14:04 +02001492 execute(TC_rr_response_frame_loss());
Harald Welte44479782019-06-02 23:23:45 +02001493 execute(TC_incorrect_cr());
Harald Weltea39ac752019-06-04 21:46:07 +02001494 execute(TC_sabm_incorrect_c());
Pau Espin Pedrol820b4742020-10-19 20:19:14 +02001495 execute(TC_normal_reestablishment());
Pau Espin Pedrolfaf97062020-10-20 13:19:33 +02001496 execute(TC_normal_reestablishment_state_unacked());
Harald Welte72c81e72019-05-30 16:36:11 +02001497}
1498
Harald Weltef6543322017-07-16 07:35:10 +02001499}