blob: e6406b750611ffb3b864c7646f832186546e3add [file] [log] [blame]
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +02001module GPRS_Components {
2/*
3 * Osmocom PCU test suite in TTCN-3, components for GPRS handlng
4 * (C) 2018-2019 Harald Welte <laforge@gnumonks.org>
5 * (C) 2019 Vadim Yanitskiy <axilirator@gmail.com>
6 * (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
7 * All rights reserved.
8 *
9 * Released under the terms of GNU General Public License, Version 2 or
10 * (at your option) any later version.
11 *
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 */
14
15import from General_Types all;
16import from Osmocom_Types all;
17import from GSM_Types all;
18import from GSM_RR_Types all;
19
20import from Osmocom_VTY_Functions all;
21import from TELNETasp_PortType all;
22
23import from MobileL3_GMM_SM_Types all;
24import from RLCMAC_CSN1_Types all;
25import from RLCMAC_CSN1_Templates all;
26import from RLCMAC_Types all;
27import from RLCMAC_Templates all;
28
29import from MobileL3_CommonIE_Types all;
30import from L3_Templates all;
31
32import from NS_Types all;
33import from BSSGP_Types all;
34import from Osmocom_Gb_Types all;
35
36import from BSSGP_Emulation all; /* BssgpConfig */
37import from NS_Emulation all; /* NSConfiguration */
38
39import from UD_Types all;
40import from PCUIF_Types all;
41import from PCUIF_CodecPort all;
42import from PCUIF_Components all;
43import from IPL4asp_Types all;
44import from Native_Functions all;
45import from SGSN_Components all;
46
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +070047type record TsTrxBtsNum {
48 uint3_t ts_nr,
49 uint3_t trx_nr,
50 uint8_t bts_nr,
51 uint8_t blk_nr
52};
53
54template (value) TsTrxBtsNum ts_TsTrxBtsNum(uint3_t ts_nr := 7,
55 uint3_t trx_nr := 0,
56 uint8_t bts_nr := 0,
57 uint8_t blk_nr := 0) := {
58 ts_nr := ts_nr,
59 trx_nr := trx_nr,
60 bts_nr := bts_nr,
61 blk_nr := blk_nr
62};
63template TsTrxBtsNum tr_TsTrxBtsNum(template uint3_t ts_nr := ?,
64 template uint3_t trx_nr := ?,
65 template uint8_t bts_nr := ?,
66 template uint8_t blk_nr := ?) := {
67 ts_nr := ts_nr,
68 trx_nr := trx_nr,
69 bts_nr := bts_nr,
70 blk_nr := blk_nr
71};
72
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +020073type union PacketDlAssignChan {
74 PacketDlAssign ccch,
75 PacketDlAssignment pacch
76};
77
78type record DlTbf {
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +010079 GsmRrMessage rr_imm_ass optional,
80 PacketDlAssignChan ass optional,
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +020081 uint5_t tfi,
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +010082 GsmArfcn arfcn,
83 BIT8 ts_mask,
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +020084 AckNackDescription acknack_desc
85};
86
87type union PacketUlAssignChan {
88 PacketUlAssign ccch,
89 EgprsUlAss ccch_egprs,
90 PacketUlAssignment pacch
91};
92
93type record UlTbf {
Pau Espin Pedroleb980252020-05-18 18:28:17 +020094 GsmRrMessage rr_imm_ass optional,
95 PacketUlAssignChan ass optional,
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +020096 uint5_t tfi,
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +010097 GsmArfcn arfcn,
98 BIT8 ts_mask,
Pau Espin Pedroleb980252020-05-18 18:28:17 +020099 uint3_t usf[8],
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200100 boolean is_egprs,
101 uint14_t bsn,
102 CodingScheme tx_cs_mcs
103};
104
105type record GprsMS {
106 hexstring imsi,
107 GprsTlli tlli,
108 uint16_t ra,
109 uint8_t ra_is_11bit,
110 PCUIF_BurstType burst_type,
111 TimingAdvance ta,
112 int16_t lqual_cb,
113 UlTbf ul_tbf optional, /* TODO: Only 1 UL tbf supported for now */
114 DlTbf dl_tbf optional /* TODO: Only 1 DL tbf supported for now */
115};
116type record of GprsMS GprsMSArray;
117
118template AckNackDescription t_AckNackDescription_init := {
119 final_ack := '0'B,
120 starting_seq_nr := 0,
121 receive_block_bitmap := '0000000000000000000000000000000000000000000000000000000000000000'B
122}
123
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200124const uint3_t USF_UNUSED := 7; /* used to indicate PRACH */
125
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200126template (value) GprsMS t_GprsMS_def := {
127 imsi := f_gen_imsi(42),
Pau Espin Pedrolbfd69f62020-10-22 18:06:07 +0200128 tlli := f_gen_tlli(),
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200129 ra := bit2int(chan_req_def),
130 ra_is_11bit := 0,
131 burst_type := BURST_TYPE_0,
132 ta := 0,
133 lqual_cb := 0,
134 ul_tbf := omit,
135 dl_tbf := omit
136};
137
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100138template (value) DlTbf t_DlTbf_def := {
139 rr_imm_ass := omit,
140 ass := omit,
141 tfi := 0,
142 arfcn := 0,
143 ts_mask := '00000000'B,
144 acknack_desc := t_AckNackDescription_init
145};
146
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200147template (value) UlTbf t_UlTbf_def := {
148 rr_imm_ass := omit,
149 ass := omit,
150 tfi := 0,
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100151 arfcn := 0,
152 ts_mask := '00000000'B,
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200153 usf := { USF_UNUSED, USF_UNUSED, USF_UNUSED, USF_UNUSED, USF_UNUSED, USF_UNUSED, USF_UNUSED, USF_UNUSED },
154 is_egprs := false,
155 bsn := 0,
156 tx_cs_mcs := CS_1
157};
158
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200159type component MS_BTS_IFACE_CT {
160 /* Virtual BTS component */
161 var RAW_PCU_BTS_CT vc_BTS;
162 /* Connection to the BTS component (one for now) */
163 port RAW_PCU_MSG_PT BTS;
164
Pau Espin Pedrolbfd69f62020-10-22 18:06:07 +0200165 /* Support only 8 ms for now */
166 var GprsMS g_ms[8];
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200167
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200168 /* Value at which Countdown Procedure starts. Announced by network (GPRS Cell Options as per TS 04.60 Chapter 12.24) */
169 var uint4_t g_bs_cv_max := 4;
170}
171
Pau Espin Pedrolbfd69f62020-10-22 18:06:07 +0200172function f_init_gprs_ms(integer num_ms := 1, template (value) GprsMS ms_params := t_GprsMS_def) runs on MS_BTS_IFACE_CT
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200173{
Pau Espin Pedrolbfd69f62020-10-22 18:06:07 +0200174 for (var integer i := 0; i < num_ms; i := i + 1 ) {
175 g_ms[i] := valueof(ms_params);
176 }
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200177}
178
179
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200180function f_shutdown(charstring file, integer line,
181 boolean final := false)
182runs on MS_BTS_IFACE_CT {
183 /* Determine if the test case was aborted in the middle */
184 if (not final) {
185 log("Test case ", testcasename(), " aborted at ", file, ":", line);
186 } else {
187 /* Guard verdict to avoid 'none' */
188 setverdict(pass);
189 }
190
191 /* Properly shutdown virtual BTS and its clock generator */
192 BTS.send(ts_RAW_PCU_CMD(GENERAL_CMD_SHUTDOWN));
193 vc_BTS.done; /* wait untill it's done */
194
195 /* Shutdown the others and MTC */
196 all component.stop;
197 mtc.stop;
198}
199
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200200function f_ultbf_new_from_rr_imm_ass(in GsmRrMessage rr_imm_ass)
201runs on MS_BTS_IFACE_CT return UlTbf {
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200202 var UlTbf ul_tbf := valueof(t_UlTbf_def);
203 var uint3_t tn_allocated := rr_imm_ass.payload.imm_ass.pkt_chan_desc.tn;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200204
205 ul_tbf.rr_imm_ass := rr_imm_ass;
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100206 if (rr_imm_ass.payload.imm_ass.pkt_chan_desc.presence == '0'B and
207 rr_imm_ass.payload.imm_ass.pkt_chan_desc.zero.hopping == '0'B) {
208 ul_tbf.arfcn := rr_imm_ass.payload.imm_ass.pkt_chan_desc.zero.arfcn;
209 }
210 ul_tbf.ts_mask[tn_allocated] := '1'B;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200211
212 /* Make sure we received an UL TBF Assignment */
213 if (match(rr_imm_ass, tr_IMM_TBF_ASS(dl := false, rest := tr_IaRestOctets_ULAss(?)))) {
214 ul_tbf.ass.ccch := rr_imm_ass.payload.imm_ass.rest_octets.hh.pa.uldl.ass.ul;
215 log("Rx Uplink TBF GPRS assignment: ", ul_tbf.ass.ccch);
216 ul_tbf.is_egprs := false;
217 if (match(ul_tbf.ass.ccch, tr_PacketUlDynAssign)) {
218 ul_tbf.tfi := ul_tbf.ass.ccch.dynamic.tfi_assignment;
Pau Espin Pedrol90401112020-05-20 17:36:27 +0200219 ul_tbf.tx_cs_mcs := f_rlcmac_block_ChCodingCommand2cs_mcs(ul_tbf.ass.ccch.dynamic.ch_coding_cmd);
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200220 ul_tbf.usf[tn_allocated] := ul_tbf.ass.ccch.dynamic.usf;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200221 } else if (match(ul_tbf.ass.ccch, tr_PacketUlSglAssign)) {
222 /* Nothing to do here yet */
223 }
224 } else if (match(rr_imm_ass, tr_IMM_TBF_ASS(dl := false, rest := tr_IaRestOctets_EGPRSULAss(?)))) {
225 ul_tbf.ass.ccch_egprs := rr_imm_ass.payload.imm_ass.rest_octets.lh.egprs_ul;
226 log("Rx Uplink TBF EGPRS assignment: ", ul_tbf.ass.ccch_egprs);
227 ul_tbf.is_egprs := true;
228 if (match(ul_tbf.ass.ccch_egprs, tr_EgprsUlAssDynamic)) {
229 ul_tbf.tfi := ul_tbf.ass.ccch_egprs.dynamic.tfi_assignment;
Pau Espin Pedrol90401112020-05-20 17:36:27 +0200230 ul_tbf.tx_cs_mcs := f_rlcmac_block_EgprsChCodingCommand2cs_mcs(ul_tbf.ass.ccch_egprs.dynamic.egprs_ch_coding_cmd);
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200231 ul_tbf.usf[tn_allocated] := ul_tbf.ass.ccch_egprs.dynamic.usf;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200232 } else if (match(ul_tbf.ass.ccch_egprs, tr_EgprsUlAssMultiblock)) {
233 /* Nothing to do here yet */
234 }
235 } else {
236 setverdict(fail, "Failed to match UL TBF Assignment: ", rr_imm_ass);
237 f_shutdown(__BFILE__, __LINE__);
238 }
239
240 setverdict(pass);
241 return ul_tbf;
242}
243
244function f_ultbf_new_from_ass_pacch(RlcmacDlBlock dl_block)
245runs on MS_BTS_IFACE_CT return UlTbf {
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200246 var UlTbf ul_tbf := valueof(t_UlTbf_def);
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100247 var boolean freq_par_present := false;
248 var FrequencyParameters freq_par;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200249
250 ul_tbf.ass.pacch := dl_block.ctrl.payload.u.ul_assignment;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200251 ul_tbf.tx_cs_mcs := f_rlcmac_dl_block_get_assigned_ul_cs_mcs(dl_block);
252 ul_tbf.tfi := f_rlcmac_dl_block_get_tfi(dl_block);
253 /* TODO: handle GlobalTfiOrTlli tfi_or_tlli from pkt_ul_ass */
254
255 /* TODO: support single block allocation */
256 if (match(dl_block, tr_RLCMAC_UL_PACKET_ASS_GPRS(?, tr_PktUlAssGprsDynamic(tr_DynamicAllocation(?))))) {
257 ul_tbf.tfi := dl_block.ctrl.payload.u.ul_assignment.gprs.dyn_block_alloc.ul_tfi_assignment;
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100258 freq_par_present := dl_block.ctrl.payload.u.ul_assignment.gprs.freq_par_present == '1'B;
259 if (freq_par_present) {
260 freq_par := dl_block.ctrl.payload.u.ul_assignment.gprs.freq_par;
261 }
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200262 ul_tbf.is_egprs := false;
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200263 for (var integer i := 0; i < 8; i := i + 1) {
264 if (dl_block.ctrl.payload.u.ul_assignment.gprs.dyn_block_alloc.ts_allocation.ts[i].presence == '1'B) {
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100265 ul_tbf.ts_mask[i] := '1'B;
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200266 ul_tbf.usf[i] := dl_block.ctrl.payload.u.ul_assignment.gprs.dyn_block_alloc.ts_allocation.ts[i].usf_tn;
267 }
268 }
269 } else if (match(dl_block, tr_RLCMAC_UL_PACKET_ASS_EGPRS(?, tr_PktUlAssEgprsDynamic(tr_DynamicAllocation(?))))) {
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200270 ul_tbf.tfi := dl_block.ctrl.payload.u.ul_assignment.egprs.dyn_block_alloc.ul_tfi_assignment;
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100271 freq_par_present := dl_block.ctrl.payload.u.ul_assignment.egprs.freq_par_present == '1'B;
272 if (freq_par_present) {
273 freq_par := dl_block.ctrl.payload.u.ul_assignment.egprs.freq_par;
274 }
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200275 ul_tbf.is_egprs := true;
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200276 for (var integer i := 0; i < 8; i := i + 1) {
277 if (dl_block.ctrl.payload.u.ul_assignment.egprs.dyn_block_alloc.ts_allocation.ts[i].presence == '1'B) {
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100278 ul_tbf.ts_mask[i] := '1'B;
Pau Espin Pedroleb980252020-05-18 18:28:17 +0200279 ul_tbf.usf[i] := dl_block.ctrl.payload.u.ul_assignment.egprs.dyn_block_alloc.ts_allocation.ts[i].usf_tn;
280 }
281 }
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200282 }
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100283
284 /* FIXME: freq_par and arfcn are optional. in that case we need to
285 * infer/reuse from current dl_tbf or ul_tbf */
286 if (freq_par_present and freq_par.presence == '00'B) {
287 ul_tbf.arfcn := freq_par.arfcn;
288 }
289
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200290 return ul_tbf;
291}
292
293function f_dltbf_new_from_rr_imm_ass(in GsmRrMessage rr_imm_ass, template PacketDlAssign dl_ass := tr_PacketDlAssign(?))
294runs on MS_BTS_IFACE_CT return DlTbf {
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100295 var DlTbf dl_tbf := valueof(t_DlTbf_def);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200296
297 dl_tbf.rr_imm_ass := rr_imm_ass;
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100298 if (rr_imm_ass.payload.imm_ass.pkt_chan_desc.presence == '0'B and
299 rr_imm_ass.payload.imm_ass.pkt_chan_desc.zero.hopping == '0'B) {
300 dl_tbf.arfcn := rr_imm_ass.payload.imm_ass.pkt_chan_desc.zero.arfcn;
301 }
302 dl_tbf.ts_mask[rr_imm_ass.payload.imm_ass.pkt_chan_desc.tn] := '1'B;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200303
304 /* Make sure we received a DL TBF Assignment */
305 if (match(rr_imm_ass, tr_IMM_TBF_ASS(dl := true, rest := tr_IaRestOctets_DLAss(dl_ass)))) {
306 dl_tbf.ass.ccch := rr_imm_ass.payload.imm_ass.rest_octets.hh.pa.uldl.ass.dl;
307 log("Rx Downlink TBF assignment: ", dl_tbf.ass);
308 } else {
309 setverdict(fail, "Failed to match DL TBF Assignment: ", rr_imm_ass);
310 f_shutdown(__BFILE__, __LINE__);
311 }
312
313 /* TODO: match TLLI */
314 if (dl_tbf.ass.ccch.group1_present == '1'B) {
315 dl_tbf.tfi := dl_tbf.ass.ccch.group1.tfi_assignment;
316 } else {
317 setverdict(fail, "Immediate Assignment contains no DL TFI");
318 f_shutdown(__BFILE__, __LINE__);
319 }
320
321 setverdict(pass);
322 return dl_tbf;
323}
324
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200325function f_dltbf_new_from_ass_pacch(RlcmacDlBlock dl_block)
326runs on MS_BTS_IFACE_CT return DlTbf {
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100327 var DlTbf dl_tbf := valueof(t_DlTbf_def);
328 var boolean freq_par_present := false;
329 var FrequencyParameters freq_par;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200330
331 dl_tbf.ass.pacch := dl_block.ctrl.payload.u.dl_assignment;
332 dl_tbf.tfi := f_rlcmac_dl_block_get_tfi(dl_block);
333 /* TODO: handle GlobalTfiOrTlli tfi_or_tlli from pkt_dl_ass */
Pau Espin Pedrolb20b7e52020-10-28 21:28:45 +0100334
335 if (match(dl_block, tr_RLCMAC_DL_PACKET_ASS(?))) {
336 dl_tbf.tfi := dl_block.ctrl.payload.u.dl_assignment.dl_tfi_assignment;
337 freq_par_present := dl_block.ctrl.payload.u.dl_assignment.freq_par_present == '1'B;
338 if (freq_par_present) {
339 freq_par := dl_block.ctrl.payload.u.dl_assignment.freq_par;
340 }
341 dl_tbf.ts_mask := dl_block.ctrl.payload.u.dl_assignment.timeslot_alloc; /* TODO: is this the correct order ? */
342 /* TODO: check egprs in dl_assignment.rel_additions (PktDlAssR99Additions) */
343 }
344
345 /* FIXME: freq_par and arfcn are optional. in that case we need to
346 * infer/reuse from current dl_tbf or ul_tbf */
347 if (freq_par_present and freq_par.presence == '00'B) {
348 dl_tbf.arfcn := freq_par.arfcn;
349 }
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200350 return dl_tbf;
351}
352
Pau Espin Pedrol05b6c172020-06-26 17:28:23 +0200353function f_ultbf_inc_bsn(inout UlTbf ul_tbf)
354runs on MS_BTS_IFACE_CT {
355 ul_tbf.bsn := ul_tbf.bsn + 1;
356 ul_tbf.bsn := ul_tbf.bsn mod 128; /* FIXME: EGPRS SNS: 2048 */
357}
358
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200359function f_ms_use_ra(inout GprsMS ms, uint16_t ra, uint8_t ra_is_11bit := 0)
360runs on MS_BTS_IFACE_CT {
361 ms.ra_is_11bit := ra_is_11bit;
362 ms.ra := ra;
363 if (ra_is_11bit == 0) {
364 ms.burst_type := BURST_TYPE_0;
365 } else {
366 ms.burst_type := BURST_TYPE_1;
367 }
368}
369
Vadim Yanitskiy7431e9e2020-07-21 01:59:17 +0700370function f_ms_rx_pkt_ass_pacch(inout GprsMS ms, out uint32_t poll_fn,
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700371 template RlcmacDlBlock t_pkt_ass := ?,
372 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200373runs on MS_BTS_IFACE_CT return RlcmacDlBlock {
374 var RlcmacDlBlock dl_block;
375 var uint32_t dl_fn;
376
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700377 f_rx_rlcmac_dl_block(dl_block, dl_fn, nr := nr);
Vadim Yanitskiy7431e9e2020-07-21 01:59:17 +0700378 if (not match(dl_block, t_pkt_ass)) {
379 setverdict(fail, "Failed to match Packet Assignment:", t_pkt_ass);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200380 f_shutdown(__BFILE__, __LINE__);
381 }
382
383 poll_fn := f_rrbp_ack_fn(dl_fn, dl_block.ctrl.mac_hdr.rrbp);
384
385 if (match(dl_block, tr_RLCMAC_UL_PACKET_ASS)) {
386 ms.ul_tbf := f_ultbf_new_from_ass_pacch(dl_block);
387 if (ms.ul_tbf.ass.pacch.identity.tlli.tlli != ms.tlli) {
388 setverdict(fail, "Wrong TLLI ", ms.ul_tbf.ass.pacch.identity.tlli, " received vs exp ", ms.tlli);
389 f_shutdown(__BFILE__, __LINE__);
390 }
391 } else if (match(dl_block, tr_RLCMAC_DL_PACKET_ASS)) {
392 ms.dl_tbf := f_dltbf_new_from_ass_pacch(dl_block);
Pau Espin Pedrol25e0f292020-10-29 12:36:40 +0100393 if (ischosen(ms.dl_tbf.ass.pacch.tfi_or_tlli.tlli) and
394 ms.dl_tbf.ass.pacch.tfi_or_tlli.tlli.tlli != ms.tlli) {
395 setverdict(fail, "Wrong TLLI ", ms.dl_tbf.ass.pacch.tfi_or_tlli.tlli.tlli, " received vs exp ", ms.tlli);
396 f_shutdown(__BFILE__, __LINE__);
397 }
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200398 } else {
399 setverdict(fail, "Should not happen:", dl_block);
400 f_shutdown(__BFILE__, __LINE__);
401 }
402
403 return dl_block;
404}
405
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700406function f_ms_establish_ul_tbf(inout GprsMS ms, template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200407runs on MS_BTS_IFACE_CT {
408 var GsmRrMessage rr_imm_ass;
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200409
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700410 rr_imm_ass := f_pcuif_tx_rach_rx_imm_ass(ms.ra, ms.ra_is_11bit, ms.burst_type, ms.ta, nr := nr);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200411 ms.ul_tbf := f_ultbf_new_from_rr_imm_ass(rr_imm_ass);
412}
413
Vadim Yanitskiy84d1dd52020-05-28 21:09:22 +0700414function f_ms_exp_dl_tbf_ass_ccch(inout GprsMS ms, template PCUIF_Sapi sapi := PCU_IF_SAPI_AGCH,
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700415 template GsmRrMessage t_imm_ass := tr_IMM_TBF_ASS(true, ?, ?),
416 template (present) TsTrxBtsNum nr := tr_TsTrxBtsNum)
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200417runs on MS_BTS_IFACE_CT {
418 var GsmRrMessage rr_imm_ass;
419
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700420 rr_imm_ass := f_pcuif_rx_imm_ass(sapi, t_imm_ass, nr := nr);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200421 ms.dl_tbf := f_dltbf_new_from_rr_imm_ass(rr_imm_ass, tr_PacketDlAssign(ms.tlli));
422}
423
424/* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700425function f_ms_tx_data_ind(inout GprsMS ms, octetstring data, uint32_t fn := 0,
426 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200427runs on MS_BTS_IFACE_CT {
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700428 f_pcuif_tx_data_ind(data, ms.lqual_cb, fn, nr := nr);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200429}
430
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700431function f_ms_tx_ul_block(inout GprsMS ms, template (value) RlcmacUlBlock ul_data,
432 uint32_t fn := 0, template (omit) CodingScheme force_cs_mcs := omit,
433 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200434runs on MS_BTS_IFACE_CT return integer {
435 var octetstring data;
436 var integer padding_len;
Pau Espin Pedrol245bfcb2020-06-30 20:17:07 +0200437 var CodingScheme cs_mcs;
438 var uint32_t cs_mcs_len;
439
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200440 /* Encode the payload of DATA.ind */
441 data := enc_RlcmacUlBlock(valueof(ul_data));
Pau Espin Pedrol245bfcb2020-06-30 20:17:07 +0200442
443 if (ispresent(force_cs_mcs)) {
444 cs_mcs := valueof(force_cs_mcs);
445 } else if (ischosen(ul_data.ctrl)) {
446 cs_mcs := CS_1; /* CTRL is always CS1 */
447 } else {
448 /* Add padding to encode payload to minimum required CS/MCS: */
449 cs_mcs := f_rlcmac_block_len_required_cs_mcs(lengthof(data), ischosen(ul_data.data_egprs));
450 }
451
452 cs_mcs_len := f_rlcmac_cs_mcs2block_len(cs_mcs);
453 padding_len := cs_mcs_len - lengthof(data);
454 if (padding_len < 0) {
455 setverdict(fail, "Unable to encode UL block of size ", lengthof(data), " with ", cs_mcs);
456 f_shutdown(__BFILE__, __LINE__);
457 }
458 data := f_pad_oct(data, cs_mcs_len, '00'O);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200459
460 /* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700461 f_ms_tx_data_ind(ms, data, fn, nr := nr);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200462 return padding_len;
463}
464
465/* FIXME: Only supports sending CS-1 so far */
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700466function f_ms_tx_ul_data_block(inout GprsMS ms, octetstring payload,
467 uint4_t cv := 15, boolean with_tlli := false, uint32_t fn := 0,
468 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200469runs on MS_BTS_IFACE_CT return integer {
470 var template (value) RlcmacUlBlock ul_data;
471 ul_data := t_RLCMAC_UL_DATA(tfi := ms.ul_tbf.tfi,
472 cv := cv,
473 bsn := ms.ul_tbf.bsn,
474 blocks := {t_RLCMAC_LLCBLOCK(payload)});
475 if (with_tlli) {
476 ul_data.data.mac_hdr.tlli_ind := true;
477 ul_data.data.tlli := ms.tlli;
478 }
Pau Espin Pedrol05b6c172020-06-26 17:28:23 +0200479 f_ultbf_inc_bsn(ms.ul_tbf);
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700480 return f_ms_tx_ul_block(ms, ul_data, fn, nr := nr);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200481}
482
483/* Send random payload for last "num_blocks" blocks in Ul TBF (ending with CV=0). */
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700484function f_ms_tx_ul_data_block_multi(inout GprsMS ms, integer num_blocks := 1, boolean with_tlli := false,
485 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200486runs on MS_BTS_IFACE_CT return octetstring {
487 var octetstring total_payload := ''O;
488
489 for (var integer i := 0; i < num_blocks; i := i + 1) {
490 var integer padding_len;
491 var octetstring payload := f_rnd_octstring(10);
492 /* Prepare a new UL block (CV, random payload) */
493 var integer cv := num_blocks - i - 1;
494 if (cv > g_bs_cv_max) {
495 cv := 15;
496 }
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700497 padding_len := f_ms_tx_ul_data_block(ms, payload, cv := cv, with_tlli := with_tlli, nr := nr);
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200498 total_payload := total_payload & payload & f_pad_oct(''O, padding_len, '00'O);
499 }
500 return total_payload;
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200501}
502
503function f_rlcmac_dl_block_get_tfi(RlcmacDlBlock dl_block)
504runs on MS_BTS_IFACE_CT return uint5_t {
505 if (ischosen(dl_block.data)) {
506 return dl_block.data.mac_hdr.hdr_ext.tfi;
507 } else if (ischosen(dl_block.data_egprs)) {
508 return dl_block.data_egprs.mac_hdr.tfi;
509 } else { /* Ctrl block */
510 if (match(dl_block, tr_RLCMAC_UL_PACKET_ASS_GPRS(?, tr_PktUlAssGprsDynamic(tr_DynamicAllocation(?))))) {
511 return dl_block.ctrl.payload.u.ul_assignment.gprs.dyn_block_alloc.ul_tfi_assignment;
512 }
513 if (match(dl_block, tr_RLCMAC_UL_PACKET_ASS_EGPRS(?, tr_PktUlAssEgprsDynamic(tr_DynamicAllocation(?))))) {
514 return dl_block.ctrl.payload.u.ul_assignment.egprs.dyn_block_alloc.ul_tfi_assignment;
515 }
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200516 if (match(dl_block, tr_RLCMAC_DL_PACKET_ASS(?))) {
517 return dl_block.ctrl.payload.u.dl_assignment.dl_tfi_assignment;
518 }
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200519 }
520 setverdict(fail, "DlBlock doesn't contain a TFI:", dl_block);
521 f_shutdown(__BFILE__, __LINE__);
522 return 0; /* make compiler happy */
523}
524
525/* Get the Chan coding command from a dl block containing PACCH UL Assignment */
526function f_rlcmac_dl_block_get_assigned_ul_cs_mcs(RlcmacDlBlock dl_block)
527runs on MS_BTS_IFACE_CT return CodingScheme {
528 if (match(dl_block, tr_RLCMAC_UL_PACKET_ASS_GPRS(?, tr_PktUlAssGprsDynamic(?)))) {
529 return f_rlcmac_block_ChCodingCommand2cs_mcs(dl_block.ctrl.payload.u.ul_assignment.gprs.ch_coding_cmd);
530 }
531 if (match(dl_block, tr_RLCMAC_UL_PACKET_ASS_EGPRS(?, tr_PktUlAssEgprsDynamic(?)))) {
532 return f_rlcmac_block_EgprsChCodingCommand2cs_mcs(dl_block.ctrl.payload.u.ul_assignment.egprs.chan_coding_cmd);
533 }
534 setverdict(fail, "DlBlock doesn't contain CS_MCS information:", dl_block);
535 f_shutdown(__BFILE__, __LINE__);
536 return CS_1; /* make compiler happy */
537}
538
539/* TS 44.060 sec 12.3 Ack/Nack Description */
540function f_acknackdesc_ack_block(inout AckNackDescription desc, RlcmacDlBlock dl_block, BIT1 final_ack := '0'B)
541{
542 var uint7_t bsn;
543 var integer i;
544 var integer inc;
545
546 if (ischosen(dl_block.data)) {
547 bsn := dl_block.data.mac_hdr.hdr_ext.bsn;
548 } else {
549 bsn := dl_block.data_egprs.mac_hdr.bsn1;
550 }
551
552 inc := bsn - desc.starting_seq_nr + 1;
553 /* Filling hole? */
554 if (bsn < desc.starting_seq_nr) {
555 desc.receive_block_bitmap[lengthof(desc.receive_block_bitmap) - (desc.starting_seq_nr - bsn)] := int2bit(1, 1);
556 return;
557 }
558
559 /* SSN is increased, and so RBB values need to be moved */
560 for (i := 0; i < lengthof(desc.receive_block_bitmap) - inc; i := i+1) {
561 desc.receive_block_bitmap[i] := desc.receive_block_bitmap[i + inc];
562 }
563 for (i := lengthof(desc.receive_block_bitmap) - inc; i < lengthof(desc.receive_block_bitmap) - 1; i := i+1) {
564 desc.receive_block_bitmap[i] := int2bit(0, 1);
565 }
566 /* Now we can set current bit and update SSN */
567 desc.starting_seq_nr := bsn + 1;
568 desc.receive_block_bitmap[lengthof(desc.receive_block_bitmap) - 1] := int2bit(1, 1);
569
570 /* Finally update the final_ack bit as requested: */
571 desc.final_ack := final_ack;
572}
573
574/* This function can be used to send DATA.cnf in response to the IUT originated DATA.req.
575 * NOTE: it's the responsibility of caller to make sure that pcu_msg contains u.data_req. */
576function f_pcuif_tx_data_cnf(in PCUIF_Message pcu_msg)
577runs on MS_BTS_IFACE_CT {
578 var PCUIF_Message pcu_msg_cnf := {
579 msg_type := PCU_IF_MSG_DATA_CNF,
580 bts_nr := pcu_msg.bts_nr,
581 spare := pcu_msg.spare,
582 u := { data_cnf := pcu_msg.u.data_req }
583 };
584
585 /* PCU wants DATA.cnf containing basically everything that was in DATA.req,
586 * but PCU_IF_SAPI_PCH is a special case - paging group shall be excluded. */
587 if (pcu_msg.u.data_req.sapi == PCU_IF_SAPI_PCH) {
588 pcu_msg_cnf.u.data_cnf.data := substr(pcu_msg.u.data_req.data, 3,
589 pcu_msg.u.data_req.len - 3);
590 }
591
592 BTS.send(pcu_msg_cnf);
593}
594
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200595////////////////////////
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700596// Low level APIs
Pau Espin Pedrol4f7b8fd2020-05-18 18:28:17 +0200597////////////////////////
598
Vadim Yanitskiy7466c332020-05-28 20:41:19 +0700599function f_pcuif_rx_imm_ass(template PCUIF_Sapi sapi := PCU_IF_SAPI_AGCH,
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700600 template GsmRrMessage t_imm_ass := ?,
601 template (present) TsTrxBtsNum nr := tr_TsTrxBtsNum)
Vadim Yanitskiy7466c332020-05-28 20:41:19 +0700602runs on MS_BTS_IFACE_CT return GsmRrMessage {
603 var GsmRrMessage rr_imm_ass;
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200604 var PCUIF_Message pcu_msg;
605 var octetstring data;
606 timer T;
607
608 T.start(2.0);
609 alt {
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700610 [] BTS.receive(tr_PCUIF_DATA_REQ(nr.bts_nr, nr.trx_nr, ts_nr := 0,
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200611 sapi := sapi, data := ?)) -> value pcu_msg {
612 /* On PCH the payload is prefixed with paging group (3 octets): skip it.
613 * TODO: add an additional template parameter, so we can match it. */
614 if (pcu_msg.u.data_req.sapi == PCU_IF_SAPI_PCH) {
615 data := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
616 } else {
617 data := pcu_msg.u.data_req.data;
618 }
619
620 rr_imm_ass := dec_GsmRrMessage(data);
621 if (not match(rr_imm_ass, t_imm_ass)) {
622 /* Not for us? Wait for more. */
623 repeat;
624 }
625
626 log("Rx Immediate Assignment: ", rr_imm_ass);
Pau Espin Pedrol34c940b2020-05-28 19:56:11 +0700627
628 /* Send DATA.cnf back to the IUT (only needed for PCH) */
629 if (pcu_msg.u.data_req.sapi == PCU_IF_SAPI_PCH) {
630 f_pcuif_tx_data_cnf(pcu_msg);
631 }
632
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200633 setverdict(pass);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200634 }
635 [] BTS.receive { repeat; }
636 [] T.timeout {
637 setverdict(fail, "Timeout waiting for Immediate Assignment");
Pau Espin Pedrolfddc20b2020-05-28 19:50:29 +0700638 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200639 }
640 }
641
Vadim Yanitskiy7466c332020-05-28 20:41:19 +0700642 return rr_imm_ass;
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200643}
644
645/* One phase packet access (see 3GPP TS 44.018, table 9.1.8.1) */
646const BIT8 chan_req_def := '01111000'B;
647
648/* Establish an Uplink TBF by sending RACH.ind towards the PCU */
Vadim Yanitskiy28d18e12020-05-29 15:25:59 +0700649function f_pcuif_tx_rach_rx_imm_ass(uint16_t ra := bit2int(chan_req_def),
650 uint8_t is_11bit := 0,
651 PCUIF_BurstType burst_type := BURST_TYPE_0,
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700652 TimingAdvance ta := 0,
653 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Vadim Yanitskiy7466c332020-05-28 20:41:19 +0700654runs on MS_BTS_IFACE_CT return GsmRrMessage {
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200655 var uint32_t fn;
656
657 /* FIXME: ask the BTS component to give us the current TDMA fn */
658 fn := 1337 + ta;
659
660 /* Send RACH.ind */
661 log("Sending RACH.ind on fn=", fn, " with RA=", ra, ", TA=", ta);
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700662 BTS.send(ts_PCUIF_RACH_IND(nr.bts_nr, nr.trx_nr, ts_nr := 0,
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200663 ra := ra, is_11bit := is_11bit,
664 burst_type := burst_type,
665 fn := fn, arfcn := 871,
666 qta := ta * 4));
667
668 /* 3GPP TS 44.018, table 9.1.8.1, note 2b: Request Reference shall be set to 127
669 * when Immediate Assignment is triggered by EGPRS Packet Channel Request. Here
670 * we assume that 11 bit RA always contains EGPRS Packet Channel Request. */
671 if (is_11bit != 0) { ra := 127; }
672
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700673 /* Expect Immediate (TBF) Assignment on the same TS/TRX/BTS */
674 return f_pcuif_rx_imm_ass(PCU_IF_SAPI_AGCH, tr_IMM_TBF_ASS(false, ra, fn), nr);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200675}
676
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200677/* Enqueue DATA.ind (both TDMA frame and block numbers to be patched) */
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700678function f_pcuif_tx_data_ind(octetstring data, int16_t lqual_cb := 0, uint32_t fn := 0,
679 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200680runs on MS_BTS_IFACE_CT {
681 var template RAW_PCU_EventParam ev_param := {tdma_fn := ? };
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700682 BTS.send(ts_PCUIF_DATA_IND(nr.bts_nr, nr.trx_nr, nr.ts_nr, nr.blk_nr,
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200683 sapi := PCU_IF_SAPI_PDTCH, data := data,
684 fn := fn, arfcn := 871, lqual_cb := lqual_cb));
685 if (fn != 0) {
686 ev_param := {tdma_fn := fn };
687 }
688 BTS.receive(tr_RAW_PCU_EV(TDMA_EV_PDTCH_BLOCK_SENT, ev_param));
689}
690
691/* Enqueue RTS.req, expect DATA.req with UL ACK from the PCU */
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700692function f_pcuif_rx_data_req(out PCUIF_Message pcu_msg,
693 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200694runs on MS_BTS_IFACE_CT {
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700695 BTS.send(ts_PCUIF_RTS_REQ(nr.bts_nr, nr.trx_nr, nr.ts_nr,
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200696 sapi := PCU_IF_SAPI_PDTCH, fn := 0,
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700697 arfcn := 871, block_nr := nr.blk_nr));
698 BTS.receive(tr_PCUIF_DATA_REQ(nr.bts_nr, nr.trx_nr, nr.ts_nr,
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200699 sapi := PCU_IF_SAPI_PDTCH)) -> value pcu_msg;
700}
701
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200702/* Expect a Paging Request Type 1 from PCU on PCUIF on specified sapi. */
703function f_pcuif_rx_pch_pag_req1(template MobileIdentityV mi1 := ?,
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700704 template integer pag_group := ?,
705 template (present) TsTrxBtsNum nr := tr_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200706runs on MS_BTS_IFACE_CT return GsmRrMessage {
707 var GsmRrMessage rr_pag_req1;
708 var PCUIF_Message pcu_msg;
709 var octetstring imsi_suff_octstr;
710 var integer pag_group_rx;
711 var octetstring macblock;
712
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700713 BTS.receive(tr_PCUIF_DATA_REQ(nr.bts_nr, nr.trx_nr, nr.ts_nr,
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200714 sapi := PCU_IF_SAPI_PCH)) -> value pcu_msg;
715
716 /* First 3 bytes contain IMSI suffix to calculate paging group: */
717 imsi_suff_octstr := substr(pcu_msg.u.data_req.data, 0, 3);
718 pag_group_rx := str2int(oct2char(imsi_suff_octstr[0])) * 100 +
719 str2int(oct2char(imsi_suff_octstr[1])) * 10 +
720 str2int(oct2char(imsi_suff_octstr[2]));
721
722 /* Make sure we've got RR Paging Request Type 1 for a given MI */
723 macblock := substr(pcu_msg.u.data_req.data, 3, pcu_msg.u.data_req.len - 3);
724 rr_pag_req1 := dec_GsmRrMessage(macblock);
725 if (not match(rr_pag_req1, tr_PAG_REQ1(tr_MI_LV(mi1)))) {
726 setverdict(fail, "Failed to match Paging Request Type 1: ", rr_pag_req1);
727 f_shutdown(__BFILE__, __LINE__);
728 }
729
730 /* Make sure that received paging froup matches the expected one */
731 if (not match(pag_group_rx, pag_group)) {
732 setverdict(fail, "Paging group", pag_group_rx, " does not match expected ", pag_group);
733 f_shutdown(__BFILE__, __LINE__);
734 }
735
736 f_pcuif_tx_data_cnf(pcu_msg);
737 return rr_pag_req1;
738}
739
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700740function f_rx_rlcmac_dl_block(out RlcmacDlBlock dl_block, out uint32_t dl_fn,
741 template (present) CodingScheme exp_cs_mcs := ?,
742 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200743runs on MS_BTS_IFACE_CT {
744 var PCUIF_Message pcu_msg;
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700745 f_pcuif_rx_data_req(pcu_msg, nr := nr);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200746 dl_block := dec_RlcmacDlBlock(pcu_msg.u.data_req.data);
747 dl_fn := pcu_msg.u.data_req.fn;
748
749 var integer len := lengthof(pcu_msg.u.data_req.data);
750 var CodingScheme cs_mcs := f_rlcmac_block_len2cs_mcs(len)
751 if (not match(f_rlcmac_block_len2cs_mcs(len), exp_cs_mcs)) {
752 setverdict(fail, "Failed to match Coding Scheme exp ", exp_cs_mcs, " vs ", cs_mcs, " (", len, ")");
753 f_shutdown(__BFILE__, __LINE__);
754 }
755}
756
Pau Espin Pedrolcdbe9032020-07-07 20:20:42 +0200757function f_rx_rlcmac_dl_block_exp_ack_nack(out RlcmacDlBlock dl_block, out uint32_t poll_fn,
758 template RlcmacDlBlock acknack_tmpl := (tr_RLCMAC_UL_ACK_NACK_GPRS(ul_tfi := ?),
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700759 tr_RLCMAC_UL_ACK_NACK_EGPRS(ul_tfi := ?)),
760 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200761runs on MS_BTS_IFACE_CT {
762 var uint32_t dl_fn;
763
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700764 f_rx_rlcmac_dl_block(dl_block, dl_fn, nr := nr);
Pau Espin Pedrolcdbe9032020-07-07 20:20:42 +0200765 if (match(dl_block, acknack_tmpl)) {
Pau Espin Pedrol692222c2020-05-17 00:25:37 +0200766 poll_fn := f_rrbp_ack_fn(dl_fn, dl_block.ctrl.mac_hdr.rrbp);
767 return;
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200768 }
Pau Espin Pedrol692222c2020-05-17 00:25:37 +0200769 setverdict(fail, "Failed to match Packet Uplink ACK / NACK:", dl_block);
770 f_shutdown(__BFILE__, __LINE__);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200771}
772
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700773function f_rx_rlcmac_dl_block_exp_dummy(out RlcmacDlBlock dl_block,
774 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200775runs on MS_BTS_IFACE_CT {
776 var uint32_t dl_fn;
777
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700778 f_rx_rlcmac_dl_block(dl_block, dl_fn, nr := nr);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200779 if (not match(dl_block, tr_RLCMAC_DUMMY_CTRL())) {
780 setverdict(fail, "Failed to match Packet DUMMY DL");
781 f_shutdown(__BFILE__, __LINE__);
782 }
783}
784
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700785function f_rx_rlcmac_dl_block_exp_pkt_pag_req(out RlcmacDlBlock dl_block,
786 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200787runs on MS_BTS_IFACE_CT {
788 var uint32_t dl_fn;
789
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700790 f_rx_rlcmac_dl_block(dl_block, dl_fn, nr := nr);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200791 if (not match(dl_block, tr_RLCMAC_PACKET_PAG_REQ())) {
792 setverdict(fail, "Failed to match Packet Paging Request: ", dl_block, " vs ", tr_RLCMAC_PACKET_PAG_REQ());
793 f_shutdown(__BFILE__, __LINE__);
794 }
795}
796
797/* This function does what could probably be done with templates */
798function f_rlcmac_dl_block_verify_data_gprs(in RlcmacDlDataBlock data_block,
799 template (present) octetstring data := ?,
800 template (present) uint7_t exp_bsn := ?,
801 template (present) CodingScheme exp_cs := ?)
802runs on MS_BTS_IFACE_CT {
803 if (not match(data_block.mac_hdr.hdr_ext.bsn, exp_bsn)) {
804 setverdict(fail, "DL block BSN doesn't match: ",
805 data_block.mac_hdr.hdr_ext.bsn, " vs exp ", exp_bsn);
806 }
807
808 if (lengthof(data_block.blocks) < 1) {
809 setverdict(fail, "DL block has no LLC payload: ", data_block);
810 f_shutdown(__BFILE__, __LINE__);
811 }
812
813 if (not match(data_block.blocks[0].payload, data)) {
814 setverdict(fail, "Failed to match content of LLC payload in DL Block: ",
815 data_block.blocks[0].payload, " vs ", data);
816 f_shutdown(__BFILE__, __LINE__);
817 }
818
819 /* Check next data blocks contain dummy frames */
820 if (lengthof(data_block.blocks) > 1 and substr(data_block.blocks[1].payload, 0, 3) != '43C001'O) {
821 setverdict(fail, "Second data payload is not a dummy frame: ",
822 data_block.blocks[1].payload);
823 f_shutdown(__BFILE__, __LINE__);
824 }
825
826 /* TODO: check exp_cs */
827}
828
829/* This function does what could probably be done with templates */
830function f_rlcmac_dl_block_verify_data_egprs(in RlcmacDlEgprsDataBlock data_block,
831 template (present) octetstring data := ?,
832 template (present) uint14_t exp_bsn := ?,
833 template (present) CodingScheme exp_cs := ?)
834runs on MS_BTS_IFACE_CT {
835 if (not match(data_block.mac_hdr.bsn1, exp_bsn)) {
836 setverdict(fail, "DL block BSN doesn't match: ",
837 data_block.mac_hdr.bsn1, " vs exp ", exp_bsn);
838 }
839
840 if (lengthof(data_block.blocks) < 1) {
841 setverdict(fail, "DL block has no LLC payload: ", data_block);
842 f_shutdown(__BFILE__, __LINE__);
843 }
844
845 if (not match(data_block.blocks[0].payload, data)) {
846 setverdict(fail, "Failed to match content of LLC payload in DL Block: ",
847 data_block.blocks[0].payload, " vs ", data);
848 f_shutdown(__BFILE__, __LINE__);
849 }
850
851 /* Check next data blocks contain dummy frames */
852 if (lengthof(data_block.blocks) > 1 and substr(data_block.blocks[1].payload, 0, 3) != '43C001'O) {
853 setverdict(fail, "Second data payload is not a dummy frame: ",
854 data_block.blocks[1].payload);
855 f_shutdown(__BFILE__, __LINE__);
856 }
857
858 /* 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.
859 See wireshark's egprs_Header_type1_coding_puncturing_scheme_to_mcs. */
860}
861
862/* High level (task specific) helper for receiving and matching GPRS/EGPRS data blocks */
863function f_rx_rlcmac_dl_block_exp_data(out RlcmacDlBlock dl_block, out uint32_t dl_fn,
864 template (present) octetstring data := ?,
865 template (present) uint7_t exp_bsn := ?,
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700866 template (present) CodingScheme exp_cs := ?,
867 template (value) TsTrxBtsNum nr := ts_TsTrxBtsNum)
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200868runs on MS_BTS_IFACE_CT {
869 /* FIXME: ideally we should use an alt statement with timeout here, rather than
870 * having +100500 layers of abstraction. This would facilitate developing the
871 * multi-TBF/-TRX/-BTS tests, where you cannot expect that the first received
872 * block is exactly what you need. */
Vadim Yanitskiy4b7473d2020-09-21 04:15:39 +0700873 f_rx_rlcmac_dl_block(dl_block, dl_fn, nr := nr);
Pau Espin Pedrolaedc5112020-05-16 17:30:42 +0200874
875 /* Make sure it's either GPRS or EGPRS data block */
876 if (not match(dl_block, tr_RLCMAC_DATA)) {
877 setverdict(fail, "Failed to match DL DATA: ", dl_block, " vs ", tr_RLCMAC_DATA);
878 f_shutdown(__BFILE__, __LINE__);
879 }
880
881 if (ischosen(dl_block.data_egprs)) {
882 f_rlcmac_dl_block_verify_data_egprs(dl_block.data_egprs, data, exp_bsn, exp_cs);
883 } else if (ischosen(dl_block.data)) {
884 f_rlcmac_dl_block_verify_data_gprs(dl_block.data, data, exp_bsn, exp_cs);
885 } else {
886 /* Should not happen, but the caller may theoretically give us a template for CTRL */
887 setverdict(fail, "DL block is neither GPRS nor EGPRS data block: ", dl_block);
888 f_shutdown(__BFILE__, __LINE__);
889 }
890}
891
892function f_dl_block_ack_fn(in RlcmacDlBlock dl_block, uint32_t dl_fn)
893runs on MS_BTS_IFACE_CT return uint32_t {
894 var boolean rrbp_valid;
895 var MacRrbp rrbp;
896
897 /* The argument must be either a GPRS or EGPRS data block */
898 if (ischosen(dl_block.data_egprs)) {
899 rrbp_valid := true; /* always valid */
900 rrbp := dl_block.data_egprs.mac_hdr.rrbp;
901 } else if (ischosen(dl_block.data)) {
902 rrbp_valid := dl_block.data.mac_hdr.mac_hdr.rrbp_valid;
903 rrbp := dl_block.data.mac_hdr.mac_hdr.rrbp;
904 } else {
905 rrbp_valid := dl_block.ctrl.mac_hdr.rrbp_valid;
906 rrbp := dl_block.ctrl.mac_hdr.rrbp;
907 }
908
909 /* Make sure that the given block really needs to be ACKnowledged */
910 if (not rrbp_valid) {
911 setverdict(fail, "DL block shall not be ACKnowledged, field RRBP is not valid");
912 f_shutdown(__BFILE__, __LINE__);
913 }
914
915 return f_rrbp_ack_fn(dl_fn, rrbp);
916}
917
918function f_pkt_paging_match_tmsi(in PacketPagingReq req, template GsmTmsi tmsi)
919runs on MS_BTS_IFACE_CT {
920 if (not match(req.repeated_pageinfo.cs.tmsi, tmsi)) {
921 setverdict(fail, "Mobile Identity (TMSI/P-TMSI) mismatch: ",
922 "expected: ", tmsi, "got: ", req.repeated_pageinfo.cs.tmsi);
923 f_shutdown(__BFILE__, __LINE__);
924 }
925}
926
927}