blob: 1b5698453db9416e780cf71f56ac31940bcf3a51 [file] [log] [blame]
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001#include <stdint.h>
2#include <endian.h>
3
Harald Welte43e060a2017-07-30 22:38:03 +02004#include "RLCMAC_Types.hh"
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02005#include "RLCMAC_Templates.hh"
Harald Welte43e060a2017-07-30 22:38:03 +02006#include "GSM_Types.hh"
7/* Decoding of TS 44.060 GPRS RLC/MAC blocks, portions requiring manual functions
8 * beyond what TITAN RAW coder can handle internally.
9 *
10 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
Harald Welte34b5a952019-05-27 11:54:11 +020011 * 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
Harald Welte43e060a2017-07-30 22:38:03 +020017 */
18
19namespace RLCMAC__Types {
20
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020021/////////////////////
22// INTENRAL HELPERS
23/////////////////////
Harald Welte43e060a2017-07-30 22:38:03 +020024
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020025/* TS 04.60 10.3a.4.1.1 */
26struct gprs_rlc_ul_header_egprs_1 {
27#if __BYTE_ORDER == __LITTLE_ENDIAN
28 uint8_t r:1,
29 si:1,
30 cv:4,
31 tfi_hi:2;
32 uint8_t tfi_lo:3,
33 bsn1_hi:5;
34 uint8_t bsn1_lo:6,
35 bsn2_hi:2;
36 uint8_t bsn2_lo:8;
37 uint8_t cps:5,
38 rsb:1,
39 pi:1,
40 spare_hi:1;
41 uint8_t spare_lo:6,
42 dummy:2;
43#else
44/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
45 uint8_t tfi_hi:2, cv:4, si:1, r:1;
46 uint8_t bsn1_hi:5, tfi_lo:3;
47 uint8_t bsn2_hi:2, bsn1_lo:6;
48 uint8_t bsn2_lo:8;
49 uint8_t spare_hi:1, pi:1, rsb:1, cps:5;
50 uint8_t dummy:2, spare_lo:6;
51#endif
52} __attribute__ ((packed));
Harald Welte43e060a2017-07-30 22:38:03 +020053
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020054/* TS 04.60 10.3a.4.2.1 */
55struct gprs_rlc_ul_header_egprs_2 {
56#if __BYTE_ORDER == __LITTLE_ENDIAN
57 uint8_t r:1,
58 si:1,
59 cv:4,
60 tfi_hi:2;
61 uint8_t tfi_lo:3,
62 bsn1_hi:5;
63 uint8_t bsn1_lo:6,
64 cps_hi:2;
65 uint8_t cps_lo:1,
66 rsb:1,
67 pi:1,
68 spare_hi:5;
69 uint8_t spare_lo:5,
70 dummy:3;
71#else
72/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
73 uint8_t tfi_hi:2, cv:4, si:1, r:1;
74 uint8_t bsn1_hi:5, tfi_lo:3;
75 uint8_t cps_hi:2, bsn1_lo:6;
76 uint8_t spare_hi:5, pi:1, rsb:1, cps_lo:1;
77 uint8_t dummy:3, spare_lo:5;
78#endif
79} __attribute__ ((packed));
Harald Welte43e060a2017-07-30 22:38:03 +020080
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020081/* TS 04.60 10.3a.4.3.1 */
82struct gprs_rlc_ul_header_egprs_3 {
83#if __BYTE_ORDER == __LITTLE_ENDIAN
84 uint8_t r:1,
85 si:1,
86 cv:4,
87 tfi_hi:2;
88 uint8_t tfi_lo:3,
89 bsn1_hi:5;
90 uint8_t bsn1_lo:6,
91 cps_hi:2;
92 uint8_t cps_lo:2,
93 spb:2,
94 rsb:1,
95 pi:1,
96 spare:1,
97 dummy:1;
98#else
99/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
100 uint8_t tfi_hi:2, cv:4, si:1, r:1;
101 uint8_t bsn1_hi:5, tfi_lo:3;
102 uint8_t cps_hi:2, bsn1_lo:6;
103 uint8_t dummy:1, spare:1, pi:1, rsb:1, spb:2, cps_lo:2;
104#endif
105} __attribute__ ((packed));
106
107struct gprs_rlc_dl_header_egprs_1 {
108#if __BYTE_ORDER == __LITTLE_ENDIAN
109 uint8_t usf:3,
110 es_p:2,
111 rrbp:2,
112 tfi_hi:1;
113 uint8_t tfi_lo:4,
114 pr:2,
115 bsn1_hi:2;
116 uint8_t bsn1_mid:8;
117 uint8_t bsn1_lo:1,
118 bsn2_hi:7;
119 uint8_t bsn2_lo:3,
120 cps:5;
121#else
122/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
123 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
124 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
125 uint8_t bsn1_mid:8;
126 uint8_t bsn2_hi:7, bsn1_lo:1;
127 uint8_t cps:5, bsn2_lo:3;
128#endif
129} __attribute__ ((packed));
130
131struct gprs_rlc_dl_header_egprs_2 {
132#if __BYTE_ORDER == __LITTLE_ENDIAN
133 uint8_t usf:3,
134 es_p:2,
135 rrbp:2,
136 tfi_hi:1;
137 uint8_t tfi_lo:4,
138 pr:2,
139 bsn1_hi:2;
140 uint8_t bsn1_mid:8;
141 uint8_t bsn1_lo:1,
142 cps:3,
143 dummy:4;
144#else
145/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
146 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
147 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
148 uint8_t bsn1_mid:8;
149 uint8_t dummy:4, cps:3, bsn1_lo:1;
150#endif
151} __attribute__ ((packed));
152
153struct gprs_rlc_dl_header_egprs_3 {
154#if __BYTE_ORDER == __LITTLE_ENDIAN
155 uint8_t usf:3,
156 es_p:2,
157 rrbp:2,
158 tfi_hi:1;
159 uint8_t tfi_lo:4,
160 pr:2,
161 bsn1_hi:2;
162 uint8_t bsn1_mid:8;
163 uint8_t bsn1_lo:1,
164 cps:4,
165 spb:2,
166 dummy:1;
167#else
168/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
169 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
170 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
171 uint8_t bsn1_mid:8;
172 uint8_t dummy:1, spb:2, cps:4, bsn1_lo:1;
173#endif
174} __attribute__ ((packed));
175
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200176/*
177static const char hex_chars[] = "0123456789abcdef";
178void printbuffer(const char* ptr, TTCN_Buffer& buf) {
179 int len = buf.get_len();
180 const unsigned char* cbuf = buf.get_data();
181
182 fprintf(stderr, "printbuffer %s (len=%d): [", ptr, len);
183
184 for (int i = 0; i < len; i++) {
185 fprintf(stderr, " %c%c", hex_chars[cbuf[i] >> 4], hex_chars[cbuf[i] & 0xf]);
186 }
187
188 fprintf(stderr, " ]\n");
189}
190*/
191
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200192static CodingScheme::enum_type payload_len_2_coding_scheme(size_t payload_len) {
193 switch (payload_len) {
194 case 23:
195 return CodingScheme::CS__1;
196 case 34:
197 return CodingScheme::CS__2;
198 case 40:
199 return CodingScheme::CS__3;
200 case 54:
201 return CodingScheme::CS__4;
202 case 27:
203 return CodingScheme::MCS__1;
204 case 33:
205 return CodingScheme::MCS__2;
206 case 42:
207 return CodingScheme::MCS__3;
208 case 49:
209 return CodingScheme::MCS__4;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100210 case 60: /* fall through */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200211 case 61:
212 return CodingScheme::MCS__5;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100213 case 78: /* fall through */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200214 case 79:
215 return CodingScheme::MCS__6;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100216 case 118: /* fall through */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200217 case 119:
218 return CodingScheme::MCS__7;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100219 case 142: /* fall through */
220 case 143:
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200221 return CodingScheme::MCS__8;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100222 case 154: /* fall through */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200223 case 155:
224 return CodingScheme::MCS__9;
225 default:
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100226 fprintf(stderr, "ERROR: Unknown CodingSCheme for payload_len=%zu\n", payload_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200227 return CodingScheme::CS__1;
Harald Welte43e060a2017-07-30 22:38:03 +0200228 }
Harald Welte43e060a2017-07-30 22:38:03 +0200229}
230
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200231static unsigned int coding_scheme_2_data_block_len(CodingScheme::enum_type mcs) {
232 switch (mcs) {
233 case CodingScheme::MCS__0:
234 return 0;
235 case CodingScheme::MCS__1:
236 return 22;
237 case CodingScheme::MCS__2:
238 return 28;
239 case CodingScheme::MCS__3:
240 return 37;
241 case CodingScheme::MCS__4:
242 return 44;
243 case CodingScheme::MCS__5:
244 return 56;
245 case CodingScheme::MCS__6:
246 return 74;
247 case CodingScheme::MCS__7:
248 return 56;
249 case CodingScheme::MCS__8:
250 return 68;
251 case CodingScheme::MCS__9:
252 return 74;
253 default:
254 return 22; /* MCS1*/
255 }
256}
257
258static uint8_t bs2uint8(const BITSTRING& bs)
259{
260 int len = bs.lengthof();
261 int i;
262 uint8_t res = 0;
263 for (i = 0; i < len; i++) {
264 res = res << 1;
265 res |= (bs[i].get_bit() ? 1 : 0);
266 }
267 return res;
268}
269
270/* determine the number of rlc data blocks and their size / offsets */
271static void
272setup_rlc_mac_priv(CodingScheme::enum_type mcs, EgprsHeaderType::enum_type hdrtype, boolean is_uplink,
273 unsigned int *n_calls, unsigned int *data_block_bits, unsigned int *data_block_offsets)
274{
275 unsigned int nc, dbl = 0, dbo[2] = {0,0};
276
277 dbl = coding_scheme_2_data_block_len(mcs);
278
279 switch (hdrtype) {
280 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
281 nc = 3;
282 dbo[0] = is_uplink ? 5*8 + 6 : 5*8 + 0;
283 dbo[1] = dbo[0] + dbl * 8 + 2;
284 break;
285 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
286 nc = 2;
287 dbo[0] = is_uplink ? 4*8 + 5 : 3*8 + 4;
288 break;
289 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
290 nc = 2;
291 dbo[0] = 3*8 + 7;
292 break;
293 default:
294 nc = 1;
295 break;
296 }
297
298 *n_calls = nc;
299 *data_block_bits = dbl * 8 + 2;
300 data_block_offsets[0] = dbo[0];
301 data_block_offsets[1] = dbo[1];
302}
303
304/* bit-shift the entire 'src' of length 'length_bytes' by 'offset_bits'
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +0200305 * and store the result to caller-allocated 'buffer'. The shifting is
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200306 * done lsb-first. */
307static void clone_aligned_buffer_lsbf(unsigned int offset_bits, unsigned int length_bytes,
308 const uint8_t *src, uint8_t *buffer)
309{
310 unsigned int hdr_bytes;
311 unsigned int extra_bits;
312 unsigned int i;
313
314 uint8_t c, last_c;
315 uint8_t *dst;
316
317 hdr_bytes = offset_bits / 8;
318 extra_bits = offset_bits % 8;
319
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200320 //fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200321
322 if (extra_bits == 0) {
323 /* It is aligned already */
324 memcpy(buffer, src + hdr_bytes, length_bytes);
325 return;
326 }
327
328 dst = buffer;
329 src = src + hdr_bytes;
330 last_c = *(src++);
331
332 for (i = 0; i < length_bytes; i++) {
333 c = src[i];
334 *(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits));
335 last_c = c;
336 }
337}
338
339/* obtain an (aligned) EGPRS data block with given bit-offset and
340 * bit-length from the parent buffer */
341static void get_egprs_data_block(const TTCN_Buffer& orig_ttcn_buffer, unsigned int offset_bits,
342 unsigned int length_bits, TTCN_Buffer& dst_ttcn_buffer)
343{
344 const unsigned int initial_spare_bits = 6;
345 unsigned char *aligned_buf = NULL;
346 size_t min_src_length_bytes = (offset_bits + length_bits + 7) / 8;
347 size_t length_bytes = (initial_spare_bits + length_bits + 7) / 8;
348 size_t accepted_len = length_bytes;
349
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200350 //fprintf(stderr, "RLMAC: trying to allocate %u bytes (orig is %zu bytes long with read pos %zu)\n", length_bytes, orig_ttcn_buffer.get_len(), orig_ttcn_buffer.get_pos());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200351 dst_ttcn_buffer.get_end(aligned_buf, accepted_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200352 if (accepted_len < length_bytes) {
353 fprintf(stderr, "RLMAC: ERROR! asked for %zu bytes but got %zu\n", length_bytes, accepted_len);
354 }
355
356 /* Copy the data out of the tvb to an aligned buffer */
357 clone_aligned_buffer_lsbf(
358 offset_bits - initial_spare_bits, length_bytes,
359 orig_ttcn_buffer.get_data(),
360 aligned_buf);
361
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200362 /* clear spare bits and move block header bits to the right */
363 aligned_buf[0] = aligned_buf[0] >> initial_spare_bits;
364
365 dst_ttcn_buffer.increase_length(length_bytes);
366}
367
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200368/* bit-shift the entire 'src' of length 'length_bytes'
369 * and store the result to caller-allocated 'buffer' by 'offset_bits'. The shifting is
370 * done lsb-first. */
371static void clone_unaligned_buffer_lsbf(unsigned int offset_bits, unsigned int length_bytes,
372 const uint8_t *src, uint8_t *buffer)
373{
374 unsigned int hdr_bytes;
375 unsigned int extra_bits;
376 unsigned int i;
377
378 uint8_t c, last_hdr_c, last_c;
379 uint8_t *dst;
380
381 hdr_bytes = offset_bits / 8;
382 extra_bits = offset_bits % 8;
383
384 //fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
385
386 if (extra_bits == 0) {
387 /* It is aligned already */
388 memcpy(buffer, src + hdr_bytes, length_bytes);
389 return;
390 }
391
392 /* Copy first header+data byte, it's not handled correctly by loop */
393 dst = buffer + hdr_bytes;
394 last_hdr_c = *dst;
395 last_c = *dst << (8 - extra_bits);
396
397 for (i = 0; i < length_bytes; i++) {
398 c = src[i];
399 *(dst++) = (last_c >> (8 - extra_bits)) | (c << extra_bits);
400 last_c = c;
401 }
402 /* overwrite the lower extra_bits */
403 *dst = (*dst & (0xff << extra_bits)) | (last_c >> (8 - extra_bits));
404
405 /* Copy back first header+data byte */
406 dst = buffer + hdr_bytes;
407 *(dst++) = last_hdr_c | (src[0] << (8 - extra_bits));
408 *dst |= (src[0] >> (extra_bits)) & (0xff >> (8 - extra_bits));
409}
410
411/* put an (aligned) EGPRS data block with given bit-offset and
412 * bit-length into parent buffer */
413static void put_egprs_data_block(const TTCN_Buffer& aligned_data_block_buffer, unsigned int offset_bits,
414 unsigned int length_bits, TTCN_Buffer& dst_ttcn_buffer)
415{
416 const unsigned int initial_spare_bits = 6;
417 unsigned char *unaligned_buf = NULL;
418 char tmpbuf[120];
419 int tmplen = dst_ttcn_buffer.get_len();
420 //size_t max_length_bytes = (initial_spare_bits + length_bits + 7) / 8;
421 size_t length_bytes = tmplen + aligned_data_block_buffer.get_len();
422 size_t accepted_len = length_bytes;
423
424 //fprintf(stderr, "RLMAC: trying to allocate %u bytes\n", length_bytes);
425
426 /* API .get_end() is the only one I could find to access writeable
427 memory in the buffer. It points to the end. Hence, we first copy
428 (readonly) data to tmpbuf and later clear() so that .get_end()
429 provides us with a pointer to the start of the buffer. */
430 memcpy(tmpbuf, dst_ttcn_buffer.get_data(), tmplen);
431 dst_ttcn_buffer.clear();
432 dst_ttcn_buffer.get_end(unaligned_buf, accepted_len);
433 if (accepted_len < tmplen) {
434 fprintf(stderr, "RLMAC: ERROR! asked for %zu bytes but got %zu\n", length_bytes, accepted_len);
435 }
436 memcpy(unaligned_buf, tmpbuf, tmplen);
437
438 /* Copy the data out of the tvb to an aligned buffer */
439 clone_unaligned_buffer_lsbf(
440 offset_bits - initial_spare_bits, length_bytes,
441 aligned_data_block_buffer.get_data(),
442 unaligned_buf);
443
444 dst_ttcn_buffer.increase_length(length_bytes);
445}
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200446
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +0100447/* Append padding bytes and spare bits at the end of ttcn_buffer, based on requested CS */
448static void encode_trailing_padding_spb(TTCN_Buffer& ttcn_buffer, CodingScheme cs)
449{
450 uint8_t buf[256]; /* enough to fit any RLCMAC buffer*/
451 uint32_t blk_len = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len(cs);
452 uint32_t blk_len_no_spb = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len__no__spare__bits(cs);
453 uint32_t data_len = ttcn_buffer.get_len();
454
455 if (data_len > blk_len_no_spb) {
456 fprintf(stderr, "Buffer too large for requested CS! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
457 // TODO: throw exception?
458 }
459
460 for (int i = 0; i < blk_len_no_spb - data_len; i++)
461 buf[i] = 0x2b; /* Padding bits if needed */
462 for (int i = blk_len_no_spb - data_len; i < blk_len - data_len; i++)
463 buf[i] = 0x00; /* Spare bits if needed */
464
465 const OCTETSTRING& pad_octstr = OCTETSTRING(blk_len - data_len, buf);
466 ttcn_buffer.put_string(pad_octstr);
467}
468
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200469/////////////////////
470// DECODE
471/////////////////////
472
473/* DECODE DOWNLINK */
474
Harald Welte43e060a2017-07-30 22:38:03 +0200475RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
476{
477 RlcmacDlDataBlock ret_val;
478 TTCN_Buffer ttcn_buffer(stream);
479 int num_llc_blocks = 0;
480
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100481 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
482
Harald Welte43e060a2017-07-30 22:38:03 +0200483 /* use automatic/generated decoder for header */
484 ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
485
486 /* optional extension octets, containing LI+M+E of Llc blocks */
487 if (ret_val.mac__hdr().hdr__ext().e() == false) {
488 /* extension octet follows, i.e. optional Llc length octets */
489 while (1) {
490 /* decode one more extension octet with LlcBlocHdr inside */
491 LlcBlock lb;
Harald Welte439e5462018-03-08 23:21:17 +0100492 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Harald Welte43e060a2017-07-30 22:38:03 +0200493 ret_val.blocks()[num_llc_blocks++] = lb;
494
495 /* if E == '1'B, we can proceed further */
Harald Welte060e27a2018-03-03 20:38:19 +0100496 if (lb.hdr()().e() == true)
Harald Welte43e060a2017-07-30 22:38:03 +0200497 break;
498 }
499 }
500
501 /* RLC blocks at end */
502 if (ret_val.mac__hdr().hdr__ext().e() == true) {
503 LlcBlock lb;
504 unsigned int length = ttcn_buffer.get_read_len();
505 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
506 * fills the current RLC data block precisely or continues in the following in-sequence RLC
507 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100508 lb.hdr() = OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +0200509 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
510 ttcn_buffer.increase_pos(length);
511 ret_val.blocks()[0] = lb;
512 } else {
513 if (ret_val.blocks().is_bound()) {
514 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
Harald Welte060e27a2018-03-03 20:38:19 +0100515 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
Pau Espin Pedrolb8b1c0d2022-04-01 16:15:55 +0200516
517 /* LI[0]=0 indicates: The current LLC PDU would fit within
518 current RLC data block but the addition of the length
519 indicator octet (to indicate the LLC PDU boundary) causes the
520 LLC PDU to extend into another RLC data block */
521 if (i == 0 && length == 0)
522 length = ttcn_buffer.get_read_len();
523
Harald Welte43e060a2017-07-30 22:38:03 +0200524 if (length > ttcn_buffer.get_read_len())
525 length = ttcn_buffer.get_read_len();
Pau Espin Pedrolb8b1c0d2022-04-01 16:15:55 +0200526
Harald Welte43e060a2017-07-30 22:38:03 +0200527 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
528 ttcn_buffer.increase_pos(length);
529 }
530 }
531 }
532
533 return ret_val;
534}
535
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200536static
537EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream)
538{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100539 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200540 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100541 const struct gprs_rlc_dl_header_egprs_1 *egprs1;
542 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200543
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100544 egprs1 = static_cast<const struct gprs_rlc_dl_header_egprs_1 *>
545 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200546
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100547 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__1;
548 ret_val.tfi() = egprs1->tfi_lo << 1 | egprs1->tfi_hi << 0;
549 ret_val.rrbp() = egprs1->rrbp;
550 tmp = egprs1->es_p;
551 ret_val.esp() = BITSTRING(2, &tmp);
552 ret_val.usf() = egprs1->usf;
553 ret_val.bsn1() = egprs1->bsn1_lo << 10 | egprs1->bsn1_mid << 2 | egprs1->bsn1_hi;
554 ret_val.bsn2__offset() = egprs1->bsn2_lo << 7 | egprs1->bsn2_hi;
555 ret_val.pr() = egprs1->pr;
556 ret_val.cps() = egprs1->cps;
Pau Espin Pedrol4f9a48f2021-02-04 19:25:33 +0100557 ret_val.spb() = OMIT_VALUE;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100558
559 ttcn_buffer.increase_pos(sizeof(*egprs1));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200560 return ret_val;
561}
562
563static
564EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream)
565{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100566 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200567 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100568 const struct gprs_rlc_dl_header_egprs_2 *egprs2;
569 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200570
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100571 egprs2 = static_cast<const struct gprs_rlc_dl_header_egprs_2 *>
572 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200573
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100574 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__2;
575 ret_val.tfi() = egprs2->tfi_lo << 1 | egprs2->tfi_hi << 0;
576 ret_val.rrbp() = egprs2->rrbp;
577 tmp = egprs2->es_p;
578 ret_val.esp() = BITSTRING(2, &tmp);
579 ret_val.usf() = egprs2->usf;
580 ret_val.bsn1() = egprs2->bsn1_lo << 10 | egprs2->bsn1_mid << 2 | egprs2->bsn1_hi;
581 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
582 ret_val.pr() = egprs2->pr;
583 ret_val.cps() = egprs2->cps;
Pau Espin Pedrol4f9a48f2021-02-04 19:25:33 +0100584 ret_val.spb() = OMIT_VALUE;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100585
586 ttcn_buffer.increase_pos(sizeof(*egprs2));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200587 return ret_val;
588}
589
590static
591EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream)
592{
593 TTCN_Buffer ttcn_buffer(stream);
594 EgprsDlMacDataHeader ret_val;
595 const struct gprs_rlc_dl_header_egprs_3 *egprs3;
596 uint8_t tmp;
597
598 egprs3 = static_cast<const struct gprs_rlc_dl_header_egprs_3 *>
599 ((const void *)ttcn_buffer.get_data());
600
601 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
602 ret_val.tfi() = egprs3->tfi_lo << 1 | egprs3->tfi_hi << 0;
603 ret_val.rrbp() = egprs3->rrbp;
604 tmp = egprs3->es_p;
605 ret_val.esp() = BITSTRING(2, &tmp);
606 ret_val.usf() = egprs3->usf;
607 ret_val.bsn1() = egprs3->bsn1_lo << 10 | egprs3->bsn1_mid << 2 | egprs3->bsn1_hi;
608 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
609 ret_val.pr() = egprs3->pr;
610 ret_val.spb() = egprs3->spb;
611 ret_val.cps() = egprs3->cps;
612
613 ttcn_buffer.increase_pos(sizeof(*egprs3));
614 return ret_val;
615}
616
617static
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100618RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200619{
620 RlcmacDlEgprsDataBlock ret_val;
621 TTCN_Buffer ttcn_buffer(stream);
622 TTCN_Buffer aligned_buffer;
623 int num_llc_blocks = 0;
624 unsigned int data_block_bits, data_block_offsets[2];
625 unsigned int num_calls;
626 const uint8_t *ti_e;
627
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100628 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
629 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200630 case CodingScheme::MCS__0:
631 case CodingScheme::MCS__1:
632 case CodingScheme::MCS__2:
633 case CodingScheme::MCS__3:
634 case CodingScheme::MCS__4:
635 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type3(stream);
636 break;
637 case CodingScheme::MCS__5:
638 case CodingScheme::MCS__6:
639 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type2(stream);
640 break;
641 case CodingScheme::MCS__7:
642 case CodingScheme::MCS__8:
643 case CodingScheme::MCS__9:
644 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream);
645 break;
646 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100647 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), false,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200648 &num_calls, &data_block_bits, data_block_offsets);
649 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
650
651 ti_e = aligned_buffer.get_read_data();
652 ret_val.fbi() = *ti_e & 0x02 ? true : false;
653 ret_val.e() = *ti_e & 0x01 ? true : false;
654 aligned_buffer.increase_pos(1);
655
656 /* optional extension octets, containing LI+E of Llc blocks */
657 if (ret_val.e() == false) {
658 /* extension octet follows, i.e. optional Llc length octets */
659 while (1) {
660 /* decode one more extension octet with LlcBlocHdr inside */
661 EgprsLlcBlock lb;
662 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
663 ret_val.blocks()[num_llc_blocks++] = lb;
664
665 /* if E == '1'B, we can proceed further */
666 if (lb.hdr()().e() == true)
667 break;
668 }
669 }
670
671 /* RLC blocks at end */
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100672 if (ret_val.e() == true) {
673 EgprsLlcBlock lb;
674 unsigned int length = aligned_buffer.get_read_len();
675 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
676 * fills the current RLC data block precisely or continues in the following in-sequence RLC
677 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100678 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100679 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
680 aligned_buffer.increase_pos(length);
681 ret_val.blocks()[0] = lb;
682 } else {
683 /* RLC blocks at end */
684 if (ret_val.blocks().is_bound()) {
685 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
686 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
687 if (length > aligned_buffer.get_read_len())
688 length = aligned_buffer.get_read_len();
689 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
690 aligned_buffer.increase_pos(length);
691 }
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200692 }
693 }
694
695 return ret_val;
696}
697
698RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
699{
700 RlcmacDlBlock ret_val;
701 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100702 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200703 unsigned char pt;
704
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100705 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200706 case CodingScheme::CS__1:
707 case CodingScheme::CS__2:
708 case CodingScheme::CS__3:
709 case CodingScheme::CS__4:
710 pt = stream[0].get_octet() >> 6;
711 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
712 ret_val.data() = dec__RlcmacDlDataBlock(stream);
713 else
714 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
715 break;
716 case CodingScheme::MCS__0:
717 case CodingScheme::MCS__1:
718 case CodingScheme::MCS__2:
719 case CodingScheme::MCS__3:
720 case CodingScheme::MCS__4:
721 case CodingScheme::MCS__5:
722 case CodingScheme::MCS__6:
723 case CodingScheme::MCS__7:
724 case CodingScheme::MCS__8:
725 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100726 ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200727 break;
728 }
729 return ret_val;
730}
731
732/* DECODE UPLINK */
733
734RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
735{
736 RlcmacUlDataBlock ret_val;
737 TTCN_Buffer ttcn_buffer(stream);
738 int num_llc_blocks = 0;
739
740 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
741 TTCN_Logger::log_event_str("==================================\n"
742 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
743 stream.log();
744 TTCN_Logger::end_event();
745
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100746 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
747
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200748 /* use automatic/generated decoder for header */
749 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
750
751 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
752 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
753 ttcn_buffer.log();
754 TTCN_Logger::end_event();
755 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
756 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
757 ret_val.log();
758 TTCN_Logger::end_event();
759
760 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
761 * optional tlli, optional pfi and LLC Blocks */
762
763 /* optional extension octets, containing LI+M+E of Llc blocks */
764 if (ret_val.mac__hdr().e() == false) {
765 /* extension octet follows, i.e. optional Llc length octets */
766 while (1) {
767 /* decode one more extension octet with LlcBlocHdr inside */
768 LlcBlock lb;
769 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
770 ret_val.blocks()[num_llc_blocks++] = lb;
771
772 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
773 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
774 ttcn_buffer.log();
775 TTCN_Logger::end_event();
776 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
777 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
778 ret_val.log();
779 TTCN_Logger::end_event();
780
781 /* if E == '1'B, we can proceed further */
782 if (lb.hdr()().e() == true)
783 break;
784 }
785 }
786
787 /* parse optional TLLI */
788 if (ret_val.mac__hdr().tlli__ind()) {
789 ret_val.tlli() = OCTETSTRING(4, ttcn_buffer.get_read_data());
790 ttcn_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200791 } else {
792 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200793 }
794 /* parse optional PFI */
795 if (ret_val.mac__hdr().pfi__ind()) {
796 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200797 } else {
798 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200799 }
800
801 /* RLC blocks at end */
802 if (ret_val.mac__hdr().e() == true) {
803 LlcBlock lb;
804 unsigned int length = ttcn_buffer.get_read_len();
805 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
806 * fills the current RLC data block precisely or continues in the following in-sequence RLC
807 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100808 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200809 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
810 ttcn_buffer.increase_pos(length);
811 ret_val.blocks()[0] = lb;
812 } else {
813 if (ret_val.blocks().is_bound()) {
814 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
815 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
816 if (length > ttcn_buffer.get_read_len())
817 length = ttcn_buffer.get_read_len();
818 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
819 ttcn_buffer.increase_pos(length);
820 }
821 }
822 }
823
824 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
825 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
826 ttcn_buffer.log();
827 TTCN_Logger::end_event();
828 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
829 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
830 ret_val.log();
831 TTCN_Logger::end_event();
832
833 return ret_val;
834}
835
836static
837EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type1(const OCTETSTRING& stream)
838{
839 EgprsUlMacDataHeader ret_val;
840
841 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
842
843 return ret_val;
844}
845
846static
847EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type2(const OCTETSTRING& stream)
848{
849 EgprsUlMacDataHeader ret_val;
850
851 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
852
853 return ret_val;
854}
855
856static
857EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
858{
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200859 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200860 EgprsUlMacDataHeader ret_val;
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200861 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
862 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200863
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200864 egprs3 = static_cast<const struct gprs_rlc_ul_header_egprs_3 *>
865 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200866
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200867 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
868 ret_val.tfi() = egprs3->tfi_lo << 2 | egprs3->tfi_hi << 0;
869 ret_val.countdown() = egprs3->cv;
870 tmp = egprs3->si;
871 ret_val.foi__si() = BITSTRING(1, &tmp);
872 tmp = egprs3->r;
873 ret_val.r__ri() = BITSTRING(1, &tmp);
874 ret_val.bsn1() = egprs3->bsn1_lo << 5 | egprs3->bsn1_hi << 0;
875 ret_val.cps() = egprs3->cps_lo << 2 | egprs3->cps_hi << 0;
876 ret_val.pfi__ind() = egprs3->pi;
877 tmp = egprs3->rsb;
878 ret_val.rsb() = BITSTRING(1, &tmp);
879 tmp = egprs3->spb;
880 ret_val.spb() = BITSTRING(2, &tmp);
881
882 ttcn_buffer.increase_pos(sizeof(*egprs3));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200883 return ret_val;
884}
885
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100886RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200887{
888 RlcmacUlEgprsDataBlock ret_val;
889 TTCN_Buffer ttcn_buffer(stream);
890 TTCN_Buffer aligned_buffer;
891 int num_llc_blocks = 0;
892 unsigned int data_block_bits, data_block_offsets[2];
893 unsigned int num_calls;
894 const uint8_t *ti_e;
895
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100896 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
897 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200898 case CodingScheme::MCS__1:
899 case CodingScheme::MCS__2:
900 case CodingScheme::MCS__3:
901 case CodingScheme::MCS__4:
902 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
903 break;
904 case CodingScheme::MCS__5:
905 case CodingScheme::MCS__6:
906 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
907 break;
908 case CodingScheme::MCS__7:
909 case CodingScheme::MCS__8:
910 case CodingScheme::MCS__9:
911 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
912 break;
913 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100914 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), true,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200915 &num_calls, &data_block_bits, data_block_offsets);
916 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
917
918 ti_e = aligned_buffer.get_read_data();
919 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
920 ret_val.e() = *ti_e & 0x01 ? true : false;
921 aligned_buffer.increase_pos(1);
922
923 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
924 * optional tlli, optional pfi and LLC Blocks */
925
926 /* optional extension octets, containing LI+M+E of Llc blocks */
927 if (ret_val.e() == false) {
928 /* extension octet follows, i.e. optional Llc length octets */
929 while (1) {
930 /* decode one more extension octet with LlcBlocHdr inside */
931 EgprsLlcBlock lb;
932 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
933 ret_val.blocks()[num_llc_blocks++] = lb;
934
935 /* if E == '1'B, we can proceed further */
936 if (lb.hdr()().e() == true)
937 break;
938 }
939 }
940
941 /* parse optional TLLI */
942 if (ret_val.tlli__ind()) {
943 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
944 aligned_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200945 } else {
946 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200947 }
948 /* parse optional PFI */
949 if (ret_val.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +0200950 ret_val.pfi().decode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200951 } else {
952 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200953 }
954
955 /* RLC blocks at end */
956 if (ret_val.e() == true) {
957 EgprsLlcBlock lb;
958 unsigned int length = aligned_buffer.get_read_len();
959 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
960 * fills the current RLC data block precisely or continues in the following in-sequence RLC
961 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100962 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200963 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
964 aligned_buffer.increase_pos(length);
965 ret_val.blocks()[0] = lb;
966 } else {
967 if (ret_val.blocks().is_bound()) {
968 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
969 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
970 if (length > aligned_buffer.get_read_len())
971 length = aligned_buffer.get_read_len();
972 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
973 aligned_buffer.increase_pos(length);
974 }
975 }
976 }
977
978 return ret_val;
979}
980
981RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
982{
983 RlcmacUlBlock ret_val;
984 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100985 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200986 unsigned char pt;
987
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100988 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200989 case CodingScheme::CS__1:
990 case CodingScheme::CS__2:
991 case CodingScheme::CS__3:
992 case CodingScheme::CS__4:
993 pt = stream[0].get_octet() >> 6;
994 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
995 ret_val.data() = dec__RlcmacUlDataBlock(stream);
996 else
997 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
998 break;
999 case CodingScheme::MCS__1:
1000 case CodingScheme::MCS__2:
1001 case CodingScheme::MCS__3:
1002 case CodingScheme::MCS__4:
1003 case CodingScheme::MCS__5:
1004 case CodingScheme::MCS__6:
1005 case CodingScheme::MCS__7:
1006 case CodingScheme::MCS__8:
1007 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +01001008 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001009 break;
1010 }
1011
1012 return ret_val;
1013}
1014
1015
1016/////////////////////
1017// ENCODE
1018/////////////////////
1019
1020/* ENCODE DOWNLINK */
1021
1022OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
1023{
1024 RlcmacDlDataBlock in = si;
1025 OCTETSTRING ret_val;
1026 TTCN_Buffer ttcn_buffer;
1027 int i;
1028
1029 /* Fix 'e' bit of initial header based on following blocks */
1030 if (!in.blocks().is_bound() ||
1031 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1032 in.mac__hdr().hdr__ext().e() = true;
1033 else
1034 in.mac__hdr().hdr__ext().e() = false;
1035
1036 /* use automatic/generated decoder for header */
1037 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1038
1039 /* Add LI octets, if any */
1040 if (in.blocks().is_bound() &&
1041 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1042 /* first write LI octets */
1043 for (i = 0; i < in.blocks().size_of(); i++) {
1044 /* fix the 'E' bit in case it is not clear */
1045 if (i < in.blocks().size_of()-1)
1046 in.blocks()[i].hdr()().e() = false;
1047 else
1048 in.blocks()[i].hdr()().e() = true;
1049 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1050 }
1051 }
1052 if (in.blocks().is_bound()) {
1053 for (i = 0; i < in.blocks().size_of(); i++) {
1054 if (!in.blocks()[i].is_bound())
1055 continue;
1056 ttcn_buffer.put_string(in.blocks()[i].payload());
1057 }
1058 }
1059
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001060 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1061
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001062 ttcn_buffer.get_string(ret_val);
1063 return ret_val;
1064}
1065
1066static
1067void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1068{
1069 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1070}
1071
1072static
1073void enc__RlcmacDlEgprsDataHeader_type2(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1074{
1075 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1076}
1077
1078static
1079void enc__RlcmacDlEgprsDataHeader_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1080{
1081 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1082}
1083
1084OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
1085{
1086 RlcmacDlEgprsDataBlock in = si;
1087 OCTETSTRING ret_val;
1088 TTCN_Buffer ttcn_buffer;
1089 int i;
1090
1091 /* Fix 'e' bit of initial header based on following blocks */
1092 if (!in.blocks().is_bound() ||
1093 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1094 in.e() = true;
1095 else
1096 in.e() = false;
1097
1098 switch (in.mac__hdr().header__type()) {
1099 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
1100 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
1101 break;
1102 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
1103 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
1104 break;
1105 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
1106 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
1107 default:
1108 break; /* TODO: error */
1109 }
1110
1111 /* Add LI octets, if any */
1112 if (in.blocks().is_bound() &&
1113 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1114 /* first write LI octets */
1115 for (i = 0; i < in.blocks().size_of(); i++) {
1116 /* fix the 'E' bit in case it is not clear */
1117 if (i < in.blocks().size_of()-1)
1118 in.blocks()[i].hdr()().e() = false;
1119 else
1120 in.blocks()[i].hdr()().e() = true;
1121 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1122 }
1123 }
1124 if (in.blocks().is_bound()) {
1125 for (i = 0; i < in.blocks().size_of(); i++) {
1126 if (!in.blocks()[i].is_bound())
1127 continue;
1128 ttcn_buffer.put_string(in.blocks()[i].payload());
1129 }
1130 }
1131
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001132 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1133
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001134 ttcn_buffer.get_string(ret_val);
1135 return ret_val;
1136}
1137
1138OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
1139{
1140 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
1141 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
1142 else if (si.ischosen(RlcmacDlBlock::ALT_data))
1143 return enc__RlcmacDlDataBlock(si.data());
1144 else
1145 return enc__RlcmacDlCtrlBlock(si.ctrl());
1146}
1147
1148/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +02001149
1150OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
1151{
1152 RlcmacUlDataBlock in = si;
1153 OCTETSTRING ret_val;
1154 TTCN_Buffer ttcn_buffer;
1155 int i;
1156
Harald Welte060e27a2018-03-03 20:38:19 +01001157 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +02001158 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +01001159 in.mac__hdr().e() = false; /* E=0: extension octet follows */
1160 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1161 /* If there's only a single block, and that block has no HDR value defined, */
1162 in.mac__hdr().e() = true; /* E=0: extension octet follows */
1163 } else {
1164 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +02001165 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +01001166 }
Harald Welte43e060a2017-07-30 22:38:03 +02001167
1168 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +02001169 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1170 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +02001171
Harald Welte060e27a2018-03-03 20:38:19 +01001172 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +02001173 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1174
Harald Welte060e27a2018-03-03 20:38:19 +01001175 if (in.mac__hdr().e() == false) {
1176 /* Add LI octets, if any */
1177 if (!in.blocks().is_bound()) {
1178 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1179 } else {
1180 for (i = 0; i < in.blocks().size_of(); i++) {
1181#if 0
1182 /* check for penultimate block */
1183 if (i == in.blocks().size_of()-2) {
1184 /* if last block has no header, no more LI */
1185 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1186 in.blocks()[i].hdr()().more() = true;
1187 } else {
1188 /* header present, we have to encode LI */
1189 in.blocks()[i].hdr()().more() = false;
1190 in.blocks()[i].hdr()().length__ind() =
1191 in.blocks()[i+1].payload().lengthof();
1192 }
1193 } else if (i < in.blocks().size_of()-2) {
1194 /* one of the first blocks, before the penultimate or last */
1195 in.blocks()[i].hdr()().e() = false; /* LI present */
1196 /* re-compute length */
1197 in.blocks()[i].hdr()().length__ind() =
1198 in.blocks()[i+1].payload().lengthof();
1199 }
1200 /* Encode LI octet if E=0 */
1201 }
1202#endif
1203 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1204 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
1205 TTCN_EncDec::CT_RAW);
1206 }
1207 }
Harald Welte43e060a2017-07-30 22:38:03 +02001208 }
1209 }
1210
1211 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +01001212 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +02001213 }
1214
1215 if (in.mac__hdr().pfi__ind()) {
1216 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1217 }
1218
1219 if (in.blocks().is_bound()) {
1220 for (i = 0; i < in.blocks().size_of(); i++) {
1221 if (!in.blocks()[i].is_bound())
1222 continue;
1223 ttcn_buffer.put_string(in.blocks()[i].payload());
1224 }
1225 }
1226
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001227 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1228
Harald Welte43e060a2017-07-30 22:38:03 +02001229 ttcn_buffer.get_string(ret_val);
1230 return ret_val;
1231}
1232
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001233static
1234void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001235{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001236 struct gprs_rlc_ul_header_egprs_1 egprs1;
1237
1238 egprs1.r = bs2uint8(si.r__ri());
1239 egprs1.si = bs2uint8(si.foi__si());
1240 egprs1.cv = si.countdown();
1241 egprs1.tfi_hi = si.tfi() >> 0;
1242 egprs1.tfi_lo = si.tfi() >> 2;
1243 egprs1.bsn1_hi = si.bsn1() >> 0;
1244 egprs1.bsn1_lo = si.bsn1() >> 5;
1245 egprs1.bsn2_hi = si.bsn2__offset() >> 0;
1246 egprs1.bsn2_lo = si.bsn2__offset() >> 2;
1247 egprs1.cps = si.cps();
1248 egprs1.rsb = bs2uint8(si.rsb());
1249 egprs1.pi = si.pfi__ind();
1250 egprs1.spare_hi = 0;
1251 egprs1.spare_lo = 0;
1252 egprs1.dummy = 0;
1253
1254 ttcn_buffer.put_s(sizeof(egprs1), (const unsigned char *)&egprs1);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001255}
Harald Welte43e060a2017-07-30 22:38:03 +02001256
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001257static
1258void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1259{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001260 struct gprs_rlc_ul_header_egprs_2 egprs2;
1261
1262 egprs2.r = bs2uint8(si.r__ri());
1263 egprs2.si = bs2uint8(si.foi__si());
1264 egprs2.cv = si.countdown();
1265 egprs2.tfi_hi = si.tfi() >> 0;
1266 egprs2.tfi_lo = si.tfi() >> 2;
1267 egprs2.bsn1_hi = si.bsn1() >> 0;
1268 egprs2.bsn1_lo = si.bsn1() >> 5;
1269 egprs2.cps_hi = si.cps() >> 0;
1270 egprs2.cps_lo = si.cps() >> 2;
1271 egprs2.rsb = bs2uint8(si.rsb());
1272 egprs2.pi = si.pfi__ind();
1273 egprs2.spare_hi = 0;
1274 egprs2.spare_lo = 0;
1275 egprs2.dummy = 0;
1276
1277 ttcn_buffer.put_s(sizeof(egprs2), (const unsigned char *)&egprs2);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001278}
Harald Welte43e060a2017-07-30 22:38:03 +02001279
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001280static
1281void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1282{
1283 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001284
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001285 egprs3.r = bs2uint8(si.r__ri());
1286 egprs3.si = bs2uint8(si.foi__si());
1287 egprs3.cv = si.countdown();
1288 egprs3.tfi_hi = si.tfi() >> 0;
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001289 egprs3.tfi_lo = si.tfi() >> 2;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001290 egprs3.bsn1_hi = si.bsn1() >> 0;
1291 egprs3.bsn1_lo = si.bsn1() >> 5;
1292 egprs3.cps_hi = si.cps() >> 0;
1293 egprs3.cps_lo = si.cps() >> 2;
1294 egprs3.spb = bs2uint8(si.spb());
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001295 egprs3.rsb = bs2uint8(si.rsb());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001296 egprs3.pi = si.pfi__ind();
1297 egprs3.spare = 0;
1298 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001299
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001300 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1301}
Harald Welte43e060a2017-07-30 22:38:03 +02001302
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001303OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1304{
1305 RlcmacUlEgprsDataBlock in = si;
1306 OCTETSTRING ret_val;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001307 TTCN_Buffer ttcn_buffer, aligned_buffer;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001308 int i;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001309 unsigned int data_block_bits, data_block_offsets[2];
1310 unsigned int num_calls;
1311 CodingScheme mcs;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001312
1313 mcs = RLCMAC__Templates::f__rlcmac__cps__htype__to__mcs(in.mac__hdr().cps(), in.mac__hdr().header__type());
1314 //fprintf(stderr, "RLCMAC: infered MCS %s (%d)\n", mcs.enum_to_str(static_cast<CodingScheme::enum_type>(mcs.as_int())), mcs.as_int());
Harald Welte43e060a2017-07-30 22:38:03 +02001315
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001316 if (!in.blocks().is_bound()) {
1317 /* we don't have nay blocks: Add length value (zero) */
1318 in.e() = false; /* E=0: extension octet follows */
1319 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1320 /* If there's only a single block, and that block has no HDR value defined, */
1321 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001322 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001323 /* Length value */
1324 in.e() = false;
1325 }
1326
1327 /* Fix other presence indications */
1328 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1329 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1330
1331 switch (in.mac__hdr().header__type()) {
1332 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001333 enc__RlcmacUlEgprsDataHeader_type1(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001334 break;
1335 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001336 enc__RlcmacUlEgprsDataHeader_type2(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001337 break;
1338 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001339 enc__RlcmacUlEgprsDataHeader_type3(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001340 default:
1341 break; /* TODO: error */
1342 }
1343
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001344 /* Put first TI + E byte */
Pau Espin Pedrol563bcd62020-11-06 19:51:23 +01001345 aligned_buffer.put_c((in.tlli__ind() & 0x01) << 1 | (in.e() & 0x01) << 0);
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001346 //printbuffer("After encoding first byte", aligned_buffer);
1347
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001348 if (in.e() == false) {
1349 /* Add LI octets, if any */
1350 if (!in.blocks().is_bound()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001351 aligned_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001352 } else {
1353 for (i = 0; i < in.blocks().size_of(); i++) {
1354#if 0
1355 /* check for penultimate block */
1356 if (i == in.blocks().size_of()-2) {
1357 /* if last block has no header, no more LI */
1358 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1359 in.blocks()[i].hdr()().more() = true;
1360 } else {
1361 /* header present, we have to encode LI */
1362 in.blocks()[i].hdr()().more() = false;
1363 in.blocks()[i].hdr()().length__ind() =
1364 in.blocks()[i+1].payload().lengthof();
1365 }
1366 } else if (i < in.blocks().size_of()-2) {
1367 /* one of the first blocks, before the penultimate or last */
1368 in.blocks()[i].hdr()().e() = false; /* LI present */
1369 /* re-compute length */
1370 in.blocks()[i].hdr()().length__ind() =
1371 in.blocks()[i+1].payload().lengthof();
1372 }
1373 /* Encode LI octet if E=0 */
1374 }
1375#endif
1376 if (in.blocks()[i].hdr() != OMIT_VALUE) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001377 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, aligned_buffer,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001378 TTCN_EncDec::CT_RAW);
1379 }
Harald Welte43e060a2017-07-30 22:38:03 +02001380 }
1381 }
1382 }
1383
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001384
1385
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001386 if (in.tlli__ind()) {
Pau Espin Pedrola05b2bc2020-11-06 20:38:21 +01001387 /* The TLLI is encoded in little endian for EGPRS (see
1388 * TS 44.060, figure 10.3a.2.1, note 2) */
1389 OCTETSTRING tlli = in.tlli();
1390 aligned_buffer.put_c(tlli[3].get_octet());
1391 aligned_buffer.put_c(tlli[2].get_octet());
1392 aligned_buffer.put_c(tlli[1].get_octet());
1393 aligned_buffer.put_c(tlli[0].get_octet());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001394 }
Harald Welte43e060a2017-07-30 22:38:03 +02001395
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001396 if (in.mac__hdr().pfi__ind()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001397 in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001398 }
1399
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001400 //printbuffer("Before encoding EgprsLlc payload", aligned_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001401 if (in.blocks().is_bound()) {
1402 for (i = 0; i < in.blocks().size_of(); i++) {
1403 if (!in.blocks()[i].is_bound())
1404 continue;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001405 aligned_buffer.put_string(in.blocks()[i].payload());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001406 }
1407 }
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001408 //printbuffer("After encoding EgprsLlc payload", aligned_buffer);
1409
1410 setup_rlc_mac_priv(mcs, in.mac__hdr().header__type(), true,
1411 &num_calls, &data_block_bits, data_block_offsets);
1412 //printbuffer("before merging data block", ttcn_buffer);
1413 put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer);
1414 //printbuffer("after merging data block", ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001415
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001416 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1417
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001418 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001419 return ret_val;
1420}
1421
Harald Welte78a1af62017-07-31 17:33:56 +02001422OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1423{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001424 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1425 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1426 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001427 return enc__RlcmacUlDataBlock(si.data());
1428 else
1429 return enc__RlcmacUlCtrlBlock(si.ctrl());
1430}
1431
Harald Welte43e060a2017-07-30 22:38:03 +02001432} // namespace