blob: 012327e85ffb8ed32495596dcb96124d5dcdab86 [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;
Vadim Yanitskiy5d2cf442020-05-02 16:49:17 +070032import from GSM_RestOctets all;
Harald Welte82ccef72018-02-25 16:17:33 +010033import from GSM_SystemInformation all;
Harald Welte70767382018-02-21 12:16:40 +010034import from L1CTL_PortType all;
35import from L1CTL_Types all;
36import from LAPDm_Types all;
Harald Weltead033dc2019-05-25 17:28:16 +020037import from LAPDm_RAW_PT all;
Harald Welte70767382018-02-21 12:16:40 +010038import from Osmocom_CTRL_Adapter all;
Neels Hofmeyr6a84b232018-04-03 19:12:36 +020039import from Osmocom_CTRL_Functions all;
Harald Welte70767382018-02-21 12:16:40 +010040
41import from RSL_Types all;
Harald Welte7484fc42018-02-24 14:09:45 +010042import from IPA_Types all;
Harald Welte70767382018-02-21 12:16:40 +010043import from IPA_Emulation all;
Stefan Sperling0ec1c262018-10-15 15:12:52 +020044import from IPA_Testing all;
Harald Welte70767382018-02-21 12:16:40 +010045import from RSL_Emulation all;
46
47import from IPL4asp_Types all;
48import from TRXC_Types all;
49import from TRXC_CodecPort all;
50import from TRXC_CodecPort_CtrlFunct all;
51
Harald Welte883340c2018-02-28 18:59:29 +010052import from PCUIF_Types all;
53import from PCUIF_CodecPort all;
Harald Weltea2e0e942019-05-27 18:12:53 +020054import from UD_Types all;
Harald Welte883340c2018-02-28 18:59:29 +010055
Harald Welte7484fc42018-02-24 14:09:45 +010056import from MobileL3_CommonIE_Types all;
Harald Welte68e495b2018-02-25 00:05:57 +010057import from MobileL3_RRM_Types all;
58import from MobileL3_Types all;
59import from L3_Templates all;
Harald Welteeaa9a862019-05-26 23:01:08 +020060import from L3_Common all;
61import from MobileL3_GMM_SM_Types all;
Harald Welte7484fc42018-02-24 14:09:45 +010062
Harald Welte8da48242018-02-27 20:41:32 +010063import from Osmocom_VTY_Functions all;
64import from TELNETasp_PortType all;
Harald Welte2f2b2b72019-05-31 22:24:57 +020065import from BTS_Tests_LAPDm all;
Harald Welte8da48242018-02-27 20:41:32 +010066
Harald Welte505cf9b2018-09-15 17:47:23 +030067friend module BTS_Tests_SMSCB;
Harald Weltead033dc2019-05-25 17:28:16 +020068friend module BTS_Tests_virtphy;
Harald Welte2f2b2b72019-05-31 22:24:57 +020069friend module BTS_Tests_LAPDm;
Pau Espin Pedrol5a012ee2020-02-06 19:33:22 +010070friend module BTS_Tests_perf;
Harald Welte505cf9b2018-09-15 17:47:23 +030071
Harald Welte70767382018-02-21 12:16:40 +010072/* The tests assume a BTS with the following timeslot configuration:
73 * TS0 : Combined CCCH + SDCCH/4
Harald Welte3d04ae62018-04-04 20:29:05 +020074 * TS1 : TCH/F
75 * TS2 : TCH/F
76 * TS3 : TCH/F_PDCH (IPA Style)
77 * TS4 : TCH/F_TCH/H_PDCH (Osmocom Style)
Harald Welte70767382018-02-21 12:16:40 +010078 * TS5 : TCH/H
79 * TS6 : SDCCH/8
80 * TS7 : PDCH
81 */
82
83modulepar {
84 charstring mp_rsl_ip := "127.0.0.2";
85 integer mp_rsl_port := 3003;
86 integer mp_trx0_arfcn := 871;
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +070087 integer mp_trx1_arfcn := 873;
88 integer mp_trx2_arfcn := 875;
89 integer mp_trx3_arfcn := 877;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +070090 charstring mp_bts_trxc_ip := "127.0.0.1";
91 integer mp_bts_trxc_port := 5701;
Harald Welte883340c2018-02-28 18:59:29 +010092 charstring mp_pcu_socket := PCU_SOCK_DEFAULT;
Neels Hofmeyr6a84b232018-04-03 19:12:36 +020093 charstring mp_ctrl_ip := "127.0.0.1";
94 integer mp_ctrl_port := 4238;
Harald Welte07bd2d22019-05-25 11:03:30 +020095 charstring mp_bsc_ctrl_ip := "127.0.0.1";
96 integer mp_bsc_ctrl_port := 4249;
Pau Espin Pedrol121724c2018-09-28 15:58:12 +020097 integer mp_tolerance_rxqual := 1;
98 integer mp_tolerance_rxlev := 3;
99 integer mp_tolerance_timing_offset_256syms := 0;
Pau Espin Pedrol752ffd52018-06-07 13:55:45 +0200100 integer mp_rxlev_exp := 57;
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +0200101 integer mp_ul_rxlev_exp := 10;
Pau Espin Pedroled359cb2018-09-28 16:08:24 +0200102 integer mp_ms_power_level_exp := 7;
Pau Espin Pedrola2e079c2020-06-03 17:31:04 +0200103 integer mp_bts_tx_nom_pwr_exp := 50; /* Expected Tx Nominal Output Power of the BTS, in dBm */
104 integer mp_bts_tx_pwr_att_exp := 20; /* Expected Tx Power attenuation wrt to Tx Nominal Output Power, in dB */
Pau Espin Pedrol121724c2018-09-28 15:58:12 +0200105 integer mp_ms_actual_ta_exp := 0;
106 integer mp_timing_offset_256syms_exp := 512;
Pau Espin Pedrol315e4712018-11-01 16:27:07 +0100107 /* Time to wait for RSL conn from BTS during startup of test */
Philipp Maier12567e42019-04-17 14:10:05 +0200108 float mp_ipa_up_timeout := 15.0;
Philipp Maiere63229e2019-04-26 12:21:37 +0200109 float mp_ipa_up_delay := 0.0;
Harald Weltead033dc2019-05-25 17:28:16 +0200110 /* false for now, as only virtphy supports it, not calypso-l1 nor trxcon */
111 boolean mp_l1_supports_gprs := false;
Harald Welte70767382018-02-21 12:16:40 +0100112}
113
Harald Welte629cc6b2018-03-11 17:19:05 +0100114type record of RslChannelNr ChannelNrs;
115
Harald Welte70767382018-02-21 12:16:40 +0100116type component test_CT extends CTRL_Adapter_CT {
Harald Welte68e495b2018-02-25 00:05:57 +0100117 /* IPA Emulation component underneath RSL */
Harald Welte70767382018-02-21 12:16:40 +0100118 var IPA_Emulation_CT vc_IPA;
Harald Welte68e495b2018-02-25 00:05:57 +0100119 /* RSL Emulation component (for ConnHdlr tests) */
Harald Welte70767382018-02-21 12:16:40 +0100120 var RSL_Emulation_CT vc_RSL;
Harald Welte68e495b2018-02-25 00:05:57 +0100121 /* Direct RSL_CCHAN_PT */
Harald Welte70767382018-02-21 12:16:40 +0100122 port RSL_CCHAN_PT RSL_CCHAN;
Vadim Yanitskiyfc631d12020-06-02 23:48:49 +0700123 timer g_rslem_up_timer;
Harald Welte68e495b2018-02-25 00:05:57 +0100124
125 /* L1CTL port (for classic tests) */
126 port L1CTL_PT L1CTL;
Harald Welte48494ca2018-02-25 16:59:50 +0100127
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700128 /* Optional TRXC connection to FakeTRX (BTS side) */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700129 port TRXC_CODEC_PT BTS_TRXC;
130 var integer g_bts_trxc_conn_id;
Harald Welte54a2a2d2018-02-26 09:14:05 +0100131
Harald Weltef50e3ae2018-09-10 10:27:56 +0200132 /* VTY connections to both BTS and BSC */
Harald Welte8da48242018-02-27 20:41:32 +0100133 port TELNETasp_PT BTSVTY;
Harald Weltef50e3ae2018-09-10 10:27:56 +0200134 port TELNETasp_PT BSCVTY;
Harald Welte8da48242018-02-27 20:41:32 +0100135
Harald Welte883340c2018-02-28 18:59:29 +0100136 /* PCU Interface of BTS */
137 port PCUIF_CODEC_PT PCU;
138 var integer g_pcu_conn_id;
139 /* Last PCU INFO IND we received */
140 var PCUIF_Message g_pcu_last_info;
141
Harald Welte48494ca2018-02-25 16:59:50 +0100142 /* SI configuration */
143 var SystemInformationConfig si_cfg := {
144 bcch_extended := false,
145 si1_present := false,
146 si2bis_present := false,
147 si2ter_present := false,
148 si2quater_present := false,
149 si7_present := false,
150 si8_present := false,
151 si9_present := false,
152 si13_present := false,
153 si13alt_present := false,
154 si15_present := false,
155 si16_present := false,
156 si17_present := false,
157 si2n_present := false,
158 si21_present := false,
159 si22_present := false
160 };
Harald Welte629cc6b2018-03-11 17:19:05 +0100161
162 /* all logical channels available on the BTS */
163 var ChannelNrs g_AllChannels;
Harald Welte0472ab42018-03-12 15:02:26 +0100164 var ChannelNrs g_AllChanTypes;
Harald Welte70767382018-02-21 12:16:40 +0100165}
166
167/* an individual call / channel */
Harald Welte2f2b2b72019-05-31 22:24:57 +0200168type component ConnHdlr extends RSL_DchanHdlr, lapdm_test_CT {
Harald Welte70767382018-02-21 12:16:40 +0100169 port L1CTL_PT L1CTL;
170
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700171 /* Optional TRXC connection to FakeTRX (BTS side) */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700172 port TRXC_CODEC_PT BTS_TRXC;
173 var integer g_bts_trxc_conn_id;
Harald Welte70767382018-02-21 12:16:40 +0100174
175 timer g_Tguard;
176 timer g_Tmeas_exp := 2.0; /* >= 103 SACCH multiframe ~ 500ms */
177
178 var ConnHdlrPars g_pars;
179 var uint8_t g_next_meas_res_nr := 0;
Harald Weltefa45e9e2018-03-10 18:59:03 +0100180 var boolean g_first_meas_res := true;
Harald Weltef26de0b2018-04-04 20:28:05 +0200181
182 /* PCU Interface of BTS */
183 port PCUIF_CODEC_PT PCU;
Harald Welte70767382018-02-21 12:16:40 +0100184}
185
Vadim Yanitskiyfc631d12020-06-02 23:48:49 +0700186private altstep as_rsl_init_guard() runs on test_CT {
187 [] g_rslem_up_timer.timeout {
188 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
189 "Timeout waiting for RSL bring up");
190 }
191}
Vadim Yanitskiyc9c9e292020-05-18 23:31:40 +0700192
Vadim Yanitskiyfc631d12020-06-02 23:48:49 +0700193function f_init_rsl(charstring id) runs on test_CT {
Harald Welte70767382018-02-21 12:16:40 +0100194 vc_IPA := IPA_Emulation_CT.create(id & "-RSL-IPA");
195 vc_RSL := RSL_Emulation_CT.create(id & "-RSL");
196
197 map(vc_IPA:IPA_PORT, system:IPA_CODEC_PT);
198 connect(vc_IPA:IPA_RSL_PORT, vc_RSL:IPA_PT);
199 connect(self:RSL_CCHAN, vc_RSL:CCHAN_PT);
200
201 vc_IPA.start(IPA_Emulation.main_server(mp_rsl_ip, mp_rsl_port));
202 vc_RSL.start(RSL_Emulation.main(false));
Vadim Yanitskiyc9c9e292020-05-18 23:31:40 +0700203
Vadim Yanitskiyfc631d12020-06-02 23:48:49 +0700204 /* TTCN-3 offers no way to guard 'interleave' statements */
205 g_rslem_up_timer.start(mp_ipa_up_timeout);
206 var default d := activate(as_rsl_init_guard());
207
208 /* We expect all 4 transceivers to connect here (separate IPA/RSL connections).
209 * See https://gerrit.osmocom.org/q/Ib5ad31388ae25399ad09739aac3fdcb0b3a1f78b. */
210 interleave {
211 /* These events are sent by the RSL_Emulation_CT */
212 [] RSL_CCHAN.receive(tr_RSLEm_EV(RSLEM_EV_TRX_UP, IPAC_PROTO_RSL_TRX0));
213 [] RSL_CCHAN.receive(tr_RSLEm_EV(RSLEM_EV_TRX_UP, IPAC_PROTO_RSL_TRX1));
214 [] RSL_CCHAN.receive(tr_RSLEm_EV(RSLEM_EV_TRX_UP, IPAC_PROTO_RSL_TRX2));
215 [] RSL_CCHAN.receive(tr_RSLEm_EV(RSLEM_EV_TRX_UP, IPAC_PROTO_RSL_TRX3));
216 /* These messages (RF RESource INDication) are sent by the IUT itself */
217 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RF_RES_IND, IPAC_PROTO_RSL_TRX0));
218 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RF_RES_IND, IPAC_PROTO_RSL_TRX1));
219 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RF_RES_IND, IPAC_PROTO_RSL_TRX2));
220 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RF_RES_IND, IPAC_PROTO_RSL_TRX3));
Vadim Yanitskiyc9c9e292020-05-18 23:31:40 +0700221 }
Vadim Yanitskiyfc631d12020-06-02 23:48:49 +0700222
223 g_rslem_up_timer.stop;
224 deactivate(d);
Harald Welte70767382018-02-21 12:16:40 +0100225}
226
227type record ConnHdlrPars {
228 RslChannelNr chan_nr,
229 RSL_IE_ChannelMode chan_mode,
230 float t_guard,
Harald Welte0472ab42018-03-12 15:02:26 +0100231 ConnL1Pars l1_pars,
Harald Weltee613f962018-04-18 22:38:16 +0200232 TestSpecUnion spec optional,
Eric Wild61edb7e2019-06-03 12:38:31 +0200233 RSL_IE_EncryptionInfo encr optional,
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +0700234 BtsBand bts0_band optional,
235
236 /* Frequency hopping parameters (disabled if absent) */
237 MaioHsn maio_hsn optional,
238 /* MA bitmap to be indicated in RR Immediate Assignment */
239 MobileAllocation ma_map,
240 /* The actual Mobile Allocation (ARFCN list) to be used */
241 L1ctlMA ma
Harald Welte0472ab42018-03-12 15:02:26 +0100242}
243
244/* Test-specific parameters */
245type union TestSpecUnion {
246 RllTestCase rll
Harald Welte70767382018-02-21 12:16:40 +0100247}
248
Harald Welte82ccef72018-02-25 16:17:33 +0100249template (value) RachControlParameters ts_RachCtrl_default := {
Harald Welte0fd1fb02018-03-10 17:19:50 +0100250 max_retrans := RACH_MAX_RETRANS_7,
251 tx_integer := '1001'B, /* 12 slots */
Harald Welte82ccef72018-02-25 16:17:33 +0100252 cell_barr_access := false,
253 re_not_allowed := true,
Harald Welteb9585f82018-03-10 17:18:47 +0100254 acc := '0000010000000000'B
Harald Welte82ccef72018-02-25 16:17:33 +0100255};
256
Harald Weltef10153f2018-02-25 16:34:05 +0100257template (value) CellSelectionParameters ts_CellSelPar_default := {
Harald Welte0fd1fb02018-03-10 17:19:50 +0100258 cell_resel_hyst_2dB := 2,
Pau Espin Pedroled359cb2018-09-28 16:08:24 +0200259 ms_txpwr_max_cch := mp_ms_power_level_exp,
Harald Weltef10153f2018-02-25 16:34:05 +0100260 acs := '0'B,
261 neci := true,
262 rxlev_access_min := 0
263}
264
265template (value) LocationAreaIdentification ts_LAI_default := {
266 mcc_mnc := '262F42'H,
267 lac := 42
268}
269
Vadim Yanitskiy12cf3d92020-05-05 00:19:50 +0700270private template (value) GPRSIndicator ts_GPRSIndicator_def := {
271 ra_colour := 0,
272 si13_pos := '0'B
273}
274
275private template (value) SI3RestOctets ts_SI3RestOctets_def
276modifies ts_SI3RestOctets := {
277 gprs_ind := {
278 presence := CSN1_H,
279 ind := ts_GPRSIndicator_def
280 }
281}
282
283private template (value) SI4RestOctets ts_SI4RestOctets_def
284modifies ts_SI4RestOctets := {
285 gprs_ind := {
Vadim Yanitskiyab5363f2020-05-05 00:30:22 +0700286 presence := CSN1_H,
287 ind := ts_GPRSIndicator_def
Vadim Yanitskiy12cf3d92020-05-05 00:19:50 +0700288 }
289}
290
Harald Welte7484fc42018-02-24 14:09:45 +0100291/* Default SYSTEM INFORMATION 3 */
Harald Weltef8df4cb2018-03-10 15:15:08 +0100292template (value) SystemInformation ts_SI3_default := {
293 header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_3, 18),
Harald Welte7484fc42018-02-24 14:09:45 +0100294 payload := {
295 si3 := {
296 cell_id := 23,
Harald Weltef10153f2018-02-25 16:34:05 +0100297 lai := ts_LAI_default,
Harald Welte7484fc42018-02-24 14:09:45 +0100298 ctrl_chan_desc := {
299 msc_r99 := true,
300 att := true,
301 bs_ag_blks_res := 1,
302 ccch_conf := CCHAN_DESC_1CCCH_COMBINED,
Harald Welte82ccef72018-02-25 16:17:33 +0100303 si22ind := false,
Harald Welte7484fc42018-02-24 14:09:45 +0100304 cbq3 := CBQ3_IU_MODE_NOT_SUPPORTED,
305 spare := '00'B,
306 bs_pa_mfrms := 0, /* 2 multiframes */
307 t3212 := 1 /* 6 minutes */
308 },
Harald Welte82ccef72018-02-25 16:17:33 +0100309 cell_options := {
Harald Welte7484fc42018-02-24 14:09:45 +0100310 dn_ind := false,
311 pwrc := false,
312 dtx := MS_MAY_USE_UL_DTX,
Harald Welte0fd1fb02018-03-10 17:19:50 +0100313 radio_link_tout_div4 := (32/4)-1
Harald Welte7484fc42018-02-24 14:09:45 +0100314 },
Harald Weltef10153f2018-02-25 16:34:05 +0100315 cell_sel_par := ts_CellSelPar_default,
Harald Welte82ccef72018-02-25 16:17:33 +0100316 rach_control := ts_RachCtrl_default,
Vadim Yanitskiy12cf3d92020-05-05 00:19:50 +0700317 rest_octets := enc_SI3RestOctets(valueof(ts_SI3RestOctets_def))
Harald Welte7484fc42018-02-24 14:09:45 +0100318 }
319 }
320}
Harald Welte70767382018-02-21 12:16:40 +0100321
Harald Weltef8df4cb2018-03-10 15:15:08 +0100322template (value) SystemInformation ts_SI2_default := {
323 header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_2, 22),
Harald Weltef10153f2018-02-25 16:34:05 +0100324 payload := {
325 si2 := {
326 bcch_freq_list := '00000000000000000000000000000000'O,
327 ncc_permitted := '11111111'B,
328 rach_control := ts_RachCtrl_default
329 }
330 }
331}
332
Harald Weltef8df4cb2018-03-10 15:15:08 +0100333template (value) SystemInformation ts_SI4_default := {
334 header := ts_RrHeader(SYSTEM_INFORMATION_TYPE_4, 12), /* no CBCH / restoct */
Harald Weltef10153f2018-02-25 16:34:05 +0100335 payload := {
336 si4 := {
337 lai := ts_LAI_default,
338 cell_sel_par := ts_CellSelPar_default,
339 rach_control := ts_RachCtrl_default,
340 cbch_chan_desc := omit,
341 cbch_mobile_alloc := omit,
Vadim Yanitskiy12cf3d92020-05-05 00:19:50 +0700342 rest_octets := enc_SI4RestOctets(valueof(ts_SI4RestOctets_def))
Harald Weltef10153f2018-02-25 16:34:05 +0100343 }
344 }
345}
346
347function f_rsl_bcch_fill_raw(RSL_IE_SysinfoType rsl_si_type, octetstring si_enc)
348runs on test_CT {
349 log("Setting ", rsl_si_type, ": ", si_enc);
Vadim Yanitskiy493abe72020-05-25 22:03:48 +0700350 RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_BCCH_INFO(rsl_si_type, si_enc)));
Harald Weltef10153f2018-02-25 16:34:05 +0100351}
352
353function f_rsl_bcch_fill(RSL_IE_SysinfoType rsl_si_type, template (value) SystemInformation si_dec)
354runs on test_CT {
355 var octetstring si_enc := enc_SystemInformation(valueof(si_dec));
356 log("Setting ", rsl_si_type, ": ", si_dec);
357 f_rsl_bcch_fill_raw(rsl_si_type, si_enc);
358}
359
Harald Welte505cf9b2018-09-15 17:47:23 +0300360friend function f_init_vty(charstring id) runs on test_CT {
Harald Welte8da48242018-02-27 20:41:32 +0100361 map(self:BTSVTY, system:BTSVTY);
362 f_vty_set_prompts(BTSVTY);
363 f_vty_transceive(BTSVTY, "enable");
364}
365
Harald Welte505cf9b2018-09-15 17:47:23 +0300366friend function f_init_vty_bsc() runs on test_CT {
Harald Weltef50e3ae2018-09-10 10:27:56 +0200367 map(self:BSCVTY, system:BSCVTY);
368 f_vty_set_prompts(BSCVTY, "OsmoBSC");
369 f_vty_transceive(BSCVTY, "enable");
370}
371
Harald Welte883340c2018-02-28 18:59:29 +0100372/* PCU socket may at any time receive a new INFO.ind */
Harald Weltef26de0b2018-04-04 20:28:05 +0200373private altstep as_pcu_info_ind(PCUIF_CODEC_PT pt, integer pcu_conn_id,
374 out PCUIF_Message pcu_last_info) {
Harald Welte883340c2018-02-28 18:59:29 +0100375 var PCUIF_send_data sd;
Harald Weltef26de0b2018-04-04 20:28:05 +0200376 [] pt.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(0, ?))) -> value sd {
377 pcu_last_info := sd.data;
Harald Welted378a252018-03-13 17:02:14 +0100378 }
Harald Weltef26de0b2018-04-04 20:28:05 +0200379 [] pt.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(?, ?, ?))) -> value sd {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200380 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Invalid PCU Version/BTS Number received");
Harald Welte883340c2018-02-28 18:59:29 +0100381 }
382}
383
Harald Weltef26de0b2018-04-04 20:28:05 +0200384private function f_init_pcu(PCUIF_CODEC_PT pt, charstring id,
385 out integer pcu_conn_id, out PCUIF_Message pcu_last_info) {
Harald Welte883340c2018-02-28 18:59:29 +0100386 timer T := 2.0;
387 var PCUIF_send_data sd;
Harald Welte84271622018-03-10 17:21:03 +0100388 if (mp_pcu_socket == "") {
Harald Weltef26de0b2018-04-04 20:28:05 +0200389 pcu_conn_id := -1;
Harald Welte84271622018-03-10 17:21:03 +0100390 return;
391 }
Harald Weltef26de0b2018-04-04 20:28:05 +0200392 pcu_conn_id := f_pcuif_connect(pt, mp_pcu_socket);
Harald Welte883340c2018-02-28 18:59:29 +0100393
394 T.start;
395 alt {
Harald Weltef26de0b2018-04-04 20:28:05 +0200396 [] as_pcu_info_ind(pt, pcu_conn_id, pcu_last_info);
Harald Welte883340c2018-02-28 18:59:29 +0100397 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200398 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU INFO_IND");
Harald Welte883340c2018-02-28 18:59:29 +0100399 }
400 }
401}
402
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700403private function f_init_trxc(TRXC_CODEC_PT pt, charstring id,
404 out integer trxc_conn_id) {
405 var Result res;
406
407 res := TRXC_CodecPort_CtrlFunct.f_IPL4_connect(pt, mp_bts_trxc_ip, mp_bts_trxc_port,
408 "", -1, -1, { udp := {} }, {});
409 if (not ispresent(res.connId)) {
410 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
411 "Could not connect to the control (TRXC) interface " &
412 "of FakeTRX, check your configuration");
413 }
414 trxc_conn_id := res.connId;
415}
416
Harald Welte70767382018-02-21 12:16:40 +0100417/* global init function */
Harald Welte10474062019-05-30 16:48:17 +0200418function f_init() runs on test_CT {
419 var charstring id := testcasename();
Harald Welte629cc6b2018-03-11 17:19:05 +0100420 g_AllChannels := {
421 /* TS 1..4: TCH/F */
422 valueof(ts_RslChanNr_Bm(1)), valueof(ts_RslChanNr_Bm(2)),
423 valueof(ts_RslChanNr_Bm(3)), valueof(ts_RslChanNr_Bm(4)),
424 /* TS 5: TCH/H */
425 valueof(ts_RslChanNr_Lm(5,0)), valueof(ts_RslChanNr_Lm(5,1)),
426 /* TS 0: SDCCH/4 */
427 valueof(ts_RslChanNr_SDCCH4(0,0)), valueof(ts_RslChanNr_SDCCH4(0,1)),
428 valueof(ts_RslChanNr_SDCCH4(0,2)), valueof(ts_RslChanNr_SDCCH4(0,3)),
429 /* TS 6: SDCCH/8 */
430 valueof(ts_RslChanNr_SDCCH8(6,0)), valueof(ts_RslChanNr_SDCCH8(6,1)),
431 valueof(ts_RslChanNr_SDCCH8(6,2)), valueof(ts_RslChanNr_SDCCH8(6,3)),
432 valueof(ts_RslChanNr_SDCCH8(6,4)), valueof(ts_RslChanNr_SDCCH8(6,5)),
433 valueof(ts_RslChanNr_SDCCH8(6,6)), valueof(ts_RslChanNr_SDCCH8(6,7))
434 };
435
Pau Espin Pedrol3dcf38f2018-10-22 14:07:54 +0200436 /* FIXME: FACCH/H is unreliable with calypso firmware, see OS#3653 */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700437 if (mp_bts_trxc_port != -1) {
Pau Espin Pedrol3dcf38f2018-10-22 14:07:54 +0200438 g_AllChanTypes := {
439 /* TS 1..4: TCH/F */
440 valueof(ts_RslChanNr_Bm(1)),
441 /* TS 5: TCH/H */
442 valueof(ts_RslChanNr_Lm(5,1)),
443 /* TS 0: SDCCH/4 */
444 valueof(ts_RslChanNr_SDCCH4(0,2)),
445 /* TS 6: SDCCH/8 */
446 valueof(ts_RslChanNr_SDCCH8(6,4))
447 };
448 } else {
449 g_AllChanTypes := {
450 /* TS 1..4: TCH/F */
451 valueof(ts_RslChanNr_Bm(1)),
452 /* TS 0: SDCCH/4 */
453 valueof(ts_RslChanNr_SDCCH4(0,2)),
454 /* TS 6: SDCCH/8 */
455 valueof(ts_RslChanNr_SDCCH8(6,4))
456 };
457 }
Harald Welte70767382018-02-21 12:16:40 +0100458 f_init_rsl(id);
Harald Welte2d142592018-02-25 13:19:44 +0100459 f_sleep(0.5); /* workaround for OS#3000 */
Harald Welte8da48242018-02-27 20:41:32 +0100460 f_init_vty(id);
Neels Hofmeyr6a84b232018-04-03 19:12:36 +0200461 f_ipa_ctrl_start(mp_ctrl_ip, mp_ctrl_port);
Harald Welte7484fc42018-02-24 14:09:45 +0100462
463 /* Send SI3 to the BTS, it is needed for various computations */
Harald Weltef10153f2018-02-25 16:34:05 +0100464 f_rsl_bcch_fill(RSL_SYSTEM_INFO_3, ts_SI3_default);
465 /* SI2 + SI4 are required for SI testing as they are mandatory defaults */
466 f_rsl_bcch_fill(RSL_SYSTEM_INFO_2, ts_SI2_default);
467 f_rsl_bcch_fill(RSL_SYSTEM_INFO_4, ts_SI4_default);
Harald Welte57fe8232018-02-26 17:52:50 +0100468
Harald Weltef26de0b2018-04-04 20:28:05 +0200469 map(self:PCU, system:PCU);
470 f_init_pcu(PCU, id, g_pcu_conn_id, g_pcu_last_info);
Harald Welte883340c2018-02-28 18:59:29 +0100471
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700472 if (mp_bts_trxc_port != -1) {
Harald Welte84271622018-03-10 17:21:03 +0100473 var TrxcMessage ret;
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700474
475 /* Init TRXC interface to FakeTRX */
476 map(self:BTS_TRXC, system:BTS_TRXC);
477 f_init_trxc(BTS_TRXC, id, g_bts_trxc_conn_id);
478
Vadim Yanitskiy10d72462019-06-04 22:27:52 +0700479 /* Start with a default moderate timing offset equalling TA=2, and RSSI=-60 */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700480 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_TIMING(2*256)));
Vadim Yanitskiy10d72462019-06-04 22:27:52 +0700481 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_RSSI(-60)));
Vadim Yanitskiyde535e02019-07-26 16:29:27 +0700482 /* OsmoBTS may have different AB / NB threshold (see MIN_QUAL_NORM, MIN_QUAL_RACH) */
483 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_CI(60)));
Harald Welte84271622018-03-10 17:21:03 +0100484 }
Philipp Maierd95f3402019-04-18 17:50:52 +0200485
486 /* Wait some extra time to make sure the BTS emits a stable carrier.
487 * (this is only relevant when running the tests with a physical BTS.) */
488 f_sleep(mp_ipa_up_delay);
Harald Welte70767382018-02-21 12:16:40 +0100489}
490
Harald Welte68e495b2018-02-25 00:05:57 +0100491/* Attach L1CTL to master test_CT (classic tests, non-handler mode) */
492function f_init_l1ctl() runs on test_CT {
493 map(self:L1CTL, system:L1CTL);
494 f_connect_reset(L1CTL);
495}
496
Harald Welte70767382018-02-21 12:16:40 +0100497type function void_fn(charstring id) runs on ConnHdlr;
498
499/* create a new test component */
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700500function f_start_handler(void_fn fn, ConnHdlrPars pars,
501 boolean pcu_comp := false,
502 boolean trxc_comp := false)
Harald Welte70767382018-02-21 12:16:40 +0100503runs on test_CT return ConnHdlr {
504 var charstring id := testcasename();
505 var ConnHdlr vc_conn;
506
507 vc_conn := ConnHdlr.create(id);
508 /* connect to RSL Emulation main component */
509 connect(vc_conn:RSL, vc_RSL:CLIENT_PT);
510 connect(vc_conn:RSL_PROC, vc_RSL:RSL_PROC);
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700511
512 /* The ConnHdlr component may want to talk to some ports directly,
513 * so we disconnect it from the test_CT and connect it to the component.
514 * This obviously only works for one component, i.e. no concurrency. */
Harald Weltef26de0b2018-04-04 20:28:05 +0200515 if (pcu_comp) {
Harald Weltef26de0b2018-04-04 20:28:05 +0200516 unmap(self:PCU, system:PCU);
517 map(vc_conn:PCU, system:PCU);
518 }
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700519 if (trxc_comp) {
520 unmap(self:BTS_TRXC, system:BTS_TRXC);
521 map(vc_conn:BTS_TRXC, system:BTS_TRXC);
522 }
Harald Welte70767382018-02-21 12:16:40 +0100523
524 vc_conn.start(f_handler_init(fn, id, pars));
525 return vc_conn;
526}
527
Harald Welte70767382018-02-21 12:16:40 +0100528private altstep as_Tguard() runs on ConnHdlr {
529 [] g_Tguard.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200530 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
Harald Welte70767382018-02-21 12:16:40 +0100531 }
532}
533
Harald Welte990a3612019-05-27 14:02:13 +0200534friend function f_l1_tune(L1CTL_PT L1CTL, L1ctlCcchMode ccch_mode := CCCH_MODE_COMBINED) {
535 f_L1CTL_FBSB(L1CTL, { false, mp_trx0_arfcn }, ccch_mode, mp_rxlev_exp);
Harald Welte70767382018-02-21 12:16:40 +0100536}
537
Vadim Yanitskiy2f01fbd2019-06-01 01:32:48 +0700538private function f_trxc_fake_rssi(TRXC_RSSI rssi) runs on ConnHdlr {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100539 var TrxcMessage ret;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700540 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_RSSI(rssi)));
Harald Welte70767382018-02-21 12:16:40 +0100541}
542
Vadim Yanitskiydc8db922019-06-04 21:58:15 +0700543private function f_trxc_fake_toffs256(int16_t toffs256) runs on ConnHdlr {
Harald Weltef8df4cb2018-03-10 15:15:08 +0100544 var TrxcMessage ret;
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +0700545 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_TIMING(toffs256)));
Harald Welte70767382018-02-21 12:16:40 +0100546}
547
548/* first function started in ConnHdlr component */
549private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
550runs on ConnHdlr {
551 g_pars := pars;
552 g_chan_nr := pars.chan_nr;
553
554 map(self:L1CTL, system:L1CTL);
555 f_connect_reset(L1CTL);
556
Harald Welted48c0c72019-06-05 10:01:15 +0200557 if (mp_bts_trxc_port != -1 and BTS_TRXC.checkstate("Mapped")) {
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +0700558 f_init_trxc(BTS_TRXC, id, g_bts_trxc_conn_id);
Harald Welte84271622018-03-10 17:21:03 +0100559 }
Harald Welte70767382018-02-21 12:16:40 +0100560
561 g_Tguard.start(pars.t_guard);
562 activate(as_Tguard());
563
564 f_rslem_register(0, pars.chan_nr);
565
566 /* call the user-supplied test case function */
567 fn.apply(id);
568}
569
Harald Welteb1726c92018-03-30 11:56:38 +0200570function f_rsl_transceive_ret(template RSL_Message tx, template RSL_Message exp_rx, charstring id,
571 boolean ignore_other := false)
572runs on ConnHdlr return RSL_Message {
573 var RSL_Message rx;
Harald Welte1eba3742018-02-25 12:48:14 +0100574 timer T := 3.0;
575 RSL.send(tx);
576 T.start;
Harald Welte70767382018-02-21 12:16:40 +0100577 alt {
Harald Welteb1726c92018-03-30 11:56:38 +0200578 [] RSL.receive(exp_rx) -> value rx {
Harald Welte1eba3742018-02-25 12:48:14 +0100579 T.stop;
580 setverdict(pass);
Harald Welte70767382018-02-21 12:16:40 +0100581 }
Harald Welte1eba3742018-02-25 12:48:14 +0100582 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200583 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout expecting " & id);
Harald Welte1eba3742018-02-25 12:48:14 +0100584 }
Harald Welte21240e62018-03-11 21:43:35 +0100585 [not ignore_other] as_l1_sacch();
586 [not ignore_other] as_meas_res();
587 [not ignore_other] as_l1_dcch();
588 [not ignore_other] RSL.receive {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200589 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RSL message received");
Harald Welte70767382018-02-21 12:16:40 +0100590 }
Harald Welte21240e62018-03-11 21:43:35 +0100591 [ignore_other] RSL.receive { repeat; }
Harald Welte70767382018-02-21 12:16:40 +0100592 }
Harald Welteb1726c92018-03-30 11:56:38 +0200593 return rx;
594}
595
596function f_rsl_transceive(template RSL_Message tx, template RSL_Message exp_rx, charstring id,
597 boolean ignore_other := false)
598runs on ConnHdlr {
599 var RSL_Message rx := f_rsl_transceive_ret(tx, exp_rx, id, ignore_other);
Harald Welte70767382018-02-21 12:16:40 +0100600}
601
Harald Welte8b01c792019-05-19 22:51:25 +0200602function f_rsl_chan_act(RSL_IE_ChannelMode mode, boolean encr_enable := false, RSL_IE_List more_ies := {},
603 RSL_IE_ActivationType act_type := t_RSL_IE_ActType_IA) runs on ConnHdlr {
604 var RSL_Message ch_act := valueof(ts_RSL_CHAN_ACT(g_chan_nr, mode, act_type));
Harald Weltee613f962018-04-18 22:38:16 +0200605 if (encr_enable) {
606 /* append encryption related IEs, if requested */
607 var RSL_IE_EncryptionInfo encr_info;
608 encr_info := valueof(ts_RSL_IE_EncrInfo(g_pars.encr.alg_id, g_pars.encr.key));
609 ch_act.ies := ch_act.ies & { valueof(t_RSL_IE(RSL_IE_ENCR_INFO, RSL_IE_Body:{encr_info :=
610encr_info})) };
611 }
Harald Weltec8d363c2019-05-19 20:36:48 +0200612 ch_act.ies := ch_act.ies & more_ies;
Harald Weltee613f962018-04-18 22:38:16 +0200613 f_rsl_transceive(ch_act, tr_RSL_CHAN_ACT_ACK(g_chan_nr), "RSL CHAN ACT");
Harald Welte1eba3742018-02-25 12:48:14 +0100614}
615
Harald Welte70767382018-02-21 12:16:40 +0100616function f_rsl_chan_deact() runs on ConnHdlr {
Harald Welte1eba3742018-02-25 12:48:14 +0100617 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 +0100618 "RF CHAN REL", true);
Harald Welte70767382018-02-21 12:16:40 +0100619}
620
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +0700621/* Default Mobile Allocation to be used for frequency hopping */
622private const L1ctlMA l1ctl_ma_def := { { false, mp_trx0_arfcn }, { false, mp_trx1_arfcn },
623 { false, mp_trx2_arfcn }, { false, mp_trx3_arfcn } };
624
Harald Welte2f2b2b72019-05-31 22:24:57 +0200625friend template ConnHdlrPars t_Pars(template RslChannelNr chan_nr,
Harald Welte70767382018-02-21 12:16:40 +0100626 template RSL_IE_ChannelMode chan_mode,
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +0700627 template (omit) MaioHsn maio_hsn := omit,
Harald Welte70767382018-02-21 12:16:40 +0100628 float t_guard := 20.0) := {
629 chan_nr := valueof(chan_nr),
630 chan_mode := valueof(chan_mode),
631 t_guard := t_guard,
632 l1_pars := {
633 dtx_enabled := false,
Harald Welte685d5982018-02-27 20:42:05 +0100634 toa256_enabled := false,
Harald Welte70767382018-02-21 12:16:40 +0100635 meas_ul := {
636 full := {
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +0200637 rxlev := mp_ul_rxlev_exp,
Harald Welte70767382018-02-21 12:16:40 +0100638 rxqual := 0
639 },
640 sub := {
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +0200641 rxlev := mp_ul_rxlev_exp,
Harald Welte70767382018-02-21 12:16:40 +0100642 rxqual := 0
643 }
644 },
Pau Espin Pedrol121724c2018-09-28 15:58:12 +0200645 timing_offset_256syms := mp_timing_offset_256syms_exp,
Harald Welte70767382018-02-21 12:16:40 +0100646 bs_power_level := 0,
Pau Espin Pedroled359cb2018-09-28 16:08:24 +0200647 ms_power_level := mp_ms_power_level_exp,
Pau Espin Pedrol121724c2018-09-28 15:58:12 +0200648 ms_actual_ta := mp_ms_actual_ta_exp
Harald Welte0472ab42018-03-12 15:02:26 +0100649 },
Harald Weltee613f962018-04-18 22:38:16 +0200650 spec := omit,
Eric Wild61edb7e2019-06-03 12:38:31 +0200651 encr := omit,
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +0700652 bts0_band := omit,
653 maio_hsn := maio_hsn,
654 ma_map := c_MA_null,
655 ma := l1ctl_ma_def
Harald Welte70767382018-02-21 12:16:40 +0100656}
657
Harald Welte93640c62018-02-25 16:59:33 +0100658/***********************************************************************
659 * Channel Activation / Deactivation
660 ***********************************************************************/
661
Harald Welte70767382018-02-21 12:16:40 +0100662/* Stress test: Do 500 channel activations/deactivations in rapid succession */
663function f_TC_chan_act_stress(charstring id) runs on ConnHdlr {
664 for (var integer i := 0; i < 500; i := i+1) {
665 f_rsl_chan_act(g_pars.chan_mode);
666 f_rsl_chan_deact();
667 }
668 setverdict(pass);
669}
670testcase TC_chan_act_stress() runs on test_CT {
671 var ConnHdlr vc_conn;
672 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +0200673 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100674 vc_conn := f_start_handler(refers(f_TC_chan_act_stress), pars);
675 vc_conn.done;
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200676 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100677}
678
679/* Test if re-activation of an already active channel fails as expected */
680function f_TC_chan_act_react(charstring id) runs on ConnHdlr {
681 f_rsl_chan_act(g_pars.chan_mode);
682 /* attempt to activate the same lchan again -> expect reject */
683 RSL.send(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode));
684 alt {
685 [] RSL.receive(tr_RSL_CHAN_ACT_ACK(g_chan_nr)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200686 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected CHAN ACT ACK on double activation");
Harald Welte70767382018-02-21 12:16:40 +0100687 }
688 [] RSL.receive(tr_RSL_CHAN_ACT_NACK(g_chan_nr)) {
689 setverdict(pass);
690 }
691 }
692 f_rsl_chan_deact();
693}
694testcase TC_chan_act_react() runs on test_CT {
695 var ConnHdlr vc_conn;
696 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte294b0a22018-03-10 23:26:48 +0100697 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100698 vc_conn := f_start_handler(refers(f_TC_chan_act_react), pars);
699 vc_conn.done;
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200700 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100701}
702
703/* Attempt to de-activate a channel that's not active */
704function f_TC_chan_deact_not_active(charstring id) runs on ConnHdlr {
705 timer T := 3.0;
706 RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
707 T.start;
708 alt {
709 [] RSL.receive(tr_RSL_RF_CHAN_REL_ACK(g_chan_nr)) {
710 setverdict(pass);
711 }
712 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200713 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout expecting RF_CHAN_REL_ACK");
Harald Welte70767382018-02-21 12:16:40 +0100714 }
715 }
716}
717testcase TC_chan_deact_not_active() runs on test_CT {
718 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte294b0a22018-03-10 23:26:48 +0100719 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100720 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_chan_deact_not_active), pars);
721 vc_conn.done;
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200722 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100723}
724
725/* attempt to activate channel with wrong RSL Channel Nr IE; expect NACK */
726function f_TC_chan_act_wrong_nr(charstring id) runs on ConnHdlr {
727 RSL.send(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode));
728 alt {
729 [] RSL.receive(tr_RSL_CHAN_ACT_ACK(g_chan_nr)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200730 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected CHAN ACT ACK");
Harald Welte70767382018-02-21 12:16:40 +0100731 }
732 [] RSL.receive(tr_RSL_CHAN_ACT_NACK(g_chan_nr)) {
733 setverdict(pass);
734 }
735 }
736}
737private type record WrongChanNrCase {
738 RslChannelNr chan_nr,
739 charstring description
740}
741private type record of WrongChanNrCase WrongChanNrCases;
742private template WrongChanNrCase t_WCN(template RslChannelNr chan_nr, charstring desc) := {
743 chan_nr := chan_nr,
744 description := desc
745}
746
747testcase TC_chan_act_wrong_nr() runs on test_CT {
748 var ConnHdlr vc_conn;
749 var ConnHdlrPars pars;
750
Harald Welte294b0a22018-03-10 23:26:48 +0100751 f_init();
Harald Welte70767382018-02-21 12:16:40 +0100752
753 var WrongChanNrCases wrong := {
754 valueof(t_WCN(t_RslChanNr_RACH(0), "RACH is not a dedicated channel")),
755 valueof(t_WCN(t_RslChanNr_RACH(1), "RACH doesn't exist on timeslot")),
756 valueof(t_WCN(t_RslChanNr_BCCH(0), "BCCH is not a dedicated channel")),
757 valueof(t_WCN(t_RslChanNr_PCH_AGCH(0), "PCH/AGCH is not a dedicated channel")),
758 valueof(t_WCN(t_RslChanNr_Bm(0), "TS0 cannot be TCH/F")),
759 valueof(t_WCN(t_RslChanNr_Lm(0, 0), "TS0 cannot be TCH/H")),
760 valueof(t_WCN(t_RslChanNr_Lm(0, 1), "TS0 cannot be TCH/H")),
761 valueof(t_WCN(t_RslChanNr_PDCH(0), "TS0 cannot be PDCH")),
762 valueof(t_WCN(t_RslChanNr_SDCCH8(0, 0), "TS0 cannot be SDCCH/8")),
763 valueof(t_WCN(t_RslChanNr_SDCCH8(0, 7), "TS0 cannot be SDCCH/8")),
764 valueof(t_WCN(t_RslChanNr_SDCCH4(7, 0), "TS7 cannot be SDCCH/4")),
765 valueof(t_WCN(t_RslChanNr_SDCCH4(7, 3), "TS7 cannot be SDCCH/4")),
766 valueof(t_WCN(t_RslChanNr_Lm(1, 0), "TS1 cannot be TCH/H"))
767 };
768
769 for (var integer i := 0; i < sizeof(wrong); i := i+1) {
770 pars := valueof(t_Pars(wrong[i].chan_nr, ts_RSL_ChanMode_SIGN));
771 vc_conn := f_start_handler(refers(f_TC_chan_act_wrong_nr), pars);
772 vc_conn.done;
773 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200774 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +0100775}
776
Harald Weltee613f962018-04-18 22:38:16 +0200777/* execute the same callback function on a variety of logical channels */
Harald Welte2f2b2b72019-05-31 22:24:57 +0200778friend function f_testmatrix_each_chan(ConnHdlrPars pars, void_fn fn) runs on test_CT {
Harald Weltee613f962018-04-18 22:38:16 +0200779 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +0200780 f_init();
Harald Weltee613f962018-04-18 22:38:16 +0200781
782 /* test on each of the channels we have */
783 for (var integer i := 0; i < sizeof(g_AllChanTypes); i := i+1) {
784 pars.chan_nr := valueof(g_AllChanTypes[i]);
785
786 log(testcasename(), ": XXX Starting on ", g_AllChanTypes[i]);
787 vc_conn := f_start_handler(fn, pars);
788 vc_conn.done;
789 }
790
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200791 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Weltee613f962018-04-18 22:38:16 +0200792}
793
Harald Welte93640c62018-02-25 16:59:33 +0100794/***********************************************************************
Harald Welte629cc6b2018-03-11 17:19:05 +0100795 * SACCH handling
796 ***********************************************************************/
797
798private function f_exp_sacch(boolean exp) runs on ConnHdlr {
799 timer T_sacch := 3.0;
800 T_sacch.start;
801 alt {
802 [not exp] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200803 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received SACCH when not expecting it");
Harald Welte629cc6b2018-03-11 17:19:05 +0100804 }
805 [not exp] T_sacch.timeout {
806 setverdict(pass);
807 }
808 [exp] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) {
809 setverdict(pass);
810 }
811 [exp] T_sacch.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200812 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for SACCH on ", g_chan_nr));
Harald Welte629cc6b2018-03-11 17:19:05 +0100813 }
814 [] L1CTL.receive { repeat; }
815 [] RSL.receive { repeat; }
816 }
817}
818
819/* Test if DEACTIVATE SACCH actualy deactivates its transmission (TS 48.058 4.6) */
820private function f_TC_deact_sacch(charstring id) runs on ConnHdlr {
821 f_l1_tune(L1CTL);
822 RSL.clear;
823
824 /* activate the logical channel */
825 f_est_dchan();
826 L1CTL.clear;
827
828 /* check that SACCH actually are received as expected */
829 f_exp_sacch(true);
830
831 /* deactivate SACCH on the logical channel */
832 RSL.send(ts_RSL_DEACT_SACCH(g_chan_nr));
833 f_sleep(1.0);
834 L1CTL.clear;
835
836 /* check that no SACCH are received anymore */
837 f_exp_sacch(false);
838
839 /* release the channel */
840 f_rsl_chan_deact();
841 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
842}
843testcase TC_deact_sacch() runs on test_CT {
844 var ConnHdlr vc_conn;
845 var ConnHdlrPars pars;
846 f_init();
847 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
848 //for (var integer i := 0; i < 1; i := i+1) {
849 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
850 log(testcasename(), ": Starting for ", g_AllChannels[i]);
851 vc_conn := f_start_handler(refers(f_TC_deact_sacch), pars);
852 vc_conn.done;
853 }
854 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200855 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte629cc6b2018-03-11 17:19:05 +0100856}
857
Harald Welte55700662018-03-12 13:15:43 +0100858/* verify that given SACCH payload is present */
Harald Welteea17b912018-03-11 22:29:31 +0100859private function f_sacch_present(template octetstring l3_exp) runs on ConnHdlr {
860 var L1ctlDlMessage dl;
861 /* check that the specified SI5 value is actually sent */
862 timer T_sacch := 3.0;
863 L1CTL.clear;
864 T_sacch.start;
865 alt {
866 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) -> value dl {
867 var octetstring l3 := substr(dl.payload.data_ind.payload, 4, 19);
868 if (match(l3, l3_exp)) {
869 setverdict(pass);
870 } else {
871 repeat;
872 }
873 }
874 [] L1CTL.receive { repeat; }
875 [] T_sacch.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200876 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for SACCH ", l3_exp));
Harald Welteea17b912018-03-11 22:29:31 +0100877 }
878 }
879}
880
Harald Welte55700662018-03-12 13:15:43 +0100881/* verify that given SACCH payload is not present */
882private function f_sacch_missing(template octetstring l3_exp) runs on ConnHdlr {
883 var L1ctlDlMessage dl;
884 /* check that the specified SI5 value is actually sent */
885 timer T_sacch := 3.0;
886 L1CTL.clear;
887 T_sacch.start;
888 alt {
889 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(0))) -> value dl {
890 var octetstring l3 := substr(dl.payload.data_ind.payload, 4, 19);
891 if (match(l3, l3_exp)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200892 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unexpected SACCH ", dl));
Harald Welte55700662018-03-12 13:15:43 +0100893 } else {
894 repeat;
895 }
896 }
897 [] L1CTL.receive { repeat; }
898 [] T_sacch.timeout {
899 setverdict(pass);
900 }
901 }
902}
903
Harald Welte629cc6b2018-03-11 17:19:05 +0100904/* Test for default SACCH FILL transmitted in DL SACCH (all channel types) */
Harald Welteea17b912018-03-11 22:29:31 +0100905private function f_TC_sacch_filling(charstring id) runs on ConnHdlr {
906 /* Set a known default SACCH filling for SI5 */
907 var octetstring si5 := f_rnd_octstring(19);
908 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
909
910 f_l1_tune(L1CTL);
911 RSL.clear;
912
913 /* activate the logical channel */
914 f_est_dchan();
915
916 /* check that the specified SI5 value is actually sent */
917 f_sacch_present(si5);
918
919 /* release the channel */
920 RSL.clear;
921 f_rsl_chan_deact();
922 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
923}
924testcase TC_sacch_filling() runs on test_CT {
925 var ConnHdlr vc_conn;
926 var ConnHdlrPars pars;
927 f_init();
928 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
929 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
930 log(testcasename(), ": Starting for ", g_AllChannels[i]);
931 vc_conn := f_start_handler(refers(f_TC_sacch_filling), pars);
932 vc_conn.done;
933 }
934 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200935 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welteea17b912018-03-11 22:29:31 +0100936}
937
Harald Welte629cc6b2018-03-11 17:19:05 +0100938/* Test for lchan-specific SACCH INFO MODIFY (TS 48.058 4.12) */
Harald Welteea17b912018-03-11 22:29:31 +0100939private function f_TC_sacch_info_mod(charstring id) runs on ConnHdlr {
940 /* Set a known default SACCH filling for SI5 */
941 var octetstring si5 := f_rnd_octstring(19);
942 var octetstring si5_diff := f_rnd_octstring(19);
943 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
944
945 f_l1_tune(L1CTL);
946 RSL.clear;
947
948 log("Activating channel, expecting standard SI5");
949 /* activate the logical channel */
950 f_est_dchan();
951 /* check that the specified SI5 value is actually sent */
952 f_sacch_present(si5);
953
954 /* set channel-specific different SI5 */
955 log("Setting channel specific SACCH INFO, expecting it");
956 RSL.send(ts_RSL_SACCH_INF_MOD(g_chan_nr, RSL_SYSTEM_INFO_5, si5_diff))
957 /* check that the specified lchan-specific value is now used */
958 f_sacch_present(si5_diff);
959
960 /* deactivate the channel and re-activate it, this should result in default SI5 */
961 log("De-activating and re-activating channel, expecting standard SI5");
962 f_rsl_chan_deact();
963 f_rsl_chan_act(valueof(ts_RSL_ChanMode_SIGN));
964 /* Verify that the TRX-wide default SACCH filling is present again */
965 f_sacch_present(si5);
966
967 /* release the channel */
968 RSL.clear;
969 f_rsl_chan_deact();
970 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
971}
972testcase TC_sacch_info_mod() runs on test_CT {
973 var ConnHdlr vc_conn;
974 var ConnHdlrPars pars;
975 f_init();
976 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
977 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
978 log(testcasename(), ": Starting for ", g_AllChannels[i]);
979 vc_conn := f_start_handler(refers(f_TC_sacch_info_mod), pars);
980 vc_conn.done;
981 }
982 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +0200983 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welteea17b912018-03-11 22:29:31 +0100984}
985
Harald Welte075d84c2018-03-12 13:07:24 +0100986/* Test SACCH scheduling of multiple different SI message types */
987private function f_TC_sacch_multi(charstring id) runs on ConnHdlr {
988 var octetstring si5 := f_rnd_octstring(19);
989 var octetstring si5bis := f_rnd_octstring(19);
990 var octetstring si5ter := f_rnd_octstring(19);
991 var octetstring si6 := f_rnd_octstring(19);
992
993 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
994 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5bis, si5bis));
995 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5ter, si5ter));
996 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, si6));
997
998 f_l1_tune(L1CTL);
999 RSL.clear;
1000
1001 /* activate the logical channel */
1002 f_est_dchan();
1003 L1CTL.clear;
1004
1005 /* check that SACCH actually are received as expected */
1006 f_sacch_present(si5);
1007 f_sacch_present(si5bis);
1008 f_sacch_present(si5ter);
1009 f_sacch_present(si6);
1010
1011 /* release the channel */
1012 f_rsl_chan_deact();
1013 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1014}
1015testcase TC_sacch_multi() runs on test_CT {
1016 var ConnHdlr vc_conn;
1017 var ConnHdlrPars pars;
1018 f_init();
1019 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1020 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1021 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1022 vc_conn := f_start_handler(refers(f_TC_sacch_multi), pars);
1023 vc_conn.done;
1024 }
1025 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001026 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte075d84c2018-03-12 13:07:24 +01001027}
1028
Harald Welte55700662018-03-12 13:15:43 +01001029/* Test if SACH information is modified as expected */
1030private function f_TC_sacch_multi_chg(charstring id) runs on ConnHdlr {
1031 var octetstring si5 := f_rnd_octstring(19);
1032 var octetstring si6 := f_rnd_octstring(19);
1033
1034 /* First, configure both SI5 and SI6 to be transmitted */
1035 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
1036 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, si6));
1037
1038 f_l1_tune(L1CTL);
1039 RSL.clear;
1040
1041 /* activate the logical channel */
1042 f_est_dchan();
1043 L1CTL.clear;
1044
1045 /* check that SACCH actually are received as expected */
1046 f_sacch_present(si5);
1047 f_sacch_present(si6);
1048
1049 /* disable SI6 */
1050 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, ''O));
1051
1052 /* check that SI5 is still transmitted */
1053 f_sacch_present(si5);
1054 /* check if SI6 is now gone */
1055 f_sacch_missing(si6);
1056
1057 /* release the channel */
1058 f_rsl_chan_deact();
1059 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1060}
1061testcase TC_sacch_multi_chg() runs on test_CT {
1062 var ConnHdlr vc_conn;
1063 var ConnHdlrPars pars;
1064 f_init();
1065 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1066 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1067 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1068 vc_conn := f_start_handler(refers(f_TC_sacch_multi_chg), pars);
1069 vc_conn.done;
1070 }
1071 /* TODO: do the above in parallel, rather than sequentially? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001072 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte55700662018-03-12 13:15:43 +01001073}
1074
Harald Weltec8d363c2019-05-19 20:36:48 +02001075/* Test for SACCH information present in RSL CHAN ACT (overrides FILLING) */
1076private function f_TC_sacch_chan_act(charstring id) runs on ConnHdlr {
1077 var octetstring si5 := f_rnd_octstring(19);
1078 var octetstring si6 := f_rnd_octstring(19);
1079 var octetstring si5_specific := f_rnd_octstring(19);
1080 var octetstring si6_specific := f_rnd_octstring(19);
1081
1082 /* First, configure both SI5 and SI6 to be transmitted */
1083 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, si5));
1084 RSL.send(ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_6, si6));
1085
1086 f_l1_tune(L1CTL);
1087 RSL.clear;
1088
1089 /* activate channel with different SACCH filling */
1090 var RSL_SacchInfo sacch_info := valueof(ts_RSL_SacchInfo({
1091 ts_RSL_SacchInfoElem(RSL_SYSTEM_INFO_5, si5_specific),
1092 ts_RSL_SacchInfoElem(RSL_SYSTEM_INFO_6, si6_specific)
1093 }));
1094 var RSL_IE_List addl_ies := { valueof(t_RSL_IE(RSL_IE_SACCH_INFO,
1095 RSL_IE_Body:{sacch_info := sacch_info})) };
1096 f_est_dchan(more_ies := addl_ies);
1097
1098 /* check that SACCH actually are received as expected */
1099 f_sacch_present(si5_specific);
1100 f_sacch_present(si6_specific);
1101
1102 /* release the channel */
1103 f_rsl_chan_deact();
1104 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1105}
1106testcase TC_sacch_chan_act() runs on test_CT {
1107 var ConnHdlr vc_conn;
1108 var ConnHdlrPars pars;
1109 f_init();
1110
1111 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1112 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1113 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1114 vc_conn := f_start_handler(refers(f_TC_sacch_chan_act), pars);
1115 vc_conn.done;
1116 }
1117 /* TODO: do the above in parallel, rather than sequentially? */
1118 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1119}
1120
Harald Welte8b01c792019-05-19 22:51:25 +02001121/* verify that SACCH DL transmission is started only if MS power IE present
1122 * see section 4.1.3 of 3GPP TS 48.058 */
1123private function f_TC_sacch_chan_act_ho_async(charstring id) runs on ConnHdlr {
1124 var octetstring si5 := f_rnd_octstring(19);
1125
1126 f_l1_tune(L1CTL);
1127 RSL.clear;
1128
1129 /* Step 1: Activate ASYNC HO channel without MS power IE */
1130
1131 /* Activate channel on BTS side */
1132 f_rsl_chan_act(g_pars.chan_mode, act_type := t_RSL_IE_ActType_HO_ASYNC);
1133 /* don't perform immediate assignment here, as we're testing non-IA case */
1134 /* enable dedicated mode */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07001135 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(g_pars.chan_nr, 7, mp_trx0_arfcn));
Harald Welte8b01c792019-05-19 22:51:25 +02001136
1137 /* Verify that no DL SACCH is being received */
1138 f_sacch_missing(?);
1139
1140 f_rsl_chan_deact();
1141 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1142
1143
1144 /* Step 2: Activate ASYNC HO channel with MS power IE */
1145
1146 /* Activate channel on BTS side */
1147 var RSL_IE_List addl_ies := {
1148 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(0)}))
1149 };
1150 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_ASYNC);
1151 /* don't perform immediate assignment here, as we're testing non-IA case */
1152 /* enable dedicated mode */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07001153 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(g_pars.chan_nr, 7, mp_trx0_arfcn));
Harald Welte8b01c792019-05-19 22:51:25 +02001154
1155 /* Verify that DL SACCH is being received */
1156 f_sacch_present(si5);
1157
1158 f_rsl_chan_deact();
1159 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1160}
1161testcase TC_sacch_chan_act_ho_async() runs on test_CT {
1162 var ConnHdlr vc_conn;
1163 var ConnHdlrPars pars;
1164 f_init();
1165
1166 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1167 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1168 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1169 vc_conn := f_start_handler(refers(f_TC_sacch_chan_act_ho_async), pars);
1170 vc_conn.done;
1171 }
1172 /* TODO: do the above in parallel, rather than sequentially? */
1173 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1174}
1175
1176/* verify that SACCH DL transmission is started only if TA + MS power IEs present,
1177 * see section 4.1.4 of 3GPP TS 48.058 */
1178private function f_TC_sacch_chan_act_ho_sync(charstring id) runs on ConnHdlr {
1179 var octetstring si5 := f_rnd_octstring(19);
1180 var RSL_IE_List addl_ies;
1181
1182 f_l1_tune(L1CTL);
1183 RSL.clear;
1184
1185 /* Step 1: Activate SYNC HO channel without MS power IE */
1186
1187 /* Activate channel on BTS side */
1188 f_rsl_chan_act(g_pars.chan_mode, act_type := t_RSL_IE_ActType_HO_SYNC);
1189 /* don't perform immediate assignment here, as we're testing non-IA case */
1190 /* enable dedicated mode */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07001191 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(g_pars.chan_nr, 7, mp_trx0_arfcn));
Harald Welte8b01c792019-05-19 22:51:25 +02001192
1193 /* Verify that no DL SACCH is being received */
1194 f_sacch_missing(?);
1195
1196 f_rsl_chan_deact();
1197 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1198
1199
1200 /* Step 2a: Activate SYNC HO channel with only MS power IE */
1201
1202 /* Activate channel on BTS side */
1203 addl_ies := {
1204 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(0)}))
1205 };
1206 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
1207 /* don't perform immediate assignment here, as we're testing non-IA case */
1208 /* enable dedicated mode */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07001209 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(g_pars.chan_nr, 7, mp_trx0_arfcn));
Harald Welte8b01c792019-05-19 22:51:25 +02001210
1211 /* Verify that no DL SACCH is being received */
1212 f_sacch_missing(?);
1213
1214 f_rsl_chan_deact();
1215 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1216
1217
1218 /* Step 2b: Activate SYNC HO channel with TA IE */
1219
1220 /* Activate channel on BTS side */
1221 addl_ies := {
1222 valueof(t_RSL_IE(RSL_IE_TIMING_ADVANCE, RSL_IE_Body:{timing_adv := 0}))
1223 };
1224 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
1225 /* don't perform immediate assignment here, as we're testing non-IA case */
1226 /* enable dedicated mode */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07001227 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(g_pars.chan_nr, 7, mp_trx0_arfcn));
Harald Welte8b01c792019-05-19 22:51:25 +02001228
1229 /* Verify that no DL SACCH is being received */
1230 f_sacch_missing(?);
1231
1232 f_rsl_chan_deact();
1233 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1234
1235
1236 /* Step 3: Activate SYNC HO channel with MS power IE and TA IE */
1237
1238 /* Activate channel on BTS side */
1239 addl_ies := {
1240 valueof(t_RSL_IE(RSL_IE_TIMING_ADVANCE, RSL_IE_Body:{timing_adv := 0})),
1241 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(0)}))
1242 };
1243 f_rsl_chan_act(g_pars.chan_mode, more_ies := addl_ies, act_type := t_RSL_IE_ActType_HO_SYNC);
1244 /* don't perform immediate assignment here, as we're testing non-IA case */
1245 /* enable dedicated mode */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07001246 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(g_pars.chan_nr, 7, mp_trx0_arfcn));
Harald Welte8b01c792019-05-19 22:51:25 +02001247
1248 /* Verify that DL SACCH is being received */
1249 f_sacch_present(si5);
1250
1251 f_rsl_chan_deact();
1252 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1253}
1254testcase TC_sacch_chan_act_ho_sync() runs on test_CT {
1255 var ConnHdlr vc_conn;
1256 var ConnHdlrPars pars;
1257 f_init();
1258
1259 for (var integer i := 0; i < sizeof(g_AllChannels); i := i+1) {
1260 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1261 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1262 vc_conn := f_start_handler(refers(f_TC_sacch_chan_act_ho_sync), pars);
1263 vc_conn.done;
1264 }
1265 /* TODO: do the above in parallel, rather than sequentially? */
1266 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1267}
Harald Welte629cc6b2018-03-11 17:19:05 +01001268
1269
1270/***********************************************************************
Harald Welte93640c62018-02-25 16:59:33 +01001271 * RACH Handling
1272 ***********************************************************************/
1273
Harald Welte8c24c2b2018-02-26 08:31:31 +01001274/* like L1SAP_IS_PACKET_RACH */
1275private function ra_is_ps(OCT1 ra) return boolean {
Harald Welte56c05802018-02-28 21:39:35 +01001276 if ((ra and4b 'F0'O == '70'O) and (ra and4b '0F'O != '0F'O)) {
Harald Welte8c24c2b2018-02-26 08:31:31 +01001277 return true;
1278 }
1279 return false;
1280}
1281
1282/* generate a random RACH for circuit-switched */
1283private function f_rnd_ra_cs() return OCT1 {
1284 var OCT1 ra;
1285 do {
1286 ra := f_rnd_octstring(1);
1287 } while (ra_is_ps(ra));
1288 return ra;
1289}
1290
Harald Welte883340c2018-02-28 18:59:29 +01001291/* generate a random RACH for packet-switched */
1292private function f_rnd_ra_ps() return OCT1 {
1293 var OCT1 ra;
1294 do {
1295 ra := f_rnd_octstring(1);
1296 } while (not ra_is_ps(ra));
1297 return ra;
1298}
1299
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +07001300/* generate a random 11-bit RA (packet-switched only) */
1301private function f_rnd_ra11_ps() return BIT11 {
1302 var integer ra11 := f_rnd_int(bit2int('11111111111'B));
1303 return int2bit(ra11, 11);
1304}
1305
Harald Welte8c24c2b2018-02-26 08:31:31 +01001306/* Send 1000 RACH requests and check their RA+FN on the RSL side */
1307testcase TC_rach_content() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02001308 f_init();
Harald Welte8c24c2b2018-02-26 08:31:31 +01001309 f_init_l1ctl();
Harald Welte68e495b2018-02-25 00:05:57 +01001310 f_l1_tune(L1CTL);
Harald Welte70767382018-02-21 12:16:40 +01001311
Harald Welte8c24c2b2018-02-26 08:31:31 +01001312 var GsmFrameNumber fn_last := 0;
Maxa199a2e2019-02-25 16:31:11 +01001313 var boolean test_failed := false;
Harald Welte8c24c2b2018-02-26 08:31:31 +01001314 for (var integer i := 0; i < 1000; i := i+1) {
1315 var OCT1 ra := f_rnd_ra_cs();
1316 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1317 if (fn == fn_last) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001318 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
Harald Welte8c24c2b2018-02-26 08:31:31 +01001319 }
1320 fn_last := fn;
1321
1322 timer T := 5.0;
Harald Welte56c05802018-02-28 21:39:35 +01001323 T.start;
Harald Welte8c24c2b2018-02-26 08:31:31 +01001324 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001325 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(ra, fn, t_RslChanNr_RACH(0)))) {
Harald Welte8c24c2b2018-02-26 08:31:31 +01001326 T.stop;
1327 }
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001328 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(?, ?, ?, ?))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001329 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected CHAN RQD");
Harald Welte8c24c2b2018-02-26 08:31:31 +01001330 }
1331 [] RSL_CCHAN.receive { repeat; }
1332 [] T.timeout {
Maxa199a2e2019-02-25 16:31:11 +01001333 test_failed := true;
1334 log("[", i, "] Timeout waiting for CHAN RQD FN=", fn, " RA=", ra);
Harald Welte8c24c2b2018-02-26 08:31:31 +01001335 }
1336 }
1337 }
Maxba06feb2019-03-05 10:52:46 +01001338 if (test_failed) {
1339 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Some out of 1000 RACH requests timed out"));
Maxa199a2e2019-02-25 16:31:11 +01001340 }
Maxba06feb2019-03-05 10:52:46 +01001341 setverdict(pass);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001342 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001343}
Harald Welte8c24c2b2018-02-26 08:31:31 +01001344
1345/* Send 1000 RACH Requests (flood ~ 89/s) and count if count(Abis) == count(Um) */
1346testcase TC_rach_count() runs on test_CT {
Harald Welte294b0a22018-03-10 23:26:48 +01001347 f_init();
Harald Welte8c24c2b2018-02-26 08:31:31 +01001348 f_init_l1ctl();
Harald Welte294b0a22018-03-10 23:26:48 +01001349 f_sleep(1.0);
Harald Welte8c24c2b2018-02-26 08:31:31 +01001350 f_l1_tune(L1CTL);
1351
1352 var GsmFrameNumber fn_last := 0;
1353 for (var integer i := 0; i < 1000; i := i+1) {
1354 var OCT1 ra := f_rnd_ra_cs();
1355 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1356 if (fn == fn_last) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001357 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
Harald Welte8c24c2b2018-02-26 08:31:31 +01001358 }
1359 fn_last := fn;
1360 }
1361 var integer rsl_chrqd := 0;
1362 timer T := 3.0;
Harald Welte56c05802018-02-28 21:39:35 +01001363 T.start;
Harald Welte8c24c2b2018-02-26 08:31:31 +01001364 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001365 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(?,?))) {
Harald Welte8c24c2b2018-02-26 08:31:31 +01001366 rsl_chrqd := rsl_chrqd + 1;
Harald Weltec3a3f452018-02-26 17:37:47 +01001367 f_timer_safe_restart(T);
Harald Welte8c24c2b2018-02-26 08:31:31 +01001368 repeat;
1369 }
1370 [] RSL_CCHAN.receive { repeat; }
1371 [] T.timeout { }
1372 }
1373 if (rsl_chrqd == 1000) {
1374 setverdict(pass);
1375 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001376 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received only ", rsl_chrqd, " out of 1000 RACH"));
Harald Welte8c24c2b2018-02-26 08:31:31 +01001377 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001378 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01001379}
1380
Harald Welte3453ab42019-05-24 21:19:58 +02001381private function f_vty_load_ind_thresh(integer period := 10, integer bts_nr := 0) runs on test_CT {
1382 var charstring bts_str := "bts " & int2str(bts_nr);
1383 f_vty_config2(BSCVTY, {"network", bts_str}, "ccch load-indication-threshold " & int2str(period));
1384}
1385
1386/* empirical value: Number of RACH slots per reporting interval (1s) on combined CCCH */
1387private template integer tr_rach_slots_per_interval := (90 .. 130);
1388
1389/* Expect 0 RACH load on an idle BTS that has just started up */
1390testcase TC_rach_load_idle_thresh0() runs on test_CT {
1391 var ASP_RSL_Unitdata rx_ud;
1392
1393 f_init_vty_bsc();
1394 /* send load indications even at 0% load */
1395 f_vty_load_ind_thresh(0);
1396 f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
1397 f_sleep(2.0);
1398
1399 f_init();
1400
1401 timer T := 5.0;
1402 T.start;
1403 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001404 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, 0, 0))) {
Harald Welte3453ab42019-05-24 21:19:58 +02001405 setverdict(pass);
1406 repeat;
1407 }
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001408 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
Harald Welte3453ab42019-05-24 21:19:58 +02001409 setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
1410 repeat;
1411 }
1412 [] RSL_CCHAN.receive {
1413 repeat;
1414 }
1415 [] T.timeout { }
1416 }
1417
1418 f_vty_load_ind_thresh(10);
1419 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1420}
1421
1422/* Expect no RACH load indications on an idle BTS that has just started up (default threshold 10%) */
1423testcase TC_rach_load_idle_below_thresh() runs on test_CT {
1424 var ASP_RSL_Unitdata rx_ud;
1425
1426 f_init_vty_bsc();
1427 f_init();
1428
1429 timer T := 5.0;
1430 T.start;
1431 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001432 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
Harald Welte3453ab42019-05-24 21:19:58 +02001433 setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
1434 repeat;
1435 }
1436 [] RSL_CCHAN.receive {
1437 repeat;
1438 }
1439 [] T.timeout {
1440 setverdict(pass);
1441 }
1442 }
1443
1444 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1445}
1446
1447/* Expect 0 RACH load on an idle BTS that has just started up */
1448testcase TC_rach_load_count() runs on test_CT {
1449 var ASP_RSL_Unitdata rx_ud;
1450 var integer load_access_count := 0;
1451
1452 f_init_vty_bsc();
1453 /* send load indications even at 0% load */
1454 f_vty_load_ind_thresh(0);
1455 f_vty_transceive(BSCVTY, "drop bts connection 0 oml");
1456 f_sleep(2.0);
1457 f_init();
1458
1459 f_init_l1ctl();
1460 f_sleep(1.0);
1461 f_l1_tune(L1CTL);
1462
1463 var GsmFrameNumber fn_last := 0;
1464 for (var integer i := 0; i < 1000; i := i+1) {
1465 var OCT1 ra := f_rnd_ra_cs();
1466 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1467 if (fn == fn_last) {
1468 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
1469 }
1470 fn_last := fn;
1471 }
1472
1473 timer T := 5.0;
1474 T.start;
1475 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001476 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(tr_rach_slots_per_interval, ?, ?)))
Harald Welte3453ab42019-05-24 21:19:58 +02001477 -> value rx_ud {
1478 var RSL_IE_Body ie;
1479 f_rsl_find_ie(rx_ud.rsl, RSL_IE_RACH_LOAD, ie);
1480 load_access_count := load_access_count + ie.rach_load.access_count;
1481 if (ie.rach_load.busy_count < ie.rach_load.access_count) {
1482 setverdict(fail, "Access count cannot be < Busy count");
1483 }
1484 repeat;
1485 }
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001486 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_RACH_LOAD_IND(?, ?, ?))) -> value rx_ud {
Harald Welte3453ab42019-05-24 21:19:58 +02001487 setverdict(fail, "Unexpected RACH LOAD IND: ", rx_ud);
1488 repeat;
1489 }
1490 [] RSL_CCHAN.receive {
1491 repeat;
1492 }
1493 [] T.timeout { }
1494 }
1495 if (load_access_count == 1000) {
1496 setverdict(pass);
1497 } else {
1498 setverdict(fail, "Load reports state ", load_access_count, " RACH, but we sent 1000");
1499 }
1500
1501 f_vty_load_ind_thresh(10);
1502 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1503}
1504
Harald Welte54a2a2d2018-02-26 09:14:05 +01001505private function f_rach_toffs(int16_t toffs256, boolean expect_pass) runs on test_CT {
Harald Weltef8df4cb2018-03-10 15:15:08 +01001506 var TrxcMessage ret;
Harald Welte54a2a2d2018-02-26 09:14:05 +01001507 /* tell fake_trx to use a given timing offset for all bursts */
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +07001508 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id, valueof(ts_TRXC_FAKE_TIMING(toffs256)));
Harald Welte54a2a2d2018-02-26 09:14:05 +01001509 f_sleep(0.5);
1510
1511 /* Transmit RACH request + wait for confirmation */
1512 var OCT1 ra := f_rnd_ra_cs();
1513 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
1514
1515 /* Check for expected result */
1516 timer T := 1.5;
1517 T.start;
1518 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001519 [expect_pass] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
Harald Welte54a2a2d2018-02-26 09:14:05 +01001520 setverdict(pass);
1521 }
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07001522 [not expect_pass] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_CHAN_RQD(ra, fn))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001523 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("RACH passed but was expected to be dropped: ", toffs256));
Harald Welte54a2a2d2018-02-26 09:14:05 +01001524 }
1525 [] RSL_CCHAN.receive { repeat; }
1526 [not expect_pass] T.timeout {
1527 setverdict(pass);
1528 }
1529 [expect_pass] T.timeout {
Max6e053042019-03-14 16:34:22 +01001530 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for CHAN RQD: FN=", fn, " RA=", ra));
Harald Welte54a2a2d2018-02-26 09:14:05 +01001531 }
1532 }
1533}
1534
1535/* Test if dropping of RACH Based on NM_ATT_MAX_TA works */
1536testcase TC_rach_max_ta() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02001537 f_init();
Harald Welte54a2a2d2018-02-26 09:14:05 +01001538 f_init_l1ctl();
1539 f_l1_tune(L1CTL);
Harald Welte54a2a2d2018-02-26 09:14:05 +01001540 f_sleep(1.0);
1541
1542 /* default max-ta is 63 (full range of GSM timing advance */
1543
Vadim Yanitskiyc81d6e42018-03-05 22:39:01 +07001544 /* We allow early arrival up to 2 symbols */
1545 f_rach_toffs(-1*256, true);
1546 f_rach_toffs(-2*256, true);
Harald Welte54a2a2d2018-02-26 09:14:05 +01001547 f_rach_toffs(-10*256, false);
1548
1549 /* 0 / 32 / 63 bits is legal / permitted */
1550 f_rach_toffs(0, true);
1551 f_rach_toffs(32*256, true);
1552 f_rach_toffs(63*256, true);
1553
1554 /* more than 63 bits is not legal / permitted */
1555 f_rach_toffs(64*256, false);
1556 f_rach_toffs(127*256, false);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001557 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte54a2a2d2018-02-26 09:14:05 +01001558}
Harald Welte8c24c2b2018-02-26 08:31:31 +01001559
Vadim Yanitskiy7c2c10c2019-05-31 20:42:01 +07001560function f_TC_ho_rach(charstring id) runs on ConnHdlr {
1561 var GsmFrameNumber fn;
1562 var RSL_Message rm;
1563
1564 f_l1_tune(L1CTL);
1565 RSL.clear;
1566
1567 /* Generate a random Handover Reference */
1568 var integer ho_ref := oct2int(f_rnd_octstring(1));
1569
1570 /* Handover Reference IE (see 3GPP TS 48.058, 9.3.9) */
1571 var RSL_IE ho_ref_ie := valueof(t_RSL_IE(RSL_IE_HANDO_REF,
1572 RSL_IE_Body:{ handover_ref := ho_ref }));
1573
1574 /* Activate a channel on the BTS side (no encryption) */
1575 f_rsl_chan_act(g_pars.chan_mode, more_ies := { ho_ref_ie },
1576 act_type := t_RSL_IE_ActType_HO_SYNC);
1577
1578 /* Switch the MS side (e.g. trxcon) to a dedicated channel without
1579 * waiting for Immediate Assignment and sending Access Burst */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07001580 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(g_pars.chan_nr, 7, mp_trx0_arfcn));
Vadim Yanitskiy7c2c10c2019-05-31 20:42:01 +07001581
1582 /* Send handover Access Burst */
1583 fn := f_L1CTL_RACH(L1CTL, ho_ref, chan_nr := g_pars.chan_nr);
1584
1585 /* TODO: test mismatching Handover Reference, and missing IE */
1586
1587 /* Wait for handover detection */
1588 timer T := 3.0;
1589 T.start;
1590 alt {
1591 [] RSL.receive(tr_RSL_HANDO_DET(g_pars.chan_nr)) -> value rm {
1592 log("Handover RACH has been detected: ", rm);
1593 setverdict(pass);
1594 }
1595 [] RSL.receive(tr_RSL_CHAN_RQD(?, ?, ?, ?)) -> value rm {
1596 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1597 log2str("RSL_CHAN_RQD was not expected: ", rm));
1598 }
1599 [] RSL.receive { repeat; }
1600 [] T.timeout {
1601 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1602 log2str("Timeout waiting for handover RACH: FN=", fn, " RA=", ho_ref));
1603 }
1604 }
1605
1606 /* Release the channel */
1607 f_rsl_chan_deact();
1608 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
1609}
1610
1611/* Test handover RACH detection */
1612testcase TC_ho_rach() runs on test_CT {
1613 var ConnHdlrPars pars;
1614 var ConnHdlr vc_conn;
1615
1616 f_init();
1617
1618 for (var integer i := 0; i < sizeof(g_AllChannels); i := i + 1) {
1619 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN));
1620 log(testcasename(), ": Starting for ", g_AllChannels[i]);
1621 vc_conn := f_start_handler(refers(f_TC_ho_rach), pars);
1622 vc_conn.done;
1623 }
1624
1625 /* TODO: do the above in parallel, rather than sequentially? */
1626 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
1627}
1628
Harald Welte93640c62018-02-25 16:59:33 +01001629/***********************************************************************
1630 * Measurement Processing / Reporting
1631 ***********************************************************************/
1632
Harald Welte70767382018-02-21 12:16:40 +01001633template LapdmAddressField ts_LapdmAddr(LapdmSapi sapi, boolean c_r) := {
1634 spare := '0'B,
1635 lpd := 0,
1636 sapi := sapi,
1637 c_r := c_r,
1638 ea := true
1639}
1640
Harald Welted879bd92018-03-12 15:01:23 +01001641template LapdmFrameAB ts_LAPDm_AB(LapdmSapi sapi, boolean c_r, boolean p, octetstring pl) := {
Harald Welte70767382018-02-21 12:16:40 +01001642 addr := ts_LapdmAddr(sapi, c_r),
Harald Welted879bd92018-03-12 15:01:23 +01001643 ctrl := ts_LapdmCtrlUI(p),
Harald Welte70767382018-02-21 12:16:40 +01001644 len := 0, /* overwritten */
1645 m := false,
1646 el := 1,
1647 payload := pl
1648}
1649
1650/* handle incoming downlink SACCH and respond with uplink SACCH (meas res) */
1651altstep as_l1_sacch() runs on ConnHdlr {
1652 var L1ctlDlMessage l1_dl;
Harald Weltef8df4cb2018-03-10 15:15:08 +01001653 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
Harald Welte70767382018-02-21 12:16:40 +01001654 log("SACCH received: ", l1_dl.payload.data_ind.payload);
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +02001655 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 +01001656 var LapdmFrameAB lb := valueof(ts_LAPDm_AB(0, false, false, enc_GsmRrL3Message(meas_rep)));
Harald Welte70767382018-02-21 12:16:40 +01001657 log("LAPDm: ", lb);
Pau Espin Pedroled359cb2018-09-28 16:08:24 +02001658
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07001659 var template (value) SacchL1Header l1h := ts_SacchL1Header(
1660 g_pars.l1_pars.ms_power_level, false,
1661 g_pars.l1_pars.ms_actual_ta);
1662
1663 /* TODO: we can use an extension of TTCN-3 for that, i.e. PADDING('2B'O) */
1664 var octetstring l2 := f_pad_oct(enc_LapdmFrameAB(lb), 21, '2B'O);
1665
1666 log("Sending Measurement Report: ", l1h, l2);
1667 L1CTL.send(ts_L1CTL_DATA_REQ_SACCH(g_chan_nr, ts_RslLinkID_SACCH(0), l1h, l2));
Harald Welte70767382018-02-21 12:16:40 +01001668 repeat;
1669 }
1670}
1671
1672altstep as_l1_dcch() runs on ConnHdlr {
1673 var L1ctlDlMessage l1_dl;
Harald Weltef8df4cb2018-03-10 15:15:08 +01001674 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_DCCH(?))) -> value l1_dl {
Harald Welte70767382018-02-21 12:16:40 +01001675 log("DCCH received: ", l1_dl.payload.data_ind.payload);
1676 var octetstring pl := '010301'O;
Vadim Yanitskiy31e7c672018-07-27 02:23:16 +07001677 L1CTL.send(ts_L1CTL_DATA_REQ(g_chan_nr, ts_RslLinkID_DCCH(0),
1678 f_pad_oct(pl, 23, '2B'O)));
Harald Welte70767382018-02-21 12:16:40 +01001679 repeat;
1680 }
1681}
1682
1683type record MeasElem {
1684 uint6_t rxlev,
1685 uint3_t rxqual
1686}
1687
1688type record MeasElemFS {
1689 MeasElem full,
1690 MeasElem sub
1691}
1692
1693type record ConnL1Pars {
1694 boolean dtx_enabled,
Harald Welte685d5982018-02-27 20:42:05 +01001695 boolean toa256_enabled,
Harald Welte70767382018-02-21 12:16:40 +01001696 MeasElemFS meas_ul,
1697 int16_t timing_offset_256syms,
1698 uint5_t bs_power_level,
1699 uint5_t ms_power_level,
1700 uint8_t ms_actual_ta
1701}
1702
1703/* Convert tiing offset from 1/256th symbol to RSL Timing Offset */
1704private function toffs256s_to_rsl(int16_t toffs256s) return uint8_t {
1705 return 63 + (toffs256s/256);
1706}
1707
Harald Welted5684392018-03-10 18:22:04 +01001708private function f_max(integer a, integer b) return integer {
1709 if (a > b) {
1710 return a;
1711 } else {
1712 return b;
1713 }
1714}
1715
1716private function f_min(integer a, integer b) return integer {
1717 if (a < b) {
1718 return a;
1719 } else {
1720 return b;
1721 }
1722}
1723
1724/* compute negative tolerance val-tolerance, ensure >= min */
1725private function f_tolerance_neg(integer val, integer min, integer tolerance) return integer {
1726 val := val - tolerance;
1727 return f_max(val, min);
1728}
1729
1730/* compute positive tolerance val+tolerance, ensure <= max */
1731private function f_tolerance_pos(integer val, integer max, integer tolerance) return integer {
1732 val := val + tolerance;
1733 return f_min(val, max);
1734}
1735
1736/* return a template of (val-tolerance .. val+tolerance) ensuring it is within (min .. max) */
1737private function f_tolerance(integer val, integer min, integer max, integer tolerance)
1738return template integer {
1739 var template integer ret;
1740 ret := (f_tolerance_neg(val, min, tolerance) .. f_tolerance_pos(val, max, tolerance));
1741 return ret;
1742}
1743
1744
Harald Welte70767382018-02-21 12:16:40 +01001745/* build a template for matching measurement results against */
1746private function f_build_meas_res_tmpl() runs on ConnHdlr return template RSL_Message {
1747 var ConnL1Pars l1p := g_pars.l1_pars;
1748 var template RSL_IE_UplinkMeas ul_meas := {
1749 len := 3,
1750 rfu := '0'B,
1751 dtx_d := l1p.dtx_enabled,
Harald Welted5684392018-03-10 18:22:04 +01001752 rxlev_f_u := f_tolerance(l1p.meas_ul.full.rxlev, 0, 63, mp_tolerance_rxlev),
Harald Welte70767382018-02-21 12:16:40 +01001753 reserved1 := '00'B,
Harald Welted5684392018-03-10 18:22:04 +01001754 rxlev_s_u := f_tolerance(l1p.meas_ul.sub.rxlev, 0, 63, mp_tolerance_rxlev),
Harald Welte70767382018-02-21 12:16:40 +01001755 reserved2 := '00'B,
Harald Welted5684392018-03-10 18:22:04 +01001756 rxq_f_u := f_tolerance(l1p.meas_ul.full.rxqual, 0, 7, mp_tolerance_rxqual),
1757 rxq_s_u := f_tolerance(l1p.meas_ul.sub.rxqual, 0, 7, mp_tolerance_rxqual),
Harald Welte70767382018-02-21 12:16:40 +01001758 supp_meas_info := omit
1759 };
Harald Welte685d5982018-02-27 20:42:05 +01001760 if (l1p.toa256_enabled) {
Harald Welte15de8ba2018-06-29 08:51:42 +02001761 ul_meas.len := (3+8);
1762 ul_meas.supp_meas_info := {
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001763 toa256_mean := f_tolerance(l1p.timing_offset_256syms, -63*256, 192*256, mp_tolerance_timing_offset_256syms),
Harald Welte15de8ba2018-06-29 08:51:42 +02001764 toa256_min := ?,
1765 toa256_max := ?,
1766 toa256_std_dev := ?
1767 }
Harald Welte685d5982018-02-27 20:42:05 +01001768 }
Harald Welte70767382018-02-21 12:16:40 +01001769 var template RSL_IE_BS_Power bs_power := {
1770 reserved := 0,
1771 epc := false,
1772 fpc := false,
1773 power_level := l1p.bs_power_level
1774 };
1775 var template RSL_IE_L1Info l1_info := {
1776 ms_power_lvl := l1p.ms_power_level,
1777 fpc := false,
1778 reserved := 0,
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001779 actual_ta := f_tolerance(l1p.ms_actual_ta, 0, 63, mp_tolerance_timing_offset_256syms/256)
Harald Welte70767382018-02-21 12:16:40 +01001780 };
1781 var uint8_t offs := toffs256s_to_rsl(l1p.timing_offset_256syms);
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001782 var template uint8_t t_toffs := f_tolerance(offs, 0, 255, mp_tolerance_timing_offset_256syms/256);
Harald Welte70767382018-02-21 12:16:40 +01001783 return tr_RSL_MEAS_RES_OSMO(g_chan_nr, g_next_meas_res_nr, ul_meas, bs_power, l1_info,
1784 ?, t_toffs);
1785}
1786
Philipp Maierdd841d32019-12-17 14:44:54 +01001787/* build a template for matching measurement results that do not contain any
1788 * MS related measurement (l1_info, l3_info and ms timing offset). */
1789private function f_build_meas_res_tmpl_empty() runs on ConnHdlr return template RSL_Message {
1790 var ConnL1Pars l1p := g_pars.l1_pars;
1791 var template RSL_IE_UplinkMeas ul_meas := {
1792 len := 3,
1793 rfu := '0'B,
1794 dtx_d := l1p.dtx_enabled,
1795 rxlev_f_u := ?,
1796 reserved1 := '00'B,
1797 rxlev_s_u := ?,
1798 reserved2 := '00'B,
1799 rxq_f_u := ?,
1800 rxq_s_u := ?,
1801 supp_meas_info := omit
1802 };
1803 if (l1p.toa256_enabled) {
1804 ul_meas.len := (3+8);
1805 ul_meas.supp_meas_info := {
1806 toa256_mean := f_tolerance(l1p.timing_offset_256syms, -63*256, 192*256, mp_tolerance_timing_offset_256syms),
1807 toa256_min := ?,
1808 toa256_max := ?,
1809 toa256_std_dev := ?
1810 }
1811 }
1812 var template RSL_IE_BS_Power bs_power := {
1813 reserved := 0,
1814 epc := false,
1815 fpc := false,
1816 power_level := l1p.bs_power_level
1817 };
1818
1819 return tr_RSL_MEAS_RES_EMPTY(g_chan_nr, g_next_meas_res_nr, ul_meas, bs_power);
1820}
1821
Harald Welte70767382018-02-21 12:16:40 +01001822/* verify we regularly receive measurement reports with incrementing numbers */
Vadim Yanitskiy41baf002018-10-04 17:44:50 +07001823altstep as_meas_res(boolean verify_meas := true) runs on ConnHdlr {
Harald Welte70767382018-02-21 12:16:40 +01001824 var RSL_Message rsl;
Philipp Maierdd841d32019-12-17 14:44:54 +01001825 var boolean chan_est := false;
1826
Vadim Yanitskiy41baf002018-10-04 17:44:50 +07001827 [not verify_meas] RSL.receive(tr_RSL_MEAS_RES(?)) { repeat; }
Philipp Maierdd841d32019-12-17 14:44:54 +01001828
1829 /* Receive osmocom specific measurement reports. This is the normal
1830 * case. Here we verify that the measurement reports we sent are
1831 * comming back as we expect them. */
Harald Welte70767382018-02-21 12:16:40 +01001832 [] RSL.receive(f_build_meas_res_tmpl()) -> value rsl {
1833 /* increment counter of next to-be-expected meas rep */
1834 g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
1835 /* Re-start the timer expecting the next MEAS RES */
Harald Weltec3a3f452018-02-26 17:37:47 +01001836 f_timer_safe_restart(g_Tmeas_exp);
Philipp Maierdd841d32019-12-17 14:44:54 +01001837
1838 /* The following two cases may only happen in the beginning
1839 * of the channel establishment phase. Once we have received
1840 * the "our" measurement report the first time, the channel
1841 * is established and empty or hardcoded TRXCON reports must
1842 * not occur anymore. */
1843 chan_est := true;
1844
1845 repeat;
1846 }
1847
1848 /* When the BTS has established the channel, the MS might need slightly
1849 * more time to establish the channel and actually start sending. The
1850 * result is then a measurement report that just lacks the measurement
1851 * information of the MS. This is normal and we tolerate this behavior. */
1852 [chan_est == false] RSL.receive(f_build_meas_res_tmpl_empty()) -> value rsl {
1853 /* increment counter of next to-be-expected meas rep */
1854 g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
1855 /* Re-start the timer expecting the next MEAS RES */
1856 f_timer_safe_restart(g_Tmeas_exp);
Harald Welte70767382018-02-21 12:16:40 +01001857 repeat;
1858 }
Philipp Maierdd841d32019-12-17 14:44:54 +01001859
1860 /* Due to the TDMA nature of GSM, TRXCON implements a way to emit dummy
1861 * measurements if the TTCN3 side does not supply measurement input in
1862 * time. In those cases TRXCON will either use a cached measurement
1863 * report or a hardcoded one. If TRXCON picks the hardcoded measurement
1864 * report the templates above will not match. We tolerate this
1865 * behavior, but only once. */
1866 [chan_est == false] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr, g_next_meas_res_nr)) -> value rsl {
Harald Weltefa45e9e2018-03-10 18:59:03 +01001867 /* increment counter of next to-be-expected meas rep */
1868 g_next_meas_res_nr := (g_next_meas_res_nr + 1) mod 256;
1869 if (g_first_meas_res) {
1870 g_first_meas_res := false;
1871 repeat;
1872 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001873 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unspecific MEAS RES ", rsl));
Harald Weltefa45e9e2018-03-10 18:59:03 +01001874 }
Harald Welte70767382018-02-21 12:16:40 +01001875 }
1876 [] RSL.receive(tr_RSL_MEAS_RES(?)) -> value rsl {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001877 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received unexpected MEAS RES ", rsl));
Harald Welte70767382018-02-21 12:16:40 +01001878 }
Pau Espin Pedrol425b62f2018-07-06 16:11:43 +02001879 [g_Tmeas_exp.running] g_Tmeas_exp.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001880 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Didn't receive expected measurement result")
Harald Welte70767382018-02-21 12:16:40 +01001881 }
1882}
1883
Harald Weltee613f962018-04-18 22:38:16 +02001884private function f_alg_id_to_l1ctl(RSL_AlgId rsl_alg_id) return uint8_t {
1885 select (rsl_alg_id) {
1886 case (RSL_ALG_ID_A5_0) { return 0; }
1887 case (RSL_ALG_ID_A5_1) { return 1; }
1888 case (RSL_ALG_ID_A5_2) { return 2; }
1889 case (RSL_ALG_ID_A5_3) { return 3; }
1890 case (RSL_ALG_ID_A5_4) { return 4; }
1891 case (RSL_ALG_ID_A5_5) { return 5; }
1892 case (RSL_ALG_ID_A5_6) { return 6; }
1893 case (RSL_ALG_ID_A5_7) { return 7; }
1894 case else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001895 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unknwon Algorithm ID");
1896 /* Make compiler happy by calling mtc.stop here. It is already
1897 * called in f_shutdown */
Daniel Willmann17ddd852018-07-05 17:33:20 +02001898 mtc.stop;
Harald Weltee613f962018-04-18 22:38:16 +02001899 }
1900 }
1901}
1902
1903private function f_alg_id_to_l3(RSL_AlgId rsl_alg_id) return BIT3 {
1904 select (rsl_alg_id) {
1905 case (RSL_ALG_ID_A5_1) { return '000'B; }
1906 case (RSL_ALG_ID_A5_2) { return '001'B; }
1907 case (RSL_ALG_ID_A5_3) { return '010'B; }
1908 case (RSL_ALG_ID_A5_4) { return '011'B; }
1909 case (RSL_ALG_ID_A5_5) { return '100'B; }
1910 case (RSL_ALG_ID_A5_6) { return '101'B; }
1911 case (RSL_ALG_ID_A5_7) { return '110'B; }
1912 case else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02001913 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unknwon Algorithm ID");
1914 /* Make compiler happy by calling mtc.stop here. It is already
1915 * called in f_shutdown */
Daniel Willmann17ddd852018-07-05 17:33:20 +02001916 mtc.stop;
Harald Weltee613f962018-04-18 22:38:16 +02001917 }
1918 }
1919}
1920
Pau Espin Pedrol6451b042018-10-24 20:36:16 +02001921/* Send RACH request through l1CTL and wait for ChanReq on RSL BST->BSC */
1922private function f_rach_req_wait_chan_rqd(integer ra) runs on ConnHdlr return GsmFrameNumber {
1923 var GsmFrameNumber fn;
1924 timer T := 8.0;
1925
1926 /* advertise to RSL Emulation that we expect to receive confirmation from RACH */
1927 RSL.send(ts_RSLDC_ChanRqd_anyFN(int2oct(ra,1)));
1928
1929 f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, g_pars.l1_pars.ms_power_level);
1930 /* Send the actual RACH */
1931 fn := f_L1CTL_RACH(L1CTL, ra);
1932
1933 T.start;
1934 alt {
1935 [] RSL.receive(tr_RSL_CHAN_RQD(int2oct(ra,1), fn)) { setverdict(pass, "Received CHAN-RQD from RACH REQ") }
1936 [] T.timeout {
1937 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for CHAN-RQD from RACH REQ <", ra, ", ", fn, ">"));
1938 }
1939 }
1940 T.stop
1941 return fn;
1942}
Harald Weltee613f962018-04-18 22:38:16 +02001943
Harald Welte70767382018-02-21 12:16:40 +01001944/* Establish dedicated channel: L1CTL + RSL side */
Harald Weltec8d363c2019-05-19 20:36:48 +02001945private function f_est_dchan(boolean encr_enable := false, RSL_IE_List more_ies := {}) runs on ConnHdlr {
Harald Welte70767382018-02-21 12:16:40 +01001946 var GsmFrameNumber fn;
1947 var ImmediateAssignment imm_ass;
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +07001948 var ChannelDescription ch_desc;
Harald Welte70767382018-02-21 12:16:40 +01001949 var integer ra := 23;
1950
Pau Espin Pedrol6451b042018-10-24 20:36:16 +02001951 /* Send RACH request and wait for ChanReq */
1952 fn := f_rach_req_wait_chan_rqd(ra);
Harald Welte70767382018-02-21 12:16:40 +01001953
1954 /* Activate channel on BTS side */
Harald Weltec8d363c2019-05-19 20:36:48 +02001955 f_rsl_chan_act(g_pars.chan_mode, encr_enable, more_ies);
Harald Welte70767382018-02-21 12:16:40 +01001956
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +07001957 /* Craft channel description (with or without frequency hopping parameters) */
1958 if (ispresent(g_pars.maio_hsn)) {
1959 ch_desc := valueof(ts_ChanDescH1(g_pars.chan_nr, maio_hsn := g_pars.maio_hsn));
1960 } else {
1961 ch_desc := valueof(ts_ChanDescH0(g_pars.chan_nr));
1962 }
1963
Harald Welte70767382018-02-21 12:16:40 +01001964 /* Send IMM.ASS via CCHAN */
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +07001965 var GsmRrMessage rr_msg := valueof(ts_IMM_ASS(ra, fn, 0, ch_desc, g_pars.ma_map));
Harald Welte70767382018-02-21 12:16:40 +01001966 RSL.send(ts_RSL_IMM_ASSIGN(enc_GsmRrMessage(rr_msg)));
1967
1968 /* receive IMM.ASS on MS side */
1969 var ImmediateAssignment ia_um;
1970 ia_um := f_L1CTL_WAIT_IMM_ASS(L1CTL, ra, fn);
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +07001971
1972 /* Make sure that IMM.ASS contains hopping parameters (if enabled) */
1973 if (ch_desc.h != ia_um.chan_desc.h) {
1974 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Hopping parameters mismatch");
1975 }
1976
Harald Welte70767382018-02-21 12:16:40 +01001977 /* enable dedicated mode */
Vadim Yanitskiy28cabc42020-05-27 19:44:44 +07001978 f_L1CTL_DM_EST_REQ_IA(L1CTL, ia_um, ma := g_pars.ma);
Harald Weltee613f962018-04-18 22:38:16 +02001979 /* enable encryption, if requested */
1980 if (encr_enable) {
1981 var uint8_t alg_id := f_alg_id_to_l1ctl(g_pars.encr.alg_id);
1982 f_L1CTL_CRYPTO_REQ(L1CTL, g_pars.chan_nr, alg_id, g_pars.encr.key);
1983 }
Harald Weltefa45e9e2018-03-10 18:59:03 +01001984
1985 g_first_meas_res := true;
Harald Welte70767382018-02-21 12:16:40 +01001986}
1987
1988/* establish DChan, verify existance + contents of measurement reports */
1989function f_TC_meas_res_periodic(charstring id) runs on ConnHdlr {
Harald Welte68e495b2018-02-25 00:05:57 +01001990 f_l1_tune(L1CTL);
Harald Welte70767382018-02-21 12:16:40 +01001991 RSL.clear;
1992
Vadim Yanitskiy44ff2142019-01-12 07:04:58 +07001993 if (mp_bts_trxc_port != -1) {
Pau Espin Pedrole9571aa2018-10-22 17:13:07 +02001994 f_trxc_fake_rssi(rxlev2dbm(mp_ul_rxlev_exp));
Vadim Yanitskiydc8db922019-06-04 21:58:15 +07001995 f_trxc_fake_toffs256(g_pars.l1_pars.timing_offset_256syms);
Pau Espin Pedrol121724c2018-09-28 15:58:12 +02001996 }
Harald Welte70767382018-02-21 12:16:40 +01001997
1998 f_est_dchan();
1999
2000 /* run for a number of seconds, send SACCH + FACCH from MS side and verify
2001 * RSL measurement reports on Abis side */
2002 timer T := 8.0;
2003 T.start;
2004 alt {
2005 [] as_l1_sacch();
2006 [] as_meas_res();
2007 [] as_l1_dcch();
2008 [] L1CTL.receive { repeat; }
2009 [g_Tmeas_exp.running] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002010 /* as_meas_res() would have done Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail) in case
Harald Welte70767382018-02-21 12:16:40 +01002011 * of any earlier errors, so if we reach this timeout, we're good */
2012 setverdict(pass);
2013 }
2014 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002015 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No MEAS RES received at all");
Harald Welte70767382018-02-21 12:16:40 +01002016 }
2017 }
2018 f_rsl_chan_deact();
Harald Welte3dc20462018-03-10 23:03:38 +01002019 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Harald Welte70767382018-02-21 12:16:40 +01002020}
Harald Welte0472ab42018-03-12 15:02:26 +01002021
Pau Espin Pedrola2e079c2020-06-03 17:31:04 +02002022/* Verify Tx power reduction and ramping up during BTS bring up */
2023function f_TC_tx_power_start_ramp_up_bcch(charstring id) runs on ConnHdlr {
2024 var L1ctlDlMessage l1_dl;
2025 f_l1_tune(L1CTL);
2026 RSL.clear;
2027
2028 var integer initial_rx_lvl := -1;
2029 var integer last_rx_lvl := -1;
2030 var integer max_rx_lvl := mp_bts_tx_nom_pwr_exp - mp_bts_tx_pwr_att_exp;
2031
2032 timer T := 2.0;
2033 alt {
2034 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
2035 var GsmRxLev rx_lvl := l1_dl.dl_info.rx_level;
2036 log("Received rx_level=", rx_lvl);
2037 if (initial_rx_lvl == -1) {
2038 initial_rx_lvl := rx_lvl;
2039 last_rx_lvl := rx_lvl;
2040
2041 /* Expect a somehow low value during first received messages */
2042 if (initial_rx_lvl >= max_rx_lvl / 2) {
2043 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2044 log2str("Detected high initial tx power during ramp up: ",
2045 initial_rx_lvl , ", full power is", max_rx_lvl));
2046 }
2047 }
2048
2049 /* received Rx level bigger than maximum allowed power by CN */
2050 if (rx_lvl > max_rx_lvl) {
2051 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2052 log2str("Detected Tx power higher than full power: ",
2053 rx_lvl , " > ", max_rx_lvl));
2054 }
2055
2056 /* Make sure it never decreases, since we are rumping up */
2057 if (last_rx_lvl > rx_lvl) {
2058 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2059 log2str("Detected Tx power decrease during ramp up: ",
2060 last_rx_lvl , " -> ", rx_lvl));
2061 }
2062
2063 if (rx_lvl == max_rx_lvl and not T.running) {
2064 /* We reached the maximum power, start timer and receive
2065 /* a few more to make sure we don't surpass it */
2066 log("Reached full power, wating a bit more until success");
2067 T.start;
2068 }
2069
2070 last_rx_lvl := rx_lvl;
2071 repeat;
2072 }
2073 [] L1CTL.receive { repeat; }
2074 [] T.timeout { }
2075 }
2076
2077 /* We didn't increase tx power during ramp up */
2078 if (initial_rx_lvl < last_rx_lvl) {
2079 log("Tx power increased during ramp up: ", initial_rx_lvl , " -> ", last_rx_lvl);
2080 } else {
2081 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2082 log2str("No Tx power increase during whole ramp up: ",
2083 initial_rx_lvl , " -> ", last_rx_lvl));
2084 }
2085
2086 setverdict(pass);
2087}
2088testcase TC_tx_power_start_ramp_up_bcch() runs on test_CT {
2089 var ConnHdlr vc_conn;
2090 var ConnHdlrPars pars;
2091 f_init();
2092 pars := valueof(t_Pars(t_RslChanNr_Bm(0), ts_RSL_ChanMode_SIGN));
2093 vc_conn := f_start_handler(refers(f_TC_tx_power_start_ramp_up_bcch), pars,
2094 pcu_comp := false, trxc_comp := true);
2095 vc_conn.done;
2096 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2097}
2098
Eric Wildae8f2622019-06-18 17:05:11 +02002099function f_check_meas_bs_power_level(integer level) runs on ConnHdlr {
2100 timer T := 8.0;
2101 T.start;
2102 var RSL_Message rsl;
2103 alt {
2104 [] as_l1_sacch();
2105 [] L1CTL.receive { repeat; }
2106 [] RSL.receive(tr_RSL_MEAS_RES(g_chan_nr, ?, ?, ?)) -> value rsl {
2107 if (rsl.ies[3].body.bs_power.power_level == level) {
2108 setverdict(pass)
2109 } else {
2110 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Received wrong BS power level in MEAS RES ", rsl));
2111 }
2112 }
2113 [] T.timeout {
2114 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No MEAS RES received at all");
2115 }
2116 }
2117}
2118
2119/* see if the rsl meas res contains our expeced bs power level
2120bs power set during assignment */
2121function f_TC_rsl_bs_pwr_static_ass(charstring id) runs on ConnHdlr {
2122 f_l1_tune(L1CTL);
2123 RSL.clear;
2124
2125 if (mp_bts_trxc_port != -1) {
2126 f_trxc_fake_rssi(rxlev2dbm(mp_ul_rxlev_exp));
2127 f_trxc_fake_toffs256(g_pars.l1_pars.timing_offset_256syms);
2128 }
2129
2130 var uint5_t pwr_var := 1;
2131 var template (value) RSL_IE_BS_Power bs_power := ts_RSL_IE_BS_Power(pwr_var);
2132 var template (value) RSL_IE pwr := t_RSL_IE(RSL_IE_BS_POWER, RSL_IE_Body:{bs_power := bs_power});
2133
2134 f_est_dchan(more_ies :={valueof(pwr)});
2135
2136 f_check_meas_bs_power_level(pwr_var);
2137
2138 f_rsl_chan_deact();
2139 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2140}
2141
2142/* see if the rsl meas res contains our expeced bs power level
2143bs power set after assignment */
2144function f_TC_rsl_bs_pwr_static_power_control(charstring id) runs on ConnHdlr {
2145 f_l1_tune(L1CTL);
2146 RSL.clear;
2147
2148 if (mp_bts_trxc_port != -1) {
2149 f_trxc_fake_rssi(rxlev2dbm(mp_ul_rxlev_exp));
2150 f_trxc_fake_toffs256(g_pars.l1_pars.timing_offset_256syms);
2151 }
2152
2153 var uint5_t pwr_var := 1;
2154 var template (value) RSL_IE_BS_Power bs_power := ts_RSL_IE_BS_Power(pwr_var);
2155
2156 f_est_dchan();
2157
2158 RSL.send(ts_RSL_BS_PWR_CTRL(g_chan_nr, bs_power));
2159
2160 f_check_meas_bs_power_level(pwr_var);
2161
2162 f_rsl_chan_deact();
2163 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2164}
2165
2166testcase TC_rsl_bs_pwr_static_ass() runs on test_CT {
2167 var ConnHdlr vc_conn;
2168 var ConnHdlrPars pars;
2169 f_init();
2170 for (var integer tn := 1; tn <= 4; tn := tn+1) {
2171 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2172 vc_conn := f_start_handler(refers(f_TC_rsl_bs_pwr_static_ass), pars,
2173 pcu_comp := false, trxc_comp := true);
2174 vc_conn.done;
2175 }
2176 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2177}
2178
2179testcase TC_rsl_bs_pwr_static_power_control() runs on test_CT {
2180 var ConnHdlr vc_conn;
2181 var ConnHdlrPars pars;
2182 f_init();
2183 for (var integer tn := 1; tn <= 4; tn := tn+1) {
2184 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2185 vc_conn := f_start_handler(refers(f_TC_rsl_bs_pwr_static_power_control), pars,
2186 pcu_comp := false, trxc_comp := true);
2187 vc_conn.done;
2188 }
2189 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2190}
2191
Eric Wild61edb7e2019-06-03 12:38:31 +02002192/* target level -100, first rssi -90, ms power 7, expected increase to 7+6 within 6 seconds,
2193second rssi -110, ms power 7+6, expected decrease to 7 within 6 seconds,
2194These power levels are valid for all bands and require no special handling */
2195function f_TC_rsl_ms_pwr_dyn_ass_updown(charstring id) runs on ConnHdlr {
2196 var uint5_t pwr_var := 7;
2197 var L1ctlDlMessage l1_dl;
2198
2199 f_trxc_fake_rssi(rxlev2dbm(10));
2200 f_l1_tune(L1CTL);
2201 RSL.clear;
2202
2203 var RSL_IE_List addl_ies;
2204 var template (value) RSL_IE_MS_Power_Parameters pp := (ts_RSL_IE_MS_Power_Parameters(''O));
2205
2206 addl_ies := {
2207 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(pwr_var)})),
2208 valueof(t_RSL_IE(RSL_IE_MS_POWER_PARAM, RSL_IE_Body:{ms_power_params := pp}))
2209 };
2210
2211 /* establish with power parameters */
2212 f_est_dchan(more_ies := addl_ies);
2213
2214 /* set a high value to ensure L1 power control level increases */
2215 f_trxc_fake_rssi(rxlev2dbm(20));
2216
2217 timer T2 := 6.0;
2218 T2.start;
2219 alt {
2220 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
Pau Espin Pedrola1f7d242019-12-04 16:08:09 +01002221 /* Update sent MS power to follow what BTS requests */
2222 f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
2223 if (oct2int(l1_dl.payload.data_ind.payload[0]) < (pwr_var + 6)) {
Eric Wild61edb7e2019-06-03 12:38:31 +02002224 repeat;
Pau Espin Pedrola1f7d242019-12-04 16:08:09 +01002225 }
Eric Wild61edb7e2019-06-03 12:38:31 +02002226 T2.stop;
2227 }
2228 [] L1CTL.receive { repeat; }
2229 [] T2.timeout {
2230 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2231 "Power Level in L1 header has not increased sufficiently");
2232 }
2233 }
2234
2235 /* set a low value to ensure L1 power control level decreases */
2236 f_trxc_fake_rssi(rxlev2dbm(0));
2237
2238 timer T4 := 6.0;
2239 T4.start;
2240 alt {
2241 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
Pau Espin Pedrola1f7d242019-12-04 16:08:09 +01002242 /* Update sent MS power to follow what BTS requests */
2243 f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
2244 if (oct2int(l1_dl.payload.data_ind.payload[0]) > pwr_var) {
Eric Wild61edb7e2019-06-03 12:38:31 +02002245 repeat;
Pau Espin Pedrola1f7d242019-12-04 16:08:09 +01002246 }
Eric Wild61edb7e2019-06-03 12:38:31 +02002247 T4.stop;
2248 setverdict(pass, "Power level in L1 decreased/increased as expected");
2249 }
2250 [] L1CTL.receive { repeat; }
2251 [] T4.timeout {
2252 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2253 "Power Level in L1 header has not decreased sufficiently");
2254 }
2255 }
2256
2257 f_rsl_chan_deact();
2258 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2259
2260}
2261
2262/* check that we do not exceed the max power */
2263function f_TC_rsl_ms_pwr_dyn_max(charstring id) runs on ConnHdlr {
2264 var uint5_t pwr_var := 7;
2265 var L1ctlDlMessage l1_dl;
2266
2267 /* set a low value to ensure power increases */
2268 f_trxc_fake_rssi(rxlev2dbm(10));
2269 f_l1_tune(L1CTL);
2270 RSL.clear;
2271
2272 var RSL_IE_List addl_ies;
2273 var template (value) RSL_IE_MS_Power_Parameters pp := (ts_RSL_IE_MS_Power_Parameters(''O));
2274
2275 addl_ies := {
2276 valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ts_RSL_IE_MS_Power(pwr_var)})),
2277 valueof(t_RSL_IE(RSL_IE_MS_POWER_PARAM, RSL_IE_Body:{ms_power_params := pp}))
2278 };
2279
2280 /* establish with power parameters */
2281 f_est_dchan(more_ies := addl_ies);
2282
2283 timer T1 := 10.0;
2284 T1.start;
2285 alt {
Pau Espin Pedrola1f7d242019-12-04 16:08:09 +01002286 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2287 /* Update sent MS power to follow what BTS requests */
2288 f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
2289 repeat;
2290 }
Eric Wild61edb7e2019-06-03 12:38:31 +02002291 [] L1CTL.receive { repeat; }
2292 [] T1.timeout {
2293 if( oct2int(l1_dl.payload.data_ind.payload[0]) != pwr_var){
2294 setverdict(fail, "Power level in L1 header should not have changed");
2295 }
2296 }
2297 }
2298
2299 f_rsl_chan_deact();
2300 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2301
2302}
2303
2304/* see if we reach the band max power */
2305function f_TC_rsl_ms_pwr_dyn_up(charstring id) runs on ConnHdlr {
2306 var L1ctlDlMessage l1_dl;
2307 var uint5_t pwr_var := 15;
2308 var uint5_t pwr_max_var := f_get_max_power_from_band();
2309
2310 /* set a low value to ensure power increases */
2311 f_trxc_fake_rssi(rxlev2dbm(10));
2312 f_l1_tune(L1CTL);
2313 RSL.clear;
2314
2315 var template (value) RSL_IE_MS_Power ms_power := ts_RSL_IE_MS_Power(pwr_var);
2316 var template (value) RSL_IE pwr := t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ms_power});
2317
2318 /* establish with fixed power level */
2319 f_est_dchan(more_ies :={valueof(pwr)});
2320
2321 /* check our initial power level */
2322 f_wait_for_l1_power_level(pwr_var);
2323
2324 /* update power param to enable power loop
2325 48.058 The maximum power to be used is indicated in the BS and MS Power elements respectively. */
2326 RSL.send(ts_RSL_MS_PWR_CTRL_with_pp(g_chan_nr, pwr_max_var));
2327
2328 /* wait, then check that our power level was reduced */
2329 timer T1 := 10.0;
2330 T1.start;
2331 alt {
Pau Espin Pedrola1f7d242019-12-04 16:08:09 +01002332 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2333 /* Update sent MS power to follow what BTS requests */
2334 f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
2335 repeat;
2336 }
Eric Wild61edb7e2019-06-03 12:38:31 +02002337 [] L1CTL.receive { repeat; }
2338 [] T1.timeout {
2339 var int8_t rcv := oct2int(l1_dl.payload.data_ind.payload[0]);
2340 if( f_power_level_is_highest_dbm(rcv) ){
2341 setverdict(pass, "Power level in L1 header reduced as expected");
2342 } else {
2343 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2344 log2str("Power Level in L1 header did not reach the expected value, e:",pwr_max_var," r:",rcv));
2345 }
2346 }
2347 }
2348
2349 f_rsl_chan_deact();
2350 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2351
2352}
2353
2354/* see if we reach the band min power */
2355function f_TC_rsl_ms_pwr_dyn_down(charstring id) runs on ConnHdlr {
2356 var L1ctlDlMessage l1_dl;
2357
2358 /* set a high value to ensure power decreases */
2359 f_trxc_fake_rssi(rxlev2dbm(50));
2360 f_l1_tune(L1CTL);
2361 RSL.clear;
2362
2363 var uint5_t pwr_var := 5;
2364 var uint5_t pwr_target_val := 15;
2365
2366 var template (value) RSL_IE_MS_Power ms_power := ts_RSL_IE_MS_Power(pwr_var);
2367 var template (value) RSL_IE pwr := t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ms_power});
2368
2369 /* establish with fixed power level */
2370 f_est_dchan(more_ies :={valueof(pwr)});
2371
2372 /* check our initial power level */
2373 f_wait_for_l1_power_level(pwr_var);
2374
2375 /* update power param to enable power loop
2376 as per spec the supplied ms power IE should set the max allowed power...*/
Pau Espin Pedrol61122c82019-11-05 13:50:27 +01002377 RSL.send(ts_RSL_MS_PWR_CTRL_with_pp(g_chan_nr, pwr_target_val));
Eric Wild61edb7e2019-06-03 12:38:31 +02002378
2379 /* wait, then check that our power level was increased */
2380 timer T1 := 10.0;
2381 T1.start;
2382 alt {
Pau Espin Pedrola1f7d242019-12-04 16:08:09 +01002383 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2384 /* Update sent MS power to follow what BTS requests */
2385 f_L1CTL_PARAM(L1CTL, g_pars.l1_pars.ms_actual_ta, oct2int(l1_dl.payload.data_ind.payload[0]));
2386 repeat;
2387 }
Eric Wild61edb7e2019-06-03 12:38:31 +02002388 [] L1CTL.receive { repeat; }
2389 [] T1.timeout {
2390 if( f_power_level_is_lowest_dbm(oct2int(l1_dl.payload.data_ind.payload[0])) ){
2391 setverdict(pass, "Power level in L1 header increased to lowest power value");
2392 } else {
2393 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2394 "Power level in L1 header NOT increased to lowest power value");
2395 }
2396 }
2397 }
2398
2399 f_rsl_chan_deact();
2400 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2401
2402}
2403
Eric Wild095024b2019-06-17 15:08:57 +02002404/* see if we change the power level without receiving power parameters, which should not happen
2405rsl chan act WITHOUT power parameters */
Eric Wild280ccb82019-06-17 11:11:52 +02002406function f_TC_rsl_ms_pwr_dyn_active(charstring id) runs on ConnHdlr {
2407 var L1ctlDlMessage l1_dl;
2408
2409 /* set a high value to ensure power decreases */
2410 f_trxc_fake_rssi(rxlev2dbm(50));
2411 f_l1_tune(L1CTL);
2412 RSL.clear;
2413
2414 var uint5_t pwr_var := 5;
2415
2416 var template (value) RSL_IE_MS_Power ms_power := ts_RSL_IE_MS_Power(pwr_var);
2417 var template (value) RSL_IE pwr := t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ms_power});
2418
2419 /* establish with fixed power level */
2420 f_est_dchan(more_ies :={valueof(pwr)});
2421
2422 /* check our initial power level */
2423 f_wait_for_l1_power_level(pwr_var);
2424
2425 /* wait, then check that our power level did not change */
2426 timer T1 := 10.0;
2427 T1.start;
2428 alt {
2429 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2430 if ( oct2int(l1_dl.payload.data_ind.payload[0]) != pwr_var) {
2431 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2432 "BS power control should not be active unless we receive a power parameters IE!");
2433 }
2434 repeat;
2435 }
2436 [] L1CTL.receive { repeat; }
2437 [] T1.timeout { setverdict(pass); }
2438 }
2439
2440 f_rsl_chan_deact();
2441 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2442
2443}
2444
Eric Wild095024b2019-06-17 15:08:57 +02002445/* see if we change the power level without receiving power parameters, which should not happen
2446ms power control WITHOUT power parameters */
2447function f_TC_rsl_ms_pwr_dyn_active2(charstring id) runs on ConnHdlr {
2448 var L1ctlDlMessage l1_dl;
2449
2450 /* set a high value to ensure power decreases */
2451 f_trxc_fake_rssi(rxlev2dbm(50));
2452 f_l1_tune(L1CTL);
2453 RSL.clear;
2454
2455 var uint5_t pwr_var := 5;
2456
2457 var template (value) RSL_IE_MS_Power ms_power := ts_RSL_IE_MS_Power(pwr_var);
2458 var template (value) RSL_IE pwr := t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ms_power});
2459
2460 /* establish with fixed power level */
2461 f_est_dchan(more_ies :={valueof(pwr)});
2462
2463 /* check our initial power level */
2464 f_wait_for_l1_power_level(pwr_var);
2465
2466 /* pwr control without power params IE, should NOT activate MS power control*/
2467 RSL.send(ts_RSL_MS_PWR_CTRL(g_chan_nr, ms_power));
2468
2469 /* wait, then check that our power level did not change */
2470 timer T1 := 10.0;
2471 T1.start;
2472 alt {
2473 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2474 if ( oct2int(l1_dl.payload.data_ind.payload[0]) != pwr_var) {
2475 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2476 "BS power control should not be active unless we receive a power parameters IE!");
2477 }
2478 repeat;
2479 }
2480 [] L1CTL.receive { repeat; }
2481 [] T1.timeout { setverdict(pass); }
2482 }
2483
2484 f_rsl_chan_deact();
2485 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2486
2487}
2488
Eric Wild61edb7e2019-06-03 12:38:31 +02002489function f_wait_for_l1_power_level(integer level) runs on ConnHdlr {
2490 var L1ctlDlMessage l1_dl;
2491 timer T0 := 10.0;
2492 T0.start;
2493 alt {
2494 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2495 if (not (l1_dl.payload.data_ind.payload[0] == int2oct(level, 1))) {
2496 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2497 "Power level in L1 header != signaled (RSL) power level.");
2498 }
2499 }
2500 [] L1CTL.receive { repeat; }
2501 [] T0.timeout {
2502 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
2503 "Timeout waiting for initial power level");
2504 }
2505 }
2506 T0.stop;
2507}
2508
2509private function f_power_level_is_lowest_dbm(integer level) runs on ConnHdlr return boolean {
2510 var IntegerRecord min_dbm_level;
2511 var IntegerRecord max_dbm_level;
2512 var IntegerRecord x := f_power_from_band(g_pars.bts0_band, min_dbm_level, max_dbm_level);
2513
2514 for (var integer i := 0; i < sizeof(min_dbm_level); i := i+1) {
2515 if (min_dbm_level[i] == level) {
2516 return true;
2517 }
2518 }
2519 return false;
2520}
2521
2522private function f_power_level_is_highest_dbm(integer level) runs on ConnHdlr return boolean {
2523 var IntegerRecord min_dbm_level;
2524 var IntegerRecord max_dbm_level;
2525 var IntegerRecord x := f_power_from_band(g_pars.bts0_band, min_dbm_level, max_dbm_level);
2526
2527 for (var integer i := 0; i < sizeof(max_dbm_level); i := i+1) {
2528 if (max_dbm_level[i] == level) {
2529 return true;
2530 }
2531 }
2532 return false;
2533}
2534
2535private function f_get_max_power_from_band() runs on ConnHdlr return integer {
2536 var IntegerRecord min_dbm_level;
2537 var IntegerRecord max_dbm_level;
2538 var IntegerRecord x := f_power_from_band(g_pars.bts0_band, min_dbm_level, max_dbm_level);
2539 return max_dbm_level[0];
2540}
2541
2542type charstring BtsBand ("GSM450","GSM480","GSM750","GSM810","GSM850","GSM900","DCS1800","PCS1900");
2543template charstring BtsBand_allGSM:= pattern "GSM???";
2544private function f_power_from_band(in BtsBand band, out IntegerRecord min_dbm_level, out IntegerRecord max_dbm_level) return IntegerRecord {
2545 // 45.005 4.1.1
2546 var IntegerRecord gsm_power :={31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
2547 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
2548 2, 1, 0};
2549 var IntegerRecord dcs_power :={28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15,
2550 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 31, 30, 29};
2551 var IntegerRecord pcs_power :={15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 31, 30};
2552 var IntegerRecord rv;
2553
2554 select(band){
2555 case (BtsBand_allGSM){
2556 rv := gsm_power;
2557 min_dbm_level := {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19} ;
2558 max_dbm_level := {2, 1, 0};
2559 }
2560 case("DCS1800"){
2561 rv := dcs_power;
2562 min_dbm_level := {28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15};
2563 max_dbm_level := {0, 29}; // let's cheat here, assume MS_TXPWR_MAX_CCH might be being broadcast, so maybe no 29,30,31
2564 }
2565 case("PCS1900"){
2566 rv := pcs_power;
2567 min_dbm_level := {15};
2568 max_dbm_level := {30};
2569 }
2570 }
2571
2572 return rv;
2573}
2574
2575private function f_vty_get_bts0_band() runs on test_CT return BtsBand {
2576 return f_vty_transceive_match_regex(BTSVTY, "show bts 0", "BTS 0 is of \w+ type in band (\w+),*", 0);
2577}
2578
2579testcase TC_rsl_ms_pwr_dyn_ass_updown() runs on test_CT {
2580 var ConnHdlr vc_conn;
2581 var ConnHdlrPars pars;
2582 f_init();
2583 f_vty_config(BTSVTY, "phy 0", "osmotrx ms-power-loop -100");
2584 for (var integer tn := 1; tn <= 1; tn := tn+1) {
2585 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2586 pars.bts0_band := f_vty_get_bts0_band();
2587 vc_conn := f_start_handler(refers(f_TC_rsl_ms_pwr_dyn_ass_updown), pars, trxc_comp := true);
2588 vc_conn.done;
2589 }
2590 f_vty_config(BTSVTY, "phy 0", "no osmotrx ms-power-loop");
2591 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2592}
2593
2594testcase TC_rsl_ms_pwr_dyn_up() runs on test_CT {
2595 var ConnHdlr vc_conn;
2596 var ConnHdlrPars pars;
2597 f_init();
2598 f_vty_config(BTSVTY, "phy 0", "osmotrx ms-power-loop -10");
2599 for (var integer tn := 1; tn <= 1; tn := tn+1) {
2600 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2601 pars.bts0_band := f_vty_get_bts0_band();
2602 vc_conn := f_start_handler(refers(f_TC_rsl_ms_pwr_dyn_up), pars, trxc_comp := true);
2603 vc_conn.done;
2604 }
2605 f_vty_config(BTSVTY, "phy 0", "no osmotrx ms-power-loop");
2606 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2607}
2608
2609testcase TC_rsl_ms_pwr_dyn_max() runs on test_CT {
2610 var ConnHdlr vc_conn;
2611 var ConnHdlrPars pars;
2612 f_init();
2613 f_vty_config(BTSVTY, "phy 0", "osmotrx ms-power-loop -10");
2614 for (var integer tn := 1; tn <= 1; tn := tn+1) {
2615 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2616 pars.bts0_band := f_vty_get_bts0_band();
2617 vc_conn := f_start_handler(refers(f_TC_rsl_ms_pwr_dyn_max), pars, trxc_comp := true);
2618 vc_conn.done;
2619 }
2620 f_vty_config(BTSVTY, "phy 0", "no osmotrx ms-power-loop");
2621 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2622}
2623
2624testcase TC_rsl_ms_pwr_dyn_down() runs on test_CT {
2625 var ConnHdlr vc_conn;
2626 var ConnHdlrPars pars;
2627 f_init();
2628 f_vty_config(BTSVTY, "phy 0", "osmotrx ms-power-loop -100");
2629 for (var integer tn := 1; tn <= 1; tn := tn+1) {
2630 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2631 pars.bts0_band := f_vty_get_bts0_band();
2632 vc_conn := f_start_handler(refers(f_TC_rsl_ms_pwr_dyn_down), pars, trxc_comp := true);
2633 vc_conn.done;
2634 }
2635 f_vty_config(BTSVTY, "phy 0", "no osmotrx ms-power-loop");
2636 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2637}
2638
Eric Wild280ccb82019-06-17 11:11:52 +02002639testcase TC_rsl_ms_pwr_dyn_active() runs on test_CT {
2640 var ConnHdlr vc_conn;
2641 var ConnHdlrPars pars;
2642 f_init();
2643 f_vty_config(BTSVTY, "phy 0", "osmotrx ms-power-loop -100");
2644 for (var integer tn := 1; tn <= 1; tn := tn+1) {
2645 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2646 pars.bts0_band := f_vty_get_bts0_band();
2647 vc_conn := f_start_handler(refers(f_TC_rsl_ms_pwr_dyn_active), pars, trxc_comp := true);
2648 vc_conn.done;
2649 }
2650 f_vty_config(BTSVTY, "phy 0", "no osmotrx ms-power-loop");
2651 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2652}
2653
Eric Wild095024b2019-06-17 15:08:57 +02002654testcase TC_rsl_ms_pwr_dyn_active2() runs on test_CT {
2655 var ConnHdlr vc_conn;
2656 var ConnHdlrPars pars;
2657 f_init();
2658 f_vty_config(BTSVTY, "phy 0", "osmotrx ms-power-loop -100");
2659 for (var integer tn := 1; tn <= 1; tn := tn+1) {
2660 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2661 pars.bts0_band := f_vty_get_bts0_band();
2662 vc_conn := f_start_handler(refers(f_TC_rsl_ms_pwr_dyn_active2), pars, trxc_comp := true);
2663 vc_conn.done;
2664 }
2665 f_vty_config(BTSVTY, "phy 0", "no osmotrx ms-power-loop");
2666 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2667}
2668
Harald Welte70767382018-02-21 12:16:40 +01002669testcase TC_meas_res_sign_tchf() runs on test_CT {
2670 var ConnHdlr vc_conn;
2671 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002672 f_init();
Harald Welte70767382018-02-21 12:16:40 +01002673 for (var integer tn := 1; tn <= 4; tn := tn+1) {
2674 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +07002675 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars,
2676 pcu_comp := false, trxc_comp := true);
Harald Welte70767382018-02-21 12:16:40 +01002677 vc_conn.done;
2678 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002679 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01002680}
2681testcase TC_meas_res_sign_tchh() runs on test_CT {
2682 var ConnHdlr vc_conn;
2683 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002684 f_init();
Harald Welte70767382018-02-21 12:16:40 +01002685 for (var integer ss := 0; ss <= 1; ss := ss+1) {
2686 pars := valueof(t_Pars(t_RslChanNr_Lm(5, ss), ts_RSL_ChanMode_SIGN));
Eric Wild5b9ef142019-07-11 19:28:02 +02002687 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars,
2688 pcu_comp := false, trxc_comp := true);
Harald Welte70767382018-02-21 12:16:40 +01002689 vc_conn.done;
2690 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002691 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01002692}
2693testcase TC_meas_res_sign_sdcch4() runs on test_CT {
2694 var ConnHdlr vc_conn;
2695 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002696 f_init();
Harald Welte70767382018-02-21 12:16:40 +01002697 for (var integer ss := 0; ss <= 3; ss := ss+1) {
2698 pars := valueof(t_Pars(t_RslChanNr_SDCCH4(0, ss), ts_RSL_ChanMode_SIGN));
Eric Wild5b9ef142019-07-11 19:28:02 +02002699 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars,
2700 pcu_comp := false, trxc_comp := true);
Harald Welte70767382018-02-21 12:16:40 +01002701 vc_conn.done;
2702 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002703 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01002704}
2705testcase TC_meas_res_sign_sdcch8() runs on test_CT {
2706 var ConnHdlr vc_conn;
2707 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002708 f_init();
Harald Welte70767382018-02-21 12:16:40 +01002709 for (var integer ss := 0; ss <= 7; ss := ss+1) {
2710 pars := valueof(t_Pars(t_RslChanNr_SDCCH8(6, ss), ts_RSL_ChanMode_SIGN));
Eric Wild5b9ef142019-07-11 19:28:02 +02002711 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars,
2712 pcu_comp := false, trxc_comp := true);
Harald Welte70767382018-02-21 12:16:40 +01002713 vc_conn.done;
2714 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002715 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte70767382018-02-21 12:16:40 +01002716}
Harald Welte685d5982018-02-27 20:42:05 +01002717testcase TC_meas_res_sign_tchh_toa256() runs on test_CT {
2718 var ConnHdlr vc_conn;
2719 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002720 f_init();
Harald Welte685d5982018-02-27 20:42:05 +01002721 f_vty_config(BTSVTY, "bts 0", "supp-meas-info toa256");
2722 for (var integer ss := 0; ss <= 1; ss := ss+1) {
2723 pars := valueof(t_Pars(t_RslChanNr_Lm(5, ss), ts_RSL_ChanMode_SIGN));
2724 pars.l1_pars.toa256_enabled := true;
2725 vc_conn := f_start_handler(refers(f_TC_meas_res_periodic), pars);
2726 vc_conn.done;
2727 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002728 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte685d5982018-02-27 20:42:05 +01002729}
2730
Philipp Maier4d1e9c92018-12-20 11:11:56 +01002731/* establish DChan, and send MS POWER CONTROL messages via RSL, verify that
2732 * the BTS is forwarding those values to the MS via the SACCH L1 header. */
2733function f_tc_rsl_ms_pwr_ctrl(charstring id) runs on ConnHdlr {
2734 var L1ctlDlMessage l1_dl;
2735 var RSL_IE_MS_Power ms_power;
2736 var RSL_Message rsl;
2737 var uint5_t power_level := 0;
2738
2739 f_l1_tune(L1CTL);
2740 RSL.clear;
2741
2742 f_est_dchan();
2743
2744 ms_power.reserved := 0;
2745 ms_power.fpc_epc := false;
2746
2747 /* Send the first power control command. This will disable any BTS/TRX
2748 * internal power control and switch the MS (which is not in scope of
2749 * this test) to a constant power level. We start with a power level
2750 * of 0 */
2751 ms_power.power_level := power_level;
2752 rsl := valueof(ts_RSL_MS_PWR_CTRL(g_chan_nr, ms_power));
2753 RSL.send(rsl);
2754
2755 alt {
2756
2757 /* Pick all SACCH blocks for checking */
2758 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2759
2760 /* The first byte of the L1 header contains the power level.
2761 * The reserved bits and the fpc bit is set to 0, so we may
2762 * compare directly. */
2763 if (not (l1_dl.payload.data_ind.payload[0] == int2oct(power_level, 1))) {
2764 setverdict(fail, "Power level in L1 header does not match the signaled (RSL) power level.");
2765 }
2766
2767 /* Signal a new power level via RSL for the next turn. */
2768 if (power_level < 31) {
2769 power_level := power_level + 1;
2770 ms_power.power_level := power_level;
2771 rsl := valueof(ts_RSL_MS_PWR_CTRL(g_chan_nr, ms_power));
2772 RSL.send(rsl);
2773 repeat;
2774 }
2775
2776 }
2777
2778 /* Ignore all other blocks */
2779 [] L1CTL.receive { repeat; }
2780
2781 }
2782
2783 f_rsl_chan_deact();
2784 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2785
2786 setverdict(pass);
2787}
2788
2789testcase TC_rsl_ms_pwr_ctrl() runs on test_CT {
2790 var ConnHdlr vc_conn;
2791 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002792 f_init();
Philipp Maier4d1e9c92018-12-20 11:11:56 +01002793
2794 for (var integer tn := 1; tn <= 4; tn := tn+1) {
2795 pars := valueof(t_Pars(t_RslChanNr_Bm(tn), ts_RSL_ChanMode_SIGN));
2796 vc_conn := f_start_handler(refers(f_tc_rsl_ms_pwr_ctrl), pars);
2797 vc_conn.done;
2798 }
2799 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2800}
Harald Welte70767382018-02-21 12:16:40 +01002801
Pau Espin Pedrol188bfd22020-06-03 20:32:45 +02002802/* establish DChan, verify that the BTS sets the TA in the first SACCH L1 header.
Eric Wild6833cc92019-05-23 19:34:44 +02002803TA for the IMM ASS messages is still controlled by g_pars.l1_pars.ms_actual_ta! */
2804function f_tc_rsl_chan_initial_ta(charstring id) runs on ConnHdlr {
2805 var L1ctlDlMessage l1_dl;
2806 var uint5_t ta_to_test := 16;
2807
2808
2809 f_l1_tune(L1CTL);
2810 RSL.clear;
2811
2812 /* tell fake_trx to use a given timing offset for all bursts */
Vadim Yanitskiydc8db922019-06-04 21:58:15 +07002813 f_trxc_fake_toffs256(ta_to_test*256);
Eric Wild6833cc92019-05-23 19:34:44 +02002814
2815 f_est_dchan(more_ies :={valueof(t_RSL_IE(RSL_IE_TIMING_ADVANCE, RSL_IE_Body:{timing_adv := ta_to_test}))} );
2816
2817
2818 alt {
2819
2820 /* Pick all SACCH blocks for checking */
2821 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2822
2823 /* The second byte of the L1 header contains the TA. */
2824 if (not (l1_dl.payload.data_ind.payload[1] == int2oct(ta_to_test, 1))) {
2825 setverdict(fail, "TA in L1 header does not match the signaled (RSL) TA.");
2826 }
2827
2828 }
2829
2830 /* Ignore all other blocks */
2831 [] L1CTL.receive { repeat; }
2832
2833 }
2834
2835 f_rsl_chan_deact();
2836 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2837
2838 setverdict(pass);
2839}
2840
2841testcase TC_rsl_chan_initial_ta() runs on test_CT {
2842 var ConnHdlr vc_conn;
2843 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002844 f_init();
Eric Wild6833cc92019-05-23 19:34:44 +02002845 pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Vadim Yanitskiyf4e997c2019-06-04 21:40:33 +07002846 vc_conn := f_start_handler(refers(f_tc_rsl_chan_initial_ta), pars,
2847 pcu_comp := false, trxc_comp := true);
Eric Wild6833cc92019-05-23 19:34:44 +02002848 vc_conn.done;
2849 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
2850}
2851
Eric Wilde57e1a62019-05-28 13:30:55 +02002852/* establish DChan, verify that the BTS sets MS power in the first SACCH L1 header. */
2853function f_tc_rsl_chan_initial_ms_pwr(charstring id) runs on ConnHdlr {
2854 var L1ctlDlMessage l1_dl;
2855 var uint5_t ms_power_level := 7;
2856
2857 var RSL_IE_MS_Power ms_power;
2858 ms_power.reserved := 0;
2859 ms_power.fpc_epc := false;
2860 ms_power.power_level := ms_power_level;
2861
2862 f_l1_tune(L1CTL);
2863 RSL.clear;
2864
2865 f_est_dchan(more_ies :={valueof(t_RSL_IE(RSL_IE_MS_POWER, RSL_IE_Body:{ms_power := ms_power}))} );
2866
2867 timer T := 1.0;
2868 T.start;
2869 alt {
2870 /* Pick all SACCH blocks for checking */
2871 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, tr_RslLinkID_SACCH(?))) -> value l1_dl {
2872 /* The first byte of the L1 header contains the power level.. */
2873 if (not (l1_dl.payload.data_ind.payload[0] == int2oct(ms_power_level, 1))) {
2874 setverdict(fail, "Power Level in L1 header does not match the signaled (RSL) MS Power Level.");
2875 }
2876 }
2877 /* Ignore all other blocks */
2878 [] L1CTL.receive { repeat; }
2879 [] T.timeout {
2880 setverdict(fail, "Power Level in L1 header does not match the signaled (RSL) MS Power Level.");
2881 }
2882 }
2883
2884 f_rsl_chan_deact();
2885 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
2886 setverdict(pass);
2887}
2888
2889testcase TC_rsl_chan_initial_ms_pwr() runs on test_CT {
2890 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
2891 f_testmatrix_each_chan(pars, refers(f_tc_rsl_chan_initial_ms_pwr));
2892}
2893
Harald Welte0472ab42018-03-12 15:02:26 +01002894/* 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 +01002895private function f_TC_conn_fail_crit(charstring id) runs on ConnHdlr {
Harald Welte68e495b2018-02-25 00:05:57 +01002896 f_l1_tune(L1CTL);
Harald Welte70767382018-02-21 12:16:40 +01002897 RSL.clear;
2898
2899 f_est_dchan();
2900 f_sleep(2.0);
Harald Weltef8df4cb2018-03-10 15:15:08 +01002901 L1CTL.send(ts_L1CTL_DM_REL_REQ(g_chan_nr));
Harald Welte70767382018-02-21 12:16:40 +01002902
2903 timer T := 40.0;
2904 T.start;
2905 alt {
2906 [] RSL.receive(tr_RSL_CONN_FAIL_IND(g_chan_nr, ?)) {
2907 setverdict(pass)
2908 }
2909 [] RSL.receive { repeat };
2910 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002911 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No CONN FAIL IND received");
Harald Welte70767382018-02-21 12:16:40 +01002912 }
2913 }
2914 f_rsl_chan_deact();
2915}
2916testcase TC_conn_fail_crit() runs on test_CT {
2917 var ConnHdlr vc_conn;
2918 var ConnHdlrPars pars;
Harald Welte10474062019-05-30 16:48:17 +02002919 f_init();
Harald Welte70767382018-02-21 12:16:40 +01002920 pars := valueof(t_Pars(t_RslChanNr_SDCCH8(6, 3), ts_RSL_ChanMode_SIGN));
2921 pars.t_guard := 60.0;
2922 vc_conn := f_start_handler(refers(f_TC_conn_fail_crit), pars);
2923 vc_conn.done;
2924}
2925
Harald Welte93640c62018-02-25 16:59:33 +01002926/***********************************************************************
2927 * Paging
2928 ***********************************************************************/
2929
Harald Welte68e495b2018-02-25 00:05:57 +01002930function tmsi_is_dummy(TMSIP_TMSI_V tmsi) return boolean {
2931 if (tmsi == 'FFFFFFFF'O) {
2932 return true;
2933 } else {
2934 return false;
2935 }
2936}
Harald Welte70767382018-02-21 12:16:40 +01002937
Philipp Maier82cb0b12018-08-31 14:41:39 +02002938type record allowedFn { integer frame_nr }
2939template allowedFn bs_ag_blks_res_0 := { frame_nr := (6, 12, 16, 22, 26, 32, 36, 42, 46) }
2940template allowedFn bs_ag_blks_res_1 := { frame_nr := (12, 16, 22, 26, 32, 36, 42, 46) }
2941template allowedFn bs_ag_blks_res_2 := { frame_nr := (16, 22, 26, 32, 36, 42, 46) }
2942template allowedFn bs_ag_blks_res_3 := { frame_nr := (22, 26, 32, 36, 42, 46) }
2943template allowedFn bs_ag_blks_res_4 := { frame_nr := (26, 32, 36, 42, 46) }
2944template allowedFn bs_ag_blks_res_5 := { frame_nr := (32, 36, 42, 46) }
2945template allowedFn bs_ag_blks_res_6 := { frame_nr := (36, 42, 46) }
2946template allowedFn bs_ag_blks_res_7 := { frame_nr := (42, 46) }
2947function check_pch_fn(integer frame_nr, integer bs_ag_blks_res) runs on test_CT
2948{
2949 var integer frame_nr_51;
2950 frame_nr_51 := frame_nr mod 51
2951
2952 var allowedFn fn_check;
2953 fn_check.frame_nr := frame_nr_51;
2954
2955 if (bs_ag_blks_res < 0 or bs_ag_blks_res > 7) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002956 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "bs_ag_blks_res out of valid range (0..7)");
Philipp Maier82cb0b12018-08-31 14:41:39 +02002957 return;
2958 }
2959
2960 if (bs_ag_blks_res == 0 and match(fn_check, bs_ag_blks_res_0)) {
2961 return;
2962 }
2963 if (bs_ag_blks_res == 1 and match(fn_check, bs_ag_blks_res_1)) {
2964 return;
2965 }
2966 if (bs_ag_blks_res == 2 and match(fn_check, bs_ag_blks_res_2)) {
2967 return;
2968 }
2969 if (bs_ag_blks_res == 3 and match(fn_check, bs_ag_blks_res_3)) {
2970 return;
2971 }
2972 if (bs_ag_blks_res == 4 and match(fn_check, bs_ag_blks_res_4)) {
2973 return;
2974 }
2975 if (bs_ag_blks_res == 5 and match(fn_check, bs_ag_blks_res_5)) {
2976 return;
2977 }
2978 if (bs_ag_blks_res == 6 and match(fn_check, bs_ag_blks_res_6)) {
2979 return;
2980 }
2981 if (bs_ag_blks_res == 7 and match(fn_check, bs_ag_blks_res_7)) {
2982 return;
2983 }
2984
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02002985 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "received paging on AGCH");
Philipp Maier82cb0b12018-08-31 14:41:39 +02002986 return;
2987}
2988
2989altstep 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 +01002990runs on test_CT {
2991 var L1ctlDlMessage dl;
Harald Weltef8df4cb2018-03-10 15:15:08 +01002992 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_DummyUI)) {
Harald Welte68e495b2018-02-25 00:05:57 +01002993 repeat;
2994 }
Harald Weltef8df4cb2018-03-10 15:15:08 +01002995 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0))) -> value dl {
Harald Welte68e495b2018-02-25 00:05:57 +01002996 var octetstring without_plen :=
2997 substr(dl.payload.data_ind.payload, 1, lengthof(dl.payload.data_ind.payload)-1);
2998 var PDU_ML3_NW_MS rr := dec_PDU_ML3_NW_MS(without_plen);
Philipp Maier82cb0b12018-08-31 14:41:39 +02002999
3000 check_pch_fn(dl.dl_info.frame_nr, cfg.bs_ag_blks_res);
3001
Vadim Yanitskiy36aa07c2020-03-31 14:33:43 +07003002 if (match(rr, tr_PAGING_REQ1(tr_MI_LV(t_MI_NoIdentity(?))))) {
3003 /* Ignore empty RR Paging Request (PCH filling) messages.
3004 * TODO: does it make sense to count them? */
3005 } else if (match(rr, tr_PAGING_REQ1)) {
Harald Welte68e495b2018-02-25 00:05:57 +01003006 num_paging_rcv_msgs := num_paging_rcv_msgs + 1;
3007 num_paging_rcv_ids := num_paging_rcv_ids + 1;
Vadim Yanitskiyd665c232020-03-30 14:40:41 +07003008 if (ispresent(rr.msgs.rrm.pagingReq_Type1.mobileIdentity2)) {
Harald Welte68e495b2018-02-25 00:05:57 +01003009 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3010 }
3011 } else if (match(rr, tr_PAGING_REQ2)) {
3012 num_paging_rcv_msgs := num_paging_rcv_msgs + 1;
3013 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type2.mobileIdentity1)) {
3014 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3015 }
3016 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type2.mobileIdentity2)) {
3017 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3018 }
Vadim Yanitskiyd665c232020-03-30 14:40:41 +07003019 if (ispresent(rr.msgs.rrm.pagingReq_Type2.mobileIdentity3)) {
Harald Welte68e495b2018-02-25 00:05:57 +01003020 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3021 }
3022 } else if (match(rr, tr_PAGING_REQ3)) {
3023 num_paging_rcv_msgs := num_paging_rcv_msgs + 1;
3024 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity1)) {
3025 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3026 }
3027 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity2)) {
3028 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3029 }
3030 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity3)) {
3031 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3032 }
3033 if (not tmsi_is_dummy(rr.msgs.rrm.pagingReq_Type3.mobileIdentity4)) {
3034 num_paging_rcv_ids := num_paging_rcv_ids + 1;
3035 }
3036 }
3037 repeat;
3038 }
3039}
3040
3041type record PagingTestCfg {
3042 boolean combined_ccch,
3043 integer bs_ag_blks_res,
3044 float load_factor,
3045 boolean exp_load_ind,
3046 boolean exp_overload,
3047 boolean use_tmsi
3048}
3049
3050type record PagingTestState {
3051 integer num_paging_sent,
3052 integer num_paging_rcv_msgs,
3053 integer num_paging_rcv_ids,
3054 integer num_overload
3055}
3056
Harald Welte68e495b2018-02-25 00:05:57 +01003057/* Helper function for paging related testing */
3058private function f_TC_paging(PagingTestCfg cfg) runs on test_CT return PagingTestState {
Harald Welte10474062019-05-30 16:48:17 +02003059 f_init();
Harald Welte68e495b2018-02-25 00:05:57 +01003060 f_init_l1ctl();
3061 f_l1_tune(L1CTL);
3062
3063 var PagingTestState st := {
3064 num_paging_sent := 0,
3065 num_paging_rcv_msgs := 0,
3066 num_paging_rcv_ids := 0,
3067 num_overload := 0
3068 };
3069
3070 var float max_pch_blocks_per_sec := f_pch_block_rate_est(cfg.combined_ccch, cfg.bs_ag_blks_res);
3071 var float max_pch_imsi_per_sec;
3072 if (cfg.use_tmsi) {
3073 max_pch_imsi_per_sec := max_pch_blocks_per_sec * 4.0; /* Type 3 */
3074 } else {
3075 max_pch_imsi_per_sec := max_pch_blocks_per_sec * 2.0; /* Type 1 */
3076 }
3077 var float pch_blocks_per_sec := max_pch_imsi_per_sec * cfg.load_factor;
3078 var float interval := 1.0 / pch_blocks_per_sec;
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003079 var float time_total := 20.0;
3080 var integer pkt_total := float2int(time_total * pch_blocks_per_sec);
3081 log("pch_blocks_total=", pkt_total," pch_blocks_per_sec=", pch_blocks_per_sec, " interval=", interval);
Harald Welte68e495b2018-02-25 00:05:57 +01003082
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003083 timer T_total := 300.0; /* big value (far bigger than time_total), used to count elapsed time */
3084 T_total.start;
Harald Welte68e495b2018-02-25 00:05:57 +01003085
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003086 timer T_itv := 0.0;
3087 T_itv.start;
3088 while (st.num_paging_sent < pkt_total) {
Harald Welte68e495b2018-02-25 00:05:57 +01003089 alt {
3090 /* check for presence of CCCH LOAD IND (paging load) */
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003091 [cfg.exp_overload] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
Harald Welte68e495b2018-02-25 00:05:57 +01003092 st.num_overload := st.num_overload + 1;
3093 repeat;
3094 }
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003095 [not cfg.exp_overload] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND(0))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003096 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PCH Overload");
Harald Welte68e495b2018-02-25 00:05:57 +01003097 }
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003098 [cfg.exp_load_ind] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND)) {
Harald Welte68e495b2018-02-25 00:05:57 +01003099 log("Rx LOAD_IND");
3100 /* FIXME: analyze/verify interval + contents */
3101 repeat;
3102 }
3103 /* check if paging requests arrive on Um side */
Philipp Maier82cb0b12018-08-31 14:41:39 +02003104 [] as_l1_count_paging(st.num_paging_rcv_msgs, st.num_paging_rcv_ids, cfg);
Harald Welte68e495b2018-02-25 00:05:57 +01003105 [] L1CTL.receive { repeat; }
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003106 [] T_itv.timeout {
3107 /* Send paging cmds based on elapsed time */
3108 var integer new_sent := f_min(pkt_total, float2int(T_total.read * pch_blocks_per_sec) + 1);
3109 while (st.num_paging_sent < new_sent) {
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07003110 var MobileIdentityV mi;
3111
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003112 /* build mobile Identity */
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003113 if (cfg.use_tmsi) {
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07003114 mi := valueof(t_MI_TMSI(f_rnd_octstring(4)));
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003115 } else {
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07003116 mi := valueof(ts_MI_IMSI(f_gen_imsi(st.num_paging_sent)));
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003117 }
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003118
3119 /* Send RSL PAGING COMMAND */
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003120 RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_PAGING_CMD(mi, st.num_paging_sent mod 4)));
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003121
3122 st.num_paging_sent := st.num_paging_sent + 1;
3123 }
3124 if (st.num_paging_sent < pkt_total) {
3125 /* Wait for interval to next PAGING COMMAND */
3126 var float time_now := T_total.read;
3127 var float next_sched := int2float(st.num_paging_sent)*interval;
3128 if (next_sched > time_now) {
3129 T_itv.start(next_sched - time_now);
3130 } else {
3131 T_itv.start(0.0);
3132 }
3133 } else {
3134 /* We are done, no need to keep counting */
3135 T_total.stop;
3136 }
3137 }
3138 [] T_total.timeout { }
Harald Welte68e495b2018-02-25 00:05:57 +01003139 }
3140 }
3141
3142 /* wait for max 18s for paging queue to drain (size: 200, ~ 13 per s -> 15s) */
3143 timer T_wait := 18.0;
3144 T_wait.start;
3145 alt {
Philipp Maier82cb0b12018-08-31 14:41:39 +02003146 [] as_l1_count_paging(st.num_paging_rcv_msgs, st.num_paging_rcv_ids, cfg);
Harald Welte68e495b2018-02-25 00:05:57 +01003147 [] L1CTL.receive { repeat; }
3148 /* 65535 == empty paging queue, we can terminate*/
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003149 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND(65535))) { }
3150 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_PAGING_LOAD_IND)) { repeat; }
Harald Welte68e495b2018-02-25 00:05:57 +01003151 [] T_wait.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003152 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Waiting for empty paging queue");
Harald Welte68e495b2018-02-25 00:05:57 +01003153 }
Harald Welte68e495b2018-02-25 00:05:57 +01003154 }
3155
3156 log("num_paging_sent=", st.num_paging_sent, " rcvd_msgs=", st.num_paging_rcv_msgs,
3157 " rcvd_ids=", st.num_paging_rcv_ids);
3158 return st;
3159}
3160
3161/* Create ~ 80% paging load (IMSI only) sustained for about 20s, verifying that
3162 * - the number of Mobile Identities on Um PCH match the number of pages on RSL
3163 * - that CCCH LOAD IND (PCH) are being generated
3164 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
3165testcase TC_paging_imsi_80percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02003166 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01003167 var PagingTestCfg cfg := {
3168 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02003169 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01003170 load_factor := 0.8,
3171 exp_load_ind := true,
3172 exp_overload := false,
3173 use_tmsi := false
3174 };
3175 var PagingTestState st := f_TC_paging(cfg);
3176 if (st.num_paging_sent != st.num_paging_rcv_ids) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003177 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Expected ", st.num_paging_sent, " pagings but have ",
3178 st.num_paging_rcv_ids));
Harald Welte68e495b2018-02-25 00:05:57 +01003179 } else {
3180 setverdict(pass);
3181 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003182 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01003183}
3184
3185/* Create ~ 80% paging load (TMSI only) sustained for about 20s, verifying that
3186 * - the number of Mobile Identities on Um PCH match the number of pages on RSL
3187 * - that CCCH LOAD IND (PCH) are being generated
3188 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
3189testcase TC_paging_tmsi_80percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02003190 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01003191 var PagingTestCfg cfg := {
3192 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02003193 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01003194 load_factor := 0.8,
3195 exp_load_ind := true,
3196 exp_overload := false,
3197 use_tmsi := true
3198 };
3199 var PagingTestState st := f_TC_paging(cfg);
3200 if (st.num_paging_sent != st.num_paging_rcv_ids) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003201 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Expected ", st.num_paging_sent, " pagings but have ",
3202 st.num_paging_rcv_ids));
Harald Welte68e495b2018-02-25 00:05:57 +01003203 } else {
3204 setverdict(pass);
3205 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003206 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01003207}
3208
3209/* Create ~ 200% paging load (IMSI only) sustained for about 20s, verifying that
3210 * - the number of Mobile Identities on Um PCH are ~ 82% of the number of pages on RSL
3211 * - that CCCH LOAD IND (PCH) are being generated and reach 0 at some point
3212 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
3213testcase TC_paging_imsi_200percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02003214 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01003215 var PagingTestCfg cfg := {
3216 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02003217 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01003218 load_factor := 2.0,
3219 exp_load_ind := true,
3220 exp_overload := true,
3221 use_tmsi := false
3222 };
3223 var PagingTestState st := f_TC_paging(cfg);
3224 /* We expect about 80-85% to pass, given that we can fill the paging buffer of 200
3225 * slots and will fully drain that buffer before returning */
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003226 var template integer tpl := (st.num_paging_sent*78/100 .. st.num_paging_sent *85/100);
Harald Welte68e495b2018-02-25 00:05:57 +01003227 if (not match(st.num_paging_rcv_ids, tpl)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003228 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 +01003229 } else {
3230 setverdict(pass);
3231 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003232 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01003233}
3234
3235/* Create ~ 200% paging load (TMSI only) sustained for about 20s, verifying that
3236 * - the number of Mobile Identities on Um PCH are ~ 82% of the number of pages on RSL
3237 * - that CCCH LOAD IND (PCH) are being generated and reach 0 at some point
3238 * - that CCCH LOAD IND (PCH) [no load] is received after paging flood is over */
3239testcase TC_paging_tmsi_200percent() runs on test_CT {
Philipp Maierd65d0562018-08-30 16:25:47 +02003240 var SystemInformation si3 := valueof(ts_SI3_default);
Harald Welte68e495b2018-02-25 00:05:57 +01003241 var PagingTestCfg cfg := {
3242 combined_ccch := true,
Philipp Maierd65d0562018-08-30 16:25:47 +02003243 bs_ag_blks_res := si3.payload.si3.ctrl_chan_desc.bs_ag_blks_res,
Harald Welte68e495b2018-02-25 00:05:57 +01003244 load_factor := 2.0,
3245 exp_load_ind := true,
3246 exp_overload := true,
3247 use_tmsi := true
3248 };
3249 var PagingTestState st := f_TC_paging(cfg);
3250 /* We expect about 70% to pass, given that we can fill the paging buffer of 200
3251 * slots and will fully drain that buffer before returning */
Pau Espin Pedrol9c3ff4e2018-09-26 18:30:16 +02003252 var template integer tpl := (st.num_paging_sent*64/100 .. st.num_paging_sent *72/100);
Harald Welte68e495b2018-02-25 00:05:57 +01003253 if (not match(st.num_paging_rcv_ids, tpl)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003254 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 +01003255 } else {
3256 setverdict(pass);
3257 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003258 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01003259}
3260
3261
Harald Welte93640c62018-02-25 16:59:33 +01003262/***********************************************************************
3263 * Immediate Assignment / AGCH
3264 ***********************************************************************/
Vadim Yanitskiya9eeb7b2020-05-27 01:42:49 +07003265private const MobileAllocation c_MA_null := {
Harald Weltee8d750e2018-06-10 21:41:35 +02003266 len := 0,
3267 ma := ''B
3268}
Harald Welte93640c62018-02-25 16:59:33 +01003269
Vadim Yanitskiy92484562020-05-27 02:05:04 +07003270template (value) ChannelDescription ts_ChanDescH0(template (value) RslChannelNr chan_nr, uint3_t tsc := 7,
Vadim Yanitskiye9f68be2020-05-27 02:08:35 +07003271 uint12_t arfcn := mp_trx0_arfcn) := {
Harald Weltee8d750e2018-06-10 21:41:35 +02003272 chan_nr := chan_nr,
3273 tsc := tsc,
3274 h := false,
3275 arfcn := arfcn,
3276 maio_hsn := omit
3277}
3278
Vadim Yanitskiy92484562020-05-27 02:05:04 +07003279template (value) ChannelDescription ts_ChanDescH1(template (value) RslChannelNr chan_nr, uint3_t tsc := 7,
3280 template (value) MaioHsn maio_hsn) := {
3281 chan_nr := chan_nr,
3282 tsc := tsc,
3283 h := true,
3284 arfcn := omit,
3285 maio_hsn := maio_hsn
3286}
3287
Harald Weltee8d750e2018-06-10 21:41:35 +02003288private function f_fmt_ia_stats(integer num_tx, integer num_rx, integer num_del) return charstring {
3289 return int2str(num_tx) & " sent, "
3290 & int2str(num_rx) & " received, "
3291 & int2str(num_del) & " deleted";
3292}
3293
3294private function f_TC_imm_ass(integer num_total, float sleep_s, float exp_pass) runs on test_CT {
3295 var L1ctlDlMessage l1_dl;
3296 timer T := 10.0;
3297 var integer num_tx := 0;
3298 var integer num_rx := 0;
3299 var integer num_del := 0;
3300 var charstring res_str;
3301 var float rx_ratio;
3302
Harald Welte10474062019-05-30 16:48:17 +02003303 f_init();
Harald Weltee8d750e2018-06-10 21:41:35 +02003304 f_init_l1ctl();
3305 f_l1_tune(L1CTL);
3306
3307 for (var integer i := 0; i < num_total; i := i+1) {
Vadim Yanitskiy92484562020-05-27 02:05:04 +07003308 var ChannelDescription ch_desc := valueof(ts_ChanDescH0(valueof(t_RslChanNr_SDCCH4(0, 0))));
Harald Weltee8d750e2018-06-10 21:41:35 +02003309 var GsmRrMessage ia := valueof(ts_IMM_ASS(42, i, 5, ch_desc, c_MA_null));
3310 var octetstring ia_enc := enc_GsmRrMessage(ia);
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003311 RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_IMM_ASSIGN(ia_enc, 0)));
Harald Weltee8d750e2018-06-10 21:41:35 +02003312 num_tx := num_tx+1;
3313 f_sleep(sleep_s);
Harald Welte68e495b2018-02-25 00:05:57 +01003314 }
3315 /* FIXME: check if imm.ass arrive on Um side */
Harald Weltee8d750e2018-06-10 21:41:35 +02003316 T.start;
3317 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003318 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_DELETE_IND(?, 0))) {
Harald Weltee8d750e2018-06-10 21:41:35 +02003319 num_del := num_del+1;
3320 repeat;
3321 }
3322 [] RSL_CCHAN.receive {
3323 repeat;
3324 }
3325 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?)) -> value l1_dl {
3326 /* somehow dec_SystemInformation will try to decode even non-RR as SI */
3327 var GsmRrMessage rr := dec_GsmRrMessage(l1_dl.payload.data_ind.payload);
3328 if (not match(rr, tr_IMM_ASS(42, ?, 5, ?, ?))) {
3329 /* FIXME: Why are we seeing paging requests on PCH/AGCH? */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003330 //Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected IMM-ASS values on AGCH: ", rr));
Harald Weltee8d750e2018-06-10 21:41:35 +02003331 } else {
3332 num_rx := num_rx+1;
3333 }
3334 repeat;
3335 }
3336 [] L1CTL.receive { repeat; }
3337 [] T.timeout { }
3338 }
3339 res_str := f_fmt_ia_stats(num_tx, num_rx, num_del);
3340 log("AGCH test: " & res_str);
3341 if (num_rx + num_del != num_tx) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003342 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "RX + DEL != TX ?!?: " & res_str);
Harald Weltee8d750e2018-06-10 21:41:35 +02003343 }
3344 rx_ratio := int2float(num_rx) / int2float(num_tx);
3345 if (rx_ratio < exp_pass*0.8 or rx_ratio > exp_pass*1.2) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003346 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 +02003347 } else {
3348 setverdict(pass);
3349 }
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003350 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01003351}
3352
Harald Weltee8d750e2018-06-10 21:41:35 +02003353/* send a long burst of 1000 IMM.ASS with 20ms spacing (50 per s); expect 75% of them to be deleted */
3354testcase TC_imm_ass_1000_20ms() runs on test_CT {
3355 f_TC_imm_ass(1000, 0.02, 0.25);
3356}
3357
3358/* send a short burst of 200 IMM.ASS without any spacing; expect 95% of them to be deleted */
3359testcase TC_imm_ass_200_0ms() runs on test_CT {
3360 f_TC_imm_ass(200, 0.0, 0.05);
3361}
3362
3363/* send 150 IMM.ASS at rate of 13/s; expect none of them to be deleted */
3364testcase TC_imm_ass_200_76ms() runs on test_CT {
3365 f_TC_imm_ass(150, 0.076, 1.00);
3366}
3367
3368
3369
Harald Welte48494ca2018-02-25 16:59:50 +01003370/***********************************************************************
3371 * BCCH
3372 ***********************************************************************/
3373
3374/* tuple of Frame Number + decoded SI */
3375type record SystemInformationFn {
3376 GsmFrameNumber frame_number,
3377 SystemInformation si
3378}
3379
3380/* an arbitrary-length vector of decoded SI + gsmtap header */
3381type record of SystemInformationFn SystemInformationVector;
3382
3383/* an array of SI-vectors indexed by TC value */
3384type SystemInformationVector SystemInformationVectorPerTc[8];
3385
3386/* determine if a given SI vector contains given SI type at least once */
3387function f_si_vecslot_contains(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean {
3388 for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
3389 var integer fn_mod51 := arr[i].frame_number mod 51;
3390 if (not bcch_ext and fn_mod51 == 2 or
3391 bcch_ext and fn_mod51 == 6) {
3392 if (arr[i].si.header.message_type == key) {
3393 return true;
3394 }
3395 }
3396 }
3397 return false;
3398}
3399
3400/* ensure a given TC slot of the SI vector contains given SI type at least once at TC */
3401function f_ensure_si_vec_contains(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) {
3402 if (not f_si_vecslot_contains(arr[tc], key, ext_bcch)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003403 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No ", key, " in TC=", tc, "!"));
Harald Welte48494ca2018-02-25 16:59:50 +01003404 }
3405}
3406
3407/* check if a given SI vector contains given SI type at least once on any TC */
3408function f_si_vec_contains(SystemInformationVectorPerTc arr, RrMessageType key) return boolean {
3409 for (var integer tc:= 0; tc < sizeof(arr); tc := tc + 1) {
3410 if (f_si_vecslot_contains(arr[tc], key) or
3411 f_si_vecslot_contains(arr[tc], key, true)) {
3412 return true;
3413 }
3414 }
3415 return false;
3416}
3417
3418/* determine if a given SI vector contains given SI type at least N of M times */
3419function f_si_vecslot_contains_n_of_m(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false, integer n := 1, integer m := 4) return boolean {
3420 var integer count := 0;
3421 if (sizeof(arr) < m) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003422 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Error: Insufficient SI in array");
Harald Welte48494ca2018-02-25 16:59:50 +01003423 }
3424 for (var integer i:= 0; i < m; i := i + 1) {
3425 var integer fn_mod51 := arr[i].frame_number mod 51;
3426 if (not bcch_ext and fn_mod51 == 2 or
3427 bcch_ext and fn_mod51 == 6) {
3428 if (arr[i].si.header.message_type == key) {
3429 count := count + 1;
3430 }
3431 }
3432 }
3433 if (count >= n) {
3434 return true;
3435 } else {
3436 return false;
3437 }
3438}
3439
3440/* ensure a given TC slot of the SI vector contains given SI type at least N out of M times at TC */
3441function f_ensure_si_vec_contains_n_of_m(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false, integer n, integer m) {
3442 if (not f_si_vecslot_contains_n_of_m(arr[tc], key, ext_bcch, n, m)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003443 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Not ", n, "/", m, " of ", key, " in TC=", tc, "!"));
Harald Welte48494ca2018-02-25 16:59:50 +01003444 }
3445}
3446
3447/* determine if a given SI vector contains given SI type at least once */
3448function f_si_vecslot_contains_only(SystemInformationVector arr, RrMessageType key, boolean bcch_ext := false) return boolean {
3449 for (var integer i:= 0; i< sizeof(arr); i := i + 1) {
3450 var integer fn_mod51 := arr[i].frame_number mod 51;
3451 if (not bcch_ext and fn_mod51 == 2 or
3452 bcch_ext and fn_mod51 == 6) {
3453 if (arr[i].si.header.message_type != key) {
3454 return false;
3455 }
3456 }
3457 }
3458 return true;
3459}
3460
3461/* ensure a given TC slot of the SI vector contains only given SI type */
3462function f_ensure_si_vec_contains_only(SystemInformationVectorPerTc arr, integer tc, RrMessageType key, boolean ext_bcch := false) {
3463 if (not f_si_vecslot_contains_only(arr[tc], key, ext_bcch)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003464 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Not all ", key, " in TC=", tc, "!"));
Harald Welte48494ca2018-02-25 16:59:50 +01003465 }
3466}
3467
3468/* SI configuration of cell, against which we validate actual SI messages */
3469type set SystemInformationConfig {
3470 boolean bcch_extended,
3471 boolean si1_present,
3472 boolean si2bis_present,
3473 boolean si2ter_present,
3474 boolean si2quater_present,
3475 boolean si7_present,
3476 boolean si8_present,
3477 boolean si9_present,
3478 boolean si13_present,
3479 boolean si13alt_present,
3480 boolean si15_present,
3481 boolean si16_present,
3482 boolean si17_present,
3483 boolean si2n_present,
3484 boolean si21_present,
3485 boolean si22_present
3486}
3487
3488/* validate the SI scheduling according to TS 45.002 version 14.1.0 Release 14, Section 6.3.1.3 */
3489function f_validate_si_scheduling(SystemInformationConfig cfg, SystemInformationVectorPerTc si_per_tc) {
3490 var integer i;
3491 for (i := 0; i < sizeof(si_per_tc); i := i + 1) {
3492 if (sizeof(si_per_tc[i]) == 0) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003493 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("No SI messages for TC=", i));
Harald Welte48494ca2018-02-25 16:59:50 +01003494 }
3495 }
3496 if (cfg.si1_present) {
3497 /* ii) System Information Type 1 needs to be sent if frequency hopping is in use or
3498 * when the NCH is present in a cell. If the MS finds another message on BCCH Norm
3499 * when TC = 0, it can assume that System Information Type 1 is not in use. */
3500 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_1);
3501 /* make sure *ALL* contain SI1 */
3502 f_ensure_si_vec_contains_only(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_1);
3503 }
3504 f_ensure_si_vec_contains(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_2);
3505 /* iii) A SI 2 message will be sent at least every time TC = 1 */
3506 f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_3);
3507 f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_3);
3508 f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_4);
3509 f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_4);
3510
3511 /* iii) System information type 2 bis or 2 ter messages are sent if needed, as determined by the
3512 * system operator. If only one of them is needed, it is sent when TC = 5. If both are
3513 * needed, 2bis is sent when TC = 5 and 2ter is sent at least once within any of 4
3514 * consecutive occurrences of TC = 4. */
3515 if (cfg.si2bis_present and not cfg.si2ter_present) {
3516 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis);
3517 } else if (cfg.si2ter_present and not cfg.si2bis_present) {
3518 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2ter);
3519 } else if (cfg.si2ter_present and cfg.si2bis_present) {
3520 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2bis);
3521 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2ter, false, 1, 4);
3522 }
3523
3524 if (cfg.si7_present or cfg.si8_present) {
3525 /* vi) Use of System Information type 7 and 8 is not always necessary. It is necessary
3526 * if System Information type 4 does not contain all information needed for cell
3527 * selection and reselection. */
3528 if (not cfg.bcch_extended) {
3529 testcase.stop("Error: SI7/SI8 require BCCH Extd.");
3530 }
3531 if (cfg.si7_present) {
3532 f_ensure_si_vec_contains(si_per_tc, 7, SYSTEM_INFORMATION_TYPE_7, true);
3533 }
3534 if (cfg.si8_present) {
3535 f_ensure_si_vec_contains(si_per_tc, 3, SYSTEM_INFORMATION_TYPE_8, true);
3536 }
3537 }
3538
3539 if (cfg.si2quater_present) {
3540 /* iii) System information type 2 quater is sent if needed, as determined by the system
3541 * operator. If sent on BCCH Norm, it shall be sent when TC = 5 if neither of 2bis
3542 * and 2ter are used, otherwise it shall be sent at least once within any of 4
3543 * consecutive occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once
3544 * within any of 4 consecutive occurrences of TC = 5. */
3545 if (not (cfg.bcch_extended)) {
3546 if (not (cfg.si2bis_present or cfg.si2ter_present)) {
3547 f_ensure_si_vec_contains(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater);
3548 } else {
3549 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2quater, false, 1, 4);
3550 }
3551 } else {
3552 f_ensure_si_vec_contains_n_of_m(si_per_tc, 5, SYSTEM_INFORMATION_TYPE_2quater, true, 1, 4);
3553 }
3554 }
3555 if (cfg.si9_present) {
3556 /* vi) System Information type 9 is sent in those blocks with TC = 4 which are specified
3557 * in system information type 3 as defined in 3GPP TS 44.018. */
3558 f_ensure_si_vec_contains(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_9); // FIXME SI3
3559 }
3560 if (cfg.si13_present) {
3561 /* vii) System Information type 13 is only related to the GPRS service. System Information
3562 * Type 13 need only be sent if GPRS support is indicated in one or more of System
3563 * Information Type 3 or 4 or 7 or 8 messages. These messages also indicate if the
3564 * message is sent on the BCCH Norm or if the message is transmitted on the BCCH Ext.
3565 * In the case that the message is sent on the BCCH Norm, it is sent at least once
3566 * within any of 4 consecutive occurrences of TC=4. */
3567 if (not cfg.bcch_extended) {
3568 log("not-bccch-extended");
3569 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13, false, 1, 4);
3570 } else {
3571 log("bccch-extended");
3572 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13, true);
3573 }
3574 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13alt)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003575 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI13alt and SI13");
Harald Welte48494ca2018-02-25 16:59:50 +01003576 }
3577 }
3578 if (cfg.si16_present or cfg.si17_present) {
3579 /* viii) System Information type 16 and 17 are only related to the SoLSA service. They
3580 * should not be sent in a cell where network sharing is used (see rule xv). */
3581 if (cfg.si22_present) {
3582 testcase.stop("Error: Cannot have SI16/SI17 and SI22!");
3583 }
3584 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_22)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003585 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI16/SI17 and SI22!");
Harald Welte48494ca2018-02-25 16:59:50 +01003586 }
3587 if (not cfg.bcch_extended) {
3588 testcase.stop("Error: SI16/SI17 requires BCCH Extd!");
3589 }
3590 if (cfg.si16_present) {
3591 f_ensure_si_vec_contains(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_16, true);
3592 }
3593 if (cfg.si17_present) {
3594 f_ensure_si_vec_contains(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_17, true);
3595 }
3596 }
3597
3598 /* ix) System Information type 18 and 20 are sent in order to transmit non-GSM
3599 * broadcast information. The frequency with which they are sent is determined by the
3600 * system operator. System Information type 9 identifies the scheduling of System
3601 * Information type 18 and 20 messages. */
3602
3603 /* x) System Information Type 19 is sent if COMPACT neighbours exist. If System
3604 * Information Type 19 is present, then its scheduling shall be indicated in System
3605 * Information Type 9. */
3606
3607 if (cfg.si15_present) {
3608 /* xi) System Information Type 15 is broadcast if dynamic ARFCN mapping is used in the
3609 * PLMN. If sent on BCCH Norm, it is sent at least once within any of 4 consecutive
3610 * occurrences of TC = 4. If sent on BCCH Ext, it is sent at least once within any of
3611 * 4 consecutive occurrences of TC = 1. */
3612 if (not cfg.bcch_extended) {
3613 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_15, false, 1, 4);
3614 } else {
3615 f_ensure_si_vec_contains_n_of_m(si_per_tc, 1, SYSTEM_INFORMATION_TYPE_15, true, 1, 4);
3616 }
3617 }
3618 if (cfg.si13alt_present) {
3619 /* xii) System Information type 13 alt is only related to the GERAN Iu mode. System
3620 * Information Type 13 alt need only be sent if GERAN Iu mode support is indicated in
3621 * one or more of System Information Type 3 or 4 or 7 or 8 messages and SI 13 is not
3622 * broadcast. These messages also indicate if the message is sent on the BCCH Norm or
3623 * if the message is transmitted on the BCCH Ext. In the case that the message is sent
3624 * on the BCCH Norm, it is sent at least once within any of 4 consecutive occurrences
3625 * of TC = 4. */
3626 if (cfg.si13_present) {
3627 testcase.stop("Error: Cannot have SI13alt and SI13");
3628 }
3629 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_13)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003630 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI13alt and SI13");
Harald Welte48494ca2018-02-25 16:59:50 +01003631 }
3632 if (not cfg.bcch_extended) {
3633 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_13alt, false, 1, 4);
3634 } else {
3635 f_ensure_si_vec_contains(si_per_tc, 0, SYSTEM_INFORMATION_TYPE_13alt, true);
3636 }
3637 }
3638 if (cfg.si2n_present) {
3639 /* xiii) System Information Type 2n is optionally sent on BCCH Norm or BCCH Ext if needed,
3640 * as determined by the system operator. In the case that the message is sent on the
3641 * BCCH Norm, it is sent at least once within any of 4 consecutive occurrences of TC =
3642 * 4. If the message is sent on BCCH Ext, it is sent at least once within any of 2
3643 * consecutive occurrences of TC = 4. */
3644 if (not cfg.bcch_extended) {
3645 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n, false, 1, 4);
3646 } else {
3647 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_2n, true, 2, 4);
3648 }
3649 }
3650 if (cfg.si21_present) {
3651 /* xiv) System Information Type 21 is optionally sent on BCCH Norm or BCCH Ext, as
3652 * determined by the system operator. If Extended Access Barring is in use in the cell
3653 * then this message is sent at least once within any of 4 consecutive occurrences of
3654 * TC = 4 regardless if it is sent on BCCH Norm or BCCH Ext. If BCCH Ext is used in a
3655 * cell then this message shall only be sent on BCCH Ext. */
3656 if (not cfg.bcch_extended) {
3657 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21, false, 1, 4);
3658 } else {
3659 f_ensure_si_vec_contains_n_of_m(si_per_tc, 4, SYSTEM_INFORMATION_TYPE_21, true, 1, 4);
3660 if (f_si_vecslot_contains(si_per_tc[4], SYSTEM_INFORMATION_TYPE_21)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003661 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI21 on BCCH Norm if BCCH Extd enabled!");
Harald Welte48494ca2018-02-25 16:59:50 +01003662 }
3663 }
3664 }
3665 if (cfg.si22_present) {
3666 /* xv) System Information Type 22 is sent if network sharing is in use in the cell. It
3667 * should not be sent in a cell where SoLSA is used (see rule viii). System
3668 * Information Type 22 instances shall be sent on BCCH Ext within any occurrence of TC
3669 * =2 and TC=6. */
3670 if (cfg.si16_present or cfg.si17_present) {
3671 testcase.stop("Error: Cannot have SI16/SI17 and SI22!");
3672 }
3673 if (f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_16) or
3674 f_si_vec_contains(si_per_tc, SYSTEM_INFORMATION_TYPE_17)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003675 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Cannot have SI16/SI17 and SI22!");
Harald Welte48494ca2018-02-25 16:59:50 +01003676 }
3677 if (not cfg.bcch_extended) {
3678 testcase.stop("Error: SI22 requires BCCH Extd!");
3679 } else {
3680 f_ensure_si_vec_contains_only(si_per_tc, 2, SYSTEM_INFORMATION_TYPE_22, true);
3681 f_ensure_si_vec_contains_only(si_per_tc, 6, SYSTEM_INFORMATION_TYPE_22, true);
3682 }
3683 }
3684}
3685
3686/* sample Systme Information for specified duration via L1CTL */
3687function f_l1_sample_si(L1CTL_PT pt, float duration := 8.0) return SystemInformationVectorPerTc {
3688 timer T := duration;
3689 var SystemInformationVectorPerTc si_per_tc;
3690 var L1ctlDlMessage l1_dl;
3691
3692 /* initialize all per-TC vectors empty */
3693 for (var integer i:= 0; i < sizeof(si_per_tc); i := i+1) {
3694 si_per_tc[i] := {};
3695 }
3696
3697 /* flush all previous L1 queued msgs */
3698 pt.clear;
3699
3700 T.start;
3701 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +01003702 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
Harald Welte48494ca2018-02-25 16:59:50 +01003703 /* somehow dec_SystemInformation will try to decode even non-RR as SI */
3704 if (not (l1_dl.payload.data_ind.payload[1] == '06'O)) {
3705 log("Ignoring non-RR SI ", l1_dl);
3706 repeat;
3707 }
3708 var SystemInformationFn sig := {
3709 frame_number := l1_dl.dl_info.frame_nr,
3710 si := dec_SystemInformation(l1_dl.payload.data_ind.payload)
3711 }
3712 var integer tc := f_gsm_compute_tc(sig.frame_number);
3713 log("SI received at TC=", tc, ": ", sig.si);
3714 /* append to the per-TC bucket */
3715 si_per_tc[tc] := si_per_tc[tc] & { sig };
3716 repeat;
3717 }
3718 [] pt.receive { repeat; }
3719 [] T.timeout { }
3720 }
3721
3722 for (var integer i:= 0; i < sizeof(si_per_tc); i := i+1) {
3723 log(testcasename(), ": TC=", i, " has #of SI=", sizeof(si_per_tc[i]));
3724 }
3725 log("si_per_tc=", si_per_tc);
3726 return si_per_tc;
3727}
3728
3729/* helper function: Set given SI via RSL + validate scheduling.
3730 * CALLER MUST MAKE SURE TO CHANGE GLOBAL si_cfg! */
3731function f_TC_si_sched() runs on test_CT {
3732 var SystemInformationVectorPerTc si_per_tc;
3733 f_init_l1ctl();
3734 f_l1_tune(L1CTL);
3735
3736 /* Sample + Validate Scheduling */
3737 si_per_tc := f_l1_sample_si(L1CTL);
3738 f_validate_si_scheduling(si_cfg, si_per_tc);
3739
3740 setverdict(pass);
3741}
3742
3743testcase TC_si_sched_default() runs on test_CT {
3744 f_init();
Harald Welte0cae4552018-03-09 22:20:26 +01003745 /* 2+3+4 are mandatory and set in f_init() */
3746 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003747 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte0cae4552018-03-09 22:20:26 +01003748}
3749
3750testcase TC_si_sched_1() runs on test_CT {
3751 f_init();
3752 si_cfg.si1_present := true;
3753 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_1, '5506198fb38000000000000000000000000000e504002b'O);
Harald Welte48494ca2018-02-25 16:59:50 +01003754 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003755 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003756}
3757
3758testcase TC_si_sched_2bis() runs on test_CT {
3759 f_init();
3760 si_cfg.si2bis_present := true;
3761 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2bis, '550602bfe809b3ff00000000000000000000007900002b'O);
3762 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003763 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003764}
3765
3766testcase TC_si_sched_2ter() runs on test_CT {
3767 f_init();
3768 si_cfg.si2ter_present := true;
3769 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2ter, '010603bf66b0aa0a00000002000000000000002b2b2b2b'O);
3770 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003771 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003772}
3773
3774testcase TC_si_sched_2ter_2bis() runs on test_CT {
3775 f_init();
3776 si_cfg.si2bis_present := true;
3777 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2bis, '550602bfe809b3ff00000000000000000000007900002b'O);
3778 si_cfg.si2ter_present := true;
3779 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2ter, '010603bf66b0aa0a00000002000000000000002b2b2b2b'O);
3780 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003781 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003782}
3783
3784testcase TC_si_sched_2quater() runs on test_CT {
3785 f_init();
3786 si_cfg.si2quater_present := true;
3787 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2quater, '050607a8a0364aa698d72ff424feee0506d5e7fff02043'O);
3788 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003789 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003790}
3791
3792testcase TC_si_sched_13() runs on test_CT {
3793 f_init();
3794 si_cfg.si13_present := true;
Harald Welte5618c2a2018-04-15 16:24:46 +02003795 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_13, '0106009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b'O);
Harald Welte48494ca2018-02-25 16:59:50 +01003796 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003797 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003798}
3799
3800testcase TC_si_sched_13_2bis_2ter_2quater() runs on test_CT {
3801 f_init();
3802 si_cfg.si2bis_present := true;
3803 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2bis, '550602bfe809b3ff00000000000000000000007900002b'O);
3804 si_cfg.si2ter_present := true;
3805 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2ter, '010603bf66b0aa0a00000002000000000000002b2b2b2b'O);
3806 si_cfg.si2quater_present := true;
3807 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_2quater, '050607a8a0364aa698d72ff424feee0506d5e7fff02043'O);
3808 si_cfg.si13_present := true;
Harald Welte5618c2a2018-04-15 16:24:46 +02003809 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_13, '0106009000185a6fc9e08410ab2b2b2b2b2b2b2b2b2b2b'O);
Harald Welte48494ca2018-02-25 16:59:50 +01003810 f_TC_si_sched();
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003811 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte48494ca2018-02-25 16:59:50 +01003812}
3813
3814
Harald Welte68e495b2018-02-25 00:05:57 +01003815testcase TC_bcch_info() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003816 f_init();
Harald Welte68e495b2018-02-25 00:05:57 +01003817 /* FIXME: enable / disable individual BCCH info */
3818 //ts_RSL_BCCH_INFO(si_type, info);
3819 /* expect no ERROR REPORT after either of them *
3820 /* negative test: ensure ERROR REPORT on unsupported types */
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003821 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte68e495b2018-02-25 00:05:57 +01003822}
3823
Harald Welte93640c62018-02-25 16:59:33 +01003824/***********************************************************************
3825 * Low-Level Protocol Errors / ERROR REPORT
3826 ***********************************************************************/
3827
Harald Welte01d982c2018-02-25 01:31:40 +01003828private function f_exp_err_rep(template RSL_Cause cause) runs on test_CT {
3829 timer T := 5.0;
3830 T.start;
3831 alt {
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003832 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_ERROR_REPORT(cause))) {
Harald Welte01d982c2018-02-25 01:31:40 +01003833 setverdict(pass);
3834 }
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003835 [] RSL_CCHAN.receive(tr_ASP_RSL_UD(tr_RSL_ERROR_REPORT(?))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003836 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Wrong cause in RSL ERR REP");
Harald Welte01d982c2018-02-25 01:31:40 +01003837 }
3838 [] RSL_CCHAN.receive {
3839 repeat;
3840 }
3841 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02003842 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RSL ERR REP");
Harald Welte01d982c2018-02-25 01:31:40 +01003843 }
3844 }
3845}
3846
3847/* Provoke a protocol error (message too short) and match on ERROR REPORT */
3848testcase TC_rsl_protocol_error() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003849 f_init();
Harald Welte01d982c2018-02-25 01:31:40 +01003850 var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3851 rsl.ies := omit;
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003852 RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
Harald Welte01d982c2018-02-25 01:31:40 +01003853
3854 f_exp_err_rep(RSL_ERR_PROTO);
3855}
3856
3857/* Provoke a mandatory IE error and match on ERROR REPORT */
3858testcase TC_rsl_mand_ie_error() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003859 f_init();
Harald Welte01d982c2018-02-25 01:31:40 +01003860
3861 var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3862 rsl.ies := { rsl.ies[0] };
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003863 RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
Harald Welte01d982c2018-02-25 01:31:40 +01003864
3865 f_exp_err_rep(RSL_ERR_MAND_IE_ERROR);
3866}
3867
3868/* Provoke an IE content error and match on ERROR REPORT */
3869testcase TC_rsl_ie_content_error() runs on test_CT {
Harald Welte10474062019-05-30 16:48:17 +02003870 f_init();
Harald Welte01d982c2018-02-25 01:31:40 +01003871 var RSL_Message rsl := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3872 rsl.ies[1].body.sysinfo_type := RSL_SYSTEM_INFO_5;
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003873 RSL_CCHAN.send(ts_ASP_RSL_UD(rsl));
Harald Welte01d982c2018-02-25 01:31:40 +01003874
3875 f_exp_err_rep(RSL_ERR_IE_CONTENT);
3876}
3877
Harald Welteee25aae2019-05-19 14:32:37 +02003878/* attempt to activate channel with wrong RSL Message Discriminator IE */
3879function f_TC_chan_act_wrong_mdisc(charstring id) runs on ConnHdlr {
3880 var template RSL_Message rsl := ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode);
3881 rsl.msg_disc := ts_RSL_MsgDisc(RSL_MDISC_RESERVED, false);
3882 RSL.send(rsl);
3883 f_rslem_unregister(0, g_chan_nr);
3884}
3885testcase TC_err_rep_wrong_mdisc() runs on test_CT {
3886 var ConnHdlr vc_conn;
3887 var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_SDCCH4(0,0), ts_RSL_ChanMode_SIGN));
3888
Harald Welte10474062019-05-30 16:48:17 +02003889 f_init();
Harald Welteee25aae2019-05-19 14:32:37 +02003890
3891 vc_conn := f_start_handler(refers(f_TC_chan_act_wrong_mdisc), pars);
3892 vc_conn.done;
3893 f_exp_err_rep(RSL_ERR_MSG_DISCR);
3894
3895 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
3896}
3897
3898/* Send messages with wrong message type */
3899function f_TC_wrong_msg_type_dchan(charstring id) runs on ConnHdlr {
3900 var template (value) RSL_Message rsl_tx;
3901 rsl_tx := ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode);
3902 rsl_tx.msg_type := RSL_MT_NOT_CMD;
3903 RSL.send(rsl_tx);
3904 f_rslem_unregister(0, g_chan_nr);
3905}
3906function f_TC_wrong_msg_type_rll(charstring id) runs on ConnHdlr {
3907 var template (value) RSL_Message rsl_tx;
3908 /* we first have to activate the dedicated channel */
3909 f_rsl_chan_act(g_pars.chan_mode);
3910 /* ... to then send an invalid RLL message */
3911 rsl_tx := ts_RSL_UNITDATA_REQ(g_chan_nr, ts_RslLinkID_DCCH(0), '0102'O);
3912 rsl_tx.msg_type := RSL_MT_CBCH_LOAD_IND;
3913 RSL.send(rsl_tx);
3914 f_rslem_unregister(0, g_chan_nr);
3915}
3916testcase TC_err_rep_wrong_msg_type() runs on test_CT {
3917 var ConnHdlr vc_conn;
3918 var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_SDCCH4(0,0), ts_RSL_ChanMode_SIGN));
3919 var template (value) RSL_Message rsl_tx;
3920
Harald Welte10474062019-05-30 16:48:17 +02003921 f_init();
Harald Welteee25aae2019-05-19 14:32:37 +02003922
3923 /* Common Channel with wrong message type */
3924 RSL_CCHAN.clear;
3925 rsl_tx := valueof(ts_RSL_BCCH_INFO(RSL_SYSTEM_INFO_1, ''O));
3926 rsl_tx.msg_type := RSL_MT_LOCATION_INFO;
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003927 RSL_CCHAN.send(ts_ASP_RSL_UD(rsl_tx));
Harald Welteee25aae2019-05-19 14:32:37 +02003928 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3929
3930 /* TRX Management */
3931 RSL_CCHAN.clear;
3932 rsl_tx := ts_RSL_SACCH_FILL(RSL_SYSTEM_INFO_5, ''O);
3933 rsl_tx.msg_type := RSL_MT_UNIT_DATA_IND;
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07003934 RSL_CCHAN.send(ts_ASP_RSL_UD(rsl_tx));
Harald Welteee25aae2019-05-19 14:32:37 +02003935 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3936
3937 /* Dedicated Channel */
3938 RSL_CCHAN.clear;
3939 vc_conn := f_start_handler(refers(f_TC_wrong_msg_type_dchan), pars);
3940 vc_conn.done;
3941 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3942
3943 /* RLL */
3944 RSL_CCHAN.clear;
3945 vc_conn := f_start_handler(refers(f_TC_wrong_msg_type_rll), pars);
3946 vc_conn.done;
3947 f_exp_err_rep(RSL_ERR_MSG_TYPE);
3948}
3949
3950/* Send messages in wrong sequence (RLL to an inactive lchan) */
3951function f_TC_err_rep_wrong_sequence(charstring id) runs on ConnHdlr {
3952 RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, ts_RslLinkID_DCCH(0), '0102'O));
3953 f_rslem_unregister(0, g_chan_nr);
3954}
3955testcase TC_err_rep_wrong_sequence() runs on test_CT {
3956 var ConnHdlr vc_conn;
3957 var ConnHdlrPars pars := valueof(t_Pars(ts_RslChanNr_SDCCH4(0,0), ts_RSL_ChanMode_SIGN));
3958
Harald Welte10474062019-05-30 16:48:17 +02003959 f_init();
Harald Welteee25aae2019-05-19 14:32:37 +02003960
3961 RSL_CCHAN.clear;
3962 vc_conn := f_start_handler(refers(f_TC_err_rep_wrong_sequence), pars);
3963 vc_conn.done;
3964 f_exp_err_rep(RSL_ERR_MSG_SEQ);
3965}
3966
Harald Welte93640c62018-02-25 16:59:33 +01003967/***********************************************************************
3968 * IPA CRCX/MDCX/DLCS media stream handling
3969 ***********************************************************************/
3970
Harald Weltea871a382018-02-25 02:03:14 +01003971/* Send IPA DLCX to inactive lchan */
3972function f_TC_ipa_dlcx_not_active(charstring id) runs on ConnHdlr {
Harald Welte1eba3742018-02-25 12:48:14 +01003973 f_rsl_transceive(ts_RSL_IPA_DLCX(g_chan_nr, 0), tr_RSL_IPA_DLCX_ACK(g_chan_nr, ?, ?),
3974 "IPA DLCX ACK");
Harald Weltea871a382018-02-25 02:03:14 +01003975}
3976testcase TC_ipa_dlcx_not_active() runs on test_CT {
3977 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02003978 f_init();
Harald Weltea871a382018-02-25 02:03:14 +01003979 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_dlcx_not_active), pars);
3980 vc_conn.done;
3981}
Harald Welte68e495b2018-02-25 00:05:57 +01003982
Harald Weltea3f1df92018-02-25 12:49:55 +01003983/* Send IPA CRCX twice to inactive lchan */
3984function f_TC_ipa_crcx_twice_not_active(charstring id) runs on ConnHdlr {
3985 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
3986 "IPA CRCX ACK");
3987 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_NACK(g_chan_nr, RSL_ERR_RES_UNAVAIL),
3988 "IPA CRCX NACK");
3989}
3990testcase TC_ipa_crcx_twice_not_active() runs on test_CT {
3991 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02003992 f_init();
Harald Weltea3f1df92018-02-25 12:49:55 +01003993 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_crcx_twice_not_active), pars);
3994 vc_conn.done;
3995}
3996
3997/* Regular sequence of CRCX/MDCX/DLCX */
3998function f_TC_ipa_crcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
3999 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
4000 "IPA CRCX ACK");
4001 var uint32_t remote_ip := f_rnd_int(c_UINT32_MAX);
4002 var uint16_t remote_port := f_rnd_int(c_UINT16_MAX);
4003 var uint7_t rtp_pt2 := f_rnd_int(127);
4004 var uint16_t fake_conn_id := 23; /* we're too lazy to read it out from the CRCX ACK above */
4005 f_rsl_transceive(ts_RSL_IPA_MDCX(g_chan_nr, fake_conn_id, remote_ip, remote_port, rtp_pt2),
4006 tr_RSL_IPA_MDCX_ACK(g_chan_nr, ?, ?, ?, rtp_pt2),
4007 "IPA MDCX ACK");
4008 f_rsl_transceive(ts_RSL_IPA_DLCX(g_chan_nr, fake_conn_id), tr_RSL_IPA_DLCX_ACK(g_chan_nr, ?, ?),
4009 "IPA DLCX ACK");
4010}
4011testcase TC_ipa_crcx_mdcx_dlcx_not_active() runs on test_CT {
4012 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02004013 f_init();
Harald Weltea3f1df92018-02-25 12:49:55 +01004014 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_crcx_mdcx_dlcx_not_active), pars);
4015 vc_conn.done;
4016}
4017
Harald Welte3ae11da2018-02-25 13:36:06 +01004018/* Sequence of CRCX, 2x MDCX, DLCX */
4019function f_TC_ipa_crcx_mdcx_mdcx_dlcx_not_active(charstring id) runs on ConnHdlr {
4020 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_ACK(g_chan_nr, ?, ?, ?),
4021 "IPA CRCX ACK");
4022 var uint32_t remote_ip := f_rnd_int(c_UINT32_MAX);
4023 var uint16_t remote_port := f_rnd_int(c_UINT16_MAX);
4024 var uint7_t rtp_pt2 := f_rnd_int(127);
4025 var uint16_t fake_conn_id := 23; /* we're too lazy to read it out from the CRCX ACK above */
4026 f_rsl_transceive(ts_RSL_IPA_MDCX(g_chan_nr, fake_conn_id, remote_ip, remote_port, rtp_pt2),
4027 tr_RSL_IPA_MDCX_ACK(g_chan_nr, ?, ?, ?, rtp_pt2),
4028 "IPA MDCX ACK");
4029 /* Second MDCX */
4030 remote_ip := f_rnd_int(c_UINT32_MAX);
4031 remote_port := f_rnd_int(c_UINT16_MAX);
4032 f_rsl_transceive(ts_RSL_IPA_MDCX(g_chan_nr, fake_conn_id, remote_ip, remote_port, rtp_pt2),
4033 tr_RSL_IPA_MDCX_ACK(g_chan_nr, ?, ?, ?, rtp_pt2),
4034 "IPA MDCX ACK");
4035 f_rsl_transceive(ts_RSL_IPA_DLCX(g_chan_nr, fake_conn_id), tr_RSL_IPA_DLCX_ACK(g_chan_nr, ?, ?),
4036 "IPA DLCX ACK");
4037}
4038testcase TC_ipa_crcx_mdcx_mdcx_dlcx_not_active() runs on test_CT {
4039 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
Harald Welte10474062019-05-30 16:48:17 +02004040 f_init();
Harald Welte3ae11da2018-02-25 13:36:06 +01004041 var ConnHdlr vc_conn := f_start_handler(refers(f_TC_ipa_crcx_mdcx_mdcx_dlcx_not_active), pars);
4042 vc_conn.done;
4043}
4044
Harald Welte9912eb52018-02-25 13:30:15 +01004045/* IPA CRCX on SDCCH/4 and SDCCH/8 (doesn't make sense) */
4046function f_TC_ipa_crcx_sdcch_not_active(charstring id) runs on ConnHdlr {
4047 f_rsl_transceive(ts_RSL_IPA_CRCX(g_chan_nr), tr_RSL_IPA_CRCX_NACK(g_chan_nr, ?),
4048 "IPA CRCX NACK");
4049}
4050testcase TC_ipa_crcx_sdcch_not_active() runs on test_CT {
4051 var ConnHdlrPars pars;
4052 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02004053 f_init();
Harald Welte9912eb52018-02-25 13:30:15 +01004054
4055 pars := valueof(t_Pars(t_RslChanNr_SDCCH4(0,1), ts_RSL_ChanMode_SIGN));
4056 vc_conn := f_start_handler(refers(f_TC_ipa_crcx_sdcch_not_active), pars);
4057 vc_conn.done;
4058
4059 pars := valueof(t_Pars(t_RslChanNr_SDCCH8(6,5), ts_RSL_ChanMode_SIGN));
4060 vc_conn := f_start_handler(refers(f_TC_ipa_crcx_sdcch_not_active), pars);
4061 vc_conn.done;
4062}
4063
Harald Weltea3f1df92018-02-25 12:49:55 +01004064
Harald Welte883340c2018-02-28 18:59:29 +01004065/***********************************************************************
4066 * PCU Socket related tests
4067 ***********************************************************************/
4068
Harald Welte07bd2d22019-05-25 11:03:30 +02004069/* Verify no RTS before ACT_REQ; verify RTS after ACT_REQ */
Harald Weltead033dc2019-05-25 17:28:16 +02004070friend 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 +01004071runs on test_CT {
4072 timer T := 3.0;
4073
4074 /* we don't expect any RTS.req before PDCH are active */
4075 T.start;
4076 alt {
4077 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004078 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "PCU RTS.req before PDCH active?");
Harald Welte883340c2018-02-28 18:59:29 +01004079 }
4080 [] PCU.receive { repeat; }
4081 [] T.timeout { }
4082 }
4083
4084 /* Send PDCH activate request for known PDCH timeslot */
4085 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, ts_nr)));
4086
4087 /* we now expect RTS.req for this timeslot (only) */
4088 T.start;
4089 alt {
4090 [exp_success] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
4091 setverdict(pass);
4092 }
4093 [not exp_success] PCU.receive(t_SD_PCUIF(g_pcu_conn_id,
4094 tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr))) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004095 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RTS.req for supposedly failing activation");
Harald Welte883340c2018-02-28 18:59:29 +01004096 }
4097 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004098 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "RTS.req for wrong TRX/TS");
Harald Welte883340c2018-02-28 18:59:29 +01004099 }
4100 [] PCU.receive { repeat; }
4101 [exp_success] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004102 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU RTS.req");
Harald Welte883340c2018-02-28 18:59:29 +01004103 }
4104 [not exp_success] T.timeout {
4105 setverdict(pass);
4106 }
4107 }
4108}
4109
Harald Welte07bd2d22019-05-25 11:03:30 +02004110/* verify no more RTS after DEACT_REQ */
Harald Weltead033dc2019-05-25 17:28:16 +02004111friend 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 +01004112runs on test_CT {
4113 timer T := 3.0;
4114
4115 /* Send PDCH activate request for known PDCH timeslot */
4116 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, ts_nr)));
4117
4118 PCU.clear;
4119 /* we now expect no RTS.req for this timeslot */
4120 T.start;
4121 alt {
4122 [] 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 +02004123 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected PCU RTS.req");
Harald Welte883340c2018-02-28 18:59:29 +01004124 }
4125 [] PCU.receive { repeat; }
4126 [] T.timeout {
4127 setverdict(pass);
4128 }
4129 }
4130}
4131
Harald Weltead033dc2019-05-25 17:28:16 +02004132friend function f_init_pcu_test() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004133 f_init();
4134 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_TXT_IND(0, PCU_VERSION, testcasename())));
4135}
4136
Harald Welte883340c2018-02-28 18:59:29 +01004137/* PDCH activation via PCU socket; check for presence of RTS.req */
4138testcase TC_pcu_act_req() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004139 f_init_pcu_test();
4140
Harald Welte883340c2018-02-28 18:59:29 +01004141 f_TC_pcu_act_req(0, 0, 7, true);
4142}
4143
4144/* PDCH activation via PCU socket on non-PDCU timeslot */
4145testcase TC_pcu_act_req_wrong_ts() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004146 f_init_pcu_test();
4147
Harald Welte883340c2018-02-28 18:59:29 +01004148 f_TC_pcu_act_req(0, 0, 1, false);
4149}
4150
4151/* PDCH activation via PCU socket on wrong BTS */
4152testcase TC_pcu_act_req_wrong_bts() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004153 f_init_pcu_test();
4154
Harald Welte883340c2018-02-28 18:59:29 +01004155 f_TC_pcu_act_req(23, 0, 7, false);
4156}
4157
4158/* PDCH activation via PCU socket on wrong TRX */
4159testcase TC_pcu_act_req_wrong_trx() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004160 f_init_pcu_test();
4161
Harald Welte883340c2018-02-28 18:59:29 +01004162 f_TC_pcu_act_req(0, 23, 7, false);
4163}
4164
4165/* PDCH deactivation via PCU socket; check for absence of RTS.req */
4166testcase TC_pcu_deact_req() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004167 f_init_pcu_test();
4168
Harald Welte883340c2018-02-28 18:59:29 +01004169 /* Activate PDCH */
4170 f_TC_pcu_act_req(0, 0, 7, true);
4171 f_sleep(1.0);
4172 /* and De-Activate again */
4173 f_TC_pcu_deact_req(0, 0, 7);
4174}
4175
4176/* Attempt to deactivate a PDCH on a non-PDCH timeslot */
4177testcase TC_pcu_deact_req_wrong_ts() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004178 f_init_pcu_test();
4179
Harald Welte883340c2018-02-28 18:59:29 +01004180 f_TC_pcu_deact_req(0, 0, 1);
4181}
4182
4183/* Test the PCU->BTS Version and BTS->PCU SI13 handshake */
4184testcase TC_pcu_ver_si13() runs on test_CT {
4185 const octetstring si13 := '00010203040506070909'O;
4186 var PCUIF_send_data sd;
4187 timer T:= 3.0;
Max2c6f5632019-03-18 17:25:17 +01004188 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01004189
4190 /* Set SI13 via RSL */
4191 f_rsl_bcch_fill_raw(RSL_SYSTEM_INFO_13, si13);
Max2c6f5632019-03-18 17:25:17 +01004192
Harald Welte883340c2018-02-28 18:59:29 +01004193 T.start;
4194 alt {
4195 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_DATA_IND(0, 0, 0, ?, PCU_IF_SAPI_BCCH))) -> value sd {
4196 if (substr(sd.data.u.data_ind.data, 0, lengthof(si13)) == si13) {
4197 setverdict(pass);
4198 } else {
4199 repeat;
4200 }
4201 }
4202 [] PCU.receive { repeat; }
4203 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004204 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for SI13");
Harald Welte883340c2018-02-28 18:59:29 +01004205 }
4206 }
4207}
4208
4209private const octetstring c_PCU_DATA := '000102030405060708090a0b0c0d0e0f10111213141516'O;
4210
4211/* helper function to send a PCU DATA.req */
Harald Weltead033dc2019-05-25 17:28:16 +02004212friend function f_pcu_data_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
Harald Welte883340c2018-02-28 18:59:29 +01004213 uint8_t block_nr, uint32_t fn, PCUIF_Sapi sapi, octetstring data)
4214runs on test_CT
4215{
4216 PCU.send(t_SD_PCUIF(g_pcu_conn_id,
4217 ts_PCUIF_DATA_REQ(bts_nr, trx_nr, ts_nr, block_nr, fn, sapi, data)));
4218}
4219
4220/* 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 +02004221friend function f_pcu_wait_rts_and_data_req(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
4222 PCUIF_Sapi sapi, octetstring data)
Harald Welte883340c2018-02-28 18:59:29 +01004223runs on test_CT
4224{
4225 var PCUIF_send_data sd;
4226
4227 timer T := 3.0;
4228 T.start;
4229 alt {
4230 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id,
4231 tr_PCUIF_RTS_REQ(bts_nr, trx_nr, ts_nr, sapi))) -> value sd {
4232 f_pcu_data_req(bts_nr, trx_nr, ts_nr, sd.data.u.rts_req.block_nr,
4233 sd.data.u.rts_req.fn, sapi, data);
4234 }
4235 [] PCU.receive { repeat; }
4236 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004237 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RTS.ind");
Harald Welte883340c2018-02-28 18:59:29 +01004238 }
4239 }
4240}
4241
4242/* Send DATA.req on invalid BTS */
4243testcase TC_pcu_data_req_wrong_bts() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02004244 var TfiUsfArr tua := f_TfiUsfArrInit();
4245 var octetstring data := '0000'O & f_rnd_octstring(21);
4246
4247 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01004248
Harald Welte883340c2018-02-28 18:59:29 +01004249 f_TC_pcu_act_req(0, 0, 7, true);
Harald Welte7162a612019-05-26 12:56:09 +02004250 f_TfiUsfArrSet(tua, 7, 0);
4251 f_L1CTL_TBF_CFG(L1CTL, false, tua);
4252 f_sleep(1.0);
4253
4254 f_pcu_to_l1(23, 0, 7, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01004255}
4256
4257/* Send DATA.req on invalid TRX */
4258testcase TC_pcu_data_req_wrong_trx() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02004259 var TfiUsfArr tua := f_TfiUsfArrInit();
4260 var octetstring data := '0000'O & f_rnd_octstring(21);
4261
4262 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01004263
Harald Welte883340c2018-02-28 18:59:29 +01004264 f_TC_pcu_act_req(0, 0, 7, true);
Harald Welte7162a612019-05-26 12:56:09 +02004265 f_TfiUsfArrSet(tua, 7, 0);
4266 f_L1CTL_TBF_CFG(L1CTL, false, tua);
4267 f_sleep(1.0);
4268
4269 f_pcu_to_l1(0, 100, 7, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01004270}
4271
4272/* Send DATA.req on invalid timeslot */
4273testcase TC_pcu_data_req_wrong_ts() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02004274 var TfiUsfArr tua := f_TfiUsfArrInit();
4275 var octetstring data := '0000'O & f_rnd_octstring(21);
4276
4277 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01004278
Harald Welte883340c2018-02-28 18:59:29 +01004279 f_TC_pcu_act_req(0, 0, 7, true);
Harald Welte7162a612019-05-26 12:56:09 +02004280 f_TfiUsfArrSet(tua, 7, 0);
4281 f_L1CTL_TBF_CFG(L1CTL, false, tua);
4282 f_sleep(1.0);
4283
4284 f_pcu_to_l1(0, 0, 70, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01004285}
4286
4287/* Send DATA.req on timeslot that hasn't been activated */
4288testcase TC_pcu_data_req_ts_inactive() runs on test_CT {
Harald Welte7162a612019-05-26 12:56:09 +02004289 var TfiUsfArr tua := f_TfiUsfArrInit();
4290 var octetstring data := '0000'O & f_rnd_octstring(21);
Max2c6f5632019-03-18 17:25:17 +01004291
Harald Welte7162a612019-05-26 12:56:09 +02004292 f_virtphy_common();
4293
4294 f_TfiUsfArrSet(tua, 7, 0);
4295 f_L1CTL_TBF_CFG(L1CTL, false, tua);
4296 f_sleep(1.0);
4297
4298 f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PDTCH, data, false, false);
Harald Welte883340c2018-02-28 18:59:29 +01004299}
4300
Harald Weltead033dc2019-05-25 17:28:16 +02004301private function f_pcu_to_l1(uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
Harald Welte7162a612019-05-26 12:56:09 +02004302 PCUIF_Sapi sapi, octetstring data, boolean expect_data := true,
4303 boolean wait_rts := true)
4304runs on test_CT {
Harald Weltead033dc2019-05-25 17:28:16 +02004305 timer T := 5.0;
Harald Welte7162a612019-05-26 12:56:09 +02004306 var L1ctlDlMessage rx_dl;
Harald Weltead033dc2019-05-25 17:28:16 +02004307
4308 PCU.clear;
Harald Welte7162a612019-05-26 12:56:09 +02004309 if (wait_rts) {
4310 f_pcu_wait_rts_and_data_req(bts_nr, trx_nr, ts_nr, sapi, data);
4311 } else {
4312 f_pcu_data_req(bts_nr, trx_nr, ts_nr, 0, 0, sapi, data);
4313 }
Harald Weltead033dc2019-05-25 17:28:16 +02004314
4315 T.start;
4316 alt {
Harald Welte7162a612019-05-26 12:56:09 +02004317 [expect_data] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PDCH(ts_nr), ?, data)) {
Harald Weltead033dc2019-05-25 17:28:16 +02004318 /* FIXME: why is fn of DATA_IND different to fn of RTS / DATA_REQ above? */
4319 setverdict(pass);
4320 }
Harald Welte7162a612019-05-26 12:56:09 +02004321 [not expect_data] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PDCH(ts_nr), ?, data)) -> value rx_dl {
4322 setverdict(fail, "Received unexpected ", rx_dl);
4323 }
Harald Weltead033dc2019-05-25 17:28:16 +02004324 [] L1CTL.receive {
4325 repeat;
4326 }
Harald Welte7162a612019-05-26 12:56:09 +02004327 [expect_data] T.timeout {
Harald Weltead033dc2019-05-25 17:28:16 +02004328 setverdict(fail, "Timeout waiting for ", data);
4329 }
Harald Welte7162a612019-05-26 12:56:09 +02004330 [not expect_data] T.timeout {
4331 setverdict(pass);
4332 }
Harald Weltead033dc2019-05-25 17:28:16 +02004333 }
4334}
4335
4336private function f_disable_dynamic_ts() runs on test_CT
4337{
4338 f_init_vty_bsc();
4339 /* I'm not quite sure why we need this with osmo-bts-virtual. Somehow it deosn't seem to
4340 * support dynamic timeslots? But it uses the same scheduler as osmo-bts-trx ?!? */
4341 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 3"}, "phys_chan_config TCH/F");
4342 f_vty_config2(BSCVTY, {"network", "bts 0", "trx 0", "timeslot 4"}, "phys_chan_config TCH/F");
Max2c6f5632019-03-18 17:25:17 +01004343 f_init_pcu_test();
Harald Weltead033dc2019-05-25 17:28:16 +02004344}
4345
4346private function f_virtphy_common() runs on test_CT {
4347 f_disable_dynamic_ts();
4348 f_init_l1ctl();
4349 f_l1_tune(L1CTL);
4350}
4351
4352testcase TC_pcu_data_req_pdtch() runs on test_CT {
4353 var TfiUsfArr tua := f_TfiUsfArrInit();
4354 var octetstring data := '0000'O & f_rnd_octstring(21);
4355
4356 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01004357
Harald Welte883340c2018-02-28 18:59:29 +01004358 f_TC_pcu_act_req(0, 0, 7, true);
Harald Weltead033dc2019-05-25 17:28:16 +02004359 f_TfiUsfArrSet(tua, 7, 0);
4360 f_L1CTL_TBF_CFG(L1CTL, false, tua);
4361 f_sleep(1.0);
4362
4363 f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PDTCH, data); //c_PCU_DATA);
Harald Welte883340c2018-02-28 18:59:29 +01004364}
4365
Vadim Yanitskiy8c242f02019-10-13 15:25:54 +07004366/* FIXME: PTTCH has nothing to do with TBFs */
Harald Welte883340c2018-02-28 18:59:29 +01004367testcase TC_pcu_data_req_ptcch() runs on test_CT {
Harald Weltead033dc2019-05-25 17:28:16 +02004368 var TfiUsfArr tua := f_TfiUsfArrInit();
4369 var octetstring data := '0000'O & f_rnd_octstring(21);
4370
4371 f_virtphy_common();
Max2c6f5632019-03-18 17:25:17 +01004372
Harald Welte883340c2018-02-28 18:59:29 +01004373 f_TC_pcu_act_req(0, 0, 7, true);
Harald Weltead033dc2019-05-25 17:28:16 +02004374 f_TfiUsfArrSet(tua, 7, 0);
4375 f_L1CTL_TBF_CFG(L1CTL, false, tua);
4376 f_sleep(1.0);
4377
4378 f_pcu_to_l1(0, 0, 7, PCU_IF_SAPI_PTCCH, data);
Harald Welte883340c2018-02-28 18:59:29 +01004379}
4380
Vadim Yanitskiy8c242f02019-10-13 15:25:54 +07004381private function f_TC_pcu_ptcch_ul(uint16_t ra)
4382runs on test_CT {
4383 var template PCUIF_Message pcu_rach_ind;
4384 var PCUIF_send_data sd;
4385 var GsmFrameNumber fn;
4386 timer T;
4387
4388 /* Send an Access Burst on PTCCH/U over the Um-interface */
4389 fn := f_L1CTL_RACH(L1CTL, ra := ra, combined := 0, offset := 0,
4390 chan_nr := ts_RslChanNr_PDCH(7),
4391 link_id := ts_RslLinkID_OSMO_PTCCH(0));
4392
Vadim Yanitskiy36558d92019-11-17 02:23:51 +07004393 pcu_rach_ind := tr_PCUIF_RACH_IND(bts_nr := 0, trx_nr := 0, ts_nr := 7,
4394 ra := ra, fn := fn, sapi := PCU_IF_SAPI_PTCCH);
Vadim Yanitskiy8c242f02019-10-13 15:25:54 +07004395
4396 /* Expect a RACH.ind on the PCU interface (timeout is one multi-frame) */
4397 T.start(52.0 * 4.615 / 1000.0);
4398 alt {
4399 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, pcu_rach_ind)) -> value sd {
4400 log("Rx an Access Burst on the PCU interface: ", sd.data);
4401 setverdict(pass);
4402 T.stop;
4403 }
4404 [] PCU.receive { repeat; }
4405 [] T.timeout {
4406 setverdict(fail, "Timeout waiting for RACH.ind on the PCU interface");
4407 /* Keep going, that's not the end of the world */
4408 }
4409 }
4410}
4411
4412testcase TC_pcu_ptcch() runs on test_CT {
4413 var L1ctlDlMessage dl;
4414 var octetstring data;
4415 timer T;
4416
4417 f_init_pcu_test();
4418 f_init_l1ctl();
4419 f_l1_tune(L1CTL);
4420
4421 /* Activate PDCH channel on TS7 */
4422 f_TC_pcu_act_req(0, 0, 7, true);
4423
4424 /* Tune trxcon to that PDCH channel */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07004425 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(ts_RslChanNr_PDCH(7), 7, mp_trx0_arfcn));
Vadim Yanitskiy8c242f02019-10-13 15:25:54 +07004426
4427 /* Verify PTCCH/U: send several access bursts, make sure they're received */
4428 for (var integer i := 0; i < 16; i := i + 1) {
4429 log("Sending an Access Burst towards the L1CTL interface");
4430 f_TC_pcu_ptcch_ul(oct2int(f_rnd_ra_ps()));
4431 }
4432
4433 /* Generate a random payload for PTCCH/D (23 octets, CS-1) */
4434 data := f_rnd_octstring(23);
4435
4436 /* Verify PTCCH/D: send a random data block, make sure it's received */
4437 log("Sending a PTCCH/D block towards the PCU interface: ", data);
4438 f_pcu_wait_rts_and_data_req(0, 0, 7, PCU_IF_SAPI_PTCCH, data);
4439
4440 /* PTCCH/D period is 2 multi-frames (2 * 52 * 4.615 ms), but
4441 * let's give it more time in case if we miss the beginning. */
4442 T.start(2.0 * 2.0 * 52.0 * 4.615 / 1000.0);
4443 alt {
4444 /* PDCH is considered as traffic in trxcon => expect TRAFFIC.ind */
4445 [] L1CTL.receive(tr_L1CTL_TRAFFIC_IND(chan_nr := t_RslChanNr_PDCH(7),
4446 link_id := tr_RslLinkID_OSMO_PTCCH(?),
4447 frame := data)) -> value dl {
4448 log("Rx PTCCH/D data (traffic) block on L1CTL: ", dl);
4449 setverdict(pass);
4450 T.stop;
4451 }
4452 /* Other PHYs (e.g. virt_phy) may consider PDCH as data => expect DATA.ind */
4453 [] L1CTL.receive(tr_L1CTL_DATA_IND(chan_nr := t_RslChanNr_PDCH(7),
4454 link_id := tr_RslLinkID_OSMO_PTCCH(?),
4455 l2_data := data)) -> value dl {
4456 log("Rx PTCCH/D data block on L1CTL: ", dl);
4457 setverdict(pass);
4458 T.stop;
4459 }
4460 [] L1CTL.receive { repeat; }
4461 [] T.timeout {
4462 setverdict(fail, "Timeout waiting for DATA.ind on L1CTL");
4463 }
4464 }
4465}
4466
Harald Welte883340c2018-02-28 18:59:29 +01004467/* Send AGCH from PCU; check it appears on Um side */
4468testcase TC_pcu_data_req_agch() runs on test_CT {
4469 timer T := 3.0;
Max2c6f5632019-03-18 17:25:17 +01004470 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01004471 f_init_l1ctl();
4472 f_l1_tune(L1CTL);
4473
4474 f_TC_pcu_act_req(0, 0, 7, true);
4475 f_pcu_data_req(0, 0, 7, 0, 0, PCU_IF_SAPI_AGCH, c_PCU_DATA);
4476
4477 T.start;
4478 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +01004479 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_PCU_DATA)) {
Harald Welte883340c2018-02-28 18:59:29 +01004480 setverdict(pass);
4481 }
4482 [] L1CTL.receive { repeat; }
4483 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004484 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU-originated AGCH block on Um");
Harald Welte883340c2018-02-28 18:59:29 +01004485 }
4486 }
4487}
4488
Harald Welte928622b2019-05-26 13:22:59 +02004489/* Send AGCH from PCU; check it appears on Um side */
4490testcase TC_pcu_data_req_pch() runs on test_CT {
4491 timer T := 3.0;
4492 f_init_pcu_test();
4493 f_init_l1ctl();
4494 f_l1_tune(L1CTL);
4495
4496 f_TC_pcu_act_req(0, 0, 7, true);
4497 /* three characters prefix: last 3 digits of IMSI as ASCII */
4498 f_pcu_data_req(0, 0, 7, 0, 0, PCU_IF_SAPI_PCH, '313233'O & c_PCU_DATA);
4499
4500 T.start;
4501 alt {
4502 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, c_PCU_DATA)) {
4503 setverdict(pass);
4504 }
4505 [] L1CTL.receive { repeat; }
4506 [] T.timeout {
4507 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU-originated PCH block on Um");
4508 }
4509 }
4510}
4511
Harald Welte883340c2018-02-28 18:59:29 +01004512/* Send IMM.ASS from PCU for PCH; check it appears on Um side */
4513testcase TC_pcu_data_req_imm_ass_pch() runs on test_CT {
4514 var octetstring imm_ass := f_rnd_octstring(23);
Max2c6f5632019-03-18 17:25:17 +01004515 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01004516 f_init_l1ctl();
4517 f_l1_tune(L1CTL);
4518
4519 /* append 3 last imsi digits so BTS can compute pagng group */
4520 var uint32_t fn := f_PCUIF_tx_imm_ass_pch(PCU, g_pcu_conn_id, imm_ass, '123459987'H);
4521
4522 timer T := 0.5;
4523 T.start;
4524 alt {
Harald Weltef8df4cb2018-03-10 15:15:08 +01004525 [] L1CTL.receive(tr_L1CTL_DATA_IND(t_RslChanNr_PCH_AGCH(0), ?, imm_ass)) {
Harald Welte883340c2018-02-28 18:59:29 +01004526 /* TODO: verify paging group */
4527 setverdict(pass);
4528 }
4529 [] L1CTL.receive { repeat; }
4530 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004531 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PCU-originated AGCH block on Um");
Harald Welte883340c2018-02-28 18:59:29 +01004532 }
4533 }
4534}
4535
4536/* Send RACH from Um side, expect it to show up on PCU socket */
4537testcase TC_pcu_rach_content() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004538 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01004539 f_init_l1ctl();
4540 f_l1_tune(L1CTL);
4541
4542 var GsmFrameNumber fn_last := 0;
4543 for (var integer i := 0; i < 1000; i := i+1) {
4544 var OCT1 ra := f_rnd_ra_ps();
4545 var GsmFrameNumber fn := f_L1CTL_RACH(L1CTL, oct2int(ra));
4546 if (fn == fn_last) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004547 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Two RACH in same FN?!?");
Harald Welte883340c2018-02-28 18:59:29 +01004548 }
4549 fn_last := fn;
4550
4551 timer T := 2.0;
4552 T.start;
4553 alt {
Vadim Yanitskiy36558d92019-11-17 02:23:51 +07004554 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND(0, 0, 0, oct2int(ra), 0, ?, fn))) {
Harald Welte883340c2018-02-28 18:59:29 +01004555 T.stop;
4556 }
4557 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004558 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RACH IND");
Harald Welte883340c2018-02-28 18:59:29 +01004559 }
4560 [] PCU.receive { repeat; }
4561 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004562 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RACH IND");
Harald Welte883340c2018-02-28 18:59:29 +01004563 }
4564 }
4565 }
4566 setverdict(pass);
4567}
4568
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +07004569/* Send extended (11-bit, TS1 & TS2) RACH bursts from the Um side,
4570 * expect them to show up on PCU socket (with proper BURST_TYPE_*). */
4571testcase TC_pcu_ext_rach_content() runs on test_CT {
4572 var template PCUIF_Message pcu_rach_ind;
4573 var GsmFrameNumber fn_last := 0;
4574 var L1ctlRachSynchSeq synch_seq;
4575 var PCUIF_BurstType pcu_bt;
4576 var GsmFrameNumber fn;
4577 var BIT11 ra11;
4578
4579 f_init_pcu_test();
4580 f_init_l1ctl();
4581 f_l1_tune(L1CTL);
4582
4583 for (var integer i := 0; i < 1000; i := i+1) {
4584 /* We need to test both TS1 & TS2 */
4585 if (i rem 2 == 0) {
4586 synch_seq := RACH_SYNCH_SEQ_TS1;
4587 pcu_bt := BURST_TYPE_1;
4588 } else {
4589 synch_seq := RACH_SYNCH_SEQ_TS2;
4590 pcu_bt := BURST_TYPE_2;
4591 }
4592
4593 ra11 := f_rnd_ra11_ps();
4594 fn := f_L1CTL_EXT_RACH(L1CTL, bit2int(ra11), synch_seq);
4595 if (fn == fn_last) {
4596 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
4597 "Two RACH in same FN?!?");
4598 }
4599 fn_last := fn;
4600
4601 /* Compose the expected message */
4602 pcu_rach_ind := tr_PCUIF_RACH_IND(
Vadim Yanitskiy36558d92019-11-17 02:23:51 +07004603 bts_nr := 0, trx_nr := 0, ts_nr := 0,
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +07004604 ra := bit2int(ra11),
4605 is_11bit := 1,
4606 burst_type := pcu_bt,
4607 fn := fn);
4608
4609 timer T := 2.0;
4610 T.start;
4611 alt {
4612 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, pcu_rach_ind)) {
4613 T.stop;
4614 }
4615 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RACH_IND)) {
4616 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RACH IND");
4617 }
4618 [] PCU.receive { repeat; }
4619 [] T.timeout {
4620 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for RACH IND");
4621 }
4622 }
4623 }
4624 setverdict(pass);
4625}
4626
Vadim Yanitskiya2c68e82019-07-03 13:07:20 +07004627private function f_TC_pcu_data_ind_lqual_cb(int16_t lqual_cb_exp, int16_t thresh)
4628runs on test_CT {
4629 var template PCUIF_send_data sdt;
4630 var PCUIF_send_data sd;
4631 var int16_t lqual_cb;
4632 timer T := 1.0;
4633
4634 /* PCUIF_DATA.ind is encapsulated into a supplementary record */
4635 sdt := t_SD_PCUIF_MSGT(g_pcu_conn_id, PCU_IF_MSG_DATA_IND);
4636
4637 /* Send a random PDTCH frame over Um */
4638 L1CTL.send(ts_L1CTL_TRAFFIC_REQ(ts_RslChanNr_PDCH(7), ts_RslLinkID_DCCH(0),
4639 '0000'O & f_rnd_octstring(21)));
4640
4641 T.start;
4642 alt {
4643 /* If expected link quality is above the threshold */
4644 [lqual_cb_exp >= thresh] PCU.receive(sdt) -> value sd {
4645 lqual_cb := sd.data.u.data_ind.lqual_cb;
4646 log("Rx PCUIF_DATA.ind (lqual_cb=", lqual_cb, ")");
4647
4648 /* Make sure the actual link quality matches the expected value */
4649 if (not match(lqual_cb, lqual_cb_exp)) {
4650 setverdict(fail, log2str("Link quality ", lqual_cb, " does not match ",
4651 "expected value ", lqual_cb_exp));
4652 } else {
4653 setverdict(pass);
4654 }
4655 }
4656 /* If expected link quality is below the threshold */
4657 [lqual_cb_exp < thresh] PCU.receive(sdt) -> value sd {
4658 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
4659 log2str("Rx unexpected PCUIF_DATA.ind: ", sd.data));
4660 }
4661 /* Ignore PCUIF_RTS.req and PCUIF_TIME.ind */
4662 [] PCU.receive { repeat; }
4663 [lqual_cb_exp < thresh] T.timeout {
4664 log("Rx nothing, as expected");
4665 setverdict(pass);
4666 }
4667 [lqual_cb_exp >= thresh] T.timeout {
4668 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
4669 "Timeout waiting for PCUIF_DATA.ind");
4670 }
4671 }
4672}
4673
4674/* Verify C/I (Carrier-to-Interference ratio) processing of PDTCH frames */
4675testcase TC_pcu_data_ind_lqual_cb() runs on test_CT {
4676 f_init_pcu_test();
4677 PCU.clear;
4678
4679 f_init_l1ctl();
4680 f_l1_tune(L1CTL);
4681
4682 /* Activate a PDCH channel on TS7 */
4683 f_TC_pcu_act_req(0, 0, 7, true);
4684
4685 /* Tune trxcon to that PDCH channel on TS7 */
Vadim Yanitskiy5afe8852020-05-27 14:40:51 +07004686 L1CTL.send(ts_L1CTL_DM_EST_REQ_H0(ts_RslChanNr_PDCH(7), 7, mp_trx0_arfcn));
Vadim Yanitskiya2c68e82019-07-03 13:07:20 +07004687
4688 /* C/I in centiBels, test range: -256 .. +1280, step 128 */
4689 for (var int16_t i := -256; i <= 1280; i := i + 128) {
4690 var TrxcMessage ret;
4691
4692 ret := f_TRXC_transceive(BTS_TRXC, g_bts_trxc_conn_id,
4693 valueof(ts_TRXC_FAKE_CI(i)));
4694
4695 /* FIXME: OsmoBTS may have different threshold (see MIN_QUAL_NORM) */
4696 f_TC_pcu_data_ind_lqual_cb(i, thresh := 0);
4697 }
4698}
4699
Harald Welte883340c2018-02-28 18:59:29 +01004700/* Send PAGING via RSL, expect it to shw up on PCU socket */
4701testcase TC_pcu_paging_from_rsl() runs on test_CT {
Max2c6f5632019-03-18 17:25:17 +01004702 f_init_pcu_test();
Harald Welte883340c2018-02-28 18:59:29 +01004703
4704 for (var integer i := 0; i < 100; i := i+1) {
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07004705 var MobileIdentityLV mi_lv;
4706 var octetstring mi_lv_enc;
4707 var MobileIdentityV mi;
Harald Welte883340c2018-02-28 18:59:29 +01004708 timer T := 3.0;
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07004709
Harald Welte883340c2018-02-28 18:59:29 +01004710 if (i < 50) {
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07004711 mi := valueof(t_MI_TMSI(f_rnd_octstring(4)));
Harald Welte883340c2018-02-28 18:59:29 +01004712 } else {
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07004713 mi := valueof(ts_MI_IMSI(f_gen_imsi(i)));
Harald Welte883340c2018-02-28 18:59:29 +01004714 }
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07004715
4716 /* Fancy encoding for PCUIF */
4717 mi_lv := valueof(ts_MI_LV(mi));
4718 mi_lv_enc := enc_MobileIdentityLV(mi_lv);
4719 mi_lv_enc := f_pad_oct(mi_lv_enc, 9, '00'O);
Harald Welte883340c2018-02-28 18:59:29 +01004720
4721 /* Send RSL PAGING COMMAND */
Vadim Yanitskiy493abe72020-05-25 22:03:48 +07004722 RSL_CCHAN.send(ts_ASP_RSL_UD(ts_RSL_PAGING_CMD(mi, i mod 4)));
Harald Welte883340c2018-02-28 18:59:29 +01004723 T.start;
4724 alt {
Vadim Yanitskiycc4623d2020-03-28 06:14:06 +07004725 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ(0, mi_lv_enc))) {
Harald Welte883340c2018-02-28 18:59:29 +01004726 }
4727 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_PAG_REQ)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004728 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PAGING REQ");
Harald Welte883340c2018-02-28 18:59:29 +01004729 }
4730 [] PCU.receive { repeat; }
4731 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02004732 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for PAGING REQ");
Harald Welte883340c2018-02-28 18:59:29 +01004733 }
4734 }
4735 }
4736 setverdict(pass);
4737}
4738
Harald Welted66c9b82019-05-25 09:03:15 +02004739/* test for periodic TIME_IND; check number of FN expired and number of TIME_IND within frames */
4740testcase TC_pcu_time_ind() runs on test_CT {
4741 var PCUIF_send_data pcu_sd;
4742 var integer num_time_ind := 0;
4743 var integer first_fn, last_fn;
4744 var float test_duration := 5.0;
4745 timer T;
4746
4747 f_init_pcu_test();
4748 f_TC_pcu_act_req(0, 0, 7, true);
4749
4750 PCU.clear;
4751 T.start(test_duration);
4752 alt {
4753 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_TIME_IND(0, ?))) -> value pcu_sd {
4754 num_time_ind := num_time_ind + 1;
4755 if (not isbound(first_fn)) {
4756 first_fn := pcu_sd.data.u.time_ind.fn;
4757 }
4758 last_fn := pcu_sd.data.u.time_ind.fn;
4759 repeat;
4760 }
4761 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_TIME_IND(?, ?))) -> value pcu_sd {
4762 setverdict(fail, "Received unexpected PCUIF_TIME_IND: ", pcu_sd.data);
4763 repeat;
4764 }
4765 [] PCU.receive {
4766 repeat;
4767 }
4768 [] T.timeout {}
4769 }
4770 var integer fn_expired := last_fn - first_fn;
4771 log(fn_expired, " fn expired with ", num_time_ind, " PCU_TIME.ind");
4772
4773 /* verify the number of frames expired matches our expectation */
4774 const float c_GSM_FN_DURATION_MS := 4.61538;
4775 var float fn_expected := test_duration * 1000.0 / c_GSM_FN_DURATION_MS;
Harald Weltec761c542019-05-28 11:59:57 +02004776 var template integer t_fn_expected := f_tolerance(float2int(fn_expected), 1, 100000, 20);
Harald Welted66c9b82019-05-25 09:03:15 +02004777 if (not match(fn_expired, t_fn_expected)) {
4778 setverdict(fail, "Number of TDMA Frames (", fn_expired, ") not matching ", t_fn_expected);
4779 }
4780
4781 /* There are three TIME.ind in every fn MOD 13 */
4782 var float time_ind_expected := int2float(fn_expired) * 3.0 / 13.0;
4783 /* Add some tolerance */
4784 var template integer t_time_ind_exp := f_tolerance(float2int(time_ind_expected), 1, 100000, 5);
4785 if (not match(num_time_ind, t_time_ind_exp)) {
4786 setverdict(fail, "Number of TIME.ind (", num_time_ind, ") not matching ", t_time_ind_exp);
4787 }
4788
4789 setverdict(pass);
4790}
4791
Harald Welte4832c862019-05-25 14:57:18 +02004792/* test for periodic RTS_REQ; check number of FN expired and number of RTS_IND per SAPI */
4793testcase TC_pcu_rts_req() runs on test_CT {
4794 var PCUIF_send_data pcu_sd;
4795 var integer first_fn, last_fn;
4796 var integer num_rts_pdtch := 0;
4797 var integer num_rts_ptcch := 0;
4798 var float test_duration := 5.0;
4799 timer T;
4800
4801 f_init_pcu_test();
4802 f_TC_pcu_act_req(0, 0, 7, true);
4803
4804 PCU.clear;
4805 T.start(test_duration);
4806 alt {
4807 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(0, 0, 7, PCU_IF_SAPI_PDTCH, ?, ?)))
4808 -> value pcu_sd {
4809 num_rts_pdtch := num_rts_pdtch + 1;
4810 if (not isbound(first_fn)) {
4811 first_fn := pcu_sd.data.u.rts_req.fn;
4812 }
4813 last_fn := pcu_sd.data.u.rts_req.fn;
4814 repeat;
4815 }
4816 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ(0, 0, 7, PCU_IF_SAPI_PTCCH, ?, ?)))
4817 -> value pcu_sd {
4818 num_rts_ptcch := num_rts_ptcch + 1;
4819 if (not isbound(first_fn)) {
4820 first_fn := pcu_sd.data.u.rts_req.fn;
4821 }
4822 last_fn := pcu_sd.data.u.rts_req.fn;
4823 repeat;
4824 }
4825 [] PCU.receive(t_SD_PCUIF(g_pcu_conn_id, tr_PCUIF_RTS_REQ)) -> value pcu_sd {
4826 setverdict(fail, "Received unexpected PCUIF_RTS_REQ: ", pcu_sd.data);
4827 repeat;
4828 }
4829 [] PCU.receive {
4830 repeat;
4831 }
4832 [] T.timeout {}
4833 }
4834 var integer fn_expired := last_fn - first_fn;
4835 log(fn_expired, " fn expired with num_rts_pdtch=", num_rts_pdtch,
4836 ", num_rts_ptcch=", num_rts_ptcch);
4837
4838 /* verify the number of frames expired matches our expectation */
4839 const float c_GSM_FN_DURATION_MS := 4.61538;
4840 var float fn_expected := test_duration * 1000.0 / c_GSM_FN_DURATION_MS;
Harald Weltec761c542019-05-28 11:59:57 +02004841 var template integer t_fn_expected := f_tolerance(float2int(fn_expected), 1, 100000, 20);
Harald Welte4832c862019-05-25 14:57:18 +02004842 if (not match(fn_expired, t_fn_expected)) {
4843 setverdict(fail, "Number of TDMA Frames (", fn_expired, ") not matching ", t_fn_expected);
4844 }
4845
4846 /* PTCCH is in pos. 12 + 38 of 52-multiframe, but four slots/bursts required per block */
4847 var float ptcch_expected := int2float(fn_expired) / 52.0 * 0.5;
4848 var template integer t_ptcch_exp := f_tolerance(float2int(ptcch_expected), 1, 100000, 1);
4849 if (not match(num_rts_ptcch, t_ptcch_exp)) {
4850 setverdict(fail, "Number of RTS.ind for PTCCH (", num_rts_ptcch, ") not matching ",
4851 t_ptcch_exp);
4852 }
4853
4854 /* We have 12 PDTCH blocks every 52-multiframe */
4855 var float pdtch_expected := int2float(fn_expired) / 52.0 * 12.0;
4856 var template integer t_pdtch_exp := f_tolerance(float2int(pdtch_expected), 1, 100000, 2);
4857 if (not match(num_rts_pdtch, t_pdtch_exp)) {
4858 setverdict(fail, "Number of RTS.ind for PDTCH (", num_rts_pdtch, ") not matching ",
4859 t_pdtch_exp);
4860 }
4861
4862 setverdict(pass);
4863}
4864
Harald Welte07bd2d22019-05-25 11:03:30 +02004865/* test for generating Abis side OML ALERT from the PCU */
4866testcase TC_pcu_oml_alert() runs on test_CT {
4867 var PCUIF_send_data pcu_sd;
4868 var integer num_time_ind := 0;
4869 var integer first_fn, last_fn;
4870 var float test_duration := 5.0;
4871 timer T;
4872
4873 f_init_pcu_test();
4874 f_TC_pcu_act_req(0, 0, 7, true);
4875
4876 /* re-connect CTRL port from BTS to BSC */
4877 f_ipa_ctrl_stop();
4878 f_ipa_ctrl_start(mp_bsc_ctrl_ip, mp_bsc_ctrl_port);
4879
4880 /* Send that OML Alert */
4881 PCU.send(t_SD_PCUIF(g_pcu_conn_id, ts_PCUIF_TXT_IND(0, PCU_OML_ALERT, testcasename())));
4882
4883 /* This requires https://gerrit.osmocom.org/#/c/osmo-bsc/+/14177 to be merged */
4884 f_ctrl_exp_trap(IPA_CTRL, "bts.0.oml_failure_report", ?);
4885 setverdict(pass);
4886}
4887
Harald Welteeaa9a862019-05-26 23:01:08 +02004888template (value) PDU_ML3_MS_NW ts_RRM_GprsSuspReq(template (value) OCT4 tlli,
4889 template (value) RoutingAreaIdentificationV rai,
4890 template (value) OCT1 cause) := {
4891 discriminator := '0000'B, /* overwritten */
4892 tiOrSkip := {
4893 skipIndicator := '0000'B
4894 },
4895 msgs := {
4896 rrm := {
4897 gPRS_suspensionRequest := {
4898 messageType := '00110100'B,
4899 tLLI := tlli,
4900 routingAreaIdentification := rai,
4901 suspensionCause := cause,
4902 service_Support := omit
4903 }
4904 }
4905 }
4906}
4907
4908/* test for forwarding of RR SUSPEND from CS lchan to PCU via PCU socket */
4909private function f_TC_rr_suspend_req(charstring id) runs on ConnHdlr {
4910 var PCUIF_Message first_info;
4911 var integer pcu_conn_id := -1;
4912 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
4913 var RoutingAreaIdentificationV rai := f_RAI('262'H, '42F'H, '2342'O, '55'O);
4914 var OCT4 tlli := '01020304'O;
4915 var OCT1 cause := '23'O;
4916 timer T := 5.0;
4917
4918 f_init_pcu(PCU, id, pcu_conn_id, first_info);
4919
4920 f_l1_tune(L1CTL);
4921 RSL.clear;
4922
4923 f_est_dchan();
4924 L1CTL.clear;
4925
4926 f_est_rll_mo(link_id.sapi, link_id, '23420815'O);
4927
4928 var PDU_ML3_MS_NW susp_req := valueof(ts_RRM_GprsSuspReq(tlli, rai, cause));
4929 var octetstring l3 := enc_PDU_ML3_MS_NW(susp_req);
4930 f_tx_lapdm(ts_LAPDm_I(link_id.sapi, cr_MO_CMD, true, 1, 0, l3), link_id);
4931
4932 /* ConnHdlr has terminated after sending the RR SUSP REQ over a dedicaed channel */
4933 T.start;
4934 alt {
4935 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_SUSP_REQ(0, tlli, ?, oct2int(cause)))) {
4936 setverdict(pass);
4937 }
4938 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_SUSP_REQ(?, ?, ?, ?))) {
4939 setverdict(fail, "Received unexpected PCUIF SUSPE REQ: ");
4940 }
4941 [] PCU.receive {
4942 repeat;
4943 }
4944 [] T.timeout {
4945 setverdict(fail, "Timeout waiting for SUSP REQ on PCUIF");
4946 }
4947 }
Alexander Couzensa0634832019-06-07 00:28:56 +02004948
4949 /* release the channel */
4950 f_rsl_chan_deact();
4951 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
4952 f_rslem_unregister(0, g_chan_nr);
Harald Welteeaa9a862019-05-26 23:01:08 +02004953}
4954testcase TC_pcu_rr_suspend() runs on test_CT {
4955 var ConnHdlrPars pars;
4956 var ConnHdlr vc_conn;
4957
4958 f_init();
4959
4960 pars := valueof(t_Pars(t_RslChanNr_SDCCH4(0,3), ts_RSL_ChanMode_SIGN));
4961 vc_conn := f_start_handler(refers(f_TC_rr_suspend_req), pars, true);
4962 vc_conn.done;
4963}
Harald Welte07bd2d22019-05-25 11:03:30 +02004964
Harald Weltea2e0e942019-05-27 18:12:53 +02004965/* Ensure that PCUIF socket can accept only a single connection */
4966testcase TC_pcu_socket_connect_multi() runs on test_CT {
4967 timer T := 5.0;
4968
4969 /* this (among other things) establishes the first connection to the PCUIF socket */
4970 f_init();
4971
4972 /* try to establish a second connection, expect it to fail */
4973 PCU.send(UD_connect:{mp_pcu_socket, -1});
4974 T.start;
4975 alt {
4976 [] PCU.receive(UD_connect_result:{id := ?, result := { result_code := ERROR, err := ? }}) {
4977 setverdict(pass);
4978 }
4979 [] PCU.receive(UD_connect_result:?) {
4980 setverdict(fail, "Unexpected unix domain connect result");
4981 }
4982 [] T.timeout {
4983 setverdict(pass);
4984 }
4985 }
4986 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
4987}
4988
Harald Weltec8effb72019-05-27 18:23:04 +02004989/* Ensure that PCUIF socket can disconnect + reconnect */
4990testcase TC_pcu_socket_reconnect() runs on test_CT {
4991 /* this (among other things) establishes the first connection to the PCUIF socket */
4992 f_init();
4993
4994 f_sleep(1.0);
4995
4996 f_pcuif_close(PCU, g_pcu_conn_id);
4997 g_pcu_conn_id := -1;
4998
4999 f_sleep(1.0);
5000
5001 /* re-connect */
5002 PCU.clear;
5003 f_init_pcu(PCU, testcasename(), g_pcu_conn_id, g_pcu_last_info);
5004 setverdict(pass);
5005
5006 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
5007}
5008
Harald Weltebe030482019-05-27 22:29:35 +02005009/* Ensure that GPRS capability is not advertised before PCU socket conncet */
Vadim Yanitskiy3c185382020-05-04 14:55:02 +07005010private function f_get_si(L1CTL_PT pt, RrMessageType si_type)
5011runs on test_CT return SystemInformation {
Harald Weltebe030482019-05-27 22:29:35 +02005012 var L1ctlDlMessage l1_dl;
5013 var SystemInformation si;
5014 timer T := 5.0;
5015 T.start;
5016 alt {
5017 [] pt.receive(tr_L1CTL_DATA_IND(t_RslChanNr_BCCH(0), ?)) -> value l1_dl {
5018 /* somehow dec_SystemInformation will try to decode even non-RR as SI */
5019 if (not (l1_dl.payload.data_ind.payload[1] == '06'O)) {
5020 log("Ignoring non-RR SI ", l1_dl);
5021 repeat;
5022 }
5023 si := dec_SystemInformation(l1_dl.payload.data_ind.payload)
Vadim Yanitskiy3c185382020-05-04 14:55:02 +07005024 if (si.header.message_type != si_type) {
Harald Weltebe030482019-05-27 22:29:35 +02005025 repeat;
5026 }
5027 }
5028 [] pt.receive {
5029 repeat;
5030 }
5031 [] T.timeout {
Vadim Yanitskiy3c185382020-05-04 14:55:02 +07005032 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
5033 log2str("Timeout waiting for ", si_type));
Harald Weltebe030482019-05-27 22:29:35 +02005034 }
5035 }
Vadim Yanitskiy3c185382020-05-04 14:55:02 +07005036 return si;
Harald Weltebe030482019-05-27 22:29:35 +02005037}
5038
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005039/* Check if GPRS Indicator is present in RR System Information of a given type */
5040private function f_si_has_gprs_indicator(RrMessageType si_type)
5041runs on test_CT return boolean {
5042 var SystemInformation si := f_get_si(L1CTL, si_type);
5043
5044 if (si_type == SYSTEM_INFORMATION_TYPE_3) {
5045 var RestOctets ro := si.payload.si3.rest_octets;
5046 var SI3RestOctets rest := dec_SI3RestOctets(ro);
5047 return rest.gprs_ind.presence == '1'B;
5048 } else if (si_type == SYSTEM_INFORMATION_TYPE_4) {
5049 var RestOctets ro := si.payload.si4.rest_octets;
5050 var SI4RestOctets rest := dec_SI4RestOctets(ro);
5051 return rest.gprs_ind.presence == '1'B;
5052 }
5053
5054 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unhandled SI type");
5055 return false;
Harald Weltebe030482019-05-27 22:29:35 +02005056}
5057
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005058/* Make sure that GPRS Indicator is absent when the PCU is not connected */
5059private function f_TC_pcu_socket_noconnect(RrMessageType si_type)
5060runs on test_CT {
Harald Weltebe030482019-05-27 22:29:35 +02005061 /* don't call f_init() as this would connect PCU socket */
5062 f_init_rsl(testcasename());
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005063
5064 /* Send both System Information Type 3 and 4 (with GPRS Indicator) */
Harald Weltebe030482019-05-27 22:29:35 +02005065 f_rsl_bcch_fill(RSL_SYSTEM_INFO_3, ts_SI3_default);
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005066 f_rsl_bcch_fill(RSL_SYSTEM_INFO_4, ts_SI4_default);
Harald Weltebe030482019-05-27 22:29:35 +02005067
5068 f_init_l1ctl();
5069 f_l1_tune(L1CTL);
Harald Weltebe030482019-05-27 22:29:35 +02005070 f_sleep(2.0);
5071 L1CTL.clear;
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005072
5073 if (f_si_has_gprs_indicator(si_type)) {
5074 setverdict(fail, si_type, " indicates GPRS even before PCU socket connected");
Harald Weltebe030482019-05-27 22:29:35 +02005075 } else {
5076 setverdict(pass);
5077 }
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005078
Harald Weltebe030482019-05-27 22:29:35 +02005079 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
5080}
5081
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005082testcase TC_pcu_socket_noconnect_nosi3gprs() runs on test_CT {
5083 f_TC_pcu_socket_noconnect(SYSTEM_INFORMATION_TYPE_3);
5084}
Harald Weltebe030482019-05-27 22:29:35 +02005085
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005086testcase TC_pcu_socket_noconnect_nosi4gprs() runs on test_CT {
5087 f_TC_pcu_socket_noconnect(SYSTEM_INFORMATION_TYPE_4);
5088}
5089
5090/* Ensure that GPRS capability is advertised after PCU socket connect */
5091private function f_TC_pcu_socket_connect(RrMessageType si_type)
5092runs on test_CT {
Harald Weltebe030482019-05-27 22:29:35 +02005093 /* this (among other things) establishes the first connection to the PCUIF socket */
5094 f_init();
5095 f_init_l1ctl();
5096 f_l1_tune(L1CTL);
5097
5098 f_sleep(2.0);
5099 L1CTL.clear;
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005100
5101 if (not f_si_has_gprs_indicator(si_type)) {
5102 setverdict(fail, si_type, " indicates no GPRS despite PCU socket connected");
Harald Weltebe030482019-05-27 22:29:35 +02005103 } else {
5104 setverdict(pass);
5105 }
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005106
Harald Weltebe030482019-05-27 22:29:35 +02005107 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
5108}
5109
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005110testcase TC_pcu_socket_connect_si3gprs() runs on test_CT {
5111 f_TC_pcu_socket_connect(SYSTEM_INFORMATION_TYPE_3);
5112}
Harald Weltebe030482019-05-27 22:29:35 +02005113
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005114testcase TC_pcu_socket_connect_si4gprs() runs on test_CT {
5115 f_TC_pcu_socket_connect(SYSTEM_INFORMATION_TYPE_4);
5116}
5117
5118/* Ensure that GPRS capability is no longer advertised after PCU socket disconnect */
5119private function f_TC_pcu_socket_disconnect(RrMessageType si_type)
5120runs on test_CT {
Harald Weltebe030482019-05-27 22:29:35 +02005121 /* this (among other things) establishes the first connection to the PCUIF socket */
5122 f_init();
5123 f_init_l1ctl();
5124 f_l1_tune(L1CTL);
5125
5126 f_pcuif_close(PCU, g_pcu_conn_id);
5127 g_pcu_conn_id := -1;
5128
5129 f_sleep(1.0);
5130
5131 /* re-connect */
5132 PCU.clear;
5133 f_init_pcu(PCU, testcasename(), g_pcu_conn_id, g_pcu_last_info);
5134
5135 f_sleep(2.0);
5136 L1CTL.clear;
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005137
5138 if (f_si_has_gprs_indicator(si_type)) {
5139 setverdict(fail, si_type, " indicates GPRS after PCU socket disconnected");
Harald Weltebe030482019-05-27 22:29:35 +02005140 } else {
5141 setverdict(pass);
5142 }
5143
5144 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
5145}
5146
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07005147testcase TC_pcu_socket_disconnect_nosi3gprs() runs on test_CT {
5148 f_TC_pcu_socket_disconnect(SYSTEM_INFORMATION_TYPE_3);
5149}
5150
5151testcase TC_pcu_socket_disconnect_nosi4gprs() runs on test_CT {
5152 f_TC_pcu_socket_disconnect(SYSTEM_INFORMATION_TYPE_4);
5153}
5154
Oliver Smithf5239c72019-08-28 10:01:25 +02005155/* Verify that the cell_id of SI3 (TS 04.08 9.1.35) and other values are passed properly to the PCU socket (OS#3854) */
5156testcase TC_pcu_socket_verify_info_ind() runs on test_CT {
5157 var SystemInformation si3 := valueof(ts_SI3_default);
5158
5159 f_init();
5160
5161 /* Verify cell_id */
5162 var uint16_t cell_id_si3 := si3.payload.si3.cell_id;
5163 var uint16_t cell_id_pcu := g_pcu_last_info.u.info_ind.cell_id;
5164 if (cell_id_si3 != cell_id_pcu) {
Oliver Smithe1c00f02019-09-04 11:35:56 +02005165 setverdict(fail, "Expected cell_id '", cell_id_si3, "' and got '", cell_id_pcu, "'. This either means,",
5166 " that the BTS is sending the wrong cell_id, or that the BTS sent it too early",
5167 " (OS#4179)");
Oliver Smithf5239c72019-08-28 10:01:25 +02005168 }
5169
5170 /* Verify LAC */
5171 var uint16_t lac_si3 := si3.payload.si3.lai.lac;
5172 var uint16_t lac_pcu := g_pcu_last_info.u.info_ind.lac;
5173 if (lac_si3 != lac_pcu) {
5174 setverdict(fail, "Expected LAC ", lac_si3, " got: ", lac_pcu);
5175 }
5176
5177 setverdict(pass);
5178}
Harald Welted66c9b82019-05-25 09:03:15 +02005179
Harald Welte3d04ae62018-04-04 20:29:05 +02005180/***********************************************************************
Harald Welte9bbbfb52018-04-05 09:33:19 +02005181 * Osmocom Style Dynamic Timeslot Support
Harald Welte3d04ae62018-04-04 20:29:05 +02005182 ***********************************************************************/
5183
5184private function f_dyn_osmo_pdch_act(integer pcu_conn_id, integer bts_nr, integer trx_nr)
5185runs on ConnHdlr {
5186 var PCUIF_send_data sd;
5187 /* Expect BTS to immediately acknowledge activation as PDCH */
5188 PCU.clear;
5189 f_rsl_chan_act(g_pars.chan_mode);
5190 /* expect INFO_IND on PCU interface listing TS as PDCH */
Pau Espin Pedrol202c2f72019-10-08 13:11:05 +02005191 timer T_wait := 2.0;
5192 T_wait.start;
Harald Welte3d04ae62018-04-04 20:29:05 +02005193 alt {
5194 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
5195 if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '1'B) {
Pau Espin Pedrol202c2f72019-10-08 13:11:05 +02005196 log("PCUIF_INFO_IND PDCH_MASK not yet '1' after PDCH ACT on TS", g_chan_nr.tn,
5197 " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
5198 repeat;
Harald Welte3d04ae62018-04-04 20:29:05 +02005199 }
5200 }
5201 [] PCU.receive { repeat; }
Pau Espin Pedrol202c2f72019-10-08 13:11:05 +02005202 [] T_wait.timeout {
5203 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
5204 log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '1' on TS", g_chan_nr.tn));
5205 }
Harald Welte3d04ae62018-04-04 20:29:05 +02005206 }
5207 /* try to activate this PDCH from the PCU point of view */
5208 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
5209 /* FIXME: is there a response? */
5210}
5211
5212private function f_dyn_osmo_pdch_deact(integer pcu_conn_id, integer bts_nr, integer trx_nr)
5213runs on ConnHdlr {
5214 var PCUIF_send_data sd;
5215 /* Send RSL CHAN REL (deactivate) */
5216 PCU.clear;
5217 RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
5218 /* expect BTS to ask PCU to deactivate the channel */
Pau Espin Pedrol202c2f72019-10-08 13:11:05 +02005219 timer T_wait := 2.0;
5220 T_wait.start;
Harald Welte3d04ae62018-04-04 20:29:05 +02005221 alt {
5222 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
5223 if (substr(sd.data.u.info_ind.trx[trx_nr].pdch_mask, g_chan_nr.tn, 1) != '0'B) {
Pau Espin Pedrol202c2f72019-10-08 13:11:05 +02005224 log("PCUIF_INFO_IND PDCH_MASK not yet '0' after PDCH DEACT on TS", g_chan_nr.tn,
5225 " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
5226 repeat;
Harald Welte3d04ae62018-04-04 20:29:05 +02005227 }
5228 }
5229 [] PCU.receive { repeat; }
Pau Espin Pedrol202c2f72019-10-08 13:11:05 +02005230 [] T_wait.timeout {
5231 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
5232 log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '0' on TS", g_chan_nr.tn));
5233 }
Harald Welte3d04ae62018-04-04 20:29:05 +02005234 }
5235 /* Emulate PCU asking BTS to deactivate PDCH */
5236 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
5237 alt {
5238 [] RSL.receive(tr_RSL_RF_CHAN_REL_ACK(g_chan_nr)) {
5239 setverdict(pass);
5240 }
5241 [] RSL.receive { repeat; }
5242 }
5243}
5244
5245/* Activate Osmocom-style dynamic PDCH from BSC side */
5246function f_TC_dyn_osmo_pdch_act_deact(charstring id) runs on ConnHdlr {
5247 var PCUIF_Message first_info;
5248 var integer ts_nr := g_chan_nr.tn;
5249 var integer trx_nr := 0;
5250 var integer bts_nr := 0;
5251 var integer pcu_conn_id := -1;
5252
5253 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5254
5255 f_dyn_osmo_pdch_act(pcu_conn_id, bts_nr, trx_nr);
5256 f_sleep(3.0);
5257 f_dyn_osmo_pdch_deact(pcu_conn_id, bts_nr, trx_nr);
5258 setverdict(pass);
5259}
5260testcase TC_dyn_osmo_pdch_act_deact() runs on test_CT {
5261 var ConnHdlrPars pars;
5262 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005263 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02005264
5265 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
5266 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_act_deact), pars, true);
5267 vc_conn.done;
5268}
5269
5270/* send a RF CHAN REL for PDCH on an osmocom dynamci PDCH that's already inactive */
5271function f_TC_dyn_osmo_pdch_unsol_deact(charstring id) runs on ConnHdlr {
5272 var PCUIF_Message first_info;
Harald Welte3d04ae62018-04-04 20:29:05 +02005273 var integer pcu_conn_id := -1;
5274
5275 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5276
Neels Hofmeyr9c50ca52018-05-08 20:37:54 +02005277 RSL.send(ts_RSL_RF_CHAN_REL(g_chan_nr));
5278 /* since the lchan is already released, we don't expect any PCU changes, just a rel ack. */
5279 RSL.receive(tr_RSL_RF_CHAN_REL_ACK(g_chan_nr));
Harald Welte3d04ae62018-04-04 20:29:05 +02005280 setverdict(pass);
5281}
5282testcase TC_dyn_osmo_pdch_unsol_deact() runs on test_CT {
5283 var ConnHdlrPars pars;
5284 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005285 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02005286
5287 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
5288 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_unsol_deact), pars, true);
5289 vc_conn.done;
5290}
5291
5292/* try to RSL CHAN ACT a PDCH on an osmocom-style PDCH that's already active */
5293function f_TC_dyn_osmo_pdch_double_act(charstring id) runs on ConnHdlr {
5294 var PCUIF_Message first_info;
5295 var integer ts_nr := g_chan_nr.tn;
5296 var integer trx_nr := 0;
5297 var integer bts_nr := 0;
5298 var integer pcu_conn_id := -1;
5299
5300 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5301
5302 f_dyn_osmo_pdch_act(pcu_conn_id, bts_nr, trx_nr);
Neels Hofmeyrdf936a22018-05-08 22:07:57 +02005303 /* Send a second Chan Activ and expect it to be NACKed */
5304 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_NACK(g_chan_nr),
5305 "RSL CHAN ACT NACK");
Harald Welte3d04ae62018-04-04 20:29:05 +02005306 setverdict(pass);
5307}
5308testcase TC_dyn_osmo_pdch_double_act() runs on test_CT {
5309 var ConnHdlrPars pars;
5310 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005311 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02005312
5313 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
5314 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_double_act), pars, true);
5315 vc_conn.done;
5316}
5317
5318/* try to RSL CHAN ACT a TCH/F on an osmocom-style PDCH */
5319function f_TC_dyn_osmo_pdch_tchf_act(charstring id) runs on ConnHdlr {
5320 var PCUIF_Message first_info;
5321 var integer ts_nr := g_chan_nr.tn;
5322 var integer trx_nr := 0;
5323 var integer bts_nr := 0;
5324 var integer pcu_conn_id := -1;
5325 var RslChannelNr chan_nr := valueof(t_RslChanNr_Bm(g_chan_nr.tn));
5326
5327 /* register for the TCH/F channel number */
5328 f_rslem_register(0, chan_nr);
5329
5330 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5331
5332 f_rsl_transceive(ts_RSL_CHAN_ACT(chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_ACK(chan_nr),
5333 "RSL CHAN ACT");
5334 setverdict(pass);
5335}
5336testcase TC_dyn_osmo_pdch_tchf_act() runs on test_CT {
5337 var ConnHdlrPars pars;
5338 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005339 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02005340
5341 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
5342 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_tchf_act), pars, true);
5343 vc_conn.done;
5344}
5345
5346/* try to RSL CHAN ACT the TCH/H on an osmocom-style PDCH */
5347function f_TC_dyn_osmo_pdch_tchh_act(charstring id) runs on ConnHdlr {
5348 var PCUIF_Message first_info;
5349 var integer ts_nr := g_chan_nr.tn;
5350 var integer trx_nr := 0;
5351 var integer bts_nr := 0;
5352 var integer pcu_conn_id := -1;
5353 var RslChannelNr chan_nr[2] := { valueof(t_RslChanNr_Lm(g_chan_nr.tn, 0)),
5354 valueof(t_RslChanNr_Lm(g_chan_nr.tn, 1)) };
5355
5356 /* register for the TCH/H channel numbers */
5357 f_rslem_register(0, chan_nr[0]);
5358 f_rslem_register(0, chan_nr[1]);
5359
5360 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5361
5362 f_rsl_transceive(ts_RSL_CHAN_ACT(chan_nr[1], g_pars.chan_mode),
5363 tr_RSL_CHAN_ACT_ACK(chan_nr[1]), "RSL CHAN ACT [1]");
5364 f_rsl_transceive(ts_RSL_CHAN_ACT(chan_nr[0], g_pars.chan_mode),
5365 tr_RSL_CHAN_ACT_ACK(chan_nr[0]), "RSL CHAN ACT [0]");
5366 setverdict(pass);
5367}
5368testcase TC_dyn_osmo_pdch_tchh_act() runs on test_CT {
5369 var ConnHdlrPars pars;
5370 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005371 f_init();
Harald Welte3d04ae62018-04-04 20:29:05 +02005372
5373 pars := valueof(t_Pars(t_RslChanNr_PDCH(4), ts_RSL_ChanMode_SIGN));
5374 vc_conn := f_start_handler(refers(f_TC_dyn_osmo_pdch_tchh_act), pars, true);
5375 vc_conn.done;
5376}
5377
Harald Welte9bbbfb52018-04-05 09:33:19 +02005378/***********************************************************************
5379 * IPA Style Dynamic Timeslot Support
5380 ***********************************************************************/
5381
5382private function f_dyn_ipa_pdch_act(integer pcu_conn_id, integer bts_nr, integer trx_nr)
5383runs on ConnHdlr {
5384 var PCUIF_send_data sd;
5385 /* Expect BTS to immediately acknowledge activation as PDCH */
5386 PCU.clear;
5387 RSL.send(ts_RSL_IPA_PDCH_ACT(g_chan_nr));
5388 /* expect INFO_IND on PCU interface listing TS as PDCH */
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01005389 timer T_wait := 2.0;
5390 T_wait.start;
Harald Welte9bbbfb52018-04-05 09:33:19 +02005391 alt {
5392 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
5393 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 +01005394 log("PCUIF_INFO_IND PDCH_MASK not yet '1' after PDCH ACT on TS", g_chan_nr.tn,
5395 " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
5396 repeat;
Harald Welte9bbbfb52018-04-05 09:33:19 +02005397 }
5398 }
5399 [] PCU.receive { repeat; }
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01005400 [] T_wait.timeout {
5401 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
5402 log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '1' on TS", g_chan_nr.tn));
5403 }
Harald Welte9bbbfb52018-04-05 09:33:19 +02005404 }
5405 /* try to activate this PDCH from the PCU point of view */
5406 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_ACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
5407 /* FIXME: is there a response? */
5408
5409 RSL.receive(tr_RSL_IPA_PDCH_ACT_ACK(g_chan_nr, ?));
5410}
5411
5412private function f_dyn_ipa_pdch_deact(integer pcu_conn_id, integer bts_nr, integer trx_nr)
5413runs on ConnHdlr {
5414 var PCUIF_send_data sd;
5415 /* Send RSL CHAN REL (deactivate) */
5416 RSL.send(ts_RSL_IPA_PDCH_DEACT(g_chan_nr));
5417 PCU.clear;
5418 /* expect BTS to ask PCU to deactivate the channel */
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01005419 timer T_wait := 2.0;
5420 T_wait.start;
Harald Welte9bbbfb52018-04-05 09:33:19 +02005421 alt {
5422 [] PCU.receive(t_SD_PCUIF(pcu_conn_id, tr_PCUIF_INFO_IND(bts_nr, ?))) -> value sd {
5423 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 +01005424 log("PCUIF_INFO_IND PDCH_MASK not yet '0' after PDCH DEACT on TS", g_chan_nr.tn,
5425 " mask:", sd.data.u.info_ind.trx[trx_nr].pdch_mask);
5426 repeat;
Harald Welte9bbbfb52018-04-05 09:33:19 +02005427 }
5428 }
5429 [] PCU.receive { repeat; }
Pau Espin Pedrol446e07b2019-02-18 21:18:36 +01005430 [] T_wait.timeout {
5431 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
5432 log2str("Timeout waiting for PCUIF_INFO_IND PDCH_MASK to be '0' on TS", g_chan_nr.tn));
5433 }
Harald Welte9bbbfb52018-04-05 09:33:19 +02005434 }
5435 /* Emulate PCU asking BTS to deactivate PDCH */
5436 PCU.send(t_SD_PCUIF(pcu_conn_id, ts_PCUIF_DEACT_REQ(bts_nr, trx_nr, g_chan_nr.tn)));
5437 alt {
5438 [] RSL.receive(tr_RSL_IPA_PDCH_DEACT_ACK(g_chan_nr)) {
5439 setverdict(pass);
5440 }
5441 [] RSL.receive { repeat; }
5442 }
5443}
5444
5445/* Activate and de-activate an IPA-style dynamic TCH/F + PDCH */
5446function f_TC_dyn_ipa_pdch_act_deact(charstring id) runs on ConnHdlr {
5447 var PCUIF_Message first_info;
5448 var integer ts_nr := g_chan_nr.tn;
5449 var integer trx_nr := 0;
5450 var integer bts_nr := 0;
5451 var integer pcu_conn_id := -1;
5452
5453 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5454
5455 f_dyn_ipa_pdch_act(pcu_conn_id, bts_nr, trx_nr);
5456 f_sleep(3.0);
5457 f_dyn_ipa_pdch_deact(pcu_conn_id, bts_nr, trx_nr);
5458
5459 setverdict(pass);
5460
5461}
5462testcase TC_dyn_ipa_pdch_act_deact() runs on test_CT {
5463 var ConnHdlrPars pars;
5464 var ConnHdlr vc_conn;
5465 f_init();
5466
5467 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
5468 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_act_deact), pars, true);
5469 vc_conn.done;
5470}
5471
5472/* try to RSL CHAN ACT a TCH/F on an IPA-style PDCH */
5473function f_TC_dyn_ipa_pdch_tchf_act(charstring id) runs on ConnHdlr {
5474 var PCUIF_Message first_info;
5475 var integer ts_nr := g_chan_nr.tn;
5476 var integer trx_nr := 0;
5477 var integer bts_nr := 0;
5478 var integer pcu_conn_id := -1;
5479
5480 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5481
5482 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_ACK(g_chan_nr),
5483 "RSL CHAN ACT");
5484 f_rsl_transceive(ts_RSL_RF_CHAN_REL(g_chan_nr), tr_RSL_RF_CHAN_REL_ACK(g_chan_nr),
5485 "RF CHAN REL", true);
5486 setverdict(pass);
5487}
5488testcase TC_dyn_ipa_pdch_tchf_act() runs on test_CT {
5489 var ConnHdlrPars pars;
5490 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005491 f_init();
Harald Welte9bbbfb52018-04-05 09:33:19 +02005492
5493 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
5494 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_tchf_act), pars, true);
5495 vc_conn.done;
5496}
5497
5498/* Activate IPA style dyn PDCH as TCH/F and then illegally try to activate it as PDCH, too */
5499function f_TC_dyn_ipa_pdch_tchf_act_pdch_act_nack(charstring id) runs on ConnHdlr {
5500 var PCUIF_Message first_info;
5501 var integer ts_nr := g_chan_nr.tn;
5502 var integer trx_nr := 0;
5503 var integer bts_nr := 0;
5504 var integer pcu_conn_id := -1;
5505
5506 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5507
5508 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_ACK(g_chan_nr),
5509 "RSL CHAN ACT");
5510
5511 RSL.send(ts_RSL_IPA_PDCH_ACT(g_chan_nr));
5512 alt {
5513 [] RSL.receive(tr_RSL_IPA_PDCH_ACT_NACK(g_chan_nr, ?));
5514 [] RSL.receive(tr_RSL_IPA_PDCH_ACT_ACK(g_chan_nr, ?)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005515 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected PDCH ACT ACK");
Harald Welte9bbbfb52018-04-05 09:33:19 +02005516 }
5517 [] RSL.receive { repeat; }
5518 }
5519
5520 f_rsl_transceive(ts_RSL_RF_CHAN_REL(g_chan_nr), tr_RSL_RF_CHAN_REL_ACK(g_chan_nr),
5521 "RF CHAN REL", true);
5522 setverdict(pass);
5523}
5524testcase TC_dyn_ipa_pdch_tchf_act_pdch_act_nack() runs on test_CT {
5525 var ConnHdlrPars pars;
5526 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005527 f_init();
Harald Welte9bbbfb52018-04-05 09:33:19 +02005528
5529 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
5530 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_tchf_act_pdch_act_nack), pars, true);
5531 vc_conn.done;
5532}
5533
5534/* try to RSL CHAN ACT a TCH/F on an IPA-style PDCH that's already in PDCH mode; expect NACK */
5535function f_TC_dyn_ipa_pdch_act_tchf_act_nack(charstring id) runs on ConnHdlr {
5536 var PCUIF_Message first_info;
5537 var integer ts_nr := g_chan_nr.tn;
5538 var integer trx_nr := 0;
5539 var integer bts_nr := 0;
5540 var integer pcu_conn_id := -1;
5541
5542 /* register for the TCH/F channel number */
5543 f_rslem_register(0, g_chan_nr);
5544
5545 f_init_pcu(PCU, id, pcu_conn_id, first_info);
5546
5547 f_dyn_ipa_pdch_act(pcu_conn_id, bts_nr, trx_nr);
5548
5549 f_rsl_transceive(ts_RSL_CHAN_ACT(g_chan_nr, g_pars.chan_mode), tr_RSL_CHAN_ACT_NACK(g_chan_nr),
5550 "RSL CHAN ACT");
5551
5552 f_dyn_ipa_pdch_deact(pcu_conn_id, bts_nr, trx_nr);
5553
5554 setverdict(pass);
5555}
5556testcase TC_dyn_ipa_pdch_act_tchf_act_nack() runs on test_CT {
5557 var ConnHdlrPars pars;
5558 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005559 f_init();
Harald Welte9bbbfb52018-04-05 09:33:19 +02005560
5561 pars := valueof(t_Pars(t_RslChanNr_Bm(3), ts_RSL_ChanMode_SIGN));
5562 vc_conn := f_start_handler(refers(f_TC_dyn_ipa_pdch_act_tchf_act_nack), pars, true);
5563 vc_conn.done;
5564}
5565
5566
Harald Welte0472ab42018-03-12 15:02:26 +01005567/***********************************************************************
5568 * LAPDm / RLL related
5569 ***********************************************************************/
5570
5571private function f_tx_lapdm(template (value) LapdmFrame l,
5572 template (value) RslLinkId link_id) runs on ConnHdlr {
5573 var octetstring l2 := enc_LapdmFrame(valueof(l));
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07005574 var template (value) SacchL1Header l1h;
5575
5576 /* TODO: we can use an extension of TTCN-3 for padding, i.e. PADDING('2B'O) */
Harald Welte0472ab42018-03-12 15:02:26 +01005577 if (valueof(link_id.c) == SACCH) {
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07005578 /* Compose dummy L1 header */
5579 l1h := ts_SacchL1Header(g_pars.l1_pars.ms_power_level, false, g_pars.l1_pars.ms_actual_ta);
5580 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 +02005581 } else {
5582 /* If required, pad L2 frame with constant 0x2b filling */
Vadim Yanitskiy0a8d6da2019-05-28 22:18:28 +07005583 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 +01005584 }
Harald Welte0472ab42018-03-12 15:02:26 +01005585}
5586
5587type record RllTestCase {
5588 uint3_t sapi,
5589 RslLinkId link_id,
5590 octetstring l3,
5591 boolean exp
5592}
5593type record of RllTestCase RllTestCases;
5594template RllTestCase t_EITC(uint3_t sapi, RslLinkId id, octetstring l3, boolean exp) := {
5595 sapi := sapi,
5596 link_id := id,
5597 l3 := l3,
5598 exp := exp
5599}
5600
5601/* execute the same callback function with a set of different parameters (tcs) on a
5602 * variety of logical channels */
5603private function f_rll_testmatrix(RllTestCases tcs, void_fn fn) runs on test_CT {
5604 var ConnHdlrPars pars;
5605 var ConnHdlr vc_conn;
Harald Welte10474062019-05-30 16:48:17 +02005606 f_init();
Harald Welte0472ab42018-03-12 15:02:26 +01005607
5608 /* test on each of the channels we have */
5609 for (var integer i := 0; i < sizeof(g_AllChanTypes); i := i+1) {
5610 pars := valueof(t_Pars(g_AllChanTypes[i], ts_RSL_ChanMode_SIGN));
5611
5612 /* test each of the test cases on the current channel */
5613 for (var integer j := 0; j < sizeof(tcs); j := j+1) {
5614 pars.spec.rll := tcs[j];
5615 log(testcasename(), ": XXX Starting ", tcs[j] , " on ", g_AllChanTypes[i]);
5616 vc_conn := f_start_handler(fn, pars);
5617 vc_conn.done;
5618 }
5619 }
5620
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005621 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
Harald Welte0472ab42018-03-12 15:02:26 +01005622}
5623
5624/* test if SABM on Um triggers EST IND (TS 48.058 3.1) */
5625private function f_TC_rll_est_ind(charstring id) runs on ConnHdlr {
5626 var RllTestCase tc := g_pars.spec.rll;
5627 timer T := 3.0;
5628
5629 f_l1_tune(L1CTL);
5630 RSL.clear;
5631
5632 /* activate the logical channel */
5633 f_est_dchan();
5634 L1CTL.clear;
5635
5636 f_tx_lapdm(ts_LAPDm_SABM(tc.sapi, cr_MO_CMD, true, tc.l3), tc.link_id);
5637 T.start;
5638 alt {
5639 [tc.l3 != ''O] RSL.receive(tr_RSL_EST_IND(g_chan_nr, tc.link_id, tc.l3)) {
5640 if (tc.exp) {
5641 setverdict(pass);
5642 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005643 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected EST IND with L3 in ", tc));
Harald Welte0472ab42018-03-12 15:02:26 +01005644 }
5645 }
5646 [tc.l3 == ''O] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, tc.link_id)) {
5647 if (tc.exp) {
5648 setverdict(pass);
5649 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005650 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected EST IND without L3 in ", tc));
Harald Welte0472ab42018-03-12 15:02:26 +01005651 }
5652 }
Vadim Yanitskiy35677872018-10-04 17:30:21 +07005653 /* We also expect to receive the measurements */
5654 [] as_meas_res(verify_meas := false);
Harald Welte0472ab42018-03-12 15:02:26 +01005655 [tc.exp] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005656 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for EST IND");
Harald Welte0472ab42018-03-12 15:02:26 +01005657 }
5658 [not tc.exp] T.timeout {
5659 setverdict(pass);
5660 }
5661 }
5662
5663 f_rsl_chan_deact();
5664 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5665 f_rslem_unregister(0, g_chan_nr);
5666}
5667testcase TC_rll_est_ind() runs on test_CT {
5668 var RllTestCases tcs := {
Harald Welte7aacbbf2018-05-09 16:56:41 +02005669 /* SAPI0 establishment (contention resolution) */
Harald Welte0472ab42018-03-12 15:02:26 +01005670 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), '01020304'O, true)),
Harald Welte7aacbbf2018-05-09 16:56:41 +02005671 /* normal SAPI0 establishment */
5672 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), ''O, true)),
Harald Welte0472ab42018-03-12 15:02:26 +01005673 /* SAPI 3 doesn't support contention resolution */
5674 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), '01020304'O, false)),
5675 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), '01020304'O, false)),
5676 /* normal SAPI3 establishment on main DCCH */
5677 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true)),
5678 /* normal SAPI3 establishment on SACCH */
5679 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
5680 };
5681 f_rll_testmatrix(tcs, refers(f_TC_rll_est_ind));
5682}
5683
5684/* test if RLL EST REQ trigeres SABM on Um; UA on Um triggers EST CONF (TS 48.058 3.2) */
5685private function f_TC_rll_est_req(charstring id) runs on ConnHdlr {
5686 var RllTestCase tc := g_pars.spec.rll;
5687 var L1ctlDlMessage dl;
5688 timer T := 3.0;
5689
5690 f_l1_tune(L1CTL);
5691 RSL.clear;
5692
5693 /* activate the logical channel */
5694 f_est_dchan();
5695 L1CTL.clear;
5696
5697 /* Send a RSL EST REQ for SAPI3 on main DCCH */
5698 RSL.send(ts_RSL_EST_REQ(g_chan_nr, tc.link_id));
5699 T.start;
5700 alt {
5701 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, ?)) -> value dl {
5702 var LapdmFrame lapdm;
5703 var octetstring l2 := dl.payload.data_ind.payload;
5704 if (dl.dl_info.link_id.c == SACCH) {
5705 /* remove L1 header */
5706 l2 := substr(l2, 2, lengthof(l2)-2);
5707 }
5708 lapdm.ab := dec_LapdmFrameAB(l2);
5709 if (match(lapdm, tr_LAPDm_SABM(tc.sapi, cr_MT_CMD, true, ''O))) {
5710 setverdict(pass);
5711 } else {
5712 repeat;
5713 }
5714 }
5715 [] L1CTL.receive { repeat; }
5716 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005717 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for SABM");
Harald Welte0472ab42018-03-12 15:02:26 +01005718 }
5719 }
5720
5721 f_rsl_chan_deact();
5722 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5723 f_rslem_unregister(0, g_chan_nr);
5724}
5725testcase TC_rll_est_req_DCCH_3() runs on test_CT {
5726 var RllTestCases tcs := {
5727 /* normal SAPI3 establishment on main DCCH */
5728 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true))//,
5729 };
5730 f_rll_testmatrix(tcs, refers(f_TC_rll_est_req));
5731}
5732testcase TC_rll_est_req_ACCH_3() runs on test_CT {
5733 var RllTestCases tcs := {
5734 /* normal SAPI3 establishment on SACCH */
5735 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
5736 }
5737 f_rll_testmatrix(tcs, refers(f_TC_rll_est_req));
5738}
5739
5740/* altstep to receive a LAPDm frame matching the given template */
5741private altstep as_l1_exp_lapdm(template LapdmFrame exp) runs on ConnHdlr {
5742 var L1ctlDlMessage dl;
5743 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, ?)) -> value dl {
5744 var LapdmFrame lapdm;
5745 var octetstring l2 := dl.payload.data_ind.payload;
5746 if (dl.dl_info.link_id.c == SACCH) {
5747 /* remove L1 header */
5748 l2 := substr(l2, 2, lengthof(l2)-2);
5749 }
5750 if (ischosen(exp.ab)) {
5751 lapdm.ab := dec_LapdmFrameAB(l2);
5752 } else if (ischosen(exp.b4)) {
5753 lapdm.b4 := dec_LapdmFrameB4(l2);
5754 } else if (ischosen(exp.bbis)) {
5755 lapdm.bbis := dec_LapdmFrameBbis(l2);
5756 }
5757 log("Rx LAPDm ", lapdm);
5758 if (match(lapdm, exp)) {
5759 setverdict(pass);
5760 } else {
5761 repeat;
5762 }
5763 }
5764 [] L1CTL.receive { repeat; }
5765}
5766private function f_l1_exp_lapdm(template LapdmFrame exp, float t := 3.0) runs on ConnHdlr {
5767 timer T := t;
5768 T.start;
5769 alt {
5770 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005771 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Timeout waiting for LAPDm ", exp));
Harald Welte0472ab42018-03-12 15:02:26 +01005772 }
5773 [] as_l1_exp_lapdm(exp);
5774 }
5775}
5776
5777/* establish one Radio Link Layer via SABM -> UA. Use l3 for contention resolution */
5778private function f_est_rll_mo(uint3_t sapi, RslLinkId link_id, octetstring l3) runs on ConnHdlr {
5779 /* send SABM from MS -> BTS */
5780 f_tx_lapdm(ts_LAPDm_SABM(sapi, cr_MO_CMD, true, l3), link_id);
5781 /* expect RLL EST IND on Abis */
5782 alt {
5783 [l3 != ''O] RSL.receive(tr_RSL_EST_IND(g_chan_nr, link_id, l3));
5784 [l3 == ''O] RSL.receive(tr_RSL_EST_IND_NOL3(g_chan_nr, link_id));
5785 [] RSL.receive(tr_RSL_ERROR_IND(g_chan_nr, link_id, ?)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005786 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Failing due to RSL_ERROR_IND");
Harald Welte0472ab42018-03-12 15:02:26 +01005787 }
5788 [] RSL.receive { repeat; }
5789 }
5790 /* expect UA from BTS -> MS */
5791 f_l1_exp_lapdm(tr_LAPDm_UA(sapi, cr_MT_RSP, true, l3));
5792}
5793
5794/* test if DISC on Um triggers RLL REL IND (TS 48.058 3.3) */
5795private function f_TC_rll_rel_ind(charstring id) runs on ConnHdlr {
5796 var RllTestCase tc := g_pars.spec.rll;
5797
5798 f_l1_tune(L1CTL);
5799 RSL.clear;
5800
5801 /* activate the logical channel */
5802 f_est_dchan();
5803 L1CTL.clear;
5804
5805 /* first establish the link-layer */
5806 f_est_rll_mo(tc.sapi, tc.link_id, tc.l3);
5807
5808 /* then send the DISC */
5809 f_tx_lapdm(ts_LAPDm_DISC(tc.sapi, cr_MO_CMD, true), tc.link_id);
5810 /* ... and expect the REL IND on the RSL side */
5811 alt {
5812 [] RSL.receive(tr_RSL_REL_IND(g_chan_nr, tc.link_id)) {
5813 setverdict(pass);
5814 }
Vadim Yanitskiy35677872018-10-04 17:30:21 +07005815 /* We also expect to receive the measurements */
5816 [] as_meas_res(verify_meas := false);
Harald Welte0472ab42018-03-12 15:02:26 +01005817 }
5818
5819 /* release the channel */
5820 f_rsl_chan_deact();
5821 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5822 f_rslem_unregister(0, g_chan_nr);
5823}
5824testcase TC_rll_rel_ind_DCCH_0() runs on test_CT {
5825 var RllTestCases tcs := {
5826 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), '01020304'O, true))
5827 };
5828 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
5829}
5830
5831testcase TC_rll_rel_ind_ACCH_0() runs on test_CT {
5832 var RllTestCases tcs := {
5833 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), ''O, true))
5834 };
5835 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
5836}
5837testcase TC_rll_rel_ind_DCCH_3() runs on test_CT {
5838 var RllTestCases tcs := {
5839 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true))
5840 };
5841 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
5842}
5843testcase TC_rll_rel_ind_ACCH_3() runs on test_CT {
5844 var RllTestCases tcs := {
5845 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
5846 };
5847 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_ind));
5848}
5849
5850/* test if RLL REL REQ triggers DISC on Um; UA/DM triggers RLL REL CONF (TS 48.058 3.4) */
5851private function f_TC_rll_rel_req(charstring id) runs on ConnHdlr {
5852 var RllTestCase tc := g_pars.spec.rll;
5853 f_l1_tune(L1CTL);
5854 RSL.clear;
5855
5856 /* activate the logical channel */
5857 f_est_dchan();
5858 L1CTL.clear;
5859
5860 /* first establish the link-layer */
5861 f_est_rll_mo(tc.sapi, tc.link_id, tc.l3);
5862
5863 /* then send the REL REQ via RSL */
5864 RSL.send(ts_RSL_REL_REQ(g_chan_nr, tc.link_id, RSL_REL_MODE_NORMAL));
5865 /* ... and expect the DISC on the Um side */
5866 alt {
Harald Weltebc6199f2018-05-10 19:38:18 +02005867 [] as_l1_exp_lapdm(tr_LAPDm_DISC(tc.sapi, cr_MT_CMD, true)) {
Harald Welte0472ab42018-03-12 15:02:26 +01005868 /* FIXME: send a UA in resposne to the DISC */
5869 }
5870 }
5871
5872 /* release the channel */
5873 f_rsl_chan_deact();
5874 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5875 f_rslem_unregister(0, g_chan_nr);
5876}
5877testcase TC_rll_rel_req() runs on test_CT {
5878 var RllTestCases tcs := {
5879 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), '01020304'O, true)),
5880 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), ''O, true)),
5881 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), ''O, true)),
5882 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), ''O, true))
5883 };
5884 f_rll_testmatrix(tcs, refers(f_TC_rll_rel_req));
5885}
5886
5887/* test if RLL DATA REQ triggers I-frames on Um (TS 48.058 3.5) */
5888testcase TC_rll_data_req() runs on test_CT {
5889}
5890
5891/* test if I-frames on Um trigger RLL DATA IND (TS 48.058 3.6) */
5892testcase TC_rll_data_ind() runs on test_CT {
5893}
5894
5895/* test if RLL UNIT DATA REQ triggers UI-frame on Um (TS 48.058 3.7) */
5896private function f_TC_rll_ud_req(charstring id) runs on ConnHdlr {
5897 var RllTestCase tc := g_pars.spec.rll;
5898
5899 f_l1_tune(L1CTL);
5900 RSL.clear;
5901
5902 f_est_dchan();
5903 L1CTL.clear;
5904
5905 /* Send UNITDATA REQ on RSL side */
5906 RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, tc.link_id, tc.l3));
5907 /* Expect it to arrive on the other side */
5908 if (tc.link_id.c == SACCH) {
Harald Weltee613f962018-04-18 22:38:16 +02005909 f_l1_exp_lapdm(tr_LAPDm_B4_UI(tc.sapi, cr_MT_CMD, tc.l3));
Harald Welte0472ab42018-03-12 15:02:26 +01005910 } else {
Harald Weltee613f962018-04-18 22:38:16 +02005911 f_l1_exp_lapdm(tr_LAPDm_UI(tc.sapi, cr_MT_CMD, tc.l3));
Harald Welte0472ab42018-03-12 15:02:26 +01005912 }
5913
5914 /* release the channel */
5915 f_rsl_chan_deact();
5916 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5917 f_rslem_unregister(0, g_chan_nr);
5918}
5919testcase TC_rll_unit_data_req_DCCH() runs on test_CT {
5920 var octetstring l3 := f_rnd_octstring(15);
5921 var RllTestCases tcs := {
5922 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), l3, true)),
5923 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), l3, true))
5924 };
5925 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_req));
5926}
5927testcase TC_rll_unit_data_req_ACCH() runs on test_CT {
5928 var octetstring l3 := f_rnd_octstring(19);
5929 var RllTestCases tcs := {
5930 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), l3, true)),
5931 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), l3, true))
5932 };
5933 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_req));
5934}
5935
5936/* test if UI-frames on Um trigger RLL UNIT DATA IND (TS 48.058 3.8) */
5937private function f_TC_rll_ud_ind(charstring id) runs on ConnHdlr {
5938 var RllTestCase tc := g_pars.spec.rll;
5939
5940 f_l1_tune(L1CTL);
5941 RSL.clear;
5942
5943 f_est_dchan();
5944 L1CTL.clear;
5945
5946 /* Send LAPDm UI frame. There is no B4 format in uplink! */
Harald Weltee613f962018-04-18 22:38:16 +02005947 f_tx_lapdm(ts_LAPDm_UI(tc.sapi, cr_MO_CMD, tc.l3), tc.link_id);
Harald Welte0472ab42018-03-12 15:02:26 +01005948 /* Expdct RLL UNITDATA IND on RSL side */
5949 alt {
5950 [] RSL.receive(tr_RSL_UNITDATA_IND(g_chan_nr, tc.link_id, tc.l3)) {
5951 setverdict(pass);
5952 }
5953 [] RSL.receive { repeat; }
5954 }
5955
5956 /* release the channel */
5957 f_rsl_chan_deact();
5958 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
5959 f_rslem_unregister(0, g_chan_nr);
5960}
5961testcase TC_rll_unit_data_ind_DCCH() runs on test_CT {
Stefan Sperlingc4181912018-07-25 17:03:08 +02005962 var octetstring l3 := f_rnd_octstring(20);
Harald Welte0472ab42018-03-12 15:02:26 +01005963 var RllTestCases tcs := {
5964 valueof(t_EITC(0, valueof(ts_RslLinkID_DCCH(0)), l3, true)),
5965 valueof(t_EITC(3, valueof(ts_RslLinkID_DCCH(3)), l3, true))
5966 };
5967 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_ind));
5968}
5969testcase TC_rll_unit_data_ind_ACCH() runs on test_CT {
5970 var octetstring l3 := f_rnd_octstring(18);
5971 var RllTestCases tcs := {
5972 valueof(t_EITC(0, valueof(ts_RslLinkID_SACCH(0)), l3, true)),
5973 valueof(t_EITC(3, valueof(ts_RslLinkID_SACCH(3)), l3, true))
5974 };
5975 f_rll_testmatrix(tcs, refers(f_TC_rll_ud_ind));
5976}
5977
Harald Weltee613f962018-04-18 22:38:16 +02005978/***********************************************************************
5979 * Encryption Related
5980 ***********************************************************************/
5981
5982/* send UNITDATA_REQ from BTS to MS and expect it to arrive */
5983function f_unitdata_mt(RslLinkId link_id, octetstring l3) runs on ConnHdlr {
5984 RSL.send(ts_RSL_UNITDATA_REQ(g_chan_nr, link_id, l3));
5985 if (link_id.c == SACCH) {
5986 f_l1_exp_lapdm(tr_LAPDm_B4_UI(link_id.sapi, cr_MT_CMD, l3));
5987 } else {
5988 f_l1_exp_lapdm(tr_LAPDm_UI(link_id.sapi, cr_MT_CMD, l3));
5989 }
5990}
5991
Vadim Yanitskiyad131c82018-10-04 06:18:59 +07005992/* Expect (or not expect) other kinds of messages */
5993private altstep as_rsl_any_ind(boolean exp_any) runs on ConnHdlr {
5994 [exp_any] RSL.receive { repeat; }
5995 [not exp_any] RSL.receive {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02005996 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected RSL message!");
Vadim Yanitskiyad131c82018-10-04 06:18:59 +07005997 }
5998}
5999
Harald Weltee613f962018-04-18 22:38:16 +02006000/* Send UI frame from MS and expect it to arrive as RLL UNITDATA IND on Abis */
Vadim Yanitskiy8d8f91c2018-10-04 06:19:45 +07006001private function f_unitdata_mo(
Vadim Yanitskiy98e03152018-10-03 18:06:06 +07006002 RslLinkId link_id,
6003 octetstring l3,
6004 boolean exp_sacch := true, /* Should tolerate SACCH messages? */
Vadim Yanitskiyb9920502018-10-03 18:29:51 +07006005 boolean exp_any := false /* Should tolerate any other RSL messages? */
Vadim Yanitskiy98e03152018-10-03 18:06:06 +07006006) runs on ConnHdlr {
Harald Weltee613f962018-04-18 22:38:16 +02006007 timer T := 3.0;
6008 f_tx_lapdm(ts_LAPDm_UI(link_id.sapi, cr_MO_CMD, l3), link_id);
6009 T.start;
6010 /* Expect RLL UNITDATA IND on RSL side */
6011 alt {
6012 [] RSL.receive(tr_RSL_UNITDATA_IND(g_chan_nr, link_id, l3)) {
6013 setverdict(pass);
6014 }
Vadim Yanitskiye0b91a72018-10-04 15:44:40 +07006015 [exp_sacch] as_meas_res(verify_meas := false);
Vadim Yanitskiyad131c82018-10-04 06:18:59 +07006016 [] as_rsl_any_ind(exp_any);
Harald Weltee613f962018-04-18 22:38:16 +02006017 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006018 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for UNIT_DATA_IND");
Harald Weltee613f962018-04-18 22:38:16 +02006019 }
Harald Weltee613f962018-04-18 22:38:16 +02006020 }
6021}
6022
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07006023/* Send I-frame from MS and expect it to arrive as RLL DATA IND on Abis */
6024private function f_data_mo(
6025 RslLinkId link_id,
6026 boolean p, uint3_t nr, uint3_t ns,
6027 octetstring l3,
6028 boolean exp_sacch := true, /* Should tolerate SACCH messages? */
Vadim Yanitskiyb9920502018-10-03 18:29:51 +07006029 boolean exp_any := false /* Should tolerate any other RSL messages? */
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07006030) runs on ConnHdlr {
6031 timer T := 3.0;
6032 f_tx_lapdm(ts_LAPDm_I(link_id.sapi, cr_MO_CMD, p, nr, ns, l3), link_id);
6033 T.start;
6034 /* Expect RLL DATA IND on RSL side */
6035 alt {
6036 [] RSL.receive(tr_RSL_DATA_IND(g_chan_nr, link_id, l3)) {
6037 setverdict(pass);
6038 }
Vadim Yanitskiye0b91a72018-10-04 15:44:40 +07006039 [exp_sacch] as_meas_res(verify_meas := false);
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07006040 [] as_rsl_any_ind(exp_any);
6041 [] T.timeout {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006042 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for DATA_IND");
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07006043 }
6044 }
6045}
6046
Harald Weltee613f962018-04-18 22:38:16 +02006047/* Test channel activation with A5/n right from the beginning (like in assignment + hand-over) */
6048function f_TC_chan_act_encr(charstring id) runs on ConnHdlr {
6049 f_l1_tune(L1CTL);
6050 f_est_dchan(true);
6051
6052 /* now we actually need to transmit some data both ways to check if the encryption works */
6053 var L1ctlDlMessage dl;
6054
Stefan Sperling603d98e2018-07-25 16:47:28 +02006055 var octetstring l3 := f_rnd_octstring(20);
Harald Weltee613f962018-04-18 22:38:16 +02006056 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
6057
6058 /* send UNITDATA_REQ from BTS to MS and expect it to arrive */
6059 f_unitdata_mt(link_id, l3);
6060
6061 /* Send UI frame from MS and expect it to arrive as RLL UNITDATA IND on Abis */
6062 f_unitdata_mo(link_id, l3);
6063
6064 /* release the channel */
6065 f_rsl_chan_deact();
6066 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
6067 f_rslem_unregister(0, g_chan_nr);
6068}
6069testcase TC_chan_act_a51() runs on test_CT {
6070 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
6071 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_1, f_rnd_octstring(8)));
6072 f_testmatrix_each_chan(pars, refers(f_TC_chan_act_encr));
6073}
6074testcase TC_chan_act_a52() runs on test_CT {
6075 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
6076 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_2, f_rnd_octstring(8)));
6077 f_testmatrix_each_chan(pars, refers(f_TC_chan_act_encr));
6078}
6079testcase TC_chan_act_a53() runs on test_CT {
6080 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
6081 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_3, f_rnd_octstring(8)));
6082 f_testmatrix_each_chan(pars, refers(f_TC_chan_act_encr));
6083}
6084
Eric Wildf1827a72019-05-28 17:37:35 +02006085/* Test channel activation with A5/n right from the beginning and RSL MODE MODIFY
6086 which should break the en/decryption on purpose by supplying a new key that is unknown to the MS*/
6087function f_TC_rsl_modify_encr(charstring id) runs on ConnHdlr {
6088 f_l1_tune(L1CTL);
6089 f_est_dchan(true);
6090
6091 /* now we actually need to transmit some data both ways to check if the encryption works */
6092 var L1ctlDlMessage dl;
6093
6094 var octetstring l3 := f_rnd_octstring(20);
6095 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
6096
6097 /* send UNITDATA_REQ from BTS to MS and expect it to arrive */
6098 f_unitdata_mt(link_id, l3);
6099
6100 /* Send UI frame from MS and expect it to arrive as RLL UNITDATA IND on Abis */
6101 f_unitdata_mo(link_id, l3);
6102
6103 var RSL_Message rsl;
6104 rsl := valueof(ts_RSL_MODE_MODIFY_REQ(g_chan_nr, valueof(ts_RSL_ChanMode_SIGN(false))));
6105
6106 /* modify key to break proper encryption */
6107 g_pars.encr.key := f_rnd_octstring(8);
6108 var RSL_IE ei := valueof(t_RSL_IE(RSL_IE_ENCR_INFO, RSL_IE_Body:{encr_info := g_pars.encr}));
6109 rsl.ies := rsl.ies & { ei };
6110 RSL.send(rsl);
6111
6112 timer T0 := 1.0;
6113 T0.start;
6114 /* Expect RSL MODIFY ACK */
6115 alt {
6116 [] RSL.receive(tr_RSL_MODE_MODIFY_ACK(g_chan_nr)) {}
6117 [] RSL.receive(tr_RSL_MODE_MODIFY_NACK(g_chan_nr, ?)) {
6118 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,"MODE MODIFY NACK");
6119 }
6120 [] T0.timeout {
6121 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for MODE MODIFY (N)ACK");
6122 }
6123 }
6124
6125 var octetstring l3msg := f_rnd_octstring(15);
6126 timer T1 := 3.0;
6127 /* Send UI frame from MS, do not expect it to arrive as RLL UNITDATA IND on Abis
6128 due to broken encryption */
6129 f_tx_lapdm(ts_LAPDm_UI(link_id.sapi, cr_MO_CMD, l3msg), link_id);
6130 T1.start;
6131 alt {
6132 [] RSL.receive(tr_RSL_UNITDATA_IND(g_chan_nr, link_id, l3msg)) {
6133 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "BTS shouldn't be able to decrypt after key change")
6134 }
6135 [] T1.timeout {
6136 setverdict(pass);
6137 }
6138 }
6139
6140 /* release the channel */
6141 f_rsl_chan_deact();
6142 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
6143 f_rslem_unregister(0, g_chan_nr);
6144}
6145testcase TC_rsl_modify_encr() runs on test_CT {
6146 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
6147 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_1, f_rnd_octstring(8)));
6148 f_testmatrix_each_chan(pars, refers(f_TC_rsl_modify_encr));
6149}
Harald Weltee613f962018-04-18 22:38:16 +02006150
6151/* Test unencrypted channel activation followed by explicit ENCR CMD later */
6152function f_TC_encr_cmd(charstring id) runs on ConnHdlr {
6153 /* L3 payload doesn't matter, as it is passed transparently */
6154 var BIT3 l3_alg_id := f_alg_id_to_l3(g_pars.encr.alg_id);
6155 var octetstring l3 := enc_PDU_ML3_NW_MS(valueof(ts_RRM_CiphModeCmd(l3_alg_id)));
6156 var RslLinkId link_id := valueof(ts_RslLinkID_DCCH(0));
6157
6158 f_l1_tune(L1CTL);
6159
6160 /* first establish a dedicated channel in the clear */
6161 f_est_dchan(false);
6162
6163 /* Establish ABM */
6164 f_est_rll_mo(link_id.sapi, link_id, '23420815'O);
6165
6166 /* then send the RSL ENCR CMD with an actual RR CIPH MOD CMD inside */
6167 RSL.send(ts_RSL_ENCR_CMD(g_chan_nr, link_id, g_pars.encr.alg_id, g_pars.encr.key, l3));
6168 /* expect the L3 to arrive still unencrypted on the MS side */
6169 f_l1_exp_lapdm(tr_LAPDm_I(link_id.sapi, cr_MT_CMD, ?, ?, ?, l3));
6170
6171 /* configure L1 to apply ciphering */
6172 var uint8_t alg_id := f_alg_id_to_l1ctl(g_pars.encr.alg_id);
6173 f_L1CTL_CRYPTO_REQ(L1CTL, g_pars.chan_nr, alg_id, g_pars.encr.key);
6174
Vadim Yanitskiy4d78a702018-10-03 03:59:34 +07006175 /* send first ciphered I-frame in response and expect it on RSL */
6176 f_data_mo(link_id, true, 1, 0, '0a0b0c0d'O, exp_sacch := true);
Harald Weltee613f962018-04-18 22:38:16 +02006177
6178 /* now the BTS code should have detected the first properly encrypted uplink I-frame,
6179 * and hence enable encryption also on the downlink */
6180
6181 /* expect bi-directional communication work in encrypted mode */
6182 f_unitdata_mo(link_id, f_rnd_octstring(15));
6183 f_unitdata_mt(link_id, f_rnd_octstring(15));
6184
6185 /* release the channel */
6186 f_rsl_chan_deact();
6187 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
6188 f_rslem_unregister(0, g_chan_nr);
6189}
6190testcase TC_encr_cmd_a51() runs on test_CT {
6191 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
6192 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_1, f_rnd_octstring(8)));
6193 f_testmatrix_each_chan(pars, refers(f_TC_encr_cmd));
6194}
6195testcase TC_encr_cmd_a52() runs on test_CT {
6196 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
6197 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_2, f_rnd_octstring(8)));
6198 f_testmatrix_each_chan(pars, refers(f_TC_encr_cmd));
6199}
6200testcase TC_encr_cmd_a53() runs on test_CT {
6201 var ConnHdlrPars pars := valueof(t_Pars(t_RslChanNr_Bm(1), ts_RSL_ChanMode_SIGN));
6202 pars.encr := valueof(ts_RSL_IE_EncrInfo(RSL_ALG_ID_A5_3, f_rnd_octstring(8)));
6203 f_testmatrix_each_chan(pars, refers(f_TC_encr_cmd));
6204}
6205
6206private function f_assert_lapdm(octetstring enc, template LapdmFrame exp_match, charstring name := "") {
6207 var LapdmFrame lf;
6208 var octetstring reenc;
6209
6210 /* decode the LAPDm frame */
6211 if (ischosen(exp_match.ab)) {
6212 lf.ab := dec_LapdmFrameAB(enc);
6213 } else {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006214 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "unsupported frame type");
Harald Weltee613f962018-04-18 22:38:16 +02006215 }
6216
6217 /* check if decoder result matches expectation */
6218 if (not match(lf, exp_match)) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006219 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str(name, ": decoded LAPDm doesn't match"));
Harald Weltee613f962018-04-18 22:38:16 +02006220 } else {
6221 log(name, ": matched");
6222 setverdict(pass);
6223 }
6224
6225 /* test if re-encoded frame equals original input */
6226 reenc := enc_LapdmFrame(lf);
6227 if (enc != reenc) {
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006228 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str(name, ": re-encoded LAPDm frame doesn't match"));
Harald Weltee613f962018-04-18 22:38:16 +02006229 } else {
6230 setverdict(pass);
6231 }
6232}
6233
6234testcase TC_lapdm_selftest() runs on test_CT {
6235 f_assert_lapdm('030301'O, tr_LAPDm_UI(0, true, ''O), "ui_s0_empty");
6236 f_assert_lapdm('0F0301'O, tr_LAPDm_UI(3, true, ''O), "ui_s3_empty");
6237 f_assert_lapdm('013F01'O, tr_LAPDm_SABM(0, false, true, ''O), "sabm_s0_empty");
6238 f_assert_lapdm('013F1123420815'O, tr_LAPDm_SABM(0, false, true, '23420815'O), "sabm_s0_l3");
6239 f_assert_lapdm('03E101'O, tr_LAPDm_RR(0, true, false, 7), "rr_s0_7");
6240 f_assert_lapdm('03000d063505'O, tr_LAPDm_I(0, true, false, 0, 0, '063505'O), "I/0/0");
6241 f_assert_lapdm('03e00d063505'O, tr_LAPDm_I(0, true, false, 7, 0, '063505'O), "I/7/0");
6242}
6243
Stefan Sperling4880be42018-08-07 18:12:59 +02006244/***********************************************************************
6245 * DTX Related (see GSM 05.08, section 8.3)
6246 ***********************************************************************/
6247
6248/* XXX These functions must be kept in sync with g_AllChannels defined on test_CT. */
6249function f_g_chan_is_tchf() runs on ConnHdlr return boolean {
6250 return (g_chan_nr == valueof(ts_RslChanNr_Bm(1)) or
6251 g_chan_nr == valueof(ts_RslChanNr_Bm(2)) or
6252 g_chan_nr == valueof(ts_RslChanNr_Bm(3)) or
6253 g_chan_nr == valueof(ts_RslChanNr_Bm(4)));
6254}
6255function f_g_chan_is_tchh() runs on ConnHdlr return boolean {
6256 return (g_chan_nr == valueof(ts_RslChanNr_Lm(5,0)) or
6257 g_chan_nr == valueof(ts_RslChanNr_Lm(5,1)));
6258}
6259function f_g_chan_is_sdcch4() runs on ConnHdlr return boolean {
6260 return (g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,0)) or
6261 g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,1)) or
6262 g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,2)) or
6263 g_chan_nr == valueof(ts_RslChanNr_SDCCH4(0,3)));
6264}
6265function f_g_chan_is_sdcch8() runs on ConnHdlr return boolean {
6266 return (g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,0)) or
6267 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,1)) or
6268 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,2)) or
6269 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,3)) or
6270 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,4)) or
6271 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,5)) or
6272 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,6)) or
6273 g_chan_nr == valueof(ts_RslChanNr_SDCCH8(6,7)));
6274}
6275
6276function f_test_l2_fill_frames(boolean dtxd) runs on ConnHdlr {
6277 var L1ctlDlMessage dl;
6278 var octetstring l2_fill_frame := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O;
6279 var octetstring l2_fill_frame_sacch := substr(l2_fill_frame, 0, lengthof(l2_fill_frame) - 2);
6280 var GsmFrameNumber first_fn;
6281 var boolean is_first_frame := true;
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006282 var integer nfill_frames_sacch := 0;
6283 var integer nfill_frames_nonsacch := 0;
6284 var integer expected_fill_frames := 10000; /* initial value causes test failure if not overridden */
Stefan Sperling4880be42018-08-07 18:12:59 +02006285 /* Frames numbers (mod 104) for which a fill frame is expected on TCHF if DTX is enabled. */
6286 var Integers required_tdma_frames_dtx_tchf := { 52, 53, 54, 55, 56, 57, 58, 59 };
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006287 const integer frame_dtx_tchf_mod := 104;
6288 /* Frame numbers (mod 104) for which a fill frame is expected at the L1SAP level,
6289 * which operates in terms of blocks rather than frames. */
6290 var Integers required_tdma_blocks_dtx_tchf := { 52, 56 };
6291 const integer block_dtx_tchf_mod := 26;
Stefan Sperling4880be42018-08-07 18:12:59 +02006292 timer T := 5.0;
6293
6294 f_l1_tune(L1CTL);
6295 RSL.clear;
6296 L1CTL.clear;
6297
6298 /* activate TCHF signalling channel */
6299 f_est_dchan(false);
6300
6301 T.start;
6302 alt {
6303 [] L1CTL.receive(tr_L1CTL_DATA_IND(g_chan_nr, ?)) -> value dl {
6304 var GsmFrameNumber fn := dl.dl_info.frame_nr;
6305 var octetstring l2 := dl.payload.data_ind.payload;
6306
6307 if (is_first_frame) {
6308 is_first_frame := false;
6309 first_fn := dl.dl_info.frame_nr;
6310 }
6311
6312 if (dl.dl_info.link_id.c == SACCH) {
6313 l2 := substr(l2, 2, lengthof(l2) - 2); /* remove L1 header */
6314 if (not match(l2_fill_frame_sacch, l2)) {
6315 repeat;
6316 }
6317 } else if (not match(l2_fill_frame, l2)) {
6318 repeat;
6319 }
6320
6321 if (dtxd) {
6322 if (not f_g_chan_is_tchf()) {
6323 T.stop;
6324 f_rsl_chan_deact();
6325 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006326 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 +02006327 }
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006328 if (fn > first_fn + frame_dtx_tchf_mod) {
Stefan Sperling4880be42018-08-07 18:12:59 +02006329 T.stop;
6330 f_rsl_chan_deact();
6331 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006332
6333 /* With DTX enabled we can expect at least 3 fill frames for every 104 frames.
6334 * 2 SACCH, 1 TCH/F */
6335 expected_fill_frames := 3;
6336
6337 if (nfill_frames_sacch + nfill_frames_nonsacch < expected_fill_frames) {
6338 log("received only ", nfill_frames_sacch, "+", nfill_frames_nonsacch,
6339 " (SACCH+other) out of ", expected_fill_frames, " expected fill frames");
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006340 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Not enough fill frames received");
Stefan Sperling4880be42018-08-07 18:12:59 +02006341 } else {
6342 setverdict(pass);
6343 }
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006344 } else {
6345 if (dl.dl_info.link_id.c == SACCH) {
6346 nfill_frames_sacch := nfill_frames_sacch + 1;
Stefan Sperling4880be42018-08-07 18:12:59 +02006347 repeat;
6348 }
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006349 /* On DTX TCH/F channels, fill frames occur only for specific frame numbers mod 104.
6350 * Furthermore, the L1SAP layer gives us frame numbers for the start of a block so
6351 * we should only see the subset of frames numbers which correspond to a block boundary.
6352 * TCH/F blocks are defined to start at 0,4,8,13,17,21 (modulo 26) */
6353 for (var integer i := 0; i < lengthof(required_tdma_blocks_dtx_tchf); i := i + 1) {
6354 if (fn mod frame_dtx_tchf_mod == required_tdma_blocks_dtx_tchf[i]) {
6355 nfill_frames_nonsacch := nfill_frames_nonsacch + 1;
6356 repeat;
6357 }
6358 }
6359 log("Received DTX TCH fill frame with bad frame number: ", fn,
6360 " (mod ", frame_dtx_tchf_mod, ": ", fn mod frame_dtx_tchf_mod, ")",
6361 " (mod ", block_dtx_tchf_mod, ": ", fn mod block_dtx_tchf_mod, ")");
6362 f_rsl_chan_deact();
6363 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006364 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unexpected L2 fill frame received on Um");
Stefan Sperling4880be42018-08-07 18:12:59 +02006365 }
Stefan Sperling4880be42018-08-07 18:12:59 +02006366 } else {
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006367 if (dl.dl_info.link_id.c == SACCH) {
6368 nfill_frames_sacch := nfill_frames_sacch + 1;
6369 } else {
6370 nfill_frames_nonsacch := nfill_frames_nonsacch + 1;
6371 }
6372 if (fn > first_fn + frame_dtx_tchf_mod) {
Stefan Sperling4880be42018-08-07 18:12:59 +02006373 T.stop;
6374 if (f_g_chan_is_tchf()) {
6375 /* Without DTX we can expect 25 fill frames for every 104 frames.
6376 * (24 FACCH + 1 SACCH filling) */
6377 expected_fill_frames := 25;
6378 } else if (f_g_chan_is_tchh()) {
6379 /* We can expect 2 fill frames for every 104 frames. */
6380 expected_fill_frames := 2;
6381 } else if (f_g_chan_is_sdcch4() or f_g_chan_is_sdcch8()) {
6382 /* We can expect 5 fill frames for every 104 frames. */
6383 expected_fill_frames := 5;
6384 } else {
6385 f_rsl_chan_deact();
6386 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006387 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Unknown channel type");
Stefan Sperling4880be42018-08-07 18:12:59 +02006388 }
6389
6390 f_rsl_chan_deact();
6391 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006392
6393 if (nfill_frames_sacch + nfill_frames_nonsacch >= expected_fill_frames) {
Stefan Sperling4880be42018-08-07 18:12:59 +02006394 setverdict(pass);
6395 } else {
Stefan Sperling91d4c9d2018-08-09 20:03:08 +02006396 log("received only ", nfill_frames_sacch, "+", nfill_frames_nonsacch,
6397 " (SACCH+other) out of ", expected_fill_frames, " expected fill frames");
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006398 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Not enough fill frames received");
Stefan Sperling4880be42018-08-07 18:12:59 +02006399 }
6400 } else {
6401 repeat;
6402 }
6403 }
6404 }
6405 [] L1CTL.receive { repeat; }
6406 [] T.timeout {
6407 f_rsl_chan_deact();
6408 f_L1CTL_DM_REL_REQ(L1CTL, g_chan_nr);
Daniel Willmann0fcc4d32018-10-23 20:32:19 +02006409 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for L2 fill frames on Um");
Stefan Sperling4880be42018-08-07 18:12:59 +02006410 }
6411 }
6412}
6413
6414function f_TC_tch_sign_l2_fill_frame(charstring id) runs on ConnHdlr {
6415 f_test_l2_fill_frames(false);
6416}
6417
6418function f_TC_tch_sign_l2_fill_frame_dtxd(charstring id) runs on ConnHdlr {
6419 f_test_l2_fill_frames(true);
6420}
6421
6422function f_tch_sign_l2_fill_frame(boolean dtxd) runs on test_CT {
6423 var ConnHdlr vc_conn;
6424 var ConnHdlrPars pars;
6425 pars.t_guard := 60.0;
Harald Welte10474062019-05-30 16:48:17 +02006426 f_init();
Stefan Sperling4880be42018-08-07 18:12:59 +02006427 for (var integer i := 0; i < sizeof(g_AllChannels); i := i + 1) {
6428 pars := valueof(t_Pars(g_AllChannels[i], ts_RSL_ChanMode_SIGN(dtxd)));
6429 if (dtxd) {
6430 if (i >= 4) { /* DTX is only allowed on TCH/F */
6431 break;
6432 }
6433 vc_conn := f_start_handler(refers(f_TC_tch_sign_l2_fill_frame_dtxd), pars);
6434 } else {
6435 vc_conn := f_start_handler(refers(f_TC_tch_sign_l2_fill_frame), pars);
6436 }
6437 vc_conn.done;
6438 }
6439}
6440
6441/* Verify that L2 fill frames are sent on TCH in signaling mode if
6442 * there is nothing to transmit while DTX is disabled on downlink. */
6443testcase TC_tch_sign_l2_fill_frame() runs on test_CT {
6444 f_tch_sign_l2_fill_frame(false);
6445}
6446
6447/* Verify that particular L2 fill frames are sent on TCH in signaling mode if
6448 * there is nothing to transmit while DTX is enabled on downlink. */
6449testcase TC_tch_sign_l2_fill_frame_dtxd() runs on test_CT {
6450 f_tch_sign_l2_fill_frame(true);
6451}
Harald Welte0472ab42018-03-12 15:02:26 +01006452
Stefan Sperling0ec1c262018-10-15 15:12:52 +02006453testcase TC_chopped_ipa_ping() runs on test_CT {
6454 IPA_Testing.f_run_TC_chopped_ipa_ping(mp_rsl_ip, mp_rsl_port, LISTEN_FOR_CLIENT);
6455}
6456
Stefan Sperlingaa1e60f2018-10-15 16:34:07 +02006457testcase TC_chopped_ipa_payload() runs on test_CT {
6458 IPA_Testing.f_run_TC_chopped_ipa_payload(mp_rsl_ip, mp_rsl_port, LISTEN_FOR_CLIENT);
6459}
6460
Harald Welte0472ab42018-03-12 15:02:26 +01006461/* test generation of RLL ERR IND based on Um errors (TS 48.058 3.9) */
6462/* protocol error as per 44.006 */
6463/* link layer failure (repetition of I-frame N200 times without ACK */
6464/* repetition of SABM or DISC N200 times without ACK */
6465/* receptiom of SABM in multi-frame established state */
6466
6467
Harald Welte68e495b2018-02-25 00:05:57 +01006468/* TODO Areas:
6469
6470* channel activation
6471** with BS_Power / MS_Power, bypassing power control loop
6472** on primary vs. secondary TRX
Harald Welte68e495b2018-02-25 00:05:57 +01006473** with timing advance from initial activation on
6474* mode modify
6475** encryption
6476** multirate
6477* check DEACTIVATE SACCH
Harald Welte68e495b2018-02-25 00:05:57 +01006478** unsupported algorithm
6479* handover detection
Harald Welte68e495b2018-02-25 00:05:57 +01006480* BS Power Control
6481* Physical Context
Harald Welte68e495b2018-02-25 00:05:57 +01006482* RF resource ind
Harald Welte68e495b2018-02-25 00:05:57 +01006483* error handling
Harald Welte68e495b2018-02-25 00:05:57 +01006484** IE duplicated?
Harald Welte883340c2018-02-28 18:59:29 +01006485* PCU interface
Harald Welte883340c2018-02-28 18:59:29 +01006486** DATA_IND from BTS->PCU
6487** verification of PCU-originated DATA_REQ arrival on Um/MS side
Harald Welte68e495b2018-02-25 00:05:57 +01006488
6489*/
Harald Welte70767382018-02-21 12:16:40 +01006490
6491control {
6492 execute( TC_chan_act_stress() );
6493 execute( TC_chan_act_react() );
6494 execute( TC_chan_deact_not_active() );
6495 execute( TC_chan_act_wrong_nr() );
Harald Welte629cc6b2018-03-11 17:19:05 +01006496 execute( TC_deact_sacch() );
Harald Welteea17b912018-03-11 22:29:31 +01006497 execute( TC_sacch_filling() );
6498 execute( TC_sacch_info_mod() );
Harald Welte075d84c2018-03-12 13:07:24 +01006499 execute( TC_sacch_multi() );
Harald Welte55700662018-03-12 13:15:43 +01006500 execute( TC_sacch_multi_chg() );
Harald Weltec8d363c2019-05-19 20:36:48 +02006501 execute( TC_sacch_chan_act() );
Harald Welte8b01c792019-05-19 22:51:25 +02006502 execute( TC_sacch_chan_act_ho_async() );
6503 execute( TC_sacch_chan_act_ho_sync() );
Harald Welte8c24c2b2018-02-26 08:31:31 +01006504 execute( TC_rach_content() );
6505 execute( TC_rach_count() );
Harald Welte54a2a2d2018-02-26 09:14:05 +01006506 execute( TC_rach_max_ta() );
Vadim Yanitskiy7c2c10c2019-05-31 20:42:01 +07006507 execute( TC_ho_rach() );
Harald Welte3453ab42019-05-24 21:19:58 +02006508 execute( TC_rach_load_idle_thresh0() );
6509 execute( TC_rach_load_idle_below_thresh() );
6510 execute( TC_rach_load_count() );
Harald Welte70767382018-02-21 12:16:40 +01006511 execute( TC_meas_res_sign_tchf() );
6512 execute( TC_meas_res_sign_tchh() );
6513 execute( TC_meas_res_sign_sdcch4() );
6514 execute( TC_meas_res_sign_sdcch8() );
Harald Welte685d5982018-02-27 20:42:05 +01006515 execute( TC_meas_res_sign_tchh_toa256() );
Pau Espin Pedrola2e079c2020-06-03 17:31:04 +02006516 execute( TC_tx_power_start_ramp_up_bcch() );
Eric Wildae8f2622019-06-18 17:05:11 +02006517 execute( TC_rsl_bs_pwr_static_ass() );
6518 execute( TC_rsl_bs_pwr_static_power_control() );
Philipp Maier4d1e9c92018-12-20 11:11:56 +01006519 execute( TC_rsl_ms_pwr_ctrl() );
Eric Wild280ccb82019-06-17 11:11:52 +02006520 execute( TC_rsl_ms_pwr_dyn_active() );
Eric Wild095024b2019-06-17 15:08:57 +02006521 execute( TC_rsl_ms_pwr_dyn_active2() );
Eric Wild61edb7e2019-06-03 12:38:31 +02006522 execute( TC_rsl_ms_pwr_dyn_up() );
6523 execute( TC_rsl_ms_pwr_dyn_down() );
6524 execute( TC_rsl_ms_pwr_dyn_ass_updown() );
6525 execute( TC_rsl_ms_pwr_dyn_max() );
Eric Wilde57e1a62019-05-28 13:30:55 +02006526 execute( TC_rsl_chan_initial_ms_pwr() );
Eric Wild6833cc92019-05-23 19:34:44 +02006527 execute( TC_rsl_chan_initial_ta() );
Eric Wildf1827a72019-05-28 17:37:35 +02006528 execute( TC_rsl_modify_encr() );
Harald Welte70767382018-02-21 12:16:40 +01006529 execute( TC_conn_fail_crit() );
Harald Welte68e495b2018-02-25 00:05:57 +01006530 execute( TC_paging_imsi_80percent() );
6531 execute( TC_paging_tmsi_80percent() );
6532 execute( TC_paging_imsi_200percent() );
6533 execute( TC_paging_tmsi_200percent() );
Harald Welte01d982c2018-02-25 01:31:40 +01006534 execute( TC_rsl_protocol_error() );
6535 execute( TC_rsl_mand_ie_error() );
6536 execute( TC_rsl_ie_content_error() );
Harald Welte48494ca2018-02-25 16:59:50 +01006537 execute( TC_si_sched_default() );
Harald Welte0cae4552018-03-09 22:20:26 +01006538 execute( TC_si_sched_1() );
Harald Welte48494ca2018-02-25 16:59:50 +01006539 execute( TC_si_sched_2bis() );
6540 execute( TC_si_sched_2ter() );
6541 execute( TC_si_sched_2ter_2bis() );
6542 execute( TC_si_sched_2quater() );
6543 execute( TC_si_sched_13() );
6544 execute( TC_si_sched_13_2bis_2ter_2quater() );
Harald Weltea871a382018-02-25 02:03:14 +01006545 execute( TC_ipa_dlcx_not_active() );
Harald Weltea3f1df92018-02-25 12:49:55 +01006546 execute( TC_ipa_crcx_twice_not_active() );
6547 execute( TC_ipa_crcx_mdcx_dlcx_not_active() );
Harald Welte3ae11da2018-02-25 13:36:06 +01006548 execute( TC_ipa_crcx_mdcx_mdcx_dlcx_not_active() );
Harald Welte9912eb52018-02-25 13:30:15 +01006549 execute( TC_ipa_crcx_sdcch_not_active() );
Harald Welte883340c2018-02-28 18:59:29 +01006550
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01006551 if (mp_pcu_socket != "") {
6552 execute( TC_pcu_act_req() );
6553 execute( TC_pcu_act_req_wrong_ts() );
6554 execute( TC_pcu_act_req_wrong_bts() );
6555 execute( TC_pcu_act_req_wrong_trx() );
6556 execute( TC_pcu_deact_req() );
6557 execute( TC_pcu_deact_req_wrong_ts() );
6558 execute( TC_pcu_ver_si13() );
Harald Weltead033dc2019-05-25 17:28:16 +02006559 if (mp_l1_supports_gprs) {
6560 execute( TC_pcu_data_req_pdtch() );
6561 execute( TC_pcu_data_req_ptcch() );
Harald Welte7162a612019-05-26 12:56:09 +02006562 execute( TC_pcu_data_req_wrong_bts() );
6563 execute( TC_pcu_data_req_wrong_trx() );
6564 execute( TC_pcu_data_req_wrong_ts() );
6565 execute( TC_pcu_data_req_ts_inactive() );
Harald Weltead033dc2019-05-25 17:28:16 +02006566 }
Vadim Yanitskiy970b1532019-10-24 15:22:19 +07006567 execute( TC_pcu_ptcch() );
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01006568 execute( TC_pcu_data_req_agch() );
Harald Welte928622b2019-05-26 13:22:59 +02006569 execute( TC_pcu_data_req_pch() );
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01006570 execute( TC_pcu_data_req_imm_ass_pch() );
6571 execute( TC_pcu_rach_content() );
Vadim Yanitskiy51cbc102019-04-22 06:37:30 +07006572 execute( TC_pcu_ext_rach_content() );
Vadim Yanitskiya2c68e82019-07-03 13:07:20 +07006573 execute( TC_pcu_data_ind_lqual_cb() );
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01006574 execute( TC_pcu_paging_from_rsl() );
Harald Welted66c9b82019-05-25 09:03:15 +02006575 execute( TC_pcu_time_ind() );
Harald Welte4832c862019-05-25 14:57:18 +02006576 execute( TC_pcu_rts_req() );
Harald Welte07bd2d22019-05-25 11:03:30 +02006577 execute( TC_pcu_oml_alert() );
Harald Welteeaa9a862019-05-26 23:01:08 +02006578 execute( TC_pcu_rr_suspend() );
Harald Weltea2e0e942019-05-27 18:12:53 +02006579 execute( TC_pcu_socket_connect_multi() );
Harald Weltec8effb72019-05-27 18:23:04 +02006580 execute( TC_pcu_socket_reconnect() );
Harald Weltebe030482019-05-27 22:29:35 +02006581 execute( TC_pcu_socket_noconnect_nosi3gprs() );
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07006582 execute( TC_pcu_socket_noconnect_nosi4gprs() );
Harald Weltebe030482019-05-27 22:29:35 +02006583 execute( TC_pcu_socket_connect_si3gprs() );
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07006584 execute( TC_pcu_socket_connect_si4gprs() );
Harald Weltebe030482019-05-27 22:29:35 +02006585 execute( TC_pcu_socket_disconnect_nosi3gprs() );
Vadim Yanitskiya8e83a82020-05-04 16:05:12 +07006586 execute( TC_pcu_socket_disconnect_nosi4gprs() );
Oliver Smithf5239c72019-08-28 10:01:25 +02006587 execute( TC_pcu_socket_verify_info_ind() );
Philipp Maier15cd6872020-01-08 13:41:41 +01006588 execute( TC_dyn_osmo_pdch_act_deact() );
6589 execute( TC_dyn_osmo_pdch_double_act() );
6590 execute( TC_dyn_ipa_pdch_act_deact() );
6591 execute( TC_dyn_ipa_pdch_act_tchf_act_nack() );
6592
Pau Espin Pedrola14a8af2018-11-20 13:12:22 +01006593 } else {
6594 log("PCU socket path not available, skipping PCU tests");
6595 }
Harald Welte3d04ae62018-04-04 20:29:05 +02006596
Harald Welte3d04ae62018-04-04 20:29:05 +02006597 execute( TC_dyn_osmo_pdch_unsol_deact() );
Harald Welte3d04ae62018-04-04 20:29:05 +02006598 execute( TC_dyn_osmo_pdch_tchf_act() );
6599 execute( TC_dyn_osmo_pdch_tchh_act() );
Harald Welte9bbbfb52018-04-05 09:33:19 +02006600 execute( TC_dyn_ipa_pdch_tchf_act() );
6601 execute( TC_dyn_ipa_pdch_tchf_act_pdch_act_nack() );
Harald Welte0472ab42018-03-12 15:02:26 +01006602
6603 execute( TC_rll_est_ind() );
6604 execute( TC_rll_est_req_DCCH_3() );
6605 execute( TC_rll_est_req_ACCH_3() );
6606 execute( TC_rll_rel_ind_DCCH_0() );
6607 execute( TC_rll_rel_ind_DCCH_3() );
6608 execute( TC_rll_rel_ind_ACCH_0() );
6609 execute( TC_rll_rel_ind_ACCH_3() );
6610 execute( TC_rll_rel_req() );
6611 execute( TC_rll_unit_data_req_DCCH() );
6612 execute( TC_rll_unit_data_req_ACCH() );
6613 execute( TC_rll_unit_data_ind_DCCH() );
6614 execute( TC_rll_unit_data_ind_ACCH() );
Harald Weltee613f962018-04-18 22:38:16 +02006615
6616 execute( TC_chan_act_a51() );
6617 execute( TC_chan_act_a52() );
6618 execute( TC_chan_act_a53() );
6619 execute( TC_encr_cmd_a51() );
6620 execute( TC_encr_cmd_a52() );
6621 execute( TC_encr_cmd_a53() );
6622
Harald Welteee25aae2019-05-19 14:32:37 +02006623 execute( TC_err_rep_wrong_mdisc() );
6624 execute( TC_err_rep_wrong_msg_type() );
6625 execute( TC_err_rep_wrong_sequence() );
6626
Harald Weltee613f962018-04-18 22:38:16 +02006627 execute( TC_lapdm_selftest() );
Stefan Sperling4880be42018-08-07 18:12:59 +02006628
6629 execute( TC_tch_sign_l2_fill_frame() );
6630 execute( TC_tch_sign_l2_fill_frame_dtxd() );
Stefan Sperling0ec1c262018-10-15 15:12:52 +02006631
6632 execute( TC_chopped_ipa_ping() );
Stefan Sperlingaa1e60f2018-10-15 16:34:07 +02006633 execute( TC_chopped_ipa_payload() );
Harald Welte70767382018-02-21 12:16:40 +01006634}
6635
6636
6637}