blob: ac60b376cc517414c7e4a906fd07d071c051843e [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 */
508 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
509 ttcn_buffer.increase_pos(length);
510 ret_val.blocks()[0] = lb;
511 } else {
512 if (ret_val.blocks().is_bound()) {
513 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
Harald Welte060e27a2018-03-03 20:38:19 +0100514 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
Harald Welte43e060a2017-07-30 22:38:03 +0200515 if (length > ttcn_buffer.get_read_len())
516 length = ttcn_buffer.get_read_len();
517 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
518 ttcn_buffer.increase_pos(length);
519 }
520 }
521 }
522
523 return ret_val;
524}
525
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200526static
527EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream)
528{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100529 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200530 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100531 const struct gprs_rlc_dl_header_egprs_1 *egprs1;
532 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200533
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100534 egprs1 = static_cast<const struct gprs_rlc_dl_header_egprs_1 *>
535 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200536
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100537 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__1;
538 ret_val.tfi() = egprs1->tfi_lo << 1 | egprs1->tfi_hi << 0;
539 ret_val.rrbp() = egprs1->rrbp;
540 tmp = egprs1->es_p;
541 ret_val.esp() = BITSTRING(2, &tmp);
542 ret_val.usf() = egprs1->usf;
543 ret_val.bsn1() = egprs1->bsn1_lo << 10 | egprs1->bsn1_mid << 2 | egprs1->bsn1_hi;
544 ret_val.bsn2__offset() = egprs1->bsn2_lo << 7 | egprs1->bsn2_hi;
545 ret_val.pr() = egprs1->pr;
546 ret_val.cps() = egprs1->cps;
547
548 ttcn_buffer.increase_pos(sizeof(*egprs1));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200549 return ret_val;
550}
551
552static
553EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream)
554{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100555 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200556 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100557 const struct gprs_rlc_dl_header_egprs_2 *egprs2;
558 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200559
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100560 egprs2 = static_cast<const struct gprs_rlc_dl_header_egprs_2 *>
561 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200562
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100563 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__2;
564 ret_val.tfi() = egprs2->tfi_lo << 1 | egprs2->tfi_hi << 0;
565 ret_val.rrbp() = egprs2->rrbp;
566 tmp = egprs2->es_p;
567 ret_val.esp() = BITSTRING(2, &tmp);
568 ret_val.usf() = egprs2->usf;
569 ret_val.bsn1() = egprs2->bsn1_lo << 10 | egprs2->bsn1_mid << 2 | egprs2->bsn1_hi;
570 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
571 ret_val.pr() = egprs2->pr;
572 ret_val.cps() = egprs2->cps;
573
574 ttcn_buffer.increase_pos(sizeof(*egprs2));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200575 return ret_val;
576}
577
578static
579EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream)
580{
581 TTCN_Buffer ttcn_buffer(stream);
582 EgprsDlMacDataHeader ret_val;
583 const struct gprs_rlc_dl_header_egprs_3 *egprs3;
584 uint8_t tmp;
585
586 egprs3 = static_cast<const struct gprs_rlc_dl_header_egprs_3 *>
587 ((const void *)ttcn_buffer.get_data());
588
589 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
590 ret_val.tfi() = egprs3->tfi_lo << 1 | egprs3->tfi_hi << 0;
591 ret_val.rrbp() = egprs3->rrbp;
592 tmp = egprs3->es_p;
593 ret_val.esp() = BITSTRING(2, &tmp);
594 ret_val.usf() = egprs3->usf;
595 ret_val.bsn1() = egprs3->bsn1_lo << 10 | egprs3->bsn1_mid << 2 | egprs3->bsn1_hi;
596 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
597 ret_val.pr() = egprs3->pr;
598 ret_val.spb() = egprs3->spb;
599 ret_val.cps() = egprs3->cps;
600
601 ttcn_buffer.increase_pos(sizeof(*egprs3));
602 return ret_val;
603}
604
605static
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100606RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200607{
608 RlcmacDlEgprsDataBlock ret_val;
609 TTCN_Buffer ttcn_buffer(stream);
610 TTCN_Buffer aligned_buffer;
611 int num_llc_blocks = 0;
612 unsigned int data_block_bits, data_block_offsets[2];
613 unsigned int num_calls;
614 const uint8_t *ti_e;
615
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100616 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
617 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200618 case CodingScheme::MCS__0:
619 case CodingScheme::MCS__1:
620 case CodingScheme::MCS__2:
621 case CodingScheme::MCS__3:
622 case CodingScheme::MCS__4:
623 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type3(stream);
624 break;
625 case CodingScheme::MCS__5:
626 case CodingScheme::MCS__6:
627 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type2(stream);
628 break;
629 case CodingScheme::MCS__7:
630 case CodingScheme::MCS__8:
631 case CodingScheme::MCS__9:
632 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream);
633 break;
634 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100635 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), false,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200636 &num_calls, &data_block_bits, data_block_offsets);
637 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
638
639 ti_e = aligned_buffer.get_read_data();
640 ret_val.fbi() = *ti_e & 0x02 ? true : false;
641 ret_val.e() = *ti_e & 0x01 ? true : false;
642 aligned_buffer.increase_pos(1);
643
644 /* optional extension octets, containing LI+E of Llc blocks */
645 if (ret_val.e() == false) {
646 /* extension octet follows, i.e. optional Llc length octets */
647 while (1) {
648 /* decode one more extension octet with LlcBlocHdr inside */
649 EgprsLlcBlock lb;
650 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
651 ret_val.blocks()[num_llc_blocks++] = lb;
652
653 /* if E == '1'B, we can proceed further */
654 if (lb.hdr()().e() == true)
655 break;
656 }
657 }
658
659 /* RLC blocks at end */
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100660 if (ret_val.e() == true) {
661 EgprsLlcBlock lb;
662 unsigned int length = aligned_buffer.get_read_len();
663 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
664 * fills the current RLC data block precisely or continues in the following in-sequence RLC
665 * data block */
666 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
667 aligned_buffer.increase_pos(length);
668 ret_val.blocks()[0] = lb;
669 } else {
670 /* RLC blocks at end */
671 if (ret_val.blocks().is_bound()) {
672 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
673 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
674 if (length > aligned_buffer.get_read_len())
675 length = aligned_buffer.get_read_len();
676 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
677 aligned_buffer.increase_pos(length);
678 }
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200679 }
680 }
681
682 return ret_val;
683}
684
685RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
686{
687 RlcmacDlBlock ret_val;
688 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100689 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200690 unsigned char pt;
691
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100692 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200693 case CodingScheme::CS__1:
694 case CodingScheme::CS__2:
695 case CodingScheme::CS__3:
696 case CodingScheme::CS__4:
697 pt = stream[0].get_octet() >> 6;
698 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
699 ret_val.data() = dec__RlcmacDlDataBlock(stream);
700 else
701 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
702 break;
703 case CodingScheme::MCS__0:
704 case CodingScheme::MCS__1:
705 case CodingScheme::MCS__2:
706 case CodingScheme::MCS__3:
707 case CodingScheme::MCS__4:
708 case CodingScheme::MCS__5:
709 case CodingScheme::MCS__6:
710 case CodingScheme::MCS__7:
711 case CodingScheme::MCS__8:
712 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100713 ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200714 break;
715 }
716 return ret_val;
717}
718
719/* DECODE UPLINK */
720
721RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
722{
723 RlcmacUlDataBlock ret_val;
724 TTCN_Buffer ttcn_buffer(stream);
725 int num_llc_blocks = 0;
726
727 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
728 TTCN_Logger::log_event_str("==================================\n"
729 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
730 stream.log();
731 TTCN_Logger::end_event();
732
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100733 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
734
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200735 /* use automatic/generated decoder for header */
736 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
737
738 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
739 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
740 ttcn_buffer.log();
741 TTCN_Logger::end_event();
742 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
743 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
744 ret_val.log();
745 TTCN_Logger::end_event();
746
747 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
748 * optional tlli, optional pfi and LLC Blocks */
749
750 /* optional extension octets, containing LI+M+E of Llc blocks */
751 if (ret_val.mac__hdr().e() == false) {
752 /* extension octet follows, i.e. optional Llc length octets */
753 while (1) {
754 /* decode one more extension octet with LlcBlocHdr inside */
755 LlcBlock lb;
756 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
757 ret_val.blocks()[num_llc_blocks++] = lb;
758
759 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
760 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
761 ttcn_buffer.log();
762 TTCN_Logger::end_event();
763 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
764 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
765 ret_val.log();
766 TTCN_Logger::end_event();
767
768 /* if E == '1'B, we can proceed further */
769 if (lb.hdr()().e() == true)
770 break;
771 }
772 }
773
774 /* parse optional TLLI */
775 if (ret_val.mac__hdr().tlli__ind()) {
776 ret_val.tlli() = OCTETSTRING(4, ttcn_buffer.get_read_data());
777 ttcn_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200778 } else {
779 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200780 }
781 /* parse optional PFI */
782 if (ret_val.mac__hdr().pfi__ind()) {
783 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200784 } else {
785 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200786 }
787
788 /* RLC blocks at end */
789 if (ret_val.mac__hdr().e() == true) {
790 LlcBlock lb;
791 unsigned int length = ttcn_buffer.get_read_len();
792 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
793 * fills the current RLC data block precisely or continues in the following in-sequence RLC
794 * data block */
795 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
796 ttcn_buffer.increase_pos(length);
797 ret_val.blocks()[0] = lb;
798 } else {
799 if (ret_val.blocks().is_bound()) {
800 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
801 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
802 if (length > ttcn_buffer.get_read_len())
803 length = ttcn_buffer.get_read_len();
804 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
805 ttcn_buffer.increase_pos(length);
806 }
807 }
808 }
809
810 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
811 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
812 ttcn_buffer.log();
813 TTCN_Logger::end_event();
814 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
815 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
816 ret_val.log();
817 TTCN_Logger::end_event();
818
819 return ret_val;
820}
821
822static
823EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type1(const OCTETSTRING& stream)
824{
825 EgprsUlMacDataHeader ret_val;
826
827 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
828
829 return ret_val;
830}
831
832static
833EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type2(const OCTETSTRING& stream)
834{
835 EgprsUlMacDataHeader ret_val;
836
837 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
838
839 return ret_val;
840}
841
842static
843EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
844{
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200845 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200846 EgprsUlMacDataHeader ret_val;
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200847 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
848 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200849
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200850 egprs3 = static_cast<const struct gprs_rlc_ul_header_egprs_3 *>
851 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200852
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200853 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
854 ret_val.tfi() = egprs3->tfi_lo << 2 | egprs3->tfi_hi << 0;
855 ret_val.countdown() = egprs3->cv;
856 tmp = egprs3->si;
857 ret_val.foi__si() = BITSTRING(1, &tmp);
858 tmp = egprs3->r;
859 ret_val.r__ri() = BITSTRING(1, &tmp);
860 ret_val.bsn1() = egprs3->bsn1_lo << 5 | egprs3->bsn1_hi << 0;
861 ret_val.cps() = egprs3->cps_lo << 2 | egprs3->cps_hi << 0;
862 ret_val.pfi__ind() = egprs3->pi;
863 tmp = egprs3->rsb;
864 ret_val.rsb() = BITSTRING(1, &tmp);
865 tmp = egprs3->spb;
866 ret_val.spb() = BITSTRING(2, &tmp);
867
868 ttcn_buffer.increase_pos(sizeof(*egprs3));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200869 return ret_val;
870}
871
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100872RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200873{
874 RlcmacUlEgprsDataBlock ret_val;
875 TTCN_Buffer ttcn_buffer(stream);
876 TTCN_Buffer aligned_buffer;
877 int num_llc_blocks = 0;
878 unsigned int data_block_bits, data_block_offsets[2];
879 unsigned int num_calls;
880 const uint8_t *ti_e;
881
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100882 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
883 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200884 case CodingScheme::MCS__1:
885 case CodingScheme::MCS__2:
886 case CodingScheme::MCS__3:
887 case CodingScheme::MCS__4:
888 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
889 break;
890 case CodingScheme::MCS__5:
891 case CodingScheme::MCS__6:
892 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
893 break;
894 case CodingScheme::MCS__7:
895 case CodingScheme::MCS__8:
896 case CodingScheme::MCS__9:
897 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
898 break;
899 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100900 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), true,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200901 &num_calls, &data_block_bits, data_block_offsets);
902 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
903
904 ti_e = aligned_buffer.get_read_data();
905 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
906 ret_val.e() = *ti_e & 0x01 ? true : false;
907 aligned_buffer.increase_pos(1);
908
909 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
910 * optional tlli, optional pfi and LLC Blocks */
911
912 /* optional extension octets, containing LI+M+E of Llc blocks */
913 if (ret_val.e() == false) {
914 /* extension octet follows, i.e. optional Llc length octets */
915 while (1) {
916 /* decode one more extension octet with LlcBlocHdr inside */
917 EgprsLlcBlock lb;
918 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
919 ret_val.blocks()[num_llc_blocks++] = lb;
920
921 /* if E == '1'B, we can proceed further */
922 if (lb.hdr()().e() == true)
923 break;
924 }
925 }
926
927 /* parse optional TLLI */
928 if (ret_val.tlli__ind()) {
929 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
930 aligned_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200931 } else {
932 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200933 }
934 /* parse optional PFI */
935 if (ret_val.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +0200936 ret_val.pfi().decode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200937 } else {
938 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200939 }
940
941 /* RLC blocks at end */
942 if (ret_val.e() == true) {
943 EgprsLlcBlock lb;
944 unsigned int length = aligned_buffer.get_read_len();
945 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
946 * fills the current RLC data block precisely or continues in the following in-sequence RLC
947 * data block */
948 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
949 aligned_buffer.increase_pos(length);
950 ret_val.blocks()[0] = lb;
951 } else {
952 if (ret_val.blocks().is_bound()) {
953 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
954 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
955 if (length > aligned_buffer.get_read_len())
956 length = aligned_buffer.get_read_len();
957 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
958 aligned_buffer.increase_pos(length);
959 }
960 }
961 }
962
963 return ret_val;
964}
965
966RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
967{
968 RlcmacUlBlock ret_val;
969 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100970 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200971 unsigned char pt;
972
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100973 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200974 case CodingScheme::CS__1:
975 case CodingScheme::CS__2:
976 case CodingScheme::CS__3:
977 case CodingScheme::CS__4:
978 pt = stream[0].get_octet() >> 6;
979 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
980 ret_val.data() = dec__RlcmacUlDataBlock(stream);
981 else
982 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
983 break;
984 case CodingScheme::MCS__1:
985 case CodingScheme::MCS__2:
986 case CodingScheme::MCS__3:
987 case CodingScheme::MCS__4:
988 case CodingScheme::MCS__5:
989 case CodingScheme::MCS__6:
990 case CodingScheme::MCS__7:
991 case CodingScheme::MCS__8:
992 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100993 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200994 break;
995 }
996
997 return ret_val;
998}
999
1000
1001/////////////////////
1002// ENCODE
1003/////////////////////
1004
1005/* ENCODE DOWNLINK */
1006
1007OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
1008{
1009 RlcmacDlDataBlock in = si;
1010 OCTETSTRING ret_val;
1011 TTCN_Buffer ttcn_buffer;
1012 int i;
1013
1014 /* Fix 'e' bit of initial header based on following blocks */
1015 if (!in.blocks().is_bound() ||
1016 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1017 in.mac__hdr().hdr__ext().e() = true;
1018 else
1019 in.mac__hdr().hdr__ext().e() = false;
1020
1021 /* use automatic/generated decoder for header */
1022 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1023
1024 /* Add LI octets, if any */
1025 if (in.blocks().is_bound() &&
1026 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1027 /* first write LI octets */
1028 for (i = 0; i < in.blocks().size_of(); i++) {
1029 /* fix the 'E' bit in case it is not clear */
1030 if (i < in.blocks().size_of()-1)
1031 in.blocks()[i].hdr()().e() = false;
1032 else
1033 in.blocks()[i].hdr()().e() = true;
1034 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1035 }
1036 }
1037 if (in.blocks().is_bound()) {
1038 for (i = 0; i < in.blocks().size_of(); i++) {
1039 if (!in.blocks()[i].is_bound())
1040 continue;
1041 ttcn_buffer.put_string(in.blocks()[i].payload());
1042 }
1043 }
1044
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001045 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1046
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001047 ttcn_buffer.get_string(ret_val);
1048 return ret_val;
1049}
1050
1051static
1052void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1053{
1054 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1055}
1056
1057static
1058void enc__RlcmacDlEgprsDataHeader_type2(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_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1065{
1066 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1067}
1068
1069OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
1070{
1071 RlcmacDlEgprsDataBlock in = si;
1072 OCTETSTRING ret_val;
1073 TTCN_Buffer ttcn_buffer;
1074 int i;
1075
1076 /* Fix 'e' bit of initial header based on following blocks */
1077 if (!in.blocks().is_bound() ||
1078 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1079 in.e() = true;
1080 else
1081 in.e() = false;
1082
1083 switch (in.mac__hdr().header__type()) {
1084 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
1085 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
1086 break;
1087 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
1088 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
1089 break;
1090 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
1091 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
1092 default:
1093 break; /* TODO: error */
1094 }
1095
1096 /* Add LI octets, if any */
1097 if (in.blocks().is_bound() &&
1098 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1099 /* first write LI octets */
1100 for (i = 0; i < in.blocks().size_of(); i++) {
1101 /* fix the 'E' bit in case it is not clear */
1102 if (i < in.blocks().size_of()-1)
1103 in.blocks()[i].hdr()().e() = false;
1104 else
1105 in.blocks()[i].hdr()().e() = true;
1106 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1107 }
1108 }
1109 if (in.blocks().is_bound()) {
1110 for (i = 0; i < in.blocks().size_of(); i++) {
1111 if (!in.blocks()[i].is_bound())
1112 continue;
1113 ttcn_buffer.put_string(in.blocks()[i].payload());
1114 }
1115 }
1116
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001117 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1118
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001119 ttcn_buffer.get_string(ret_val);
1120 return ret_val;
1121}
1122
1123OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
1124{
1125 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
1126 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
1127 else if (si.ischosen(RlcmacDlBlock::ALT_data))
1128 return enc__RlcmacDlDataBlock(si.data());
1129 else
1130 return enc__RlcmacDlCtrlBlock(si.ctrl());
1131}
1132
1133/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +02001134
1135OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
1136{
1137 RlcmacUlDataBlock in = si;
1138 OCTETSTRING ret_val;
1139 TTCN_Buffer ttcn_buffer;
1140 int i;
1141
Harald Welte060e27a2018-03-03 20:38:19 +01001142 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +02001143 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +01001144 in.mac__hdr().e() = false; /* E=0: extension octet follows */
1145 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1146 /* If there's only a single block, and that block has no HDR value defined, */
1147 in.mac__hdr().e() = true; /* E=0: extension octet follows */
1148 } else {
1149 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +02001150 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +01001151 }
Harald Welte43e060a2017-07-30 22:38:03 +02001152
1153 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +02001154 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1155 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +02001156
Harald Welte060e27a2018-03-03 20:38:19 +01001157 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +02001158 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1159
Harald Welte060e27a2018-03-03 20:38:19 +01001160 if (in.mac__hdr().e() == false) {
1161 /* Add LI octets, if any */
1162 if (!in.blocks().is_bound()) {
1163 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1164 } else {
1165 for (i = 0; i < in.blocks().size_of(); i++) {
1166#if 0
1167 /* check for penultimate block */
1168 if (i == in.blocks().size_of()-2) {
1169 /* if last block has no header, no more LI */
1170 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1171 in.blocks()[i].hdr()().more() = true;
1172 } else {
1173 /* header present, we have to encode LI */
1174 in.blocks()[i].hdr()().more() = false;
1175 in.blocks()[i].hdr()().length__ind() =
1176 in.blocks()[i+1].payload().lengthof();
1177 }
1178 } else if (i < in.blocks().size_of()-2) {
1179 /* one of the first blocks, before the penultimate or last */
1180 in.blocks()[i].hdr()().e() = false; /* LI present */
1181 /* re-compute length */
1182 in.blocks()[i].hdr()().length__ind() =
1183 in.blocks()[i+1].payload().lengthof();
1184 }
1185 /* Encode LI octet if E=0 */
1186 }
1187#endif
1188 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1189 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
1190 TTCN_EncDec::CT_RAW);
1191 }
1192 }
Harald Welte43e060a2017-07-30 22:38:03 +02001193 }
1194 }
1195
1196 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +01001197 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +02001198 }
1199
1200 if (in.mac__hdr().pfi__ind()) {
1201 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1202 }
1203
1204 if (in.blocks().is_bound()) {
1205 for (i = 0; i < in.blocks().size_of(); i++) {
1206 if (!in.blocks()[i].is_bound())
1207 continue;
1208 ttcn_buffer.put_string(in.blocks()[i].payload());
1209 }
1210 }
1211
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001212 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1213
Harald Welte43e060a2017-07-30 22:38:03 +02001214 ttcn_buffer.get_string(ret_val);
1215 return ret_val;
1216}
1217
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001218static
1219void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001220{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001221 struct gprs_rlc_ul_header_egprs_1 egprs1;
1222
1223 egprs1.r = bs2uint8(si.r__ri());
1224 egprs1.si = bs2uint8(si.foi__si());
1225 egprs1.cv = si.countdown();
1226 egprs1.tfi_hi = si.tfi() >> 0;
1227 egprs1.tfi_lo = si.tfi() >> 2;
1228 egprs1.bsn1_hi = si.bsn1() >> 0;
1229 egprs1.bsn1_lo = si.bsn1() >> 5;
1230 egprs1.bsn2_hi = si.bsn2__offset() >> 0;
1231 egprs1.bsn2_lo = si.bsn2__offset() >> 2;
1232 egprs1.cps = si.cps();
1233 egprs1.rsb = bs2uint8(si.rsb());
1234 egprs1.pi = si.pfi__ind();
1235 egprs1.spare_hi = 0;
1236 egprs1.spare_lo = 0;
1237 egprs1.dummy = 0;
1238
1239 ttcn_buffer.put_s(sizeof(egprs1), (const unsigned char *)&egprs1);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001240}
Harald Welte43e060a2017-07-30 22:38:03 +02001241
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001242static
1243void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1244{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001245 struct gprs_rlc_ul_header_egprs_2 egprs2;
1246
1247 egprs2.r = bs2uint8(si.r__ri());
1248 egprs2.si = bs2uint8(si.foi__si());
1249 egprs2.cv = si.countdown();
1250 egprs2.tfi_hi = si.tfi() >> 0;
1251 egprs2.tfi_lo = si.tfi() >> 2;
1252 egprs2.bsn1_hi = si.bsn1() >> 0;
1253 egprs2.bsn1_lo = si.bsn1() >> 5;
1254 egprs2.cps_hi = si.cps() >> 0;
1255 egprs2.cps_lo = si.cps() >> 2;
1256 egprs2.rsb = bs2uint8(si.rsb());
1257 egprs2.pi = si.pfi__ind();
1258 egprs2.spare_hi = 0;
1259 egprs2.spare_lo = 0;
1260 egprs2.dummy = 0;
1261
1262 ttcn_buffer.put_s(sizeof(egprs2), (const unsigned char *)&egprs2);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001263}
Harald Welte43e060a2017-07-30 22:38:03 +02001264
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001265static
1266void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1267{
1268 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001269
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001270 egprs3.r = bs2uint8(si.r__ri());
1271 egprs3.si = bs2uint8(si.foi__si());
1272 egprs3.cv = si.countdown();
1273 egprs3.tfi_hi = si.tfi() >> 0;
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001274 egprs3.tfi_lo = si.tfi() >> 2;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001275 egprs3.bsn1_hi = si.bsn1() >> 0;
1276 egprs3.bsn1_lo = si.bsn1() >> 5;
1277 egprs3.cps_hi = si.cps() >> 0;
1278 egprs3.cps_lo = si.cps() >> 2;
1279 egprs3.spb = bs2uint8(si.spb());
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001280 egprs3.rsb = bs2uint8(si.rsb());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001281 egprs3.pi = si.pfi__ind();
1282 egprs3.spare = 0;
1283 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001284
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001285 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1286}
Harald Welte43e060a2017-07-30 22:38:03 +02001287
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001288OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1289{
1290 RlcmacUlEgprsDataBlock in = si;
1291 OCTETSTRING ret_val;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001292 TTCN_Buffer ttcn_buffer, aligned_buffer;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001293 int i;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001294 unsigned int data_block_bits, data_block_offsets[2];
1295 unsigned int num_calls;
1296 CodingScheme mcs;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001297
1298 mcs = RLCMAC__Templates::f__rlcmac__cps__htype__to__mcs(in.mac__hdr().cps(), in.mac__hdr().header__type());
1299 //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 +02001300
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001301 if (!in.blocks().is_bound()) {
1302 /* we don't have nay blocks: Add length value (zero) */
1303 in.e() = false; /* E=0: extension octet follows */
1304 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1305 /* If there's only a single block, and that block has no HDR value defined, */
1306 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001307 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001308 /* Length value */
1309 in.e() = false;
1310 }
1311
1312 /* Fix other presence indications */
1313 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1314 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1315
1316 switch (in.mac__hdr().header__type()) {
1317 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001318 enc__RlcmacUlEgprsDataHeader_type1(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001319 break;
1320 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001321 enc__RlcmacUlEgprsDataHeader_type2(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001322 break;
1323 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001324 enc__RlcmacUlEgprsDataHeader_type3(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001325 default:
1326 break; /* TODO: error */
1327 }
1328
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001329 /* Put first TI + E byte */
Pau Espin Pedrol563bcd62020-11-06 19:51:23 +01001330 aligned_buffer.put_c((in.tlli__ind() & 0x01) << 1 | (in.e() & 0x01) << 0);
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001331 //printbuffer("After encoding first byte", aligned_buffer);
1332
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001333 if (in.e() == false) {
1334 /* Add LI octets, if any */
1335 if (!in.blocks().is_bound()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001336 aligned_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001337 } else {
1338 for (i = 0; i < in.blocks().size_of(); i++) {
1339#if 0
1340 /* check for penultimate block */
1341 if (i == in.blocks().size_of()-2) {
1342 /* if last block has no header, no more LI */
1343 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1344 in.blocks()[i].hdr()().more() = true;
1345 } else {
1346 /* header present, we have to encode LI */
1347 in.blocks()[i].hdr()().more() = false;
1348 in.blocks()[i].hdr()().length__ind() =
1349 in.blocks()[i+1].payload().lengthof();
1350 }
1351 } else if (i < in.blocks().size_of()-2) {
1352 /* one of the first blocks, before the penultimate or last */
1353 in.blocks()[i].hdr()().e() = false; /* LI present */
1354 /* re-compute length */
1355 in.blocks()[i].hdr()().length__ind() =
1356 in.blocks()[i+1].payload().lengthof();
1357 }
1358 /* Encode LI octet if E=0 */
1359 }
1360#endif
1361 if (in.blocks()[i].hdr() != OMIT_VALUE) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001362 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, aligned_buffer,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001363 TTCN_EncDec::CT_RAW);
1364 }
Harald Welte43e060a2017-07-30 22:38:03 +02001365 }
1366 }
1367 }
1368
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001369
1370
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001371 if (in.tlli__ind()) {
Pau Espin Pedrola05b2bc2020-11-06 20:38:21 +01001372 /* The TLLI is encoded in little endian for EGPRS (see
1373 * TS 44.060, figure 10.3a.2.1, note 2) */
1374 OCTETSTRING tlli = in.tlli();
1375 aligned_buffer.put_c(tlli[3].get_octet());
1376 aligned_buffer.put_c(tlli[2].get_octet());
1377 aligned_buffer.put_c(tlli[1].get_octet());
1378 aligned_buffer.put_c(tlli[0].get_octet());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001379 }
Harald Welte43e060a2017-07-30 22:38:03 +02001380
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001381 if (in.mac__hdr().pfi__ind()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001382 in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001383 }
1384
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001385 //printbuffer("Before encoding EgprsLlc payload", aligned_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001386 if (in.blocks().is_bound()) {
1387 for (i = 0; i < in.blocks().size_of(); i++) {
1388 if (!in.blocks()[i].is_bound())
1389 continue;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001390 aligned_buffer.put_string(in.blocks()[i].payload());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001391 }
1392 }
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001393 //printbuffer("After encoding EgprsLlc payload", aligned_buffer);
1394
1395 setup_rlc_mac_priv(mcs, in.mac__hdr().header__type(), true,
1396 &num_calls, &data_block_bits, data_block_offsets);
1397 //printbuffer("before merging data block", ttcn_buffer);
1398 put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer);
1399 //printbuffer("after merging data block", ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001400
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001401 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1402
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001403 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001404 return ret_val;
1405}
1406
Harald Welte78a1af62017-07-31 17:33:56 +02001407OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1408{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001409 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1410 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1411 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001412 return enc__RlcmacUlDataBlock(si.data());
1413 else
1414 return enc__RlcmacUlCtrlBlock(si.ctrl());
1415}
1416
Harald Welte43e060a2017-07-30 22:38:03 +02001417} // namespace