blob: a40819dacc3790170bd66b731f6dc2706646f0e0 [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 {
104 /* Connection to the BTS component (one for now) */
105 port RAW_PCU_MSG_PT BTS;
106 /* Connection to the PCUIF component */
107 port RAW_PCU_MSG_PT PCUIF;
108 /* VTY connection to the PCU */
109 port TELNETasp_PT PCUVTY;
110
111 /* Uplink CS/MCS thresholds, default from pcu_main.c: */
112 var lqual_range g_cs_lqual_ranges[4] := {{low := 0, high := 6},
113 {low := 5, high := 8},
114 {low := 7, high := 13},
115 {low := 12,high := 35}};
116 var lqual_range g_mcs_lqual_ranges[9] := {{low := 0, high := 6},
117 {low := 5, high := 8},
118 {low := 7, high := 13},
119 {low := 12,high := 15},
120 {low := 14, high := 17},
121 {low := 16, high := 18},
122 {low := 17,high := 20},
123 {low := 19, high := 24},
124 {low := 23,high := 35}};
125 var uint8_t g_cs_initial_dl := 1;
126 var uint8_t g_cs_initial_ul := 1;
127 var uint8_t g_mcs_initial_dl := 1;
128 var uint8_t g_mcs_initial_ul := 1;
129 var uint8_t g_cs_max_dl := 4;
130 var uint8_t g_cs_max_ul := 4;
131 var uint8_t g_mcs_max_dl := 9;
132 var uint8_t g_mcs_max_ul := 9;
133
134 var boolean g_egprs_only := false;
135
136 /* Guard timeout */
137 timer g_T_guard := 60.0;
138};
139
140private altstep as_Tguard_RAW() runs on RAW_PCU_Test_CT {
141 [] g_T_guard.timeout {
142 setverdict(fail, "Timeout of T_guard");
143 mtc.stop;
144 }
145}
146
147private function f_pcuvty_set_allowed_cs_mcs() runs on RAW_PCU_Test_CT {
148 f_vty_config2(PCUVTY, {"pcu"}, "cs " & int2str(g_cs_initial_dl) & " " & int2str(g_cs_initial_ul));
149 f_vty_config2(PCUVTY, {"pcu"}, "cs max " & int2str(g_cs_max_dl) & " " & int2str(g_cs_max_ul));
150
151 f_vty_config2(PCUVTY, {"pcu"}, "mcs " & int2str(g_mcs_initial_dl) & " " & int2str(g_mcs_initial_ul));
152 f_vty_config2(PCUVTY, {"pcu"}, "mcs max " & int2str(g_mcs_max_dl) & " " & int2str(g_mcs_max_ul));
153}
154
155private function f_pcuvty_set_link_quality_ranges() runs on RAW_PCU_Test_CT {
156 var charstring cmd;
157
158 cmd := "cs link-quality-ranges" &
159 " cs1 " & int2str(g_cs_lqual_ranges[0].high) &
160 " cs2 " & int2str(g_cs_lqual_ranges[1].low) & " " & int2str(g_cs_lqual_ranges[1].high) &
161 " cs3 " & int2str(g_cs_lqual_ranges[2].low) & " " & int2str(g_cs_lqual_ranges[2].high) &
162 " cs4 " & int2str(g_cs_lqual_ranges[3].low);
163 f_vty_config2(PCUVTY, {"pcu"}, cmd);
164
165 cmd := "mcs link-quality-ranges" &
166 " mcs1 " & int2str(g_mcs_lqual_ranges[0].high) &
167 " mcs2 " & int2str(g_mcs_lqual_ranges[1].low) & " " & int2str(g_mcs_lqual_ranges[1].high) &
168 " mcs3 " & int2str(g_mcs_lqual_ranges[2].low) & " " & int2str(g_mcs_lqual_ranges[2].high) &
169 " mcs4 " & int2str(g_mcs_lqual_ranges[3].low) & " " & int2str(g_mcs_lqual_ranges[3].high) &
170 " mcs5 " & int2str(g_mcs_lqual_ranges[4].low) & " " & int2str(g_mcs_lqual_ranges[4].high) &
171 " mcs6 " & int2str(g_mcs_lqual_ranges[5].low) & " " & int2str(g_mcs_lqual_ranges[5].high) &
172 " mcs7 " & int2str(g_mcs_lqual_ranges[6].low) & " " & int2str(g_mcs_lqual_ranges[6].high) &
173 " mcs8 " & int2str(g_mcs_lqual_ranges[7].low) & " " & int2str(g_mcs_lqual_ranges[7].high) &
174 " mcs9 " & int2str(g_mcs_lqual_ranges[8].low);
175 f_vty_config2(PCUVTY, {"pcu"}, cmd);
176}
177
178private function f_init_vty(charstring id) runs on RAW_PCU_Test_CT {
179 map(self:PCUVTY, system:PCUVTY);
180 f_vty_set_prompts(PCUVTY);
181 f_vty_transceive(PCUVTY, "enable");
182
183 if (g_egprs_only) {
184 f_vty_config2(PCUVTY, {"pcu"}, "egprs only");
185 } else {
186 f_vty_config2(PCUVTY, {"pcu"}, "no egprs");
187 }
188}
189
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200190function f_init_raw(charstring id, template (value) PCUIF_info_ind info_ind := ts_PCUIF_INFO_default)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200191runs on RAW_PCU_Test_CT {
192 var RAW_PCUIF_CT vc_PCUIF;
193 var RAW_PCU_BTS_CT vc_BTS;
194
195 /* Start the guard timer */
196 g_T_guard.start;
197 activate(as_Tguard_RAW());
198
199 /* Init PCU interface component */
200 vc_PCUIF := RAW_PCUIF_CT.create("PCUIF-" & id);
201 connect(vc_PCUIF:MTC, self:PCUIF);
202 map(vc_PCUIF:PCU, system:PCU);
203
204 /* Create one BTS component (we may want more some day) */
205 vc_BTS := RAW_PCU_BTS_CT.create("BTS-" & id);
206 connect(vc_BTS:PCUIF, vc_PCUIF:BTS);
207 connect(vc_BTS:TC, self:BTS);
208
209 f_init_vty(id);
210
211 vc_PCUIF.start(f_PCUIF_CT_handler(mp_pcu_sock_path));
212 vc_BTS.start(f_BTS_CT_handler(0, valueof(info_ind)));
213
214 /* Wait until the BTS is ready (SI13 negotiated) */
215 BTS.receive(tr_RAW_PCU_EV(BTS_EV_SI13_NEGO));
216}
217
218template AckNackDescription t_AckNackDescription_init := {
219 final_ack := '0'B,
220 starting_seq_nr := 0,
221 receive_block_bitmap := '0000000000000000000000000000000000000000000000000000000000000000'B
222}
223
224private function f_rlcmac_dl_block_get_tfi(RlcmacDlBlock dl_block) return uint5_t {
225 if (ischosen(dl_block.data)) {
226 return dl_block.data.mac_hdr.hdr_ext.tfi;
227 } else {
228 return dl_block.data_egprs.mac_hdr.tfi;
229 }
230}
231
232/* TS 44.060 sec 12.3 Ack/Nack Description */
233private function f_acknackdesc_ack_block(inout AckNackDescription desc, RlcmacDlBlock dl_block, BIT1 final_ack := '0'B)
234{
235 var uint7_t bsn;
236 var integer i;
237 var integer inc;
238
239 if (ischosen(dl_block.data)) {
240 bsn := dl_block.data.mac_hdr.hdr_ext.bsn;
241 } else {
242 bsn := dl_block.data_egprs.mac_hdr.bsn1;
243 }
244
245 inc := bsn - desc.starting_seq_nr + 1;
246 /* Filling hole? */
247 if (bsn < desc.starting_seq_nr) {
248 desc.receive_block_bitmap[lengthof(desc.receive_block_bitmap) - (desc.starting_seq_nr - bsn)] := int2bit(1, 1);
249 return;
250 }
251
252 /* SSN is increased, and so RBB values need to be moved */
253 for (i := 0; i < lengthof(desc.receive_block_bitmap) - inc; i := i+1) {
254 desc.receive_block_bitmap[i] := desc.receive_block_bitmap[i + inc];
255 }
256 for (i := lengthof(desc.receive_block_bitmap) - inc; i < lengthof(desc.receive_block_bitmap) - 1; i := i+1) {
257 desc.receive_block_bitmap[i] := int2bit(0, 1);
258 }
259 /* Now we can set current bit and update SSN */
260 desc.starting_seq_nr := bsn + 1;
261 desc.receive_block_bitmap[lengthof(desc.receive_block_bitmap) - 1] := int2bit(1, 1);
262
263 /* Finally update the final_ack bit as requested: */
264 desc.final_ack := final_ack;
265}
266
267/* This function can be used to send DATA.cnf in response to the IUT originated DATA.req.
268 * NOTE: it's the responsibility of caller to make sure that pcu_msg contains u.data_req. */
269private function f_pcuif_tx_data_cnf(in PCUIF_Message pcu_msg)
270runs on RAW_PCU_Test_CT {
271 var PCUIF_Message pcu_msg_cnf := {
272 msg_type := PCU_IF_MSG_DATA_CNF,
273 bts_nr := pcu_msg.bts_nr,
274 spare := pcu_msg.spare,
275 u := { data_cnf := pcu_msg.u.data_req }
276 };
277
278 /* PCU wants DATA.cnf containing basically everything that was in DATA.req,
279 * but PCU_IF_SAPI_PCH is a special case - paging group shall be excluded. */
280 if (pcu_msg.u.data_req.sapi == PCU_IF_SAPI_PCH) {
281 pcu_msg_cnf.u.data_cnf.data := substr(pcu_msg.u.data_req.data, 3,
282 pcu_msg.u.data_req.len - 3);
283 }
284
285 BTS.send(pcu_msg_cnf);
286}
287
288private function f_pcuif_rx_imm_ass(out GsmRrMessage rr_imm_ass,
289 template PCUIF_Sapi sapi := PCU_IF_SAPI_AGCH,
290 template GsmRrMessage t_imm_ass := ?,
291 uint8_t bts_nr := 0)
292runs on RAW_PCU_Test_CT return boolean {
293 var PCUIF_Message pcu_msg;
294 var octetstring data;
295 timer T;
296
297 T.start(2.0);
298 alt {
299 [] BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := bts_nr, trx_nr := 0, ts_nr := 0,
300 sapi := sapi, data := ?)) -> value pcu_msg {
301 /* On PCH the payload is prefixed with paging group (3 octets): skip it.
302 * TODO: add an additional template parameter, so we can match it. */
303 if (pcu_msg.u.data_req.sapi == PCU_IF_SAPI_PCH) {
304 data := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
305 } else {
306 data := pcu_msg.u.data_req.data;
307 }
308
309 rr_imm_ass := dec_GsmRrMessage(data);
310 if (not match(rr_imm_ass, t_imm_ass)) {
311 /* Not for us? Wait for more. */
312 repeat;
313 }
314
315 log("Rx Immediate Assignment: ", rr_imm_ass);
316 setverdict(pass);
317 return true;
318 }
319 [] BTS.receive { repeat; }
320 [] T.timeout {
321 setverdict(fail, "Timeout waiting for Immediate Assignment");
322 }
323 }
324
325 return false;
326}
327
Vadim Yanitskiyf74ae992020-05-06 16:05:51 +0700328/* One phase packet access (see 3GPP TS 44.018, table 9.1.8.1) */
329private const BIT8 chan_req_def := '01111000'B;
330
Vadim Yanitskiy85cb9912020-05-06 16:29:43 +0700331/* Establish an Uplink TBF by sending RACH.ind towards the PCU */
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200332private function f_establish_tbf(out GsmRrMessage rr_imm_ass, uint8_t bts_nr := 0,
Vadim Yanitskiyf74ae992020-05-06 16:05:51 +0700333 uint16_t ra := bit2int(chan_req_def),
334 uint8_t is_11bit := 0,
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200335 PCUIF_BurstType burst_type := BURST_TYPE_0,
336 TimingAdvance ta := 0)
337runs on RAW_PCU_Test_CT return boolean {
338 var uint32_t fn;
339
340 /* FIXME: ask the BTS component to give us the current TDMA fn */
341 fn := 1337 + ta;
342
343 /* Send RACH.ind */
344 log("Sending RACH.ind on fn=", fn, " with RA=", ra, ", TA=", ta);
345 BTS.send(ts_PCUIF_RACH_IND(bts_nr := bts_nr, trx_nr := 0, ts_nr := 0,
346 ra := ra, is_11bit := is_11bit,
347 burst_type := burst_type,
348 fn := fn, arfcn := 871,
349 qta := ta * 4));
350
351 /* 3GPP TS 44.018, table 9.1.8.1, note 2b: Request Reference shall be set to 127
352 * when Immediate Assignment is triggered by EGPRS Packet Channel Request. Here
353 * we assume that 11 bit RA always contains EGPRS Packet Channel Request. */
354 if (is_11bit != 0) { ra := 127; }
355
356 /* Expect Immediate (TBF) Assignment on TS0/AGCH */
357 return f_pcuif_rx_imm_ass(rr_imm_ass, PCU_IF_SAPI_AGCH,
Vadim Yanitskiy85cb9912020-05-06 16:29:43 +0700358 tr_IMM_TBF_ASS(false, ra, fn),
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200359 bts_nr := bts_nr);
360}
361
Vadim Yanitskiy5b649cc2020-05-06 16:35:38 +0700362private function f_imm_ass_verify_ul_tbf_ass(in GsmRrMessage rr_imm_ass, out PacketUlAssign ul_tbf_ass)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200363runs on RAW_PCU_Test_CT return boolean {
364
365 /* Make sure we received an UL TBF Assignment */
366 if (match(rr_imm_ass, tr_IMM_TBF_ASS(dl := false, rest := tr_IaRestOctets_ULAss(?)))) {
367 ul_tbf_ass := rr_imm_ass.payload.imm_ass.rest_octets.hh.pa.uldl.ass.ul;
368 log("Rx Uplink TBF assignment: ", ul_tbf_ass);
369 setverdict(pass);
370 } else {
371 setverdict(fail, "Failed to match UL TBF Assignment");
372 return false;
373 }
374
375 /* Make sure we have got a TBF with Dynamic Block Allocation */
376 if (ul_tbf_ass.dynamic == omit) {
377 setverdict(fail, "Single Block Allocation is not handled by ", testcasename());
378 return false;
379 }
380
381 return true;
382}
383
Vadim Yanitskiy5b649cc2020-05-06 16:35:38 +0700384private function f_imm_ass_verify_dl_tbf_ass(in GsmRrMessage rr_imm_ass, out PacketDlAssign dl_tbf_ass)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200385runs on RAW_PCU_Test_CT return boolean {
386
387 /* Make sure we received a DL TBF Assignment */
388 if (match(rr_imm_ass, tr_IMM_TBF_ASS(dl := true, rest := tr_IaRestOctets_DLAss(?)))) {
389 dl_tbf_ass := rr_imm_ass.payload.imm_ass.rest_octets.hh.pa.uldl.ass.dl;
390 log("Rx Downlink TBF assignment: ", dl_tbf_ass);
391 setverdict(pass);
392 } else {
393 setverdict(fail, "Failed to match DL TBF Assignment");
394 return false;
395 }
396
397 return true;
398}
399
400/* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200401function f_pcuif_tx_data_ind(octetstring data, int16_t lqual_cb := 0, uint32_t fn := 0)
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200402runs on RAW_PCU_Test_CT {
403 var template RAW_PCU_EventParam ev_param := {tdma_fn := ? };
404 BTS.send(ts_PCUIF_DATA_IND(bts_nr := 0, trx_nr := 0, ts_nr := 7, block_nr := 0,
405 sapi := PCU_IF_SAPI_PDTCH, data := data,
406 fn := fn, arfcn := 871, lqual_cb := lqual_cb));
407 if (fn != 0) {
408 ev_param := {tdma_fn := fn };
409 }
410 BTS.receive(tr_RAW_PCU_EV(TDMA_EV_PDTCH_BLOCK_SENT, ev_param));
411}
412
413/* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
414private function f_pcuif_rx_data_req(out PCUIF_Message pcu_msg)
415runs on RAW_PCU_Test_CT {
416 BTS.send(ts_PCUIF_RTS_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
417 sapi := PCU_IF_SAPI_PDTCH, fn := 0,
418 arfcn := 871, block_nr := 0));
419 BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
420 sapi := PCU_IF_SAPI_PDTCH)) -> value pcu_msg;
421}
422
423/* Expect an Immediate Assignment (paging) from PCU on PCUIF on specified sapi. */
424private function f_pcuif_rx_pch_imm_tbf_ass(out GsmRrMessage rr_imm_ass)
425runs on RAW_PCU_Test_CT {
426 var PCUIF_Message pcu_msg;
427 var octetstring macblock;
428 BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 0,
429 sapi := PCU_IF_SAPI_PCH)) -> value pcu_msg;
430 /* First 3 bytes contain paging group: */
431 macblock := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
432 rr_imm_ass := dec_GsmRrMessage(macblock);
433 if (not match(rr_imm_ass, tr_IMM_TBF_ASS())) {
434 setverdict(fail, "Failed to match Immediate Assignment: ", rr_imm_ass);
435 mtc.stop;
436 }
437 f_pcuif_tx_data_cnf(pcu_msg);
438}
439
440/* Expect a Paging Request Type 1 from PCU on PCUIF on specified sapi. */
441private function f_pcuif_rx_pch_pag_req1(template MobileIdentityV mi1 := ?,
442 template integer pag_group := ?)
443runs on RAW_PCU_Test_CT return GsmRrMessage {
444 var GsmRrMessage rr_pag_req1;
445 var PCUIF_Message pcu_msg;
446 var octetstring imsi_suff_octstr;
447 var integer pag_group_rx;
448 var octetstring macblock;
449
450 BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 0,
451 sapi := PCU_IF_SAPI_PCH)) -> value pcu_msg;
452
453 /* First 3 bytes contain IMSI suffix to calculate paging group: */
454 imsi_suff_octstr := substr(pcu_msg.u.data_req.data, 0, 3);
455 pag_group_rx := str2int(oct2char(imsi_suff_octstr[0])) * 100 +
456 str2int(oct2char(imsi_suff_octstr[1])) * 10 +
457 str2int(oct2char(imsi_suff_octstr[2]));
458
459 /* Make sure we've got RR Paging Request Type 1 for a given MI */
460 macblock := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
461 rr_pag_req1 := dec_GsmRrMessage(macblock);
462 if (not match(rr_pag_req1, tr_PAG_REQ1(tr_MI_LV(mi1)))) {
463 setverdict(fail, "Failed to match Paging Request Type 1: ", rr_pag_req1);
464 mtc.stop;
465 }
466
467 /* Make sure that received paging froup matches the expected one */
468 if (not match(pag_group_rx, pag_group)) {
469 setverdict(fail, "Paging group", pag_group_rx, " does not match expected ", pag_group);
470 mtc.stop;
471 }
472
473 f_pcuif_tx_data_cnf(pcu_msg);
474 return rr_pag_req1;
475}
476
477private function f_tx_rlcmac_ul_block(template (value) RlcmacUlBlock ul_data, int16_t lqual_cb := 0, uint32_t fn := 0)
478runs on RAW_PCU_Test_CT {
479 var octetstring data;
480 /* Encode the payload of DATA.ind */
481 data := enc_RlcmacUlBlock(valueof(ul_data));
482 data := f_pad_oct(data, 23, '00'O); /* CS-1 */
483
484 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
485 f_pcuif_tx_data_ind(data, lqual_cb, fn);
486}
487
488private function f_tx_rlcmac_ul_n_blocks(PacketUlAssign ul_tbf_ass, integer num_blocks := 1)
489runs on RAW_PCU_Test_CT {
490 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
491 tfi := ul_tbf_ass.dynamic.tfi_assignment,
492 cv := num_blocks - 1, /* num UL blocks to be sent (to be overridden in loop) */
493 bsn := 0, /* TODO: what should be here? */
494 blocks := { /* To be generated in loop */ });
495
496 /* HACK: patch missing TLLI; otherwise OsmoPCU rejects DATA.req */
497 ul_data.data.tlli := '00000001'O;
498
499 for (var integer i := 0; i < num_blocks; i := i + 1) {
500 /* Prepare a new UL block (CV, random payload) */
501 ul_data.data.mac_hdr.countdown := (num_blocks - i - 1);
502 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
503 f_tx_rlcmac_ul_block(ul_data);
504 }
505}
506
507private function f_rx_rlcmac_dl_block(out RlcmacDlBlock dl_block, out uint32_t dl_fn, template (present) CodingScheme exp_cs_mcs := ?)
508runs on RAW_PCU_Test_CT {
509 var PCUIF_Message pcu_msg;
510 f_pcuif_rx_data_req(pcu_msg);
511 dl_block := dec_RlcmacDlBlock(pcu_msg.u.data_req.data);
512 dl_fn := pcu_msg.u.data_req.fn;
513
514 var integer len := lengthof(pcu_msg.u.data_req.data);
515 var CodingScheme cs_mcs := f_rlcmac_block_len2cs_mcs(len)
516 if (not match(f_rlcmac_block_len2cs_mcs(len), exp_cs_mcs)) {
517 setverdict(fail, "Failed to match Coding Scheme exp ", exp_cs_mcs, " vs ", cs_mcs, " (", len, ")");
518 mtc.stop;
519 }
520}
521
522private function f_rx_rlcmac_dl_block_exp_ack_nack(out RlcmacDlBlock dl_block, out uint32_t poll_fn)
523runs on RAW_PCU_Test_CT {
524 var uint32_t dl_fn;
525
526 f_rx_rlcmac_dl_block(dl_block, dl_fn);
527 if (not match(dl_block, tr_RLCMAC_UL_ACK_NACK(ul_tfi := ?, tlli := ?))) {
528 setverdict(fail, "Failed to match Packet Uplink ACK / NACK");
529 mtc.stop;
530 }
531
532 poll_fn := dl_fn + f_rrbp_fn_delay(dl_block.ctrl.mac_hdr.rrbp);
533}
534
535private function f_rx_rlcmac_dl_block_exp_dummy(out RlcmacDlBlock dl_block)
536runs on RAW_PCU_Test_CT {
537 var uint32_t dl_fn;
538
539 f_rx_rlcmac_dl_block(dl_block, dl_fn);
540 if (not match(dl_block, tr_RLCMAC_DUMMY_CTRL())) {
541 setverdict(fail, "Failed to match Packet DUMMY DL");
542 mtc.stop;
543 }
544}
545
546private function f_rx_rlcmac_dl_block_exp_pkt_ass(out RlcmacDlBlock dl_block, out uint32_t poll_fn)
547runs on RAW_PCU_Test_CT {
548 var uint32_t dl_fn;
549
550 f_rx_rlcmac_dl_block(dl_block, dl_fn);
551 if (not match(dl_block, tr_RLCMAC_DL_PACKET_ASS())) {
552 setverdict(fail, "Failed to match Packet Downlink Assignment");
553 mtc.stop;
554 }
555
556 poll_fn := dl_fn + f_rrbp_fn_delay(dl_block.ctrl.mac_hdr.rrbp);
557}
558
559private function f_rx_rlcmac_dl_block_exp_pkt_ul_ass(out RlcmacDlBlock dl_block, out uint32_t poll_fn)
560runs on RAW_PCU_Test_CT {
561 var uint32_t dl_fn;
562
563 f_rx_rlcmac_dl_block(dl_block, dl_fn);
564 if (not match(dl_block, tr_RLCMAC_UL_PACKET_ASS())) {
565 setverdict(fail, "Failed to match Packet Uplink Assignment");
566 mtc.stop;
567 }
568
569 poll_fn := dl_fn + f_rrbp_fn_delay(dl_block.ctrl.mac_hdr.rrbp);
570}
571
572
573private function f_rx_rlcmac_dl_block_exp_pkt_pag_req(out RlcmacDlBlock dl_block)
574runs on RAW_PCU_Test_CT {
575 var uint32_t dl_fn;
576
577 f_rx_rlcmac_dl_block(dl_block, dl_fn);
578 if (not match(dl_block, tr_RLCMAC_PACKET_PAG_REQ())) {
579 setverdict(fail, "Failed to match Packet Paging Request: ", dl_block, " vs ", tr_RLCMAC_PACKET_PAG_REQ());
580 mtc.stop;
581 }
582}
583
584private function f_rlcmac_dl_block_verify_data_gprs(RlcmacDlBlock dl_block, uint32_t dl_fn, out uint32_t ack_fn, octetstring data, template (present) uint7_t exp_bsn := ?, template (present) CodingScheme exp_cs := ?)
585{
586 log("verifying dl data block (gprs): ", dl_block);
587
588 ack_fn := dl_fn + f_rrbp_fn_delay(dl_block.data.mac_hdr.mac_hdr.rrbp);
589
590 if (not match(dl_block.data.mac_hdr.hdr_ext.bsn, exp_bsn)) {
591 setverdict(fail, "DL block BSN doesn't match: ",
592 dl_block.data.blocks[0].hdr.length_ind, " vs exp ", exp_bsn);
593 }
594
595 if (lengthof(dl_block.data.blocks) < 1) {
596 setverdict(fail, "DL block has no LLC payload: ", dl_block);
597 mtc.stop;
598 }
599
600 if (ispresent(dl_block.data.blocks[0].hdr) and dl_block.data.blocks[0].hdr.length_ind != lengthof(data)) {
601 setverdict(fail, "DL block has LLC header with wrong expected size: ",
602 dl_block.data.blocks[0].hdr.length_ind, " vs ", lengthof(data));
603 mtc.stop;
604 }
605
606 if (dl_block.data.blocks[0].payload != data) {
607 setverdict(fail, "Failed to match content of LLC payload in DL Block: ", dl_block, " vs ", data);
608 mtc.stop;
609 }
610
611 /* Check next data blocks contain dummy frames */
612 if (lengthof(dl_block.data.blocks) > 1 and substr(dl_block.data.blocks[1].payload, 0, 3) != '43C001'O) {
613 setverdict(fail, "Second data payload is not a dummy frame: ", dl_block.data.blocks[1].payload);
614 mtc.stop;
615 }
616
617 /* TODO: check exp_cs */
618}
619
620private function f_rlcmac_dl_block_verify_data_egprs(RlcmacDlBlock dl_block, uint32_t dl_fn, out uint32_t ack_fn, octetstring data, template (present) uint14_t exp_bsn := ?, template (present) CodingScheme exp_cs := ?)
621{
622 log("verifying dl data block (egprs): ", dl_block);
623
624 ack_fn := dl_fn + f_rrbp_fn_delay(dl_block.data_egprs.mac_hdr.rrbp);
625
626 if (not match(dl_block.data_egprs.mac_hdr.bsn1, exp_bsn)) {
627 setverdict(fail, "DL block BSN doesn't match: ",
628 dl_block.data_egprs.blocks[0].hdr.length_ind, " vs exp ", exp_bsn);
629 }
630
631 if (lengthof(dl_block.data_egprs.blocks) < 1) {
632 setverdict(fail, "DL block has no LLC payload: ", dl_block);
633 mtc.stop;
634 }
635
636 if (ispresent(dl_block.data_egprs.blocks[0].hdr) and dl_block.data_egprs.blocks[0].hdr.length_ind != lengthof(data)) {
637 setverdict(fail, "DL block has LLC header with wrong expected size: ",
638 dl_block.data_egprs.blocks[0].hdr.length_ind, " vs ", lengthof(data));
639 mtc.stop;
640 }
641
642 if (dl_block.data_egprs.blocks[0].payload != data) {
643 setverdict(fail, "Failed to match content of LLC payload in DL Block: ", dl_block, " vs ", data);
644 mtc.stop;
645 }
646
647 /* Check next data blocks contain dummy frames */
648 if (lengthof(dl_block.data_egprs.blocks) > 1 and substr(dl_block.data_egprs.blocks[1].payload, 0, 3) != '43C001'O) {
649 setverdict(fail, "Second data payload is not a dummy frame: ", dl_block.data.blocks[1].payload);
650 mtc.stop;
651 }
652
653 /* 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.
654 See wireshark's egprs_Header_type1_coding_puncturing_scheme_to_mcs. */
655}
656
657private function f_rx_rlcmac_dl_block_exp_data(out RlcmacDlBlock dl_block, out uint32_t ack_fn, octetstring data, template (present) uint7_t exp_bsn := ?, template (present) CodingScheme exp_cs := ?)
658runs on RAW_PCU_Test_CT {
659 var PCUIF_Message pcu_msg;
660 var uint32_t dl_fn;
661 var boolean is_egprs := false;
662 var template RlcmacDlBlock dl_template := tr_RLCMAC_DATA_RRBP;
663 dl_template.data.blocks := ?;
664
665 f_rx_rlcmac_dl_block(dl_block, dl_fn);
666 if (not match(dl_block, dl_template)) {
667 dl_template := tr_RLCMAC_DATA_EGPRS;
668 dl_template.data_egprs.blocks := ?;
669 if (not match(dl_block, dl_template)) {
670 setverdict(fail, "Failed to match Packet data: ", dl_block, " vs ", dl_template);
671 mtc.stop;
672 }
673 is_egprs := true;
674 }
675
676 if (is_egprs) {
677 f_rlcmac_dl_block_verify_data_egprs(dl_block, dl_fn, ack_fn, data, exp_bsn, exp_cs);
678 } else {
679 f_rlcmac_dl_block_verify_data_gprs(dl_block, dl_fn, ack_fn, data, exp_bsn, exp_cs);
680 }
681}
682
683testcase TC_pcuif_suspend() runs on RAW_PCU_Test_CT {
684 var octetstring ra_id := enc_RoutingAreaIdentification(mp_gb_cfg.cell_id.ra_id);
685 var GprsTlli tlli := 'FFFFFFFF'O;
686 timer T;
687
688 /* Initialize NS/BSSGP side */
689 f_init_bssgp();
690
691 /* Initialize the PCU interface abstraction */
692 f_init_raw(testcasename());
693
694 /* Establish BSSGP connection to the PCU */
695 f_bssgp_establish();
696
697 BTS.send(ts_PCUIF_SUSP_REQ(0, tlli, ra_id, 0));
698
699 T.start(2.0);
700 alt {
701 [] BSSGP_SIG[0].receive(tr_BSSGP_SUSPEND(tlli, mp_gb_cfg.cell_id.ra_id)) {
702 setverdict(pass);
703 }
704 [] T.timeout {
705 setverdict(fail, "Timeout waiting for BSSGP SUSPEND");
706 }
707 }
708}
709
710/* Test of correct Timing Advance at the time of TBF establishment
711 * (derived from timing offset of the Access Burst). */
712testcase TC_ta_rach_imm_ass() runs on RAW_PCU_Test_CT {
713 var GsmRrMessage rr_msg;
714 var boolean ok;
715
716 /* Initialize the PCU interface abstraction */
717 f_init_raw(testcasename());
718
719 /* We cannot send too many TBF requests in a short time because
720 * at some point the PCU will fail to allocate a new TBF. */
721 for (var TimingAdvance ta := 0; ta < 64; ta := ta + 16) {
722 /* Establish an Uplink TBF (send RACH.ind with current TA) */
723 ok := f_establish_tbf(rr_msg, bts_nr := 0, ta := ta);
724 if (not ok) {
725 setverdict(fail, "Failed to establish an Uplink TBF");
726 mtc.stop;
727 }
728
729 /* Make sure Timing Advance IE matches out expectations */
Vadim Yanitskiy8685b382020-05-06 16:53:26 +0700730 if (rr_msg.payload.imm_ass.timing_advance != ta) {
731 setverdict(fail, "Timing Advance mismatch: ",
732 rr_msg.payload.imm_ass.timing_advance,
733 " vs expected ", ta);
734 mtc.stop;
Pau Espin Pedrol8dd59fb2020-04-29 15:08:16 +0200735 }
736 }
737}
738
739/* Verify Timing Advance value(s) indicated during the packet Downlink assignment
740 * procedure as per 3GPP TS 44.018, section 3.5.3. There seems to be a bug in the
741 * IUT that causes it to send an unreasonable Timing Advance value > 0 despite
742 * no active TBF exists at the moment of establishment (idle mode). */
743testcase TC_ta_idle_dl_tbf_ass() runs on RAW_PCU_Test_CT {
744 var OCT4 tlli := f_rnd_octstring(4);
745 var GsmRrMessage rr_imm_ass;
746
747 /* Initialize NS/BSSGP side */
748 f_init_bssgp();
749
750 /* Initialize the PCU interface abstraction */
751 f_init_raw(testcasename());
752
753 /* Establish BSSGP connection to the PCU */
754 f_bssgp_establish();
755 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
756
757 /* SGSN sends some DL data, PCU will initiate Packet Downlink
758 * Assignment on CCCH (PCH). We don't care about the payload. */
759 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, f_rnd_octstring(10)));
760 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass); // TODO: match by TLLI!
761
762 /* Make sure that Timing Advance is 0 (the actual value is not known yet).
763 * As per 3GPP S 44.018, section 3.5.3.1.2, the network *shall* initiate
764 * the procedures defined in 3GPP TS 44.060 or use the polling mechanism. */
765 if (not match(rr_imm_ass, tr_IMM_TBF_ASS(ta := 0))) {
766 setverdict(fail, "Timing Advance value doesn't match");
767 mtc.stop;
768 }
769}
770
771/* Verify that the PCU generates valid PTCCH/D messages
772 * while neither Uplink nor Downlink TBF is established. */
773testcase TC_ta_ptcch_idle() runs on RAW_PCU_Test_CT {
774 var PTCCHDownlinkMsg ptcch_msg;
775 var PCUIF_Message pcu_msg;
776 timer T;
777
778 /* Initialize the PCU interface abstraction */
779 f_init_raw(testcasename());
780
781 /* Sent an RTS.req for PTCCH/D */
782 BTS.send(ts_PCUIF_RTS_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
783 sapi := PCU_IF_SAPI_PTCCH, fn := 0,
784 arfcn := 871, block_nr := 0));
785 T.start(5.0);
786 alt {
787 [] BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
788 sapi := PCU_IF_SAPI_PTCCH)) -> value pcu_msg {
789 log("Rx DATA.req message: ", pcu_msg);
790 setverdict(pass);
791 }
792 [] BTS.receive(PCUIF_Message:?) { repeat; }
793 [] T.timeout {
794 setverdict(fail, "Timeout waiting for a PTCCH/D block");
795 mtc.stop;
796 }
797 }
798
799 ptcch_msg := dec_PTCCHDownlinkMsg(pcu_msg.u.data_req.data);
800 log("Decoded PTCCH/D message: ", ptcch_msg);
801
802 /* Make sure the message is encoded correctly
803 * TODO: do we expect all TA values to be equal '1111111'B? */
804 if (not match(ptcch_msg, tr_PTCCHDownlinkMsg)) {
805 setverdict(fail, "Malformed PTCCH/D message");
806 mtc.stop;
807 }
808}
809
810/* Test of correct Timing Advance during an active Uplink TBF.
811 *
812 * Unlike the circuit-switched domain, Uplink transmissions on PDCH time-slots
813 * are not continuous and there can be long time gaps between them. This happens
814 * due to a bursty nature of packet data. The actual Timing Advance of a MS may
815 * significantly change between such rare Uplink transmissions, so GPRS introduces
816 * additional mechanisms to control Timing Advance, and thus reduce interference
817 * between neighboring TDMA time-slots.
818 *
819 * At the moment of Uplink TBF establishment, initial Timing Advance is measured
820 * from ToA (Timing of Arrival) of an Access Burst. This is covered by another
821 * test case - TC_ta_rach_imm_ass. In response to that Access Burst the network
822 * sends Immediate Assignment on AGCH, which _may_ contain Timing Advance Index
823 * among with the initial Timing Advance value. And here PTCCH comes to play.
824 *
825 * PTCCH is a unidirectional channel on which the network can instruct a sub-set
826 * of 16 MS (whether TBFs are active or not) to adjust their Timing Advance
827 * continuously. To ensure continuous measurements of the signal propagation
828 * delay, the MSs shall transmit Access Bursts on Uplink (PTCCH/U) on sub-slots
829 * defined by an assigned Timing Advance Index (see 3GPP TS 45.002).
830 *
831 * The purpose of this test case is to verify the assignment of Timing Advance
832 * Index, and the process of Timing Advance notification on PTCCH/D. The MTC
833 * first establishes several Uplink TBFs, but does not transmit any Uplink
834 * blocks on them. During 4 TDMA multi-frame periods the MTC is sending RACH
835 * indications to the PCU, checking the correctness of two received PTCCH/D
836 * messages (period of PTCCH/D is two multi-frames).
837 */
838
839/* List of ToA values for Access Bursts to be sent on PTCCH/U,
840 * each ToA (Timing of Arrival) value is in units of 1/4 of
841 * a symbol (i.e. 1 symbol is 4 QTA units). */
842type record length(16) of int16_t PTCCH_TAI_ToA_MAP;
843const PTCCH_TAI_ToA_MAP ptcch_toa_map_def := {
844 0, 0, 0, 0,
845 0, 0, 0, 0,
846 0, 0, 0, 0,
847 0, 0, 0, 0
848};
849
850private altstep as_ta_ptcch(uint8_t bts_nr := 0, uint8_t trx_nr := 0, uint8_t ts_nr := 7,
851 in PTCCH_TAI_ToA_MAP toa_map := ptcch_toa_map_def)
852runs on RAW_PCU_Test_CT {
853 var RAW_PCU_Event event;
854 var integer ss;
855
856 /* Send Access Bursts on PTCCH/U for every TA Index */
857 [] BTS.receive(tr_RAW_PCU_EV(TDMA_EV_PTCCH_UL_BURST)) -> value event {
858 ss := f_tdma_ptcch_fn2ss(event.data.tdma_fn);
859 if (ss < 0) { mtc.stop; } /* Shall not happen */
860
861 log("Sending an Access Burst on PTCCH/U",
862 ", sub-slot=", ss, " (TAI)",
863 ", fn=", event.data.tdma_fn,
864 ", ToA=", toa_map[ss], " (QTA)");
865 /* TODO: do we care about RA and burst format? */
866 BTS.send(ts_PCUIF_RACH_IND(bts_nr, trx_nr, ts_nr,
867 ra := oct2int('3A'O),
868 is_11bit := 0,
869 burst_type := BURST_TYPE_0,
870 fn := event.data.tdma_fn,
871 arfcn := 871,
872 qta := toa_map[ss],
873 sapi := PCU_IF_SAPI_PTCCH));
874 repeat;
875 }
876}
877
878private function f_TC_ta_ptcch_ul_multi_tbf(in PTCCH_TAI_ToA_MAP ptcch_toa_map,
879 template PTCCHDownlinkMsg t_ta_msg)
880runs on RAW_PCU_Test_CT {
881 var PTCCHDownlinkMsg ta_msg;
882 var PCUIF_Message pcu_msg;
883 timer T;
884
885 /* First, send an RTS.req for the upcoming PTCCH/D block */
886 BTS.send(ts_PCUIF_RTS_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
887 sapi := PCU_IF_SAPI_PTCCH, fn := 0,
888 arfcn := 871, block_nr := 0));
889 T.start(2.0);
890 alt {
891 /* Keep sending of Access Bursts during two multi-frames (period of PTCCH/D)
892 * with increasing ToA (Timing of Arrival) values: 0, 7, 14, 28, 35... */
893 [] as_ta_ptcch(bts_nr := 0, trx_nr := 0, ts_nr := 7, toa_map := ptcch_toa_map);
894 /* In the end of 2nd multi-frame we should receive a PTCCH/D block */
895 [] BTS.receive(tr_PCUIF_DATA_REQ(bts_nr := 0, trx_nr := 0, ts_nr := 7,
896 sapi := PCU_IF_SAPI_PTCCH)) -> value pcu_msg {
897 ta_msg := dec_PTCCHDownlinkMsg(pcu_msg.u.data_req.data);
898 log("Rx PTCCH/D message: ", ta_msg);
899
900 /* Make sure Timing Advance values match our expectations */
901 if (match(ta_msg, t_ta_msg)) {
902 setverdict(pass);
903 } else {
904 setverdict(fail, "PTCCH/D message does not match: ", t_ta_msg);
905 }
906 }
907 [] BTS.receive { repeat; }
908 [] T.timeout {
909 setverdict(fail, "Timeout waiting for a PTCCH/D block");
910 mtc.stop;
911 }
912 }
913}
914
915testcase TC_ta_ptcch_ul_multi_tbf() runs on RAW_PCU_Test_CT {
916 var template PacketUlAssign t_ul_tbf_ass;
917 var PacketUlAssign ul_tbf_ass[7];
918 var GsmRrMessage rr_msg[7];
919 var boolean ok;
920
921 /* Initialize the PCU interface abstraction */
922 f_init_raw(testcasename());
923
924 /* Enable forwarding of PTCCH/U TDMA events to us */
925 BTS.send(ts_RAW_PCU_CMD(TDMA_CMD_ENABLE_PTCCH_UL_FWD));
926
927 /* Establish 7 Uplink TBFs (USF flag is 3 bits long, '111'B is reserved) */
928 for (var integer i := 0; i < 7; i := i + 1) {
929 ok := f_establish_tbf(rr_msg[i], ta := 0);
930 if (not ok) {
931 setverdict(fail, "Failed to establish an Uplink TBF #", i);
932 mtc.stop;
933 }
934
935 /* Make sure we received an UL TBF Assignment */
936 if (match(rr_msg[i], tr_IMM_TBF_ASS(dl := false, rest := tr_IaRestOctets_ULAss(?)))) {
937 ul_tbf_ass[i] := rr_msg[i].payload.imm_ass.rest_octets.hh.pa.uldl.ass.ul;
938 log("Rx Uplink TBF assignment for #", i, ": ", ul_tbf_ass[i]);
939 } else {
940 setverdict(fail, "Failed to match UL TBF Assignment for #", i);
941 mtc.stop;
942 }
943
944 /* We expect incremental TFI/USF assignment (dynamic allocation) */
945 t_ul_tbf_ass := tr_PacketUlDynAssign(tfi := i, usf := i);
946 if (not match(ul_tbf_ass[i], t_ul_tbf_ass)) {
947 setverdict(fail, "Failed to match Packet Uplink Assignment for #", i);
948 mtc.stop;
949 }
950
951 /* We also expect Timing Advance Index to be a part of the assignment */
952 if (ul_tbf_ass[i].dynamic.ta_index != i) {
953 setverdict(fail, "Failed to match Timing Advance Index for #", i);
954 /* Keep going, the current OsmoPCU does not assign TA Index */
955 }
956 }
957
958 /* Prepare a list of ToA values for Access Bursts to be sent on PTCCH/U */
959 var PTCCH_TAI_ToA_MAP toa_map := ptcch_toa_map_def;
960 for (var integer i := 0; i < 7; i := i + 1) {
961 /* ToA in units of 1/4 of a symbol */
962 toa_map[i] := (i + 1) * 7 * 4;
963 }
964
965 /* Now we have all 7 TBFs established in one-phase access mode,
966 * however we will not be sending any data on them. Instead, we
967 * will be sending RACH.ind on PTCCH/U during 4 multi-frame
968 * periods (TAI 0..8), and then will check two PTCCH/D blocks.
969 *
970 * Why not 4 TBFs at once? Because Uplink is delayed by 3 TDMA
971 * time-slots, so at the moment of scheduling a PTCCH/D block
972 * the PCU has odd number of PTCCH/U Access Bursts received. */
973 f_TC_ta_ptcch_ul_multi_tbf(toa_map, tr_PTCCHDownlinkMsg(
974 tai0_ta := 7, tai1_ta := 14, tai2_ta := 21,
975 /* Other values are not known (yet) */
976 tai3_ta := ?));
977 f_TC_ta_ptcch_ul_multi_tbf(toa_map, tr_PTCCHDownlinkMsg(
978 tai0_ta := 7, tai1_ta := 14, tai2_ta := 21,
979 tai3_ta := 28, tai4_ta := 35, tai5_ta := 42,
980 /* Other values are out of our interest */
981 tai6_ta := ?));
982}
983
984/* Default link quality adaptation (Coding Scheme) ranges (inclusive).
985 * OsmoPCU (VTY): cs link-quality-ranges cs1 6 cs2 5 8 cs3 7 13 cs4 12
986 *
987 * NOTE: the ranges are intentionally overlapping because OsmoPCU
988 * does not change CS/MCS on the range borders (5-6, 7-8, 12-13). */
989private template integer CS1_lqual_dB_range := (-infinity .. 6);
990private template integer CS2_lqual_dB_range := (5 .. 8);
991private template integer CS3_lqual_dB_range := (7 .. 13);
992private template integer CS4_lqual_dB_range := (12 .. infinity);
993
994testcase TC_cs_lqual_ul_tbf() runs on RAW_PCU_Test_CT {
995 var GsmRrMessage rr_imm_ass;
996 var PacketUlAssign ul_tbf_ass;
997 var RlcmacDlBlock dl_block;
998 var PCUIF_Message pcu_msg;
999 var octetstring data;
1000 var boolean ok;
1001 var uint32_t unused_fn;
1002
1003 /* Initialize the PCU interface abstraction */
1004 f_init_raw(testcasename());
1005
1006 f_pcuvty_set_allowed_cs_mcs();
1007 f_pcuvty_set_link_quality_ranges();
1008
1009 /* Establish an Uplink TBF */
1010 ok := f_establish_tbf(rr_imm_ass);
1011 if (not ok) {
1012 setverdict(fail, "Failed to establish TBF");
1013 mtc.stop;
1014 }
1015
1016 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1017 if (not ok) {
1018 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1019 mtc.stop;
1020 }
1021
1022 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
1023 tfi := ul_tbf_ass.dynamic.tfi_assignment,
1024 cv := 15, /* 16 UL blocks to be sent (to be overridden in loop) */
1025 bsn := 0, /* TODO: what should be here? */
1026 blocks := { /* To be generated in loop */ });
1027
1028 /* HACK: patch missing TLLI; otherwise OsmoPCU rejects DATA.req */
1029 ul_data.data.tlli := '00000001'O;
1030
1031 /* The actual / old link quality values. We need to keep track of the old
1032 * (basically previous) link quality value, because OsmoPCU actually
1033 * changes the coding scheme if not only the actual, but also the old
1034 * value leaves the current link quality range (window). */
1035 var integer lqual := 0;
1036 var integer lqual_old;
1037
1038 /* 16 UL blocks (0 .. 15 dB, step = 1 dB) */
1039 for (var integer i := 0; i < 16; i := i + 1) {
1040 /* Prepare a new UL block (CV, random payload) */
1041 ul_data.data.mac_hdr.countdown := (15 - i);
1042 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1043
1044 /* Update the old / actual link quality */
1045 lqual_old := lqual;
1046 lqual := i;
1047
1048 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1049 log("Sending DATA.ind with link quality (dB): ", lqual);
1050 f_tx_rlcmac_ul_block(ul_data, lqual * 10);
1051
1052 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1053 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1054
1055 log("Rx Packet Uplink ACK / NACK with Channel Coding Command: ",
1056 dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd);
1057
1058 /* Match the received Channel Coding Command. Since we are increasing
1059 * the link quality value on each iteration and not decreasing, there
1060 * is no need to check the both old and current link quality values. */
1061 var template ChCodingCommand ch_coding;
1062 select (lqual_old) {
1063 case (CS1_lqual_dB_range) { ch_coding := CH_CODING_CS1; }
1064 case (CS2_lqual_dB_range) { ch_coding := CH_CODING_CS2; }
1065 case (CS3_lqual_dB_range) { ch_coding := CH_CODING_CS3; }
1066 case (CS4_lqual_dB_range) { ch_coding := CH_CODING_CS4; }
1067 }
1068
1069 if (not match(dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd, ch_coding)) {
1070 setverdict(fail, "Channel Coding does not match our expectations: ", ch_coding);
1071 } else {
1072 setverdict(pass);
1073 }
1074 }
1075}
1076
1077/* Test the max UL CS set by VTY works fine */
1078testcase TC_cs_initial_ul() runs on RAW_PCU_Test_CT {
1079 var GsmRrMessage rr_imm_ass;
1080 var PacketUlAssign ul_tbf_ass;
1081 var RlcmacDlBlock dl_block;
1082 var boolean ok;
1083 var integer lqual_cb;
1084 var ChCodingCommand last_ch_coding;
1085 var uint32_t unused_fn;
1086
1087 /* Initialize the PCU interface abstraction */
1088 f_init_raw(testcasename());
1089
1090 /* Set initial UL CS to 3 */
1091 g_cs_initial_ul := 3;
1092 f_pcuvty_set_allowed_cs_mcs();
1093 f_pcuvty_set_link_quality_ranges();
1094
1095 /* Take lqual (dB->cB) so that we stay in that CS */
1096 lqual_cb := g_cs_lqual_ranges[2].low * 10;
1097
1098 /* Establish an Uplink TBF */
1099 ok := f_establish_tbf(rr_imm_ass);
1100 if (not ok) {
1101 setverdict(fail, "Failed to establish TBF");
1102 mtc.stop;
1103 }
1104
1105 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1106 if (not ok) {
1107 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1108 mtc.stop;
1109 }
1110
1111 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
1112 tfi := ul_tbf_ass.dynamic.tfi_assignment,
1113 cv := 3, /* 8 UL blocks to be sent (to be overridden in loop) */
1114 bsn := 0, /* TODO: what should be here? */
1115 blocks := { /* To be generated in loop */ });
1116
1117 /* HACK: patch missing TLLI; otherwise OsmoPCU rejects DATA.req */
1118 ul_data.data.tlli := '00000001'O;
1119
1120 /* 3 UL blocks, check we are in same initial CS: */
1121 for (var integer i := 0; i < 3; i := i + 1) {
1122 /* Prepare a new UL block (CV, random payload) */
1123 ul_data.data.mac_hdr.countdown := (7 - i);
1124 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1125
1126 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1127 f_tx_rlcmac_ul_block(ul_data, lqual_cb);
1128
1129 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1130 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1131 last_ch_coding := dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd;
1132 }
1133
1134 if (last_ch_coding != CH_CODING_CS3) {
1135 setverdict(fail, "Channel Coding does not match our expectations (CS-3): ", last_ch_coding);
1136 mtc.stop;
1137 }
1138
1139 setverdict(pass);
1140
1141 /* Remaining UL blocks are used to make sure regardless of initial
1142 /* lqual, we can go lower at any time */
1143
1144 /* 5 UL blocks, check we are in same initial CS: */
1145 for (var integer i := 3; i < 8; i := i + 1) {
1146 /* Prepare a new UL block (CV, random payload) */
1147 ul_data.data.mac_hdr.countdown := (7 - i);
1148 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1149
1150 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1151 f_tx_rlcmac_ul_block(ul_data, 0); /* 0 dB, make sure we downgrade CS */
1152
1153 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1154 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1155
1156 last_ch_coding := dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd;
1157 }
1158
1159 if (last_ch_coding != CH_CODING_CS1) {
1160 setverdict(fail, "Channel Coding does not match our expectations (CS-1): ", last_ch_coding);
1161 } else {
1162 setverdict(pass);
1163 }
1164}
1165
1166/* Test the max UL CS set by VTY works fine */
1167testcase TC_cs_max_ul() runs on RAW_PCU_Test_CT {
1168 var GsmRrMessage rr_imm_ass;
1169 var PacketUlAssign ul_tbf_ass;
1170 var RlcmacDlBlock dl_block;
1171 var boolean ok;
1172 var ChCodingCommand last_ch_coding;
1173 var uint32_t unused_fn;
1174
1175 /* Initialize the PCU interface abstraction */
1176 f_init_raw(testcasename());
1177
1178 /* Set maximum allowed UL CS to 3 */
1179 g_cs_max_ul := 3;
1180 f_pcuvty_set_allowed_cs_mcs();
1181 f_pcuvty_set_link_quality_ranges();
1182
1183 /* Establish an Uplink TBF */
1184 ok := f_establish_tbf(rr_imm_ass);
1185 if (not ok) {
1186 setverdict(fail, "Failed to establish TBF");
1187 mtc.stop;
1188 }
1189
1190 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1191 if (not ok) {
1192 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1193 mtc.stop;
1194 }
1195
1196 var template (value) RlcmacUlBlock ul_data := t_RLCMAC_UL_DATA(
1197 tfi := ul_tbf_ass.dynamic.tfi_assignment,
1198 cv := 15, /* 16 UL blocks to be sent (to be overridden in loop) */
1199 bsn := 0, /* TODO: what should be here? */
1200 blocks := { /* To be generated in loop */ });
1201
1202 /* HACK: patch missing TLLI; otherwise OsmoPCU rejects DATA.req */
1203 ul_data.data.tlli := '00000001'O;
1204
1205 /* 16 UL blocks */
1206 for (var integer i := 0; i < 16; i := i + 1) {
1207 /* Prepare a new UL block (CV, random payload) */
1208 ul_data.data.mac_hdr.countdown := (15 - i);
1209 ul_data.data.blocks := { valueof(t_RLCMAC_LLCBLOCK(f_rnd_octstring(10))) };
1210
1211 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
1212 f_tx_rlcmac_ul_block(ul_data, 40*10); /* 40 dB */
1213
1214 /* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
1215 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1216
1217 last_ch_coding := dl_block.ctrl.payload.u.ul_ack_nack.gprs.ch_coding_cmd;
1218 }
1219
1220 if (last_ch_coding != CH_CODING_CS3) {
1221 setverdict(fail, "Channel Coding does not match our expectations (CS-3): ", last_ch_coding);
1222 } else {
1223 setverdict(pass);
1224 }
1225}
1226
1227/* Verify PCU drops TBF after some time of inactivity. */
1228testcase TC_t3169() runs on RAW_PCU_Test_CT {
1229 var PCUIF_info_ind info_ind;
1230 var GsmRrMessage rr_imm_ass;
1231 var PacketUlAssign ul_tbf_ass;
1232 var RlcmacDlBlock dl_block;
1233 var PCUIF_Message pcu_msg;
1234 var octetstring data;
1235 var boolean ok;
1236 var uint32_t unused_fn;
1237 var OCT4 tlli := '00000001'O;
1238
1239 /* Initialize NS/BSSGP side */
1240 f_init_bssgp();
1241
1242 info_ind := valueof(ts_PCUIF_INFO_default);
1243 /* Set timer to 1 sec (default 5) to speedup test: */
1244 info_ind.t3169 := 1;
1245
1246 /* Initialize the PCU interface abstraction */
1247 f_init_raw(testcasename(), info_ind);
1248
1249 /* Establish BSSGP connection to the PCU */
1250 f_bssgp_establish();
1251 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1252
1253 /* Establish an Uplink TBF */
1254 ok := f_establish_tbf(rr_imm_ass);
1255 if (not ok) {
1256 setverdict(fail, "Failed to establish TBF");
1257 mtc.stop;
1258 }
1259
1260 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1261 if (not ok) {
1262 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1263 mtc.stop;
1264 }
1265
1266 /* Send one UL block and make sure it is ACKED fine */
1267 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1);
1268 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, unused_fn);
1269 /* UL block should be received in SGSN */
1270 BSSGP[0].receive(tr_BSSGP_UL_UD(tlli, mp_gb_cfg.cell_id));
1271
1272 /* Wait until T3169 fires (plus 1 extra sec to make sure) */
1273 f_sleep(int2float(info_ind.t3169) + 1.0);
1274
1275 /* Send an UL block once again, the TBF should be gone by now so no ACK */
1276 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1);
1277 f_rx_rlcmac_dl_block_exp_dummy(dl_block);
1278}
1279
1280/* Verify that a Downlink TBF can be assigned using PACCH shortly after the
1281 * release of prev DL TBF due to MS staying in PDCH for a while (T3192, in PCU
1282 * T3193) after DL TBF release */
1283testcase TC_t3193() runs on RAW_PCU_Test_CT {
1284 var GsmRrMessage rr_imm_ass;
1285 var PacketDlAssign dl_tbf_ass;
1286 var RlcmacDlBlock dl_block;
1287 var octetstring data := f_rnd_octstring(10);
1288 var boolean ok;
1289 var uint32_t sched_fn;
1290 var OCT4 tlli := '00000001'O;
1291 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1292
1293 /* Initialize NS/BSSGP side */
1294 f_init_bssgp();
1295
1296 /* Initialize the PCU interface abstraction */
1297 f_init_raw(testcasename());
1298
1299 /* Establish BSSGP connection to the PCU */
1300 f_bssgp_establish();
1301 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1302
1303 /* SGSN sends some DL data, PCU will page on CCCH (PCH) */
1304 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1305 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1306 ok := f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1307 if (not ok) {
1308 setverdict(fail, "Immediate Assignment not a Downlink TBF");
1309 mtc.stop;
1310 }
1311 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1312 f_sleep(X2002);
1313 f_rx_rlcmac_dl_block_exp_data(dl_block, sched_fn, data, 0);
1314
1315 /* ACK the DL block */
1316 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
1317 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc), 0, sched_fn);
1318 /* we are done with the DL-TBF here so far, let's clean up our local state: */
1319 ack_nack_desc := valueof(t_AckNackDescription_init)
1320
1321 /* Now that final DL block is ACKED and TBF is released, T3193 in PCU
1322 (T3192 in MS) was started and until it fires the MS will be abailable
1323 on PDCH in case new data arrives from SGSN. Let's verify it: */
1324 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1325 f_rx_rlcmac_dl_block_exp_pkt_ass(dl_block, sched_fn);
1326 f_tx_rlcmac_ul_block(ts_RLCMAC_CTRL_ACK(tlli), 0, sched_fn);
1327
1328 /* Now that we confirmed the new assignment in the dl-tbf, lets receive the data and ack it */
1329 f_rx_rlcmac_dl_block_exp_data(dl_block, sched_fn, data, 0);
1330 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
1331 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc), 0, sched_fn);
1332}
1333
1334/* Test scenario where MS wants to send some data on PDCH against SGSN and it is
1335 * answered, so TBFs for uplink and later for downlink are created.
1336 */
1337private function f_TC_mo_ping_pong(template (omit) MSRadioAccessCapabilityV ms_racap := omit, template (present) CodingScheme exp_cs_mcs := ?) runs on RAW_PCU_Test_CT {
1338 var GsmRrMessage rr_imm_ass;
1339 var PacketUlAssign ul_tbf_ass;
1340 var PacketDlAssign dl_tbf_ass;
1341 var RlcmacDlBlock dl_block;
1342 var PCUIF_Message pcu_msg;
1343 var octetstring data := f_rnd_octstring(10);
1344 var boolean ok;
1345 var uint32_t sched_fn;
1346 var OCT4 tlli := '00000001'O;
1347 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1348
1349 /* Initialize NS/BSSGP side */
1350 f_init_bssgp();
1351
1352 /* Initialize the PCU interface abstraction */
1353 f_init_raw(testcasename());
1354
1355 /* Establish BSSGP connection to the PCU */
1356 f_bssgp_establish();
1357 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1358
1359 /* Establish an Uplink TBF */
1360 ok := f_establish_tbf(rr_imm_ass);
1361 if (not ok) {
1362 setverdict(fail, "Failed to establish TBF");
1363 mtc.stop;
1364 }
1365 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1366 if (not ok) {
1367 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1368 mtc.stop;
1369 }
1370
1371 if (not istemplatekind(ms_racap, "omit")) {
1372 /* Send PACKET RESOURCE REQUEST to upgrade to EGPRS
1373 * (see 3GPP TS 04.60 "7.1.3.1 Initiation of the Packet resource request procedure")
1374 */
1375 f_tx_rlcmac_ul_block(ts_RLC_UL_CTRL_ACK(valueof(ts_RlcMacUlCtrl_PKT_RES_REQ(tlli, ms_racap))), 0);
1376 f_rx_rlcmac_dl_block_exp_pkt_ul_ass(dl_block, sched_fn);
1377 if (dl_block.ctrl.payload.u.ul_assignment.identity.tlli.tlli != tlli) {
1378 setverdict(fail, "Wrong TLLI ", dl_block.ctrl.payload.u.ul_assignment.identity.tlli, " received vs exp ", tlli);
1379 mtc.stop;
1380 }
1381 }
1382
1383 /* Send one UL block and make sure it is ACKED fine */
1384 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1);
1385 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, sched_fn);
1386 /* DL ACK/NACK sets poll+rrbp requesting PACKET CONTROL ACK */
1387 f_tx_rlcmac_ul_block(ts_RLCMAC_CTRL_ACK(tlli), 0, sched_fn);
1388
1389 /* UL block should be received in SGSN */
1390 BSSGP[0].receive(tr_BSSGP_UL_UD(tlli, mp_gb_cfg.cell_id));
1391
1392 /* Now SGSN sends some DL data, PCU will page on CCCH (PCH) */
1393 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1394 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1395
1396 ok := f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1397 if (not ok) {
1398 setverdict(fail, "Immediate Assignment not a Downlink TBF");
1399 mtc.stop;
1400 }
1401
1402 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1403 f_sleep(X2002);
1404 f_rx_rlcmac_dl_block_exp_data(dl_block, sched_fn, data, 0, exp_cs_mcs);
1405
1406 /* ACK the DL block */
1407 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
1408 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc), 0, sched_fn);
1409}
1410
1411/* Test scenario where MS wants to send some data on PDCH against SGSN and it is
1412 * answered, so TBFs for uplink and later for downlink are created.
1413 */
1414testcase TC_mo_ping_pong() runs on RAW_PCU_Test_CT {
1415 var CodingScheme exp_cs_mcs := CS_1;
1416 f_TC_mo_ping_pong(omit, exp_cs_mcs);
1417}
1418
1419
1420testcase TC_mo_ping_pong_with_ul_racap() runs on RAW_PCU_Test_CT {
1421 var MultislotCap_GPRS mscap_gprs := {
1422 gprsmultislotclass := '00011'B,
1423 gprsextendeddynalloccap := '0'B
1424 };
1425 var MSRadioAccessCapabilityV ms_racap := { valueof(ts_RaCapRec('0001'B /* E-GSM */, mscap_gprs, omit)) };
1426 var CodingScheme exp_cs_mcs := CS_2;
1427
1428 f_TC_mo_ping_pong(ms_racap, exp_cs_mcs);
1429}
1430
1431/* Test scenario where SGSN wants to send some data against MS and it is
1432 * answered by the MS on PDCH, so TBFs for downlink and later for uplink are created.
1433 */
1434private 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 {
1435 var GsmRrMessage rr_imm_ass;
1436 var PacketUlAssign ul_tbf_ass;
1437 var PacketDlAssign dl_tbf_ass;
1438 var RlcmacDlBlock dl_block;
1439 var PCUIF_Message pcu_msg;
1440 var octetstring data := f_rnd_octstring(10);
1441 var boolean ok;
1442 var uint32_t sched_fn;
1443 var OCT4 tlli := '00000001'O;
1444 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1445
1446 /* Initialize NS/BSSGP side */
1447 f_init_bssgp();
1448
1449 /* Initialize the PCU interface abstraction */
1450 f_init_raw(testcasename());
1451
1452 /* Establish BSSGP connection to the PCU */
1453 f_bssgp_establish();
1454 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1455
1456 /* SGSN sends some DL data, PCU will page on CCCH (PCH) */
1457 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data, ms_racap));
1458 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1459
1460 ok := f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1461 if (not ok) {
1462 setverdict(fail, "Immediate Assignment not a Downlink TBF");
1463 mtc.stop;
1464 }
1465
1466 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1467 f_sleep(X2002);
1468 f_rx_rlcmac_dl_block_exp_data(dl_block, sched_fn, data, 0, exp_cs_mcs);
1469
1470 /* ACK the DL block */
1471 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
1472 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc), 0, sched_fn);
1473
1474 /* Now MS wants to answer the DL data, Establish an Uplink TBF */
1475 ok := f_establish_tbf(rr_imm_ass);
1476 if (not ok) {
1477 setverdict(fail, "Failed to establish TBF");
1478 mtc.stop;
1479 }
1480 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1481 if (not ok) {
1482 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1483 mtc.stop;
1484 }
1485
1486 /* Send one UL block and make sure it is ACKED fine */
1487 f_tx_rlcmac_ul_n_blocks(ul_tbf_ass, 1);
1488 f_rx_rlcmac_dl_block_exp_ack_nack(dl_block, sched_fn);
1489 /* DL ACK/NACK sets poll+rrbp requesting PACKET CONTROL ACK */
1490 f_tx_rlcmac_ul_block(ts_RLCMAC_CTRL_ACK(tlli), 0, sched_fn);
1491
1492 /* UL block should be received in SGSN */
1493 BSSGP[0].receive(tr_BSSGP_UL_UD(tlli, mp_gb_cfg.cell_id));
1494}
1495
1496testcase TC_mt_ping_pong() runs on RAW_PCU_Test_CT {
1497 var CodingScheme exp_cs_mcs := CS_1;
1498 f_TC_mt_ping_pong(omit, exp_cs_mcs);
1499}
1500
1501/* TC_mt_ping_pong, but DL-UNITDATA contains RA Access capability with (M)CS
1502/* information about the MS */
1503testcase TC_mt_ping_pong_with_dl_racap() runs on RAW_PCU_Test_CT {
1504 var MultislotCap_GPRS_BSSGP mscap_gprs := {
1505 gprsmultislotclass := '00011'B,
1506 gprsextendeddynalloccap := '0'B
1507 } ;
1508 var MSRadioAccessCapabilityV_BSSGP ms_racap := { valueof(ts_RaCapRec_BSSGP('0001'B /* E-GSM */, mscap_gprs, omit)) };
1509 var CodingScheme exp_cs_mcs := CS_2;
1510 f_TC_mt_ping_pong(ms_racap, exp_cs_mcs);
1511}
1512
1513/* Verify that if PCU doesn't get an ACK for first DL block after IMM ASS, it
1514 * will retry by retransmitting both the IMM ASS + DL block after poll (ack)
1515 * timeout occurs (specified by sent RRBP on DL block). */
1516testcase TC_imm_ass_dl_block_retrans() runs on RAW_PCU_Test_CT {
1517 var GsmRrMessage rr_imm_ass;
1518 var PacketDlAssign dl_tbf_ass;
1519 var RlcmacDlBlock dl_block;
1520 var octetstring data := f_rnd_octstring(10);
1521 var boolean ok;
1522 var uint32_t sched_fn;
1523 var OCT4 tlli := '00000001'O;
1524 var AckNackDescription ack_nack_desc := valueof(t_AckNackDescription_init);
1525
1526 /* Initialize NS/BSSGP side */
1527 f_init_bssgp();
1528
1529 /* Initialize the PCU interface abstraction */
1530 f_init_raw(testcasename());
1531
1532 /* Establish BSSGP connection to the PCU */
1533 f_bssgp_establish();
1534 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1535
1536 /* SGSN sends some DL data, PCU will page on CCCH (PCH) */
1537 BSSGP[0].send(ts_BSSGP_DL_UD(tlli, data));
1538 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1539 ok := f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1540 if (not ok) {
1541 setverdict(fail, "Immediate Assignment not a Downlink TBF");
1542 mtc.stop;
1543 }
1544
1545 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1546 f_sleep(X2002);
1547 f_rx_rlcmac_dl_block_exp_data(dl_block, sched_fn, data, 0);
1548
1549 /* Now we don't ack the dl block (emulate MS failed receiveing IMM ASS
1550 * or GPRS DL, or DL ACK was lost for some reason). As a result, PCU
1551 * should retrigger IMM ASS + GPRS DL procedure after poll timeout. */
1552 f_pcuif_rx_pch_imm_tbf_ass(rr_imm_ass);
1553 ok := f_imm_ass_verify_dl_tbf_ass(rr_imm_ass, dl_tbf_ass);
1554 if (not ok) {
1555 setverdict(fail, "Immediate Assignment not a Downlink TBF");
1556 mtc.stop;
1557 }
1558 /* Wait timer X2002 and DL block is available after CCCH IMM ASS: */
1559 f_sleep(X2002);
1560 f_rx_rlcmac_dl_block_exp_data(dl_block, sched_fn, data, 0);
1561
1562 /* ACK the DL block */
1563 f_acknackdesc_ack_block(ack_nack_desc, dl_block, '1'B);
1564 f_tx_rlcmac_ul_block(ts_RLCMAC_DL_ACK_NACK(f_rlcmac_dl_block_get_tfi(dl_block), ack_nack_desc), 0, sched_fn);
1565}
1566
1567private function f_pkt_paging_match_imsi(in PacketPagingReq req, hexstring imsi) {
1568 var MobileIdentityLV_Paging mi_lv := req.repeated_pageinfo.cs.mobile_identity;
1569 var MobileIdentityV mi := dec_MobileIdentityV(mi_lv.mobile_id);
1570
1571 if (mi_lv.len != 8) { /* 8 octets: type of ID (3 bits) + even/odd flag (1 bit) + 15 BCD-encoded digits (60 bits) */
1572 setverdict(fail, "Mobile Identity length mismatch: ",
1573 "expected: 8, got: ", mi_lv.len);
1574 mtc.stop;
1575 }
1576
1577 /* Make sure MI contains IMSI before referencing it */
1578 if (mi.typeOfIdentity != '001'B) {
1579 setverdict(fail, "Mobile Identity must be of type IMSI ('001'B), ",
1580 "got: ", mi.typeOfIdentity);
1581 mtc.stop;
1582 } else if (mi.oddEvenInd_identity.imsi.digits != imsi) {
1583 setverdict(fail, "Mobile Identity contains unexpected IMSI, ",
1584 "expected: ", imsi, " got: ", mi.oddEvenInd_identity.imsi.digits);
1585 mtc.stop;
1586 }
1587}
1588
1589private function f_pkt_paging_match_tmsi(in PacketPagingReq req, template GsmTmsi tmsi) {
1590 if (not match(req.repeated_pageinfo.cs.tmsi, tmsi)) {
1591 setverdict(fail, "Mobile Identity (TMSI/P-TMSI) mismatch: ",
1592 "expected: ", tmsi, "got: ", req.repeated_pageinfo.cs.tmsi);
1593 mtc.stop;
1594 }
1595}
1596
1597/* Test CS paging over the BTS<->PCU socket.
1598 * 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.
1599 * Paging should be send on the PACCH.
1600 *
1601 * 1. Send a Paging Request over PCU socket.
1602 * 2. Send a Ready-To-Send message over PCU socket
1603 * 3. Expect a Paging Frame
1604 */
1605testcase TC_paging_cs_from_bts() runs on RAW_PCU_Test_CT {
1606 var GsmRrMessage rr_imm_ass;
1607 var PacketUlAssign ul_tbf_ass;
1608 var RlcmacDlBlock dl_block;
1609 var boolean ok;
1610 var OCT4 tlli := '00000001'O;
1611 var MobileIdentityLV mi;
1612 var octetstring mi_enc_lv;
1613 var hexstring imsi := f_gen_imsi(42);
1614
1615 /* Initialize NS/BSSGP side */
1616 f_init_bssgp();
1617
1618 /* Initialize the PCU interface abstraction */
1619 f_init_raw(testcasename());
1620
1621 /* Establish BSSGP connection to the PCU */
1622 f_bssgp_establish();
1623 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1624
1625 /* Establish an Uplink TBF */
1626 ok := f_establish_tbf(rr_imm_ass);
1627 if (not ok) {
1628 setverdict(fail, "Failed to establish TBF");
1629 mtc.stop;
1630 }
1631
1632 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1633 if (not ok) {
1634 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1635 mtc.stop;
1636 }
1637
1638
1639 /* build mobile Identity */
1640 mi := valueof(ts_MI_IMSI_LV(imsi));
1641 mi_enc_lv := enc_MobileIdentityLV(mi);
1642 /* Send paging request */
1643 BTS.send(ts_PCUIF_PAG_REQ(bts_nr := 0, id_lv := mi_enc_lv, chan_needed := 0,
1644 sapi :=PCU_IF_SAPI_PDTCH));
1645
1646 /* Receive it on BTS side towards MS */
1647 f_rx_rlcmac_dl_block_exp_pkt_pag_req(dl_block);
1648
1649 /* Make sure that Packet Paging Request contains the same IMSI */
1650 f_pkt_paging_match_imsi(dl_block.ctrl.payload.u.paging, imsi);
1651
1652 setverdict(pass);
1653}
1654
1655/* Test CS paging over Gb (SGSN->PCU->BTS[PDCH]).
1656 */
1657private function f_tc_paging_cs_from_sgsn(Nsvci bvci, boolean use_ptmsi := false)
1658runs on RAW_PCU_Test_CT {
1659 var GsmRrMessage rr_imm_ass;
1660 var PacketUlAssign ul_tbf_ass;
1661 var RlcmacDlBlock dl_block;
1662 var boolean ok;
1663 var OCT4 tlli := '00000001'O;
1664 var hexstring imsi := f_gen_imsi(42);
1665 var GsmTmsi tmsi;
1666
1667 /* Initialize NS/BSSGP side */
1668 f_init_bssgp();
1669
1670 /* Initialize the PCU interface abstraction */
1671 f_init_raw(testcasename());
1672
1673 /* Establish BSSGP connection to the PCU */
1674 f_bssgp_establish();
1675 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1676
1677 /* Establish an Uplink TBF */
1678 ok := f_establish_tbf(rr_imm_ass);
1679 if (not ok) {
1680 setverdict(fail, "Failed to establish TBF");
1681 mtc.stop;
1682 }
1683
1684 ok := f_imm_ass_verify_ul_tbf_ass(rr_imm_ass, ul_tbf_ass);
1685 if (not ok) {
1686 setverdict(fail, "Immediate Assignment not an Uplink TBF");
1687 mtc.stop;
1688 }
1689
1690 /* Send paging request with or without TMSI */
1691 if (use_ptmsi) {
1692 tmsi := oct2int(f_rnd_octstring(4)); /* Random P-TMSI */
1693 BSSGP[0].send(ts_BSSGP_CS_PAGING_PTMSI(bvci, imsi, tmsi));
1694 } else {
1695 BSSGP[0].send(ts_BSSGP_CS_PAGING_IMSI(bvci, imsi));
1696 }
1697
1698 /* Receive it on BTS side towards MS */
1699 f_rx_rlcmac_dl_block_exp_pkt_pag_req(dl_block);
1700
1701 /* Make sure that Packet Paging Request contains the same P-TMSI/IMSI */
1702 if (use_ptmsi) {
1703 f_pkt_paging_match_tmsi(dl_block.ctrl.payload.u.paging, tmsi);
1704 } else {
1705 f_pkt_paging_match_imsi(dl_block.ctrl.payload.u.paging, imsi);
1706 }
1707
1708 setverdict(pass);
1709}
1710
1711testcase TC_paging_cs_from_sgsn_sign_ptmsi() runs on RAW_PCU_Test_CT {
1712 f_tc_paging_cs_from_sgsn(0, true);
1713}
1714
1715testcase TC_paging_cs_from_sgsn_sign() runs on RAW_PCU_Test_CT {
1716 f_tc_paging_cs_from_sgsn(0);
1717}
1718
1719testcase TC_paging_cs_from_sgsn_ptp() runs on RAW_PCU_Test_CT {
1720 f_tc_paging_cs_from_sgsn(mp_gb_cfg.bvci);
1721}
1722
1723/* Test PS paging over Gb (SGSN->PCU->BTS[CCCH]).
1724 */
1725private function f_tc_paging_ps_from_sgsn(Nsvci bvci, boolean use_ptmsi := false)
1726runs on RAW_PCU_Test_CT {
1727 var OCT4 tlli := '00000001'O;
1728 var integer imsi_suff_tx := 423;
1729 var hexstring imsi := f_gen_imsi(imsi_suff_tx);
1730
1731 /* Initialize NS/BSSGP side */
1732 f_init_bssgp();
1733
1734 /* Initialize the PCU interface abstraction */
1735 f_init_raw(testcasename());
1736
1737 /* Establish BSSGP connection to the PCU */
1738 f_bssgp_establish();
1739 f_bssgp_client_llgmm_assign('FFFFFFFF'O, tlli);
1740
1741 /* Send BSSGP PAGING-PS (with or without TMSI), wait for RR Paging Request Type 1.
1742 * Make sure that both paging group (IMSI suffix) and Mobile Identity match. */
1743 if (use_ptmsi) {
1744 var OCT4 tmsi := f_rnd_octstring(4); /* Random P-TMSI */
1745 BSSGP[0].send(ts_BSSGP_PS_PAGING_PTMSI(bvci, imsi, oct2int(tmsi)));
1746 f_pcuif_rx_pch_pag_req1(t_MI_TMSI(tmsi), imsi_suff_tx);
1747 } else {
1748 BSSGP[0].send(ts_BSSGP_PS_PAGING_IMSI(bvci, imsi));
1749 f_pcuif_rx_pch_pag_req1(tr_MI_IMSI(imsi), imsi_suff_tx);
1750 }
1751
1752 setverdict(pass);
1753}
1754
1755testcase TC_paging_ps_from_sgsn_sign_ptmsi() runs on RAW_PCU_Test_CT {
1756 f_tc_paging_ps_from_sgsn(0, true);
1757}
1758
1759testcase TC_paging_ps_from_sgsn_sign() runs on RAW_PCU_Test_CT {
1760 f_tc_paging_ps_from_sgsn(0);
1761}
1762
1763testcase TC_paging_ps_from_sgsn_ptp() runs on RAW_PCU_Test_CT {
1764 f_tc_paging_ps_from_sgsn(mp_gb_cfg.bvci);
1765}
1766
1767private function f_TC_egprs_pkt_chan_req(in EGPRSPktChRequest req,
1768 template GsmRrMessage t_imm_ass := ?,
1769 PCUIF_BurstType bt := BURST_TYPE_1)
1770runs on RAW_PCU_Test_CT {
1771 var GsmRrMessage rr_msg;
1772 var uint16_t ra11;
1773 var boolean ok;
1774
1775 ra11 := enc_EGPRSPktChRequest2uint(req);
1776 log("Sending EGPRS Packet Channel Request (", ra11, "): ", req);
1777
1778 ok := f_establish_tbf(rr_msg, ra := ra11, is_11bit := 1, burst_type := bt);
1779 if (not ok) {
1780 setverdict(fail, "Failed to establush an Uplink TBF");
1781 mtc.stop;
1782 }
1783
1784 if (not match(rr_msg, t_imm_ass)) {
1785 setverdict(fail, "Immediate Assignment does not match");
1786 mtc.stop;
1787 }
1788
1789 setverdict(pass);
1790}
1791
1792testcase TC_egprs_pkt_chan_req_signalling() runs on RAW_PCU_Test_CT {
1793 var template GsmRrMessage imm_ass;
1794 var template IaRestOctets rest;
1795 var template EgprsUlAss ul_ass;
1796
1797 /* Initialize the PCU interface abstraction */
1798 f_init_raw(testcasename());
1799
1800 var EGPRSPktChRequest req := {
1801 /* NOTE: other fields are set in the loop */
1802 signalling := { tag := '110011'B }
1803 };
1804
1805 for (var integer i := 0; i < 6; i := i + 1) {
1806 var BIT5 ext_ra := int2bit(f_rnd_int(32), 5);
1807 req.signalling.random_bits := ext_ra;
1808
1809 /* For signalling, do we expect Multiblock UL TBF Assignment? */
1810 ul_ass := tr_EgprsUlAssMultiblock(ext_ra := ext_ra);
1811 rest := tr_IaRestOctets_EGPRSULAss(ul_ass);
1812 imm_ass := tr_IMM_TBF_ASS(dl := false, rest := rest);
1813
1814 f_TC_egprs_pkt_chan_req(req, imm_ass);
1815 }
1816}
1817
1818testcase TC_egprs_pkt_chan_req_one_phase() runs on RAW_PCU_Test_CT {
1819 var template GsmRrMessage imm_ass;
1820 var template IaRestOctets rest;
1821 var template EgprsUlAss ul_ass;
1822
1823 /* Initialize the PCU interface abstraction */
1824 f_init_raw(testcasename());
1825
1826 var EGPRSPktChRequest req := {
1827 /* NOTE: other fields are set in the loop */
1828 one_phase := { tag := '0'B }
1829 };
1830
1831 for (var integer i := 0; i < 6; i := i + 1) {
1832 var BIT5 ext_ra := int2bit(f_rnd_int(32), 5);
1833 var BIT5 mslot_class := int2bit(f_rnd_int(32), 5);
1834 var BIT2 priority := substr(ext_ra, 0, 2);
1835 var BIT3 rand := substr(ext_ra, 2, 3);
1836
1837 req.one_phase.multislot_class := mslot_class;
1838 req.one_phase.priority := priority;
1839 req.one_phase.random_bits := rand;
1840
1841 /* For one phase access, do we expect Dynamic UL TBF Assignment? */
1842 ul_ass := tr_EgprsUlAssDynamic(ext_ra := ext_ra);
1843 rest := tr_IaRestOctets_EGPRSULAss(ul_ass);
1844 imm_ass := tr_IMM_TBF_ASS(dl := false, rest := rest);
1845
1846 f_TC_egprs_pkt_chan_req(req, imm_ass);
1847 }
1848}
1849
1850testcase TC_egprs_pkt_chan_req_two_phase() runs on RAW_PCU_Test_CT {
1851 var template GsmRrMessage imm_ass;
1852 var template IaRestOctets rest;
1853 var template EgprsUlAss ul_ass;
1854
1855 /* Initialize the PCU interface abstraction */
1856 f_init_raw(testcasename());
1857
1858 var EGPRSPktChRequest req := {
1859 /* NOTE: other fields are set in the loop */
1860 two_phase := { tag := '110000'B }
1861 };
1862
1863 for (var integer i := 0; i < 6; i := i + 1) {
1864 var BIT5 ext_ra := int2bit(f_rnd_int(32), 5);
1865 var BIT2 priority := substr(ext_ra, 0, 2);
1866 var BIT3 rand := substr(ext_ra, 2, 3);
1867
1868 req.two_phase.priority := priority;
1869 req.two_phase.random_bits := rand;
1870
1871 /* For two phase access, do we expect Multiblock UL TBF Assignment? */
1872 ul_ass := tr_EgprsUlAssMultiblock(ext_ra := ext_ra);
1873 rest := tr_IaRestOctets_EGPRSULAss(ul_ass);
1874 imm_ass := tr_IMM_TBF_ASS(dl := false, rest := rest);
1875
1876 f_TC_egprs_pkt_chan_req(req, imm_ass);
1877 }
1878}
1879
1880control {
1881 execute( TC_pcuif_suspend() );
1882 execute( TC_ta_ptcch_idle() );
1883 execute( TC_ta_rach_imm_ass() );
1884 execute( TC_ta_idle_dl_tbf_ass() );
1885 execute( TC_ta_ptcch_ul_multi_tbf() );
1886 execute( TC_cs_lqual_ul_tbf() );
1887 execute( TC_cs_initial_ul() );
1888 execute( TC_cs_max_ul() );
1889 execute( TC_t3169() );
1890 execute( TC_t3193() );
1891 execute( TC_mo_ping_pong() );
1892 execute( TC_mo_ping_pong_with_ul_racap() );
1893 execute( TC_mt_ping_pong() );
1894 execute( TC_mt_ping_pong_with_dl_racap() );
1895 execute( TC_imm_ass_dl_block_retrans() );
1896 execute( TC_paging_cs_from_bts() );
1897 execute( TC_paging_cs_from_sgsn_sign_ptmsi() );
1898 execute( TC_paging_cs_from_sgsn_sign() );
1899 execute( TC_paging_cs_from_sgsn_ptp() );
1900 execute( TC_paging_ps_from_sgsn_sign_ptmsi() );
1901 execute( TC_paging_ps_from_sgsn_sign() );
1902 execute( TC_paging_ps_from_sgsn_ptp() );
1903
1904 /* EGPRS specific test cases */
1905 execute( TC_egprs_pkt_chan_req_signalling() );
1906 execute( TC_egprs_pkt_chan_req_one_phase() );
1907 execute( TC_egprs_pkt_chan_req_two_phase() );
1908}
1909
1910
1911
1912
1913
1914
Harald Weltea419df22019-03-21 17:23:04 +01001915}