blob: 97bd0be946f5d4e819ad49f539a650062a79d4f4 [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();
Harald Welte43e060a2017-07-30 22:38:03 +0200516 if (length > ttcn_buffer.get_read_len())
517 length = ttcn_buffer.get_read_len();
518 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
519 ttcn_buffer.increase_pos(length);
520 }
521 }
522 }
523
524 return ret_val;
525}
526
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200527static
528EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream)
529{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100530 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200531 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100532 const struct gprs_rlc_dl_header_egprs_1 *egprs1;
533 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200534
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100535 egprs1 = static_cast<const struct gprs_rlc_dl_header_egprs_1 *>
536 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200537
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100538 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__1;
539 ret_val.tfi() = egprs1->tfi_lo << 1 | egprs1->tfi_hi << 0;
540 ret_val.rrbp() = egprs1->rrbp;
541 tmp = egprs1->es_p;
542 ret_val.esp() = BITSTRING(2, &tmp);
543 ret_val.usf() = egprs1->usf;
544 ret_val.bsn1() = egprs1->bsn1_lo << 10 | egprs1->bsn1_mid << 2 | egprs1->bsn1_hi;
545 ret_val.bsn2__offset() = egprs1->bsn2_lo << 7 | egprs1->bsn2_hi;
546 ret_val.pr() = egprs1->pr;
547 ret_val.cps() = egprs1->cps;
Pau Espin Pedrol4f9a48f2021-02-04 19:25:33 +0100548 ret_val.spb() = OMIT_VALUE;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100549
550 ttcn_buffer.increase_pos(sizeof(*egprs1));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200551 return ret_val;
552}
553
554static
555EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream)
556{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100557 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200558 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100559 const struct gprs_rlc_dl_header_egprs_2 *egprs2;
560 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200561
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100562 egprs2 = static_cast<const struct gprs_rlc_dl_header_egprs_2 *>
563 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200564
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100565 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__2;
566 ret_val.tfi() = egprs2->tfi_lo << 1 | egprs2->tfi_hi << 0;
567 ret_val.rrbp() = egprs2->rrbp;
568 tmp = egprs2->es_p;
569 ret_val.esp() = BITSTRING(2, &tmp);
570 ret_val.usf() = egprs2->usf;
571 ret_val.bsn1() = egprs2->bsn1_lo << 10 | egprs2->bsn1_mid << 2 | egprs2->bsn1_hi;
572 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
573 ret_val.pr() = egprs2->pr;
574 ret_val.cps() = egprs2->cps;
Pau Espin Pedrol4f9a48f2021-02-04 19:25:33 +0100575 ret_val.spb() = OMIT_VALUE;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100576
577 ttcn_buffer.increase_pos(sizeof(*egprs2));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200578 return ret_val;
579}
580
581static
582EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream)
583{
584 TTCN_Buffer ttcn_buffer(stream);
585 EgprsDlMacDataHeader ret_val;
586 const struct gprs_rlc_dl_header_egprs_3 *egprs3;
587 uint8_t tmp;
588
589 egprs3 = static_cast<const struct gprs_rlc_dl_header_egprs_3 *>
590 ((const void *)ttcn_buffer.get_data());
591
592 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
593 ret_val.tfi() = egprs3->tfi_lo << 1 | egprs3->tfi_hi << 0;
594 ret_val.rrbp() = egprs3->rrbp;
595 tmp = egprs3->es_p;
596 ret_val.esp() = BITSTRING(2, &tmp);
597 ret_val.usf() = egprs3->usf;
598 ret_val.bsn1() = egprs3->bsn1_lo << 10 | egprs3->bsn1_mid << 2 | egprs3->bsn1_hi;
599 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
600 ret_val.pr() = egprs3->pr;
601 ret_val.spb() = egprs3->spb;
602 ret_val.cps() = egprs3->cps;
603
604 ttcn_buffer.increase_pos(sizeof(*egprs3));
605 return ret_val;
606}
607
608static
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100609RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200610{
611 RlcmacDlEgprsDataBlock ret_val;
612 TTCN_Buffer ttcn_buffer(stream);
613 TTCN_Buffer aligned_buffer;
614 int num_llc_blocks = 0;
615 unsigned int data_block_bits, data_block_offsets[2];
616 unsigned int num_calls;
617 const uint8_t *ti_e;
618
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100619 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
620 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200621 case CodingScheme::MCS__0:
622 case CodingScheme::MCS__1:
623 case CodingScheme::MCS__2:
624 case CodingScheme::MCS__3:
625 case CodingScheme::MCS__4:
626 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type3(stream);
627 break;
628 case CodingScheme::MCS__5:
629 case CodingScheme::MCS__6:
630 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type2(stream);
631 break;
632 case CodingScheme::MCS__7:
633 case CodingScheme::MCS__8:
634 case CodingScheme::MCS__9:
635 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream);
636 break;
637 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100638 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), false,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200639 &num_calls, &data_block_bits, data_block_offsets);
640 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
641
642 ti_e = aligned_buffer.get_read_data();
643 ret_val.fbi() = *ti_e & 0x02 ? true : false;
644 ret_val.e() = *ti_e & 0x01 ? true : false;
645 aligned_buffer.increase_pos(1);
646
647 /* optional extension octets, containing LI+E of Llc blocks */
648 if (ret_val.e() == false) {
649 /* extension octet follows, i.e. optional Llc length octets */
650 while (1) {
651 /* decode one more extension octet with LlcBlocHdr inside */
652 EgprsLlcBlock lb;
653 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
654 ret_val.blocks()[num_llc_blocks++] = lb;
655
656 /* if E == '1'B, we can proceed further */
657 if (lb.hdr()().e() == true)
658 break;
659 }
660 }
661
662 /* RLC blocks at end */
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100663 if (ret_val.e() == true) {
664 EgprsLlcBlock lb;
665 unsigned int length = aligned_buffer.get_read_len();
666 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
667 * fills the current RLC data block precisely or continues in the following in-sequence RLC
668 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100669 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100670 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
671 aligned_buffer.increase_pos(length);
672 ret_val.blocks()[0] = lb;
673 } else {
674 /* RLC blocks at end */
675 if (ret_val.blocks().is_bound()) {
676 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
677 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
678 if (length > aligned_buffer.get_read_len())
679 length = aligned_buffer.get_read_len();
680 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
681 aligned_buffer.increase_pos(length);
682 }
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200683 }
684 }
685
686 return ret_val;
687}
688
689RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
690{
691 RlcmacDlBlock ret_val;
692 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100693 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200694 unsigned char pt;
695
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100696 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200697 case CodingScheme::CS__1:
698 case CodingScheme::CS__2:
699 case CodingScheme::CS__3:
700 case CodingScheme::CS__4:
701 pt = stream[0].get_octet() >> 6;
702 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
703 ret_val.data() = dec__RlcmacDlDataBlock(stream);
704 else
705 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
706 break;
707 case CodingScheme::MCS__0:
708 case CodingScheme::MCS__1:
709 case CodingScheme::MCS__2:
710 case CodingScheme::MCS__3:
711 case CodingScheme::MCS__4:
712 case CodingScheme::MCS__5:
713 case CodingScheme::MCS__6:
714 case CodingScheme::MCS__7:
715 case CodingScheme::MCS__8:
716 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100717 ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200718 break;
719 }
720 return ret_val;
721}
722
723/* DECODE UPLINK */
724
725RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
726{
727 RlcmacUlDataBlock ret_val;
728 TTCN_Buffer ttcn_buffer(stream);
729 int num_llc_blocks = 0;
730
731 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
732 TTCN_Logger::log_event_str("==================================\n"
733 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
734 stream.log();
735 TTCN_Logger::end_event();
736
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100737 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
738
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200739 /* use automatic/generated decoder for header */
740 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
741
742 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
743 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
744 ttcn_buffer.log();
745 TTCN_Logger::end_event();
746 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
747 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
748 ret_val.log();
749 TTCN_Logger::end_event();
750
751 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
752 * optional tlli, optional pfi and LLC Blocks */
753
754 /* optional extension octets, containing LI+M+E of Llc blocks */
755 if (ret_val.mac__hdr().e() == false) {
756 /* extension octet follows, i.e. optional Llc length octets */
757 while (1) {
758 /* decode one more extension octet with LlcBlocHdr inside */
759 LlcBlock lb;
760 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
761 ret_val.blocks()[num_llc_blocks++] = lb;
762
763 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
764 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
765 ttcn_buffer.log();
766 TTCN_Logger::end_event();
767 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
768 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
769 ret_val.log();
770 TTCN_Logger::end_event();
771
772 /* if E == '1'B, we can proceed further */
773 if (lb.hdr()().e() == true)
774 break;
775 }
776 }
777
778 /* parse optional TLLI */
779 if (ret_val.mac__hdr().tlli__ind()) {
780 ret_val.tlli() = OCTETSTRING(4, ttcn_buffer.get_read_data());
781 ttcn_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200782 } else {
783 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200784 }
785 /* parse optional PFI */
786 if (ret_val.mac__hdr().pfi__ind()) {
787 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200788 } else {
789 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200790 }
791
792 /* RLC blocks at end */
793 if (ret_val.mac__hdr().e() == true) {
794 LlcBlock lb;
795 unsigned int length = ttcn_buffer.get_read_len();
796 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
797 * fills the current RLC data block precisely or continues in the following in-sequence RLC
798 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100799 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200800 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
801 ttcn_buffer.increase_pos(length);
802 ret_val.blocks()[0] = lb;
803 } else {
804 if (ret_val.blocks().is_bound()) {
805 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
806 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
807 if (length > ttcn_buffer.get_read_len())
808 length = ttcn_buffer.get_read_len();
809 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
810 ttcn_buffer.increase_pos(length);
811 }
812 }
813 }
814
815 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
816 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
817 ttcn_buffer.log();
818 TTCN_Logger::end_event();
819 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
820 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
821 ret_val.log();
822 TTCN_Logger::end_event();
823
824 return ret_val;
825}
826
827static
828EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type1(const OCTETSTRING& stream)
829{
830 EgprsUlMacDataHeader ret_val;
831
832 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
833
834 return ret_val;
835}
836
837static
838EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type2(const OCTETSTRING& stream)
839{
840 EgprsUlMacDataHeader ret_val;
841
842 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
843
844 return ret_val;
845}
846
847static
848EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
849{
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200850 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200851 EgprsUlMacDataHeader ret_val;
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200852 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
853 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200854
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200855 egprs3 = static_cast<const struct gprs_rlc_ul_header_egprs_3 *>
856 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200857
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200858 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
859 ret_val.tfi() = egprs3->tfi_lo << 2 | egprs3->tfi_hi << 0;
860 ret_val.countdown() = egprs3->cv;
861 tmp = egprs3->si;
862 ret_val.foi__si() = BITSTRING(1, &tmp);
863 tmp = egprs3->r;
864 ret_val.r__ri() = BITSTRING(1, &tmp);
865 ret_val.bsn1() = egprs3->bsn1_lo << 5 | egprs3->bsn1_hi << 0;
866 ret_val.cps() = egprs3->cps_lo << 2 | egprs3->cps_hi << 0;
867 ret_val.pfi__ind() = egprs3->pi;
868 tmp = egprs3->rsb;
869 ret_val.rsb() = BITSTRING(1, &tmp);
870 tmp = egprs3->spb;
871 ret_val.spb() = BITSTRING(2, &tmp);
872
873 ttcn_buffer.increase_pos(sizeof(*egprs3));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200874 return ret_val;
875}
876
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100877RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200878{
879 RlcmacUlEgprsDataBlock ret_val;
880 TTCN_Buffer ttcn_buffer(stream);
881 TTCN_Buffer aligned_buffer;
882 int num_llc_blocks = 0;
883 unsigned int data_block_bits, data_block_offsets[2];
884 unsigned int num_calls;
885 const uint8_t *ti_e;
886
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100887 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
888 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200889 case CodingScheme::MCS__1:
890 case CodingScheme::MCS__2:
891 case CodingScheme::MCS__3:
892 case CodingScheme::MCS__4:
893 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
894 break;
895 case CodingScheme::MCS__5:
896 case CodingScheme::MCS__6:
897 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
898 break;
899 case CodingScheme::MCS__7:
900 case CodingScheme::MCS__8:
901 case CodingScheme::MCS__9:
902 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
903 break;
904 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100905 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), true,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200906 &num_calls, &data_block_bits, data_block_offsets);
907 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
908
909 ti_e = aligned_buffer.get_read_data();
910 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
911 ret_val.e() = *ti_e & 0x01 ? true : false;
912 aligned_buffer.increase_pos(1);
913
914 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
915 * optional tlli, optional pfi and LLC Blocks */
916
917 /* optional extension octets, containing LI+M+E of Llc blocks */
918 if (ret_val.e() == false) {
919 /* extension octet follows, i.e. optional Llc length octets */
920 while (1) {
921 /* decode one more extension octet with LlcBlocHdr inside */
922 EgprsLlcBlock lb;
923 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
924 ret_val.blocks()[num_llc_blocks++] = lb;
925
926 /* if E == '1'B, we can proceed further */
927 if (lb.hdr()().e() == true)
928 break;
929 }
930 }
931
932 /* parse optional TLLI */
933 if (ret_val.tlli__ind()) {
934 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
935 aligned_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200936 } else {
937 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200938 }
939 /* parse optional PFI */
940 if (ret_val.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +0200941 ret_val.pfi().decode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200942 } else {
943 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200944 }
945
946 /* RLC blocks at end */
947 if (ret_val.e() == true) {
948 EgprsLlcBlock lb;
949 unsigned int length = aligned_buffer.get_read_len();
950 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
951 * fills the current RLC data block precisely or continues in the following in-sequence RLC
952 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100953 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200954 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
955 aligned_buffer.increase_pos(length);
956 ret_val.blocks()[0] = lb;
957 } else {
958 if (ret_val.blocks().is_bound()) {
959 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
960 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
961 if (length > aligned_buffer.get_read_len())
962 length = aligned_buffer.get_read_len();
963 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
964 aligned_buffer.increase_pos(length);
965 }
966 }
967 }
968
969 return ret_val;
970}
971
972RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
973{
974 RlcmacUlBlock ret_val;
975 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100976 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200977 unsigned char pt;
978
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100979 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200980 case CodingScheme::CS__1:
981 case CodingScheme::CS__2:
982 case CodingScheme::CS__3:
983 case CodingScheme::CS__4:
984 pt = stream[0].get_octet() >> 6;
985 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
986 ret_val.data() = dec__RlcmacUlDataBlock(stream);
987 else
988 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
989 break;
990 case CodingScheme::MCS__1:
991 case CodingScheme::MCS__2:
992 case CodingScheme::MCS__3:
993 case CodingScheme::MCS__4:
994 case CodingScheme::MCS__5:
995 case CodingScheme::MCS__6:
996 case CodingScheme::MCS__7:
997 case CodingScheme::MCS__8:
998 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100999 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001000 break;
1001 }
1002
1003 return ret_val;
1004}
1005
1006
1007/////////////////////
1008// ENCODE
1009/////////////////////
1010
1011/* ENCODE DOWNLINK */
1012
1013OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
1014{
1015 RlcmacDlDataBlock in = si;
1016 OCTETSTRING ret_val;
1017 TTCN_Buffer ttcn_buffer;
1018 int i;
1019
1020 /* Fix 'e' bit of initial header based on following blocks */
1021 if (!in.blocks().is_bound() ||
1022 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1023 in.mac__hdr().hdr__ext().e() = true;
1024 else
1025 in.mac__hdr().hdr__ext().e() = false;
1026
1027 /* use automatic/generated decoder for header */
1028 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1029
1030 /* Add LI octets, if any */
1031 if (in.blocks().is_bound() &&
1032 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1033 /* first write LI octets */
1034 for (i = 0; i < in.blocks().size_of(); i++) {
1035 /* fix the 'E' bit in case it is not clear */
1036 if (i < in.blocks().size_of()-1)
1037 in.blocks()[i].hdr()().e() = false;
1038 else
1039 in.blocks()[i].hdr()().e() = true;
1040 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1041 }
1042 }
1043 if (in.blocks().is_bound()) {
1044 for (i = 0; i < in.blocks().size_of(); i++) {
1045 if (!in.blocks()[i].is_bound())
1046 continue;
1047 ttcn_buffer.put_string(in.blocks()[i].payload());
1048 }
1049 }
1050
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001051 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1052
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001053 ttcn_buffer.get_string(ret_val);
1054 return ret_val;
1055}
1056
1057static
1058void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1059{
1060 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1061}
1062
1063static
1064void enc__RlcmacDlEgprsDataHeader_type2(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1065{
1066 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1067}
1068
1069static
1070void enc__RlcmacDlEgprsDataHeader_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1071{
1072 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1073}
1074
1075OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
1076{
1077 RlcmacDlEgprsDataBlock in = si;
1078 OCTETSTRING ret_val;
1079 TTCN_Buffer ttcn_buffer;
1080 int i;
1081
1082 /* Fix 'e' bit of initial header based on following blocks */
1083 if (!in.blocks().is_bound() ||
1084 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1085 in.e() = true;
1086 else
1087 in.e() = false;
1088
1089 switch (in.mac__hdr().header__type()) {
1090 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
1091 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
1092 break;
1093 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
1094 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
1095 break;
1096 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
1097 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
1098 default:
1099 break; /* TODO: error */
1100 }
1101
1102 /* Add LI octets, if any */
1103 if (in.blocks().is_bound() &&
1104 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1105 /* first write LI octets */
1106 for (i = 0; i < in.blocks().size_of(); i++) {
1107 /* fix the 'E' bit in case it is not clear */
1108 if (i < in.blocks().size_of()-1)
1109 in.blocks()[i].hdr()().e() = false;
1110 else
1111 in.blocks()[i].hdr()().e() = true;
1112 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1113 }
1114 }
1115 if (in.blocks().is_bound()) {
1116 for (i = 0; i < in.blocks().size_of(); i++) {
1117 if (!in.blocks()[i].is_bound())
1118 continue;
1119 ttcn_buffer.put_string(in.blocks()[i].payload());
1120 }
1121 }
1122
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001123 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1124
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001125 ttcn_buffer.get_string(ret_val);
1126 return ret_val;
1127}
1128
1129OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
1130{
1131 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
1132 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
1133 else if (si.ischosen(RlcmacDlBlock::ALT_data))
1134 return enc__RlcmacDlDataBlock(si.data());
1135 else
1136 return enc__RlcmacDlCtrlBlock(si.ctrl());
1137}
1138
1139/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +02001140
1141OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
1142{
1143 RlcmacUlDataBlock in = si;
1144 OCTETSTRING ret_val;
1145 TTCN_Buffer ttcn_buffer;
1146 int i;
1147
Harald Welte060e27a2018-03-03 20:38:19 +01001148 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +02001149 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +01001150 in.mac__hdr().e() = false; /* E=0: extension octet follows */
1151 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1152 /* If there's only a single block, and that block has no HDR value defined, */
1153 in.mac__hdr().e() = true; /* E=0: extension octet follows */
1154 } else {
1155 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +02001156 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +01001157 }
Harald Welte43e060a2017-07-30 22:38:03 +02001158
1159 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +02001160 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1161 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +02001162
Harald Welte060e27a2018-03-03 20:38:19 +01001163 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +02001164 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1165
Harald Welte060e27a2018-03-03 20:38:19 +01001166 if (in.mac__hdr().e() == false) {
1167 /* Add LI octets, if any */
1168 if (!in.blocks().is_bound()) {
1169 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1170 } else {
1171 for (i = 0; i < in.blocks().size_of(); i++) {
1172#if 0
1173 /* check for penultimate block */
1174 if (i == in.blocks().size_of()-2) {
1175 /* if last block has no header, no more LI */
1176 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1177 in.blocks()[i].hdr()().more() = true;
1178 } else {
1179 /* header present, we have to encode LI */
1180 in.blocks()[i].hdr()().more() = false;
1181 in.blocks()[i].hdr()().length__ind() =
1182 in.blocks()[i+1].payload().lengthof();
1183 }
1184 } else if (i < in.blocks().size_of()-2) {
1185 /* one of the first blocks, before the penultimate or last */
1186 in.blocks()[i].hdr()().e() = false; /* LI present */
1187 /* re-compute length */
1188 in.blocks()[i].hdr()().length__ind() =
1189 in.blocks()[i+1].payload().lengthof();
1190 }
1191 /* Encode LI octet if E=0 */
1192 }
1193#endif
1194 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1195 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
1196 TTCN_EncDec::CT_RAW);
1197 }
1198 }
Harald Welte43e060a2017-07-30 22:38:03 +02001199 }
1200 }
1201
1202 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +01001203 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +02001204 }
1205
1206 if (in.mac__hdr().pfi__ind()) {
1207 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1208 }
1209
1210 if (in.blocks().is_bound()) {
1211 for (i = 0; i < in.blocks().size_of(); i++) {
1212 if (!in.blocks()[i].is_bound())
1213 continue;
1214 ttcn_buffer.put_string(in.blocks()[i].payload());
1215 }
1216 }
1217
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001218 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1219
Harald Welte43e060a2017-07-30 22:38:03 +02001220 ttcn_buffer.get_string(ret_val);
1221 return ret_val;
1222}
1223
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001224static
1225void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001226{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001227 struct gprs_rlc_ul_header_egprs_1 egprs1;
1228
1229 egprs1.r = bs2uint8(si.r__ri());
1230 egprs1.si = bs2uint8(si.foi__si());
1231 egprs1.cv = si.countdown();
1232 egprs1.tfi_hi = si.tfi() >> 0;
1233 egprs1.tfi_lo = si.tfi() >> 2;
1234 egprs1.bsn1_hi = si.bsn1() >> 0;
1235 egprs1.bsn1_lo = si.bsn1() >> 5;
1236 egprs1.bsn2_hi = si.bsn2__offset() >> 0;
1237 egprs1.bsn2_lo = si.bsn2__offset() >> 2;
1238 egprs1.cps = si.cps();
1239 egprs1.rsb = bs2uint8(si.rsb());
1240 egprs1.pi = si.pfi__ind();
1241 egprs1.spare_hi = 0;
1242 egprs1.spare_lo = 0;
1243 egprs1.dummy = 0;
1244
1245 ttcn_buffer.put_s(sizeof(egprs1), (const unsigned char *)&egprs1);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001246}
Harald Welte43e060a2017-07-30 22:38:03 +02001247
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001248static
1249void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1250{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001251 struct gprs_rlc_ul_header_egprs_2 egprs2;
1252
1253 egprs2.r = bs2uint8(si.r__ri());
1254 egprs2.si = bs2uint8(si.foi__si());
1255 egprs2.cv = si.countdown();
1256 egprs2.tfi_hi = si.tfi() >> 0;
1257 egprs2.tfi_lo = si.tfi() >> 2;
1258 egprs2.bsn1_hi = si.bsn1() >> 0;
1259 egprs2.bsn1_lo = si.bsn1() >> 5;
1260 egprs2.cps_hi = si.cps() >> 0;
1261 egprs2.cps_lo = si.cps() >> 2;
1262 egprs2.rsb = bs2uint8(si.rsb());
1263 egprs2.pi = si.pfi__ind();
1264 egprs2.spare_hi = 0;
1265 egprs2.spare_lo = 0;
1266 egprs2.dummy = 0;
1267
1268 ttcn_buffer.put_s(sizeof(egprs2), (const unsigned char *)&egprs2);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001269}
Harald Welte43e060a2017-07-30 22:38:03 +02001270
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001271static
1272void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1273{
1274 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001275
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001276 egprs3.r = bs2uint8(si.r__ri());
1277 egprs3.si = bs2uint8(si.foi__si());
1278 egprs3.cv = si.countdown();
1279 egprs3.tfi_hi = si.tfi() >> 0;
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001280 egprs3.tfi_lo = si.tfi() >> 2;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001281 egprs3.bsn1_hi = si.bsn1() >> 0;
1282 egprs3.bsn1_lo = si.bsn1() >> 5;
1283 egprs3.cps_hi = si.cps() >> 0;
1284 egprs3.cps_lo = si.cps() >> 2;
1285 egprs3.spb = bs2uint8(si.spb());
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001286 egprs3.rsb = bs2uint8(si.rsb());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001287 egprs3.pi = si.pfi__ind();
1288 egprs3.spare = 0;
1289 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001290
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001291 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1292}
Harald Welte43e060a2017-07-30 22:38:03 +02001293
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001294OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1295{
1296 RlcmacUlEgprsDataBlock in = si;
1297 OCTETSTRING ret_val;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001298 TTCN_Buffer ttcn_buffer, aligned_buffer;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001299 int i;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001300 unsigned int data_block_bits, data_block_offsets[2];
1301 unsigned int num_calls;
1302 CodingScheme mcs;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001303
1304 mcs = RLCMAC__Templates::f__rlcmac__cps__htype__to__mcs(in.mac__hdr().cps(), in.mac__hdr().header__type());
1305 //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 +02001306
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001307 if (!in.blocks().is_bound()) {
1308 /* we don't have nay blocks: Add length value (zero) */
1309 in.e() = false; /* E=0: extension octet follows */
1310 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1311 /* If there's only a single block, and that block has no HDR value defined, */
1312 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001313 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001314 /* Length value */
1315 in.e() = false;
1316 }
1317
1318 /* Fix other presence indications */
1319 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1320 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1321
1322 switch (in.mac__hdr().header__type()) {
1323 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001324 enc__RlcmacUlEgprsDataHeader_type1(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001325 break;
1326 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001327 enc__RlcmacUlEgprsDataHeader_type2(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001328 break;
1329 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001330 enc__RlcmacUlEgprsDataHeader_type3(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001331 default:
1332 break; /* TODO: error */
1333 }
1334
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001335 /* Put first TI + E byte */
Pau Espin Pedrol563bcd62020-11-06 19:51:23 +01001336 aligned_buffer.put_c((in.tlli__ind() & 0x01) << 1 | (in.e() & 0x01) << 0);
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001337 //printbuffer("After encoding first byte", aligned_buffer);
1338
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001339 if (in.e() == false) {
1340 /* Add LI octets, if any */
1341 if (!in.blocks().is_bound()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001342 aligned_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001343 } else {
1344 for (i = 0; i < in.blocks().size_of(); i++) {
1345#if 0
1346 /* check for penultimate block */
1347 if (i == in.blocks().size_of()-2) {
1348 /* if last block has no header, no more LI */
1349 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1350 in.blocks()[i].hdr()().more() = true;
1351 } else {
1352 /* header present, we have to encode LI */
1353 in.blocks()[i].hdr()().more() = false;
1354 in.blocks()[i].hdr()().length__ind() =
1355 in.blocks()[i+1].payload().lengthof();
1356 }
1357 } else if (i < in.blocks().size_of()-2) {
1358 /* one of the first blocks, before the penultimate or last */
1359 in.blocks()[i].hdr()().e() = false; /* LI present */
1360 /* re-compute length */
1361 in.blocks()[i].hdr()().length__ind() =
1362 in.blocks()[i+1].payload().lengthof();
1363 }
1364 /* Encode LI octet if E=0 */
1365 }
1366#endif
1367 if (in.blocks()[i].hdr() != OMIT_VALUE) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001368 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, aligned_buffer,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001369 TTCN_EncDec::CT_RAW);
1370 }
Harald Welte43e060a2017-07-30 22:38:03 +02001371 }
1372 }
1373 }
1374
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001375
1376
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001377 if (in.tlli__ind()) {
Pau Espin Pedrola05b2bc2020-11-06 20:38:21 +01001378 /* The TLLI is encoded in little endian for EGPRS (see
1379 * TS 44.060, figure 10.3a.2.1, note 2) */
1380 OCTETSTRING tlli = in.tlli();
1381 aligned_buffer.put_c(tlli[3].get_octet());
1382 aligned_buffer.put_c(tlli[2].get_octet());
1383 aligned_buffer.put_c(tlli[1].get_octet());
1384 aligned_buffer.put_c(tlli[0].get_octet());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001385 }
Harald Welte43e060a2017-07-30 22:38:03 +02001386
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001387 if (in.mac__hdr().pfi__ind()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001388 in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001389 }
1390
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001391 //printbuffer("Before encoding EgprsLlc payload", aligned_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001392 if (in.blocks().is_bound()) {
1393 for (i = 0; i < in.blocks().size_of(); i++) {
1394 if (!in.blocks()[i].is_bound())
1395 continue;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001396 aligned_buffer.put_string(in.blocks()[i].payload());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001397 }
1398 }
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001399 //printbuffer("After encoding EgprsLlc payload", aligned_buffer);
1400
1401 setup_rlc_mac_priv(mcs, in.mac__hdr().header__type(), true,
1402 &num_calls, &data_block_bits, data_block_offsets);
1403 //printbuffer("before merging data block", ttcn_buffer);
1404 put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer);
1405 //printbuffer("after merging data block", ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001406
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001407 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1408
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001409 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001410 return ret_val;
1411}
1412
Harald Welte78a1af62017-07-31 17:33:56 +02001413OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1414{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001415 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1416 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1417 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001418 return enc__RlcmacUlDataBlock(si.data());
1419 else
1420 return enc__RlcmacUlCtrlBlock(si.ctrl());
1421}
1422
Harald Welte43e060a2017-07-30 22:38:03 +02001423} // namespace