blob: c43774d92841bed97d4af7c0809008d8c52e4e0b [file] [log] [blame]
Harald Welte70767382018-02-21 12:16:40 +01001module BTS_Tests {
2
Harald Welte14906952019-05-27 09:19:49 +02003/* Integration Tests for OsmoBTS
Harald Welte34b5a952019-05-27 11:54:11 +02004 * (C) 2018-2019 by Harald Welte <laforge@gnumonks.org>
Harald Welte14906952019-05-27 09:19:49 +02005 * contributions by Vadim Yanitskiy and sysmocom - s.f.m.c. GmbH
6 * All rights reserved.
7 *
8 * Released under the terms of GNU General Public License, Version 2 or
9 * (at your option) any later version.
10 *
Harald Welte34b5a952019-05-27 11:54:11 +020011 * SPDX-License-Identifier: GPL-2.0-or-later
12 *
Harald Welte14906952019-05-27 09:19:49 +020013 * This test suite tests OsmoBTS by attaching to the external interfaces
14 * such as Abis RSL, PCU, VTY as well as by attaching to a MS L1 implementation
15 * using the L1CTL protocol/interface.
16 *
17 * You can run the tests with
18 * a) osmo-bts-trx + trxcon + fake_trx (without any hardware)
19 * b) any osmo-bts-* + OsmocomBB layer1 + osmocon (with real BTS hardware)
20 * c) osmo-bts-virtual + virt_phy (without any hardware)
21 *
22 * Some of the tests will only run on a subset of those three configurations
23 * due to limitations in the respective L1.
24 */
25
Daniel Willmann0fcc4d32018-10-23 20:32:19 +020026import from Misc_Helpers all;
Harald Welte70767382018-02-21 12:16:40 +010027import from General_Types all;
28import from GSM_Types all;
29import from GSM_RR_Types all;
30import from Osmocom_Types all;
31import from GSM_Types all;
Harald Welte82ccef72018-02-25 16:17:33 +010032import from GSM_SystemInformation all;
Harald Welte70767382018-02-21 12:16:40 +010033import from L1CTL_PortType all;
34import from L1CTL_Types all;
35import from LAPDm_Types all;
Harald Weltead033dc2019-05-25 17:28:16 +020036import from LAPDm_RAW_PT all;
Harald Welte70767382018-02-21 12:16:40 +010037import from Osmocom_CTRL_Adapter all;
Neels Hofmeyr6a84b232018-04-03 19:12:36 +020038import from Osmocom_CTRL_Functions all;
Harald Welte70767382018-02-21 12:16:40 +010039
40import from RSL_Types all;
Harald Welte7484fc42018-02-24 14:09:45 +010041import from IPA_Types all;
Harald Welte70767382018-02-21 12:16:40 +010042import from IPA_Emulation all;
Stefan Sperling0ec1c262018-10-15 15:12:52 +020043import from IPA_Testing all;
Harald Welte70767382018-02-21 12:16:40 +010044import from RSL_Emulation all;
45
46import from IPL4asp_Types all;
47import from TRXC_Types all;
48import from TRXC_CodecPort all;
49import from TRXC_CodecPort_CtrlFunct all;
50
Harald Welte883340c2018-02-28 18:59:29 +010051import from PCUIF_Types all;
52import from PCUIF_CodecPort all;
Harald Weltea2e0e942019-05-27 18:12:53 +020053import from UD_Types all;
Harald Welte883340c2018-02-28 18:59:29 +010054
Harald Welte7484fc42018-02-24 14:09:45 +010055import from MobileL3_CommonIE_Types all;
Harald Welte68e495b2018-02-25 00:05:57 +010056import from MobileL3_RRM_Types all;
57import from MobileL3_Types all;
58import from L3_Templates all;
Harald Welteeaa9a862019-05-26 23:01:08 +020059import from L3_Common all;
60import from MobileL3_GMM_SM_Types all;
Harald Welte7484fc42018-02-24 14:09:45 +010061
Harald Welte8da48242018-02-27 20:41:32 +010062import from Osmocom_VTY_Functions all;
63import from TELNETasp_PortType all;
64
Harald Welte505cf9b2018-09-15 17:47:23 +030065friend module BTS_Tests_SMSCB;
Harald Weltead033dc2019-05-25 17:28:16 +020066friend module BTS_Tests_virtphy;
Harald Welte505cf9b2018-09-15 17:47:23 +030067
Harald Welte70767382018-02-21 12:16:40 +010068/* The tests assume a BTS with the following timeslot configuration:
69 * TS0 : Combined CCCH + SDCCH/4
Harald Welte3d04ae62018-04-04 20:29:05 +020070 * TS1 : TCH/F
71 * TS2 : TCH/F
72 * TS3 : TCH/F_PDCH (IPA Style)
73 * TS4 : TCH/F_TCH/H_PDCH (Osmocom Style)
Harald Welte70767382018-02-21 12:16:40 +010074 * TS5 : TCH/H
75 * TS6 : SDCCH/8
76 * TS7 : PDCH
77 */
78
79modulepar {
80 charstring mp_rsl_ip := "127.0.0.2";
81 integer mp_rsl_port := 3003;
82 integer mp_trx0_arfcn := 871;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +070083 charstring mp_bts_trxc_ip := "127.0.0.1";
84 integer mp_bts_trxc_port := 5701;
Harald Welte883340c2018-02-28 18:59:29 +010085 charstring mp_pcu_socket := PCU_SOCK_DEFAULT;
Neels Hofmeyr6a84b232018-04-03 19:12:36 +020086 charstring mp_ctrl_ip := "127.0.0.1";
87 integer mp_ctrl_port := 4238;
Harald Welte07bd2d22019-05-25 11:03:30 +020088 charstring mp_bsc_ctrl_ip := "127.0.0.1";
89 integer mp_bsc_ctrl_port := 4249;
Pau Espin Pedrol121724c2018-09-28 15:58:12 +020090 integer mp_tolerance_rxqual := 1;
91 integer mp_tolerance_rxlev := 3;
92 integer mp_tolerance_timing_offset_256syms := 0;
Pau Espin Pedrol752ffd52018-06-07 13:55:45 +020093 integer mp_rxlev_exp := 57;
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +020094 integer mp_ul_rxlev_exp := 10;
Pau Espin Pedroled359cb2018-09-28 16:08:24 +020095 integer mp_ms_power_level_exp := 7;
Pau Espin Pedrol121724c2018-09-28 15:58:12 +020096 integer mp_ms_actual_ta_exp := 0;
97 integer mp_timing_offset_256syms_exp := 512;
Pau Espin Pedrol315e4712018-11-01 16:27:07 +010098 /* Time to wait for RSL conn from BTS during startup of test */
Philipp Maier12567e42019-04-17 14:10:05 +020099 float mp_ipa_up_timeout := 15.0;
Philipp Maiere63229e2019-04-26 12:21:37 +0200100 float mp_ipa_up_delay := 0.0;
Harald Weltead033dc2019-05-25 17:28:16 +0200101 /* false for now, as only virtphy supports it, not calypso-l1 nor trxcon */
102 boolean mp_l1_supports_gprs := false;
Harald Welte70767382018-02-21 12:16:40 +0100103}
104
Harald Welte629cc6b2018-03-11 17:19:05 +0100105type record of RslChannelNr ChannelNrs;
106
Harald Welte70767382018-02-21 12:16:40 +0100107type component test_CT extends CTRL_Adapter_CT {
Harald Welte68e495b2018-02-25 00:05:57 +0100108 /* IPA Emulation component underneath RSL */
Harald Welte70767382018-02-21 12:16:40 +0100109 var IPA_Emulation_CT vc_IPA;
Harald Welte68e495b2018-02-25 00:05:57 +0100110 /* RSL Emulation component (for ConnHdlr tests) */
Harald Welte70767382018-02-21 12:16:40 +0100111 var RSL_Emulation_CT vc_RSL;
Harald Welte68e495b2018-02-25 00:05:57 +0100112 /* Direct RSL_CCHAN_PT */
Harald Welte70767382018-02-21 12:16:40 +0100113 port RSL_CCHAN_PT RSL_CCHAN;
Harald Welte68e495b2018-02-25 00:05:57 +0100114
115 /* L1CTL port (for classic tests) */
116 port L1CTL_PT L1CTL;
Harald Welte48494ca2018-02-25 16:59:50 +0100117
Harald Welte54a2a2d2018-02-26 09:14:05 +0100118 /* TRXC port (for classic tests) */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700119 port TRXC_CODEC_PT BTS_TRXC;
120 var integer g_bts_trxc_conn_id;
Harald Welte54a2a2d2018-02-26 09:14:05 +0100121
Harald Weltef50e3ae2018-09-10 10:27:56 +0200122 /* VTY connections to both BTS and BSC */
Harald Welte8da48242018-02-27 20:41:32 +0100123 port TELNETasp_PT BTSVTY;
Harald Weltef50e3ae2018-09-10 10:27:56 +0200124 port TELNETasp_PT BSCVTY;
Harald Welte8da48242018-02-27 20:41:32 +0100125
Harald Welte883340c2018-02-28 18:59:29 +0100126 /* PCU Interface of BTS */
127 port PCUIF_CODEC_PT PCU;
128 var integer g_pcu_conn_id;
129 /* Last PCU INFO IND we received */
130 var PCUIF_Message g_pcu_last_info;
131
Harald Welte48494ca2018-02-25 16:59:50 +0100132 /* SI configuration */
133 var SystemInformationConfig si_cfg := {
134 bcch_extended := false,
135 si1_present := false,
136 si2bis_present := false,
137 si2ter_present := false,
138 si2quater_present := false,
139 si7_present := false,
140 si8_present := false,
141 si9_present := false,
142 si13_present := false,
143 si13alt_present := false,
144 si15_present := false,
145 si16_present := false,
146 si17_present := false,
147 si2n_present := false,
148 si21_present := false,
149 si22_present := false
150 };
Harald Welte629cc6b2018-03-11 17:19:05 +0100151
152 /* all logical channels available on the BTS */
153 var ChannelNrs g_AllChannels;
Harald Welte0472ab42018-03-12 15:02:26 +0100154 var ChannelNrs g_AllChanTypes;
Harald Welte70767382018-02-21 12:16:40 +0100155}
156
157/* an individual call / channel */
158type component ConnHdlr extends RSL_DchanHdlr {
159 port L1CTL_PT L1CTL;
160
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700161 port TRXC_CODEC_PT BTS_TRXC;
162 var integer g_bts_trxc_conn_id;
Harald Welte70767382018-02-21 12:16:40 +0100163
164 timer g_Tguard;
165 timer g_Tmeas_exp := 2.0; /* >= 103 SACCH multiframe ~ 500ms */
166
167 var ConnHdlrPars g_pars;
168 var uint8_t g_next_meas_res_nr := 0;
Harald Weltefa45e9e2018-03-10 18:59:03 +0100169 var boolean g_first_meas_res := true;
Harald Weltef26de0b2018-04-04 20:28:05 +0200170
171 /* PCU Interface of BTS */
172 port PCUIF_CODEC_PT PCU;
Harald Welte70767382018-02-21 12:16:40 +0100173}
174
175function f_init_rsl(charstring id) runs on test_CT {
176 vc_IPA := IPA_Emulation_CT.create(id & "-RSL-IPA");
177 vc_RSL := RSL_Emulation_CT.create(id & "-RSL");
178
179 map(vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
180 connect(vc_IPA:IPA_RSL_PORT, vc_RSL:IPA_PT);
181 connect(self:RSL_CCHAN, vc_RSL:CCHAN_PT);
182
183 vc_IPA.start(IPA_Emulation.main_server(mp_rsl_ip, mp_rsl_port));
184 vc_RSL.start(RSL_Emulation.main(false));
185}
186
187type record ConnHdlrPars {
188 RslChannelNr chan_nr,
189 RSL_IE_ChannelMode chan_mode,
190 float t_guard,
Harald Welte0472ab42018-03-12 15:02:26 +0100191 ConnL1Pars l1_pars,
Harald Weltee613f962018-04-18 22:38:16 +0200192 TestSpecUnion spec optional,
193 RSL_IE_EncryptionInfo encr optional
Harald Welte0472ab42018-03-12 15:02:26 +0100194}
195
196/* Test-specific parameters */
197type union TestSpecUnion {
198 RllTestCase rll
Harald Welte70767382018-02-21 12:16:40 +0100199}
200
Harald Welte82ccef72018-02-25 16:17:33 +0100201template (value) RachControlParameters ts_RachCtrl_default := {
Harald Welte0fd1fb02018-03-10 17:19:50 +0100202 max_retrans := RACH_MAX_RETRANS_7,
203 tx_integer := '1001'B, /* 12 slots */
Harald Welte82ccef72018-02-25 16:17:33 +0100204 cell_barr_access := false,
205 re_not_allowed := true,
Harald Welteb9585f82018-03-10 17:18:47 +0100206 acc := '0000010000000000'B
Harald Welte82ccef72018-02-25 16:17:33 +0100207};
208
Harald Weltef10153f2018-02-25 16:34:05 +0100209template (value) CellSelectionParameters ts_CellSelPar_default := {
Harald Welte0fd1fb02018-03-10 17:19:50 +0100210 cell_resel_hyst_2dB := 2,
Pau Espin Pedroled359cb2018-09-28 16:08:24 +0200211 ms_txpwr_max_cch := mp_ms_power_level_exp,
Harald Weltef10153f2018-02-25 16:34:05 +0100212 acs := '0'B,
213 neci := true,
214 rxlev_access_min := 0
215}
216
217template (value) LocationAreaIdentification ts_LAI_default := {
218 mcc_mnc := '262F42'H,
219 lac := 42
220}
221
Harald Welte7484fc42018-02-24 14:09:45 +0100222/* Default SYSTEM INFORMATION 3 */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100223template (value) SystemInformation ts_SI3_default := {
224 header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_3, 18),
Harald Welte7484fc42018-02-24 14:09:45 +0100225 payload := {
226 si3 := {
227 cell_id := 23,
Harald Weltef10153f2018-02-25 16:34:05 +0100228 lai := ts_LAI_default,
Harald Welte7484fc42018-02-24 14:09:45 +0100229 ctrl_chan_desc := {
230 msc_r99 := true,
231 att := true,
232 bs_ag_blks_res := 1,
233 ccch_conf := CCHAN_DESC_1CCCH_COMBINED,
Harald Welte82ccef72018-02-25 16:17:33 +0100234 si22ind := false,
Harald Welte7484fc42018-02-24 14:09:45 +0100235 cbq3 := CBQ3_IU_MODE_NOT_SUPPORTED,
236 spare := '00'B,
237 bs_pa_mfrms := 0, /* 2 multiframes */
238 t3212 := 1 /* 6 minutes */
239 },
Harald Welte82ccef72018-02-25 16:17:33 +0100240 cell_options := {
Harald Welte7484fc42018-02-24 14:09:45 +0100241 dn_ind := false,
242 pwrc := false,
243 dtx := MS_MAY_USE_UL_DTX,
Harald Welte0fd1fb02018-03-10 17:19:50 +0100244 radio_link_tout_div4 := (32/4)-1
Harald Welte7484fc42018-02-24 14:09:45 +0100245 },
Harald Weltef10153f2018-02-25 16:34:05 +0100246 cell_sel_par := ts_CellSelPar_default,
Harald Welte82ccef72018-02-25 16:17:33 +0100247 rach_control := ts_RachCtrl_default,
Harald Weltebe030482019-05-27 22:29:35 +0200248 rest_octets := '2C2B2B2B'O /* GPRS present */
Harald Welte7484fc42018-02-24 14:09:45 +0100249 }
250 }
251}
Harald Welte70767382018-02-21 12:16:40 +0100252
Harald Weltef8df4cb2018-03-10 15:15:08 +0100253template (value) SystemInformation ts_SI2_default := {
254 header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_2, 22),
Harald Weltef10153f2018-02-25 16:34:05 +0100255 payload := {
256 si2 := {
257 bcch_freq_list := '00000000000000000000000000000000'O,
258 ncc_permitted := '11111111'B,
259 rach_control := ts_RachCtrl_default
260 }
261 }
262}
263
Harald Weltef8df4cb2018-03-10 15:15:08 +0100264template (value) SystemInformation ts_SI4_default := {
265 header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_4, 12), /* no CBCH / restoct */
Harald Weltef10153f2018-02-25 16:34:05 +0100266 payload := {
267 si4 := {
268 lai := ts_LAI_default,
269 cell_sel_par := ts_CellSelPar_default,
270 rach_control := ts_RachCtrl_default,
271 cbch_chan_desc := omit,
272 cbch_mobile_alloc := omit,
273 rest_octets := ''O
274 }
275 }
276}
277
278function f_rsl_bcch_fill_raw(RSL_IE_SysinfoType rsl_si_type, octetstring si_enc)
279runs on test_CT {
280 log("Setting ", rsl_si_type, ": ", si_enc);
281 RSL_CCHAN.send(ts_RSL_UD(ts_RSL_BCCH_INFO(rsl_si_type, si_enc)));
282}
283
284function f_rsl_bcch_fill(RSL_IE_SysinfoType rsl_si_type, template (value) SystemInformation si_dec)
285runs on test_CT {
286 var octetstring si_enc := enc_SystemInformation(valueof(si_dec));
287 log("Setting ", rsl_si_type, ": ", si_dec);
288 f_rsl_bcch_fill_raw(rsl_si_type, si_enc);
289}
290
Harald Welte505cf9b2018-09-15 17:47:23 +0300291friend function f_init_vty(charstring id) runs on test_CT {
Harald Welte8da48242018-02-27 20:41:32 +0100292 map(self:BTSVTY, system:BTSVTY);
293 f_vty_set_prompts(BTSVTY);
294 f_vty_transceive(BTSVTY, "enable");
295}
296
Harald Welte505cf9b2018-09-15 17:47:23 +0300297friend function f_init_vty_bsc() runs on test_CT {
Harald Weltef50e3ae2018-09-10 10:27:56 +0200298 map(self:BSCVTY, system:BSCVTY);
299 f_vty_set_prompts(BSCVTY, "OsmoBSC");
300 f_vty_transceive(BSCVTY, "enable");
301}
302
Harald Welte883340c2018-02-28 18:59:29 +0100303/* PCU socket may at any time receive a new INFO.ind */
Harald Weltef26de0b2018-04-04 20:28:05 +0200304private altstep as_pcu_info_ind(PCUIF_CODEC_PT pt, integer pcu_conn_id,
305 out PCUIF_Message pcu_last_info) {
Harald Welte883340c2018-02-28 18:59:29 +0100306 var PCUIF_send_data sd;
Harald Weltef26de0b2018-04-04 20:28:05 +0200307 [] pt.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(0, ?))) -> value sd {
308 pcu_last_info := sd.data;
Harald Welted378a252018-03-13 17:02:14 +0100309 }
Harald Weltef26de0b2018-04-04 20:28:05 +0200310 [] pt.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(?, ?, ?))) -> value sd {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200311 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Invalid PCU Version/BTS Number received");
Harald Welte883340c2018-02-28 18:59:29 +0100312 }
313}
314
Harald Weltef26de0b2018-04-04 20:28:05 +0200315private function f_init_pcu(PCUIF_CODEC_PT pt, charstring id,
316 out integer pcu_conn_id, out PCUIF_Message pcu_last_info) {
Harald Welte883340c2018-02-28 18:59:29 +0100317 timer T := 2.0;
318 var PCUIF_send_data sd;
Harald Welte84271622018-03-10 17:21:03 +0100319 if (mp_pcu_socket == "") {
Harald Weltef26de0b2018-04-04 20:28:05 +0200320 pcu_conn_id := -1;
Harald Welte84271622018-03-10 17:21:03 +0100321 return;
322 }
Harald Weltef26de0b2018-04-04 20:28:05 +0200323 pcu_conn_id := f_pcuif_connect(pt, mp_pcu_socket);
Harald Welte883340c2018-02-28 18:59:29 +0100324
325 T.start;
326 alt {
Harald Weltef26de0b2018-04-04 20:28:05 +0200327 [] as_pcu_info_ind(pt, pcu_conn_id, pcu_last_info);
Harald Welte883340c2018-02-28 18:59:29 +0100328 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200329 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU INFO_IND");
Harald Welte883340c2018-02-28 18:59:29 +0100330 }
331 }
332}
333
Harald Welte70767382018-02-21 12:16:40 +0100334/* global init function */
Harald Welte10474062019-05-30 16:48:17 +0200335function f_init() runs on test_CT {
336 var charstring id := testcasename();
Pau Espin Pedrol315e4712018-11-01 16:27:07 +0100337 timer T := mp_ipa_up_timeout;
Harald Welte629cc6b2018-03-11 17:19:05 +0100338 g_AllChannels := {
339 /* TS 1..4: TCH/F */
340 valueof(ts_RslChanNr_Bm(1)), valueof(ts_RslChanNr_Bm(2)),
341 valueof(ts_RslChanNr_Bm(3)), valueof(ts_RslChanNr_Bm(4)),
342 /* TS 5: TCH/H */
343 valueof(ts_RslChanNr_Lm(5,0)), valueof(ts_RslChanNr_Lm(5,1)),
344 /* TS 0: SDCCH/4 */
345 valueof(ts_RslChanNr_SDCCH4(0,0)), valueof(ts_RslChanNr_SDCCH4(0,1)),
346 valueof(ts_RslChanNr_SDCCH4(0,2)), valueof(ts_RslChanNr_SDCCH4(0,3)),
347 /* TS 6: SDCCH/8 */
348 valueof(ts_RslChanNr_SDCCH8(6,0)), valueof(ts_RslChanNr_SDCCH8(6,1)),
349 valueof(ts_RslChanNr_SDCCH8(6,2)), valueof(ts_RslChanNr_SDCCH8(6,3)),
350 valueof(ts_RslChanNr_SDCCH8(6,4)), valueof(ts_RslChanNr_SDCCH8(6,5)),
351 valueof(ts_RslChanNr_SDCCH8(6,6)), valueof(ts_RslChanNr_SDCCH8(6,7))
352 };
353
Pau Espin Pedrol3dcf38f2018-10-22 14:07:54 +0200354 /* FIXME: FACCH/H is unreliable with calypso firmware, see OS#3653 */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700355 if (mp_bts_trxc_port != -1) {
Pau Espin Pedrol3dcf38f2018-10-22 14:07:54 +0200356 g_AllChanTypes := {
357 /* TS 1..4: TCH/F */
358 valueof(ts_RslChanNr_Bm(1)),
359 /* TS 5: TCH/H */
360 valueof(ts_RslChanNr_Lm(5,1)),
361 /* TS 0: SDCCH/4 */
362 valueof(ts_RslChanNr_SDCCH4(0,2)),
363 /* TS 6: SDCCH/8 */
364 valueof(ts_RslChanNr_SDCCH8(6,4))
365 };
366 } else {
367 g_AllChanTypes := {
368 /* TS 1..4: TCH/F */
369 valueof(ts_RslChanNr_Bm(1)),
370 /* TS 0: SDCCH/4 */
371 valueof(ts_RslChanNr_SDCCH4(0,2)),
372 /* TS 6: SDCCH/8 */
373 valueof(ts_RslChanNr_SDCCH8(6,4))
374 };
375 }
Harald Welte70767382018-02-21 12:16:40 +0100376 f_init_rsl(id);
Harald Welte83f6dbf2018-06-03 18:26:50 +0200377 T.start;
378 alt {
379 [] RSL_CCHAN.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP});
380 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200381 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for ASP_IPA_EVENT_UP");
Harald Welte83f6dbf2018-06-03 18:26:50 +0200382 }
383 }
Harald Welte2d142592018-02-25 13:19:44 +0100384 f_sleep(0.5); /* workaround for OS#3000 */
Harald Welte8da48242018-02-27 20:41:32 +0100385 f_init_vty(id);
Neels Hofmeyr6a84b232018-04-03 19:12:36 +0200386 f_ipa_ctrl_start(mp_ctrl_ip, mp_ctrl_port);
Harald Welte7484fc42018-02-24 14:09:45 +0100387
388 /* Send SI3 to the BTS, it is needed for various computations */
Harald Weltef10153f2018-02-25 16:34:05 +0100389 f_rsl_bcch_fill(RSL_SYSTEM_INFO_3, ts_SI3_default);
390 /* SI2 + SI4 are required for SI testing as they are mandatory defaults */
391 f_rsl_bcch_fill(RSL_SYSTEM_INFO_2, ts_SI2_default);
392 f_rsl_bcch_fill(RSL_SYSTEM_INFO_4, ts_SI4_default);
Harald Welte57fe8232018-02-26 17:52:50 +0100393
Harald Weltef26de0b2018-04-04 20:28:05 +0200394 map(self:PCU, system:PCU);
395 f_init_pcu(PCU, id, g_pcu_conn_id, g_pcu_last_info);
Harald Welte883340c2018-02-28 18:59:29 +0100396
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700397 if (mp_bts_trxc_port != -1) {
Harald Welte84271622018-03-10 17:21:03 +0100398 var TrxcMessage ret;
399 /* start with a default moderate timing offset equalling TA=2 */
400 f_main_trxc_connect();
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700401 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_TIMING(2*256)));
Harald Welte84271622018-03-10 17:21:03 +0100402 }
Philipp Maierd95f3402019-04-18 17:50:52 +0200403
404 /* Wait some extra time to make sure the BTS emits a stable carrier.
405 * (this is only relevant when running the tests with a physical BTS.) */
406 f_sleep(mp_ipa_up_delay);
Harald Welte70767382018-02-21 12:16:40 +0100407}
408
Harald Welte68e495b2018-02-25 00:05:57 +0100409/* Attach L1CTL to master test_CT (classic tests, non-handler mode) */
410function f_init_l1ctl() runs on test_CT {
411 map(self:L1CTL, system:L1CTL);
412 f_connect_reset(L1CTL);
413}
414
Harald Welte70767382018-02-21 12:16:40 +0100415type function void_fn(charstring id) runs on ConnHdlr;
416
417/* create a new test component */
Harald Weltef26de0b2018-04-04 20:28:05 +0200418function f_start_handler(void_fn fn, ConnHdlrPars pars, boolean pcu_comp := false)
Harald Welte70767382018-02-21 12:16:40 +0100419runs on test_CT return ConnHdlr {
420 var charstring id := testcasename();
421 var ConnHdlr vc_conn;
422
423 vc_conn := ConnHdlr.create(id);
424 /* connect to RSL Emulation main component */
425 connect(vc_conn:RSL, vc_RSL:CLIENT_PT);
426 connect(vc_conn:RSL_PROC, vc_RSL:RSL_PROC);
Harald Weltef26de0b2018-04-04 20:28:05 +0200427 if (pcu_comp) {
428 /* the ConnHdlr component wants to talk directly to the PCU, so disconnect
429 * it from the test_CT and connect it to the component. This obviously only
430 * works for one component, i.e. no concurrency */
431 unmap(self:PCU, system:PCU);
432 map(vc_conn:PCU, system:PCU);
433 }
Harald Welte70767382018-02-21 12:16:40 +0100434
435 vc_conn.start(f_handler_init(fn, id, pars));
436 return vc_conn;
437}
438
Harald Welte7484fc42018-02-24 14:09:45 +0100439template ASP_RSL_Unitdata ts_RSL_UD(template RSL_Message rsl, IpaStreamId sid := IPAC_PROTO_RSL_TRX0) := {
440 streamId := sid,
441 rsl := rsl
442}
443
444template ASP_RSL_Unitdata tr_RSL_UD(template RSL_Message rsl,
445 template IpaStreamId sid := IPAC_PROTO_RSL_TRX0) := {
446 streamId := sid,
447 rsl := rsl
448}
449
Harald Welte70767382018-02-21 12:16:40 +0100450private altstep as_Tguard() runs on ConnHdlr {
451 [] g_Tguard.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200452 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
Harald Welte70767382018-02-21 12:16:40 +0100453 }
454}
455
Harald Welte990a3612019-05-27 14:02:13 +0200456friend function f_l1_tune(L1CTL_PT L1CTL, L1ctlCcchMode ccch_mode := CCCH_MODE_COMBINED) {
457 f_L1CTL_FBSB(L1CTL, { false, mp_trx0_arfcn }, ccch_mode, mp_rxlev_exp);
Harald Welte70767382018-02-21 12:16:40 +0100458}
459
460private function f_trxc_connect() runs on ConnHdlr {
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700461 map(self:BTS_TRXC, system:BTS_TRXC);
Harald Welte70767382018-02-21 12:16:40 +0100462 var Result res;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700463 res := TRXC_CodecPort_CtrlFunct.f_IPL4_connect(BTS_TRXC, mp_bts_trxc_ip, mp_bts_trxc_port,
Harald Weltea4d8f352018-03-01 15:47:20 +0100464 "", -1, -1, {udp:={}}, {});
Harald Welte9220f632018-05-23 20:27:02 +0200465 if (not ispresent(res.connId)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200466 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Could not connect to trx-control interface of trxcon, check your configuration");
Harald Welte9220f632018-05-23 20:27:02 +0200467 }
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700468 g_bts_trxc_conn_id := res.connId;
Harald Welte70767382018-02-21 12:16:40 +0100469}
470
Vadim Yanitskiy2f01fbd2019-06-01 01:32:48 +0700471private function f_trxc_fake_rssi(TRXC_RSSI rssi) runs on ConnHdlr {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100472 var TrxcMessage ret;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700473 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_RSSI(rssi)));
Harald Welte70767382018-02-21 12:16:40 +0100474}
475
476private function f_trx_fake_toffs256(int16_t toffs256) runs on ConnHdlr {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100477 var TrxcMessage ret;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700478 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_TIMING(toffs256)));
Harald Welte70767382018-02-21 12:16:40 +0100479}
480
481/* first function started in ConnHdlr component */
482private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
483runs on ConnHdlr {
484 g_pars := pars;
485 g_chan_nr := pars.chan_nr;
486
487 map(self:L1CTL, system:L1CTL);
488 f_connect_reset(L1CTL);
489
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700490 if (mp_bts_trxc_port != -1) {
Harald Welte84271622018-03-10 17:21:03 +0100491 f_trxc_connect();
492 }
Harald Welte70767382018-02-21 12:16:40 +0100493
494 g_Tguard.start(pars.t_guard);
495 activate(as_Tguard());
496
497 f_rslem_register(0, pars.chan_nr);
498
499 /* call the user-supplied test case function */
500 fn.apply(id);
501}
502
Harald Welteb1726c92018-03-30 11:56:38 +0200503function f_rsl_transceive_ret(template RSL_Message tx, template RSL_Message exp_rx, charstring id,
504 boolean ignore_other := false)
505runs on ConnHdlr return RSL_Message {
506 var RSL_Message rx;
Harald Welte1eba3742018-02-25 12:48:14 +0100507 timer T := 3.0;
508 RSL.send(tx);
509 T.start;
Harald Welte70767382018-02-21 12:16:40 +0100510 alt {
Harald Welteb1726c92018-03-30 11:56:38 +0200511 [] RSL.receive(exp_rx) -> value rx {
Harald Welte1eba3742018-02-25 12:48:14 +0100512 T.stop;
513 setverdict(pass);
Harald Welte70767382018-02-21 12:16:40 +0100514 }
Harald Welte1eba3742018-02-25 12:48:14 +0100515 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200516 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout expecting " & id);
Harald Welte1eba3742018-02-25 12:48:14 +0100517 }
Harald Welte21240e62018-03-11 21:43:35 +0100518 [not ignore_other] as_l1_sacch();
519 [not ignore_other] as_meas_res();
520 [not ignore_other] as_l1_dcch();
521 [not ignore_other] RSL.receive {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200522 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RSL message received");
Harald Welte70767382018-02-21 12:16:40 +0100523 }
Harald Welte21240e62018-03-11 21:43:35 +0100524 [ignore_other] RSL.receive { repeat; }
Harald Welte70767382018-02-21 12:16:40 +0100525 }
Harald Welteb1726c92018-03-30 11:56:38 +0200526 return rx;
527}
528
529function f_rsl_transceive(template RSL_Message tx, template RSL_Message exp_rx, charstring id,
530 boolean ignore_other := false)
531runs on ConnHdlr {
532 var RSL_Message rx := f_rsl_transceive_ret(tx, exp_rx, id, ignore_other);
Harald Welte70767382018-02-21 12:16:40 +0100533}
534
Harald Welte8b01c792019-05-19 22:51:25 +0200535function f_rsl_chan_act(RSL_IE_ChannelMode mode, boolean encr_enable := false, RSL_IE_List more_ies := {},
536 RSL_IE_ActivationType act_type := t_RSL_IE_ActType_IA) runs on ConnHdlr {
537 var RSL_Message ch_act := valueof(ts_RSL_CHAN_ACT(g_chan_nr, mode, act_type));
Harald Weltee613f962018-04-18 22:38:16 +0200538 if (encr_enable) {
539 /* append encryption related IEs, if requested */
540 var RSL_IE_EncryptionInfo encr_info;
541 encr_info := valueof(ts_RSL_IE_EncrInfo(g_pars.encr.alg_id, g_pars.encr.key));
542 ch_act.ies := ch_act.ies & { valueof(t_RSL_IE(RSL_IE_ENCR_INFO, RSL_IE_Body:{encr_info :=
543encr_info})) };
544 }
Harald Weltec8d363c2019-05-19 20:36:48 +0200545 ch_act.ies := ch_act.ies & more_ies;
Harald Weltee613f962018-04-18 22:38:16 +0200546 f_rsl_transceive(ch_act, tr_RSL_CHAN_ACT_ACK(g_chan_nr), "RSL CHAN ACT");
Harald Welte1eba3742018-02-25 12:48:14 +0100547}
548
Harald Welte70767382018-02-21 12:16:40 +0100549function f_rsl_chan_deact() runs on ConnHdlr {
Harald Welte1eba3742018-02-25 12:48:14 +0100550 f_rsl_transceive(ts_RSL_RF_CHAN_REL(g_chan_nr), tr_RSL_RF_CHAN_REL_ACK(g_chan_nr),
Harald Welte21240e62018-03-11 21:43:35 +0100551 "RF CHAN REL", true);
Harald Welte70767382018-02-21 12:16:40 +0100552}
553
Harald Welte70767382018-02-21 12:16:40 +0100554private template ConnHdlrPars t_Pars(template RslChannelNr chan_nr,
555 template RSL_IE_ChannelMode chan_mode,
556 float t_guard := 20.0) := {
557 chan_nr := valueof(chan_nr),
558 chan_mode := valueof(chan_mode),
559 t_guard := t_guard,
560 l1_pars := {
561 dtx_enabled := false,
Harald Welte685d5982018-02-27 20:42:05 +0100562 toa256_enabled := false,
Harald Welte70767382018-02-21 12:16:40 +0100563 meas_ul := {
564 full := {
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +0200565 rxlev := mp_ul_rxlev_exp,
Harald Welte70767382018-02-21 12:16:40 +0100566 rxqual := 0
567 },
568 sub := {
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +0200569 rxlev := mp_ul_rxlev_exp,
Harald Welte70767382018-02-21 12:16:40 +0100570 rxqual := 0
571 }
572 },
Pau Espin Pedrol121724c2018-09-28 15:58:12 +0200573 timing_offset_256syms := mp_timing_offset_256syms_exp,
Harald Welte70767382018-02-21 12:16:40 +0100574 bs_power_level := 0,
Pau Espin Pedroled359cb2018-09-28 16:08:24 +0200575 ms_power_level := mp_ms_power_level_exp,
Pau Espin Pedrol121724c2018-09-28 15:58:12 +0200576 ms_actual_ta := mp_ms_actual_ta_exp
Harald Welte0472ab42018-03-12 15:02:26 +0100577 },
Harald Weltee613f962018-04-18 22:38:16 +0200578 spec := omit,
579 encr := omit
Harald Welte70767382018-02-21 12:16:40 +0100580}
581
Harald Welte93640c62018-02-25 16:59:33 +0100582/***********************************************************************
583 * Channel Activation / Deactivation
584 ***********************************************************************/
585
Harald Welte70767382018-02-21 12:16:40 +0100586/* Stress test: Do 500 channel activations/deactivations in rapid succession */
587function f_TC_chan_act_stress(charstring id) runs on ConnHdlr {
588 for (var integer i := 0; i < 500; i := i+1) {
589 f_rsl_chan_act(g_pars.chan_mode);
590 f_rsl_chan_deact();
591 }
592 setverdict(pass);
593}
594testcase TC_chan_act_stress() runs on test_CT {
595 var ConnHdlr vc_conn;
596 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +0200597 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100598 vc_conn := f_start_handler(refers(f_TC_chan_act_stress), pars);
599 vc_conn.done;
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200600 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100601}
602
603/* Test if re-activation of an already active channel fails as expected */
604function f_TC_chan_act_react(charstring id) runs on ConnHdlr {
605 f_rsl_chan_act(g_pars.chan_mode);
606 /* attempt to activate the same lchan again -> expect reject */
607 RSL.send(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode));
608 alt {
609 [] RSL.receive(tr_RSL_CHAN_ACT_ACK(g_chan_nr)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200610 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected CHAN ACT ACK on double activation");
Harald Welte70767382018-02-21 12:16:40 +0100611 }
612 [] RSL.receive(tr_RSL_CHAN_ACT_NACK(g_chan_nr)) {
613 setverdict(pass);
614 }
615 }
616 f_rsl_chan_deact();
617}
618testcase TC_chan_act_react() runs on test_CT {
619 var ConnHdlr vc_conn;
620 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte294b0a22018-03-10 23:26:48 +0100621 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100622 vc_conn := f_start_handler(refers(f_TC_chan_act_react), pars);
623 vc_conn.done;
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200624 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100625}
626
627/* Attempt to de-activate a channel that's not active */
628function f_TC_chan_deact_not_active(charstring id) runs on ConnHdlr {
629 timer T := 3.0;
630 RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
631 T.start;
632 alt {
633 [] RSL.receive(tr_RSL_RF_CHAN_REL_ACK(g_chan_nr)) {
634 setverdict(pass);
635 }
636 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200637 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout expecting RF_CHAN_REL_ACK");
Harald Welte70767382018-02-21 12:16:40 +0100638 }
639 }
640}
641testcase TC_chan_deact_not_active() runs on test_CT {
642 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte294b0a22018-03-10 23:26:48 +0100643 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100644 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_chan_deact_not_active), pars);
645 vc_conn.done;
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200646 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100647}
648
649/* attempt to activate channel with wrong RSL Channel Nr IE; expect NACK */
650function f_TC_chan_act_wrong_nr(charstring id) runs on ConnHdlr {
651 RSL.send(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode));
652 alt {
653 [] RSL.receive(tr_RSL_CHAN_ACT_ACK(g_chan_nr)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200654 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected CHAN ACT ACK");
Harald Welte70767382018-02-21 12:16:40 +0100655 }
656 [] RSL.receive(tr_RSL_CHAN_ACT_NACK(g_chan_nr)) {
657 setverdict(pass);
658 }
659 }
660}
661private type record WrongChanNrCase {
662 RslChannelNr chan_nr,
663 charstring description
664}
665private type record of WrongChanNrCase WrongChanNrCases;
666private template WrongChanNrCase t_WCN(template RslChannelNr chan_nr, charstring desc) := {
667 chan_nr := chan_nr,
668 description := desc
669}
670
671testcase TC_chan_act_wrong_nr() runs on test_CT {
672 var ConnHdlr vc_conn;
673 var ConnHdlrPars pars;
674
Harald Welte294b0a22018-03-10 23:26:48 +0100675 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100676
677 var WrongChanNrCases wrong := {
678 valueof(t_WCN(t_RslChanNr_RACH(0), "RACH is not a dedicated channel")),
679 valueof(t_WCN(t_RslChanNr_RACH(1), "RACH doesn't exist on timeslot")),
680 valueof(t_WCN(t_RslChanNr_BCCH(0), "BCCH is not a dedicated channel")),
681 valueof(t_WCN(t_RslChanNr_PCH_AGCH(0), "PCH/AGCH is not a dedicated channel")),
682 valueof(t_WCN(t_RslChanNr_Bm(0), "TS0 cannot be TCH/F")),
683 valueof(t_WCN(t_RslChanNr_Lm(0, 0), "TS0 cannot be TCH/H")),
684 valueof(t_WCN(t_RslChanNr_Lm(0, 1), "TS0 cannot be TCH/H")),
685 valueof(t_WCN(t_RslChanNr_PDCH(0), "TS0 cannot be PDCH")),
686 valueof(t_WCN(t_RslChanNr_SDCCH8(0, 0), "TS0 cannot be SDCCH/8")),
687 valueof(t_WCN(t_RslChanNr_SDCCH8(0, 7), "TS0 cannot be SDCCH/8")),
688 valueof(t_WCN(t_RslChanNr_SDCCH4(7, 0), "TS7 cannot be SDCCH/4")),
689 valueof(t_WCN(t_RslChanNr_SDCCH4(7, 3), "TS7 cannot be SDCCH/4")),
690 valueof(t_WCN(t_RslChanNr_Lm(1, 0), "TS1 cannot be TCH/H"))
691 };
692
693 for (var integer i := 0; i < sizeof(wrong); i := i+1) {
694 pars := valueof(t_Pars(wrong[i].chan_nr, ts_RSL_ChanMode_SIGN));
695 vc_conn := f_start_handler(refers(f_TC_chan_act_wrong_nr), pars);
696 vc_conn.done;
697 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200698 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100699}
700
Harald Weltee613f962018-04-18 22:38:16 +0200701/* execute the same callback function on a variety of logical channels */
702private function f_testmatrix_each_chan(ConnHdlrPars pars, void_fn fn) runs on test_CT {
703 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +0200704 f_init();
Harald Weltee613f962018-04-18 22:38:16 +0200705
706 /* test on each of the channels we have */
707 for (var integer i := 0; i < sizeof(g_AllChanTypes); i := i+1) {
708 pars.chan_nr := valueof(g_AllChanTypes[i]);
709
710 log(testcasename(), ": XXX Starting on ", g_AllChanTypes[i]);
711 vc_conn := f_start_handler(fn, pars);
712 vc_conn.done;
713 }
714
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200715 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Weltee613f962018-04-18 22:38:16 +0200716}
717
Harald Welte93640c62018-02-25 16:59:33 +0100718/***********************************************************************
Harald Welte629cc6b2018-03-11 17:19:05 +0100719 * SACCH handling
720 ***********************************************************************/
721
722private function f_exp_sacch(boolean exp) runs on ConnHdlr {
723 timer T_sacch := 3.0;
724 T_sacch.start;
725 alt {
726 [not exp] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200727 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received SACCH when not expecting it");
Harald Welte629cc6b2018-03-11 17:19:05 +0100728 }
729 [not exp] T_sacch.timeout {
730 setverdict(pass);
731 }
732 [exp] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) {
733 setverdict(pass);
734 }
735 [exp] T_sacch.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200736 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for SACCH on ", g_chan_nr));
Harald Welte629cc6b2018-03-11 17:19:05 +0100737 }
738 [] L1CTL.receive { repeat; }
739 [] RSL.receive { repeat; }
740 }
741}
742
743/* Test if DEACTIVATE SACCH actualy deactivates its transmission (TS 48.058 4.6) */
744private function f_TC_deact_sacch(charstring id) runs on ConnHdlr {
745 f_l1_tune(L1CTL);
746 RSL.clear;
747
748 /* activate the logical channel */
749 f_est_dchan();
750 L1CTL.clear;
751
752 /* check that SACCH actually are received as expected */
753 f_exp_sacch(true);
754
755 /* deactivate SACCH on the logical channel */
756 RSL.send(ts_RSL_DEACT_SACCH(g_chan_nr));
757 f_sleep(1.0);
758 L1CTL.clear;
759
760 /* check that no SACCH are received anymore */
761 f_exp_sacch(false);
762
763 /* release the channel */
764 f_rsl_chan_deact();
765 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
766}
767testcase TC_deact_sacch() runs on test_CT {
768 var ConnHdlr vc_conn;
769 var ConnHdlrPars pars;
770 f_init();
771 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
772 //for (var integer i := 0; i < 1; i := i+1) {
773 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
774 log(testcasename(), ": Starting for ", g_AllChannels[i]);
775 vc_conn := f_start_handler(refers(f_TC_deact_sacch), pars);
776 vc_conn.done;
777 }
778 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200779 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte629cc6b2018-03-11 17:19:05 +0100780}
781
Harald Welte55700662018-03-12 13:15:43 +0100782/* verify that given SACCH payload is present */
Harald Welteea17b912018-03-11 22:29:31 +0100783private function f_sacch_present(template octetstring l3_exp) runs on ConnHdlr {
784 var L1ctlDlMessage dl;
785 /* check that the specified SI5 value is actually sent */
786 timer T_sacch := 3.0;
787 L1CTL.clear;
788 T_sacch.start;
789 alt {
790 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) -> value dl {
791 var octetstring l3 := substr(dl.payload.data_ind.payload, 4, 19);
792 if (match(l3, l3_exp)) {
793 setverdict(pass);
794 } else {
795 repeat;
796 }
797 }
798 [] L1CTL.receive { repeat; }
799 [] T_sacch.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200800 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for SACCH ", l3_exp));
Harald Welteea17b912018-03-11 22:29:31 +0100801 }
802 }
803}
804
Harald Welte55700662018-03-12 13:15:43 +0100805/* verify that given SACCH payload is not present */
806private function f_sacch_missing(template octetstring l3_exp) runs on ConnHdlr {
807 var L1ctlDlMessage dl;
808 /* check that the specified SI5 value is actually sent */
809 timer T_sacch := 3.0;
810 L1CTL.clear;
811 T_sacch.start;
812 alt {
813 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) -> value dl {
814 var octetstring l3 := substr(dl.payload.data_ind.payload, 4, 19);
815 if (match(l3, l3_exp)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200816 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unexpected SACCH ", dl));
Harald Welte55700662018-03-12 13:15:43 +0100817 } else {
818 repeat;
819 }
820 }
821 [] L1CTL.receive { repeat; }
822 [] T_sacch.timeout {
823 setverdict(pass);
824 }
825 }
826}
827
Harald Welte629cc6b2018-03-11 17:19:05 +0100828/* Test for default SACCH FILL transmitted in DL SACCH (all channel types) */
Harald Welteea17b912018-03-11 22:29:31 +0100829private function f_TC_sacch_filling(charstring id) runs on ConnHdlr {
830 /* Set a known default SACCH filling for SI5 */
831 var octetstring si5 := f_rnd_octstring(19);
832 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
833
834 f_l1_tune(L1CTL);
835 RSL.clear;
836
837 /* activate the logical channel */
838 f_est_dchan();
839
840 /* check that the specified SI5 value is actually sent */
841 f_sacch_present(si5);
842
843 /* release the channel */
844 RSL.clear;
845 f_rsl_chan_deact();
846 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
847}
848testcase TC_sacch_filling() runs on test_CT {
849 var ConnHdlr vc_conn;
850 var ConnHdlrPars pars;
851 f_init();
852 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
853 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
854 log(testcasename(), ": Starting for ", g_AllChannels[i]);
855 vc_conn := f_start_handler(refers(f_TC_sacch_filling), pars);
856 vc_conn.done;
857 }
858 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200859 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welteea17b912018-03-11 22:29:31 +0100860}
861
Harald Welte629cc6b2018-03-11 17:19:05 +0100862/* Test for lchan-specific SACCH INFO MODIFY (TS 48.058 4.12) */
Harald Welteea17b912018-03-11 22:29:31 +0100863private function f_TC_sacch_info_mod(charstring id) runs on ConnHdlr {
864 /* Set a known default SACCH filling for SI5 */
865 var octetstring si5 := f_rnd_octstring(19);
866 var octetstring si5_diff := f_rnd_octstring(19);
867 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
868
869 f_l1_tune(L1CTL);
870 RSL.clear;
871
872 log("Activating channel, expecting standard SI5");
873 /* activate the logical channel */
874 f_est_dchan();
875 /* check that the specified SI5 value is actually sent */
876 f_sacch_present(si5);
877
878 /* set channel-specific different SI5 */
879 log("Setting channel specific SACCH INFO, expecting it");
880 RSL.send(ts_RSL_SACCH_INF_MOD(g_chan_nr, RSL_SYSTEM_INFO_5, si5_diff))
881 /* check that the specified lchan-specific value is now used */
882 f_sacch_present(si5_diff);
883
884 /* deactivate the channel and re-activate it, this should result in default SI5 */
885 log("De-activating and re-activating channel, expecting standard SI5");
886 f_rsl_chan_deact();
887 f_rsl_chan_act(valueof(ts_RSL_ChanMode_SIGN));
888 /* Verify that the TRX-wide default SACCH filling is present again */
889 f_sacch_present(si5);
890
891 /* release the channel */
892 RSL.clear;
893 f_rsl_chan_deact();
894 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
895}
896testcase TC_sacch_info_mod() runs on test_CT {
897 var ConnHdlr vc_conn;
898 var ConnHdlrPars pars;
899 f_init();
900 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
901 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
902 log(testcasename(), ": Starting for ", g_AllChannels[i]);
903 vc_conn := f_start_handler(refers(f_TC_sacch_info_mod), pars);
904 vc_conn.done;
905 }
906 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200907 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welteea17b912018-03-11 22:29:31 +0100908}
909
Harald Welte075d84c2018-03-12 13:07:24 +0100910/* Test SACCH scheduling of multiple different SI message types */
911private function f_TC_sacch_multi(charstring id) runs on ConnHdlr {
912 var octetstring si5 := f_rnd_octstring(19);
913 var octetstring si5bis := f_rnd_octstring(19);
914 var octetstring si5ter := f_rnd_octstring(19);
915 var octetstring si6 := f_rnd_octstring(19);
916
917 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
918 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5bis, si5bis));
919 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5ter, si5ter));
920 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, si6));
921
922 f_l1_tune(L1CTL);
923 RSL.clear;
924
925 /* activate the logical channel */
926 f_est_dchan();
927 L1CTL.clear;
928
929 /* check that SACCH actually are received as expected */
930 f_sacch_present(si5);
931 f_sacch_present(si5bis);
932 f_sacch_present(si5ter);
933 f_sacch_present(si6);
934
935 /* release the channel */
936 f_rsl_chan_deact();
937 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
938}
939testcase TC_sacch_multi() runs on test_CT {
940 var ConnHdlr vc_conn;
941 var ConnHdlrPars pars;
942 f_init();
943 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
944 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
945 log(testcasename(), ": Starting for ", g_AllChannels[i]);
946 vc_conn := f_start_handler(refers(f_TC_sacch_multi), pars);
947 vc_conn.done;
948 }
949 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200950 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte075d84c2018-03-12 13:07:24 +0100951}
952
Harald Welte55700662018-03-12 13:15:43 +0100953/* Test if SACH information is modified as expected */
954private function f_TC_sacch_multi_chg(charstring id) runs on ConnHdlr {
955 var octetstring si5 := f_rnd_octstring(19);
956 var octetstring si6 := f_rnd_octstring(19);
957
958 /* First, configure both SI5 and SI6 to be transmitted */
959 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
960 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, si6));
961
962 f_l1_tune(L1CTL);
963 RSL.clear;
964
965 /* activate the logical channel */
966 f_est_dchan();
967 L1CTL.clear;
968
969 /* check that SACCH actually are received as expected */
970 f_sacch_present(si5);
971 f_sacch_present(si6);
972
973 /* disable SI6 */
974 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, ''O));
975
976 /* check that SI5 is still transmitted */
977 f_sacch_present(si5);
978 /* check if SI6 is now gone */
979 f_sacch_missing(si6);
980
981 /* release the channel */
982 f_rsl_chan_deact();
983 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
984}
985testcase TC_sacch_multi_chg() runs on test_CT {
986 var ConnHdlr vc_conn;
987 var ConnHdlrPars pars;
988 f_init();
989 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
990 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
991 log(testcasename(), ": Starting for ", g_AllChannels[i]);
992 vc_conn := f_start_handler(refers(f_TC_sacch_multi_chg), pars);
993 vc_conn.done;
994 }
995 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200996 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte55700662018-03-12 13:15:43 +0100997}
998
Harald Weltec8d363c2019-05-19 20:36:48 +0200999/* Test for SACCH information present in RSL CHAN ACT (overrides FILLING) */
1000private function f_TC_sacch_chan_act(charstring id) runs on ConnHdlr {
1001 var octetstring si5 := f_rnd_octstring(19);
1002 var octetstring si6 := f_rnd_octstring(19);
1003 var octetstring si5_specific := f_rnd_octstring(19);
1004 var octetstring si6_specific := f_rnd_octstring(19);
1005
1006 /* First, configure both SI5 and SI6 to be transmitted */
1007 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
1008 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, si6));
1009
1010 f_l1_tune(L1CTL);
1011 RSL.clear;
1012
1013 /* activate channel with different SACCH filling */
1014 var RSL_SacchInfo sacch_info := valueof(ts_RSL_SacchInfo({
1015 ts_RSL_SacchInfoElem(RSL_SYSTEM_INFO_5, si5_specific),
1016 ts_RSL_SacchInfoElem(RSL_SYSTEM_INFO_6, si6_specific)
1017 }));
1018 var RSL_IE_List addl_ies := { valueof(t_RSL_IE(RSL_IE_SACCH_INFO,
1019 RSL_IE_Body:{sacch_info := sacch_info})) };
1020 f_est_dchan(more_ies := addl_ies);
1021
1022 /* check that SACCH actually are received as expected */
1023 f_sacch_present(si5_specific);
1024 f_sacch_present(si6_specific);
1025
1026 /* release the channel */
1027 f_rsl_chan_deact();
1028 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1029}
1030testcase TC_sacch_chan_act() runs on test_CT {
1031 var ConnHdlr vc_conn;
1032 var ConnHdlrPars pars;
1033 f_init();
1034
1035 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1036 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1037 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1038 vc_conn := f_start_handler(refers(f_TC_sacch_chan_act), pars);
1039 vc_conn.done;
1040 }
1041 /* TODO: do the above in parallel, rather than sequentially? */
1042 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1043}
1044
Harald Welte8b01c792019-05-19 22:51:25 +02001045/* verify that SACCH DL transmission is started only if MS power IE present
1046 * see section 4.1.3 of 3GPP TS 48.058 */
1047private function f_TC_sacch_chan_act_ho_async(charstring id) runs on ConnHdlr {
1048 var octetstring si5 := f_rnd_octstring(19);
1049
1050 f_l1_tune(L1CTL);
1051 RSL.clear;
1052
1053 /* Step 1: Activate ASYNC HO channel without MS power IE */
1054
1055 /* Activate channel on BTS side */
1056 f_rsl_chan_act(g_pars.chan_mode, act_type := t_RSL_IE_ActType_HO_ASYNC);
1057 /* don't perform immediate assignment here, as we're testing non-IA case */
1058 /* enable dedicated mode */
1059 f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
1060
1061 /* Verify that no DL SACCH is being received */
1062 f_sacch_missing(?);
1063
1064 f_rsl_chan_deact();
1065 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1066
1067
1068 /* Step 2: Activate ASYNC HO channel with MS power IE */
1069
1070 /* Activate channel on BTS side */
1071 var RSL_IE_List addl_ies := {
1072 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(0)}))
1073 };
1074 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_ASYNC);
1075 /* don't perform immediate assignment here, as we're testing non-IA case */
1076 /* enable dedicated mode */
1077 f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
1078
1079 /* Verify that DL SACCH is being received */
1080 f_sacch_present(si5);
1081
1082 f_rsl_chan_deact();
1083 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1084}
1085testcase TC_sacch_chan_act_ho_async() runs on test_CT {
1086 var ConnHdlr vc_conn;
1087 var ConnHdlrPars pars;
1088 f_init();
1089
1090 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1091 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1092 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1093 vc_conn := f_start_handler(refers(f_TC_sacch_chan_act_ho_async), pars);
1094 vc_conn.done;
1095 }
1096 /* TODO: do the above in parallel, rather than sequentially? */
1097 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1098}
1099
1100/* verify that SACCH DL transmission is started only if TA + MS power IEs present,
1101 * see section 4.1.4 of 3GPP TS 48.058 */
1102private function f_TC_sacch_chan_act_ho_sync(charstring id) runs on ConnHdlr {
1103 var octetstring si5 := f_rnd_octstring(19);
1104 var RSL_IE_List addl_ies;
1105
1106 f_l1_tune(L1CTL);
1107 RSL.clear;
1108
1109 /* Step 1: Activate SYNC HO channel without MS power IE */
1110
1111 /* Activate channel on BTS side */
1112 f_rsl_chan_act(g_pars.chan_mode, act_type := t_RSL_IE_ActType_HO_SYNC);
1113 /* don't perform immediate assignment here, as we're testing non-IA case */
1114 /* enable dedicated mode */
1115 f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
1116
1117 /* Verify that no DL SACCH is being received */
1118 f_sacch_missing(?);
1119
1120 f_rsl_chan_deact();
1121 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1122
1123
1124 /* Step 2a: Activate SYNC HO channel with only MS power IE */
1125
1126 /* Activate channel on BTS side */
1127 addl_ies := {
1128 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(0)}))
1129 };
1130 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
1131 /* don't perform immediate assignment here, as we're testing non-IA case */
1132 /* enable dedicated mode */
1133 f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
1134
1135 /* Verify that no DL SACCH is being received */
1136 f_sacch_missing(?);
1137
1138 f_rsl_chan_deact();
1139 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1140
1141
1142 /* Step 2b: Activate SYNC HO channel with TA IE */
1143
1144 /* Activate channel on BTS side */
1145 addl_ies := {
1146 valueof(t_RSL_IE(RSL_IE_TIMING_ADVANCE, RSL_IE_Body:{timing_adv := 0}))
1147 };
1148 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
1149 /* don't perform immediate assignment here, as we're testing non-IA case */
1150 /* enable dedicated mode */
1151 f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
1152
1153 /* Verify that no DL SACCH is being received */
1154 f_sacch_missing(?);
1155
1156 f_rsl_chan_deact();
1157 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1158
1159
1160 /* Step 3: Activate SYNC HO channel with MS power IE and TA IE */
1161
1162 /* Activate channel on BTS side */
1163 addl_ies := {
1164 valueof(t_RSL_IE(RSL_IE_TIMING_ADVANCE, RSL_IE_Body:{timing_adv := 0})),
1165 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(0)}))
1166 };
1167 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
1168 /* don't perform immediate assignment here, as we're testing non-IA case */
1169 /* enable dedicated mode */
1170 f_L1CTL_DM_EST_REQ(L1CTL, {false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
1171
1172 /* Verify that DL SACCH is being received */
1173 f_sacch_present(si5);
1174
1175 f_rsl_chan_deact();
1176 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1177}
1178testcase TC_sacch_chan_act_ho_sync() runs on test_CT {
1179 var ConnHdlr vc_conn;
1180 var ConnHdlrPars pars;
1181 f_init();
1182
1183 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1184 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1185 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1186 vc_conn := f_start_handler(refers(f_TC_sacch_chan_act_ho_sync), pars);
1187 vc_conn.done;
1188 }
1189 /* TODO: do the above in parallel, rather than sequentially? */
1190 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1191}
Harald Welte629cc6b2018-03-11 17:19:05 +01001192
1193
1194/***********************************************************************
Harald Welte93640c62018-02-25 16:59:33 +01001195 * RACH Handling
1196 ***********************************************************************/
1197
Harald Welte8c24c2b2018-02-26 08:31:31 +01001198/* like L1SAP_IS_PACKET_RACH */
1199private function ra_is_ps(OCT1 ra) return boolean {
Harald Welte56c05802018-02-28 21:39:35 +01001200 if ((ra and4b 'F0'O == '70'O) and (ra and4b '0F'O != '0F'O)) {
Harald Welte8c24c2b2018-02-26 08:31:31 +01001201 return true;
1202 }
1203 return false;
1204}
1205
1206/* generate a random RACH for circuit-switched */
1207private function f_rnd_ra_cs() return OCT1 {
1208 var OCT1 ra;
1209 do {
1210 ra := f_rnd_octstring(1);
1211 } while (ra_is_ps(ra));
1212 return ra;
1213}
1214
Harald Welte883340c2018-02-28 18:59:29 +01001215/* generate a random RACH for packet-switched */
1216private function f_rnd_ra_ps() return OCT1 {
1217 var OCT1 ra;
1218 do {
1219 ra := f_rnd_octstring(1);
1220 } while (not ra_is_ps(ra));
1221 return ra;
1222}
1223
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +07001224/* generate a random 11-bit RA (packet-switched only) */
1225private function f_rnd_ra11_ps() return BIT11 {
1226 var integer ra11 := f_rnd_int(bit2int('11111111111'B));
1227 return int2bit(ra11, 11);
1228}
1229
Harald Welte8c24c2b2018-02-26 08:31:31 +01001230/* Send 1000 RACH requests and check their RA+FN on the RSL side */
1231testcase TC_rach_content() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02001232 f_init();
Harald Welte8c24c2b2018-02-26 08:31:31 +01001233 f_init_l1ctl();
Harald Welte68e495b2018-02-25 00:05:57 +01001234 f_l1_tune(L1CTL);
Harald Welte70767382018-02-21 12:16:40 +01001235
Harald Welte8c24c2b2018-02-26 08:31:31 +01001236 var GsmFrameNumber fn_last := 0;
Maxa199a2e2019-02-25 16:31:11 +01001237 var boolean test_failed := false;
Harald Welte8c24c2b2018-02-26 08:31:31 +01001238 for (var integer i := 0; i < 1000; i := i+1) {
1239 var OCT1 ra := f_rnd_ra_cs();
1240 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1241 if (fn == fn_last) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001242 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
Harald Welte8c24c2b2018-02-26 08:31:31 +01001243 }
1244 fn_last := fn;
1245
1246 timer T := 5.0;
Harald Welte56c05802018-02-28 21:39:35 +01001247 T.start;
Harald Welte8c24c2b2018-02-26 08:31:31 +01001248 alt {
Vadim Yanitskiyab448a52019-05-31 20:24:03 +07001249 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(ra, fn, t_RslChanNr_RACH(0)))) {
Harald Welte8c24c2b2018-02-26 08:31:31 +01001250 T.stop;
1251 }
Vadim Yanitskiyab448a52019-05-31 20:24:03 +07001252 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(?, ?, ?, ?))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001253 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected CHAN RQD");
Harald Welte8c24c2b2018-02-26 08:31:31 +01001254 }
1255 [] RSL_CCHAN.receive { repeat; }
1256 [] T.timeout {
Maxa199a2e2019-02-25 16:31:11 +01001257 test_failed := true;
1258 log("[", i, "] Timeout waiting for CHAN RQD FN=", fn, " RA=", ra);
Harald Welte8c24c2b2018-02-26 08:31:31 +01001259 }
1260 }
1261 }
Maxba06feb2019-03-05 10:52:46 +01001262 if (test_failed) {
1263 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Some out of 1000 RACH requests timed out"));
Maxa199a2e2019-02-25 16:31:11 +01001264 }
Maxba06feb2019-03-05 10:52:46 +01001265 setverdict(pass);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001266 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001267}
Harald Welte8c24c2b2018-02-26 08:31:31 +01001268
1269/* Send 1000 RACH Requests (flood ~ 89/s) and count if count(Abis) == count(Um) */
1270testcase TC_rach_count() runs on test_CT {
Harald Welte294b0a22018-03-10 23:26:48 +01001271 f_init();
Harald Welte8c24c2b2018-02-26 08:31:31 +01001272 f_init_l1ctl();
Harald Welte294b0a22018-03-10 23:26:48 +01001273 f_sleep(1.0);
Harald Welte8c24c2b2018-02-26 08:31:31 +01001274 f_l1_tune(L1CTL);
1275
1276 var GsmFrameNumber fn_last := 0;
1277 for (var integer i := 0; i < 1000; i := i+1) {
1278 var OCT1 ra := f_rnd_ra_cs();
1279 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1280 if (fn == fn_last) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001281 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
Harald Welte8c24c2b2018-02-26 08:31:31 +01001282 }
1283 fn_last := fn;
1284 }
1285 var integer rsl_chrqd := 0;
1286 timer T := 3.0;
Harald Welte56c05802018-02-28 21:39:35 +01001287 T.start;
Harald Welte8c24c2b2018-02-26 08:31:31 +01001288 alt {
1289 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(?,?))) {
1290 rsl_chrqd := rsl_chrqd + 1;
Harald Weltec3a3f452018-02-26 17:37:47 +01001291 f_timer_safe_restart(T);
Harald Welte8c24c2b2018-02-26 08:31:31 +01001292 repeat;
1293 }
1294 [] RSL_CCHAN.receive { repeat; }
1295 [] T.timeout { }
1296 }
1297 if (rsl_chrqd == 1000) {
1298 setverdict(pass);
1299 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001300 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received only ", rsl_chrqd, " out of 1000 RACH"));
Harald Welte8c24c2b2018-02-26 08:31:31 +01001301 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001302 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001303}
1304
Harald Welte3453ab42019-05-24 21:19:58 +02001305private function f_vty_load_ind_thresh(integer period := 10, integer bts_nr := 0) runs on test_CT {
1306 var charstring bts_str := "bts " & int2str(bts_nr);
1307 f_vty_config2(BSCVTY, {"network", bts_str}, "ccch load-indication-threshold " & int2str(period));
1308}
1309
1310/* empirical value: Number of RACH slots per reporting interval (1s) on combined CCCH */
1311private template integer tr_rach_slots_per_interval := (90 .. 130);
1312
1313/* Expect 0 RACH load on an idle BTS that has just started up */
1314testcase TC_rach_load_idle_thresh0() runs on test_CT {
1315 var ASP_RSL_Unitdata rx_ud;
1316
1317 f_init_vty_bsc();
1318 /* send load indications even at 0% load */
1319 f_vty_load_ind_thresh(0);
1320 f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
1321 f_sleep(2.0);
1322
1323 f_init();
1324
1325 timer T := 5.0;
1326 T.start;
1327 alt {
1328 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, 0, 0))) {
1329 setverdict(pass);
1330 repeat;
1331 }
1332 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
1333 setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
1334 repeat;
1335 }
1336 [] RSL_CCHAN.receive {
1337 repeat;
1338 }
1339 [] T.timeout { }
1340 }
1341
1342 f_vty_load_ind_thresh(10);
1343 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1344}
1345
1346/* Expect no RACH load indications on an idle BTS that has just started up (default threshold 10%) */
1347testcase TC_rach_load_idle_below_thresh() runs on test_CT {
1348 var ASP_RSL_Unitdata rx_ud;
1349
1350 f_init_vty_bsc();
1351 f_init();
1352
1353 timer T := 5.0;
1354 T.start;
1355 alt {
1356 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
1357 setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
1358 repeat;
1359 }
1360 [] RSL_CCHAN.receive {
1361 repeat;
1362 }
1363 [] T.timeout {
1364 setverdict(pass);
1365 }
1366 }
1367
1368 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1369}
1370
1371/* Expect 0 RACH load on an idle BTS that has just started up */
1372testcase TC_rach_load_count() runs on test_CT {
1373 var ASP_RSL_Unitdata rx_ud;
1374 var integer load_access_count := 0;
1375
1376 f_init_vty_bsc();
1377 /* send load indications even at 0% load */
1378 f_vty_load_ind_thresh(0);
1379 f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
1380 f_sleep(2.0);
1381 f_init();
1382
1383 f_init_l1ctl();
1384 f_sleep(1.0);
1385 f_l1_tune(L1CTL);
1386
1387 var GsmFrameNumber fn_last := 0;
1388 for (var integer i := 0; i < 1000; i := i+1) {
1389 var OCT1 ra := f_rnd_ra_cs();
1390 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1391 if (fn == fn_last) {
1392 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
1393 }
1394 fn_last := fn;
1395 }
1396
1397 timer T := 5.0;
1398 T.start;
1399 alt {
1400 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, ?, ?)))
1401 -> value rx_ud {
1402 var RSL_IE_Body ie;
1403 f_rsl_find_ie(rx_ud.rsl, RSL_IE_RACH_LOAD, ie);
1404 load_access_count := load_access_count + ie.rach_load.access_count;
1405 if (ie.rach_load.busy_count < ie.rach_load.access_count) {
1406 setverdict(fail, "Access count cannot be < Busy count");
1407 }
1408 repeat;
1409 }
1410 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
1411 setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
1412 repeat;
1413 }
1414 [] RSL_CCHAN.receive {
1415 repeat;
1416 }
1417 [] T.timeout { }
1418 }
1419 if (load_access_count == 1000) {
1420 setverdict(pass);
1421 } else {
1422 setverdict(fail, "Load reports state ", load_access_count, " RACH, but we sent 1000");
1423 }
1424
1425 f_vty_load_ind_thresh(10);
1426 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1427}
1428
1429
1430
Harald Welte54a2a2d2018-02-26 09:14:05 +01001431private function f_main_trxc_connect() runs on test_CT {
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +07001432 map(self:BTS_TRXC, system:BTS_TRXC);
Harald Welte54a2a2d2018-02-26 09:14:05 +01001433 var Result res;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +07001434 res := TRXC_CodecPort_CtrlFunct.f_IPL4_connect(BTS_TRXC, mp_bts_trxc_ip, mp_bts_trxc_port,
Harald Welted3a88a62018-03-01 16:04:52 +01001435 "", -1, -1, {udp:={}}, {});
Harald Welte9220f632018-05-23 20:27:02 +02001436 if (not ispresent(res.connId)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001437 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Could not connect to trx-control interface of trxcon, check your configuration");
Harald Welte9220f632018-05-23 20:27:02 +02001438 }
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +07001439 g_bts_trxc_conn_id := res.connId;
Harald Welte54a2a2d2018-02-26 09:14:05 +01001440}
1441
1442private function f_rach_toffs(int16_t toffs256, boolean expect_pass) runs on test_CT {
Harald Weltef8df4cb2018-03-10 15:15:08 +01001443 var TrxcMessage ret;
Harald Welte54a2a2d2018-02-26 09:14:05 +01001444 /* tell fake_trx to use a given timing offset for all bursts */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +07001445 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_TIMING(toffs256)));
Harald Welte54a2a2d2018-02-26 09:14:05 +01001446 f_sleep(0.5);
1447
1448 /* Transmit RACH request + wait for confirmation */
1449 var OCT1 ra := f_rnd_ra_cs();
1450 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1451
1452 /* Check for expected result */
1453 timer T := 1.5;
1454 T.start;
1455 alt {
1456 [expect_pass] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
1457 setverdict(pass);
1458 }
1459 [not expect_pass] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001460 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("RACH passed but was expected to be dropped: ", toffs256));
Harald Welte54a2a2d2018-02-26 09:14:05 +01001461 }
1462 [] RSL_CCHAN.receive { repeat; }
1463 [not expect_pass] T.timeout {
1464 setverdict(pass);
1465 }
1466 [expect_pass] T.timeout {
Max6e053042019-03-14 16:34:22 +01001467 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for CHAN RQD: FN=", fn, " RA=", ra));
Harald Welte54a2a2d2018-02-26 09:14:05 +01001468 }
1469 }
1470}
1471
1472/* Test if dropping of RACH Based on NM_ATT_MAX_TA works */
1473testcase TC_rach_max_ta() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02001474 f_init();
Harald Welte54a2a2d2018-02-26 09:14:05 +01001475 f_init_l1ctl();
1476 f_l1_tune(L1CTL);
Harald Welte54a2a2d2018-02-26 09:14:05 +01001477 f_sleep(1.0);
1478
1479 /* default max-ta is 63 (full range of GSM timing advance */
1480
Vadim Yanitskiyc81d6e42018-03-05 22:39:01 +07001481 /* We allow early arrival up to 2 symbols */
1482 f_rach_toffs(-1*256, true);
1483 f_rach_toffs(-2*256, true);
Harald Welte54a2a2d2018-02-26 09:14:05 +01001484 f_rach_toffs(-10*256, false);
1485
1486 /* 0 / 32 / 63 bits is legal / permitted */
1487 f_rach_toffs(0, true);
1488 f_rach_toffs(32*256, true);
1489 f_rach_toffs(63*256, true);
1490
1491 /* more than 63 bits is not legal / permitted */
1492 f_rach_toffs(64*256, false);
1493 f_rach_toffs(127*256, false);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001494 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte54a2a2d2018-02-26 09:14:05 +01001495}
Harald Welte8c24c2b2018-02-26 08:31:31 +01001496
Vadim Yanitskiy7c2c10c2019-05-31 20:42:01 +07001497function f_TC_ho_rach(charstring id) runs on ConnHdlr {
1498 var GsmFrameNumber fn;
1499 var RSL_Message rm;
1500
1501 f_l1_tune(L1CTL);
1502 RSL.clear;
1503
1504 /* Generate a random Handover Reference */
1505 var integer ho_ref := oct2int(f_rnd_octstring(1));
1506
1507 /* Handover Reference IE (see 3GPP TS 48.058, 9.3.9) */
1508 var RSL_IE ho_ref_ie := valueof(t_RSL_IE(RSL_IE_HANDO_REF,
1509 RSL_IE_Body:{ handover_ref := ho_ref }));
1510
1511 /* Activate a channel on the BTS side (no encryption) */
1512 f_rsl_chan_act(g_pars.chan_mode, more_ies := { ho_ref_ie },
1513 act_type := t_RSL_IE_ActType_HO_SYNC);
1514
1515 /* Switch the MS side (e.g. trxcon) to a dedicated channel without
1516 * waiting for Immediate Assignment and sending Access Burst */
1517 f_L1CTL_DM_EST_REQ(L1CTL, { false, mp_trx0_arfcn }, g_pars.chan_nr, 7);
1518
1519 /* Send handover Access Burst */
1520 fn := f_L1CTL_RACH(L1CTL, ho_ref, chan_nr := g_pars.chan_nr);
1521
1522 /* TODO: test mismatching Handover Reference, and missing IE */
1523
1524 /* Wait for handover detection */
1525 timer T := 3.0;
1526 T.start;
1527 alt {
1528 [] RSL.receive(tr_RSL_HANDO_DET(g_pars.chan_nr)) -> value rm {
1529 log("Handover RACH has been detected: ", rm);
1530 setverdict(pass);
1531 }
1532 [] RSL.receive(tr_RSL_CHAN_RQD(?, ?, ?, ?)) -> value rm {
1533 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1534 log2str("RSL_CHAN_RQD was not expected: ", rm));
1535 }
1536 [] RSL.receive { repeat; }
1537 [] T.timeout {
1538 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1539 log2str("Timeout waiting for handover RACH: FN=", fn, " RA=", ho_ref));
1540 }
1541 }
1542
1543 /* Release the channel */
1544 f_rsl_chan_deact();
1545 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1546}
1547
1548/* Test handover RACH detection */
1549testcase TC_ho_rach() runs on test_CT {
1550 var ConnHdlrPars pars;
1551 var ConnHdlr vc_conn;
1552
1553 f_init();
1554
1555 for (var integer i := 0; i < sizeof(g_AllChannels); i := i + 1) {
1556 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1557 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1558 vc_conn := f_start_handler(refers(f_TC_ho_rach), pars);
1559 vc_conn.done;
1560 }
1561
1562 /* TODO: do the above in parallel, rather than sequentially? */
1563 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1564}
1565
Harald Welte93640c62018-02-25 16:59:33 +01001566/***********************************************************************
1567 * Measurement Processing / Reporting
1568 ***********************************************************************/
1569
Harald Welte70767382018-02-21 12:16:40 +01001570template LapdmAddressField ts_LapdmAddr(LapdmSapi sapi, boolean c_r) := {
1571 spare := '0'B,
1572 lpd := 0,
1573 sapi := sapi,
1574 c_r := c_r,
1575 ea := true
1576}
1577
Harald Welted879bd92018-03-12 15:01:23 +01001578template LapdmFrameAB ts_LAPDm_AB(LapdmSapi sapi, boolean c_r, boolean p, octetstring pl) := {
Harald Welte70767382018-02-21 12:16:40 +01001579 addr := ts_LapdmAddr(sapi, c_r),
Harald Welted879bd92018-03-12 15:01:23 +01001580 ctrl := ts_LapdmCtrlUI(p),
Harald Welte70767382018-02-21 12:16:40 +01001581 len := 0, /* overwritten */
1582 m := false,
1583 el := 1,
1584 payload := pl
1585}
1586
1587/* handle incoming downlink SACCH and respond with uplink SACCH (meas res) */
1588altstep as_l1_sacch() runs on ConnHdlr {
1589 var L1ctlDlMessage l1_dl;
Harald Weltef8df4cb2018-03-10 15:15:08 +01001590 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
Harald Welte70767382018-02-21 12:16:40 +01001591 log("SACCH received: ", l1_dl.payload.data_ind.payload);
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +02001592 var GsmRrL3Message meas_rep := valueof(ts_MEAS_REP(true, mp_rxlev_exp, mp_rxlev_exp, 0, 0, omit));
Harald Welted879bd92018-03-12 15:01:23 +01001593 var LapdmFrameAB lb := valueof(ts_LAPDm_AB(0, false, false, enc_GsmRrL3Message(meas_rep)));
Harald Welte70767382018-02-21 12:16:40 +01001594 log("LAPDm: ", lb);
Pau Espin Pedroled359cb2018-09-28 16:08:24 +02001595
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07001596 var template (value) SacchL1Header l1h := ts_SacchL1Header(
1597 g_pars.l1_pars.ms_power_level, false,
1598 g_pars.l1_pars.ms_actual_ta);
1599
1600 /* TODO: we can use an extension of TTCN-3 for that, i.e. PADDING('2B'O) */
1601 var octetstring l2 := f_pad_oct(enc_LapdmFrameAB(lb), 21, '2B'O);
1602
1603 log("Sending Measurement Report: ", l1h, l2);
1604 L1CTL.send(ts_L1CTL_DATA_REQ_SACCH(g_chan_nr, ts_RslLinkID_SACCH(0), l1h, l2));
Harald Welte70767382018-02-21 12:16:40 +01001605 repeat;
1606 }
1607}
1608
1609altstep as_l1_dcch() runs on ConnHdlr {
1610 var L1ctlDlMessage l1_dl;
Harald Weltef8df4cb2018-03-10 15:15:08 +01001611 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_DCCH(?))) -> value l1_dl {
Harald Welte70767382018-02-21 12:16:40 +01001612 log("DCCH received: ", l1_dl.payload.data_ind.payload);
1613 var octetstring pl := '010301'O;
Vadim Yanitskiy31e7c672018-07-27 02:23:16 +07001614 L1CTL.send(ts_L1CTL_DATA_REQ(g_chan_nr, ts_RslLinkID_DCCH(0),
1615 f_pad_oct(pl, 23, '2B'O)));
Harald Welte70767382018-02-21 12:16:40 +01001616 repeat;
1617 }
1618}
1619
1620type record MeasElem {
1621 uint6_t rxlev,
1622 uint3_t rxqual
1623}
1624
1625type record MeasElemFS {
1626 MeasElem full,
1627 MeasElem sub
1628}
1629
1630type record ConnL1Pars {
1631 boolean dtx_enabled,
Harald Welte685d5982018-02-27 20:42:05 +01001632 boolean toa256_enabled,
Harald Welte70767382018-02-21 12:16:40 +01001633 MeasElemFS meas_ul,
1634 int16_t timing_offset_256syms,
1635 uint5_t bs_power_level,
1636 uint5_t ms_power_level,
1637 uint8_t ms_actual_ta
1638}
1639
1640/* Convert tiing offset from 1/256th symbol to RSL Timing Offset */
1641private function toffs256s_to_rsl(int16_t toffs256s) return uint8_t {
1642 return 63 + (toffs256s/256);
1643}
1644
Harald Welted5684392018-03-10 18:22:04 +01001645private function f_max(integer a, integer b) return integer {
1646 if (a > b) {
1647 return a;
1648 } else {
1649 return b;
1650 }
1651}
1652
1653private function f_min(integer a, integer b) return integer {
1654 if (a < b) {
1655 return a;
1656 } else {
1657 return b;
1658 }
1659}
1660
1661/* compute negative tolerance val-tolerance, ensure >= min */
1662private function f_tolerance_neg(integer val, integer min, integer tolerance) return integer {
1663 val := val - tolerance;
1664 return f_max(val, min);
1665}
1666
1667/* compute positive tolerance val+tolerance, ensure <= max */
1668private function f_tolerance_pos(integer val, integer max, integer tolerance) return integer {
1669 val := val + tolerance;
1670 return f_min(val, max);
1671}
1672
1673/* return a template of (val-tolerance .. val+tolerance) ensuring it is within (min .. max) */
1674private function f_tolerance(integer val, integer min, integer max, integer tolerance)
1675return template integer {
1676 var template integer ret;
1677 ret := (f_tolerance_neg(val, min, tolerance) .. f_tolerance_pos(val, max, tolerance));
1678 return ret;
1679}
1680
1681
Harald Welte70767382018-02-21 12:16:40 +01001682/* build a template for matching measurement results against */
1683private function f_build_meas_res_tmpl() runs on ConnHdlr return template RSL_Message {
1684 var ConnL1Pars l1p := g_pars.l1_pars;
1685 var template RSL_IE_UplinkMeas ul_meas := {
1686 len := 3,
1687 rfu := '0'B,
1688 dtx_d := l1p.dtx_enabled,
Harald Welted5684392018-03-10 18:22:04 +01001689 rxlev_f_u := f_tolerance(l1p.meas_ul.full.rxlev, 0, 63, mp_tolerance_rxlev),
Harald Welte70767382018-02-21 12:16:40 +01001690 reserved1 := '00'B,
Harald Welted5684392018-03-10 18:22:04 +01001691 rxlev_s_u := f_tolerance(l1p.meas_ul.sub.rxlev, 0, 63, mp_tolerance_rxlev),
Harald Welte70767382018-02-21 12:16:40 +01001692 reserved2 := '00'B,
Harald Welted5684392018-03-10 18:22:04 +01001693 rxq_f_u := f_tolerance(l1p.meas_ul.full.rxqual, 0, 7, mp_tolerance_rxqual),
1694 rxq_s_u := f_tolerance(l1p.meas_ul.sub.rxqual, 0, 7, mp_tolerance_rxqual),
Harald Welte70767382018-02-21 12:16:40 +01001695 supp_meas_info := omit
1696 };
Harald Welte685d5982018-02-27 20:42:05 +01001697 if (l1p.toa256_enabled) {
Harald Welte15de8ba2018-06-29 08:51:42 +02001698 ul_meas.len := (3+8);
1699 ul_meas.supp_meas_info := {
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001700 toa256_mean := f_tolerance(l1p.timing_offset_256syms, -63*256, 192*256, mp_tolerance_timing_offset_256syms),
Harald Welte15de8ba2018-06-29 08:51:42 +02001701 toa256_min := ?,
1702 toa256_max := ?,
1703 toa256_std_dev := ?
1704 }
Harald Welte685d5982018-02-27 20:42:05 +01001705 }
Harald Welte70767382018-02-21 12:16:40 +01001706 var template RSL_IE_BS_Power bs_power := {
1707 reserved := 0,
1708 epc := false,
1709 fpc := false,
1710 power_level := l1p.bs_power_level
1711 };
1712 var template RSL_IE_L1Info l1_info := {
1713 ms_power_lvl := l1p.ms_power_level,
1714 fpc := false,
1715 reserved := 0,
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001716 actual_ta := f_tolerance(l1p.ms_actual_ta, 0, 63, mp_tolerance_timing_offset_256syms/256)
Harald Welte70767382018-02-21 12:16:40 +01001717 };
1718 var uint8_t offs := toffs256s_to_rsl(l1p.timing_offset_256syms);
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001719 var template uint8_t t_toffs := f_tolerance(offs, 0, 255, mp_tolerance_timing_offset_256syms/256);
Harald Welte70767382018-02-21 12:16:40 +01001720 return tr_RSL_MEAS_RES_OSMO(g_chan_nr, g_next_meas_res_nr, ul_meas, bs_power, l1_info,
1721 ?, t_toffs);
1722}
1723
1724/* verify we regularly receive measurement reports with incrementing numbers */
Vadim Yanitskiy41baf002018-10-04 17:44:50 +07001725altstep as_meas_res(boolean verify_meas := true) runs on ConnHdlr {
Harald Welte70767382018-02-21 12:16:40 +01001726 var RSL_Message rsl;
Vadim Yanitskiy41baf002018-10-04 17:44:50 +07001727 [not verify_meas] RSL.receive(tr_RSL_MEAS_RES(?)) { repeat; }
Harald Welte70767382018-02-21 12:16:40 +01001728 [] RSL.receive(f_build_meas_res_tmpl()) -> value rsl {
1729 /* increment counter of next to-be-expected meas rep */
1730 g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
1731 /* Re-start the timer expecting the next MEAS RES */
Harald Weltec3a3f452018-02-26 17:37:47 +01001732 f_timer_safe_restart(g_Tmeas_exp);
Harald Welte70767382018-02-21 12:16:40 +01001733 repeat;
1734 }
1735 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr, g_next_meas_res_nr)) -> value rsl {
Harald Weltefa45e9e2018-03-10 18:59:03 +01001736 /* increment counter of next to-be-expected meas rep */
1737 g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
1738 if (g_first_meas_res) {
1739 g_first_meas_res := false;
1740 repeat;
1741 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001742 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unspecific MEAS RES ", rsl));
Harald Weltefa45e9e2018-03-10 18:59:03 +01001743 }
Harald Welte70767382018-02-21 12:16:40 +01001744 }
1745 [] RSL.receive(tr_RSL_MEAS_RES(?)) -> value rsl {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001746 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unexpected MEAS RES ", rsl));
Harald Welte70767382018-02-21 12:16:40 +01001747 }
Pau Espin Pedrol425b62f2018-07-06 16:11:43 +02001748 [g_Tmeas_exp.running] g_Tmeas_exp.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001749 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Didn't receive expected measurement result")
Harald Welte70767382018-02-21 12:16:40 +01001750 }
1751}
1752
Harald Weltee613f962018-04-18 22:38:16 +02001753private function f_alg_id_to_l1ctl(RSL_AlgId rsl_alg_id) return uint8_t {
1754 select (rsl_alg_id) {
1755 case (RSL_ALG_ID_A5_0) { return 0; }
1756 case (RSL_ALG_ID_A5_1) { return 1; }
1757 case (RSL_ALG_ID_A5_2) { return 2; }
1758 case (RSL_ALG_ID_A5_3) { return 3; }
1759 case (RSL_ALG_ID_A5_4) { return 4; }
1760 case (RSL_ALG_ID_A5_5) { return 5; }
1761 case (RSL_ALG_ID_A5_6) { return 6; }
1762 case (RSL_ALG_ID_A5_7) { return 7; }
1763 case else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001764 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unknwon Algorithm ID");
1765 /* Make compiler happy by calling mtc.stop here. It is already
1766 * called in f_shutdown */
Daniel Willmann17ddd852018-07-05 17:33:20 +02001767 mtc.stop;
Harald Weltee613f962018-04-18 22:38:16 +02001768 }
1769 }
1770}
1771
1772private function f_alg_id_to_l3(RSL_AlgId rsl_alg_id) return BIT3 {
1773 select (rsl_alg_id) {
1774 case (RSL_ALG_ID_A5_1) { return '000'B; }
1775 case (RSL_ALG_ID_A5_2) { return '001'B; }
1776 case (RSL_ALG_ID_A5_3) { return '010'B; }
1777 case (RSL_ALG_ID_A5_4) { return '011'B; }
1778 case (RSL_ALG_ID_A5_5) { return '100'B; }
1779 case (RSL_ALG_ID_A5_6) { return '101'B; }
1780 case (RSL_ALG_ID_A5_7) { return '110'B; }
1781 case else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001782 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unknwon Algorithm ID");
1783 /* Make compiler happy by calling mtc.stop here. It is already
1784 * called in f_shutdown */
Daniel Willmann17ddd852018-07-05 17:33:20 +02001785 mtc.stop;
Harald Weltee613f962018-04-18 22:38:16 +02001786 }
1787 }
1788}
1789
Pau Espin Pedrol6451b042018-10-24 20:36:16 +02001790/* Send RACH request through l1CTL and wait for ChanReq on RSL BST->BSC */
1791private function f_rach_req_wait_chan_rqd(integer ra) runs on ConnHdlr return GsmFrameNumber {
1792 var GsmFrameNumber fn;
1793 timer T := 8.0;
1794
1795 /* advertise to RSL Emulation that we expect to receive confirmation from RACH */
1796 RSL.send(ts_RSLDC_ChanRqd_anyFN(int2oct(ra,1)));
1797
1798 f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, g_pars.l1_pars.ms_power_level);
1799 /* Send the actual RACH */
1800 fn := f_L1CTL_RACH(L1CTL, ra);
1801
1802 T.start;
1803 alt {
1804 [] RSL.receive(tr_RSL_CHAN_RQD(int2oct(ra,1), fn)) { setverdict(pass, "Received CHAN-RQD from RACH REQ") }
1805 [] T.timeout {
1806 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for CHAN-RQD from RACH REQ <", ra, ", ", fn, ">"));
1807 }
1808 }
1809 T.stop
1810 return fn;
1811}
Harald Weltee613f962018-04-18 22:38:16 +02001812
Harald Welte70767382018-02-21 12:16:40 +01001813/* Establish dedicated channel: L1CTL + RSL side */
Harald Weltec8d363c2019-05-19 20:36:48 +02001814private function f_est_dchan(boolean encr_enable := false, RSL_IE_List more_ies := {}) runs on ConnHdlr {
Harald Welte70767382018-02-21 12:16:40 +01001815 var GsmFrameNumber fn;
1816 var ImmediateAssignment imm_ass;
1817 var integer ra := 23;
1818
Pau Espin Pedrol6451b042018-10-24 20:36:16 +02001819 /* Send RACH request and wait for ChanReq */
1820 fn := f_rach_req_wait_chan_rqd(ra);
Harald Welte70767382018-02-21 12:16:40 +01001821
1822 /* Activate channel on BTS side */
Harald Weltec8d363c2019-05-19 20:36:48 +02001823 f_rsl_chan_act(g_pars.chan_mode, encr_enable, more_ies);
Harald Welte70767382018-02-21 12:16:40 +01001824
1825 /* Send IMM.ASS via CCHAN */
1826 var ChannelDescription ch_desc := {
1827 chan_nr := g_pars.chan_nr,
1828 tsc := 7,
1829 h := false,
1830 arfcn := mp_trx0_arfcn,
1831 maio_hsn := omit
1832 };
1833 var MobileAllocation ma := {
1834 len := 0,
1835 ma := ''B
1836 };
1837 var GsmRrMessage rr_msg := valueof(ts_IMM_ASS(ra, fn, 0, ch_desc, ma));
1838 RSL.send(ts_RSL_IMM_ASSIGN(enc_GsmRrMessage(rr_msg)));
1839
1840 /* receive IMM.ASS on MS side */
1841 var ImmediateAssignment ia_um;
1842 ia_um := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, fn);
1843 /* enable dedicated mode */
1844 f_L1CTL_DM_EST_REQ_IA(L1CTL, ia_um);
Harald Weltee613f962018-04-18 22:38:16 +02001845 /* enable encryption, if requested */
1846 if (encr_enable) {
1847 var uint8_t alg_id := f_alg_id_to_l1ctl(g_pars.encr.alg_id);
1848 f_L1CTL_CRYPTO_REQ(L1CTL, g_pars.chan_nr, alg_id, g_pars.encr.key);
1849 }
Harald Weltefa45e9e2018-03-10 18:59:03 +01001850
1851 g_first_meas_res := true;
Harald Welte70767382018-02-21 12:16:40 +01001852}
1853
1854/* establish DChan, verify existance + contents of measurement reports */
1855function f_TC_meas_res_periodic(charstring id) runs on ConnHdlr {
Harald Welte68e495b2018-02-25 00:05:57 +01001856 f_l1_tune(L1CTL);
Harald Welte70767382018-02-21 12:16:40 +01001857 RSL.clear;
1858
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +07001859 if (mp_bts_trxc_port != -1) {
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +02001860 f_trxc_fake_rssi(rxlev2dbm(mp_ul_rxlev_exp));
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001861 f_trx_fake_toffs256(g_pars.l1_pars.timing_offset_256syms);
1862 }
Harald Welte70767382018-02-21 12:16:40 +01001863
1864 f_est_dchan();
1865
1866 /* run for a number of seconds, send SACCH + FACCH from MS side and verify
1867 * RSL measurement reports on Abis side */
1868 timer T := 8.0;
1869 T.start;
1870 alt {
1871 [] as_l1_sacch();
1872 [] as_meas_res();
1873 [] as_l1_dcch();
1874 [] L1CTL.receive { repeat; }
1875 [g_Tmeas_exp.running] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001876 /* as_meas_res() would have done Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail) in case
Harald Welte70767382018-02-21 12:16:40 +01001877 * of any earlier errors, so if we reach this timeout, we're good */
1878 setverdict(pass);
1879 }
1880 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001881 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No MEAS RES received at all");
Harald Welte70767382018-02-21 12:16:40 +01001882 }
1883 }
1884 f_rsl_chan_deact();
Harald Welte3dc20462018-03-10 23:03:38 +01001885 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Harald Welte70767382018-02-21 12:16:40 +01001886}
Harald Welte0472ab42018-03-12 15:02:26 +01001887
Harald Welte70767382018-02-21 12:16:40 +01001888testcase TC_meas_res_sign_tchf() runs on test_CT {
1889 var ConnHdlr vc_conn;
1890 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02001891 f_init();
Harald Welte70767382018-02-21 12:16:40 +01001892 for (var integer tn := 1; tn <= 4; tn := tn+1) {
1893 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
1894 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars);
1895 vc_conn.done;
1896 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001897 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001898}
1899testcase TC_meas_res_sign_tchh() runs on test_CT {
1900 var ConnHdlr vc_conn;
1901 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02001902 f_init();
Harald Welte70767382018-02-21 12:16:40 +01001903 for (var integer ss := 0; ss <= 1; ss := ss+1) {
1904 pars := valueof(t_Pars(t_RslChanNr_Lm(5, ss), ts_RSL_ChanMode_SIGN));
1905 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars);
1906 vc_conn.done;
1907 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001908 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001909}
1910testcase TC_meas_res_sign_sdcch4() runs on test_CT {
1911 var ConnHdlr vc_conn;
1912 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02001913 f_init();
Harald Welte70767382018-02-21 12:16:40 +01001914 for (var integer ss := 0; ss <= 3; ss := ss+1) {
1915 pars := valueof(t_Pars(t_RslChanNr_SDCCH4(0, ss), ts_RSL_ChanMode_SIGN));
1916 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars);
1917 vc_conn.done;
1918 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001919 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001920}
1921testcase TC_meas_res_sign_sdcch8() runs on test_CT {
1922 var ConnHdlr vc_conn;
1923 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02001924 f_init();
Harald Welte70767382018-02-21 12:16:40 +01001925 for (var integer ss := 0; ss <= 7; ss := ss+1) {
1926 pars := valueof(t_Pars(t_RslChanNr_SDCCH8(6, ss), ts_RSL_ChanMode_SIGN));
1927 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars);
1928 vc_conn.done;
1929 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001930 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001931}
Harald Welte685d5982018-02-27 20:42:05 +01001932testcase TC_meas_res_sign_tchh_toa256() runs on test_CT {
1933 var ConnHdlr vc_conn;
1934 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02001935 f_init();
Harald Welte685d5982018-02-27 20:42:05 +01001936 f_vty_config(BTSVTY, "bts 0", "supp-meas-info toa256");
1937 for (var integer ss := 0; ss <= 1; ss := ss+1) {
1938 pars := valueof(t_Pars(t_RslChanNr_Lm(5, ss), ts_RSL_ChanMode_SIGN));
1939 pars.l1_pars.toa256_enabled := true;
1940 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars);
1941 vc_conn.done;
1942 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001943 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte685d5982018-02-27 20:42:05 +01001944}
1945
Philipp Maier4d1e9c92018-12-20 11:11:56 +01001946/* establish DChan, and send MS POWER CONTROL messages via RSL, verify that
1947 * the BTS is forwarding those values to the MS via the SACCH L1 header. */
1948function f_tc_rsl_ms_pwr_ctrl(charstring id) runs on ConnHdlr {
1949 var L1ctlDlMessage l1_dl;
1950 var RSL_IE_MS_Power ms_power;
1951 var RSL_Message rsl;
1952 var uint5_t power_level := 0;
1953
1954 f_l1_tune(L1CTL);
1955 RSL.clear;
1956
1957 f_est_dchan();
1958
1959 ms_power.reserved := 0;
1960 ms_power.fpc_epc := false;
1961
1962 /* Send the first power control command. This will disable any BTS/TRX
1963 * internal power control and switch the MS (which is not in scope of
1964 * this test) to a constant power level. We start with a power level
1965 * of 0 */
1966 ms_power.power_level := power_level;
1967 rsl := valueof(ts_RSL_MS_PWR_CTRL(g_chan_nr, ms_power));
1968 RSL.send(rsl);
1969
1970 alt {
1971
1972 /* Pick all SACCH blocks for checking */
1973 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
1974
1975 /* The first byte of the L1 header contains the power level.
1976 * The reserved bits and the fpc bit is set to 0, so we may
1977 * compare directly. */
1978 if (not (l1_dl.payload.data_ind.payload[0] == int2oct(power_level, 1))) {
1979 setverdict(fail, "Power level in L1 header does not match the signaled (RSL) power level.");
1980 }
1981
1982 /* Signal a new power level via RSL for the next turn. */
1983 if (power_level < 31) {
1984 power_level := power_level + 1;
1985 ms_power.power_level := power_level;
1986 rsl := valueof(ts_RSL_MS_PWR_CTRL(g_chan_nr, ms_power));
1987 RSL.send(rsl);
1988 repeat;
1989 }
1990
1991 }
1992
1993 /* Ignore all other blocks */
1994 [] L1CTL.receive { repeat; }
1995
1996 }
1997
1998 f_rsl_chan_deact();
1999 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2000
2001 setverdict(pass);
2002}
2003
2004testcase TC_rsl_ms_pwr_ctrl() runs on test_CT {
2005 var ConnHdlr vc_conn;
2006 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002007 f_init();
Philipp Maier4d1e9c92018-12-20 11:11:56 +01002008
2009 for (var integer tn := 1; tn <= 4; tn := tn+1) {
2010 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2011 vc_conn := f_start_handler(refers(f_tc_rsl_ms_pwr_ctrl), pars);
2012 vc_conn.done;
2013 }
2014 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2015}
Harald Welte70767382018-02-21 12:16:40 +01002016
Eric Wild6833cc92019-05-23 19:34:44 +02002017/* establish DChan, verify that the BTS sets the TA in the first SACCH L1 header.
2018TA for the IMM ASS messages is still controlled by g_pars.l1_pars.ms_actual_ta! */
2019function f_tc_rsl_chan_initial_ta(charstring id) runs on ConnHdlr {
2020 var L1ctlDlMessage l1_dl;
2021 var uint5_t ta_to_test := 16;
2022
2023
2024 f_l1_tune(L1CTL);
2025 RSL.clear;
2026
2027 /* tell fake_trx to use a given timing offset for all bursts */
2028 f_trx_fake_toffs256(ta_to_test*256);
2029
2030 f_est_dchan(more_ies :={valueof(t_RSL_IE(RSL_IE_TIMING_ADVANCE, RSL_IE_Body:{timing_adv := ta_to_test}))} );
2031
2032
2033 alt {
2034
2035 /* Pick all SACCH blocks for checking */
2036 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2037
2038 /* The second byte of the L1 header contains the TA. */
2039 if (not (l1_dl.payload.data_ind.payload[1] == int2oct(ta_to_test, 1))) {
2040 setverdict(fail, "TA in L1 header does not match the signaled (RSL) TA.");
2041 }
2042
2043 }
2044
2045 /* Ignore all other blocks */
2046 [] L1CTL.receive { repeat; }
2047
2048 }
2049
2050 f_rsl_chan_deact();
2051 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2052
2053 setverdict(pass);
2054}
2055
2056testcase TC_rsl_chan_initial_ta() runs on test_CT {
2057 var ConnHdlr vc_conn;
2058 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002059 f_init();
Eric Wild6833cc92019-05-23 19:34:44 +02002060 pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
2061 vc_conn := f_start_handler(refers(f_tc_rsl_chan_initial_ta), pars);
2062 vc_conn.done;
2063 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2064}
2065
Eric Wilde57e1a62019-05-28 13:30:55 +02002066/* establish DChan, verify that the BTS sets MS power in the first SACCH L1 header. */
2067function f_tc_rsl_chan_initial_ms_pwr(charstring id) runs on ConnHdlr {
2068 var L1ctlDlMessage l1_dl;
2069 var uint5_t ms_power_level := 7;
2070
2071 var RSL_IE_MS_Power ms_power;
2072 ms_power.reserved := 0;
2073 ms_power.fpc_epc := false;
2074 ms_power.power_level := ms_power_level;
2075
2076 f_l1_tune(L1CTL);
2077 RSL.clear;
2078
2079 f_est_dchan(more_ies :={valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ms_power}))} );
2080
2081 timer T := 1.0;
2082 T.start;
2083 alt {
2084 /* Pick all SACCH blocks for checking */
2085 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2086 /* The first byte of the L1 header contains the power level.. */
2087 if (not (l1_dl.payload.data_ind.payload[0] == int2oct(ms_power_level, 1))) {
2088 setverdict(fail, "Power Level in L1 header does not match the signaled (RSL) MS Power Level.");
2089 }
2090 }
2091 /* Ignore all other blocks */
2092 [] L1CTL.receive { repeat; }
2093 [] T.timeout {
2094 setverdict(fail, "Power Level in L1 header does not match the signaled (RSL) MS Power Level.");
2095 }
2096 }
2097
2098 f_rsl_chan_deact();
2099 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2100 setverdict(pass);
2101}
2102
2103testcase TC_rsl_chan_initial_ms_pwr() runs on test_CT {
2104 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
2105 f_testmatrix_each_chan(pars, refers(f_tc_rsl_chan_initial_ms_pwr));
2106}
2107
Harald Welte0472ab42018-03-12 15:02:26 +01002108/* Test if a channel without valid uplink bursts generates RSL CONN FAIL IND (TS 48.058 4.10) */
Harald Welte70767382018-02-21 12:16:40 +01002109private function f_TC_conn_fail_crit(charstring id) runs on ConnHdlr {
Harald Welte68e495b2018-02-25 00:05:57 +01002110 f_l1_tune(L1CTL);
Harald Welte70767382018-02-21 12:16:40 +01002111 RSL.clear;
2112
2113 f_est_dchan();
2114 f_sleep(2.0);
Harald Weltef8df4cb2018-03-10 15:15:08 +01002115 L1CTL.send(ts_L1CTL_DM_REL_REQ(g_chan_nr));
Harald Welte70767382018-02-21 12:16:40 +01002116
2117 timer T := 40.0;
2118 T.start;
2119 alt {
2120 [] RSL.receive(tr_RSL_CONN_FAIL_IND(g_chan_nr, ?)) {
2121 setverdict(pass)
2122 }
2123 [] RSL.receive { repeat };
2124 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002125 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No CONN FAIL IND received");
Harald Welte70767382018-02-21 12:16:40 +01002126 }
2127 }
2128 f_rsl_chan_deact();
2129}
2130testcase TC_conn_fail_crit() runs on test_CT {
2131 var ConnHdlr vc_conn;
2132 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002133 f_init();
Harald Welte70767382018-02-21 12:16:40 +01002134 pars := valueof(t_Pars(t_RslChanNr_SDCCH8(6, 3), ts_RSL_ChanMode_SIGN));
2135 pars.t_guard := 60.0;
2136 vc_conn := f_start_handler(refers(f_TC_conn_fail_crit), pars);
2137 vc_conn.done;
2138}
2139
Harald Welte93640c62018-02-25 16:59:33 +01002140/***********************************************************************
2141 * Paging
2142 ***********************************************************************/
2143
Harald Welte68e495b2018-02-25 00:05:57 +01002144function tmsi_is_dummy(TMSIP_TMSI_V tmsi) return boolean {
2145 if (tmsi == 'FFFFFFFF'O) {
2146 return true;
2147 } else {
2148 return false;
2149 }
2150}
Harald Welte70767382018-02-21 12:16:40 +01002151
Philipp Maier82cb0b12018-08-31 14:41:39 +02002152type record allowedFn { integer frame_nr }
2153template allowedFn bs_ag_blks_res_0 := { frame_nr := (6, 12, 16, 22, 26, 32, 36, 42, 46) }
2154template allowedFn bs_ag_blks_res_1 := { frame_nr := (12, 16, 22, 26, 32, 36, 42, 46) }
2155template allowedFn bs_ag_blks_res_2 := { frame_nr := (16, 22, 26, 32, 36, 42, 46) }
2156template allowedFn bs_ag_blks_res_3 := { frame_nr := (22, 26, 32, 36, 42, 46) }
2157template allowedFn bs_ag_blks_res_4 := { frame_nr := (26, 32, 36, 42, 46) }
2158template allowedFn bs_ag_blks_res_5 := { frame_nr := (32, 36, 42, 46) }
2159template allowedFn bs_ag_blks_res_6 := { frame_nr := (36, 42, 46) }
2160template allowedFn bs_ag_blks_res_7 := { frame_nr := (42, 46) }
2161function check_pch_fn(integer frame_nr, integer bs_ag_blks_res) runs on test_CT
2162{
2163 var integer frame_nr_51;
2164 frame_nr_51 := frame_nr mod 51
2165
2166 var allowedFn fn_check;
2167 fn_check.frame_nr := frame_nr_51;
2168
2169 if (bs_ag_blks_res < 0 or bs_ag_blks_res > 7) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002170 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "bs_ag_blks_res out of valid range (0..7)");
Philipp Maier82cb0b12018-08-31 14:41:39 +02002171 return;
2172 }
2173
2174 if (bs_ag_blks_res == 0 and match(fn_check, bs_ag_blks_res_0)) {
2175 return;
2176 }
2177 if (bs_ag_blks_res == 1 and match(fn_check, bs_ag_blks_res_1)) {
2178 return;
2179 }
2180 if (bs_ag_blks_res == 2 and match(fn_check, bs_ag_blks_res_2)) {
2181 return;
2182 }
2183 if (bs_ag_blks_res == 3 and match(fn_check, bs_ag_blks_res_3)) {
2184 return;
2185 }
2186 if (bs_ag_blks_res == 4 and match(fn_check, bs_ag_blks_res_4)) {
2187 return;
2188 }
2189 if (bs_ag_blks_res == 5 and match(fn_check, bs_ag_blks_res_5)) {
2190 return;
2191 }
2192 if (bs_ag_blks_res == 6 and match(fn_check, bs_ag_blks_res_6)) {
2193 return;
2194 }
2195 if (bs_ag_blks_res == 7 and match(fn_check, bs_ag_blks_res_7)) {
2196 return;
2197 }
2198
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002199 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "received paging on AGCH");
Philipp Maier82cb0b12018-08-31 14:41:39 +02002200 return;
2201}
2202
2203altstep as_l1_count_paging(inout integer num_paging_rcv_msgs, inout integer num_paging_rcv_ids, PagingTestCfg cfg)
Harald Welte68e495b2018-02-25 00:05:57 +01002204runs on test_CT {
2205 var L1ctlDlMessage dl;
Harald Weltef8df4cb2018-03-10 15:15:08 +01002206 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_DummyUI)) {
Harald Welte68e495b2018-02-25 00:05:57 +01002207 repeat;
2208 }
Harald Weltef8df4cb2018-03-10 15:15:08 +01002209 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
Harald Welte68e495b2018-02-25 00:05:57 +01002210 var octetstring without_plen :=
2211 substr(dl.payload.data_ind.payload, 1, lengthof(dl.payload.data_ind.payload)-1);
2212 var PDU_ML3_NW_MS rr := dec_PDU_ML3_NW_MS(without_plen);
Philipp Maier82cb0b12018-08-31 14:41:39 +02002213
2214 check_pch_fn(dl.dl_info.frame_nr, cfg.bs_ag_blks_res);
2215
Harald Welte68e495b2018-02-25 00:05:57 +01002216 if (match(rr, tr_PAGING_REQ1)) {
2217 num_paging_rcv_msgs := num_paging_rcv_msgs + 1;
2218 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2219 if (isvalue(rr.msgs.rrm.pagingReq_Type1.mobileIdentity2)) {
2220 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2221 }
2222 } else if (match(rr, tr_PAGING_REQ2)) {
2223 num_paging_rcv_msgs := num_paging_rcv_msgs + 1;
2224 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type2.mobileIdentity1)) {
2225 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2226 }
2227 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type2.mobileIdentity2)) {
2228 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2229 }
2230 if (isvalue(rr.msgs.rrm.pagingReq_Type2.mobileIdentity3)) {
2231 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2232 }
2233 } else if (match(rr, tr_PAGING_REQ3)) {
2234 num_paging_rcv_msgs := num_paging_rcv_msgs + 1;
2235 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity1)) {
2236 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2237 }
2238 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity2)) {
2239 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2240 }
2241 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity3)) {
2242 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2243 }
2244 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity4)) {
2245 num_paging_rcv_ids := num_paging_rcv_ids + 1;
2246 }
2247 }
2248 repeat;
2249 }
2250}
2251
2252type record PagingTestCfg {
2253 boolean combined_ccch,
2254 integer bs_ag_blks_res,
2255 float load_factor,
2256 boolean exp_load_ind,
2257 boolean exp_overload,
2258 boolean use_tmsi
2259}
2260
2261type record PagingTestState {
2262 integer num_paging_sent,
2263 integer num_paging_rcv_msgs,
2264 integer num_paging_rcv_ids,
2265 integer num_overload
2266}
2267
2268/* receive + ignore RSL RF RES IND */
2269altstep as_rsl_res_ind() runs on test_CT {
2270 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_RF_RES_IND)) {
2271 repeat;
2272 }
2273}
2274
2275/* Helper function for paging related testing */
2276private function f_TC_paging(PagingTestCfg cfg) runs on test_CT return PagingTestState {
Harald Welte10474062019-05-30 16:48:17 +02002277 f_init();
Harald Welte68e495b2018-02-25 00:05:57 +01002278 f_init_l1ctl();
2279 f_l1_tune(L1CTL);
2280
2281 var PagingTestState st := {
2282 num_paging_sent := 0,
2283 num_paging_rcv_msgs := 0,
2284 num_paging_rcv_ids := 0,
2285 num_overload := 0
2286 };
2287
2288 var float max_pch_blocks_per_sec := f_pch_block_rate_est(cfg.combined_ccch, cfg.bs_ag_blks_res);
2289 var float max_pch_imsi_per_sec;
2290 if (cfg.use_tmsi) {
2291 max_pch_imsi_per_sec := max_pch_blocks_per_sec * 4.0; /* Type 3 */
2292 } else {
2293 max_pch_imsi_per_sec := max_pch_blocks_per_sec * 2.0; /* Type 1 */
2294 }
2295 var float pch_blocks_per_sec := max_pch_imsi_per_sec * cfg.load_factor;
2296 var float interval := 1.0 / pch_blocks_per_sec;
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02002297 var float time_total := 20.0;
2298 var integer pkt_total := float2int(time_total * pch_blocks_per_sec);
2299 log("pch_blocks_total=", pkt_total," pch_blocks_per_sec=", pch_blocks_per_sec, " interval=", interval);
Harald Welte68e495b2018-02-25 00:05:57 +01002300
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02002301 timer T_total := 300.0; /* big value (far bigger than time_total), used to count elapsed time */
2302 T_total.start;
Harald Welte68e495b2018-02-25 00:05:57 +01002303
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02002304 timer T_itv := 0.0;
2305 T_itv.start;
2306 while (st.num_paging_sent < pkt_total) {
Harald Welte68e495b2018-02-25 00:05:57 +01002307 alt {
2308 /* check for presence of CCCH LOAD IND (paging load) */
2309 [cfg.exp_overload] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
2310 st.num_overload := st.num_overload + 1;
2311 repeat;
2312 }
2313 [not cfg.exp_overload] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002314 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PCH Overload");
Harald Welte68e495b2018-02-25 00:05:57 +01002315 }
2316 [cfg.exp_load_ind] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND)) {
2317 log("Rx LOAD_IND");
2318 /* FIXME: analyze/verify interval + contents */
2319 repeat;
2320 }
2321 /* check if paging requests arrive on Um side */
Philipp Maier82cb0b12018-08-31 14:41:39 +02002322 [] as_l1_count_paging(st.num_paging_rcv_msgs, st.num_paging_rcv_ids, cfg);
Harald Welte68e495b2018-02-25 00:05:57 +01002323 [] L1CTL.receive { repeat; }
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02002324 [] T_itv.timeout {
2325 /* Send paging cmds based on elapsed time */
2326 var integer new_sent := f_min(pkt_total, float2int(T_total.read * pch_blocks_per_sec) + 1);
2327 while (st.num_paging_sent < new_sent) {
2328 /* build mobile Identity */
2329 var MobileL3_CommonIE_Types.MobileIdentityLV mi;
2330 if (cfg.use_tmsi) {
2331 mi := valueof(ts_MI_TMSI_LV(f_rnd_octstring(4)));
2332 } else {
2333 mi := valueof(ts_MI_IMSI_LV(f_gen_imsi(st.num_paging_sent)));
2334 }
2335 var octetstring mi_enc_lv := enc_MobileIdentityLV(mi);
2336 var octetstring mi_enc := substr(mi_enc_lv, 1, lengthof(mi_enc_lv)-1);
2337
2338 /* Send RSL PAGING COMMAND */
2339 RSL_CCHAN.send(ts_RSL_UD(ts_RSL_PAGING_CMD(mi_enc, st.num_paging_sent mod 4)));
2340
2341 st.num_paging_sent := st.num_paging_sent + 1;
2342 }
2343 if (st.num_paging_sent < pkt_total) {
2344 /* Wait for interval to next PAGING COMMAND */
2345 var float time_now := T_total.read;
2346 var float next_sched := int2float(st.num_paging_sent)*interval;
2347 if (next_sched > time_now) {
2348 T_itv.start(next_sched - time_now);
2349 } else {
2350 T_itv.start(0.0);
2351 }
2352 } else {
2353 /* We are done, no need to keep counting */
2354 T_total.stop;
2355 }
2356 }
2357 [] T_total.timeout { }
Harald Welte68e495b2018-02-25 00:05:57 +01002358 [] as_rsl_res_ind();
2359 }
2360 }
2361
2362 /* wait for max 18s for paging queue to drain (size: 200, ~ 13 per s -> 15s) */
2363 timer T_wait := 18.0;
2364 T_wait.start;
2365 alt {
Philipp Maier82cb0b12018-08-31 14:41:39 +02002366 [] as_l1_count_paging(st.num_paging_rcv_msgs, st.num_paging_rcv_ids, cfg);
Harald Welte68e495b2018-02-25 00:05:57 +01002367 [] L1CTL.receive { repeat; }
2368 /* 65535 == empty paging queue, we can terminate*/
2369 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND(65535))) { }
2370 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_PAGING_LOAD_IND)) { repeat; }
2371 [] T_wait.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002372 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Waiting for empty paging queue");
Harald Welte68e495b2018-02-25 00:05:57 +01002373 }
2374 [] as_rsl_res_ind();
2375 }
2376
2377 log("num_paging_sent=", st.num_paging_sent, " rcvd_msgs=", st.num_paging_rcv_msgs,
2378 " rcvd_ids=", st.num_paging_rcv_ids);
2379 return st;
2380}
2381
2382/* Create ~ 80% paging load (IMSI only) sustained for about 20s, verifying that
2383 * - the number of Mobile Identities on Um PCH match the number of pages on RSL
2384 * - that CCCH LOAD IND (PCH) are being generated
2385 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
2386testcase TC_paging_imsi_80percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02002387 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01002388 var PagingTestCfg cfg := {
2389 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02002390 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01002391 load_factor := 0.8,
2392 exp_load_ind := true,
2393 exp_overload := false,
2394 use_tmsi := false
2395 };
2396 var PagingTestState st := f_TC_paging(cfg);
2397 if (st.num_paging_sent != st.num_paging_rcv_ids) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002398 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Expected ", st.num_paging_sent, " pagings but have ",
2399 st.num_paging_rcv_ids));
Harald Welte68e495b2018-02-25 00:05:57 +01002400 } else {
2401 setverdict(pass);
2402 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002403 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01002404}
2405
2406/* Create ~ 80% paging load (TMSI only) sustained for about 20s, verifying that
2407 * - the number of Mobile Identities on Um PCH match the number of pages on RSL
2408 * - that CCCH LOAD IND (PCH) are being generated
2409 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
2410testcase TC_paging_tmsi_80percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02002411 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01002412 var PagingTestCfg cfg := {
2413 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02002414 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01002415 load_factor := 0.8,
2416 exp_load_ind := true,
2417 exp_overload := false,
2418 use_tmsi := true
2419 };
2420 var PagingTestState st := f_TC_paging(cfg);
2421 if (st.num_paging_sent != st.num_paging_rcv_ids) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002422 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Expected ", st.num_paging_sent, " pagings but have ",
2423 st.num_paging_rcv_ids));
Harald Welte68e495b2018-02-25 00:05:57 +01002424 } else {
2425 setverdict(pass);
2426 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002427 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01002428}
2429
2430/* Create ~ 200% paging load (IMSI only) sustained for about 20s, verifying that
2431 * - the number of Mobile Identities on Um PCH are ~ 82% of the number of pages on RSL
2432 * - that CCCH LOAD IND (PCH) are being generated and reach 0 at some point
2433 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
2434testcase TC_paging_imsi_200percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02002435 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01002436 var PagingTestCfg cfg := {
2437 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02002438 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01002439 load_factor := 2.0,
2440 exp_load_ind := true,
2441 exp_overload := true,
2442 use_tmsi := false
2443 };
2444 var PagingTestState st := f_TC_paging(cfg);
2445 /* We expect about 80-85% to pass, given that we can fill the paging buffer of 200
2446 * slots and will fully drain that buffer before returning */
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02002447 var template integer tpl := (st.num_paging_sent*78/100 .. st.num_paging_sent *85/100);
Harald Welte68e495b2018-02-25 00:05:57 +01002448 if (not match(st.num_paging_rcv_ids, tpl)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002449 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Expected ", tpl, " pagings but have ", st.num_paging_rcv_ids));
Harald Welte68e495b2018-02-25 00:05:57 +01002450 } else {
2451 setverdict(pass);
2452 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002453 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01002454}
2455
2456/* Create ~ 200% paging load (TMSI only) sustained for about 20s, verifying that
2457 * - the number of Mobile Identities on Um PCH are ~ 82% of the number of pages on RSL
2458 * - that CCCH LOAD IND (PCH) are being generated and reach 0 at some point
2459 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
2460testcase TC_paging_tmsi_200percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02002461 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01002462 var PagingTestCfg cfg := {
2463 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02002464 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01002465 load_factor := 2.0,
2466 exp_load_ind := true,
2467 exp_overload := true,
2468 use_tmsi := true
2469 };
2470 var PagingTestState st := f_TC_paging(cfg);
2471 /* We expect about 70% to pass, given that we can fill the paging buffer of 200
2472 * slots and will fully drain that buffer before returning */
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02002473 var template integer tpl := (st.num_paging_sent*64/100 .. st.num_paging_sent *72/100);
Harald Welte68e495b2018-02-25 00:05:57 +01002474 if (not match(st.num_paging_rcv_ids, tpl)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002475 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Expected ", tpl, " pagings but have ", st.num_paging_rcv_ids));
Harald Welte68e495b2018-02-25 00:05:57 +01002476 } else {
2477 setverdict(pass);
2478 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002479 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01002480}
2481
2482
Harald Welte93640c62018-02-25 16:59:33 +01002483/***********************************************************************
2484 * Immediate Assignment / AGCH
2485 ***********************************************************************/
Harald Weltee8d750e2018-06-10 21:41:35 +02002486const MobileAllocation c_MA_null := {
2487 len := 0,
2488 ma := ''B
2489}
Harald Welte93640c62018-02-25 16:59:33 +01002490
Harald Weltee8d750e2018-06-10 21:41:35 +02002491template (value) ChannelDescription ts_ChanDesc(template (value) RslChannelNr chan_nr, uint3_t tsc := 7,
2492 uint12_t arfcn := 871) := {
2493 chan_nr := chan_nr,
2494 tsc := tsc,
2495 h := false,
2496 arfcn := arfcn,
2497 maio_hsn := omit
2498}
2499
2500private function f_fmt_ia_stats(integer num_tx, integer num_rx, integer num_del) return charstring {
2501 return int2str(num_tx) & " sent, "
2502 & int2str(num_rx) & " received, "
2503 & int2str(num_del) & " deleted";
2504}
2505
2506private function f_TC_imm_ass(integer num_total, float sleep_s, float exp_pass) runs on test_CT {
2507 var L1ctlDlMessage l1_dl;
2508 timer T := 10.0;
2509 var integer num_tx := 0;
2510 var integer num_rx := 0;
2511 var integer num_del := 0;
2512 var charstring res_str;
2513 var float rx_ratio;
2514
Harald Welte10474062019-05-30 16:48:17 +02002515 f_init();
Harald Weltee8d750e2018-06-10 21:41:35 +02002516 f_init_l1ctl();
2517 f_l1_tune(L1CTL);
2518
2519 for (var integer i := 0; i < num_total; i := i+1) {
2520 var ChannelDescription ch_desc := valueof(ts_ChanDesc(valueof(t_RslChanNr_SDCCH4(0, 0))));
2521 var GsmRrMessage ia := valueof(ts_IMM_ASS(42, i, 5, ch_desc, c_MA_null));
2522 var octetstring ia_enc := enc_GsmRrMessage(ia);
Harald Welte68e495b2018-02-25 00:05:57 +01002523 RSL_CCHAN.send(ts_RSL_UD(ts_RSL_IMM_ASSIGN(ia_enc, 0)));
Harald Weltee8d750e2018-06-10 21:41:35 +02002524 num_tx := num_tx+1;
2525 f_sleep(sleep_s);
Harald Welte68e495b2018-02-25 00:05:57 +01002526 }
2527 /* FIXME: check if imm.ass arrive on Um side */
Harald Weltee8d750e2018-06-10 21:41:35 +02002528 T.start;
2529 alt {
2530 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_DELETE_IND(?, 0))) {
2531 num_del := num_del+1;
2532 repeat;
2533 }
2534 [] RSL_CCHAN.receive {
2535 repeat;
2536 }
2537 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?)) -> value l1_dl {
2538 /* somehow dec_SystemInformation will try to decode even non-RR as SI */
2539 var GsmRrMessage rr := dec_GsmRrMessage(l1_dl.payload.data_ind.payload);
2540 if (not match(rr, tr_IMM_ASS(42, ?, 5, ?, ?))) {
2541 /* FIXME: Why are we seeing paging requests on PCH/AGCH? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002542 //Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected IMM-ASS values on AGCH: ", rr));
Harald Weltee8d750e2018-06-10 21:41:35 +02002543 } else {
2544 num_rx := num_rx+1;
2545 }
2546 repeat;
2547 }
2548 [] L1CTL.receive { repeat; }
2549 [] T.timeout { }
2550 }
2551 res_str := f_fmt_ia_stats(num_tx, num_rx, num_del);
2552 log("AGCH test: " & res_str);
2553 if (num_rx + num_del != num_tx) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002554 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "RX + DEL != TX ?!?: " & res_str);
Harald Weltee8d750e2018-06-10 21:41:35 +02002555 }
2556 rx_ratio := int2float(num_rx) / int2float(num_tx);
2557 if (rx_ratio < exp_pass*0.8 or rx_ratio > exp_pass*1.2) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002558 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "RX ratio ("&float2str(rx_ratio)&") far from expected ("&float2str(exp_pass)&") " & res_str);
Harald Weltee8d750e2018-06-10 21:41:35 +02002559 } else {
2560 setverdict(pass);
2561 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002562 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01002563}
2564
Harald Weltee8d750e2018-06-10 21:41:35 +02002565/* send a long burst of 1000 IMM.ASS with 20ms spacing (50 per s); expect 75% of them to be deleted */
2566testcase TC_imm_ass_1000_20ms() runs on test_CT {
2567 f_TC_imm_ass(1000, 0.02, 0.25);
2568}
2569
2570/* send a short burst of 200 IMM.ASS without any spacing; expect 95% of them to be deleted */
2571testcase TC_imm_ass_200_0ms() runs on test_CT {
2572 f_TC_imm_ass(200, 0.0, 0.05);
2573}
2574
2575/* send 150 IMM.ASS at rate of 13/s; expect none of them to be deleted */
2576testcase TC_imm_ass_200_76ms() runs on test_CT {
2577 f_TC_imm_ass(150, 0.076, 1.00);
2578}
2579
2580
2581
Harald Welte48494ca2018-02-25 16:59:50 +01002582/***********************************************************************
2583 * BCCH
2584 ***********************************************************************/
2585
2586/* tuple of Frame Number + decoded SI */
2587type record SystemInformationFn {
2588 GsmFrameNumber frame_number,
2589 SystemInformation si
2590}
2591
2592/* an arbitrary-length vector of decoded SI + gsmtap header */
2593type record of SystemInformationFn SystemInformationVector;
2594
2595/* an array of SI-vectors indexed by TC value */
2596type SystemInformationVector SystemInformationVectorPerTc[8];
2597
2598/* determine if a given SI vector contains given SI type at least once */
2599function f_si_vecslot_contains(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean {
2600 for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
2601 var integer fn_mod51 := arr[i].frame_number mod 51;
2602 if (not bcch_ext and fn_mod51 == 2 or
2603 bcch_ext and fn_mod51 == 6) {
2604 if (arr[i].si.header.message_type == key) {
2605 return true;
2606 }
2607 }
2608 }
2609 return false;
2610}
2611
2612/* ensure a given TC slot of the SI vector contains given SI type at least once at TC */
2613function f_ensure_si_vec_contains(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) {
2614 if (not f_si_vecslot_contains(arr[tc], key, ext_bcch)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002615 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No ", key, " in TC=", tc, "!"));
Harald Welte48494ca2018-02-25 16:59:50 +01002616 }
2617}
2618
2619/* check if a given SI vector contains given SI type at least once on any TC */
2620function f_si_vec_contains(SystemInformationVectorPerTc arr, RrMessageType key) return boolean {
2621 for (var integer tc:= 0; tc < sizeof(arr); tc := tc + 1) {
2622 if (f_si_vecslot_contains(arr[tc], key) or
2623 f_si_vecslot_contains(arr[tc], key, true)) {
2624 return true;
2625 }
2626 }
2627 return false;
2628}
2629
2630/* determine if a given SI vector contains given SI type at least N of M times */
2631function f_si_vecslot_contains_n_of_m(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false, integer n := 1, integer m := 4) return boolean {
2632 var integer count := 0;
2633 if (sizeof(arr) < m) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002634 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Error: Insufficient SI in array");
Harald Welte48494ca2018-02-25 16:59:50 +01002635 }
2636 for (var integer i:= 0; i < m; i := i + 1) {
2637 var integer fn_mod51 := arr[i].frame_number mod 51;
2638 if (not bcch_ext and fn_mod51 == 2 or
2639 bcch_ext and fn_mod51 == 6) {
2640 if (arr[i].si.header.message_type == key) {
2641 count := count + 1;
2642 }
2643 }
2644 }
2645 if (count >= n) {
2646 return true;
2647 } else {
2648 return false;
2649 }
2650}
2651
2652/* ensure a given TC slot of the SI vector contains given SI type at least N out of M times at TC */
2653function f_ensure_si_vec_contains_n_of_m(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false, integer n, integer m) {
2654 if (not f_si_vecslot_contains_n_of_m(arr[tc], key, ext_bcch, n, m)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002655 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Not ", n, "/", m, " of ", key, " in TC=", tc, "!"));
Harald Welte48494ca2018-02-25 16:59:50 +01002656 }
2657}
2658
2659/* determine if a given SI vector contains given SI type at least once */
2660function f_si_vecslot_contains_only(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean {
2661 for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
2662 var integer fn_mod51 := arr[i].frame_number mod 51;
2663 if (not bcch_ext and fn_mod51 == 2 or
2664 bcch_ext and fn_mod51 == 6) {
2665 if (arr[i].si.header.message_type != key) {
2666 return false;
2667 }
2668 }
2669 }
2670 return true;
2671}
2672
2673/* ensure a given TC slot of the SI vector contains only given SI type */
2674function f_ensure_si_vec_contains_only(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) {
2675 if (not f_si_vecslot_contains_only(arr[tc], key, ext_bcch)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002676 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Not all ", key, " in TC=", tc, "!"));
Harald Welte48494ca2018-02-25 16:59:50 +01002677 }
2678}
2679
2680/* SI configuration of cell, against which we validate actual SI messages */
2681type set SystemInformationConfig {
2682 boolean bcch_extended,
2683 boolean si1_present,
2684 boolean si2bis_present,
2685 boolean si2ter_present,
2686 boolean si2quater_present,
2687 boolean si7_present,
2688 boolean si8_present,
2689 boolean si9_present,
2690 boolean si13_present,
2691 boolean si13alt_present,
2692 boolean si15_present,
2693 boolean si16_present,
2694 boolean si17_present,
2695 boolean si2n_present,
2696 boolean si21_present,
2697 boolean si22_present
2698}
2699
2700/* validate the SI scheduling according to TS 45.002 version 14.1.0 Release 14, Section 6.3.1.3 */
2701function f_validate_si_scheduling(SystemInformationConfig cfg, SystemInformationVectorPerTc si_per_tc) {
2702 var integer i;
2703 for (i := 0; i < sizeof(si_per_tc); i := i + 1) {
2704 if (sizeof(si_per_tc[i]) == 0) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002705 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No SI messages for TC=", i));
Harald Welte48494ca2018-02-25 16:59:50 +01002706 }
2707 }
2708 if (cfg.si1_present) {
2709 /* ii) System Information Type 1 needs to be sent if frequency hopping is in use or
2710 * when the NCH is present in a cell. If the MS finds another message on BCCH Norm
2711 * when TC = 0, it can assume that System Information Type 1 is not in use. */
2712 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_1);
2713 /* make sure *ALL* contain SI1 */
2714 f_ensure_si_vec_contains_only(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_1);
2715 }
2716 f_ensure_si_vec_contains(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_2);
2717 /* iii) A SI 2 message will be sent at least every time TC = 1 */
2718 f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_3);
2719 f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_3);
2720 f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_4);
2721 f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_4);
2722
2723 /* iii) System information type 2 bis or 2 ter messages are sent if needed, as determined by the
2724 * system operator. If only one of them is needed, it is sent when TC = 5. If both are
2725 * needed, 2bis is sent when TC = 5 and 2ter is sent at least once within any of 4
2726 * consecutive occurrences of TC = 4. */
2727 if (cfg.si2bis_present and not cfg.si2ter_present) {
2728 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis);
2729 } else if (cfg.si2ter_present and not cfg.si2bis_present) {
2730 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2ter);
2731 } else if (cfg.si2ter_present and cfg.si2bis_present) {
2732 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis);
2733 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2ter, false, 1, 4);
2734 }
2735
2736 if (cfg.si7_present or cfg.si8_present) {
2737 /* vi) Use of System Information type 7 and 8 is not always necessary. It is necessary
2738 * if System Information type 4 does not contain all information needed for cell
2739 * selection and reselection. */
2740 if (not cfg.bcch_extended) {
2741 testcase.stop("Error: SI7/SI8 require BCCH Extd.");
2742 }
2743 if (cfg.si7_present) {
2744 f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_7, true);
2745 }
2746 if (cfg.si8_present) {
2747 f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_8, true);
2748 }
2749 }
2750
2751 if (cfg.si2quater_present) {
2752 /* iii) System information type 2 quater is sent if needed, as determined by the system
2753 * operator. If sent on BCCH Norm, it shall be sent when TC = 5 if neither of 2bis
2754 * and 2ter are used, otherwise it shall be sent at least once within any of 4
2755 * consecutive occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once
2756 * within any of 4 consecutive occurrences of TC = 5. */
2757 if (not (cfg.bcch_extended)) {
2758 if (not (cfg.si2bis_present or cfg.si2ter_present)) {
2759 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater);
2760 } else {
2761 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2quater, false, 1, 4);
2762 }
2763 } else {
2764 f_ensure_si_vec_contains_n_of_m(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater, true, 1, 4);
2765 }
2766 }
2767 if (cfg.si9_present) {
2768 /* vi) System Information type 9 is sent in those blocks with TC = 4 which are specified
2769 * in system information type 3 as defined in 3GPP TS 44.018. */
2770 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_9); // FIXME SI3
2771 }
2772 if (cfg.si13_present) {
2773 /* vii) System Information type 13 is only related to the GPRS service. System Information
2774 * Type 13 need only be sent if GPRS support is indicated in one or more of System
2775 * Information Type 3 or 4 or 7 or 8 messages. These messages also indicate if the
2776 * message is sent on the BCCH Norm or if the message is transmitted on the BCCH Ext.
2777 * In the case that the message is sent on the BCCH Norm, it is sent at least once
2778 * within any of 4 consecutive occurrences of TC=4. */
2779 if (not cfg.bcch_extended) {
2780 log("not-bccch-extended");
2781 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13, false, 1, 4);
2782 } else {
2783 log("bccch-extended");
2784 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13, true);
2785 }
2786 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13alt)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002787 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI13alt and SI13");
Harald Welte48494ca2018-02-25 16:59:50 +01002788 }
2789 }
2790 if (cfg.si16_present or cfg.si17_present) {
2791 /* viii) System Information type 16 and 17 are only related to the SoLSA service. They
2792 * should not be sent in a cell where network sharing is used (see rule xv). */
2793 if (cfg.si22_present) {
2794 testcase.stop("Error: Cannot have SI16/SI17 and SI22!");
2795 }
2796 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_22)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002797 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI16/SI17 and SI22!");
Harald Welte48494ca2018-02-25 16:59:50 +01002798 }
2799 if (not cfg.bcch_extended) {
2800 testcase.stop("Error: SI16/SI17 requires BCCH Extd!");
2801 }
2802 if (cfg.si16_present) {
2803 f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_16, true);
2804 }
2805 if (cfg.si17_present) {
2806 f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_17, true);
2807 }
2808 }
2809
2810 /* ix) System Information type 18 and 20 are sent in order to transmit non-GSM
2811 * broadcast information. The frequency with which they are sent is determined by the
2812 * system operator. System Information type 9 identifies the scheduling of System
2813 * Information type 18 and 20 messages. */
2814
2815 /* x) System Information Type 19 is sent if COMPACT neighbours exist. If System
2816 * Information Type 19 is present, then its scheduling shall be indicated in System
2817 * Information Type 9. */
2818
2819 if (cfg.si15_present) {
2820 /* xi) System Information Type 15 is broadcast if dynamic ARFCN mapping is used in the
2821 * PLMN. If sent on BCCH Norm, it is sent at least once within any of 4 consecutive
2822 * occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once within any of
2823 * 4 consecutive occurrences of TC = 1. */
2824 if (not cfg.bcch_extended) {
2825 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_15, false, 1, 4);
2826 } else {
2827 f_ensure_si_vec_contains_n_of_m(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_15, true, 1, 4);
2828 }
2829 }
2830 if (cfg.si13alt_present) {
2831 /* xii) System Information type 13 alt is only related to the GERAN Iu mode. System
2832 * Information Type 13 alt need only be sent if GERAN Iu mode support is indicated in
2833 * one or more of System Information Type 3 or 4 or 7 or 8 messages and SI 13 is not
2834 * broadcast. These messages also indicate if the message is sent on the BCCH Norm or
2835 * if the message is transmitted on the BCCH Ext. In the case that the message is sent
2836 * on the BCCH Norm, it is sent at least once within any of 4 consecutive occurrences
2837 * of TC = 4. */
2838 if (cfg.si13_present) {
2839 testcase.stop("Error: Cannot have SI13alt and SI13");
2840 }
2841 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002842 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI13alt and SI13");
Harald Welte48494ca2018-02-25 16:59:50 +01002843 }
2844 if (not cfg.bcch_extended) {
2845 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13alt, false, 1, 4);
2846 } else {
2847 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13alt, true);
2848 }
2849 }
2850 if (cfg.si2n_present) {
2851 /* xiii) System Information Type 2n is optionally sent on BCCH Norm or BCCH Ext if needed,
2852 * as determined by the system operator. In the case that the message is sent on the
2853 * BCCH Norm, it is sent at least once within any of 4 consecutive occurrences of TC =
2854 * 4. If the message is sent on BCCH Ext, it is sent at least once within any of 2
2855 * consecutive occurrences of TC = 4. */
2856 if (not cfg.bcch_extended) {
2857 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n, false, 1, 4);
2858 } else {
2859 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n, true, 2, 4);
2860 }
2861 }
2862 if (cfg.si21_present) {
2863 /* xiv) System Information Type 21 is optionally sent on BCCH Norm or BCCH Ext, as
2864 * determined by the system operator. If Extended Access Barring is in use in the cell
2865 * then this message is sent at least once within any of 4 consecutive occurrences of
2866 * TC = 4 regardless if it is sent on BCCH Norm or BCCH Ext. If BCCH Ext is used in a
2867 * cell then this message shall only be sent on BCCH Ext. */
2868 if (not cfg.bcch_extended) {
2869 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21, false, 1, 4);
2870 } else {
2871 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21, true, 1, 4);
2872 if (f_si_vecslot_contains(si_per_tc[4], SYSTEM_INFORMATION_TYPE_21)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002873 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI21 on BCCH Norm if BCCH Extd enabled!");
Harald Welte48494ca2018-02-25 16:59:50 +01002874 }
2875 }
2876 }
2877 if (cfg.si22_present) {
2878 /* xv) System Information Type 22 is sent if network sharing is in use in the cell. It
2879 * should not be sent in a cell where SoLSA is used (see rule viii). System
2880 * Information Type 22 instances shall be sent on BCCH Ext within any occurrence of TC
2881 * =2 and TC=6. */
2882 if (cfg.si16_present or cfg.si17_present) {
2883 testcase.stop("Error: Cannot have SI16/SI17 and SI22!");
2884 }
2885 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_16) or
2886 f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_17)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002887 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI16/SI17 and SI22!");
Harald Welte48494ca2018-02-25 16:59:50 +01002888 }
2889 if (not cfg.bcch_extended) {
2890 testcase.stop("Error: SI22 requires BCCH Extd!");
2891 } else {
2892 f_ensure_si_vec_contains_only(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_22, true);
2893 f_ensure_si_vec_contains_only(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_22, true);
2894 }
2895 }
2896}
2897
2898/* sample Systme Information for specified duration via L1CTL */
2899function f_l1_sample_si(L1CTL_PT pt, float duration := 8.0) return SystemInformationVectorPerTc {
2900 timer T := duration;
2901 var SystemInformationVectorPerTc si_per_tc;
2902 var L1ctlDlMessage l1_dl;
2903
2904 /* initialize all per-TC vectors empty */
2905 for (var integer i:= 0; i < sizeof(si_per_tc); i := i+1) {
2906 si_per_tc[i] := {};
2907 }
2908
2909 /* flush all previous L1 queued msgs */
2910 pt.clear;
2911
2912 T.start;
2913 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +01002914 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
Harald Welte48494ca2018-02-25 16:59:50 +01002915 /* somehow dec_SystemInformation will try to decode even non-RR as SI */
2916 if (not (l1_dl.payload.data_ind.payload[1] == '06'O)) {
2917 log("Ignoring non-RR SI ", l1_dl);
2918 repeat;
2919 }
2920 var SystemInformationFn sig := {
2921 frame_number := l1_dl.dl_info.frame_nr,
2922 si := dec_SystemInformation(l1_dl.payload.data_ind.payload)
2923 }
2924 var integer tc := f_gsm_compute_tc(sig.frame_number);
2925 log("SI received at TC=", tc, ": ", sig.si);
2926 /* append to the per-TC bucket */
2927 si_per_tc[tc] := si_per_tc[tc] & { sig };
2928 repeat;
2929 }
2930 [] pt.receive { repeat; }
2931 [] T.timeout { }
2932 }
2933
2934 for (var integer i:= 0; i < sizeof(si_per_tc); i := i+1) {
2935 log(testcasename(), ": TC=", i, " has #of SI=", sizeof(si_per_tc[i]));
2936 }
2937 log("si_per_tc=", si_per_tc);
2938 return si_per_tc;
2939}
2940
2941/* helper function: Set given SI via RSL + validate scheduling.
2942 * CALLER MUST MAKE SURE TO CHANGE GLOBAL si_cfg! */
2943function f_TC_si_sched() runs on test_CT {
2944 var SystemInformationVectorPerTc si_per_tc;
2945 f_init_l1ctl();
2946 f_l1_tune(L1CTL);
2947
2948 /* Sample + Validate Scheduling */
2949 si_per_tc := f_l1_sample_si(L1CTL);
2950 f_validate_si_scheduling(si_cfg, si_per_tc);
2951
2952 setverdict(pass);
2953}
2954
2955testcase TC_si_sched_default() runs on test_CT {
2956 f_init();
Harald Welte0cae4552018-03-09 22:20:26 +01002957 /* 2+3+4 are mandatory and set in f_init() */
2958 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002959 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte0cae4552018-03-09 22:20:26 +01002960}
2961
2962testcase TC_si_sched_1() runs on test_CT {
2963 f_init();
2964 si_cfg.si1_present := true;
2965 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_1, '5506198fb38000000000000000000000000000e504002b'O);
Harald Welte48494ca2018-02-25 16:59:50 +01002966 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002967 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01002968}
2969
2970testcase TC_si_sched_2bis() runs on test_CT {
2971 f_init();
2972 si_cfg.si2bis_present := true;
2973 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2bis, '550602bfe809b3ff00000000000000000000007900002b'O);
2974 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002975 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01002976}
2977
2978testcase TC_si_sched_2ter() runs on test_CT {
2979 f_init();
2980 si_cfg.si2ter_present := true;
2981 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2ter, '010603bf66b0aa0a00000002000000000000002b2b2b2b'O);
2982 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002983 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01002984}
2985
2986testcase TC_si_sched_2ter_2bis() runs on test_CT {
2987 f_init();
2988 si_cfg.si2bis_present := true;
2989 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2bis, '550602bfe809b3ff00000000000000000000007900002b'O);
2990 si_cfg.si2ter_present := true;
2991 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2ter, '010603bf66b0aa0a00000002000000000000002b2b2b2b'O);
2992 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002993 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01002994}
2995
2996testcase TC_si_sched_2quater() runs on test_CT {
2997 f_init();
2998 si_cfg.si2quater_present := true;
2999 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2quater, '050607a8a0364aa698d72ff424feee0506d5e7fff02043'O);
3000 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003001 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003002}
3003
3004testcase TC_si_sched_13() runs on test_CT {
3005 f_init();
3006 si_cfg.si13_present := true;
Harald Welte5618c2a2018-04-15 16:24:46 +02003007 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_13, '0106009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b'O);
Harald Welte48494ca2018-02-25 16:59:50 +01003008 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003009 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003010}
3011
3012testcase TC_si_sched_13_2bis_2ter_2quater() runs on test_CT {
3013 f_init();
3014 si_cfg.si2bis_present := true;
3015 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2bis, '550602bfe809b3ff00000000000000000000007900002b'O);
3016 si_cfg.si2ter_present := true;
3017 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2ter, '010603bf66b0aa0a00000002000000000000002b2b2b2b'O);
3018 si_cfg.si2quater_present := true;
3019 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2quater, '050607a8a0364aa698d72ff424feee0506d5e7fff02043'O);
3020 si_cfg.si13_present := true;
Harald Welte5618c2a2018-04-15 16:24:46 +02003021 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_13, '0106009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b'O);
Harald Welte48494ca2018-02-25 16:59:50 +01003022 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003023 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003024}
3025
3026
Harald Welte68e495b2018-02-25 00:05:57 +01003027testcase TC_bcch_info() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003028 f_init();
Harald Welte68e495b2018-02-25 00:05:57 +01003029 /* FIXME: enable / disable individual BCCH info */
3030 //ts_RSL_BCCH_INFO(si_type, info);
3031 /* expect no ERROR REPORT after either of them *
3032 /* negative test: ensure ERROR REPORT on unsupported types */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003033 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01003034}
3035
Harald Welte93640c62018-02-25 16:59:33 +01003036/***********************************************************************
3037 * Low-Level Protocol Errors / ERROR REPORT
3038 ***********************************************************************/
3039
Harald Welte01d982c2018-02-25 01:31:40 +01003040private function f_exp_err_rep(template RSL_Cause cause) runs on test_CT {
3041 timer T := 5.0;
3042 T.start;
3043 alt {
3044 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_ERROR_REPORT(cause))) {
3045 setverdict(pass);
3046 }
3047 [] RSL_CCHAN.receive(tr_RSL_UD(tr_RSL_ERROR_REPORT(?))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003048 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Wrong cause in RSL ERR REP");
Harald Welte01d982c2018-02-25 01:31:40 +01003049 }
3050 [] RSL_CCHAN.receive {
3051 repeat;
3052 }
3053 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003054 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RSL ERR REP");
Harald Welte01d982c2018-02-25 01:31:40 +01003055 }
3056 }
3057}
3058
3059/* Provoke a protocol error (message too short) and match on ERROR REPORT */
3060testcase TC_rsl_protocol_error() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003061 f_init();
Harald Welte01d982c2018-02-25 01:31:40 +01003062 var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3063 rsl.ies := omit;
3064 RSL_CCHAN.send(ts_RSL_UD(rsl));
3065
3066 f_exp_err_rep(RSL_ERR_PROTO);
3067}
3068
3069/* Provoke a mandatory IE error and match on ERROR REPORT */
3070testcase TC_rsl_mand_ie_error() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003071 f_init();
Harald Welte01d982c2018-02-25 01:31:40 +01003072
3073 var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3074 rsl.ies := { rsl.ies[0] };
3075 RSL_CCHAN.send(ts_RSL_UD(rsl));
3076
3077 f_exp_err_rep(RSL_ERR_MAND_IE_ERROR);
3078}
3079
3080/* Provoke an IE content error and match on ERROR REPORT */
3081testcase TC_rsl_ie_content_error() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003082 f_init();
Harald Welte01d982c2018-02-25 01:31:40 +01003083 var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3084 rsl.ies[1].body.sysinfo_type := RSL_SYSTEM_INFO_5;
3085 RSL_CCHAN.send(ts_RSL_UD(rsl));
3086
3087 f_exp_err_rep(RSL_ERR_IE_CONTENT);
3088}
3089
Harald Welteee25aae2019-05-19 14:32:37 +02003090/* attempt to activate channel with wrong RSL Message Discriminator IE */
3091function f_TC_chan_act_wrong_mdisc(charstring id) runs on ConnHdlr {
3092 var template RSL_Message rsl := ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode);
3093 rsl.msg_disc := ts_RSL_MsgDisc(RSL_MDISC_RESERVED, false);
3094 RSL.send(rsl);
3095 f_rslem_unregister(0, g_chan_nr);
3096}
3097testcase TC_err_rep_wrong_mdisc() runs on test_CT {
3098 var ConnHdlr vc_conn;
3099 var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_SDCCH4(0,0), ts_RSL_ChanMode_SIGN));
3100
Harald Welte10474062019-05-30 16:48:17 +02003101 f_init();
Harald Welteee25aae2019-05-19 14:32:37 +02003102
3103 vc_conn := f_start_handler(refers(f_TC_chan_act_wrong_mdisc), pars);
3104 vc_conn.done;
3105 f_exp_err_rep(RSL_ERR_MSG_DISCR);
3106
3107 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
3108}
3109
3110/* Send messages with wrong message type */
3111function f_TC_wrong_msg_type_dchan(charstring id) runs on ConnHdlr {
3112 var template (value) RSL_Message rsl_tx;
3113 rsl_tx := ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode);
3114 rsl_tx.msg_type := RSL_MT_NOT_CMD;
3115 RSL.send(rsl_tx);
3116 f_rslem_unregister(0, g_chan_nr);
3117}
3118function f_TC_wrong_msg_type_rll(charstring id) runs on ConnHdlr {
3119 var template (value) RSL_Message rsl_tx;
3120 /* we first have to activate the dedicated channel */
3121 f_rsl_chan_act(g_pars.chan_mode);
3122 /* ... to then send an invalid RLL message */
3123 rsl_tx := ts_RSL_UNITDATA_REQ(g_chan_nr, ts_RslLinkID_DCCH(0), '0102'O);
3124 rsl_tx.msg_type := RSL_MT_CBCH_LOAD_IND;
3125 RSL.send(rsl_tx);
3126 f_rslem_unregister(0, g_chan_nr);
3127}
3128testcase TC_err_rep_wrong_msg_type() runs on test_CT {
3129 var ConnHdlr vc_conn;
3130 var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_SDCCH4(0,0), ts_RSL_ChanMode_SIGN));
3131 var template (value) RSL_Message rsl_tx;
3132
Harald Welte10474062019-05-30 16:48:17 +02003133 f_init();
Harald Welteee25aae2019-05-19 14:32:37 +02003134
3135 /* Common Channel with wrong message type */
3136 RSL_CCHAN.clear;
3137 rsl_tx := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3138 rsl_tx.msg_type := RSL_MT_LOCATION_INFO;
3139 RSL_CCHAN.send(ts_RSL_UD(rsl_tx));
3140 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3141
3142 /* TRX Management */
3143 RSL_CCHAN.clear;
3144 rsl_tx := ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, ''O);
3145 rsl_tx.msg_type := RSL_MT_UNIT_DATA_IND;
3146 RSL_CCHAN.send(ts_RSL_UD(rsl_tx));
3147 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3148
3149 /* Dedicated Channel */
3150 RSL_CCHAN.clear;
3151 vc_conn := f_start_handler(refers(f_TC_wrong_msg_type_dchan), pars);
3152 vc_conn.done;
3153 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3154
3155 /* RLL */
3156 RSL_CCHAN.clear;
3157 vc_conn := f_start_handler(refers(f_TC_wrong_msg_type_rll), pars);
3158 vc_conn.done;
3159 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3160}
3161
3162/* Send messages in wrong sequence (RLL to an inactive lchan) */
3163function f_TC_err_rep_wrong_sequence(charstring id) runs on ConnHdlr {
3164 RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, ts_RslLinkID_DCCH(0), '0102'O));
3165 f_rslem_unregister(0, g_chan_nr);
3166}
3167testcase TC_err_rep_wrong_sequence() runs on test_CT {
3168 var ConnHdlr vc_conn;
3169 var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_SDCCH4(0,0), ts_RSL_ChanMode_SIGN));
3170
Harald Welte10474062019-05-30 16:48:17 +02003171 f_init();
Harald Welteee25aae2019-05-19 14:32:37 +02003172
3173 RSL_CCHAN.clear;
3174 vc_conn := f_start_handler(refers(f_TC_err_rep_wrong_sequence), pars);
3175 vc_conn.done;
3176 f_exp_err_rep(RSL_ERR_MSG_SEQ);
3177}
3178
Harald Welte93640c62018-02-25 16:59:33 +01003179/***********************************************************************
3180 * IPA CRCX/MDCX/DLCS media stream handling
3181 ***********************************************************************/
3182
Harald Weltea871a382018-02-25 02:03:14 +01003183/* Send IPA DLCX to inactive lchan */
3184function f_TC_ipa_dlcx_not_active(charstring id) runs on ConnHdlr {
Harald Welte1eba3742018-02-25 12:48:14 +01003185 f_rsl_transceive(ts_RSL_IPA_DLCX(g_chan_nr, 0), tr_RSL_IPA_DLCX_ACK(g_chan_nr, ?, ?),
3186 "IPA DLCX ACK");
Harald Weltea871a382018-02-25 02:03:14 +01003187}
3188testcase TC_ipa_dlcx_not_active() runs on test_CT {
3189 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02003190 f_init();
Harald Weltea871a382018-02-25 02:03:14 +01003191 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_dlcx_not_active), pars);
3192 vc_conn.done;
3193}
Harald Welte68e495b2018-02-25 00:05:57 +01003194
Harald Weltea3f1df92018-02-25 12:49:55 +01003195/* Send IPA CRCX twice to inactive lchan */
3196function f_TC_ipa_crcx_twice_not_active(charstring id) runs on ConnHdlr {
3197 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
3198 "IPA CRCX ACK");
3199 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_NACK(g_chan_nr, RSL_ERR_RES_UNAVAIL),
3200 "IPA CRCX NACK");
3201}
3202testcase TC_ipa_crcx_twice_not_active() runs on test_CT {
3203 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02003204 f_init();
Harald Weltea3f1df92018-02-25 12:49:55 +01003205 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_crcx_twice_not_active), pars);
3206 vc_conn.done;
3207}
3208
3209/* Regular sequence of CRCX/MDCX/DLCX */
3210function f_TC_ipa_crcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
3211 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
3212 "IPA CRCX ACK");
3213 var uint32_t remote_ip := f_rnd_int(c_UINT32_MAX);
3214 var uint16_t remote_port := f_rnd_int(c_UINT16_MAX);
3215 var uint7_t rtp_pt2 := f_rnd_int(127);
3216 var uint16_t fake_conn_id := 23; /* we're too lazy to read it out from the CRCX ACK above */
3217 f_rsl_transceive(ts_RSL_IPA_MDCX(g_chan_nr, fake_conn_id, remote_ip, remote_port, rtp_pt2),
3218 tr_RSL_IPA_MDCX_ACK(g_chan_nr, ?, ?, ?, rtp_pt2),
3219 "IPA MDCX ACK");
3220 f_rsl_transceive(ts_RSL_IPA_DLCX(g_chan_nr, fake_conn_id), tr_RSL_IPA_DLCX_ACK(g_chan_nr, ?, ?),
3221 "IPA DLCX ACK");
3222}
3223testcase TC_ipa_crcx_mdcx_dlcx_not_active() runs on test_CT {
3224 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02003225 f_init();
Harald Weltea3f1df92018-02-25 12:49:55 +01003226 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_crcx_mdcx_dlcx_not_active), pars);
3227 vc_conn.done;
3228}
3229
Harald Welte3ae11da2018-02-25 13:36:06 +01003230/* Sequence of CRCX, 2x MDCX, DLCX */
3231function f_TC_ipa_crcx_mdcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
3232 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
3233 "IPA CRCX ACK");
3234 var uint32_t remote_ip := f_rnd_int(c_UINT32_MAX);
3235 var uint16_t remote_port := f_rnd_int(c_UINT16_MAX);
3236 var uint7_t rtp_pt2 := f_rnd_int(127);
3237 var uint16_t fake_conn_id := 23; /* we're too lazy to read it out from the CRCX ACK above */
3238 f_rsl_transceive(ts_RSL_IPA_MDCX(g_chan_nr, fake_conn_id, remote_ip, remote_port, rtp_pt2),
3239 tr_RSL_IPA_MDCX_ACK(g_chan_nr, ?, ?, ?, rtp_pt2),
3240 "IPA MDCX ACK");
3241 /* Second MDCX */
3242 remote_ip := f_rnd_int(c_UINT32_MAX);
3243 remote_port := f_rnd_int(c_UINT16_MAX);
3244 f_rsl_transceive(ts_RSL_IPA_MDCX(g_chan_nr, fake_conn_id, remote_ip, remote_port, rtp_pt2),
3245 tr_RSL_IPA_MDCX_ACK(g_chan_nr, ?, ?, ?, rtp_pt2),
3246 "IPA MDCX ACK");
3247 f_rsl_transceive(ts_RSL_IPA_DLCX(g_chan_nr, fake_conn_id), tr_RSL_IPA_DLCX_ACK(g_chan_nr, ?, ?),
3248 "IPA DLCX ACK");
3249}
3250testcase TC_ipa_crcx_mdcx_mdcx_dlcx_not_active() runs on test_CT {
3251 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02003252 f_init();
Harald Welte3ae11da2018-02-25 13:36:06 +01003253 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_crcx_mdcx_mdcx_dlcx_not_active), pars);
3254 vc_conn.done;
3255}
3256
Harald Welte9912eb52018-02-25 13:30:15 +01003257/* IPA CRCX on SDCCH/4 and SDCCH/8 (doesn't make sense) */
3258function f_TC_ipa_crcx_sdcch_not_active(charstring id) runs on ConnHdlr {
3259 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_NACK(g_chan_nr, ?),
3260 "IPA CRCX NACK");
3261}
3262testcase TC_ipa_crcx_sdcch_not_active() runs on test_CT {
3263 var ConnHdlrPars pars;
3264 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02003265 f_init();
Harald Welte9912eb52018-02-25 13:30:15 +01003266
3267 pars := valueof(t_Pars(t_RslChanNr_SDCCH4(0,1), ts_RSL_ChanMode_SIGN));
3268 vc_conn := f_start_handler(refers(f_TC_ipa_crcx_sdcch_not_active), pars);
3269 vc_conn.done;
3270
3271 pars := valueof(t_Pars(t_RslChanNr_SDCCH8(6,5), ts_RSL_ChanMode_SIGN));
3272 vc_conn := f_start_handler(refers(f_TC_ipa_crcx_sdcch_not_active), pars);
3273 vc_conn.done;
3274}
3275
Harald Weltea3f1df92018-02-25 12:49:55 +01003276
Harald Welte883340c2018-02-28 18:59:29 +01003277/***********************************************************************
3278 * PCU Socket related tests
3279 ***********************************************************************/
3280
Harald Welte07bd2d22019-05-25 11:03:30 +02003281/* Verify no RTS before ACT_REQ; verify RTS after ACT_REQ */
Harald Weltead033dc2019-05-25 17:28:16 +02003282friend function f_TC_pcu_act_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr, boolean exp_success)
Harald Welte883340c2018-02-28 18:59:29 +01003283runs on test_CT {
3284 timer T := 3.0;
3285
3286 /* we don't expect any RTS.req before PDCH are active */
3287 T.start;
3288 alt {
3289 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003290 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "PCU RTS.req before PDCH active?");
Harald Welte883340c2018-02-28 18:59:29 +01003291 }
3292 [] PCU.receive { repeat; }
3293 [] T.timeout { }
3294 }
3295
3296 /* Send PDCH activate request for known PDCH timeslot */
3297 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, ts_nr)));
3298
3299 /* we now expect RTS.req for this timeslot (only) */
3300 T.start;
3301 alt {
3302 [exp_success] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
3303 setverdict(pass);
3304 }
3305 [not exp_success] PCU.receive(t_SD_PCUIF(g_pcu_conn_id,
3306 tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003307 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RTS.req for supposedly failing activation");
Harald Welte883340c2018-02-28 18:59:29 +01003308 }
3309 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003310 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "RTS.req for wrong TRX/TS");
Harald Welte883340c2018-02-28 18:59:29 +01003311 }
3312 [] PCU.receive { repeat; }
3313 [exp_success] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003314 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU RTS.req");
Harald Welte883340c2018-02-28 18:59:29 +01003315 }
3316 [not exp_success] T.timeout {
3317 setverdict(pass);
3318 }
3319 }
3320}
3321
Harald Welte07bd2d22019-05-25 11:03:30 +02003322/* verify no more RTS after DEACT_REQ */
Harald Weltead033dc2019-05-25 17:28:16 +02003323friend function f_TC_pcu_deact_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
Harald Welte883340c2018-02-28 18:59:29 +01003324runs on test_CT {
3325 timer T := 3.0;
3326
3327 /* Send PDCH activate request for known PDCH timeslot */
3328 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, ts_nr)));
3329
3330 PCU.clear;
3331 /* we now expect no RTS.req for this timeslot */
3332 T.start;
3333 alt {
3334 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003335 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected PCU RTS.req");
Harald Welte883340c2018-02-28 18:59:29 +01003336 }
3337 [] PCU.receive { repeat; }
3338 [] T.timeout {
3339 setverdict(pass);
3340 }
3341 }
3342}
3343
Harald Weltead033dc2019-05-25 17:28:16 +02003344friend function f_init_pcu_test() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003345 f_init();
3346 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_TXT_IND(0, PCU_VERSION, testcasename())));
3347}
3348
Harald Welte883340c2018-02-28 18:59:29 +01003349/* PDCH activation via PCU socket; check for presence of RTS.req */
3350testcase TC_pcu_act_req() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003351 f_init_pcu_test();
3352
Harald Welte883340c2018-02-28 18:59:29 +01003353 f_TC_pcu_act_req(0, 0, 7, true);
3354}
3355
3356/* PDCH activation via PCU socket on non-PDCU timeslot */
3357testcase TC_pcu_act_req_wrong_ts() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003358 f_init_pcu_test();
3359
Harald Welte883340c2018-02-28 18:59:29 +01003360 f_TC_pcu_act_req(0, 0, 1, false);
3361}
3362
3363/* PDCH activation via PCU socket on wrong BTS */
3364testcase TC_pcu_act_req_wrong_bts() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003365 f_init_pcu_test();
3366
Harald Welte883340c2018-02-28 18:59:29 +01003367 f_TC_pcu_act_req(23, 0, 7, false);
3368}
3369
3370/* PDCH activation via PCU socket on wrong TRX */
3371testcase TC_pcu_act_req_wrong_trx() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003372 f_init_pcu_test();
3373
Harald Welte883340c2018-02-28 18:59:29 +01003374 f_TC_pcu_act_req(0, 23, 7, false);
3375}
3376
3377/* PDCH deactivation via PCU socket; check for absence of RTS.req */
3378testcase TC_pcu_deact_req() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003379 f_init_pcu_test();
3380
Harald Welte883340c2018-02-28 18:59:29 +01003381 /* Activate PDCH */
3382 f_TC_pcu_act_req(0, 0, 7, true);
3383 f_sleep(1.0);
3384 /* and De-Activate again */
3385 f_TC_pcu_deact_req(0, 0, 7);
3386}
3387
3388/* Attempt to deactivate a PDCH on a non-PDCH timeslot */
3389testcase TC_pcu_deact_req_wrong_ts() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003390 f_init_pcu_test();
3391
Harald Welte883340c2018-02-28 18:59:29 +01003392 f_TC_pcu_deact_req(0, 0, 1);
3393}
3394
3395/* Test the PCU->BTS Version and BTS->PCU SI13 handshake */
3396testcase TC_pcu_ver_si13() runs on test_CT {
3397 const octetstring si13 := '00010203040506070909'O;
3398 var PCUIF_send_data sd;
3399 timer T:= 3.0;
Max2c6f5632019-03-18 17:25:17 +01003400 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01003401
3402 /* Set SI13 via RSL */
3403 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_13, si13);
Max2c6f5632019-03-18 17:25:17 +01003404
Harald Welte883340c2018-02-28 18:59:29 +01003405 T.start;
3406 alt {
3407 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_DATA_IND(0, 0, 0, ?, PCU_IF_SAPI_BCCH))) -> value sd {
3408 if (substr(sd.data.u.data_ind.data, 0, lengthof(si13)) == si13) {
3409 setverdict(pass);
3410 } else {
3411 repeat;
3412 }
3413 }
3414 [] PCU.receive { repeat; }
3415 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003416 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for SI13");
Harald Welte883340c2018-02-28 18:59:29 +01003417 }
3418 }
3419}
3420
3421private const octetstring c_PCU_DATA := '000102030405060708090a0b0c0d0e0f10111213141516'O;
3422
3423/* helper function to send a PCU DATA.req */
Harald Weltead033dc2019-05-25 17:28:16 +02003424friend function f_pcu_data_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
Harald Welte883340c2018-02-28 18:59:29 +01003425 uint8_t block_nr, uint32_t fn, PCUIF_Sapi sapi, octetstring data)
3426runs on test_CT
3427{
3428 PCU.send(t_SD_PCUIF(g_pcu_conn_id,
3429 ts_PCUIF_DATA_REQ(bts_nr, trx_nr, ts_nr, block_nr, fn, sapi, data)));
3430}
3431
3432/* helper function to wait for RTS.ind for given SAPI on given BTS/TRX/TS and then send */
Harald Weltead033dc2019-05-25 17:28:16 +02003433friend function f_pcu_wait_rts_and_data_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
3434 PCUIF_Sapi sapi, octetstring data)
Harald Welte883340c2018-02-28 18:59:29 +01003435runs on test_CT
3436{
3437 var PCUIF_send_data sd;
3438
3439 timer T := 3.0;
3440 T.start;
3441 alt {
3442 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id,
3443 tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr, sapi))) -> value sd {
3444 f_pcu_data_req(bts_nr, trx_nr, ts_nr, sd.data.u.rts_req.block_nr,
3445 sd.data.u.rts_req.fn, sapi, data);
3446 }
3447 [] PCU.receive { repeat; }
3448 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003449 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RTS.ind");
Harald Welte883340c2018-02-28 18:59:29 +01003450 }
3451 }
3452}
3453
3454/* Send DATA.req on invalid BTS */
3455testcase TC_pcu_data_req_wrong_bts() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02003456 var TfiUsfArr tua := f_TfiUsfArrInit();
3457 var octetstring data := '0000'O & f_rnd_octstring(21);
3458
3459 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01003460
Harald Welte883340c2018-02-28 18:59:29 +01003461 f_TC_pcu_act_req(0, 0, 7, true);
Harald Welte7162a612019-05-26 12:56:09 +02003462 f_TfiUsfArrSet(tua, 7, 0);
3463 f_L1CTL_TBF_CFG(L1CTL, false, tua);
3464 f_sleep(1.0);
3465
3466 f_pcu_to_l1(23, 0, 7, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01003467}
3468
3469/* Send DATA.req on invalid TRX */
3470testcase TC_pcu_data_req_wrong_trx() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02003471 var TfiUsfArr tua := f_TfiUsfArrInit();
3472 var octetstring data := '0000'O & f_rnd_octstring(21);
3473
3474 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01003475
Harald Welte883340c2018-02-28 18:59:29 +01003476 f_TC_pcu_act_req(0, 0, 7, true);
Harald Welte7162a612019-05-26 12:56:09 +02003477 f_TfiUsfArrSet(tua, 7, 0);
3478 f_L1CTL_TBF_CFG(L1CTL, false, tua);
3479 f_sleep(1.0);
3480
3481 f_pcu_to_l1(0, 100, 7, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01003482}
3483
3484/* Send DATA.req on invalid timeslot */
3485testcase TC_pcu_data_req_wrong_ts() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02003486 var TfiUsfArr tua := f_TfiUsfArrInit();
3487 var octetstring data := '0000'O & f_rnd_octstring(21);
3488
3489 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01003490
Harald Welte883340c2018-02-28 18:59:29 +01003491 f_TC_pcu_act_req(0, 0, 7, true);
Harald Welte7162a612019-05-26 12:56:09 +02003492 f_TfiUsfArrSet(tua, 7, 0);
3493 f_L1CTL_TBF_CFG(L1CTL, false, tua);
3494 f_sleep(1.0);
3495
3496 f_pcu_to_l1(0, 0, 70, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01003497}
3498
3499/* Send DATA.req on timeslot that hasn't been activated */
3500testcase TC_pcu_data_req_ts_inactive() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02003501 var TfiUsfArr tua := f_TfiUsfArrInit();
3502 var octetstring data := '0000'O & f_rnd_octstring(21);
Max2c6f5632019-03-18 17:25:17 +01003503
Harald Welte7162a612019-05-26 12:56:09 +02003504 f_virtphy_common();
3505
3506 f_TfiUsfArrSet(tua, 7, 0);
3507 f_L1CTL_TBF_CFG(L1CTL, false, tua);
3508 f_sleep(1.0);
3509
3510 f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01003511}
3512
Harald Weltead033dc2019-05-25 17:28:16 +02003513private function f_pcu_to_l1(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
Harald Welte7162a612019-05-26 12:56:09 +02003514 PCUIF_Sapi sapi, octetstring data, boolean expect_data := true,
3515 boolean wait_rts := true)
3516runs on test_CT {
Harald Weltead033dc2019-05-25 17:28:16 +02003517 timer T := 5.0;
Harald Welte7162a612019-05-26 12:56:09 +02003518 var L1ctlDlMessage rx_dl;
Harald Weltead033dc2019-05-25 17:28:16 +02003519
3520 PCU.clear;
Harald Welte7162a612019-05-26 12:56:09 +02003521 if (wait_rts) {
3522 f_pcu_wait_rts_and_data_req(bts_nr, trx_nr, ts_nr, sapi, data);
3523 } else {
3524 f_pcu_data_req(bts_nr, trx_nr, ts_nr, 0, 0, sapi, data);
3525 }
Harald Weltead033dc2019-05-25 17:28:16 +02003526
3527 T.start;
3528 alt {
Harald Welte7162a612019-05-26 12:56:09 +02003529 [expect_data] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PDCH(ts_nr), ?, data)) {
Harald Weltead033dc2019-05-25 17:28:16 +02003530 /* FIXME: why is fn of DATA_IND different to fn of RTS / DATA_REQ above? */
3531 setverdict(pass);
3532 }
Harald Welte7162a612019-05-26 12:56:09 +02003533 [not expect_data] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PDCH(ts_nr), ?, data)) -> value rx_dl {
3534 setverdict(fail, "Received unexpected ", rx_dl);
3535 }
Harald Weltead033dc2019-05-25 17:28:16 +02003536 [] L1CTL.receive {
3537 repeat;
3538 }
Harald Welte7162a612019-05-26 12:56:09 +02003539 [expect_data] T.timeout {
Harald Weltead033dc2019-05-25 17:28:16 +02003540 setverdict(fail, "Timeout waiting for ", data);
3541 }
Harald Welte7162a612019-05-26 12:56:09 +02003542 [not expect_data] T.timeout {
3543 setverdict(pass);
3544 }
Harald Weltead033dc2019-05-25 17:28:16 +02003545 }
3546}
3547
3548private function f_disable_dynamic_ts() runs on test_CT
3549{
3550 f_init_vty_bsc();
3551 /* I'm not quite sure why we need this with osmo-bts-virtual. Somehow it deosn't seem to
3552 * support dynamic timeslots? But it uses the same scheduler as osmo-bts-trx ?!? */
3553 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 3"}, "phys_chan_config TCH/F");
3554 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 4"}, "phys_chan_config TCH/F");
Max2c6f5632019-03-18 17:25:17 +01003555 f_init_pcu_test();
Harald Weltead033dc2019-05-25 17:28:16 +02003556}
3557
3558private function f_virtphy_common() runs on test_CT {
3559 f_disable_dynamic_ts();
3560 f_init_l1ctl();
3561 f_l1_tune(L1CTL);
3562}
3563
3564testcase TC_pcu_data_req_pdtch() runs on test_CT {
3565 var TfiUsfArr tua := f_TfiUsfArrInit();
3566 var octetstring data := '0000'O & f_rnd_octstring(21);
3567
3568 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01003569
Harald Welte883340c2018-02-28 18:59:29 +01003570 f_TC_pcu_act_req(0, 0, 7, true);
Harald Weltead033dc2019-05-25 17:28:16 +02003571 f_TfiUsfArrSet(tua, 7, 0);
3572 f_L1CTL_TBF_CFG(L1CTL, false, tua);
3573 f_sleep(1.0);
3574
3575 f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PDTCH, data); //c_PCU_DATA);
Harald Welte883340c2018-02-28 18:59:29 +01003576}
3577
3578testcase TC_pcu_data_req_ptcch() runs on test_CT {
Harald Weltead033dc2019-05-25 17:28:16 +02003579 var TfiUsfArr tua := f_TfiUsfArrInit();
3580 var octetstring data := '0000'O & f_rnd_octstring(21);
3581
3582 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01003583
Harald Welte883340c2018-02-28 18:59:29 +01003584 f_TC_pcu_act_req(0, 0, 7, true);
Harald Weltead033dc2019-05-25 17:28:16 +02003585 f_TfiUsfArrSet(tua, 7, 0);
3586 f_L1CTL_TBF_CFG(L1CTL, false, tua);
3587 f_sleep(1.0);
3588
3589 f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PTCCH, data);
Harald Welte883340c2018-02-28 18:59:29 +01003590}
3591
3592/* Send AGCH from PCU; check it appears on Um side */
3593testcase TC_pcu_data_req_agch() runs on test_CT {
3594 timer T := 3.0;
Max2c6f5632019-03-18 17:25:17 +01003595 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01003596 f_init_l1ctl();
3597 f_l1_tune(L1CTL);
3598
3599 f_TC_pcu_act_req(0, 0, 7, true);
3600 f_pcu_data_req(0, 0, 7, 0, 0, PCU_IF_SAPI_AGCH, c_PCU_DATA);
3601
3602 T.start;
3603 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +01003604 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_PCU_DATA)) {
Harald Welte883340c2018-02-28 18:59:29 +01003605 setverdict(pass);
3606 }
3607 [] L1CTL.receive { repeat; }
3608 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003609 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU-originated AGCH block on Um");
Harald Welte883340c2018-02-28 18:59:29 +01003610 }
3611 }
3612}
3613
Harald Welte928622b2019-05-26 13:22:59 +02003614/* Send AGCH from PCU; check it appears on Um side */
3615testcase TC_pcu_data_req_pch() runs on test_CT {
3616 timer T := 3.0;
3617 f_init_pcu_test();
3618 f_init_l1ctl();
3619 f_l1_tune(L1CTL);
3620
3621 f_TC_pcu_act_req(0, 0, 7, true);
3622 /* three characters prefix: last 3 digits of IMSI as ASCII */
3623 f_pcu_data_req(0, 0, 7, 0, 0, PCU_IF_SAPI_PCH, '313233'O & c_PCU_DATA);
3624
3625 T.start;
3626 alt {
3627 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_PCU_DATA)) {
3628 setverdict(pass);
3629 }
3630 [] L1CTL.receive { repeat; }
3631 [] T.timeout {
3632 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU-originated PCH block on Um");
3633 }
3634 }
3635}
3636
Harald Welte883340c2018-02-28 18:59:29 +01003637/* Send IMM.ASS from PCU for PCH; check it appears on Um side */
3638testcase TC_pcu_data_req_imm_ass_pch() runs on test_CT {
3639 var octetstring imm_ass := f_rnd_octstring(23);
Max2c6f5632019-03-18 17:25:17 +01003640 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01003641 f_init_l1ctl();
3642 f_l1_tune(L1CTL);
3643
3644 /* append 3 last imsi digits so BTS can compute pagng group */
3645 var uint32_t fn := f_PCUIF_tx_imm_ass_pch(PCU, g_pcu_conn_id, imm_ass, '123459987'H);
3646
3647 timer T := 0.5;
3648 T.start;
3649 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +01003650 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, imm_ass)) {
Harald Welte883340c2018-02-28 18:59:29 +01003651 /* TODO: verify paging group */
3652 setverdict(pass);
3653 }
3654 [] L1CTL.receive { repeat; }
3655 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003656 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU-originated AGCH block on Um");
Harald Welte883340c2018-02-28 18:59:29 +01003657 }
3658 }
3659}
3660
3661/* Send RACH from Um side, expect it to show up on PCU socket */
3662testcase TC_pcu_rach_content() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003663 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01003664 f_init_l1ctl();
3665 f_l1_tune(L1CTL);
3666
3667 var GsmFrameNumber fn_last := 0;
3668 for (var integer i := 0; i < 1000; i := i+1) {
3669 var OCT1 ra := f_rnd_ra_ps();
3670 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
3671 if (fn == fn_last) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003672 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
Harald Welte883340c2018-02-28 18:59:29 +01003673 }
3674 fn_last := fn;
3675
3676 timer T := 2.0;
3677 T.start;
3678 alt {
3679 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND(0, oct2int(ra), 0, ?, fn))) {
3680 T.stop;
3681 }
3682 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003683 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RACH IND");
Harald Welte883340c2018-02-28 18:59:29 +01003684 }
3685 [] PCU.receive { repeat; }
3686 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003687 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RACH IND");
Harald Welte883340c2018-02-28 18:59:29 +01003688 }
3689 }
3690 }
3691 setverdict(pass);
3692}
3693
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +07003694/* Send extended (11-bit, TS1 & TS2) RACH bursts from the Um side,
3695 * expect them to show up on PCU socket (with proper BURST_TYPE_*). */
3696testcase TC_pcu_ext_rach_content() runs on test_CT {
3697 var template PCUIF_Message pcu_rach_ind;
3698 var GsmFrameNumber fn_last := 0;
3699 var L1ctlRachSynchSeq synch_seq;
3700 var PCUIF_BurstType pcu_bt;
3701 var GsmFrameNumber fn;
3702 var BIT11 ra11;
3703
3704 f_init_pcu_test();
3705 f_init_l1ctl();
3706 f_l1_tune(L1CTL);
3707
3708 for (var integer i := 0; i < 1000; i := i+1) {
3709 /* We need to test both TS1 & TS2 */
3710 if (i rem 2 == 0) {
3711 synch_seq := RACH_SYNCH_SEQ_TS1;
3712 pcu_bt := BURST_TYPE_1;
3713 } else {
3714 synch_seq := RACH_SYNCH_SEQ_TS2;
3715 pcu_bt := BURST_TYPE_2;
3716 }
3717
3718 ra11 := f_rnd_ra11_ps();
3719 fn := f_L1CTL_EXT_RACH(L1CTL, bit2int(ra11), synch_seq);
3720 if (fn == fn_last) {
3721 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
3722 "Two RACH in same FN?!?");
3723 }
3724 fn_last := fn;
3725
3726 /* Compose the expected message */
3727 pcu_rach_ind := tr_PCUIF_RACH_IND(
3728 bts_nr := 0,
3729 ra := bit2int(ra11),
3730 is_11bit := 1,
3731 burst_type := pcu_bt,
3732 fn := fn);
3733
3734 timer T := 2.0;
3735 T.start;
3736 alt {
3737 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, pcu_rach_ind)) {
3738 T.stop;
3739 }
3740 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND)) {
3741 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RACH IND");
3742 }
3743 [] PCU.receive { repeat; }
3744 [] T.timeout {
3745 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RACH IND");
3746 }
3747 }
3748 }
3749 setverdict(pass);
3750}
3751
Harald Welte883340c2018-02-28 18:59:29 +01003752/* Send PAGING via RSL, expect it to shw up on PCU socket */
3753testcase TC_pcu_paging_from_rsl() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01003754 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01003755
3756 for (var integer i := 0; i < 100; i := i+1) {
3757 var MobileL3_CommonIE_Types.MobileIdentityLV mi;
3758 timer T := 3.0;
3759 if (i < 50) {
3760 mi := valueof(ts_MI_TMSI_LV(f_rnd_octstring(4)));
3761 } else {
3762 mi := valueof(ts_MI_IMSI_LV(f_gen_imsi(i)));
3763 }
3764 var octetstring mi_enc_lv := enc_MobileIdentityLV(mi);
3765 var octetstring mi_enc := substr(mi_enc_lv, 1, lengthof(mi_enc_lv)-1);
3766 var octetstring t_mi_lv := f_pad_oct(mi_enc_lv, 9, '00'O);
3767
3768 /* Send RSL PAGING COMMAND */
3769 RSL_CCHAN.send(ts_RSL_UD(ts_RSL_PAGING_CMD(mi_enc, i mod 4)));
3770 T.start;
3771 alt {
3772 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ(0, t_mi_lv))) {
3773 }
3774 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003775 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PAGING REQ");
Harald Welte883340c2018-02-28 18:59:29 +01003776 }
3777 [] PCU.receive { repeat; }
3778 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003779 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PAGING REQ");
Harald Welte883340c2018-02-28 18:59:29 +01003780 }
3781 }
3782 }
3783 setverdict(pass);
3784}
3785
Harald Welted66c9b82019-05-25 09:03:15 +02003786/* test for periodic TIME_IND; check number of FN expired and number of TIME_IND within frames */
3787testcase TC_pcu_time_ind() runs on test_CT {
3788 var PCUIF_send_data pcu_sd;
3789 var integer num_time_ind := 0;
3790 var integer first_fn, last_fn;
3791 var float test_duration := 5.0;
3792 timer T;
3793
3794 f_init_pcu_test();
3795 f_TC_pcu_act_req(0, 0, 7, true);
3796
3797 PCU.clear;
3798 T.start(test_duration);
3799 alt {
3800 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_TIME_IND(0, ?))) -> value pcu_sd {
3801 num_time_ind := num_time_ind + 1;
3802 if (not isbound(first_fn)) {
3803 first_fn := pcu_sd.data.u.time_ind.fn;
3804 }
3805 last_fn := pcu_sd.data.u.time_ind.fn;
3806 repeat;
3807 }
3808 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_TIME_IND(?, ?))) -> value pcu_sd {
3809 setverdict(fail, "Received unexpected PCUIF_TIME_IND: ", pcu_sd.data);
3810 repeat;
3811 }
3812 [] PCU.receive {
3813 repeat;
3814 }
3815 [] T.timeout {}
3816 }
3817 var integer fn_expired := last_fn - first_fn;
3818 log(fn_expired, " fn expired with ", num_time_ind, " PCU_TIME.ind");
3819
3820 /* verify the number of frames expired matches our expectation */
3821 const float c_GSM_FN_DURATION_MS := 4.61538;
3822 var float fn_expected := test_duration * 1000.0 / c_GSM_FN_DURATION_MS;
Harald Weltec761c542019-05-28 11:59:57 +02003823 var template integer t_fn_expected := f_tolerance(float2int(fn_expected), 1, 100000, 20);
Harald Welted66c9b82019-05-25 09:03:15 +02003824 if (not match(fn_expired, t_fn_expected)) {
3825 setverdict(fail, "Number of TDMA Frames (", fn_expired, ") not matching ", t_fn_expected);
3826 }
3827
3828 /* There are three TIME.ind in every fn MOD 13 */
3829 var float time_ind_expected := int2float(fn_expired) * 3.0 / 13.0;
3830 /* Add some tolerance */
3831 var template integer t_time_ind_exp := f_tolerance(float2int(time_ind_expected), 1, 100000, 5);
3832 if (not match(num_time_ind, t_time_ind_exp)) {
3833 setverdict(fail, "Number of TIME.ind (", num_time_ind, ") not matching ", t_time_ind_exp);
3834 }
3835
3836 setverdict(pass);
3837}
3838
Harald Welte4832c862019-05-25 14:57:18 +02003839/* test for periodic RTS_REQ; check number of FN expired and number of RTS_IND per SAPI */
3840testcase TC_pcu_rts_req() runs on test_CT {
3841 var PCUIF_send_data pcu_sd;
3842 var integer first_fn, last_fn;
3843 var integer num_rts_pdtch := 0;
3844 var integer num_rts_ptcch := 0;
3845 var float test_duration := 5.0;
3846 timer T;
3847
3848 f_init_pcu_test();
3849 f_TC_pcu_act_req(0, 0, 7, true);
3850
3851 PCU.clear;
3852 T.start(test_duration);
3853 alt {
3854 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(0, 0, 7, PCU_IF_SAPI_PDTCH, ?, ?)))
3855 -> value pcu_sd {
3856 num_rts_pdtch := num_rts_pdtch + 1;
3857 if (not isbound(first_fn)) {
3858 first_fn := pcu_sd.data.u.rts_req.fn;
3859 }
3860 last_fn := pcu_sd.data.u.rts_req.fn;
3861 repeat;
3862 }
3863 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(0, 0, 7, PCU_IF_SAPI_PTCCH, ?, ?)))
3864 -> value pcu_sd {
3865 num_rts_ptcch := num_rts_ptcch + 1;
3866 if (not isbound(first_fn)) {
3867 first_fn := pcu_sd.data.u.rts_req.fn;
3868 }
3869 last_fn := pcu_sd.data.u.rts_req.fn;
3870 repeat;
3871 }
3872 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ)) -> value pcu_sd {
3873 setverdict(fail, "Received unexpected PCUIF_RTS_REQ: ", pcu_sd.data);
3874 repeat;
3875 }
3876 [] PCU.receive {
3877 repeat;
3878 }
3879 [] T.timeout {}
3880 }
3881 var integer fn_expired := last_fn - first_fn;
3882 log(fn_expired, " fn expired with num_rts_pdtch=", num_rts_pdtch,
3883 ", num_rts_ptcch=", num_rts_ptcch);
3884
3885 /* verify the number of frames expired matches our expectation */
3886 const float c_GSM_FN_DURATION_MS := 4.61538;
3887 var float fn_expected := test_duration * 1000.0 / c_GSM_FN_DURATION_MS;
Harald Weltec761c542019-05-28 11:59:57 +02003888 var template integer t_fn_expected := f_tolerance(float2int(fn_expected), 1, 100000, 20);
Harald Welte4832c862019-05-25 14:57:18 +02003889 if (not match(fn_expired, t_fn_expected)) {
3890 setverdict(fail, "Number of TDMA Frames (", fn_expired, ") not matching ", t_fn_expected);
3891 }
3892
3893 /* PTCCH is in pos. 12 + 38 of 52-multiframe, but four slots/bursts required per block */
3894 var float ptcch_expected := int2float(fn_expired) / 52.0 * 0.5;
3895 var template integer t_ptcch_exp := f_tolerance(float2int(ptcch_expected), 1, 100000, 1);
3896 if (not match(num_rts_ptcch, t_ptcch_exp)) {
3897 setverdict(fail, "Number of RTS.ind for PTCCH (", num_rts_ptcch, ") not matching ",
3898 t_ptcch_exp);
3899 }
3900
3901 /* We have 12 PDTCH blocks every 52-multiframe */
3902 var float pdtch_expected := int2float(fn_expired) / 52.0 * 12.0;
3903 var template integer t_pdtch_exp := f_tolerance(float2int(pdtch_expected), 1, 100000, 2);
3904 if (not match(num_rts_pdtch, t_pdtch_exp)) {
3905 setverdict(fail, "Number of RTS.ind for PDTCH (", num_rts_pdtch, ") not matching ",
3906 t_pdtch_exp);
3907 }
3908
3909 setverdict(pass);
3910}
3911
Harald Welte07bd2d22019-05-25 11:03:30 +02003912/* test for generating Abis side OML ALERT from the PCU */
3913testcase TC_pcu_oml_alert() runs on test_CT {
3914 var PCUIF_send_data pcu_sd;
3915 var integer num_time_ind := 0;
3916 var integer first_fn, last_fn;
3917 var float test_duration := 5.0;
3918 timer T;
3919
3920 f_init_pcu_test();
3921 f_TC_pcu_act_req(0, 0, 7, true);
3922
3923 /* re-connect CTRL port from BTS to BSC */
3924 f_ipa_ctrl_stop();
3925 f_ipa_ctrl_start(mp_bsc_ctrl_ip, mp_bsc_ctrl_port);
3926
3927 /* Send that OML Alert */
3928 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_TXT_IND(0, PCU_OML_ALERT, testcasename())));
3929
3930 /* This requires https://gerrit.osmocom.org/#/c/osmo-bsc/+/14177 to be merged */
3931 f_ctrl_exp_trap(IPA_CTRL, "bts.0.oml_failure_report", ?);
3932 setverdict(pass);
3933}
3934
Harald Welteeaa9a862019-05-26 23:01:08 +02003935template (value) PDU_ML3_MS_NW ts_RRM_GprsSuspReq(template (value) OCT4 tlli,
3936 template (value) RoutingAreaIdentificationV rai,
3937 template (value) OCT1 cause) := {
3938 discriminator := '0000'B, /* overwritten */
3939 tiOrSkip := {
3940 skipIndicator := '0000'B
3941 },
3942 msgs := {
3943 rrm := {
3944 gPRS_suspensionRequest := {
3945 messageType := '00110100'B,
3946 tLLI := tlli,
3947 routingAreaIdentification := rai,
3948 suspensionCause := cause,
3949 service_Support := omit
3950 }
3951 }
3952 }
3953}
3954
3955/* test for forwarding of RR SUSPEND from CS lchan to PCU via PCU socket */
3956private function f_TC_rr_suspend_req(charstring id) runs on ConnHdlr {
3957 var PCUIF_Message first_info;
3958 var integer pcu_conn_id := -1;
3959 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
3960 var RoutingAreaIdentificationV rai := f_RAI('262'H, '42F'H, '2342'O, '55'O);
3961 var OCT4 tlli := '01020304'O;
3962 var OCT1 cause := '23'O;
3963 timer T := 5.0;
3964
3965 f_init_pcu(PCU, id, pcu_conn_id, first_info);
3966
3967 f_l1_tune(L1CTL);
3968 RSL.clear;
3969
3970 f_est_dchan();
3971 L1CTL.clear;
3972
3973 f_est_rll_mo(link_id.sapi, link_id, '23420815'O);
3974
3975 var PDU_ML3_MS_NW susp_req := valueof(ts_RRM_GprsSuspReq(tlli, rai, cause));
3976 var octetstring l3 := enc_PDU_ML3_MS_NW(susp_req);
3977 f_tx_lapdm(ts_LAPDm_I(link_id.sapi, cr_MO_CMD, true, 1, 0, l3), link_id);
3978
3979 /* ConnHdlr has terminated after sending the RR SUSP REQ over a dedicaed channel */
3980 T.start;
3981 alt {
3982 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_SUSP_REQ(0, tlli, ?, oct2int(cause)))) {
3983 setverdict(pass);
3984 }
3985 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_SUSP_REQ(?, ?, ?, ?))) {
3986 setverdict(fail, "Received unexpected PCUIF SUSPE REQ: ");
3987 }
3988 [] PCU.receive {
3989 repeat;
3990 }
3991 [] T.timeout {
3992 setverdict(fail, "Timeout waiting for SUSP REQ on PCUIF");
3993 }
3994 }
3995}
3996testcase TC_pcu_rr_suspend() runs on test_CT {
3997 var ConnHdlrPars pars;
3998 var ConnHdlr vc_conn;
3999
4000 f_init();
4001
4002 pars := valueof(t_Pars(t_RslChanNr_SDCCH4(0,3), ts_RSL_ChanMode_SIGN));
4003 vc_conn := f_start_handler(refers(f_TC_rr_suspend_req), pars, true);
4004 vc_conn.done;
4005}
Harald Welte07bd2d22019-05-25 11:03:30 +02004006
Harald Weltea2e0e942019-05-27 18:12:53 +02004007/* Ensure that PCUIF socket can accept only a single connection */
4008testcase TC_pcu_socket_connect_multi() runs on test_CT {
4009 timer T := 5.0;
4010
4011 /* this (among other things) establishes the first connection to the PCUIF socket */
4012 f_init();
4013
4014 /* try to establish a second connection, expect it to fail */
4015 PCU.send(UD_connect:{mp_pcu_socket, -1});
4016 T.start;
4017 alt {
4018 [] PCU.receive(UD_connect_result:{id := ?, result := { result_code := ERROR, err := ? }}) {
4019 setverdict(pass);
4020 }
4021 [] PCU.receive(UD_connect_result:?) {
4022 setverdict(fail, "Unexpected unix domain connect result");
4023 }
4024 [] T.timeout {
4025 setverdict(pass);
4026 }
4027 }
4028 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
4029}
4030
Harald Weltec8effb72019-05-27 18:23:04 +02004031/* Ensure that PCUIF socket can disconnect + reconnect */
4032testcase TC_pcu_socket_reconnect() runs on test_CT {
4033 /* this (among other things) establishes the first connection to the PCUIF socket */
4034 f_init();
4035
4036 f_sleep(1.0);
4037
4038 f_pcuif_close(PCU, g_pcu_conn_id);
4039 g_pcu_conn_id := -1;
4040
4041 f_sleep(1.0);
4042
4043 /* re-connect */
4044 PCU.clear;
4045 f_init_pcu(PCU, testcasename(), g_pcu_conn_id, g_pcu_last_info);
4046 setverdict(pass);
4047
4048 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
4049}
4050
Harald Weltebe030482019-05-27 22:29:35 +02004051/* Ensure that GPRS capability is not advertised before PCU socket conncet */
4052private function f_get_si3(L1CTL_PT pt) runs on test_CT return SystemInformationType3 {
4053 var L1ctlDlMessage l1_dl;
4054 var SystemInformation si;
4055 timer T := 5.0;
4056 T.start;
4057 alt {
4058 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
4059 /* somehow dec_SystemInformation will try to decode even non-RR as SI */
4060 if (not (l1_dl.payload.data_ind.payload[1] == '06'O)) {
4061 log("Ignoring non-RR SI ", l1_dl);
4062 repeat;
4063 }
4064 si := dec_SystemInformation(l1_dl.payload.data_ind.payload)
4065 if (not ischosen(si.payload.si3)) {
4066 repeat;
4067 }
4068 }
4069 [] pt.receive {
4070 repeat;
4071 }
4072 [] T.timeout {
4073 setverdict(fail, "Timeout waiting for SI3");
4074 }
4075 }
4076 return si.payload.si3;
4077}
4078
4079/* CSN.1 L/H logic: is the bit at the current position using "inverted logic" (true) or not? */
4080private function f_bitpos_is_inv(integer idx) return boolean {
4081 select (idx mod 8) {
4082 case ((2, 4, 6, 7)) { return true; } /* 1-bits of 0x2B */
4083 case else { return false; } /* 0-bits of 0x2B */
4084 }
4085}
4086/* determine if the bit at position 'idx' in 'str' is a CSN.1 'H' (true) or 'L' (false) */
4087private function f_bit_is_high(bitstring str, integer idx) return boolean {
4088 var boolean invert := f_bitpos_is_inv(idx);
4089 if (invert) {
4090 if (str[idx] == '1'B) {
4091 return false;
4092 } else {
4093 return true;
4094 }
4095 } else {
4096 if (str[idx] == '1'B) {
4097 return true;
4098 } else {
4099 return false;
4100 }
4101 }
4102}
4103/* As the TITAN RAW codec cannot expres the CSN.1 L/H concept yet, we have to do this
4104 manually. Let's hope https://www.eclipse.org/forums/index.php/t/1099087/ takes off and
4105 we can replace this piece of code soon ... */
4106private function f_si3_has_gprs_indicator(OCT4 si3_restoctets) return boolean {
4107 var bitstring bits := oct2bit(si3_restoctets);
4108 var integer idx := 0;
4109
4110 if (f_bit_is_high(bits, idx)) {
4111 /* skip Optional selection parameters */
4112 idx := idx + 16;
4113 } else {
4114 idx := idx + 1;
4115 }
4116
4117 if (f_bit_is_high(bits, idx)) {
4118 /* skip Optional power offset */
4119 idx := idx + 3;
4120 } else {
4121 idx := idx + 1;
4122 }
4123
4124 /* skip SI2ter Indicator */
4125 idx := idx + 1;
4126
4127 /* skip Early CM Sending Control */
4128 idx := idx + 1;
4129
4130 /* skip Scheduling if and where */
4131 if (f_bit_is_high(bits, idx)) {
4132 idx := idx + 4;
4133 } else {
4134 idx := idx + 1;
4135 }
4136
4137 return f_bit_is_high(bits, idx);
4138}
4139
4140testcase TC_pcu_socket_noconnect_nosi3gprs() runs on test_CT {
4141 var SystemInformationType3 si3;
4142 timer T := 5.0;
4143
4144 /* don't call f_init() as this would connect PCU socket */
4145 f_init_rsl(testcasename());
4146 T.start;
4147 alt {
4148 [] RSL_CCHAN.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP});
4149 [] T.timeout {
4150 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for ASP_IPA_EVENT_UP");
4151 }
4152 }
4153 f_rsl_bcch_fill(RSL_SYSTEM_INFO_3, ts_SI3_default);
4154
4155 f_init_l1ctl();
4156 f_l1_tune(L1CTL);
4157
4158 f_sleep(2.0);
4159 L1CTL.clear;
4160 si3 := f_get_si3(L1CTL);
4161 if (f_si3_has_gprs_indicator(si3.rest_octets)) {
4162 setverdict(fail, "SI3 indicates GPRS even before PCU socket connected");
4163 } else {
4164 setverdict(pass);
4165 }
4166 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
4167}
4168
4169/* Ensure that GPRS capability is advertised after PCU socket connect */
4170testcase TC_pcu_socket_connect_si3gprs() runs on test_CT {
4171 var SystemInformationType3 si3;
4172
4173 /* this (among other things) establishes the first connection to the PCUIF socket */
4174 f_init();
4175 f_init_l1ctl();
4176 f_l1_tune(L1CTL);
4177
4178 f_sleep(2.0);
4179 L1CTL.clear;
4180 si3 := f_get_si3(L1CTL);
4181 if (not f_si3_has_gprs_indicator(si3.rest_octets)) {
4182 setverdict(fail, "SI3 indicates no GPRS despite PCU socket connected");
4183 } else {
4184 setverdict(pass);
4185 }
4186 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
4187}
4188
4189/* Ensure that GPRS capability is no longer advertised after PCU socket disconnect */
4190testcase TC_pcu_socket_disconnect_nosi3gprs() runs on test_CT {
4191 var SystemInformationType3 si3;
4192
4193 /* this (among other things) establishes the first connection to the PCUIF socket */
4194 f_init();
4195 f_init_l1ctl();
4196 f_l1_tune(L1CTL);
4197
4198 f_pcuif_close(PCU, g_pcu_conn_id);
4199 g_pcu_conn_id := -1;
4200
4201 f_sleep(1.0);
4202
4203 /* re-connect */
4204 PCU.clear;
4205 f_init_pcu(PCU, testcasename(), g_pcu_conn_id, g_pcu_last_info);
4206
4207 f_sleep(2.0);
4208 L1CTL.clear;
4209 si3 := f_get_si3(L1CTL);
4210 if (f_si3_has_gprs_indicator(si3.rest_octets)) {
4211 setverdict(fail, "SI3 indicates GPRS after PCU socket disconnected");
4212 } else {
4213 setverdict(pass);
4214 }
4215
4216 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
4217}
4218
Harald Welted66c9b82019-05-25 09:03:15 +02004219
Harald Welte3d04ae62018-04-04 20:29:05 +02004220/***********************************************************************
Harald Welte9bbbfb52018-04-05 09:33:19 +02004221 * Osmocom Style Dynamic Timeslot Support
Harald Welte3d04ae62018-04-04 20:29:05 +02004222 ***********************************************************************/
4223
4224private function f_dyn_osmo_pdch_act(integer pcu_conn_id, integer bts_nr, integer trx_nr)
4225runs on ConnHdlr {
4226 var PCUIF_send_data sd;
4227 /* Expect BTS to immediately acknowledge activation as PDCH */
4228 PCU.clear;
4229 f_rsl_chan_act(g_pars.chan_mode);
4230 /* expect INFO_IND on PCU interface listing TS as PDCH */
4231 alt {
4232 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
4233 if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '1'B) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004234 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "PCUIF_INFO_IND PDCH_MASK not '1' after PDCH ACT");
Harald Welte3d04ae62018-04-04 20:29:05 +02004235 }
4236 }
4237 [] PCU.receive { repeat; }
4238 }
4239 /* try to activate this PDCH from the PCU point of view */
4240 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
4241 /* FIXME: is there a response? */
4242}
4243
4244private function f_dyn_osmo_pdch_deact(integer pcu_conn_id, integer bts_nr, integer trx_nr)
4245runs on ConnHdlr {
4246 var PCUIF_send_data sd;
4247 /* Send RSL CHAN REL (deactivate) */
4248 PCU.clear;
4249 RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
4250 /* expect BTS to ask PCU to deactivate the channel */
4251 alt {
4252 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
4253 if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '0'B) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004254 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "PCUIF_INFO_IND PDCH_MASK not '0' after PDCH DEACT");
Harald Welte3d04ae62018-04-04 20:29:05 +02004255 }
4256 }
4257 [] PCU.receive { repeat; }
4258 }
4259 /* Emulate PCU asking BTS to deactivate PDCH */
4260 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
4261 alt {
4262 [] RSL.receive(tr_RSL_RF_CHAN_REL_ACK(g_chan_nr)) {
4263 setverdict(pass);
4264 }
4265 [] RSL.receive { repeat; }
4266 }
4267}
4268
4269/* Activate Osmocom-style dynamic PDCH from BSC side */
4270function f_TC_dyn_osmo_pdch_act_deact(charstring id) runs on ConnHdlr {
4271 var PCUIF_Message first_info;
4272 var integer ts_nr := g_chan_nr.tn;
4273 var integer trx_nr := 0;
4274 var integer bts_nr := 0;
4275 var integer pcu_conn_id := -1;
4276
4277 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4278
4279 f_dyn_osmo_pdch_act(pcu_conn_id, bts_nr, trx_nr);
4280 f_sleep(3.0);
4281 f_dyn_osmo_pdch_deact(pcu_conn_id, bts_nr, trx_nr);
4282 setverdict(pass);
4283}
4284testcase TC_dyn_osmo_pdch_act_deact() runs on test_CT {
4285 var ConnHdlrPars pars;
4286 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004287 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02004288
4289 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
4290 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_act_deact), pars, true);
4291 vc_conn.done;
4292}
4293
4294/* send a RF CHAN REL for PDCH on an osmocom dynamci PDCH that's already inactive */
4295function f_TC_dyn_osmo_pdch_unsol_deact(charstring id) runs on ConnHdlr {
4296 var PCUIF_Message first_info;
Harald Welte3d04ae62018-04-04 20:29:05 +02004297 var integer pcu_conn_id := -1;
4298
4299 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4300
Neels Hofmeyr9c50ca52018-05-08 20:37:54 +02004301 RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
4302 /* since the lchan is already released, we don't expect any PCU changes, just a rel ack. */
4303 RSL.receive(tr_RSL_RF_CHAN_REL_ACK(g_chan_nr));
Harald Welte3d04ae62018-04-04 20:29:05 +02004304 setverdict(pass);
4305}
4306testcase TC_dyn_osmo_pdch_unsol_deact() runs on test_CT {
4307 var ConnHdlrPars pars;
4308 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004309 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02004310
4311 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
4312 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_unsol_deact), pars, true);
4313 vc_conn.done;
4314}
4315
4316/* try to RSL CHAN ACT a PDCH on an osmocom-style PDCH that's already active */
4317function f_TC_dyn_osmo_pdch_double_act(charstring id) runs on ConnHdlr {
4318 var PCUIF_Message first_info;
4319 var integer ts_nr := g_chan_nr.tn;
4320 var integer trx_nr := 0;
4321 var integer bts_nr := 0;
4322 var integer pcu_conn_id := -1;
4323
4324 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4325
4326 f_dyn_osmo_pdch_act(pcu_conn_id, bts_nr, trx_nr);
Neels Hofmeyrdf936a22018-05-08 22:07:57 +02004327 /* Send a second Chan Activ and expect it to be NACKed */
4328 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_NACK(g_chan_nr),
4329 "RSL CHAN ACT NACK");
Harald Welte3d04ae62018-04-04 20:29:05 +02004330 setverdict(pass);
4331}
4332testcase TC_dyn_osmo_pdch_double_act() runs on test_CT {
4333 var ConnHdlrPars pars;
4334 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004335 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02004336
4337 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
4338 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_double_act), pars, true);
4339 vc_conn.done;
4340}
4341
4342/* try to RSL CHAN ACT a TCH/F on an osmocom-style PDCH */
4343function f_TC_dyn_osmo_pdch_tchf_act(charstring id) runs on ConnHdlr {
4344 var PCUIF_Message first_info;
4345 var integer ts_nr := g_chan_nr.tn;
4346 var integer trx_nr := 0;
4347 var integer bts_nr := 0;
4348 var integer pcu_conn_id := -1;
4349 var RslChannelNr chan_nr := valueof(t_RslChanNr_Bm(g_chan_nr.tn));
4350
4351 /* register for the TCH/F channel number */
4352 f_rslem_register(0, chan_nr);
4353
4354 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4355
4356 f_rsl_transceive(ts_RSL_CHAN_ACT(chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_ACK(chan_nr),
4357 "RSL CHAN ACT");
4358 setverdict(pass);
4359}
4360testcase TC_dyn_osmo_pdch_tchf_act() runs on test_CT {
4361 var ConnHdlrPars pars;
4362 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004363 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02004364
4365 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
4366 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_tchf_act), pars, true);
4367 vc_conn.done;
4368}
4369
4370/* try to RSL CHAN ACT the TCH/H on an osmocom-style PDCH */
4371function f_TC_dyn_osmo_pdch_tchh_act(charstring id) runs on ConnHdlr {
4372 var PCUIF_Message first_info;
4373 var integer ts_nr := g_chan_nr.tn;
4374 var integer trx_nr := 0;
4375 var integer bts_nr := 0;
4376 var integer pcu_conn_id := -1;
4377 var RslChannelNr chan_nr[2] := { valueof(t_RslChanNr_Lm(g_chan_nr.tn, 0)),
4378 valueof(t_RslChanNr_Lm(g_chan_nr.tn, 1)) };
4379
4380 /* register for the TCH/H channel numbers */
4381 f_rslem_register(0, chan_nr[0]);
4382 f_rslem_register(0, chan_nr[1]);
4383
4384 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4385
4386 f_rsl_transceive(ts_RSL_CHAN_ACT(chan_nr[1], g_pars.chan_mode),
4387 tr_RSL_CHAN_ACT_ACK(chan_nr[1]), "RSL CHAN ACT [1]");
4388 f_rsl_transceive(ts_RSL_CHAN_ACT(chan_nr[0], g_pars.chan_mode),
4389 tr_RSL_CHAN_ACT_ACK(chan_nr[0]), "RSL CHAN ACT [0]");
4390 setverdict(pass);
4391}
4392testcase TC_dyn_osmo_pdch_tchh_act() runs on test_CT {
4393 var ConnHdlrPars pars;
4394 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004395 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02004396
4397 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
4398 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_tchh_act), pars, true);
4399 vc_conn.done;
4400}
4401
Harald Welte9bbbfb52018-04-05 09:33:19 +02004402/***********************************************************************
4403 * IPA Style Dynamic Timeslot Support
4404 ***********************************************************************/
4405
4406private function f_dyn_ipa_pdch_act(integer pcu_conn_id, integer bts_nr, integer trx_nr)
4407runs on ConnHdlr {
4408 var PCUIF_send_data sd;
4409 /* Expect BTS to immediately acknowledge activation as PDCH */
4410 PCU.clear;
4411 RSL.send(ts_RSL_IPA_PDCH_ACT(g_chan_nr));
4412 /* expect INFO_IND on PCU interface listing TS as PDCH */
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01004413 timer T_wait := 2.0;
4414 T_wait.start;
Harald Welte9bbbfb52018-04-05 09:33:19 +02004415 alt {
4416 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
4417 if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '1'B) {
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01004418 log("PCUIF_INFO_IND PDCH_MASK not yet '1' after PDCH ACT on TS", g_chan_nr.tn,
4419 " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
4420 repeat;
Harald Welte9bbbfb52018-04-05 09:33:19 +02004421 }
4422 }
4423 [] PCU.receive { repeat; }
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01004424 [] T_wait.timeout {
4425 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
4426 log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '1' on TS", g_chan_nr.tn));
4427 }
Harald Welte9bbbfb52018-04-05 09:33:19 +02004428 }
4429 /* try to activate this PDCH from the PCU point of view */
4430 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
4431 /* FIXME: is there a response? */
4432
4433 RSL.receive(tr_RSL_IPA_PDCH_ACT_ACK(g_chan_nr, ?));
4434}
4435
4436private function f_dyn_ipa_pdch_deact(integer pcu_conn_id, integer bts_nr, integer trx_nr)
4437runs on ConnHdlr {
4438 var PCUIF_send_data sd;
4439 /* Send RSL CHAN REL (deactivate) */
4440 RSL.send(ts_RSL_IPA_PDCH_DEACT(g_chan_nr));
4441 PCU.clear;
4442 /* expect BTS to ask PCU to deactivate the channel */
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01004443 timer T_wait := 2.0;
4444 T_wait.start;
Harald Welte9bbbfb52018-04-05 09:33:19 +02004445 alt {
4446 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
4447 if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '0'B) {
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01004448 log("PCUIF_INFO_IND PDCH_MASK not yet '0' after PDCH DEACT on TS", g_chan_nr.tn,
4449 " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
4450 repeat;
Harald Welte9bbbfb52018-04-05 09:33:19 +02004451 }
4452 }
4453 [] PCU.receive { repeat; }
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01004454 [] T_wait.timeout {
4455 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
4456 log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '0' on TS", g_chan_nr.tn));
4457 }
Harald Welte9bbbfb52018-04-05 09:33:19 +02004458 }
4459 /* Emulate PCU asking BTS to deactivate PDCH */
4460 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
4461 alt {
4462 [] RSL.receive(tr_RSL_IPA_PDCH_DEACT_ACK(g_chan_nr)) {
4463 setverdict(pass);
4464 }
4465 [] RSL.receive { repeat; }
4466 }
4467}
4468
4469/* Activate and de-activate an IPA-style dynamic TCH/F + PDCH */
4470function f_TC_dyn_ipa_pdch_act_deact(charstring id) runs on ConnHdlr {
4471 var PCUIF_Message first_info;
4472 var integer ts_nr := g_chan_nr.tn;
4473 var integer trx_nr := 0;
4474 var integer bts_nr := 0;
4475 var integer pcu_conn_id := -1;
4476
4477 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4478
4479 f_dyn_ipa_pdch_act(pcu_conn_id, bts_nr, trx_nr);
4480 f_sleep(3.0);
4481 f_dyn_ipa_pdch_deact(pcu_conn_id, bts_nr, trx_nr);
4482
4483 setverdict(pass);
4484
4485}
4486testcase TC_dyn_ipa_pdch_act_deact() runs on test_CT {
4487 var ConnHdlrPars pars;
4488 var ConnHdlr vc_conn;
4489 f_init();
4490
4491 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
4492 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_act_deact), pars, true);
4493 vc_conn.done;
4494}
4495
4496/* try to RSL CHAN ACT a TCH/F on an IPA-style PDCH */
4497function f_TC_dyn_ipa_pdch_tchf_act(charstring id) runs on ConnHdlr {
4498 var PCUIF_Message first_info;
4499 var integer ts_nr := g_chan_nr.tn;
4500 var integer trx_nr := 0;
4501 var integer bts_nr := 0;
4502 var integer pcu_conn_id := -1;
4503
4504 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4505
4506 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_ACK(g_chan_nr),
4507 "RSL CHAN ACT");
4508 f_rsl_transceive(ts_RSL_RF_CHAN_REL(g_chan_nr), tr_RSL_RF_CHAN_REL_ACK(g_chan_nr),
4509 "RF CHAN REL", true);
4510 setverdict(pass);
4511}
4512testcase TC_dyn_ipa_pdch_tchf_act() runs on test_CT {
4513 var ConnHdlrPars pars;
4514 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004515 f_init();
Harald Welte9bbbfb52018-04-05 09:33:19 +02004516
4517 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
4518 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_tchf_act), pars, true);
4519 vc_conn.done;
4520}
4521
4522/* Activate IPA style dyn PDCH as TCH/F and then illegally try to activate it as PDCH, too */
4523function f_TC_dyn_ipa_pdch_tchf_act_pdch_act_nack(charstring id) runs on ConnHdlr {
4524 var PCUIF_Message first_info;
4525 var integer ts_nr := g_chan_nr.tn;
4526 var integer trx_nr := 0;
4527 var integer bts_nr := 0;
4528 var integer pcu_conn_id := -1;
4529
4530 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4531
4532 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_ACK(g_chan_nr),
4533 "RSL CHAN ACT");
4534
4535 RSL.send(ts_RSL_IPA_PDCH_ACT(g_chan_nr));
4536 alt {
4537 [] RSL.receive(tr_RSL_IPA_PDCH_ACT_NACK(g_chan_nr, ?));
4538 [] RSL.receive(tr_RSL_IPA_PDCH_ACT_ACK(g_chan_nr, ?)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004539 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PDCH ACT ACK");
Harald Welte9bbbfb52018-04-05 09:33:19 +02004540 }
4541 [] RSL.receive { repeat; }
4542 }
4543
4544 f_rsl_transceive(ts_RSL_RF_CHAN_REL(g_chan_nr), tr_RSL_RF_CHAN_REL_ACK(g_chan_nr),
4545 "RF CHAN REL", true);
4546 setverdict(pass);
4547}
4548testcase TC_dyn_ipa_pdch_tchf_act_pdch_act_nack() runs on test_CT {
4549 var ConnHdlrPars pars;
4550 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004551 f_init();
Harald Welte9bbbfb52018-04-05 09:33:19 +02004552
4553 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
4554 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_tchf_act_pdch_act_nack), pars, true);
4555 vc_conn.done;
4556}
4557
4558/* try to RSL CHAN ACT a TCH/F on an IPA-style PDCH that's already in PDCH mode; expect NACK */
4559function f_TC_dyn_ipa_pdch_act_tchf_act_nack(charstring id) runs on ConnHdlr {
4560 var PCUIF_Message first_info;
4561 var integer ts_nr := g_chan_nr.tn;
4562 var integer trx_nr := 0;
4563 var integer bts_nr := 0;
4564 var integer pcu_conn_id := -1;
4565
4566 /* register for the TCH/F channel number */
4567 f_rslem_register(0, g_chan_nr);
4568
4569 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4570
4571 f_dyn_ipa_pdch_act(pcu_conn_id, bts_nr, trx_nr);
4572
4573 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_NACK(g_chan_nr),
4574 "RSL CHAN ACT");
4575
4576 f_dyn_ipa_pdch_deact(pcu_conn_id, bts_nr, trx_nr);
4577
4578 setverdict(pass);
4579}
4580testcase TC_dyn_ipa_pdch_act_tchf_act_nack() runs on test_CT {
4581 var ConnHdlrPars pars;
4582 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004583 f_init();
Harald Welte9bbbfb52018-04-05 09:33:19 +02004584
4585 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
4586 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_act_tchf_act_nack), pars, true);
4587 vc_conn.done;
4588}
4589
4590
Harald Welte0472ab42018-03-12 15:02:26 +01004591/***********************************************************************
4592 * LAPDm / RLL related
4593 ***********************************************************************/
4594
4595private function f_tx_lapdm(template (value) LapdmFrame l,
4596 template (value) RslLinkId link_id) runs on ConnHdlr {
4597 var octetstring l2 := enc_LapdmFrame(valueof(l));
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07004598 var template (value) SacchL1Header l1h;
4599
4600 /* TODO: we can use an extension of TTCN-3 for padding, i.e. PADDING('2B'O) */
Harald Welte0472ab42018-03-12 15:02:26 +01004601 if (valueof(link_id.c) == SACCH) {
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07004602 /* Compose dummy L1 header */
4603 l1h := ts_SacchL1Header(g_pars.l1_pars.ms_power_level, false, g_pars.l1_pars.ms_actual_ta);
4604 L1CTL.send(ts_L1CTL_DATA_REQ_SACCH(g_chan_nr, link_id, l1h, f_pad_oct(l2, 21, '2B'O)));
Pau Espin Pedrola0fb42a2018-10-10 15:56:39 +02004605 } else {
4606 /* If required, pad L2 frame with constant 0x2b filling */
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07004607 L1CTL.send(ts_L1CTL_DATA_REQ(g_chan_nr, link_id, f_pad_oct(l2, 23, '2B'O)));
Harald Welte0472ab42018-03-12 15:02:26 +01004608 }
Harald Welte0472ab42018-03-12 15:02:26 +01004609}
4610
4611type record RllTestCase {
4612 uint3_t sapi,
4613 RslLinkId link_id,
4614 octetstring l3,
4615 boolean exp
4616}
4617type record of RllTestCase RllTestCases;
4618template RllTestCase t_EITC(uint3_t sapi, RslLinkId id, octetstring l3, boolean exp) := {
4619 sapi := sapi,
4620 link_id := id,
4621 l3 := l3,
4622 exp := exp
4623}
4624
4625/* execute the same callback function with a set of different parameters (tcs) on a
4626 * variety of logical channels */
4627private function f_rll_testmatrix(RllTestCases tcs, void_fn fn) runs on test_CT {
4628 var ConnHdlrPars pars;
4629 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004630 f_init();
Harald Welte0472ab42018-03-12 15:02:26 +01004631
4632 /* test on each of the channels we have */
4633 for (var integer i := 0; i < sizeof(g_AllChanTypes); i := i+1) {
4634 pars := valueof(t_Pars(g_AllChanTypes[i], ts_RSL_ChanMode_SIGN));
4635
4636 /* test each of the test cases on the current channel */
4637 for (var integer j := 0; j < sizeof(tcs); j := j+1) {
4638 pars.spec.rll := tcs[j];
4639 log(testcasename(), ": XXX Starting ", tcs[j] , " on ", g_AllChanTypes[i]);
4640 vc_conn := f_start_handler(fn, pars);
4641 vc_conn.done;
4642 }
4643 }
4644
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004645 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte0472ab42018-03-12 15:02:26 +01004646}
4647
4648/* test if SABM on Um triggers EST IND (TS 48.058 3.1) */
4649private function f_TC_rll_est_ind(charstring id) runs on ConnHdlr {
4650 var RllTestCase tc := g_pars.spec.rll;
4651 timer T := 3.0;
4652
4653 f_l1_tune(L1CTL);
4654 RSL.clear;
4655
4656 /* activate the logical channel */
4657 f_est_dchan();
4658 L1CTL.clear;
4659
4660 f_tx_lapdm(ts_LAPDm_SABM(tc.sapi, cr_MO_CMD, true, tc.l3), tc.link_id);
4661 T.start;
4662 alt {
4663 [tc.l3 != ''O] RSL.receive(tr_RSL_EST_IND(g_chan_nr, tc.link_id, tc.l3)) {
4664 if (tc.exp) {
4665 setverdict(pass);
4666 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004667 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected EST IND with L3 in ", tc));
Harald Welte0472ab42018-03-12 15:02:26 +01004668 }
4669 }
4670 [tc.l3 == ''O] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, tc.link_id)) {
4671 if (tc.exp) {
4672 setverdict(pass);
4673 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004674 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected EST IND without L3 in ", tc));
Harald Welte0472ab42018-03-12 15:02:26 +01004675 }
4676 }
Vadim Yanitskiy35677872018-10-04 17:30:21 +07004677 /* We also expect to receive the measurements */
4678 [] as_meas_res(verify_meas := false);
Harald Welte0472ab42018-03-12 15:02:26 +01004679 [tc.exp] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004680 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for EST IND");
Harald Welte0472ab42018-03-12 15:02:26 +01004681 }
4682 [not tc.exp] T.timeout {
4683 setverdict(pass);
4684 }
4685 }
4686
4687 f_rsl_chan_deact();
4688 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
4689 f_rslem_unregister(0, g_chan_nr);
4690}
4691testcase TC_rll_est_ind() runs on test_CT {
4692 var RllTestCases tcs := {
Harald Welte7aacbbf2018-05-09 16:56:41 +02004693 /* SAPI0 establishment (contention resolution) */
Harald Welte0472ab42018-03-12 15:02:26 +01004694 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), '01020304'O, true)),
Harald Welte7aacbbf2018-05-09 16:56:41 +02004695 /* normal SAPI0 establishment */
4696 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), ''O, true)),
Harald Welte0472ab42018-03-12 15:02:26 +01004697 /* SAPI 3 doesn't support contention resolution */
4698 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), '01020304'O, false)),
4699 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), '01020304'O, false)),
4700 /* normal SAPI3 establishment on main DCCH */
4701 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true)),
4702 /* normal SAPI3 establishment on SACCH */
4703 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
4704 };
4705 f_rll_testmatrix(tcs, refers(f_TC_rll_est_ind));
4706}
4707
4708/* test if RLL EST REQ trigeres SABM on Um; UA on Um triggers EST CONF (TS 48.058 3.2) */
4709private function f_TC_rll_est_req(charstring id) runs on ConnHdlr {
4710 var RllTestCase tc := g_pars.spec.rll;
4711 var L1ctlDlMessage dl;
4712 timer T := 3.0;
4713
4714 f_l1_tune(L1CTL);
4715 RSL.clear;
4716
4717 /* activate the logical channel */
4718 f_est_dchan();
4719 L1CTL.clear;
4720
4721 /* Send a RSL EST REQ for SAPI3 on main DCCH */
4722 RSL.send(ts_RSL_EST_REQ(g_chan_nr, tc.link_id));
4723 T.start;
4724 alt {
4725 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, ?)) -> value dl {
4726 var LapdmFrame lapdm;
4727 var octetstring l2 := dl.payload.data_ind.payload;
4728 if (dl.dl_info.link_id.c == SACCH) {
4729 /* remove L1 header */
4730 l2 := substr(l2, 2, lengthof(l2)-2);
4731 }
4732 lapdm.ab := dec_LapdmFrameAB(l2);
4733 if (match(lapdm, tr_LAPDm_SABM(tc.sapi, cr_MT_CMD, true, ''O))) {
4734 setverdict(pass);
4735 } else {
4736 repeat;
4737 }
4738 }
4739 [] L1CTL.receive { repeat; }
4740 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004741 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for SABM");
Harald Welte0472ab42018-03-12 15:02:26 +01004742 }
4743 }
4744
4745 f_rsl_chan_deact();
4746 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
4747 f_rslem_unregister(0, g_chan_nr);
4748}
4749testcase TC_rll_est_req_DCCH_3() runs on test_CT {
4750 var RllTestCases tcs := {
4751 /* normal SAPI3 establishment on main DCCH */
4752 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true))//,
4753 };
4754 f_rll_testmatrix(tcs, refers(f_TC_rll_est_req));
4755}
4756testcase TC_rll_est_req_ACCH_3() runs on test_CT {
4757 var RllTestCases tcs := {
4758 /* normal SAPI3 establishment on SACCH */
4759 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
4760 }
4761 f_rll_testmatrix(tcs, refers(f_TC_rll_est_req));
4762}
4763
4764/* altstep to receive a LAPDm frame matching the given template */
4765private altstep as_l1_exp_lapdm(template LapdmFrame exp) runs on ConnHdlr {
4766 var L1ctlDlMessage dl;
4767 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, ?)) -> value dl {
4768 var LapdmFrame lapdm;
4769 var octetstring l2 := dl.payload.data_ind.payload;
4770 if (dl.dl_info.link_id.c == SACCH) {
4771 /* remove L1 header */
4772 l2 := substr(l2, 2, lengthof(l2)-2);
4773 }
4774 if (ischosen(exp.ab)) {
4775 lapdm.ab := dec_LapdmFrameAB(l2);
4776 } else if (ischosen(exp.b4)) {
4777 lapdm.b4 := dec_LapdmFrameB4(l2);
4778 } else if (ischosen(exp.bbis)) {
4779 lapdm.bbis := dec_LapdmFrameBbis(l2);
4780 }
4781 log("Rx LAPDm ", lapdm);
4782 if (match(lapdm, exp)) {
4783 setverdict(pass);
4784 } else {
4785 repeat;
4786 }
4787 }
4788 [] L1CTL.receive { repeat; }
4789}
4790private function f_l1_exp_lapdm(template LapdmFrame exp, float t := 3.0) runs on ConnHdlr {
4791 timer T := t;
4792 T.start;
4793 alt {
4794 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004795 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for LAPDm ", exp));
Harald Welte0472ab42018-03-12 15:02:26 +01004796 }
4797 [] as_l1_exp_lapdm(exp);
4798 }
4799}
4800
4801/* establish one Radio Link Layer via SABM -> UA. Use l3 for contention resolution */
4802private function f_est_rll_mo(uint3_t sapi, RslLinkId link_id, octetstring l3) runs on ConnHdlr {
4803 /* send SABM from MS -> BTS */
4804 f_tx_lapdm(ts_LAPDm_SABM(sapi, cr_MO_CMD, true, l3), link_id);
4805 /* expect RLL EST IND on Abis */
4806 alt {
4807 [l3 != ''O] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3));
4808 [l3 == ''O] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
4809 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, ?)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004810 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Failing due to RSL_ERROR_IND");
Harald Welte0472ab42018-03-12 15:02:26 +01004811 }
4812 [] RSL.receive { repeat; }
4813 }
4814 /* expect UA from BTS -> MS */
4815 f_l1_exp_lapdm(tr_LAPDm_UA(sapi, cr_MT_RSP, true, l3));
4816}
4817
4818/* test if DISC on Um triggers RLL REL IND (TS 48.058 3.3) */
4819private function f_TC_rll_rel_ind(charstring id) runs on ConnHdlr {
4820 var RllTestCase tc := g_pars.spec.rll;
4821
4822 f_l1_tune(L1CTL);
4823 RSL.clear;
4824
4825 /* activate the logical channel */
4826 f_est_dchan();
4827 L1CTL.clear;
4828
4829 /* first establish the link-layer */
4830 f_est_rll_mo(tc.sapi, tc.link_id, tc.l3);
4831
4832 /* then send the DISC */
4833 f_tx_lapdm(ts_LAPDm_DISC(tc.sapi, cr_MO_CMD, true), tc.link_id);
4834 /* ... and expect the REL IND on the RSL side */
4835 alt {
4836 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tc.link_id)) {
4837 setverdict(pass);
4838 }
Vadim Yanitskiy35677872018-10-04 17:30:21 +07004839 /* We also expect to receive the measurements */
4840 [] as_meas_res(verify_meas := false);
Harald Welte0472ab42018-03-12 15:02:26 +01004841 }
4842
4843 /* release the channel */
4844 f_rsl_chan_deact();
4845 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
4846 f_rslem_unregister(0, g_chan_nr);
4847}
4848testcase TC_rll_rel_ind_DCCH_0() runs on test_CT {
4849 var RllTestCases tcs := {
4850 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), '01020304'O, true))
4851 };
4852 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
4853}
4854
4855testcase TC_rll_rel_ind_ACCH_0() runs on test_CT {
4856 var RllTestCases tcs := {
4857 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), ''O, true))
4858 };
4859 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
4860}
4861testcase TC_rll_rel_ind_DCCH_3() runs on test_CT {
4862 var RllTestCases tcs := {
4863 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true))
4864 };
4865 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
4866}
4867testcase TC_rll_rel_ind_ACCH_3() runs on test_CT {
4868 var RllTestCases tcs := {
4869 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
4870 };
4871 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
4872}
4873
4874/* test if RLL REL REQ triggers DISC on Um; UA/DM triggers RLL REL CONF (TS 48.058 3.4) */
4875private function f_TC_rll_rel_req(charstring id) runs on ConnHdlr {
4876 var RllTestCase tc := g_pars.spec.rll;
4877 f_l1_tune(L1CTL);
4878 RSL.clear;
4879
4880 /* activate the logical channel */
4881 f_est_dchan();
4882 L1CTL.clear;
4883
4884 /* first establish the link-layer */
4885 f_est_rll_mo(tc.sapi, tc.link_id, tc.l3);
4886
4887 /* then send the REL REQ via RSL */
4888 RSL.send(ts_RSL_REL_REQ(g_chan_nr, tc.link_id, RSL_REL_MODE_NORMAL));
4889 /* ... and expect the DISC on the Um side */
4890 alt {
Harald Weltebc6199f2018-05-10 19:38:18 +02004891 [] as_l1_exp_lapdm(tr_LAPDm_DISC(tc.sapi, cr_MT_CMD, true)) {
Harald Welte0472ab42018-03-12 15:02:26 +01004892 /* FIXME: send a UA in resposne to the DISC */
4893 }
4894 }
4895
4896 /* release the channel */
4897 f_rsl_chan_deact();
4898 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
4899 f_rslem_unregister(0, g_chan_nr);
4900}
4901testcase TC_rll_rel_req() runs on test_CT {
4902 var RllTestCases tcs := {
4903 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), '01020304'O, true)),
4904 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), ''O, true)),
4905 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true)),
4906 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
4907 };
4908 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_req));
4909}
4910
4911/* test if RLL DATA REQ triggers I-frames on Um (TS 48.058 3.5) */
4912testcase TC_rll_data_req() runs on test_CT {
4913}
4914
4915/* test if I-frames on Um trigger RLL DATA IND (TS 48.058 3.6) */
4916testcase TC_rll_data_ind() runs on test_CT {
4917}
4918
4919/* test if RLL UNIT DATA REQ triggers UI-frame on Um (TS 48.058 3.7) */
4920private function f_TC_rll_ud_req(charstring id) runs on ConnHdlr {
4921 var RllTestCase tc := g_pars.spec.rll;
4922
4923 f_l1_tune(L1CTL);
4924 RSL.clear;
4925
4926 f_est_dchan();
4927 L1CTL.clear;
4928
4929 /* Send UNITDATA REQ on RSL side */
4930 RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, tc.link_id, tc.l3));
4931 /* Expect it to arrive on the other side */
4932 if (tc.link_id.c == SACCH) {
Harald Weltee613f962018-04-18 22:38:16 +02004933 f_l1_exp_lapdm(tr_LAPDm_B4_UI(tc.sapi, cr_MT_CMD, tc.l3));
Harald Welte0472ab42018-03-12 15:02:26 +01004934 } else {
Harald Weltee613f962018-04-18 22:38:16 +02004935 f_l1_exp_lapdm(tr_LAPDm_UI(tc.sapi, cr_MT_CMD, tc.l3));
Harald Welte0472ab42018-03-12 15:02:26 +01004936 }
4937
4938 /* release the channel */
4939 f_rsl_chan_deact();
4940 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
4941 f_rslem_unregister(0, g_chan_nr);
4942}
4943testcase TC_rll_unit_data_req_DCCH() runs on test_CT {
4944 var octetstring l3 := f_rnd_octstring(15);
4945 var RllTestCases tcs := {
4946 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), l3, true)),
4947 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), l3, true))
4948 };
4949 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_req));
4950}
4951testcase TC_rll_unit_data_req_ACCH() runs on test_CT {
4952 var octetstring l3 := f_rnd_octstring(19);
4953 var RllTestCases tcs := {
4954 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), l3, true)),
4955 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), l3, true))
4956 };
4957 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_req));
4958}
4959
4960/* test if UI-frames on Um trigger RLL UNIT DATA IND (TS 48.058 3.8) */
4961private function f_TC_rll_ud_ind(charstring id) runs on ConnHdlr {
4962 var RllTestCase tc := g_pars.spec.rll;
4963
4964 f_l1_tune(L1CTL);
4965 RSL.clear;
4966
4967 f_est_dchan();
4968 L1CTL.clear;
4969
4970 /* Send LAPDm UI frame. There is no B4 format in uplink! */
Harald Weltee613f962018-04-18 22:38:16 +02004971 f_tx_lapdm(ts_LAPDm_UI(tc.sapi, cr_MO_CMD, tc.l3), tc.link_id);
Harald Welte0472ab42018-03-12 15:02:26 +01004972 /* Expdct RLL UNITDATA IND on RSL side */
4973 alt {
4974 [] RSL.receive(tr_RSL_UNITDATA_IND(g_chan_nr, tc.link_id, tc.l3)) {
4975 setverdict(pass);
4976 }
4977 [] RSL.receive { repeat; }
4978 }
4979
4980 /* release the channel */
4981 f_rsl_chan_deact();
4982 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
4983 f_rslem_unregister(0, g_chan_nr);
4984}
4985testcase TC_rll_unit_data_ind_DCCH() runs on test_CT {
Stefan Sperlingc4181912018-07-25 17:03:08 +02004986 var octetstring l3 := f_rnd_octstring(20);
Harald Welte0472ab42018-03-12 15:02:26 +01004987 var RllTestCases tcs := {
4988 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), l3, true)),
4989 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), l3, true))
4990 };
4991 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_ind));
4992}
4993testcase TC_rll_unit_data_ind_ACCH() runs on test_CT {
4994 var octetstring l3 := f_rnd_octstring(18);
4995 var RllTestCases tcs := {
4996 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), l3, true)),
4997 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), l3, true))
4998 };
4999 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_ind));
5000}
5001
Harald Weltee613f962018-04-18 22:38:16 +02005002/***********************************************************************
5003 * Encryption Related
5004 ***********************************************************************/
5005
5006/* send UNITDATA_REQ from BTS to MS and expect it to arrive */
5007function f_unitdata_mt(RslLinkId link_id, octetstring l3) runs on ConnHdlr {
5008 RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, link_id, l3));
5009 if (link_id.c == SACCH) {
5010 f_l1_exp_lapdm(tr_LAPDm_B4_UI(link_id.sapi, cr_MT_CMD, l3));
5011 } else {
5012 f_l1_exp_lapdm(tr_LAPDm_UI(link_id.sapi, cr_MT_CMD, l3));
5013 }
5014}
5015
Vadim Yanitskiyad131c82018-10-04 06:18:59 +07005016/* Expect (or not expect) other kinds of messages */
5017private altstep as_rsl_any_ind(boolean exp_any) runs on ConnHdlr {
5018 [exp_any] RSL.receive { repeat; }
5019 [not exp_any] RSL.receive {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005020 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RSL message!");
Vadim Yanitskiyad131c82018-10-04 06:18:59 +07005021 }
5022}
5023
Harald Weltee613f962018-04-18 22:38:16 +02005024/* Send UI frame from MS and expect it to arrive as RLL UNITDATA IND on Abis */
Vadim Yanitskiy8d8f91c2018-10-04 06:19:45 +07005025private function f_unitdata_mo(
Vadim Yanitskiy98e03152018-10-03 18:06:06 +07005026 RslLinkId link_id,
5027 octetstring l3,
5028 boolean exp_sacch := true, /* Should tolerate SACCH messages? */
Vadim Yanitskiyb9920502018-10-03 18:29:51 +07005029 boolean exp_any := false /* Should tolerate any other RSL messages? */
Vadim Yanitskiy98e03152018-10-03 18:06:06 +07005030) runs on ConnHdlr {
Harald Weltee613f962018-04-18 22:38:16 +02005031 timer T := 3.0;
5032 f_tx_lapdm(ts_LAPDm_UI(link_id.sapi, cr_MO_CMD, l3), link_id);
5033 T.start;
5034 /* Expect RLL UNITDATA IND on RSL side */
5035 alt {
5036 [] RSL.receive(tr_RSL_UNITDATA_IND(g_chan_nr, link_id, l3)) {
5037 setverdict(pass);
5038 }
Vadim Yanitskiye0b91a72018-10-04 15:44:40 +07005039 [exp_sacch] as_meas_res(verify_meas := false);
Vadim Yanitskiyad131c82018-10-04 06:18:59 +07005040 [] as_rsl_any_ind(exp_any);
Harald Weltee613f962018-04-18 22:38:16 +02005041 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005042 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for UNIT_DATA_IND");
Harald Weltee613f962018-04-18 22:38:16 +02005043 }
Harald Weltee613f962018-04-18 22:38:16 +02005044 }
5045}
5046
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07005047/* Send I-frame from MS and expect it to arrive as RLL DATA IND on Abis */
5048private function f_data_mo(
5049 RslLinkId link_id,
5050 boolean p, uint3_t nr, uint3_t ns,
5051 octetstring l3,
5052 boolean exp_sacch := true, /* Should tolerate SACCH messages? */
Vadim Yanitskiyb9920502018-10-03 18:29:51 +07005053 boolean exp_any := false /* Should tolerate any other RSL messages? */
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07005054) runs on ConnHdlr {
5055 timer T := 3.0;
5056 f_tx_lapdm(ts_LAPDm_I(link_id.sapi, cr_MO_CMD, p, nr, ns, l3), link_id);
5057 T.start;
5058 /* Expect RLL DATA IND on RSL side */
5059 alt {
5060 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
5061 setverdict(pass);
5062 }
Vadim Yanitskiye0b91a72018-10-04 15:44:40 +07005063 [exp_sacch] as_meas_res(verify_meas := false);
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07005064 [] as_rsl_any_ind(exp_any);
5065 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005066 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for DATA_IND");
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07005067 }
5068 }
5069}
5070
Harald Weltee613f962018-04-18 22:38:16 +02005071/* Test channel activation with A5/n right from the beginning (like in assignment + hand-over) */
5072function f_TC_chan_act_encr(charstring id) runs on ConnHdlr {
5073 f_l1_tune(L1CTL);
5074 f_est_dchan(true);
5075
5076 /* now we actually need to transmit some data both ways to check if the encryption works */
5077 var L1ctlDlMessage dl;
5078
Stefan Sperling603d98e2018-07-25 16:47:28 +02005079 var octetstring l3 := f_rnd_octstring(20);
Harald Weltee613f962018-04-18 22:38:16 +02005080 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
5081
5082 /* send UNITDATA_REQ from BTS to MS and expect it to arrive */
5083 f_unitdata_mt(link_id, l3);
5084
5085 /* Send UI frame from MS and expect it to arrive as RLL UNITDATA IND on Abis */
5086 f_unitdata_mo(link_id, l3);
5087
5088 /* release the channel */
5089 f_rsl_chan_deact();
5090 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5091 f_rslem_unregister(0, g_chan_nr);
5092}
5093testcase TC_chan_act_a51() runs on test_CT {
5094 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
5095 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_1, f_rnd_octstring(8)));
5096 f_testmatrix_each_chan(pars, refers(f_TC_chan_act_encr));
5097}
5098testcase TC_chan_act_a52() runs on test_CT {
5099 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
5100 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_2, f_rnd_octstring(8)));
5101 f_testmatrix_each_chan(pars, refers(f_TC_chan_act_encr));
5102}
5103testcase TC_chan_act_a53() runs on test_CT {
5104 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
5105 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_3, f_rnd_octstring(8)));
5106 f_testmatrix_each_chan(pars, refers(f_TC_chan_act_encr));
5107}
5108
Eric Wildf1827a72019-05-28 17:37:35 +02005109/* Test channel activation with A5/n right from the beginning and RSL MODE MODIFY
5110 which should break the en/decryption on purpose by supplying a new key that is unknown to the MS*/
5111function f_TC_rsl_modify_encr(charstring id) runs on ConnHdlr {
5112 f_l1_tune(L1CTL);
5113 f_est_dchan(true);
5114
5115 /* now we actually need to transmit some data both ways to check if the encryption works */
5116 var L1ctlDlMessage dl;
5117
5118 var octetstring l3 := f_rnd_octstring(20);
5119 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
5120
5121 /* send UNITDATA_REQ from BTS to MS and expect it to arrive */
5122 f_unitdata_mt(link_id, l3);
5123
5124 /* Send UI frame from MS and expect it to arrive as RLL UNITDATA IND on Abis */
5125 f_unitdata_mo(link_id, l3);
5126
5127 var RSL_Message rsl;
5128 rsl := valueof(ts_RSL_MODE_MODIFY_REQ(g_chan_nr, valueof(ts_RSL_ChanMode_SIGN(false))));
5129
5130 /* modify key to break proper encryption */
5131 g_pars.encr.key := f_rnd_octstring(8);
5132 var RSL_IE ei := valueof(t_RSL_IE(RSL_IE_ENCR_INFO, RSL_IE_Body:{encr_info := g_pars.encr}));
5133 rsl.ies := rsl.ies & { ei };
5134 RSL.send(rsl);
5135
5136 timer T0 := 1.0;
5137 T0.start;
5138 /* Expect RSL MODIFY ACK */
5139 alt {
5140 [] RSL.receive(tr_RSL_MODE_MODIFY_ACK(g_chan_nr)) {}
5141 [] RSL.receive(tr_RSL_MODE_MODIFY_NACK(g_chan_nr, ?)) {
5142 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,"MODE MODIFY NACK");
5143 }
5144 [] T0.timeout {
5145 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for MODE MODIFY (N)ACK");
5146 }
5147 }
5148
5149 var octetstring l3msg := f_rnd_octstring(15);
5150 timer T1 := 3.0;
5151 /* Send UI frame from MS, do not expect it to arrive as RLL UNITDATA IND on Abis
5152 due to broken encryption */
5153 f_tx_lapdm(ts_LAPDm_UI(link_id.sapi, cr_MO_CMD, l3msg), link_id);
5154 T1.start;
5155 alt {
5156 [] RSL.receive(tr_RSL_UNITDATA_IND(g_chan_nr, link_id, l3msg)) {
5157 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "BTS shouldn't be able to decrypt after key change")
5158 }
5159 [] T1.timeout {
5160 setverdict(pass);
5161 }
5162 }
5163
5164 /* release the channel */
5165 f_rsl_chan_deact();
5166 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5167 f_rslem_unregister(0, g_chan_nr);
5168}
5169testcase TC_rsl_modify_encr() runs on test_CT {
5170 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
5171 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_1, f_rnd_octstring(8)));
5172 f_testmatrix_each_chan(pars, refers(f_TC_rsl_modify_encr));
5173}
Harald Weltee613f962018-04-18 22:38:16 +02005174
5175/* Test unencrypted channel activation followed by explicit ENCR CMD later */
5176function f_TC_encr_cmd(charstring id) runs on ConnHdlr {
5177 /* L3 payload doesn't matter, as it is passed transparently */
5178 var BIT3 l3_alg_id := f_alg_id_to_l3(g_pars.encr.alg_id);
5179 var octetstring l3 := enc_PDU_ML3_NW_MS(valueof(ts_RRM_CiphModeCmd(l3_alg_id)));
5180 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
5181
5182 f_l1_tune(L1CTL);
5183
5184 /* first establish a dedicated channel in the clear */
5185 f_est_dchan(false);
5186
5187 /* Establish ABM */
5188 f_est_rll_mo(link_id.sapi, link_id, '23420815'O);
5189
5190 /* then send the RSL ENCR CMD with an actual RR CIPH MOD CMD inside */
5191 RSL.send(ts_RSL_ENCR_CMD(g_chan_nr, link_id, g_pars.encr.alg_id, g_pars.encr.key, l3));
5192 /* expect the L3 to arrive still unencrypted on the MS side */
5193 f_l1_exp_lapdm(tr_LAPDm_I(link_id.sapi, cr_MT_CMD, ?, ?, ?, l3));
5194
5195 /* configure L1 to apply ciphering */
5196 var uint8_t alg_id := f_alg_id_to_l1ctl(g_pars.encr.alg_id);
5197 f_L1CTL_CRYPTO_REQ(L1CTL, g_pars.chan_nr, alg_id, g_pars.encr.key);
5198
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07005199 /* send first ciphered I-frame in response and expect it on RSL */
5200 f_data_mo(link_id, true, 1, 0, '0a0b0c0d'O, exp_sacch := true);
Harald Weltee613f962018-04-18 22:38:16 +02005201
5202 /* now the BTS code should have detected the first properly encrypted uplink I-frame,
5203 * and hence enable encryption also on the downlink */
5204
5205 /* expect bi-directional communication work in encrypted mode */
5206 f_unitdata_mo(link_id, f_rnd_octstring(15));
5207 f_unitdata_mt(link_id, f_rnd_octstring(15));
5208
5209 /* release the channel */
5210 f_rsl_chan_deact();
5211 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5212 f_rslem_unregister(0, g_chan_nr);
5213}
5214testcase TC_encr_cmd_a51() runs on test_CT {
5215 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
5216 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_1, f_rnd_octstring(8)));
5217 f_testmatrix_each_chan(pars, refers(f_TC_encr_cmd));
5218}
5219testcase TC_encr_cmd_a52() runs on test_CT {
5220 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
5221 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_2, f_rnd_octstring(8)));
5222 f_testmatrix_each_chan(pars, refers(f_TC_encr_cmd));
5223}
5224testcase TC_encr_cmd_a53() runs on test_CT {
5225 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
5226 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_3, f_rnd_octstring(8)));
5227 f_testmatrix_each_chan(pars, refers(f_TC_encr_cmd));
5228}
5229
5230private function f_assert_lapdm(octetstring enc, template LapdmFrame exp_match, charstring name := "") {
5231 var LapdmFrame lf;
5232 var octetstring reenc;
5233
5234 /* decode the LAPDm frame */
5235 if (ischosen(exp_match.ab)) {
5236 lf.ab := dec_LapdmFrameAB(enc);
5237 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005238 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "unsupported frame type");
Harald Weltee613f962018-04-18 22:38:16 +02005239 }
5240
5241 /* check if decoder result matches expectation */
5242 if (not match(lf, exp_match)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005243 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str(name, ": decoded LAPDm doesn't match"));
Harald Weltee613f962018-04-18 22:38:16 +02005244 } else {
5245 log(name, ": matched");
5246 setverdict(pass);
5247 }
5248
5249 /* test if re-encoded frame equals original input */
5250 reenc := enc_LapdmFrame(lf);
5251 if (enc != reenc) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005252 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str(name, ": re-encoded LAPDm frame doesn't match"));
Harald Weltee613f962018-04-18 22:38:16 +02005253 } else {
5254 setverdict(pass);
5255 }
5256}
5257
5258testcase TC_lapdm_selftest() runs on test_CT {
5259 f_assert_lapdm('030301'O, tr_LAPDm_UI(0, true, ''O), "ui_s0_empty");
5260 f_assert_lapdm('0F0301'O, tr_LAPDm_UI(3, true, ''O), "ui_s3_empty");
5261 f_assert_lapdm('013F01'O, tr_LAPDm_SABM(0, false, true, ''O), "sabm_s0_empty");
5262 f_assert_lapdm('013F1123420815'O, tr_LAPDm_SABM(0, false, true, '23420815'O), "sabm_s0_l3");
5263 f_assert_lapdm('03E101'O, tr_LAPDm_RR(0, true, false, 7), "rr_s0_7");
5264 f_assert_lapdm('03000d063505'O, tr_LAPDm_I(0, true, false, 0, 0, '063505'O), "I/0/0");
5265 f_assert_lapdm('03e00d063505'O, tr_LAPDm_I(0, true, false, 7, 0, '063505'O), "I/7/0");
5266}
5267
Stefan Sperling4880be42018-08-07 18:12:59 +02005268/***********************************************************************
5269 * DTX Related (see GSM 05.08, section 8.3)
5270 ***********************************************************************/
5271
5272/* XXX These functions must be kept in sync with g_AllChannels defined on test_CT. */
5273function f_g_chan_is_tchf() runs on ConnHdlr return boolean {
5274 return (g_chan_nr == valueof(ts_RslChanNr_Bm(1)) or
5275 g_chan_nr == valueof(ts_RslChanNr_Bm(2)) or
5276 g_chan_nr == valueof(ts_RslChanNr_Bm(3)) or
5277 g_chan_nr == valueof(ts_RslChanNr_Bm(4)));
5278}
5279function f_g_chan_is_tchh() runs on ConnHdlr return boolean {
5280 return (g_chan_nr == valueof(ts_RslChanNr_Lm(5,0)) or
5281 g_chan_nr == valueof(ts_RslChanNr_Lm(5,1)));
5282}
5283function f_g_chan_is_sdcch4() runs on ConnHdlr return boolean {
5284 return (g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,0)) or
5285 g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,1)) or
5286 g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,2)) or
5287 g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,3)));
5288}
5289function f_g_chan_is_sdcch8() runs on ConnHdlr return boolean {
5290 return (g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,0)) or
5291 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,1)) or
5292 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,2)) or
5293 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,3)) or
5294 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,4)) or
5295 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,5)) or
5296 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,6)) or
5297 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,7)));
5298}
5299
5300function f_test_l2_fill_frames(boolean dtxd) runs on ConnHdlr {
5301 var L1ctlDlMessage dl;
5302 var octetstring l2_fill_frame := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O;
5303 var octetstring l2_fill_frame_sacch := substr(l2_fill_frame, 0, lengthof(l2_fill_frame) - 2);
5304 var GsmFrameNumber first_fn;
5305 var boolean is_first_frame := true;
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005306 var integer nfill_frames_sacch := 0;
5307 var integer nfill_frames_nonsacch := 0;
5308 var integer expected_fill_frames := 10000; /* initial value causes test failure if not overridden */
Stefan Sperling4880be42018-08-07 18:12:59 +02005309 /* Frames numbers (mod 104) for which a fill frame is expected on TCHF if DTX is enabled. */
5310 var Integers required_tdma_frames_dtx_tchf := { 52, 53, 54, 55, 56, 57, 58, 59 };
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005311 const integer frame_dtx_tchf_mod := 104;
5312 /* Frame numbers (mod 104) for which a fill frame is expected at the L1SAP level,
5313 * which operates in terms of blocks rather than frames. */
5314 var Integers required_tdma_blocks_dtx_tchf := { 52, 56 };
5315 const integer block_dtx_tchf_mod := 26;
Stefan Sperling4880be42018-08-07 18:12:59 +02005316 timer T := 5.0;
5317
5318 f_l1_tune(L1CTL);
5319 RSL.clear;
5320 L1CTL.clear;
5321
5322 /* activate TCHF signalling channel */
5323 f_est_dchan(false);
5324
5325 T.start;
5326 alt {
5327 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, ?)) -> value dl {
5328 var GsmFrameNumber fn := dl.dl_info.frame_nr;
5329 var octetstring l2 := dl.payload.data_ind.payload;
5330
5331 if (is_first_frame) {
5332 is_first_frame := false;
5333 first_fn := dl.dl_info.frame_nr;
5334 }
5335
5336 if (dl.dl_info.link_id.c == SACCH) {
5337 l2 := substr(l2, 2, lengthof(l2) - 2); /* remove L1 header */
5338 if (not match(l2_fill_frame_sacch, l2)) {
5339 repeat;
5340 }
5341 } else if (not match(l2_fill_frame, l2)) {
5342 repeat;
5343 }
5344
5345 if (dtxd) {
5346 if (not f_g_chan_is_tchf()) {
5347 T.stop;
5348 f_rsl_chan_deact();
5349 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005350 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received fill frame on non-TCH/F channel; DTX is only allowed on TCH/F!");
Stefan Sperling4880be42018-08-07 18:12:59 +02005351 }
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005352 if (fn > first_fn + frame_dtx_tchf_mod) {
Stefan Sperling4880be42018-08-07 18:12:59 +02005353 T.stop;
5354 f_rsl_chan_deact();
5355 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005356
5357 /* With DTX enabled we can expect at least 3 fill frames for every 104 frames.
5358 * 2 SACCH, 1 TCH/F */
5359 expected_fill_frames := 3;
5360
5361 if (nfill_frames_sacch + nfill_frames_nonsacch < expected_fill_frames) {
5362 log("received only ", nfill_frames_sacch, "+", nfill_frames_nonsacch,
5363 " (SACCH+other) out of ", expected_fill_frames, " expected fill frames");
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005364 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Not enough fill frames received");
Stefan Sperling4880be42018-08-07 18:12:59 +02005365 } else {
5366 setverdict(pass);
5367 }
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005368 } else {
5369 if (dl.dl_info.link_id.c == SACCH) {
5370 nfill_frames_sacch := nfill_frames_sacch + 1;
Stefan Sperling4880be42018-08-07 18:12:59 +02005371 repeat;
5372 }
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005373 /* On DTX TCH/F channels, fill frames occur only for specific frame numbers mod 104.
5374 * Furthermore, the L1SAP layer gives us frame numbers for the start of a block so
5375 * we should only see the subset of frames numbers which correspond to a block boundary.
5376 * TCH/F blocks are defined to start at 0,4,8,13,17,21 (modulo 26) */
5377 for (var integer i := 0; i < lengthof(required_tdma_blocks_dtx_tchf); i := i + 1) {
5378 if (fn mod frame_dtx_tchf_mod == required_tdma_blocks_dtx_tchf[i]) {
5379 nfill_frames_nonsacch := nfill_frames_nonsacch + 1;
5380 repeat;
5381 }
5382 }
5383 log("Received DTX TCH fill frame with bad frame number: ", fn,
5384 " (mod ", frame_dtx_tchf_mod, ": ", fn mod frame_dtx_tchf_mod, ")",
5385 " (mod ", block_dtx_tchf_mod, ": ", fn mod block_dtx_tchf_mod, ")");
5386 f_rsl_chan_deact();
5387 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005388 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected L2 fill frame received on Um");
Stefan Sperling4880be42018-08-07 18:12:59 +02005389 }
Stefan Sperling4880be42018-08-07 18:12:59 +02005390 } else {
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005391 if (dl.dl_info.link_id.c == SACCH) {
5392 nfill_frames_sacch := nfill_frames_sacch + 1;
5393 } else {
5394 nfill_frames_nonsacch := nfill_frames_nonsacch + 1;
5395 }
5396 if (fn > first_fn + frame_dtx_tchf_mod) {
Stefan Sperling4880be42018-08-07 18:12:59 +02005397 T.stop;
5398 if (f_g_chan_is_tchf()) {
5399 /* Without DTX we can expect 25 fill frames for every 104 frames.
5400 * (24 FACCH + 1 SACCH filling) */
5401 expected_fill_frames := 25;
5402 } else if (f_g_chan_is_tchh()) {
5403 /* We can expect 2 fill frames for every 104 frames. */
5404 expected_fill_frames := 2;
5405 } else if (f_g_chan_is_sdcch4() or f_g_chan_is_sdcch8()) {
5406 /* We can expect 5 fill frames for every 104 frames. */
5407 expected_fill_frames := 5;
5408 } else {
5409 f_rsl_chan_deact();
5410 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005411 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unknown channel type");
Stefan Sperling4880be42018-08-07 18:12:59 +02005412 }
5413
5414 f_rsl_chan_deact();
5415 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005416
5417 if (nfill_frames_sacch + nfill_frames_nonsacch >= expected_fill_frames) {
Stefan Sperling4880be42018-08-07 18:12:59 +02005418 setverdict(pass);
5419 } else {
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02005420 log("received only ", nfill_frames_sacch, "+", nfill_frames_nonsacch,
5421 " (SACCH+other) out of ", expected_fill_frames, " expected fill frames");
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005422 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Not enough fill frames received");
Stefan Sperling4880be42018-08-07 18:12:59 +02005423 }
5424 } else {
5425 repeat;
5426 }
5427 }
5428 }
5429 [] L1CTL.receive { repeat; }
5430 [] T.timeout {
5431 f_rsl_chan_deact();
5432 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005433 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for L2 fill frames on Um");
Stefan Sperling4880be42018-08-07 18:12:59 +02005434 }
5435 }
5436}
5437
5438function f_TC_tch_sign_l2_fill_frame(charstring id) runs on ConnHdlr {
5439 f_test_l2_fill_frames(false);
5440}
5441
5442function f_TC_tch_sign_l2_fill_frame_dtxd(charstring id) runs on ConnHdlr {
5443 f_test_l2_fill_frames(true);
5444}
5445
5446function f_tch_sign_l2_fill_frame(boolean dtxd) runs on test_CT {
5447 var ConnHdlr vc_conn;
5448 var ConnHdlrPars pars;
5449 pars.t_guard := 60.0;
Harald Welte10474062019-05-30 16:48:17 +02005450 f_init();
Stefan Sperling4880be42018-08-07 18:12:59 +02005451 for (var integer i := 0; i < sizeof(g_AllChannels); i := i + 1) {
5452 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN(dtxd)));
5453 if (dtxd) {
5454 if (i >= 4) { /* DTX is only allowed on TCH/F */
5455 break;
5456 }
5457 vc_conn := f_start_handler(refers(f_TC_tch_sign_l2_fill_frame_dtxd), pars);
5458 } else {
5459 vc_conn := f_start_handler(refers(f_TC_tch_sign_l2_fill_frame), pars);
5460 }
5461 vc_conn.done;
5462 }
5463}
5464
5465/* Verify that L2 fill frames are sent on TCH in signaling mode if
5466 * there is nothing to transmit while DTX is disabled on downlink. */
5467testcase TC_tch_sign_l2_fill_frame() runs on test_CT {
5468 f_tch_sign_l2_fill_frame(false);
5469}
5470
5471/* Verify that particular L2 fill frames are sent on TCH in signaling mode if
5472 * there is nothing to transmit while DTX is enabled on downlink. */
5473testcase TC_tch_sign_l2_fill_frame_dtxd() runs on test_CT {
5474 f_tch_sign_l2_fill_frame(true);
5475}
Harald Welte0472ab42018-03-12 15:02:26 +01005476
Stefan Sperling0ec1c262018-10-15 15:12:52 +02005477testcase TC_chopped_ipa_ping() runs on test_CT {
5478 IPA_Testing.f_run_TC_chopped_ipa_ping(mp_rsl_ip, mp_rsl_port, LISTEN_FOR_CLIENT);
5479}
5480
Stefan Sperlingaa1e60f2018-10-15 16:34:07 +02005481testcase TC_chopped_ipa_payload() runs on test_CT {
5482 IPA_Testing.f_run_TC_chopped_ipa_payload(mp_rsl_ip, mp_rsl_port, LISTEN_FOR_CLIENT);
5483}
5484
Harald Welte0472ab42018-03-12 15:02:26 +01005485/* test generation of RLL ERR IND based on Um errors (TS 48.058 3.9) */
5486/* protocol error as per 44.006 */
5487/* link layer failure (repetition of I-frame N200 times without ACK */
5488/* repetition of SABM or DISC N200 times without ACK */
5489/* receptiom of SABM in multi-frame established state */
5490
5491
Harald Welte68e495b2018-02-25 00:05:57 +01005492/* TODO Areas:
5493
5494* channel activation
5495** with BS_Power / MS_Power, bypassing power control loop
5496** on primary vs. secondary TRX
Harald Welte68e495b2018-02-25 00:05:57 +01005497** with timing advance from initial activation on
5498* mode modify
5499** encryption
5500** multirate
5501* check DEACTIVATE SACCH
Harald Welte68e495b2018-02-25 00:05:57 +01005502** unsupported algorithm
5503* handover detection
Harald Welte68e495b2018-02-25 00:05:57 +01005504* BS Power Control
5505* Physical Context
Harald Welte68e495b2018-02-25 00:05:57 +01005506* RF resource ind
Harald Welte68e495b2018-02-25 00:05:57 +01005507* error handling
Harald Welte68e495b2018-02-25 00:05:57 +01005508** IE duplicated?
Harald Welte883340c2018-02-28 18:59:29 +01005509* PCU interface
Harald Welte883340c2018-02-28 18:59:29 +01005510** DATA_IND from BTS->PCU
5511** verification of PCU-originated DATA_REQ arrival on Um/MS side
Harald Welte68e495b2018-02-25 00:05:57 +01005512
5513*/
Harald Welte70767382018-02-21 12:16:40 +01005514
5515control {
5516 execute( TC_chan_act_stress() );
5517 execute( TC_chan_act_react() );
5518 execute( TC_chan_deact_not_active() );
5519 execute( TC_chan_act_wrong_nr() );
Harald Welte629cc6b2018-03-11 17:19:05 +01005520 execute( TC_deact_sacch() );
Harald Welteea17b912018-03-11 22:29:31 +01005521 execute( TC_sacch_filling() );
5522 execute( TC_sacch_info_mod() );
Harald Welte075d84c2018-03-12 13:07:24 +01005523 execute( TC_sacch_multi() );
Harald Welte55700662018-03-12 13:15:43 +01005524 execute( TC_sacch_multi_chg() );
Harald Weltec8d363c2019-05-19 20:36:48 +02005525 execute( TC_sacch_chan_act() );
Harald Welte8b01c792019-05-19 22:51:25 +02005526 execute( TC_sacch_chan_act_ho_async() );
5527 execute( TC_sacch_chan_act_ho_sync() );
Harald Welte8c24c2b2018-02-26 08:31:31 +01005528 execute( TC_rach_content() );
5529 execute( TC_rach_count() );
Harald Welte54a2a2d2018-02-26 09:14:05 +01005530 execute( TC_rach_max_ta() );
Vadim Yanitskiy7c2c10c2019-05-31 20:42:01 +07005531 execute( TC_ho_rach() );
Harald Welte3453ab42019-05-24 21:19:58 +02005532 execute( TC_rach_load_idle_thresh0() );
5533 execute( TC_rach_load_idle_below_thresh() );
5534 execute( TC_rach_load_count() );
Harald Welte70767382018-02-21 12:16:40 +01005535 execute( TC_meas_res_sign_tchf() );
5536 execute( TC_meas_res_sign_tchh() );
5537 execute( TC_meas_res_sign_sdcch4() );
5538 execute( TC_meas_res_sign_sdcch8() );
Harald Welte685d5982018-02-27 20:42:05 +01005539 execute( TC_meas_res_sign_tchh_toa256() );
Philipp Maier4d1e9c92018-12-20 11:11:56 +01005540 execute( TC_rsl_ms_pwr_ctrl() );
Eric Wilde57e1a62019-05-28 13:30:55 +02005541 execute( TC_rsl_chan_initial_ms_pwr() );
Eric Wild6833cc92019-05-23 19:34:44 +02005542 execute( TC_rsl_chan_initial_ta() );
Eric Wildf1827a72019-05-28 17:37:35 +02005543 execute( TC_rsl_modify_encr() );
Harald Welte70767382018-02-21 12:16:40 +01005544 execute( TC_conn_fail_crit() );
Harald Welte68e495b2018-02-25 00:05:57 +01005545 execute( TC_paging_imsi_80percent() );
5546 execute( TC_paging_tmsi_80percent() );
5547 execute( TC_paging_imsi_200percent() );
5548 execute( TC_paging_tmsi_200percent() );
Harald Welte01d982c2018-02-25 01:31:40 +01005549 execute( TC_rsl_protocol_error() );
5550 execute( TC_rsl_mand_ie_error() );
5551 execute( TC_rsl_ie_content_error() );
Harald Welte48494ca2018-02-25 16:59:50 +01005552 execute( TC_si_sched_default() );
Harald Welte0cae4552018-03-09 22:20:26 +01005553 execute( TC_si_sched_1() );
Harald Welte48494ca2018-02-25 16:59:50 +01005554 execute( TC_si_sched_2bis() );
5555 execute( TC_si_sched_2ter() );
5556 execute( TC_si_sched_2ter_2bis() );
5557 execute( TC_si_sched_2quater() );
5558 execute( TC_si_sched_13() );
5559 execute( TC_si_sched_13_2bis_2ter_2quater() );
Harald Weltea871a382018-02-25 02:03:14 +01005560 execute( TC_ipa_dlcx_not_active() );
Harald Weltea3f1df92018-02-25 12:49:55 +01005561 execute( TC_ipa_crcx_twice_not_active() );
5562 execute( TC_ipa_crcx_mdcx_dlcx_not_active() );
Harald Welte3ae11da2018-02-25 13:36:06 +01005563 execute( TC_ipa_crcx_mdcx_mdcx_dlcx_not_active() );
Harald Welte9912eb52018-02-25 13:30:15 +01005564 execute( TC_ipa_crcx_sdcch_not_active() );
Harald Welte883340c2018-02-28 18:59:29 +01005565
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01005566 if (mp_pcu_socket != "") {
5567 execute( TC_pcu_act_req() );
5568 execute( TC_pcu_act_req_wrong_ts() );
5569 execute( TC_pcu_act_req_wrong_bts() );
5570 execute( TC_pcu_act_req_wrong_trx() );
5571 execute( TC_pcu_deact_req() );
5572 execute( TC_pcu_deact_req_wrong_ts() );
5573 execute( TC_pcu_ver_si13() );
Harald Weltead033dc2019-05-25 17:28:16 +02005574 if (mp_l1_supports_gprs) {
5575 execute( TC_pcu_data_req_pdtch() );
5576 execute( TC_pcu_data_req_ptcch() );
Harald Welte7162a612019-05-26 12:56:09 +02005577 execute( TC_pcu_data_req_wrong_bts() );
5578 execute( TC_pcu_data_req_wrong_trx() );
5579 execute( TC_pcu_data_req_wrong_ts() );
5580 execute( TC_pcu_data_req_ts_inactive() );
Harald Weltead033dc2019-05-25 17:28:16 +02005581 }
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01005582 execute( TC_pcu_data_req_agch() );
Harald Welte928622b2019-05-26 13:22:59 +02005583 execute( TC_pcu_data_req_pch() );
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01005584 execute( TC_pcu_data_req_imm_ass_pch() );
5585 execute( TC_pcu_rach_content() );
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +07005586 execute( TC_pcu_ext_rach_content() );
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01005587 execute( TC_pcu_paging_from_rsl() );
Harald Welted66c9b82019-05-25 09:03:15 +02005588 execute( TC_pcu_time_ind() );
Harald Welte4832c862019-05-25 14:57:18 +02005589 execute( TC_pcu_rts_req() );
Harald Welte07bd2d22019-05-25 11:03:30 +02005590 execute( TC_pcu_oml_alert() );
Harald Welteeaa9a862019-05-26 23:01:08 +02005591 execute( TC_pcu_rr_suspend() );
Harald Weltea2e0e942019-05-27 18:12:53 +02005592 execute( TC_pcu_socket_connect_multi() );
Harald Weltec8effb72019-05-27 18:23:04 +02005593 execute( TC_pcu_socket_reconnect() );
Harald Weltebe030482019-05-27 22:29:35 +02005594 execute( TC_pcu_socket_noconnect_nosi3gprs() );
5595 execute( TC_pcu_socket_connect_si3gprs() );
5596 execute( TC_pcu_socket_disconnect_nosi3gprs() );
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01005597 } else {
5598 log("PCU socket path not available, skipping PCU tests");
5599 }
Harald Welte3d04ae62018-04-04 20:29:05 +02005600
5601 execute( TC_dyn_osmo_pdch_act_deact() );
5602 execute( TC_dyn_osmo_pdch_unsol_deact() );
5603 execute( TC_dyn_osmo_pdch_double_act() );
5604 execute( TC_dyn_osmo_pdch_tchf_act() );
5605 execute( TC_dyn_osmo_pdch_tchh_act() );
Harald Welte9bbbfb52018-04-05 09:33:19 +02005606 execute( TC_dyn_ipa_pdch_act_deact() );
5607 execute( TC_dyn_ipa_pdch_tchf_act() );
5608 execute( TC_dyn_ipa_pdch_tchf_act_pdch_act_nack() );
5609 execute( TC_dyn_ipa_pdch_act_tchf_act_nack() );
Harald Welte0472ab42018-03-12 15:02:26 +01005610
5611 execute( TC_rll_est_ind() );
5612 execute( TC_rll_est_req_DCCH_3() );
5613 execute( TC_rll_est_req_ACCH_3() );
5614 execute( TC_rll_rel_ind_DCCH_0() );
5615 execute( TC_rll_rel_ind_DCCH_3() );
5616 execute( TC_rll_rel_ind_ACCH_0() );
5617 execute( TC_rll_rel_ind_ACCH_3() );
5618 execute( TC_rll_rel_req() );
5619 execute( TC_rll_unit_data_req_DCCH() );
5620 execute( TC_rll_unit_data_req_ACCH() );
5621 execute( TC_rll_unit_data_ind_DCCH() );
5622 execute( TC_rll_unit_data_ind_ACCH() );
Harald Weltee613f962018-04-18 22:38:16 +02005623
5624 execute( TC_chan_act_a51() );
5625 execute( TC_chan_act_a52() );
5626 execute( TC_chan_act_a53() );
5627 execute( TC_encr_cmd_a51() );
5628 execute( TC_encr_cmd_a52() );
5629 execute( TC_encr_cmd_a53() );
5630
Harald Welteee25aae2019-05-19 14:32:37 +02005631 execute( TC_err_rep_wrong_mdisc() );
5632 execute( TC_err_rep_wrong_msg_type() );
5633 execute( TC_err_rep_wrong_sequence() );
5634
Harald Weltee613f962018-04-18 22:38:16 +02005635 execute( TC_lapdm_selftest() );
Stefan Sperling4880be42018-08-07 18:12:59 +02005636
5637 execute( TC_tch_sign_l2_fill_frame() );
5638 execute( TC_tch_sign_l2_fill_frame_dtxd() );
Stefan Sperling0ec1c262018-10-15 15:12:52 +02005639
5640 execute( TC_chopped_ipa_ping() );
Stefan Sperlingaa1e60f2018-10-15 16:34:07 +02005641 execute( TC_chopped_ipa_payload() );
Harald Welte70767382018-02-21 12:16:40 +01005642}
5643
5644
5645}