blob: 2eade0a9a94b1c08e626cb799bc217a59d31fb12 [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;
Harald Welte2f2b2b72019-05-31 22:24:57 +02009import from Misc_Helpers all;
Harald Welte66110f02017-07-16 21:05:18 +020010
Harald Welte72c81e72019-05-30 16:36:11 +020011/* test that use exclusively only LAPDm over L1CTL */
12type component lapdm_test_CT {
13 port LAPDm_PT LAPDM;
14 var lapdm_CT lapdm_component;
15};
16
17/* contrary to BTS_Tests.ttcn, we use LAPDm_PT here, a convenience wrapper
18 * around L1CTL to perform encode/decode of abstract LAPDm frames */
Harald Welte72c81e72019-05-30 16:36:11 +020019
Harald Welte61332c02019-05-30 16:45:15 +020020/*********************************************************************************
21 * Test using only L1CTL/LAPDm
22 *********************************************************************************/
23
24function f_lapdm_init() runs on lapdm_test_CT {
Harald Welte72c81e72019-05-30 16:36:11 +020025 /* create the LAPDm component */
26 lapdm_component := lapdm_CT.create;
27 /* connect our own LAPDM port to the LAPDM Service Provider of the LAPDm component */
28 connect(self:LAPDM, lapdm_component:LAPDM_SP);
29 /* connect the LAPDm compoent's lower-side port to the system L1CTL port (which is internally
30 * connected to the Unix Domain Socket test port */
31 map(lapdm_component:L1CTL, system:L1CTL);
32
33 /* start the LAPDm parallel component calling it's local function LAPDmStart */
34 lapdm_component.start(LAPDmStart());
35}
36
Harald Welte2f2b2b72019-05-31 22:24:57 +020037function f_lapdm_exit() runs on lapdm_test_CT {
38 lapdm_component.stop;
39 lapdm_component.done;
40 unmap(lapdm_component:L1CTL, system:L1CTL);
41}
42
Harald Welte72c81e72019-05-30 16:36:11 +020043/* master function establishing a dedicated radio channel (takes care of RACH/IMM.ASS handling) */
44function f_establish_dcch() runs on lapdm_test_CT {
Harald Welte2f2b2b72019-05-31 22:24:57 +020045 var BCCH_tune_req tune_req := { arfcn := { false, mp_trx0_arfcn }, combined_ccch := true };
Harald Welte72c81e72019-05-30 16:36:11 +020046 var DCCH_establish_req est_req := { ra := 23 };
47
48 LAPDM.send(tune_req);
49 LAPDM.send(est_req);
50 LAPDM.receive(DCCH_establish_res:?);
51}
52
Harald Welte2f2b2b72019-05-31 22:24:57 +020053/* master function switching to a dedicated radio channel */
54function f_switch_dcch(Arfcn arfcn, RslChannelNr chan_nr, GsmTsc tsc) runs on lapdm_test_CT {
55 var BCCH_tune_req tune_req := { arfcn := arfcn, combined_ccch := true };
56 var DCCH_switch_req sw_req := { arfcn, chan_nr, tsc };
57
58 LAPDM.send(tune_req);
59 LAPDM.send(sw_req);
60 LAPDM.receive(DCCH_switch_res:?);
61}
62
Harald Welte72c81e72019-05-30 16:36:11 +020063/* helper function releasing dedicated radio channel physically (no Um signaling!) */
64function f_release_dcch() runs on lapdm_test_CT {
65 var DCCH_release_req rel_req := {};
66 LAPDM.send(rel_req);
67}
68
69template LAPDm_ph_data t_PH_DATA(template GsmSapi sapi, template boolean sacch, template LapdmFrame frame) := {
70 sacch := sacch,
71 sapi := sapi,
72 lapdm := frame
73}
74/* template for a valid SABM frame */
75template LapdmFrame LAPDm_B_SABM(template GsmSapi sapi, octetstring payload) := {
76 ab := {
77 addr := tr_LapdmAddr(sapi, false),
78 ctrl := tr_LapdmCtrlSABM(true),
79 len := lengthof(payload),
80 m := false,
81 el := 1,
82 payload := payload
Harald Weltec38611b2019-05-30 16:33:58 +020083 }
Harald Welte72c81e72019-05-30 16:36:11 +020084}
Harald Weltec38611b2019-05-30 16:33:58 +020085
Harald Welte72c81e72019-05-30 16:36:11 +020086/* template for a valid UA frame */
87template LapdmFrame tr_LAPDm_B_UA(template GsmSapi sapi, template octetstring payload) := {
88 ab := {
89 addr := tr_LapdmAddr(sapi, false),
90 ctrl := tr_LapdmCtrlUA(true),
91 len := ?,
92 m := false,
93 el := 1,
94 payload := payload
Harald Welte52c713c2017-07-16 15:44:44 +020095 }
Harald Welte72c81e72019-05-30 16:36:11 +020096}
Harald Welte52c713c2017-07-16 15:44:44 +020097
Harald Welte72c81e72019-05-30 16:36:11 +020098/* template for a valid UA frame */
99template LapdmFrame LAPDm_B_UA(template GsmSapi sapi, octetstring payload) := {
100 ab := {
101 addr := tr_LapdmAddr(sapi, false),
102 ctrl := tr_LapdmCtrlUA(true),
103 len := lengthof(payload),
104 m := false,
105 el := 1,
106 payload := payload
Harald Welte9e4725d2017-07-16 23:18:09 +0200107 }
Harald Welte72c81e72019-05-30 16:36:11 +0200108}
Harald Welte66110f02017-07-16 21:05:18 +0200109
Harald Welte72c81e72019-05-30 16:36:11 +0200110/* template for a valid UI frame */
111template LapdmFrame LAPDm_B_UI(template GsmSapi sapi, octetstring payload) := {
112 ab := {
113 addr := tr_LapdmAddr(sapi, true),
114 ctrl := tr_LapdmCtrlUI(false),
115 len := lengthof(payload),
116 m := false,
117 el := 1,
118 payload := payload
Harald Welte9e4725d2017-07-16 23:18:09 +0200119 }
Harald Welte72c81e72019-05-30 16:36:11 +0200120}
Harald Welte9e4725d2017-07-16 23:18:09 +0200121
Harald Welte72c81e72019-05-30 16:36:11 +0200122template LapdmFrame t_nopayload(template GsmSapi sapi) := {
123 ab := {
124 addr := tr_LapdmAddr(sapi, true),
125 ctrl := ?,
126 len := 0,
127 m := false,
128 el := 1,
129 payload := ''O
Harald Welted4ba7ff2017-07-17 21:00:48 +0200130 }
Harald Welte72c81e72019-05-30 16:36:11 +0200131}
132
133template LapdmFrame LAPDm_B_DISC(template GsmSapi sapi) modifies t_nopayload := {
134 ab := {
135 ctrl := tr_LapdmCtrlDISC(true)
136 }
137}
138
139template LapdmFrame LAPDm_B_RR(template GsmSapi sapi, template uint3_t nr) modifies t_nopayload := {
140 ab := {
141 ctrl := tr_LapdmCtrlRR(nr, false)
142 }
143}
144
145
146function f_test_sabm_results_in_ua(uint8_t sapi, boolean use_sacch, octetstring payload) runs on lapdm_test_CT return boolean {
147 var LAPDm_ph_data phd;
148 var boolean result := false;
149 timer T := 5.0;
150
151 f_establish_dcch();
152 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload)));
153 log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload)));
154 T.start
155 alt {
156 [] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { result := true; }
157 [] LAPDM.receive(t_PH_DATA(?, use_sacch, ?)) -> value phd { log("Other msg on DCH: ", phd); repeat; }
158 [] LAPDM.receive(t_PH_DATA(?, ?, ?)) -> value phd { log("Other PH-DATA: ", phd); repeat; }
159 [] T.timeout { }
160 }
161 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_RR(sapi, 0)));
162 f_release_dcch();
163 return result;
164}
165
166testcase TC_sabm_ua_dcch_sapi0() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200167 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200168 if (not f_test_sabm_results_in_ua(0, false, 'FEFE'O)) {
169 setverdict(fail);
170 }
171 setverdict(pass);
172}
173
174testcase TC_sabm_ua_dcch_sapi0_nopayload() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200175 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200176 if (f_test_sabm_results_in_ua(0, false, ''O)) {
177 setverdict(fail, "Initial SABM/UA must contain L3 payload but BTS accepts without");
178 }
179 setverdict(pass);
180}
181
182testcase TC_sabm_ua_dcch_sapi3() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200183 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200184 if (f_test_sabm_results_in_ua(3, false, 'FEFE'O)) {
185 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=3");
186 }
187 setverdict(pass);
188}
189
190testcase TC_sabm_ua_dcch_sapi4() runs on lapdm_test_CT {
Harald Welte61332c02019-05-30 16:45:15 +0200191 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200192 if (f_test_sabm_results_in_ua(4, false, 'FEFE'O)) {
193 setverdict(fail, "Initial SABM/UA must be on SAPI0, but BTS accepts SAPI=4");
194 }
195 setverdict(pass);
196}
197
198testcase TC_sabm_contention() runs on lapdm_test_CT {
199 var LAPDm_ph_data phd;
200 const octetstring payload := '0102030405'O;
201 const GsmSapi sapi := 0;
202 const boolean use_sacch := false;
203 timer T := 5.0;
204
Harald Welte61332c02019-05-30 16:45:15 +0200205 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200206
207 f_establish_dcch();
208 /* first frame is our real SABM */
209 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, payload)));
210 /* second frame is a SABM with different payload, which BTS has to ignore according to 8.4.1.4 */
211 LAPDM.send(t_PH_DATA(sapi, use_sacch, LAPDm_B_SABM(sapi, 'ABCDEF'O)));
212 log("====> expecting ", t_PH_DATA(sapi, use_sacch, LAPDm_B_UA(sapi, payload)));
213 T.start
214 alt {
215 [] LAPDM.receive(t_PH_DATA(?, use_sacch, LAPDm_B_UA(sapi, payload))) { setverdict(pass); repeat; }
216 [] LAPDM.receive(t_PH_DATA(?, use_sacch, tr_LAPDm_B_UA(sapi, ?))) {
217 setverdict(fail, "Second SABM was responded to during contention resolution");
Harald Welted4ba7ff2017-07-17 21:00:48 +0200218 }
Harald Welte72c81e72019-05-30 16:36:11 +0200219 [] LAPDM.receive { repeat };
220 [] T.timeout { }
Harald Welte9e4725d2017-07-16 23:18:09 +0200221 }
Harald Welte72c81e72019-05-30 16:36:11 +0200222 f_release_dcch();
223}
Harald Welte9e4725d2017-07-16 23:18:09 +0200224
Harald Welte72c81e72019-05-30 16:36:11 +0200225/* we test that a re-transmitted SABM with identical payload will result in the retransmission of a
226 * UA. This is required during the contention resolution procedure as specified in 8.4.1.4 */
227testcase TC_sabm_retransmit() runs on lapdm_test_CT {
228 const octetstring payload := '00FEFEDEADBEEF'O;
Harald Welte61332c02019-05-30 16:45:15 +0200229 f_lapdm_init();
Harald Welte72c81e72019-05-30 16:36:11 +0200230 if (not f_test_sabm_results_in_ua(0, false, payload)) {
231 setverdict(fail, "UA not received for first SABM");
Harald Welte599faa12017-07-17 21:49:24 +0200232 }
Harald Welte72c81e72019-05-30 16:36:11 +0200233 if (not f_test_sabm_results_in_ua(0, false, payload)) {
234 setverdict(fail, "UA not received for second SABM");
Harald Welted4ba7ff2017-07-17 21:00:48 +0200235 }
Harald Welte72c81e72019-05-30 16:36:11 +0200236 setverdict(pass);
237}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200238
Harald Welte72c81e72019-05-30 16:36:11 +0200239testcase TC_foo() runs on lapdm_test_CT {
240 var LapdmFrame lf;
Harald Welted4ba7ff2017-07-17 21:00:48 +0200241/*
Harald Welte72c81e72019-05-30 16:36:11 +0200242 var LapdmFrame lf := valueof(LAPDm_B_UA(0, ''O));
243 log("ENC UA: ", enc_LapdmFrame(lf));
244 lf := valueof(LAPDm_B_UI(0, ''O));
245 log("ENC UI B: ", enc_LapdmFrame(lf));
246 log("ENC UI B: ", enc_LapdmFrameB(lf.b));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200247
Harald Welte72c81e72019-05-30 16:36:11 +0200248 log("DEC UI AF: ", dec_LapdmAddressField('03'O));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200249*/
Harald Welteffcad682017-07-30 22:51:04 +0200250
Harald Welte72c81e72019-05-30 16:36:11 +0200251 lf := valueof(LAPDm_B_RR(0, 0));
252 log("ENC RR: ", enc_LapdmFrame(lf));
Harald Welteffcad682017-07-30 22:51:04 +0200253
Harald Welte72c81e72019-05-30 16:36:11 +0200254 lf := valueof(LAPDm_B_UA(0, ''O));
255 log("ENC UA: ", enc_LapdmFrame(lf));
Harald Welteffcad682017-07-30 22:51:04 +0200256
Harald Welte72c81e72019-05-30 16:36:11 +0200257 lf := valueof(LAPDm_B_UI(0, ''O));
258 log("ENC UI: ", enc_LapdmFrame(lf));
Harald Welteffcad682017-07-30 22:51:04 +0200259
Harald Welte72c81e72019-05-30 16:36:11 +0200260 log("DEC UI CU: ", dec_LapdmCtrlU('03'O));
261 log("DEC UI CT: ", dec_LapdmCtrl('03'O));
Harald Welted4ba7ff2017-07-17 21:00:48 +0200262
Harald Welte72c81e72019-05-30 16:36:11 +0200263 log("DEC UA: ", dec_LapdmFrameAB('017301'O));
264 log("DEC UI: ", dec_LapdmFrameAB('030301'O));
265 log("DEC I: ", dec_LapdmFrameAB('030001'O));
266 log("DEC S: ", dec_LapdmFrameAB('030101'O));
267 log("DEC: ", dec_LapdmFrameAB('030301'O));
268 log("DEC: ", dec_LapdmFrameAB('0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O));
269}
Harald Welted4ba7ff2017-07-17 21:00:48 +0200270
Harald Welte2f2b2b72019-05-31 22:24:57 +0200271/*********************************************************************************
272 * Test using both L1CTL/LAPDm and RSL
273 *********************************************************************************/
274
275private function fp_common_init() runs on ConnHdlr
276{
277 /* undo what f_start_handler is doing and pull LAPDm_CT into the loop */
278 unmap(self:L1CTL, system:L1CTL);
279 f_lapdm_init();
280 /* activate the channel on the BTS side */
281 f_rsl_chan_act(g_pars.chan_mode, false, {});
282 /* activate the channel on the MS side */
283 f_switch_dcch({false, mp_trx0_arfcn}, g_chan_nr, 7);
284}
285
286private function fp_common_fini() runs on ConnHdlr
287{
288 f_release_dcch();
289 f_rsl_chan_deact();
290 f_lapdm_exit();
291}
292
293/* Verify that the BTS is re-transmitting SABM messages after T200 timeout, inspired
294 by 3GPP TS 51.010-1 25.2.1.1.2.1 + 25.2.1.2.4 */
295private function f_TC_sabm_retransmit_bts(charstring id) runs on ConnHdlr {
296 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
297 fp_common_init();
298
299 LAPDM.clear;
300 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
301
302 timer T := 8.0;
303 var integer sabm_received := 0;
304 T.start;
305 alt {
306 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
307 sabm_received := sabm_received + 1;
308 repeat;
309 }
310 [] LAPDM.receive { repeat; }
311 [] T.timeout { }
312 }
313 if (sabm_received == 0) {
314 setverdict(fail, "No SABM observed at all!");
315 } else if (sabm_received != 6) {
316 setverdict(fail, "Incorrect number of SABM re-transmissions of observed: ",
317 sabm_received);
318 } else {
319 setverdict(pass, "Received ", sabm_received, " SABM");
320 }
321
322 fp_common_fini();
323}
324testcase TC_sabm_retransmit_bts() runs on test_CT {
325 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
326 f_testmatrix_each_chan(pars, refers(f_TC_sabm_retransmit_bts));
327}
328
329
330type record LapdmNamedFrame {
331 charstring name,
332 LapdmFrame lapdm
333};
334
335/* Test that the BTS will ignore receipt of frames other than a UA when
336 * received in response to the SABM frame, inspired from 3GPP TS 51.010-1
337 * Section 25.2.1.1.2.3 */
338private function f_TC_sabm_invalid_resp2(charstring id, LapdmNamedFrame err_frame) runs on ConnHdlr {
339 var integer sapi := err_frame.lapdm.ab.addr.sapi;
340 fp_common_init();
341
342 /* Establish Request via RSL; Expect SABM on LAPDm side */
343 LAPDM.clear;
344 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
345 alt {
346 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
347 [] LAPDM.receive { repeat; }
348 }
349
350 /* send erroneous response to SABM */
351 LAPDM.send(t_PH_DATA(0, false, err_frame.lapdm));
352
353 /* expect a SABM retransmission of the BTS */
354 timer T := 3.0;
355 T.start;
356 alt {
357 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
358 setverdict(pass);
359 }
360 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
361 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
362 setverdict(fail, "Received unexpected LAPDm frame instead of SABM after sending ",
363 err_frame.name);
364 }
365 [] LAPDM.receive { repeat; }
366 [] T.timeout {
367 setverdict(fail, "Timeout waiting for SABM retransmission after sending ",
368 err_frame.name);
369 }
370 }
371
372 fp_common_fini();
373}
374private function f_TC_sabm_invalid_resp(charstring id) runs on ConnHdlr {
375 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
376 var LapdmNamedFrame err_frame[3] := {
377 { "I", valueof(ts_LAPDm_I(sapi, c_r := cr_MO_CMD, p := true, nr := 0, ns := 0,
378 l3 := '01020304'O)) },
379 { "RR", valueof(ts_LAPDm_RR(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) },
380 { "REJ" , valueof(ts_LAPDm_REJ(sapi, c_r := cr_MO_CMD, p := true, nr := 0)) }
381 };
382 var integer i;
383
384 for (i := 0; i < lengthof(err_frame); i := i+1) {
385 f_TC_sabm_invalid_resp2(id, err_frame[i])
386 }
387}
388testcase TC_sabm_invalid_resp() runs on test_CT {
389 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
390 f_testmatrix_each_chan(pars, refers(f_TC_sabm_invalid_resp));
391}
392
393/* Test that the BTS will not re-transmit SABM frames after receiving a DM response,
394 * inspired from 3GPP TS 51.010-1 Section 25.2.1.1.3 */
395private function f_TC_sabm_dm(charstring id) runs on ConnHdlr {
396 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
397 fp_common_init();
398
399 /* Establish Request via RSL; Expect SABM on LAPDm side */
400 LAPDM.clear;
401 RSL.send(ts_RSL_EST_REQ(g_chan_nr, ts_RslLinkID_DCCH(sapi)));
402 alt {
403 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O)));
404 [] LAPDM.receive { repeat; }
405 }
406
407 /* send DM response to SABM */
408 RSL.clear;
409 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_DM(sapi, c_r:=cr_MO_RSP, f:=true)));
410 alt {
411 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tr_RslLinkID_DCCH(sapi)));
412 [] RSL.receive { repeat; }
413 }
414
415 /* expect no SABM retransmission of the BTS */
416 timer T := 3.0;
417 T.start;
418 alt {
419 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
420 setverdict(fail, "Received unexpected SABM retransmission");
421 }
422 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
423 [] LAPDM.receive(t_PH_DATA(0, false, ?)) {
424 setverdict(fail, "Received unexpected LAPDm frame");
425 }
426 [] LAPDM.receive { repeat; }
427 [] T.timeout {
428 setverdict(pass);
429 }
430 }
431
432 fp_common_fini();
433}
434testcase TC_sabm_dm() runs on test_CT {
435 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
436 f_testmatrix_each_chan(pars, refers(f_TC_sabm_dm));
437}
438
439/* Test the full LAPDm establishment while simulating the loss of the initial SABM or UA
440 * frame, requiring the BTS to re-transmit one SABM and then following up all the way to
441 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.1.2.2 */
442private function f_TC_establish_ign_first_sabm(charstring id) runs on ConnHdlr {
443 const integer sapi := 3; /* BTS may not establish SAPI=0 outbound */
444 var integer num_sabm := 0;
445 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
446 timer T := 3.0;
447
448 fp_common_init();
449
450 /* Establish Request via RSL */
451 LAPDM.clear;
452 RSL.send(ts_RSL_EST_REQ(g_chan_nr, link_id));
453 /* Expect two SABM (retransmit) */
454 T.start;
455 alt {
456 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_SABM(sapi, ?, ?, ''O))) {
457 num_sabm := num_sabm + 1;
458 if (num_sabm < 2) {
459 repeat;
460 }
461 }
462 [] LAPDM.receive { repeat; }
463 }
464
465 /* send UA response to SABM */
466 RSL.clear;
467 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_UA(sapi, c_r:=cr_MO_RSP, f:=true, l3:=''O)));
468 alt {
469 [] RSL.receive(tr_RSL_EST_CONF(g_chan_nr, link_id));
470 [] RSL.receive { repeat; }
471 }
472
473 /* Send I frame from BTS to MS */
474 var octetstring l3 := f_rnd_octstring(10);
475 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3));
476 alt {
477 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
478 nr:=0, ns:=0, l3:=l3)));
479 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
480 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
481 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
482 }
483 /* Send RR frame in response */
484 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=false, nr:=1)));
485
486 /* expect idle UI Frame from BTS */
487 alt {
488 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) {
489 setverdict(pass);
490 }
491 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
492 [] LAPDM.receive { setverdict(fail, "Unexpected LAPDm received"); }
493 }
494
495 fp_common_fini();
496}
497testcase TC_establish_ign_first_sabm() runs on test_CT {
498 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
499 f_testmatrix_each_chan(pars, refers(f_TC_establish_ign_first_sabm));
500}
501
502/* ignore all SACCH frames */
503private altstep as_lapdm_acch() runs on ConnHdlr {
504 [] LAPDM.receive(t_PH_DATA(0, true, ?)) { repeat; }
505}
506/* ignore all LAPDm idle frames (UI) */
507private altstep as_lapdm_idle() runs on ConnHdlr {
508 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UI(0, ?, ''O))) { repeat; }
509}
510/* ignore all measurement reports */
511private altstep as_rsl_meas_rep() runs on ConnHdlr {
512 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr)) { repeat; }
513}
514/* fail if we receive an RSL ERROR IND */
515private altstep as_rsl_fail_err() runs on ConnHdlr {
516 var RSL_Message rx_rsl;
517 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, ?, ?)) {
518 setverdict(fail, "Received RSL ERROR IND ", rx_rsl);
519 }
520}
521/* all of the above */
522private altstep as_ignore_background() runs on ConnHdlr {
523 [] as_lapdm_acch();
524 [] as_lapdm_idle();
525 [] as_rsl_meas_rep();
526 [] as_rsl_fail_err();
527}
528
529/* Test the operation of Layer 2 sequence numbering.
530 * dedicated mode; inspired by 3GPP TS 51.010-1 25.2.2.1 */
531private function f_TC_iframe_seq_and_ack(charstring id) runs on ConnHdlr {
532 const integer sapi := 0;
533 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
534 var octetstring l3 := f_rnd_octstring(18);
535 var default d;
536 timer T := 3.0;
537
538 fp_common_init();
539
540 /* some common altstep for meas res and other background noise */
541 d := activate(as_ignore_background());
542 RSL.clear;
543 LAPDM.clear;
544
545 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
546 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3)));
547 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3));
548 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
549 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3)));
550
551 var integer last_ns_rx := 0;
552
553 for (var integer i := 0; i < 10; i := i+1) {
554 var octetstring l3_mo := f_rnd_octstring(12);
555 var octetstring l3_mt := f_rnd_octstring(12);
556 var LAPDm_ph_data pd;
557
558 log("Starting iteration ", i);
559 /* MT I frame */
560 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
561 alt {
562 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0. */
563 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false,
564 nr:=i mod 8))) {
565 log("Ignoring RR in iteration ", i);
566 repeat;
567 }
568 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201. */
569 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
570 nr:=i mod 8, ns:=i mod 8,
571 l3:=l3_mt))) -> value pd {
572 last_ns_rx := pd.lapdm.ab.ctrl.i.n_s;
573 }
574 }
575 /* respond with MO I-frame: SAPI = 0, C = 0, P = 0, M = 0, 0 <= L <= N201. */
576 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
577 nr:=(last_ns_rx+1)mod 8,
578 ns:=i mod 8, l3 := l3_mo)));
579 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
580 }
581 log("Completed iteration");
582
583 deactivate(d);
584 fp_common_fini();
585}
586testcase TC_iframe_seq_and_ack() runs on test_CT {
587 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
588 f_testmatrix_each_chan(pars, refers(f_TC_iframe_seq_and_ack));
589}
590
591/* To test that the BTS is able to respond to I frames whilst in the timer recovery state.
592 * Inspired by 3GPP TS 51.010-1 25.2.2.2 */
593
594/*
595 1) The BTS is brought into the multiple frame established state
596 2) The MS sends an L3 Request asking for IMEI to the MS.
597 3) The BTS shall respond with a RR frame though this may be incorporated with
598 the L3 Response I frame. The MS does not respond to the I frame.
599 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
600 with the P bit set to 1.
601 5) The MS then sends a valid L3 Request I frame asking for IMEI which
602 does not acknowledge receipt of the I frame from the BTS.
603On the FACCH the BTS may send an RR frame acknowledging the I frame.
604 6) The BTS shall repeat the I frame, this frame will acknowledge receipt of
605 the second I frame from the MS.
606 7) The MS then acknowledges receipt of the MS I frame by sending a RR frame.
607 8) The BTS shall send the next I frame. The MS acknowledges this I frame.
608*/
609private function f_TC_iframe_timer_recovery(charstring id) runs on ConnHdlr {
610 const integer sapi := 0;
611 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(sapi));
612 var default d;
613 timer T := 3.0;
614
615 fp_common_init();
616
617 /* some common altstep for meas res and other background noise */
618 d := activate(as_ignore_background());
619 RSL.clear;
620 LAPDM.clear;
621
622 var octetstring l3_mo := f_rnd_octstring(12);
623 var octetstring l3_mt := f_rnd_octstring(12);
624
625 /* 1) The BTS is brought into the multiple frame established state */
626
627 /* MO Establish Request via LADPm: SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201.. */
628 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_SABM(sapi, c_r:=cr_MO_CMD, p:=true, l3:=l3_mo)));
629 RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3_mo));
630 /* UA: SAPI = 0, R = 0, F = 1, M = 0, L = L of SABM. */
631 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_UA(sapi, cr_MT_RSP, f:=true, l3:=l3_mo)));
632
633 /* 2) The MS sends an L3 Request to the BTS */
634 l3_mo := f_rnd_octstring(18);
635 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 0, N(R) = 0. * */
636 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
637 nr:=0, ns:=0, l3:=l3_mo)));
638 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
639 /* 3) The BTS shall respond with a RR frame though this may be incorporated with
640 the L3 Response I frame. The MS does not respond to the I frame. */
641 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
642 alt {
643 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 1. */
644 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=1))) {
645 repeat;
646 }
647 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0 */
648 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
649 nr:=1, ns:=0, l3:=l3_mt)));
650 }
651
652 /* 4) The BTS shall wait for expiry of timer T200 and then repeat the I frame but
653 with the P bit set to 1. */
654 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 1, N(S) = 0. * */
655 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
656 nr:=1, ns:=0, l3:=l3_mt)));
657
658 /* 5) The MS then sends a valid L3 Request I frame asking for IMEI which
659 does not acknowledge receipt of the I frame from the BTS. */
660 /* SAPI = 0, C = 1, P = 0, M = 0, 0 ≤ L ≤ N201, N(S) = 1, N(R) = 0. * */
661 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_I(sapi, c_r:=cr_MO_CMD, p:=false,
662 nr:=0, ns:=1, l3 := l3_mo)));
663 RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3_mo));
664 alt {
665 /* On the FACCH the BTS may send an RR frame acknowledging the I frame. */
666 /* SAPI = 0, R = 1, F = 0, M = 0, L = 0, N(R) = 2. */
667 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_RR(sapi, c_r:=cr_MT_RSP, p:=false, nr:=2))) {
668 repeat;
669 }
670 /* 6) The BTS shall repeat the I frame, this frame will acknowledge
671 receipt of the second I frame from the MS. */
672 /* SAPI = 0, C = 0, P = 1, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 0. * */
673 [] LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=true,
674 nr:=2, ns:=0, l3:=l3_mt)));
675 }
676
677 /* 7) The MS then acknowledges receipt of the BTS I frame by sending a RR * frame. */
678 /* SAPI = 0, R = 0, F = 1, 0, M = 0, L = 0, N(R) = 1 */
679 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=1)));
680
681 /* 8) The BTS shall send the next I frame. The MS acknowledges this I frame. */
682 l3_mt := f_rnd_octstring(16);
683 RSL.send(ts_RSL_DATA_REQ(g_chan_nr, link_id, l3_mt));
684 /* SAPI = 0, C = 0, P = 0, M = 0, 0 ≤ L ≤ N201, N(R) = 2, N(S) = 1 */
685 LAPDM.receive(t_PH_DATA(0, false, tr_LAPDm_I(sapi, c_r:=cr_MT_CMD, p:=false,
686 nr:=2, ns:=1, l3:=l3_mt)));
687 LAPDM.send(t_PH_DATA(0, false, ts_LAPDm_RR(sapi, c_r:=cr_MO_RSP, p:=true, nr:=2)));
688
689 deactivate(d);
690 fp_common_fini();
691}
692testcase TC_iframe_timer_recovery() runs on test_CT {
693 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
694 f_testmatrix_each_chan(pars, refers(f_TC_iframe_timer_recovery));
695}
696
697
698
Harald Welte72c81e72019-05-30 16:36:11 +0200699control {
700 execute(TC_foo());
701 execute(TC_sabm_ua_dcch_sapi0());
702 execute(TC_sabm_ua_dcch_sapi0_nopayload());
703 execute(TC_sabm_ua_dcch_sapi3());
704 execute(TC_sabm_ua_dcch_sapi4());
705 execute(TC_sabm_contention());
706 execute(TC_sabm_retransmit());
Harald Welte2f2b2b72019-05-31 22:24:57 +0200707 execute(TC_sabm_retransmit_bts());
708 execute(TC_sabm_invalid_resp());
709 execute(TC_sabm_dm());
710 execute(TC_establish_ign_first_sabm());
711 execute(TC_iframe_seq_and_ack());
712 execute(TC_iframe_timer_recovery());
Harald Welte72c81e72019-05-30 16:36:11 +0200713}
714
Harald Weltef6543322017-07-16 07:35:10 +0200715}