blob: efb7d94e120303489b84ea6bbcb082dc9c64162f [file] [log] [blame]
Harald Weltea0895f92018-03-08 11:51:23 +01001module PCU_Tests {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02002
3/* "RAW" PCU tests: Talk directly to the PCU socket of OsmoPCU on the one hand side (emulating
4 the BTS/BSC side PCU socket server) and the Gb interface on the other hand side. No NS/BSSGP
5 Emulation is used; rather, we simply use the NS_CodecPort to implement both standard and non-
6 standard procedures on the NS and BSSGP level. The goal of these tests is to test exactly
7 those NS and BSSGP implementations on the BSS (PCU) side. */
8
9/* (C) 2018-2019 Harald Welte <laforge@gnumonks.org>
10 * (C) 2019 Vadim Yanitskiy <axilirator@gmail.com>
11 * All rights reserved.
12 *
13 * Released under the terms of GNU General Public License, Version 2 or
14 * (at your option) any later version.
15 *
16 * SPDX-License-Identifier: GPL-2.0-or-later
17 */
18
19friend module PCU_Tests_NS;
20
21import from General_Types all;
22import from Osmocom_Types all;
23import from GSM_Types all;
24import from GSM_RR_Types all;
25
26import from Osmocom_VTY_Functions all;
27import from TELNETasp_PortType all;
28
29import from MobileL3_GMM_SM_Types all;
30import from RLCMAC_CSN1_Types all;
Pau Espin Pedrole8d7d162020-04-29 19:07:36 +020031import from RLCMAC_CSN1_Templates all;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +020032import from RLCMAC_Types all;
Pau Espin Pedrole8d7d162020-04-29 19:07:36 +020033import from RLCMAC_Templates all;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +020034
35import from MobileL3_CommonIE_Types all;
36import from L3_Templates all;
37
38import from NS_Types all;
39import from BSSGP_Types all;
40import from Osmocom_Gb_Types all;
41
42import from BSSGP_Emulation all; /* BssgpConfig */
43import from NS_Emulation all; /* NSConfiguration */
44
45import from UD_Types all;
46import from PCUIF_Types all;
47import from PCUIF_CodecPort all;
48import from PCUIF_Components all;
49import from IPL4asp_Types all;
50import from Native_Functions all;
51import from SGSN_Components all;
52
53modulepar {
54 charstring mp_pcu_sock_path := PCU_SOCK_DEFAULT;
55
56 float X2002 := 0.2; /* Timer -2002, IMM ASSIGN confirm delay */
57}
58
59
60/* FIXME: make sure to use parameters from mp_gb_cfg.cell_id in the PCU INFO IND */
61private template (value) PCUIF_info_ind ts_PCUIF_INFO_default := {
62 version := PCU_IF_VERSION,
63 flags := c_PCUIF_Flags_default,
64 trx := valueof(ts_PCUIF_InfoTrxs_def),
65 bsic := 7,
66 mcc := 262,
67 mnc := 42,
68 mnc_3_digits := 0,
69 lac := 13135,
70 rac := 0,
71 nsei := mp_nsconfig.nsei,
72 nse_timer := { 3, 3, 3, 3, 30, 3, 10 },
73 cell_timer := { 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 },
74 cell_id := 20960,
75 repeat_time := 5 * 50,
76 repeat_count := 3,
77 bvci := mp_gb_cfg.bvci,
78 t3142 := 20,
79 t3169 := 5,
80 t3191 := 5,
81 t3193_10ms := 160,
82 t3195 := 5,
83 t3101 := 10,
84 t3103 := 4,
85 t3105 := 8,
86 cv_countdown := 15,
87 dl_tbf_ext := 250 * 10, /* ms */
88 ul_tbf_ext := 250 * 10, /* ms */
89 initial_cs := 2,
90 initial_mcs := 6,
91 nsvci := { mp_nsconfig.nsvci, 0 },
92 local_pprt := { mp_nsconfig.remote_udp_port, 0 },
93 remote_port := { mp_nsconfig.local_udp_port, 0 },
94 remote_ip := { f_inet_haddr(mp_nsconfig.local_ip) , '00000000'O }
95}
96
97type record lqual_range {
98 /* component reference to the IPA_Client component used for RSL */
99 uint8_t low,
100 uint8_t high
101}
102
103type component RAW_PCU_Test_CT extends bssgp_CT {
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700104 /* PCU interface abstraction component */
105 var RAW_PCUIF_CT vc_PCUIF;
106 /* Virtual BTS component */
107 var RAW_PCU_BTS_CT vc_BTS;
108
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200109 /* Connection to the BTS component (one for now) */
110 port RAW_PCU_MSG_PT BTS;
111 /* Connection to the PCUIF component */
112 port RAW_PCU_MSG_PT PCUIF;
113 /* VTY connection to the PCU */
114 port TELNETasp_PT PCUVTY;
115
116 /* Uplink CS/MCS thresholds, default from pcu_main.c: */
117 var lqual_range g_cs_lqual_ranges[4] := {{low := 0, high := 6},
118 {low := 5, high := 8},
119 {low := 7, high := 13},
120 {low := 12,high := 35}};
121 var lqual_range g_mcs_lqual_ranges[9] := {{low := 0, high := 6},
122 {low := 5, high := 8},
123 {low := 7, high := 13},
124 {low := 12,high := 15},
125 {low := 14, high := 17},
126 {low := 16, high := 18},
127 {low := 17,high := 20},
128 {low := 19, high := 24},
129 {low := 23,high := 35}};
130 var uint8_t g_cs_initial_dl := 1;
131 var uint8_t g_cs_initial_ul := 1;
132 var uint8_t g_mcs_initial_dl := 1;
133 var uint8_t g_mcs_initial_ul := 1;
134 var uint8_t g_cs_max_dl := 4;
135 var uint8_t g_cs_max_ul := 4;
136 var uint8_t g_mcs_max_dl := 9;
137 var uint8_t g_mcs_max_ul := 9;
138
139 var boolean g_egprs_only := false;
140
141 /* Guard timeout */
142 timer g_T_guard := 60.0;
143};
144
145private altstep as_Tguard_RAW() runs on RAW_PCU_Test_CT {
146 [] g_T_guard.timeout {
147 setverdict(fail, "Timeout of T_guard");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700148 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200149 }
150}
151
152private function f_pcuvty_set_allowed_cs_mcs() runs on RAW_PCU_Test_CT {
153 f_vty_config2(PCUVTY, {"pcu"}, "cs " & int2str(g_cs_initial_dl) & " " & int2str(g_cs_initial_ul));
154 f_vty_config2(PCUVTY, {"pcu"}, "cs max " & int2str(g_cs_max_dl) & " " & int2str(g_cs_max_ul));
155
156 f_vty_config2(PCUVTY, {"pcu"}, "mcs " & int2str(g_mcs_initial_dl) & " " & int2str(g_mcs_initial_ul));
157 f_vty_config2(PCUVTY, {"pcu"}, "mcs max " & int2str(g_mcs_max_dl) & " " & int2str(g_mcs_max_ul));
158}
159
160private function f_pcuvty_set_link_quality_ranges() runs on RAW_PCU_Test_CT {
161 var charstring cmd;
162
163 cmd := "cs link-quality-ranges" &
164 " cs1 " & int2str(g_cs_lqual_ranges[0].high) &
165 " cs2 " & int2str(g_cs_lqual_ranges[1].low) & " " & int2str(g_cs_lqual_ranges[1].high) &
166 " cs3 " & int2str(g_cs_lqual_ranges[2].low) & " " & int2str(g_cs_lqual_ranges[2].high) &
167 " cs4 " & int2str(g_cs_lqual_ranges[3].low);
168 f_vty_config2(PCUVTY, {"pcu"}, cmd);
169
170 cmd := "mcs link-quality-ranges" &
171 " mcs1 " & int2str(g_mcs_lqual_ranges[0].high) &
172 " mcs2 " & int2str(g_mcs_lqual_ranges[1].low) & " " & int2str(g_mcs_lqual_ranges[1].high) &
173 " mcs3 " & int2str(g_mcs_lqual_ranges[2].low) & " " & int2str(g_mcs_lqual_ranges[2].high) &
174 " mcs4 " & int2str(g_mcs_lqual_ranges[3].low) & " " & int2str(g_mcs_lqual_ranges[3].high) &
175 " mcs5 " & int2str(g_mcs_lqual_ranges[4].low) & " " & int2str(g_mcs_lqual_ranges[4].high) &
176 " mcs6 " & int2str(g_mcs_lqual_ranges[5].low) & " " & int2str(g_mcs_lqual_ranges[5].high) &
177 " mcs7 " & int2str(g_mcs_lqual_ranges[6].low) & " " & int2str(g_mcs_lqual_ranges[6].high) &
178 " mcs8 " & int2str(g_mcs_lqual_ranges[7].low) & " " & int2str(g_mcs_lqual_ranges[7].high) &
179 " mcs9 " & int2str(g_mcs_lqual_ranges[8].low);
180 f_vty_config2(PCUVTY, {"pcu"}, cmd);
181}
182
183private function f_init_vty(charstring id) runs on RAW_PCU_Test_CT {
184 map(self:PCUVTY, system:PCUVTY);
185 f_vty_set_prompts(PCUVTY);
186 f_vty_transceive(PCUVTY, "enable");
187
188 if (g_egprs_only) {
189 f_vty_config2(PCUVTY, {"pcu"}, "egprs only");
190 } else {
191 f_vty_config2(PCUVTY, {"pcu"}, "no egprs");
192 }
193}
194
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200195function f_init_raw(charstring id, template (value) PCUIF_info_ind info_ind := ts_PCUIF_INFO_default)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200196runs on RAW_PCU_Test_CT {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200197 /* Start the guard timer */
198 g_T_guard.start;
199 activate(as_Tguard_RAW());
200
201 /* Init PCU interface component */
202 vc_PCUIF := RAW_PCUIF_CT.create("PCUIF-" & id);
203 connect(vc_PCUIF:MTC, self:PCUIF);
204 map(vc_PCUIF:PCU, system:PCU);
205
206 /* Create one BTS component (we may want more some day) */
207 vc_BTS := RAW_PCU_BTS_CT.create("BTS-" & id);
208 connect(vc_BTS:PCUIF, vc_PCUIF:BTS);
209 connect(vc_BTS:TC, self:BTS);
210
211 f_init_vty(id);
212
213 vc_PCUIF.start(f_PCUIF_CT_handler(mp_pcu_sock_path));
214 vc_BTS.start(f_BTS_CT_handler(0, valueof(info_ind)));
215
216 /* Wait until the BTS is ready (SI13 negotiated) */
217 BTS.receive(tr_RAW_PCU_EV(BTS_EV_SI13_NEGO));
218}
219
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700220private function f_shutdown(charstring file, integer line,
221 boolean final := false)
222runs on RAW_PCU_Test_CT {
223 /* Determine if the test case was aborted in the middle */
224 if (not final) {
225 log("Test case ", testcasename(), " aborted at ", file, ":", line);
226 } else {
227 /* Guard verdict to avoid 'none' */
228 setverdict(pass);
229 }
230
231 /* Properly shutdown virtual BTS and its clock generator */
232 BTS.send(ts_RAW_PCU_CMD(GENERAL_CMD_SHUTDOWN));
233 vc_BTS.done; /* wait untill it's done */
234
235 /* Shutdown the others and MTC */
236 all component.stop;
237 mtc.stop;
238}
239
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200240template AckNackDescription t_AckNackDescription_init := {
241 final_ack := '0'B,
242 starting_seq_nr := 0,
243 receive_block_bitmap := '0000000000000000000000000000000000000000000000000000000000000000'B
244}
245
246private function f_rlcmac_dl_block_get_tfi(RlcmacDlBlock dl_block) return uint5_t {
247 if (ischosen(dl_block.data)) {
248 return dl_block.data.mac_hdr.hdr_ext.tfi;
249 } else {
250 return dl_block.data_egprs.mac_hdr.tfi;
251 }
252}
253
254/* TS 44.060 sec 12.3 Ack/Nack Description */
255private function f_acknackdesc_ack_block(inout AckNackDescription desc, RlcmacDlBlock dl_block, BIT1 final_ack := '0'B)
256{
257 var uint7_t bsn;
258 var integer i;
259 var integer inc;
260
261 if (ischosen(dl_block.data)) {
262 bsn := dl_block.data.mac_hdr.hdr_ext.bsn;
263 } else {
264 bsn := dl_block.data_egprs.mac_hdr.bsn1;
265 }
266
267 inc := bsn - desc.starting_seq_nr + 1;
268 /* Filling hole? */
269 if (bsn < desc.starting_seq_nr) {
270 desc.receive_block_bitmap[lengthof(desc.receive_block_bitmap) - (desc.starting_seq_nr - bsn)] := int2bit(1, 1);
271 return;
272 }
273
274 /* SSN is increased, and so RBB values need to be moved */
275 for (i := 0; i < lengthof(desc.receive_block_bitmap) - inc; i := i+1) {
276 desc.receive_block_bitmap[i] := desc.receive_block_bitmap[i + inc];
277 }
278 for (i := lengthof(desc.receive_block_bitmap) - inc; i < lengthof(desc.receive_block_bitmap) - 1; i := i+1) {
279 desc.receive_block_bitmap[i] := int2bit(0, 1);
280 }
281 /* Now we can set current bit and update SSN */
282 desc.starting_seq_nr := bsn + 1;
283 desc.receive_block_bitmap[lengthof(desc.receive_block_bitmap) - 1] := int2bit(1, 1);
284
285 /* Finally update the final_ack bit as requested: */
286 desc.final_ack := final_ack;
287}
288
289/* This function can be used to send DATA.cnf in response to the IUT originated DATA.req.
290 * NOTE: it's the responsibility of caller to make sure that pcu_msg contains u.data_req. */
291private function f_pcuif_tx_data_cnf(in PCUIF_Message pcu_msg)
292runs on RAW_PCU_Test_CT {
293 var PCUIF_Message pcu_msg_cnf := {
294 msg_type := PCU_IF_MSG_DATA_CNF,
295 bts_nr := pcu_msg.bts_nr,
296 spare := pcu_msg.spare,
297 u := { data_cnf := pcu_msg.u.data_req }
298 };
299
300 /* PCU wants DATA.cnf containing basically everything that was in DATA.req,
301 * but PCU_IF_SAPI_PCH is a special case - paging group shall be excluded. */
302 if (pcu_msg.u.data_req.sapi == PCU_IF_SAPI_PCH) {
303 pcu_msg_cnf.u.data_cnf.data := substr(pcu_msg.u.data_req.data, 3,
304 pcu_msg.u.data_req.len - 3);
305 }
306
307 BTS.send(pcu_msg_cnf);
308}
309
310private function f_pcuif_rx_imm_ass(out GsmRrMessage rr_imm_ass,
311 template PCUIF_Sapi sapi := PCU_IF_SAPI_AGCH,
312 template GsmRrMessage t_imm_ass := ?,
313 uint8_t bts_nr := 0)
314runs on RAW_PCU_Test_CT return boolean {
315 var PCUIF_Message pcu_msg;
316 var octetstring data;
317 timer T;
318
319 T.start(2.0);
320 alt {
321 [] BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := bts_nr, trx_nr := 0, ts_nr := 0,
322 sapi := sapi, data := ?)) -> value pcu_msg {
323 /* On PCH the payload is prefixed with paging group (3 octets): skip it.
324 * TODO: add an additional template parameter, so we can match it. */
325 if (pcu_msg.u.data_req.sapi == PCU_IF_SAPI_PCH) {
326 data := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
327 } else {
328 data := pcu_msg.u.data_req.data;
329 }
330
331 rr_imm_ass := dec_GsmRrMessage(data);
332 if (not match(rr_imm_ass, t_imm_ass)) {
333 /* Not for us? Wait for more. */
334 repeat;
335 }
336
337 log("Rx Immediate Assignment: ", rr_imm_ass);
338 setverdict(pass);
339 return true;
340 }
341 [] BTS.receive { repeat; }
342 [] T.timeout {
343 setverdict(fail, "Timeout waiting for Immediate Assignment");
344 }
345 }
346
347 return false;
348}
349
Vadim Yanitskiyf74ae992020-05-06 16:05:51 +0700350/* One phase packet access (see 3GPP TS 44.018, table 9.1.8.1) */
351private const BIT8 chan_req_def := '01111000'B;
352
Vadim Yanitskiy85cb9912020-05-06 16:29:43 +0700353/* Establish an Uplink TBF by sending RACH.ind towards the PCU */
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200354private function f_establish_tbf(out GsmRrMessage rr_imm_ass, uint8_t bts_nr := 0,
Vadim Yanitskiyf74ae992020-05-06 16:05:51 +0700355 uint16_t ra := bit2int(chan_req_def),
356 uint8_t is_11bit := 0,
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200357 PCUIF_BurstType burst_type := BURST_TYPE_0,
358 TimingAdvance ta := 0)
359runs on RAW_PCU_Test_CT return boolean {
360 var uint32_t fn;
361
362 /* FIXME: ask the BTS component to give us the current TDMA fn */
363 fn := 1337 + ta;
364
365 /* Send RACH.ind */
366 log("Sending RACH.ind on fn=", fn, " with RA=", ra, ", TA=", ta);
367 BTS.send(ts_PCUIF_RACH_IND(bts_nr := bts_nr, trx_nr := 0, ts_nr := 0,
368 ra := ra, is_11bit := is_11bit,
369 burst_type := burst_type,
370 fn := fn, arfcn := 871,
371 qta := ta * 4));
372
373 /* 3GPP TS 44.018, table 9.1.8.1, note 2b: Request Reference shall be set to 127
374 * when Immediate Assignment is triggered by EGPRS Packet Channel Request. Here
375 * we assume that 11 bit RA always contains EGPRS Packet Channel Request. */
376 if (is_11bit != 0) { ra := 127; }
377
378 /* Expect Immediate (TBF) Assignment on TS0/AGCH */
379 return f_pcuif_rx_imm_ass(rr_imm_ass, PCU_IF_SAPI_AGCH,
Vadim Yanitskiy85cb9912020-05-06 16:29:43 +0700380 tr_IMM_TBF_ASS(false, ra, fn),
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200381 bts_nr := bts_nr);
382}
383
Vadim Yanitskiy5b649cc2020-05-06 16:35:38 +0700384private function f_imm_ass_verify_ul_tbf_ass(in GsmRrMessage rr_imm_ass, out PacketUlAssign ul_tbf_ass)
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +0700385runs on RAW_PCU_Test_CT {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200386
387 /* Make sure we received an UL TBF Assignment */
388 if (match(rr_imm_ass, tr_IMM_TBF_ASS(dl := false, rest := tr_IaRestOctets_ULAss(?)))) {
389 ul_tbf_ass := rr_imm_ass.payload.imm_ass.rest_octets.hh.pa.uldl.ass.ul;
390 log("Rx Uplink TBF assignment: ", ul_tbf_ass);
391 setverdict(pass);
392 } else {
393 setverdict(fail, "Failed to match UL TBF Assignment");
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +0700394 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200395 }
396
397 /* Make sure we have got a TBF with Dynamic Block Allocation */
398 if (ul_tbf_ass.dynamic == omit) {
399 setverdict(fail, "Single Block Allocation is not handled by ", testcasename());
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +0700400 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200401 }
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200402}
403
Vadim Yanitskiy5b649cc2020-05-06 16:35:38 +0700404private function f_imm_ass_verify_dl_tbf_ass(in GsmRrMessage rr_imm_ass, out PacketDlAssign dl_tbf_ass)
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +0700405runs on RAW_PCU_Test_CT {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200406
407 /* Make sure we received a DL TBF Assignment */
408 if (match(rr_imm_ass, tr_IMM_TBF_ASS(dl := true, rest := tr_IaRestOctets_DLAss(?)))) {
409 dl_tbf_ass := rr_imm_ass.payload.imm_ass.rest_octets.hh.pa.uldl.ass.dl;
410 log("Rx Downlink TBF assignment: ", dl_tbf_ass);
411 setverdict(pass);
412 } else {
413 setverdict(fail, "Failed to match DL TBF Assignment");
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +0700414 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200415 }
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200416}
417
418/* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200419function f_pcuif_tx_data_ind(octetstring data, int16_t lqual_cb := 0, uint32_t fn := 0)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200420runs on RAW_PCU_Test_CT {
421 var template RAW_PCU_EventParam ev_param := {tdma_fn := ? };
422 BTS.send(ts_PCUIF_DATA_IND(bts_nr := 0, trx_nr := 0, ts_nr := 7, block_nr := 0,
423 sapi := PCU_IF_SAPI_PDTCH, data := data,
424 fn := fn, arfcn := 871, lqual_cb := lqual_cb));
425 if (fn != 0) {
426 ev_param := {tdma_fn := fn };
427 }
428 BTS.receive(tr_RAW_PCU_EV(TDMA_EV_PDTCH_BLOCK_SENT, ev_param));
429}
430
431/* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
432private function f_pcuif_rx_data_req(out PCUIF_Message pcu_msg)
433runs on RAW_PCU_Test_CT {
434 BTS.send(ts_PCUIF_RTS_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
435 sapi := PCU_IF_SAPI_PDTCH, fn := 0,
436 arfcn := 871, block_nr := 0));
437 BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
438 sapi := PCU_IF_SAPI_PDTCH)) -> value pcu_msg;
439}
440
441/* Expect an Immediate Assignment (paging) from PCU on PCUIF on specified sapi. */
442private function f_pcuif_rx_pch_imm_tbf_ass(out GsmRrMessage rr_imm_ass)
443runs on RAW_PCU_Test_CT {
444 var PCUIF_Message pcu_msg;
445 var octetstring macblock;
446 BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 0,
447 sapi := PCU_IF_SAPI_PCH)) -> value pcu_msg;
448 /* First 3 bytes contain paging group: */
449 macblock := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
450 rr_imm_ass := dec_GsmRrMessage(macblock);
451 if (not match(rr_imm_ass, tr_IMM_TBF_ASS())) {
452 setverdict(fail, "Failed to match Immediate Assignment: ", rr_imm_ass);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700453 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200454 }
455 f_pcuif_tx_data_cnf(pcu_msg);
456}
457
458/* Expect a Paging Request Type 1 from PCU on PCUIF on specified sapi. */
459private function f_pcuif_rx_pch_pag_req1(template MobileIdentityV mi1 := ?,
460 template integer pag_group := ?)
461runs on RAW_PCU_Test_CT return GsmRrMessage {
462 var GsmRrMessage rr_pag_req1;
463 var PCUIF_Message pcu_msg;
464 var octetstring imsi_suff_octstr;
465 var integer pag_group_rx;
466 var octetstring macblock;
467
468 BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 0,
469 sapi := PCU_IF_SAPI_PCH)) -> value pcu_msg;
470
471 /* First 3 bytes contain IMSI suffix to calculate paging group: */
472 imsi_suff_octstr := substr(pcu_msg.u.data_req.data, 0, 3);
473 pag_group_rx := str2int(oct2char(imsi_suff_octstr[0])) * 100 +
474 str2int(oct2char(imsi_suff_octstr[1])) * 10 +
475 str2int(oct2char(imsi_suff_octstr[2]));
476
477 /* Make sure we've got RR Paging Request Type 1 for a given MI */
478 macblock := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
479 rr_pag_req1 := dec_GsmRrMessage(macblock);
480 if (not match(rr_pag_req1, tr_PAG_REQ1(tr_MI_LV(mi1)))) {
481 setverdict(fail, "Failed to match Paging Request Type 1: ", rr_pag_req1);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700482 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200483 }
484
485 /* Make sure that received paging froup matches the expected one */
486 if (not match(pag_group_rx, pag_group)) {
487 setverdict(fail, "Paging group", pag_group_rx, " does not match expected ", pag_group);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700488 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200489 }
490
491 f_pcuif_tx_data_cnf(pcu_msg);
492 return rr_pag_req1;
493}
494
495private function f_tx_rlcmac_ul_block(template (value) RlcmacUlBlock ul_data, int16_t lqual_cb := 0, uint32_t fn := 0)
496runs on RAW_PCU_Test_CT {
497 var octetstring data;
498 /* Encode the payload of DATA.ind */
499 data := enc_RlcmacUlBlock(valueof(ul_data));
500 data := f_pad_oct(data, 23, '00'O); /* CS-1 */
501
502 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
503 f_pcuif_tx_data_ind(data, lqual_cb, fn);
504}
505
Pau Espin Pedrol4aac3d02020-05-13 15:13:49 +0200506private function f_tx_rlcmac_ul_n_blocks(PacketUlAssign ul_tbf_ass, integer num_blocks := 1, template (omit) GprsTlli tlli := omit)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200507runs on RAW_PCU_Test_CT {
508 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
509 tfi := ul_tbf_ass.dynamic.tfi_assignment,
510 cv := num_blocks - 1, /* num UL blocks to be sent (to be overridden in loop) */
511 bsn := 0, /* TODO: what should be here? */
512 blocks := { /* To be generated in loop */ });
513
Pau Espin Pedrol4aac3d02020-05-13 15:13:49 +0200514 if (not istemplatekind(tlli, "omit")) {
515 ul_data.data.mac_hdr.tlli_ind := true;
516 ul_data.data.tlli := tlli;
517 }
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200518
519 for (var integer i := 0; i < num_blocks; i := i + 1) {
520 /* Prepare a new UL block (CV, random payload) */
521 ul_data.data.mac_hdr.countdown := (num_blocks - i - 1);
522 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
523 f_tx_rlcmac_ul_block(ul_data);
524 }
525}
526
527private function f_rx_rlcmac_dl_block(out RlcmacDlBlock dl_block, out uint32_t dl_fn, template (present) CodingScheme exp_cs_mcs := ?)
528runs on RAW_PCU_Test_CT {
529 var PCUIF_Message pcu_msg;
530 f_pcuif_rx_data_req(pcu_msg);
531 dl_block := dec_RlcmacDlBlock(pcu_msg.u.data_req.data);
532 dl_fn := pcu_msg.u.data_req.fn;
533
534 var integer len := lengthof(pcu_msg.u.data_req.data);
535 var CodingScheme cs_mcs := f_rlcmac_block_len2cs_mcs(len)
536 if (not match(f_rlcmac_block_len2cs_mcs(len), exp_cs_mcs)) {
537 setverdict(fail, "Failed to match Coding Scheme exp ", exp_cs_mcs, " vs ", cs_mcs, " (", len, ")");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700538 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200539 }
540}
541
542private function f_rx_rlcmac_dl_block_exp_ack_nack(out RlcmacDlBlock dl_block, out uint32_t poll_fn)
543runs on RAW_PCU_Test_CT {
544 var uint32_t dl_fn;
545
546 f_rx_rlcmac_dl_block(dl_block, dl_fn);
547 if (not match(dl_block, tr_RLCMAC_UL_ACK_NACK(ul_tfi := ?, tlli := ?))) {
548 setverdict(fail, "Failed to match Packet Uplink ACK / NACK");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700549 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200550 }
551
Vadim Yanitskiy2742bcd2020-05-10 12:45:18 +0700552 poll_fn := f_rrbp_ack_fn(dl_fn, dl_block.ctrl.mac_hdr.rrbp);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200553}
554
555private function f_rx_rlcmac_dl_block_exp_dummy(out RlcmacDlBlock dl_block)
556runs on RAW_PCU_Test_CT {
557 var uint32_t dl_fn;
558
559 f_rx_rlcmac_dl_block(dl_block, dl_fn);
560 if (not match(dl_block, tr_RLCMAC_DUMMY_CTRL())) {
561 setverdict(fail, "Failed to match Packet DUMMY DL");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700562 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200563 }
564}
565
566private function f_rx_rlcmac_dl_block_exp_pkt_ass(out RlcmacDlBlock dl_block, out uint32_t poll_fn)
567runs on RAW_PCU_Test_CT {
568 var uint32_t dl_fn;
569
570 f_rx_rlcmac_dl_block(dl_block, dl_fn);
571 if (not match(dl_block, tr_RLCMAC_DL_PACKET_ASS())) {
572 setverdict(fail, "Failed to match Packet Downlink Assignment");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700573 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200574 }
575
Vadim Yanitskiy2742bcd2020-05-10 12:45:18 +0700576 poll_fn := f_rrbp_ack_fn(dl_fn, dl_block.ctrl.mac_hdr.rrbp);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200577}
578
579private function f_rx_rlcmac_dl_block_exp_pkt_ul_ass(out RlcmacDlBlock dl_block, out uint32_t poll_fn)
580runs on RAW_PCU_Test_CT {
581 var uint32_t dl_fn;
582
583 f_rx_rlcmac_dl_block(dl_block, dl_fn);
584 if (not match(dl_block, tr_RLCMAC_UL_PACKET_ASS())) {
585 setverdict(fail, "Failed to match Packet Uplink Assignment");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700586 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200587 }
588
Vadim Yanitskiy2742bcd2020-05-10 12:45:18 +0700589 poll_fn := f_rrbp_ack_fn(dl_fn, dl_block.ctrl.mac_hdr.rrbp);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200590}
591
592
593private function f_rx_rlcmac_dl_block_exp_pkt_pag_req(out RlcmacDlBlock dl_block)
594runs on RAW_PCU_Test_CT {
595 var uint32_t dl_fn;
596
597 f_rx_rlcmac_dl_block(dl_block, dl_fn);
598 if (not match(dl_block, tr_RLCMAC_PACKET_PAG_REQ())) {
599 setverdict(fail, "Failed to match Packet Paging Request: ", dl_block, " vs ", tr_RLCMAC_PACKET_PAG_REQ());
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700600 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200601 }
602}
603
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700604/* This function does what could probably be done with templates */
605private function f_rlcmac_dl_block_verify_data_gprs(in RlcmacDlDataBlock data_block,
606 template (present) octetstring data := ?,
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700607 template (present) uint7_t exp_bsn := ?,
608 template (present) CodingScheme exp_cs := ?)
609runs on RAW_PCU_Test_CT {
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700610 if (not match(data_block.mac_hdr.hdr_ext.bsn, exp_bsn)) {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200611 setverdict(fail, "DL block BSN doesn't match: ",
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700612 data_block.mac_hdr.hdr_ext.bsn, " vs exp ", exp_bsn);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200613 }
614
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700615 if (lengthof(data_block.blocks) < 1) {
616 setverdict(fail, "DL block has no LLC payload: ", data_block);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700617 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200618 }
619
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700620 if (not match(data_block.blocks[0].payload, data)) {
621 setverdict(fail, "Failed to match content of LLC payload in DL Block: ",
622 data_block.blocks[0].payload, " vs ", data);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700623 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200624 }
625
626 /* Check next data blocks contain dummy frames */
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700627 if (lengthof(data_block.blocks) > 1 and substr(data_block.blocks[1].payload, 0, 3) != '43C001'O) {
628 setverdict(fail, "Second data payload is not a dummy frame: ",
629 data_block.blocks[1].payload);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700630 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200631 }
632
633 /* TODO: check exp_cs */
634}
635
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700636/* This function does what could probably be done with templates */
637private function f_rlcmac_dl_block_verify_data_egprs(in RlcmacDlEgprsDataBlock data_block,
638 template (present) octetstring data := ?,
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700639 template (present) uint14_t exp_bsn := ?,
640 template (present) CodingScheme exp_cs := ?)
641runs on RAW_PCU_Test_CT {
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700642 if (not match(data_block.mac_hdr.bsn1, exp_bsn)) {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200643 setverdict(fail, "DL block BSN doesn't match: ",
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700644 data_block.mac_hdr.bsn1, " vs exp ", exp_bsn);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200645 }
646
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700647 if (lengthof(data_block.blocks) < 1) {
648 setverdict(fail, "DL block has no LLC payload: ", data_block);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700649 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200650 }
651
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700652 if (not match(data_block.blocks[0].payload, data)) {
653 setverdict(fail, "Failed to match content of LLC payload in DL Block: ",
654 data_block.blocks[0].payload, " vs ", data);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700655 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200656 }
657
658 /* Check next data blocks contain dummy frames */
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700659 if (lengthof(data_block.blocks) > 1 and substr(data_block.blocks[1].payload, 0, 3) != '43C001'O) {
660 setverdict(fail, "Second data payload is not a dummy frame: ",
661 data_block.blocks[1].payload);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700662 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200663 }
664
665 /* TODO: Check exp_cs. In the case of EGPRS, first check mac_hdr.header_type and then decode CPS = exp_cs based on mac_hdr.header_type.
666 See wireshark's egprs_Header_type1_coding_puncturing_scheme_to_mcs. */
667}
668
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700669/* High level (task specific) helper for receiving and matching GPRS/EGPRS data blocks */
670private function f_rx_rlcmac_dl_block_exp_data(out RlcmacDlBlock dl_block, out uint32_t dl_fn,
671 template (present) octetstring data := ?,
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700672 template (present) uint7_t exp_bsn := ?,
673 template (present) CodingScheme exp_cs := ?)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200674runs on RAW_PCU_Test_CT {
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700675 /* FIXME: ideally we should use an alt statement with timeout here, rather than
676 * having +100500 layers of abstraction. This would facilitate developing the
677 * multi-TBF/-TRX/-BTS tests, where you cannot expect that the first received
678 * block is exactly what you need. */
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200679 f_rx_rlcmac_dl_block(dl_block, dl_fn);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700680
681 /* Make sure it's either GPRS or EGPRS data block */
682 if (not match(dl_block, tr_RLCMAC_DATA)) {
683 setverdict(fail, "Failed to match DL DATA: ", dl_block, " vs ", tr_RLCMAC_DATA);
684 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200685 }
686
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700687 if (ischosen(dl_block.data_egprs)) {
688 f_rlcmac_dl_block_verify_data_egprs(dl_block.data_egprs, data, exp_bsn, exp_cs);
689 } else if (ischosen(dl_block.data)) {
690 f_rlcmac_dl_block_verify_data_gprs(dl_block.data, data, exp_bsn, exp_cs);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200691 } else {
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700692 /* Should not happen, but the caller may theoretically give us a template for CTRL */
693 setverdict(fail, "DL block is neither GPRS nor EGPRS data block: ", dl_block);
694 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200695 }
696}
697
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +0700698private function f_dl_block_ack_fn(in RlcmacDlBlock dl_block, uint32_t dl_fn)
699runs on RAW_PCU_Test_CT return uint32_t {
700 var boolean rrbp_valid;
701 var MacRrbp rrbp;
702
703 /* The argument must be either a GPRS or EGPRS data block */
704 if (ischosen(dl_block.data_egprs)) {
705 rrbp_valid := true; /* always valid */
706 rrbp := dl_block.data_egprs.mac_hdr.rrbp;
707 } else if (ischosen(dl_block.data)) {
708 rrbp_valid := dl_block.data.mac_hdr.mac_hdr.rrbp_valid;
709 rrbp := dl_block.data.mac_hdr.mac_hdr.rrbp;
710 } else {
711 /* Should not happen, but the caller may theoretically give us a CTRL block */
712 setverdict(fail, "DL block is neither GPRS nor EGPRS data block: ", dl_block);
713 f_shutdown(__BFILE__, __LINE__);
714 }
715
716 /* Make sure that the given block really needs to be ACKnowledged */
717 if (not rrbp_valid) {
718 setverdict(fail, "DL block shall not be ACKnowledged, field RRBP is not valid");
719 f_shutdown(__BFILE__, __LINE__);
720 }
721
722 return f_rrbp_ack_fn(dl_fn, rrbp);
723}
724
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200725testcase TC_pcuif_suspend() runs on RAW_PCU_Test_CT {
726 var octetstring ra_id := enc_RoutingAreaIdentification(mp_gb_cfg.cell_id.ra_id);
727 var GprsTlli tlli := 'FFFFFFFF'O;
728 timer T;
729
730 /* Initialize NS/BSSGP side */
731 f_init_bssgp();
732
733 /* Initialize the PCU interface abstraction */
734 f_init_raw(testcasename());
735
736 /* Establish BSSGP connection to the PCU */
737 f_bssgp_establish();
738
739 BTS.send(ts_PCUIF_SUSP_REQ(0, tlli, ra_id, 0));
740
741 T.start(2.0);
742 alt {
743 [] BSSGP_SIG[0].receive(tr_BSSGP_SUSPEND(tlli, mp_gb_cfg.cell_id.ra_id)) {
744 setverdict(pass);
745 }
746 [] T.timeout {
747 setverdict(fail, "Timeout waiting for BSSGP SUSPEND");
748 }
749 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700750
751 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200752}
753
754/* Test of correct Timing Advance at the time of TBF establishment
755 * (derived from timing offset of the Access Burst). */
756testcase TC_ta_rach_imm_ass() runs on RAW_PCU_Test_CT {
757 var GsmRrMessage rr_msg;
758 var boolean ok;
759
760 /* Initialize the PCU interface abstraction */
761 f_init_raw(testcasename());
762
763 /* We cannot send too many TBF requests in a short time because
764 * at some point the PCU will fail to allocate a new TBF. */
765 for (var TimingAdvance ta := 0; ta < 64; ta := ta + 16) {
766 /* Establish an Uplink TBF (send RACH.ind with current TA) */
767 ok := f_establish_tbf(rr_msg, bts_nr := 0, ta := ta);
768 if (not ok) {
769 setverdict(fail, "Failed to establish an Uplink TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700770 break;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200771 }
772
773 /* Make sure Timing Advance IE matches out expectations */
Vadim Yanitskiy8685b382020-05-06 16:53:26 +0700774 if (rr_msg.payload.imm_ass.timing_advance != ta) {
775 setverdict(fail, "Timing Advance mismatch: ",
776 rr_msg.payload.imm_ass.timing_advance,
777 " vs expected ", ta);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700778 break;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200779 }
780 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700781
782 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200783}
784
785/* Verify Timing Advance value(s) indicated during the packet Downlink assignment
786 * procedure as per 3GPP TS 44.018, section 3.5.3. There seems to be a bug in the
787 * IUT that causes it to send an unreasonable Timing Advance value > 0 despite
788 * no active TBF exists at the moment of establishment (idle mode). */
789testcase TC_ta_idle_dl_tbf_ass() runs on RAW_PCU_Test_CT {
790 var OCT4 tlli := f_rnd_octstring(4);
791 var GsmRrMessage rr_imm_ass;
792
793 /* Initialize NS/BSSGP side */
794 f_init_bssgp();
795
796 /* Initialize the PCU interface abstraction */
797 f_init_raw(testcasename());
798
799 /* Establish BSSGP connection to the PCU */
800 f_bssgp_establish();
801 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
802
803 /* SGSN sends some DL data, PCU will initiate Packet Downlink
804 * Assignment on CCCH (PCH). We don't care about the payload. */
805 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, f_rnd_octstring(10)));
806 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass); // TODO: match by TLLI!
807
808 /* Make sure that Timing Advance is 0 (the actual value is not known yet).
809 * As per 3GPP S 44.018, section 3.5.3.1.2, the network *shall* initiate
810 * the procedures defined in 3GPP TS 44.060 or use the polling mechanism. */
811 if (not match(rr_imm_ass, tr_IMM_TBF_ASS(ta := 0))) {
812 setverdict(fail, "Timing Advance value doesn't match");
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200813 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700814
815 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200816}
817
818/* Verify that the PCU generates valid PTCCH/D messages
819 * while neither Uplink nor Downlink TBF is established. */
820testcase TC_ta_ptcch_idle() runs on RAW_PCU_Test_CT {
821 var PTCCHDownlinkMsg ptcch_msg;
822 var PCUIF_Message pcu_msg;
823 timer T;
824
825 /* Initialize the PCU interface abstraction */
826 f_init_raw(testcasename());
827
828 /* Sent an RTS.req for PTCCH/D */
829 BTS.send(ts_PCUIF_RTS_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
830 sapi := PCU_IF_SAPI_PTCCH, fn := 0,
831 arfcn := 871, block_nr := 0));
832 T.start(5.0);
833 alt {
834 [] BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
835 sapi := PCU_IF_SAPI_PTCCH)) -> value pcu_msg {
836 log("Rx DATA.req message: ", pcu_msg);
837 setverdict(pass);
838 }
839 [] BTS.receive(PCUIF_Message:?) { repeat; }
840 [] T.timeout {
841 setverdict(fail, "Timeout waiting for a PTCCH/D block");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700842 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200843 }
844 }
845
846 ptcch_msg := dec_PTCCHDownlinkMsg(pcu_msg.u.data_req.data);
847 log("Decoded PTCCH/D message: ", ptcch_msg);
848
849 /* Make sure the message is encoded correctly
850 * TODO: do we expect all TA values to be equal '1111111'B? */
851 if (not match(ptcch_msg, tr_PTCCHDownlinkMsg)) {
852 setverdict(fail, "Malformed PTCCH/D message");
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200853 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700854
855 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200856}
857
858/* Test of correct Timing Advance during an active Uplink TBF.
859 *
860 * Unlike the circuit-switched domain, Uplink transmissions on PDCH time-slots
861 * are not continuous and there can be long time gaps between them. This happens
862 * due to a bursty nature of packet data. The actual Timing Advance of a MS may
863 * significantly change between such rare Uplink transmissions, so GPRS introduces
864 * additional mechanisms to control Timing Advance, and thus reduce interference
865 * between neighboring TDMA time-slots.
866 *
867 * At the moment of Uplink TBF establishment, initial Timing Advance is measured
868 * from ToA (Timing of Arrival) of an Access Burst. This is covered by another
869 * test case - TC_ta_rach_imm_ass. In response to that Access Burst the network
870 * sends Immediate Assignment on AGCH, which _may_ contain Timing Advance Index
871 * among with the initial Timing Advance value. And here PTCCH comes to play.
872 *
873 * PTCCH is a unidirectional channel on which the network can instruct a sub-set
874 * of 16 MS (whether TBFs are active or not) to adjust their Timing Advance
875 * continuously. To ensure continuous measurements of the signal propagation
876 * delay, the MSs shall transmit Access Bursts on Uplink (PTCCH/U) on sub-slots
877 * defined by an assigned Timing Advance Index (see 3GPP TS 45.002).
878 *
879 * The purpose of this test case is to verify the assignment of Timing Advance
880 * Index, and the process of Timing Advance notification on PTCCH/D. The MTC
881 * first establishes several Uplink TBFs, but does not transmit any Uplink
882 * blocks on them. During 4 TDMA multi-frame periods the MTC is sending RACH
883 * indications to the PCU, checking the correctness of two received PTCCH/D
884 * messages (period of PTCCH/D is two multi-frames).
885 */
886
887/* List of ToA values for Access Bursts to be sent on PTCCH/U,
888 * each ToA (Timing of Arrival) value is in units of 1/4 of
889 * a symbol (i.e. 1 symbol is 4 QTA units). */
890type record length(16) of int16_t PTCCH_TAI_ToA_MAP;
891const PTCCH_TAI_ToA_MAP ptcch_toa_map_def := {
892 0, 0, 0, 0,
893 0, 0, 0, 0,
894 0, 0, 0, 0,
895 0, 0, 0, 0
896};
897
898private altstep as_ta_ptcch(uint8_t bts_nr := 0, uint8_t trx_nr := 0, uint8_t ts_nr := 7,
899 in PTCCH_TAI_ToA_MAP toa_map := ptcch_toa_map_def)
900runs on RAW_PCU_Test_CT {
901 var RAW_PCU_Event event;
902 var integer ss;
903
904 /* Send Access Bursts on PTCCH/U for every TA Index */
905 [] BTS.receive(tr_RAW_PCU_EV(TDMA_EV_PTCCH_UL_BURST)) -> value event {
906 ss := f_tdma_ptcch_fn2ss(event.data.tdma_fn);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700907 if (ss < 0) { /* Shall not happen */
908 f_shutdown(__BFILE__, __LINE__);
909 }
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200910
911 log("Sending an Access Burst on PTCCH/U",
912 ", sub-slot=", ss, " (TAI)",
913 ", fn=", event.data.tdma_fn,
914 ", ToA=", toa_map[ss], " (QTA)");
915 /* TODO: do we care about RA and burst format? */
916 BTS.send(ts_PCUIF_RACH_IND(bts_nr, trx_nr, ts_nr,
917 ra := oct2int('3A'O),
918 is_11bit := 0,
919 burst_type := BURST_TYPE_0,
920 fn := event.data.tdma_fn,
921 arfcn := 871,
922 qta := toa_map[ss],
923 sapi := PCU_IF_SAPI_PTCCH));
924 repeat;
925 }
926}
927
928private function f_TC_ta_ptcch_ul_multi_tbf(in PTCCH_TAI_ToA_MAP ptcch_toa_map,
929 template PTCCHDownlinkMsg t_ta_msg)
930runs on RAW_PCU_Test_CT {
931 var PTCCHDownlinkMsg ta_msg;
932 var PCUIF_Message pcu_msg;
933 timer T;
934
935 /* First, send an RTS.req for the upcoming PTCCH/D block */
936 BTS.send(ts_PCUIF_RTS_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
937 sapi := PCU_IF_SAPI_PTCCH, fn := 0,
938 arfcn := 871, block_nr := 0));
939 T.start(2.0);
940 alt {
941 /* Keep sending of Access Bursts during two multi-frames (period of PTCCH/D)
942 * with increasing ToA (Timing of Arrival) values: 0, 7, 14, 28, 35... */
943 [] as_ta_ptcch(bts_nr := 0, trx_nr := 0, ts_nr := 7, toa_map := ptcch_toa_map);
944 /* In the end of 2nd multi-frame we should receive a PTCCH/D block */
945 [] BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
946 sapi := PCU_IF_SAPI_PTCCH)) -> value pcu_msg {
947 ta_msg := dec_PTCCHDownlinkMsg(pcu_msg.u.data_req.data);
948 log("Rx PTCCH/D message: ", ta_msg);
949
950 /* Make sure Timing Advance values match our expectations */
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700951 if (not match(ta_msg, t_ta_msg)) {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200952 setverdict(fail, "PTCCH/D message does not match: ", t_ta_msg);
953 }
954 }
955 [] BTS.receive { repeat; }
956 [] T.timeout {
957 setverdict(fail, "Timeout waiting for a PTCCH/D block");
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200958 }
959 }
960}
961
962testcase TC_ta_ptcch_ul_multi_tbf() runs on RAW_PCU_Test_CT {
963 var template PacketUlAssign t_ul_tbf_ass;
964 var PacketUlAssign ul_tbf_ass[7];
965 var GsmRrMessage rr_msg[7];
966 var boolean ok;
967
968 /* Initialize the PCU interface abstraction */
969 f_init_raw(testcasename());
970
971 /* Enable forwarding of PTCCH/U TDMA events to us */
972 BTS.send(ts_RAW_PCU_CMD(TDMA_CMD_ENABLE_PTCCH_UL_FWD));
973
974 /* Establish 7 Uplink TBFs (USF flag is 3 bits long, '111'B is reserved) */
975 for (var integer i := 0; i < 7; i := i + 1) {
976 ok := f_establish_tbf(rr_msg[i], ta := 0);
977 if (not ok) {
978 setverdict(fail, "Failed to establish an Uplink TBF #", i);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700979 break;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200980 }
981
982 /* Make sure we received an UL TBF Assignment */
983 if (match(rr_msg[i], tr_IMM_TBF_ASS(dl := false, rest := tr_IaRestOctets_ULAss(?)))) {
984 ul_tbf_ass[i] := rr_msg[i].payload.imm_ass.rest_octets.hh.pa.uldl.ass.ul;
985 log("Rx Uplink TBF assignment for #", i, ": ", ul_tbf_ass[i]);
986 } else {
987 setverdict(fail, "Failed to match UL TBF Assignment for #", i);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700988 break;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200989 }
990
991 /* We expect incremental TFI/USF assignment (dynamic allocation) */
992 t_ul_tbf_ass := tr_PacketUlDynAssign(tfi := i, usf := i);
993 if (not match(ul_tbf_ass[i], t_ul_tbf_ass)) {
994 setverdict(fail, "Failed to match Packet Uplink Assignment for #", i);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +0700995 break;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200996 }
997
998 /* We also expect Timing Advance Index to be a part of the assignment */
999 if (ul_tbf_ass[i].dynamic.ta_index != i) {
1000 setverdict(fail, "Failed to match Timing Advance Index for #", i);
1001 /* Keep going, the current OsmoPCU does not assign TA Index */
1002 }
1003 }
1004
1005 /* Prepare a list of ToA values for Access Bursts to be sent on PTCCH/U */
1006 var PTCCH_TAI_ToA_MAP toa_map := ptcch_toa_map_def;
1007 for (var integer i := 0; i < 7; i := i + 1) {
1008 /* ToA in units of 1/4 of a symbol */
1009 toa_map[i] := (i + 1) * 7 * 4;
1010 }
1011
1012 /* Now we have all 7 TBFs established in one-phase access mode,
1013 * however we will not be sending any data on them. Instead, we
1014 * will be sending RACH.ind on PTCCH/U during 4 multi-frame
1015 * periods (TAI 0..8), and then will check two PTCCH/D blocks.
1016 *
1017 * Why not 4 TBFs at once? Because Uplink is delayed by 3 TDMA
1018 * time-slots, so at the moment of scheduling a PTCCH/D block
1019 * the PCU has odd number of PTCCH/U Access Bursts received. */
1020 f_TC_ta_ptcch_ul_multi_tbf(toa_map, tr_PTCCHDownlinkMsg(
1021 tai0_ta := 7, tai1_ta := 14, tai2_ta := 21,
1022 /* Other values are not known (yet) */
1023 tai3_ta := ?));
1024 f_TC_ta_ptcch_ul_multi_tbf(toa_map, tr_PTCCHDownlinkMsg(
1025 tai0_ta := 7, tai1_ta := 14, tai2_ta := 21,
1026 tai3_ta := 28, tai4_ta := 35, tai5_ta := 42,
1027 /* Other values are out of our interest */
1028 tai6_ta := ?));
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001029
1030 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001031}
1032
1033/* Default link quality adaptation (Coding Scheme) ranges (inclusive).
1034 * OsmoPCU (VTY): cs link-quality-ranges cs1 6 cs2 5 8 cs3 7 13 cs4 12
1035 *
1036 * NOTE: the ranges are intentionally overlapping because OsmoPCU
1037 * does not change CS/MCS on the range borders (5-6, 7-8, 12-13). */
1038private template integer CS1_lqual_dB_range := (-infinity .. 6);
1039private template integer CS2_lqual_dB_range := (5 .. 8);
1040private template integer CS3_lqual_dB_range := (7 .. 13);
1041private template integer CS4_lqual_dB_range := (12 .. infinity);
1042
1043testcase TC_cs_lqual_ul_tbf() runs on RAW_PCU_Test_CT {
1044 var GsmRrMessage rr_imm_ass;
1045 var PacketUlAssign ul_tbf_ass;
1046 var RlcmacDlBlock dl_block;
1047 var PCUIF_Message pcu_msg;
1048 var octetstring data;
1049 var boolean ok;
1050 var uint32_t unused_fn;
1051
1052 /* Initialize the PCU interface abstraction */
1053 f_init_raw(testcasename());
1054
1055 f_pcuvty_set_allowed_cs_mcs();
1056 f_pcuvty_set_link_quality_ranges();
1057
1058 /* Establish an Uplink TBF */
1059 ok := f_establish_tbf(rr_imm_ass);
1060 if (not ok) {
1061 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001062 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001063 }
1064
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001065 /* Make sure we've got an Uplink TBF assignment */
1066 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001067
1068 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
1069 tfi := ul_tbf_ass.dynamic.tfi_assignment,
1070 cv := 15, /* 16 UL blocks to be sent (to be overridden in loop) */
1071 bsn := 0, /* TODO: what should be here? */
1072 blocks := { /* To be generated in loop */ });
1073
1074 /* HACK: patch missing TLLI; otherwise OsmoPCU rejects DATA.req */
1075 ul_data.data.tlli := '00000001'O;
1076
1077 /* The actual / old link quality values. We need to keep track of the old
1078 * (basically previous) link quality value, because OsmoPCU actually
1079 * changes the coding scheme if not only the actual, but also the old
1080 * value leaves the current link quality range (window). */
1081 var integer lqual := 0;
1082 var integer lqual_old;
1083
1084 /* 16 UL blocks (0 .. 15 dB, step = 1 dB) */
1085 for (var integer i := 0; i < 16; i := i + 1) {
1086 /* Prepare a new UL block (CV, random payload) */
1087 ul_data.data.mac_hdr.countdown := (15 - i);
1088 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1089
1090 /* Update the old / actual link quality */
1091 lqual_old := lqual;
1092 lqual := i;
1093
1094 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1095 log("Sending DATA.ind with link quality (dB): ", lqual);
1096 f_tx_rlcmac_ul_block(ul_data, lqual * 10);
1097
1098 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1099 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1100
1101 log("Rx Packet Uplink ACK / NACK with Channel Coding Command: ",
1102 dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd);
1103
1104 /* Match the received Channel Coding Command. Since we are increasing
1105 * the link quality value on each iteration and not decreasing, there
1106 * is no need to check the both old and current link quality values. */
1107 var template ChCodingCommand ch_coding;
1108 select (lqual_old) {
1109 case (CS1_lqual_dB_range) { ch_coding := CH_CODING_CS1; }
1110 case (CS2_lqual_dB_range) { ch_coding := CH_CODING_CS2; }
1111 case (CS3_lqual_dB_range) { ch_coding := CH_CODING_CS3; }
1112 case (CS4_lqual_dB_range) { ch_coding := CH_CODING_CS4; }
1113 }
1114
1115 if (not match(dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd, ch_coding)) {
1116 setverdict(fail, "Channel Coding does not match our expectations: ", ch_coding);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001117 }
1118 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001119
1120 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001121}
1122
1123/* Test the max UL CS set by VTY works fine */
1124testcase TC_cs_initial_ul() runs on RAW_PCU_Test_CT {
1125 var GsmRrMessage rr_imm_ass;
1126 var PacketUlAssign ul_tbf_ass;
1127 var RlcmacDlBlock dl_block;
1128 var boolean ok;
1129 var integer lqual_cb;
1130 var ChCodingCommand last_ch_coding;
1131 var uint32_t unused_fn;
1132
1133 /* Initialize the PCU interface abstraction */
1134 f_init_raw(testcasename());
1135
1136 /* Set initial UL CS to 3 */
1137 g_cs_initial_ul := 3;
1138 f_pcuvty_set_allowed_cs_mcs();
1139 f_pcuvty_set_link_quality_ranges();
1140
1141 /* Take lqual (dB->cB) so that we stay in that CS */
1142 lqual_cb := g_cs_lqual_ranges[2].low * 10;
1143
1144 /* Establish an Uplink TBF */
1145 ok := f_establish_tbf(rr_imm_ass);
1146 if (not ok) {
1147 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001148 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001149 }
1150
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001151 /* Make sure we've got an Uplink TBF assignment */
1152 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001153
1154 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
1155 tfi := ul_tbf_ass.dynamic.tfi_assignment,
1156 cv := 3, /* 8 UL blocks to be sent (to be overridden in loop) */
1157 bsn := 0, /* TODO: what should be here? */
1158 blocks := { /* To be generated in loop */ });
1159
1160 /* HACK: patch missing TLLI; otherwise OsmoPCU rejects DATA.req */
1161 ul_data.data.tlli := '00000001'O;
1162
1163 /* 3 UL blocks, check we are in same initial CS: */
1164 for (var integer i := 0; i < 3; i := i + 1) {
1165 /* Prepare a new UL block (CV, random payload) */
1166 ul_data.data.mac_hdr.countdown := (7 - i);
1167 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1168
1169 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1170 f_tx_rlcmac_ul_block(ul_data, lqual_cb);
1171
1172 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1173 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1174 last_ch_coding := dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd;
1175 }
1176
1177 if (last_ch_coding != CH_CODING_CS3) {
1178 setverdict(fail, "Channel Coding does not match our expectations (CS-3): ", last_ch_coding);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001179 }
1180
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001181 /* Remaining UL blocks are used to make sure regardless of initial
1182 /* lqual, we can go lower at any time */
1183
1184 /* 5 UL blocks, check we are in same initial CS: */
1185 for (var integer i := 3; i < 8; i := i + 1) {
1186 /* Prepare a new UL block (CV, random payload) */
1187 ul_data.data.mac_hdr.countdown := (7 - i);
1188 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1189
1190 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1191 f_tx_rlcmac_ul_block(ul_data, 0); /* 0 dB, make sure we downgrade CS */
1192
1193 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1194 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1195
1196 last_ch_coding := dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd;
1197 }
1198
1199 if (last_ch_coding != CH_CODING_CS1) {
1200 setverdict(fail, "Channel Coding does not match our expectations (CS-1): ", last_ch_coding);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001201 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001202
1203 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001204}
1205
1206/* Test the max UL CS set by VTY works fine */
1207testcase TC_cs_max_ul() runs on RAW_PCU_Test_CT {
1208 var GsmRrMessage rr_imm_ass;
1209 var PacketUlAssign ul_tbf_ass;
1210 var RlcmacDlBlock dl_block;
1211 var boolean ok;
1212 var ChCodingCommand last_ch_coding;
1213 var uint32_t unused_fn;
1214
1215 /* Initialize the PCU interface abstraction */
1216 f_init_raw(testcasename());
1217
1218 /* Set maximum allowed UL CS to 3 */
1219 g_cs_max_ul := 3;
1220 f_pcuvty_set_allowed_cs_mcs();
1221 f_pcuvty_set_link_quality_ranges();
1222
1223 /* Establish an Uplink TBF */
1224 ok := f_establish_tbf(rr_imm_ass);
1225 if (not ok) {
1226 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001227 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001228 }
1229
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001230 /* Make sure we've got an Uplink TBF assignment */
1231 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001232
1233 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
1234 tfi := ul_tbf_ass.dynamic.tfi_assignment,
1235 cv := 15, /* 16 UL blocks to be sent (to be overridden in loop) */
1236 bsn := 0, /* TODO: what should be here? */
1237 blocks := { /* To be generated in loop */ });
1238
1239 /* HACK: patch missing TLLI; otherwise OsmoPCU rejects DATA.req */
1240 ul_data.data.tlli := '00000001'O;
1241
1242 /* 16 UL blocks */
1243 for (var integer i := 0; i < 16; i := i + 1) {
1244 /* Prepare a new UL block (CV, random payload) */
1245 ul_data.data.mac_hdr.countdown := (15 - i);
1246 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1247
1248 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1249 f_tx_rlcmac_ul_block(ul_data, 40*10); /* 40 dB */
1250
1251 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1252 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1253
1254 last_ch_coding := dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd;
1255 }
1256
1257 if (last_ch_coding != CH_CODING_CS3) {
1258 setverdict(fail, "Channel Coding does not match our expectations (CS-3): ", last_ch_coding);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001259 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001260
1261 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001262}
1263
1264/* Verify PCU drops TBF after some time of inactivity. */
1265testcase TC_t3169() runs on RAW_PCU_Test_CT {
1266 var PCUIF_info_ind info_ind;
1267 var GsmRrMessage rr_imm_ass;
1268 var PacketUlAssign ul_tbf_ass;
1269 var RlcmacDlBlock dl_block;
1270 var PCUIF_Message pcu_msg;
1271 var octetstring data;
1272 var boolean ok;
1273 var uint32_t unused_fn;
1274 var OCT4 tlli := '00000001'O;
1275
1276 /* Initialize NS/BSSGP side */
1277 f_init_bssgp();
1278
1279 info_ind := valueof(ts_PCUIF_INFO_default);
1280 /* Set timer to 1 sec (default 5) to speedup test: */
1281 info_ind.t3169 := 1;
1282
1283 /* Initialize the PCU interface abstraction */
1284 f_init_raw(testcasename(), info_ind);
1285
1286 /* Establish BSSGP connection to the PCU */
1287 f_bssgp_establish();
1288 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1289
1290 /* Establish an Uplink TBF */
1291 ok := f_establish_tbf(rr_imm_ass);
1292 if (not ok) {
1293 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001294 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001295 }
1296
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001297 /* Make sure we've got an Uplink TBF assignment */
1298 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001299
Pau Espin Pedrol4aac3d02020-05-13 15:13:49 +02001300 /* Send one UL block (with TLLI since we are in One-Phase Access
1301 contention resoultion) and make sure it is ACKED fine */
1302 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1, tlli);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001303 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1304 /* UL block should be received in SGSN */
1305 BSSGP[0].receive(tr_BSSGP_UL_UD(tlli, mp_gb_cfg.cell_id));
1306
1307 /* Wait until T3169 fires (plus 1 extra sec to make sure) */
1308 f_sleep(int2float(info_ind.t3169) + 1.0);
1309
1310 /* Send an UL block once again, the TBF should be gone by now so no ACK */
1311 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1);
1312 f_rx_rlcmac_dl_block_exp_dummy(dl_block);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001313
1314 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001315}
1316
1317/* Verify that a Downlink TBF can be assigned using PACCH shortly after the
1318 * release of prev DL TBF due to MS staying in PDCH for a while (T3192, in PCU
1319 * T3193) after DL TBF release */
1320testcase TC_t3193() runs on RAW_PCU_Test_CT {
1321 var GsmRrMessage rr_imm_ass;
1322 var PacketDlAssign dl_tbf_ass;
1323 var RlcmacDlBlock dl_block;
1324 var octetstring data := f_rnd_octstring(10);
1325 var boolean ok;
1326 var uint32_t sched_fn;
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001327 var uint32_t dl_fn;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001328 var OCT4 tlli := '00000001'O;
1329 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1330
1331 /* Initialize NS/BSSGP side */
1332 f_init_bssgp();
1333
1334 /* Initialize the PCU interface abstraction */
1335 f_init_raw(testcasename());
1336
1337 /* Establish BSSGP connection to the PCU */
1338 f_bssgp_establish();
1339 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1340
1341 /* SGSN sends some DL data, PCU will page on CCCH (PCH) */
1342 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1343 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001344
1345 /* Make sure we've got a Downlink TBF assignment */
1346 f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1347
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001348 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1349 f_sleep(X2002);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001350 f_rx_rlcmac_dl_block_exp_data(dl_block, dl_fn, data, 0);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001351
1352 /* ACK the DL block */
1353 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001354 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc),
1355 0, f_dl_block_ack_fn(dl_block, dl_fn));
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001356 /* we are done with the DL-TBF here so far, let's clean up our local state: */
1357 ack_nack_desc := valueof(t_AckNackDescription_init)
1358
1359 /* Now that final DL block is ACKED and TBF is released, T3193 in PCU
1360 (T3192 in MS) was started and until it fires the MS will be abailable
1361 on PDCH in case new data arrives from SGSN. Let's verify it: */
1362 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1363 f_rx_rlcmac_dl_block_exp_pkt_ass(dl_block, sched_fn);
1364 f_tx_rlcmac_ul_block(ts_RLCMAC_CTRL_ACK(tlli), 0, sched_fn);
1365
1366 /* Now that we confirmed the new assignment in the dl-tbf, lets receive the data and ack it */
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001367 f_rx_rlcmac_dl_block_exp_data(dl_block, dl_fn, data, 0);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001368 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001369 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc),
1370 0, f_dl_block_ack_fn(dl_block, dl_fn));
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001371
1372 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001373}
1374
1375/* Test scenario where MS wants to send some data on PDCH against SGSN and it is
1376 * answered, so TBFs for uplink and later for downlink are created.
1377 */
1378private function f_TC_mo_ping_pong(template (omit) MSRadioAccessCapabilityV ms_racap := omit, template (present) CodingScheme exp_cs_mcs := ?) runs on RAW_PCU_Test_CT {
1379 var GsmRrMessage rr_imm_ass;
1380 var PacketUlAssign ul_tbf_ass;
1381 var PacketDlAssign dl_tbf_ass;
1382 var RlcmacDlBlock dl_block;
1383 var PCUIF_Message pcu_msg;
1384 var octetstring data := f_rnd_octstring(10);
1385 var boolean ok;
1386 var uint32_t sched_fn;
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001387 var uint32_t dl_fn;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001388 var OCT4 tlli := '00000001'O;
1389 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1390
1391 /* Initialize NS/BSSGP side */
1392 f_init_bssgp();
1393
1394 /* Initialize the PCU interface abstraction */
1395 f_init_raw(testcasename());
1396
1397 /* Establish BSSGP connection to the PCU */
1398 f_bssgp_establish();
1399 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1400
1401 /* Establish an Uplink TBF */
1402 ok := f_establish_tbf(rr_imm_ass);
1403 if (not ok) {
1404 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001405 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001406 }
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001407
1408 /* Make sure we've got an Uplink TBF assignment */
1409 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001410
1411 if (not istemplatekind(ms_racap, "omit")) {
1412 /* Send PACKET RESOURCE REQUEST to upgrade to EGPRS
1413 * (see 3GPP TS 04.60 "7.1.3.1 Initiation of the Packet resource request procedure")
1414 */
1415 f_tx_rlcmac_ul_block(ts_RLC_UL_CTRL_ACK(valueof(ts_RlcMacUlCtrl_PKT_RES_REQ(tlli, ms_racap))), 0);
1416 f_rx_rlcmac_dl_block_exp_pkt_ul_ass(dl_block, sched_fn);
1417 if (dl_block.ctrl.payload.u.ul_assignment.identity.tlli.tlli != tlli) {
1418 setverdict(fail, "Wrong TLLI ", dl_block.ctrl.payload.u.ul_assignment.identity.tlli, " received vs exp ", tlli);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001419 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001420 }
1421 }
1422
Pau Espin Pedrol4aac3d02020-05-13 15:13:49 +02001423 /* Send one UL block (with TLLI since we are in One-Phase Access
1424 contention resoultion) and make sure it is ACKED fine */
1425 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1, tlli);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001426 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, sched_fn);
1427 /* DL ACK/NACK sets poll+rrbp requesting PACKET CONTROL ACK */
1428 f_tx_rlcmac_ul_block(ts_RLCMAC_CTRL_ACK(tlli), 0, sched_fn);
1429
1430 /* UL block should be received in SGSN */
1431 BSSGP[0].receive(tr_BSSGP_UL_UD(tlli, mp_gb_cfg.cell_id));
1432
1433 /* Now SGSN sends some DL data, PCU will page on CCCH (PCH) */
1434 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1435 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1436
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001437 /* Make sure we've got a Downlink TBF assignment */
1438 f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001439
1440 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1441 f_sleep(X2002);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001442 f_rx_rlcmac_dl_block_exp_data(dl_block, dl_fn, data, 0, exp_cs_mcs);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001443
1444 /* ACK the DL block */
1445 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001446 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc),
1447 0, f_dl_block_ack_fn(dl_block, dl_fn));
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001448
1449 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001450}
1451
1452/* Test scenario where MS wants to send some data on PDCH against SGSN and it is
1453 * answered, so TBFs for uplink and later for downlink are created.
1454 */
1455testcase TC_mo_ping_pong() runs on RAW_PCU_Test_CT {
1456 var CodingScheme exp_cs_mcs := CS_1;
1457 f_TC_mo_ping_pong(omit, exp_cs_mcs);
1458}
1459
1460
1461testcase TC_mo_ping_pong_with_ul_racap() runs on RAW_PCU_Test_CT {
1462 var MultislotCap_GPRS mscap_gprs := {
1463 gprsmultislotclass := '00011'B,
1464 gprsextendeddynalloccap := '0'B
1465 };
1466 var MSRadioAccessCapabilityV ms_racap := { valueof(ts_RaCapRec('0001'B /* E-GSM */, mscap_gprs, omit)) };
1467 var CodingScheme exp_cs_mcs := CS_2;
1468
1469 f_TC_mo_ping_pong(ms_racap, exp_cs_mcs);
1470}
1471
1472/* Test scenario where SGSN wants to send some data against MS and it is
1473 * answered by the MS on PDCH, so TBFs for downlink and later for uplink are created.
1474 */
1475private function f_TC_mt_ping_pong(template (omit) MSRadioAccessCapabilityV_BSSGP ms_racap := omit, template (present) CodingScheme exp_cs_mcs := ?) runs on RAW_PCU_Test_CT {
1476 var GsmRrMessage rr_imm_ass;
1477 var PacketUlAssign ul_tbf_ass;
1478 var PacketDlAssign dl_tbf_ass;
1479 var RlcmacDlBlock dl_block;
1480 var PCUIF_Message pcu_msg;
1481 var octetstring data := f_rnd_octstring(10);
1482 var boolean ok;
1483 var uint32_t sched_fn;
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001484 var uint32_t dl_fn;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001485 var OCT4 tlli := '00000001'O;
1486 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1487
1488 /* Initialize NS/BSSGP side */
1489 f_init_bssgp();
1490
1491 /* Initialize the PCU interface abstraction */
1492 f_init_raw(testcasename());
1493
1494 /* Establish BSSGP connection to the PCU */
1495 f_bssgp_establish();
1496 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1497
1498 /* SGSN sends some DL data, PCU will page on CCCH (PCH) */
1499 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data, ms_racap));
1500 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1501
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001502 /* Make sure we've got a Downlink TBF assignment */
1503 f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001504
1505 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1506 f_sleep(X2002);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001507 f_rx_rlcmac_dl_block_exp_data(dl_block, dl_fn, data, 0, exp_cs_mcs);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001508
1509 /* ACK the DL block */
1510 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001511 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc),
1512 0, f_dl_block_ack_fn(dl_block, dl_fn));
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001513
1514 /* Now MS wants to answer the DL data, Establish an Uplink TBF */
1515 ok := f_establish_tbf(rr_imm_ass);
1516 if (not ok) {
1517 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001518 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001519 }
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001520
1521 /* Make sure we've got an Uplink TBF assignment */
1522 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001523
Pau Espin Pedrol4aac3d02020-05-13 15:13:49 +02001524 /* Send one UL block (with TLLI since we are in One-Phase Access
1525 contention resoultion) and make sure it is ACKED fine */
1526 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1, tlli);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001527 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, sched_fn);
1528 /* DL ACK/NACK sets poll+rrbp requesting PACKET CONTROL ACK */
1529 f_tx_rlcmac_ul_block(ts_RLCMAC_CTRL_ACK(tlli), 0, sched_fn);
1530
1531 /* UL block should be received in SGSN */
1532 BSSGP[0].receive(tr_BSSGP_UL_UD(tlli, mp_gb_cfg.cell_id));
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001533
1534 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001535}
1536
1537testcase TC_mt_ping_pong() runs on RAW_PCU_Test_CT {
1538 var CodingScheme exp_cs_mcs := CS_1;
1539 f_TC_mt_ping_pong(omit, exp_cs_mcs);
1540}
1541
1542/* TC_mt_ping_pong, but DL-UNITDATA contains RA Access capability with (M)CS
1543/* information about the MS */
1544testcase TC_mt_ping_pong_with_dl_racap() runs on RAW_PCU_Test_CT {
1545 var MultislotCap_GPRS_BSSGP mscap_gprs := {
1546 gprsmultislotclass := '00011'B,
1547 gprsextendeddynalloccap := '0'B
1548 } ;
1549 var MSRadioAccessCapabilityV_BSSGP ms_racap := { valueof(ts_RaCapRec_BSSGP('0001'B /* E-GSM */, mscap_gprs, omit)) };
1550 var CodingScheme exp_cs_mcs := CS_2;
1551 f_TC_mt_ping_pong(ms_racap, exp_cs_mcs);
1552}
1553
1554/* Verify that if PCU doesn't get an ACK for first DL block after IMM ASS, it
1555 * will retry by retransmitting both the IMM ASS + DL block after poll (ack)
1556 * timeout occurs (specified by sent RRBP on DL block). */
1557testcase TC_imm_ass_dl_block_retrans() runs on RAW_PCU_Test_CT {
1558 var GsmRrMessage rr_imm_ass;
1559 var PacketDlAssign dl_tbf_ass;
1560 var RlcmacDlBlock dl_block;
1561 var octetstring data := f_rnd_octstring(10);
1562 var boolean ok;
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001563 var uint32_t dl_fn;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001564 var OCT4 tlli := '00000001'O;
1565 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1566
1567 /* Initialize NS/BSSGP side */
1568 f_init_bssgp();
1569
1570 /* Initialize the PCU interface abstraction */
1571 f_init_raw(testcasename());
1572
1573 /* Establish BSSGP connection to the PCU */
1574 f_bssgp_establish();
1575 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1576
1577 /* SGSN sends some DL data, PCU will page on CCCH (PCH) */
1578 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1579 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001580
1581 /* Make sure we've got a Downlink TBF assignment */
1582 f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001583
1584 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1585 f_sleep(X2002);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001586 f_rx_rlcmac_dl_block_exp_data(dl_block, dl_fn, data, 0);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001587
1588 /* Now we don't ack the dl block (emulate MS failed receiveing IMM ASS
1589 * or GPRS DL, or DL ACK was lost for some reason). As a result, PCU
1590 * should retrigger IMM ASS + GPRS DL procedure after poll timeout. */
1591 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001592
1593 /* Make sure we've got a Downlink TBF assignment */
1594 f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1595
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001596 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1597 f_sleep(X2002);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001598 f_rx_rlcmac_dl_block_exp_data(dl_block, dl_fn, data, 0);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001599
1600 /* ACK the DL block */
1601 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
Vadim Yanitskiyb6733a62020-05-10 14:39:00 +07001602 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc),
1603 0, f_dl_block_ack_fn(dl_block, dl_fn));
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001604
1605 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001606}
1607
Vadim Yanitskiy71238c12020-05-11 03:48:06 +07001608/* Verify scheduling of multiple Downlink data blocks during one RRBP. */
1609testcase TC_dl_flow_more_blocks() runs on RAW_PCU_Test_CT {
1610 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1611 var octetstring data := f_rnd_octstring(16);
1612 var OCT4 tlli := f_rnd_octstring(4);
1613 var PacketDlAssign dl_tbf_ass;
1614 var GsmRrMessage rr_imm_ass;
1615 var RlcmacDlBlock dl_block;
1616 var uint32_t ack_fn;
1617 var uint32_t fn;
1618 timer T := 5.0;
1619
1620 /* Initialize NS/BSSGP side */
1621 f_init_bssgp();
1622
1623 /* Initialize the PCU interface abstraction */
1624 f_init_raw(testcasename());
1625
1626 /* Establish BSSGP connection to the PCU */
1627 f_bssgp_establish();
1628 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1629
1630 /* SGSN sends some DL data, PCU will page on CCCH (PCH) */
1631 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1632 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1633
1634 /* Make sure we've got a Downlink TBF assignment with DL TFI */
1635 f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1636 if (not ispresent(dl_tbf_ass.group1)) {
1637 setverdict(fail, "Immediate Assignment contains no DL TFI");
1638 f_shutdown(__BFILE__, __LINE__);
1639 }
1640
1641 /* Get DL TFI from received Downlink TBF assignment */
1642 var uint5_t tfi := dl_tbf_ass.group1.tfi_assignment;
1643
1644 /* Wait timer X2002 and DL block is available after CCCH IMM ASS */
1645 f_sleep(X2002);
1646
1647 /* Expect the first (GPRS DL) block with bsn=0 and rrbp_valid=1 */
1648 f_rx_rlcmac_dl_block_exp_data(dl_block, fn, data, 0);
1649 f_acknackdesc_ack_block(ack_nack_desc, dl_block);
1650
1651 /* TDMA frame number on which we are supposed to send the ACK */
1652 ack_fn := f_dl_block_ack_fn(dl_block, fn);
1653
1654 /* SGSN sends more blocks during the indicated RRBP */
1655 for (var integer bsn := 1; bsn < 63; bsn := bsn + 1) {
1656 data := f_rnd_octstring(16); /* Random LLC data */
1657 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1658
1659 f_rx_rlcmac_dl_block_exp_data(dl_block, fn, data, bsn);
1660
1661 /* Make sure this block has the same TFI as was assigned
1662 * FIXME: this is only valid for GPRS, not EGPRS. */
1663 if (dl_block.data.mac_hdr.hdr_ext.tfi != tfi) {
1664 setverdict(fail, "Rx DL data block with unexpected TFI: ",
1665 dl_block.data.mac_hdr.hdr_ext.tfi);
1666 f_shutdown(__BFILE__, __LINE__);
1667 }
1668
1669 /* Keep Ack/Nack description updated */
1670 f_acknackdesc_ack_block(ack_nack_desc, dl_block);
1671
1672 /* Break if this is the end of RRBP */
1673 if (fn == ack_fn) {
1674 ack_nack_desc.final_ack := '1'B;
1675 break;
1676 }
1677 }
1678
1679 /* This is the end of RRBP, send Packet Downlink Ack/Nack */
1680 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(tfi, ack_nack_desc), fn := fn);
1681
1682 /* Make sure that the next block (after the Ack) is dummy */
1683 f_rx_rlcmac_dl_block_exp_dummy(dl_block);
1684
1685 f_shutdown(__BFILE__, __LINE__, final := true);
1686}
1687
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001688private function f_pkt_paging_match_imsi(in PacketPagingReq req, hexstring imsi)
1689runs on RAW_PCU_Test_CT {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001690 var MobileIdentityLV_Paging mi_lv := req.repeated_pageinfo.cs.mobile_identity;
1691 var MobileIdentityV mi := dec_MobileIdentityV(mi_lv.mobile_id);
1692
1693 if (mi_lv.len != 8) { /* 8 octets: type of ID (3 bits) + even/odd flag (1 bit) + 15 BCD-encoded digits (60 bits) */
1694 setverdict(fail, "Mobile Identity length mismatch: ",
1695 "expected: 8, got: ", mi_lv.len);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001696 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001697 }
1698
1699 /* Make sure MI contains IMSI before referencing it */
1700 if (mi.typeOfIdentity != '001'B) {
1701 setverdict(fail, "Mobile Identity must be of type IMSI ('001'B), ",
1702 "got: ", mi.typeOfIdentity);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001703 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001704 } else if (mi.oddEvenInd_identity.imsi.digits != imsi) {
1705 setverdict(fail, "Mobile Identity contains unexpected IMSI, ",
1706 "expected: ", imsi, " got: ", mi.oddEvenInd_identity.imsi.digits);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001707 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001708 }
1709}
1710
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001711private function f_pkt_paging_match_tmsi(in PacketPagingReq req, template GsmTmsi tmsi)
1712runs on RAW_PCU_Test_CT {
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001713 if (not match(req.repeated_pageinfo.cs.tmsi, tmsi)) {
1714 setverdict(fail, "Mobile Identity (TMSI/P-TMSI) mismatch: ",
1715 "expected: ", tmsi, "got: ", req.repeated_pageinfo.cs.tmsi);
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001716 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001717 }
1718}
1719
1720/* Test CS paging over the BTS<->PCU socket.
1721 * When a (class B or C, not A) MS has an active TBF (or is on the PDCH), the MS can not react on CS paging over CCCH.
1722 * Paging should be send on the PACCH.
1723 *
1724 * 1. Send a Paging Request over PCU socket.
1725 * 2. Send a Ready-To-Send message over PCU socket
1726 * 3. Expect a Paging Frame
1727 */
1728testcase TC_paging_cs_from_bts() runs on RAW_PCU_Test_CT {
1729 var GsmRrMessage rr_imm_ass;
1730 var PacketUlAssign ul_tbf_ass;
1731 var RlcmacDlBlock dl_block;
1732 var boolean ok;
1733 var OCT4 tlli := '00000001'O;
1734 var MobileIdentityLV mi;
1735 var octetstring mi_enc_lv;
1736 var hexstring imsi := f_gen_imsi(42);
1737
1738 /* Initialize NS/BSSGP side */
1739 f_init_bssgp();
1740
1741 /* Initialize the PCU interface abstraction */
1742 f_init_raw(testcasename());
1743
1744 /* Establish BSSGP connection to the PCU */
1745 f_bssgp_establish();
1746 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1747
1748 /* Establish an Uplink TBF */
1749 ok := f_establish_tbf(rr_imm_ass);
1750 if (not ok) {
1751 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001752 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001753 }
1754
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001755 /* Make sure we've got an Uplink TBF assignment */
1756 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001757
1758 /* build mobile Identity */
1759 mi := valueof(ts_MI_IMSI_LV(imsi));
1760 mi_enc_lv := enc_MobileIdentityLV(mi);
1761 /* Send paging request */
1762 BTS.send(ts_PCUIF_PAG_REQ(bts_nr := 0, id_lv := mi_enc_lv, chan_needed := 0,
1763 sapi :=PCU_IF_SAPI_PDTCH));
1764
1765 /* Receive it on BTS side towards MS */
1766 f_rx_rlcmac_dl_block_exp_pkt_pag_req(dl_block);
1767
1768 /* Make sure that Packet Paging Request contains the same IMSI */
1769 f_pkt_paging_match_imsi(dl_block.ctrl.payload.u.paging, imsi);
1770
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001771 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001772}
1773
1774/* Test CS paging over Gb (SGSN->PCU->BTS[PDCH]).
1775 */
1776private function f_tc_paging_cs_from_sgsn(Nsvci bvci, boolean use_ptmsi := false)
1777runs on RAW_PCU_Test_CT {
1778 var GsmRrMessage rr_imm_ass;
1779 var PacketUlAssign ul_tbf_ass;
1780 var RlcmacDlBlock dl_block;
1781 var boolean ok;
1782 var OCT4 tlli := '00000001'O;
1783 var hexstring imsi := f_gen_imsi(42);
1784 var GsmTmsi tmsi;
1785
1786 /* Initialize NS/BSSGP side */
1787 f_init_bssgp();
1788
1789 /* Initialize the PCU interface abstraction */
1790 f_init_raw(testcasename());
1791
1792 /* Establish BSSGP connection to the PCU */
1793 f_bssgp_establish();
1794 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1795
1796 /* Establish an Uplink TBF */
1797 ok := f_establish_tbf(rr_imm_ass);
1798 if (not ok) {
1799 setverdict(fail, "Failed to establish TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001800 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001801 }
1802
Vadim Yanitskiy2e213ae2020-05-06 22:26:17 +07001803 /* Make sure we've got an Uplink TBF assignment */
1804 f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001805
1806 /* Send paging request with or without TMSI */
1807 if (use_ptmsi) {
1808 tmsi := oct2int(f_rnd_octstring(4)); /* Random P-TMSI */
1809 BSSGP[0].send(ts_BSSGP_CS_PAGING_PTMSI(bvci, imsi, tmsi));
1810 } else {
1811 BSSGP[0].send(ts_BSSGP_CS_PAGING_IMSI(bvci, imsi));
1812 }
1813
1814 /* Receive it on BTS side towards MS */
1815 f_rx_rlcmac_dl_block_exp_pkt_pag_req(dl_block);
1816
1817 /* Make sure that Packet Paging Request contains the same P-TMSI/IMSI */
1818 if (use_ptmsi) {
1819 f_pkt_paging_match_tmsi(dl_block.ctrl.payload.u.paging, tmsi);
1820 } else {
1821 f_pkt_paging_match_imsi(dl_block.ctrl.payload.u.paging, imsi);
1822 }
1823
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001824 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001825}
1826
1827testcase TC_paging_cs_from_sgsn_sign_ptmsi() runs on RAW_PCU_Test_CT {
1828 f_tc_paging_cs_from_sgsn(0, true);
1829}
1830
1831testcase TC_paging_cs_from_sgsn_sign() runs on RAW_PCU_Test_CT {
1832 f_tc_paging_cs_from_sgsn(0);
1833}
1834
1835testcase TC_paging_cs_from_sgsn_ptp() runs on RAW_PCU_Test_CT {
1836 f_tc_paging_cs_from_sgsn(mp_gb_cfg.bvci);
1837}
1838
1839/* Test PS paging over Gb (SGSN->PCU->BTS[CCCH]).
1840 */
1841private function f_tc_paging_ps_from_sgsn(Nsvci bvci, boolean use_ptmsi := false)
1842runs on RAW_PCU_Test_CT {
1843 var OCT4 tlli := '00000001'O;
1844 var integer imsi_suff_tx := 423;
1845 var hexstring imsi := f_gen_imsi(imsi_suff_tx);
1846
1847 /* Initialize NS/BSSGP side */
1848 f_init_bssgp();
1849
1850 /* Initialize the PCU interface abstraction */
1851 f_init_raw(testcasename());
1852
1853 /* Establish BSSGP connection to the PCU */
1854 f_bssgp_establish();
1855 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1856
1857 /* Send BSSGP PAGING-PS (with or without TMSI), wait for RR Paging Request Type 1.
1858 * Make sure that both paging group (IMSI suffix) and Mobile Identity match. */
1859 if (use_ptmsi) {
1860 var OCT4 tmsi := f_rnd_octstring(4); /* Random P-TMSI */
1861 BSSGP[0].send(ts_BSSGP_PS_PAGING_PTMSI(bvci, imsi, oct2int(tmsi)));
1862 f_pcuif_rx_pch_pag_req1(t_MI_TMSI(tmsi), imsi_suff_tx);
1863 } else {
1864 BSSGP[0].send(ts_BSSGP_PS_PAGING_IMSI(bvci, imsi));
1865 f_pcuif_rx_pch_pag_req1(tr_MI_IMSI(imsi), imsi_suff_tx);
1866 }
1867
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001868 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001869}
1870
1871testcase TC_paging_ps_from_sgsn_sign_ptmsi() runs on RAW_PCU_Test_CT {
1872 f_tc_paging_ps_from_sgsn(0, true);
1873}
1874
1875testcase TC_paging_ps_from_sgsn_sign() runs on RAW_PCU_Test_CT {
1876 f_tc_paging_ps_from_sgsn(0);
1877}
1878
1879testcase TC_paging_ps_from_sgsn_ptp() runs on RAW_PCU_Test_CT {
1880 f_tc_paging_ps_from_sgsn(mp_gb_cfg.bvci);
1881}
1882
1883private function f_TC_egprs_pkt_chan_req(in EGPRSPktChRequest req,
1884 template GsmRrMessage t_imm_ass := ?,
1885 PCUIF_BurstType bt := BURST_TYPE_1)
1886runs on RAW_PCU_Test_CT {
1887 var GsmRrMessage rr_msg;
1888 var uint16_t ra11;
1889 var boolean ok;
1890
1891 ra11 := enc_EGPRSPktChRequest2uint(req);
1892 log("Sending EGPRS Packet Channel Request (", ra11, "): ", req);
1893
1894 ok := f_establish_tbf(rr_msg, ra := ra11, is_11bit := 1, burst_type := bt);
1895 if (not ok) {
1896 setverdict(fail, "Failed to establush an Uplink TBF");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001897 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001898 }
1899
1900 if (not match(rr_msg, t_imm_ass)) {
1901 setverdict(fail, "Immediate Assignment does not match");
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001902 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001903 }
1904
1905 setverdict(pass);
1906}
1907
1908testcase TC_egprs_pkt_chan_req_signalling() runs on RAW_PCU_Test_CT {
1909 var template GsmRrMessage imm_ass;
1910 var template IaRestOctets rest;
1911 var template EgprsUlAss ul_ass;
1912
1913 /* Initialize the PCU interface abstraction */
1914 f_init_raw(testcasename());
1915
1916 var EGPRSPktChRequest req := {
1917 /* NOTE: other fields are set in the loop */
1918 signalling := { tag := '110011'B }
1919 };
1920
1921 for (var integer i := 0; i < 6; i := i + 1) {
1922 var BIT5 ext_ra := int2bit(f_rnd_int(32), 5);
1923 req.signalling.random_bits := ext_ra;
1924
1925 /* For signalling, do we expect Multiblock UL TBF Assignment? */
1926 ul_ass := tr_EgprsUlAssMultiblock(ext_ra := ext_ra);
1927 rest := tr_IaRestOctets_EGPRSULAss(ul_ass);
1928 imm_ass := tr_IMM_TBF_ASS(dl := false, rest := rest);
1929
1930 f_TC_egprs_pkt_chan_req(req, imm_ass);
1931 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001932
1933 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001934}
1935
1936testcase TC_egprs_pkt_chan_req_one_phase() runs on RAW_PCU_Test_CT {
1937 var template GsmRrMessage imm_ass;
1938 var template IaRestOctets rest;
1939 var template EgprsUlAss ul_ass;
1940
1941 /* Initialize the PCU interface abstraction */
1942 f_init_raw(testcasename());
1943
1944 var EGPRSPktChRequest req := {
1945 /* NOTE: other fields are set in the loop */
1946 one_phase := { tag := '0'B }
1947 };
1948
1949 for (var integer i := 0; i < 6; i := i + 1) {
1950 var BIT5 ext_ra := int2bit(f_rnd_int(32), 5);
1951 var BIT5 mslot_class := int2bit(f_rnd_int(32), 5);
1952 var BIT2 priority := substr(ext_ra, 0, 2);
1953 var BIT3 rand := substr(ext_ra, 2, 3);
1954
1955 req.one_phase.multislot_class := mslot_class;
1956 req.one_phase.priority := priority;
1957 req.one_phase.random_bits := rand;
1958
1959 /* For one phase access, do we expect Dynamic UL TBF Assignment? */
1960 ul_ass := tr_EgprsUlAssDynamic(ext_ra := ext_ra);
1961 rest := tr_IaRestOctets_EGPRSULAss(ul_ass);
1962 imm_ass := tr_IMM_TBF_ASS(dl := false, rest := rest);
1963
1964 f_TC_egprs_pkt_chan_req(req, imm_ass);
1965 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001966
1967 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02001968}
1969
1970testcase TC_egprs_pkt_chan_req_two_phase() runs on RAW_PCU_Test_CT {
1971 var template GsmRrMessage imm_ass;
1972 var template IaRestOctets rest;
1973 var template EgprsUlAss ul_ass;
1974
1975 /* Initialize the PCU interface abstraction */
1976 f_init_raw(testcasename());
1977
1978 var EGPRSPktChRequest req := {
1979 /* NOTE: other fields are set in the loop */
1980 two_phase := { tag := '110000'B }
1981 };
1982
1983 for (var integer i := 0; i < 6; i := i + 1) {
1984 var BIT5 ext_ra := int2bit(f_rnd_int(32), 5);
1985 var BIT2 priority := substr(ext_ra, 0, 2);
1986 var BIT3 rand := substr(ext_ra, 2, 3);
1987
1988 req.two_phase.priority := priority;
1989 req.two_phase.random_bits := rand;
1990
1991 /* For two phase access, do we expect Multiblock UL TBF Assignment? */
1992 ul_ass := tr_EgprsUlAssMultiblock(ext_ra := ext_ra);
1993 rest := tr_IaRestOctets_EGPRSULAss(ul_ass);
1994 imm_ass := tr_IMM_TBF_ASS(dl := false, rest := rest);
1995
1996 f_TC_egprs_pkt_chan_req(req, imm_ass);
1997 }
Vadim Yanitskiy91f8a092020-05-06 21:41:05 +07001998
1999 f_shutdown(__BFILE__, __LINE__, final := true);
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02002000}
2001
2002control {
2003 execute( TC_pcuif_suspend() );
2004 execute( TC_ta_ptcch_idle() );
2005 execute( TC_ta_rach_imm_ass() );
2006 execute( TC_ta_idle_dl_tbf_ass() );
2007 execute( TC_ta_ptcch_ul_multi_tbf() );
2008 execute( TC_cs_lqual_ul_tbf() );
2009 execute( TC_cs_initial_ul() );
2010 execute( TC_cs_max_ul() );
2011 execute( TC_t3169() );
2012 execute( TC_t3193() );
2013 execute( TC_mo_ping_pong() );
2014 execute( TC_mo_ping_pong_with_ul_racap() );
2015 execute( TC_mt_ping_pong() );
2016 execute( TC_mt_ping_pong_with_dl_racap() );
2017 execute( TC_imm_ass_dl_block_retrans() );
Vadim Yanitskiy71238c12020-05-11 03:48:06 +07002018 execute( TC_dl_flow_more_blocks() );
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +02002019 execute( TC_paging_cs_from_bts() );
2020 execute( TC_paging_cs_from_sgsn_sign_ptmsi() );
2021 execute( TC_paging_cs_from_sgsn_sign() );
2022 execute( TC_paging_cs_from_sgsn_ptp() );
2023 execute( TC_paging_ps_from_sgsn_sign_ptmsi() );
2024 execute( TC_paging_ps_from_sgsn_sign() );
2025 execute( TC_paging_ps_from_sgsn_ptp() );
2026
2027 /* EGPRS specific test cases */
2028 execute( TC_egprs_pkt_chan_req_signalling() );
2029 execute( TC_egprs_pkt_chan_req_one_phase() );
2030 execute( TC_egprs_pkt_chan_req_two_phase() );
2031}
2032
2033
2034
2035
2036
2037
Harald Weltea419df22019-03-21 17:23:04 +01002038}