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