blob: dd32d8f8f44a2fc17817c07e1a22e464c59d92f8 [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?
Vadim Yanitskiy17953b82023-12-15 16:45:50 +0700458 return;
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +0100459 }
460
461 for (int i = 0; i < blk_len_no_spb - data_len; i++)
462 buf[i] = 0x2b; /* Padding bits if needed */
463 for (int i = blk_len_no_spb - data_len; i < blk_len - data_len; i++)
464 buf[i] = 0x00; /* Spare bits if needed */
465
466 const OCTETSTRING& pad_octstr = OCTETSTRING(blk_len - data_len, buf);
467 ttcn_buffer.put_string(pad_octstr);
468}
469
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200470/////////////////////
471// DECODE
472/////////////////////
473
474/* DECODE DOWNLINK */
475
Harald Welte43e060a2017-07-30 22:38:03 +0200476RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
477{
478 RlcmacDlDataBlock ret_val;
479 TTCN_Buffer ttcn_buffer(stream);
480 int num_llc_blocks = 0;
481
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100482 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
483
Harald Welte43e060a2017-07-30 22:38:03 +0200484 /* use automatic/generated decoder for header */
485 ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
486
487 /* optional extension octets, containing LI+M+E of Llc blocks */
488 if (ret_val.mac__hdr().hdr__ext().e() == false) {
489 /* extension octet follows, i.e. optional Llc length octets */
490 while (1) {
491 /* decode one more extension octet with LlcBlocHdr inside */
492 LlcBlock lb;
Harald Welte439e5462018-03-08 23:21:17 +0100493 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Harald Welte43e060a2017-07-30 22:38:03 +0200494 ret_val.blocks()[num_llc_blocks++] = lb;
495
496 /* if E == '1'B, we can proceed further */
Harald Welte060e27a2018-03-03 20:38:19 +0100497 if (lb.hdr()().e() == true)
Harald Welte43e060a2017-07-30 22:38:03 +0200498 break;
499 }
500 }
501
502 /* RLC blocks at end */
503 if (ret_val.mac__hdr().hdr__ext().e() == true) {
504 LlcBlock lb;
505 unsigned int length = ttcn_buffer.get_read_len();
506 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
507 * fills the current RLC data block precisely or continues in the following in-sequence RLC
508 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100509 lb.hdr() = OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +0200510 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
511 ttcn_buffer.increase_pos(length);
512 ret_val.blocks()[0] = lb;
513 } else {
514 if (ret_val.blocks().is_bound()) {
515 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
Harald Welte060e27a2018-03-03 20:38:19 +0100516 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
Pau Espin Pedrolb8b1c0d2022-04-01 16:15:55 +0200517
518 /* LI[0]=0 indicates: The current LLC PDU would fit within
519 current RLC data block but the addition of the length
520 indicator octet (to indicate the LLC PDU boundary) causes the
521 LLC PDU to extend into another RLC data block */
522 if (i == 0 && length == 0)
523 length = ttcn_buffer.get_read_len();
524
Harald Welte43e060a2017-07-30 22:38:03 +0200525 if (length > ttcn_buffer.get_read_len())
526 length = ttcn_buffer.get_read_len();
Pau Espin Pedrolb8b1c0d2022-04-01 16:15:55 +0200527
Harald Welte43e060a2017-07-30 22:38:03 +0200528 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
529 ttcn_buffer.increase_pos(length);
530 }
531 }
532 }
533
534 return ret_val;
535}
536
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200537static
538EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream)
539{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100540 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200541 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100542 const struct gprs_rlc_dl_header_egprs_1 *egprs1;
543 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200544
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100545 egprs1 = static_cast<const struct gprs_rlc_dl_header_egprs_1 *>
546 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200547
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100548 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__1;
549 ret_val.tfi() = egprs1->tfi_lo << 1 | egprs1->tfi_hi << 0;
550 ret_val.rrbp() = egprs1->rrbp;
551 tmp = egprs1->es_p;
552 ret_val.esp() = BITSTRING(2, &tmp);
553 ret_val.usf() = egprs1->usf;
554 ret_val.bsn1() = egprs1->bsn1_lo << 10 | egprs1->bsn1_mid << 2 | egprs1->bsn1_hi;
555 ret_val.bsn2__offset() = egprs1->bsn2_lo << 7 | egprs1->bsn2_hi;
556 ret_val.pr() = egprs1->pr;
557 ret_val.cps() = egprs1->cps;
Pau Espin Pedrol4f9a48f2021-02-04 19:25:33 +0100558 ret_val.spb() = OMIT_VALUE;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100559
560 ttcn_buffer.increase_pos(sizeof(*egprs1));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200561 return ret_val;
562}
563
564static
565EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream)
566{
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100567 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200568 EgprsDlMacDataHeader ret_val;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100569 const struct gprs_rlc_dl_header_egprs_2 *egprs2;
570 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200571
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100572 egprs2 = static_cast<const struct gprs_rlc_dl_header_egprs_2 *>
573 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200574
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100575 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__2;
576 ret_val.tfi() = egprs2->tfi_lo << 1 | egprs2->tfi_hi << 0;
577 ret_val.rrbp() = egprs2->rrbp;
578 tmp = egprs2->es_p;
579 ret_val.esp() = BITSTRING(2, &tmp);
580 ret_val.usf() = egprs2->usf;
581 ret_val.bsn1() = egprs2->bsn1_lo << 10 | egprs2->bsn1_mid << 2 | egprs2->bsn1_hi;
582 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
583 ret_val.pr() = egprs2->pr;
584 ret_val.cps() = egprs2->cps;
Pau Espin Pedrol4f9a48f2021-02-04 19:25:33 +0100585 ret_val.spb() = OMIT_VALUE;
Pau Espin Pedrol68a7a492020-11-12 21:00:44 +0100586
587 ttcn_buffer.increase_pos(sizeof(*egprs2));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200588 return ret_val;
589}
590
591static
592EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream)
593{
594 TTCN_Buffer ttcn_buffer(stream);
595 EgprsDlMacDataHeader ret_val;
596 const struct gprs_rlc_dl_header_egprs_3 *egprs3;
597 uint8_t tmp;
598
599 egprs3 = static_cast<const struct gprs_rlc_dl_header_egprs_3 *>
600 ((const void *)ttcn_buffer.get_data());
601
602 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
603 ret_val.tfi() = egprs3->tfi_lo << 1 | egprs3->tfi_hi << 0;
604 ret_val.rrbp() = egprs3->rrbp;
605 tmp = egprs3->es_p;
606 ret_val.esp() = BITSTRING(2, &tmp);
607 ret_val.usf() = egprs3->usf;
608 ret_val.bsn1() = egprs3->bsn1_lo << 10 | egprs3->bsn1_mid << 2 | egprs3->bsn1_hi;
609 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
610 ret_val.pr() = egprs3->pr;
611 ret_val.spb() = egprs3->spb;
612 ret_val.cps() = egprs3->cps;
613
614 ttcn_buffer.increase_pos(sizeof(*egprs3));
615 return ret_val;
616}
617
618static
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100619RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200620{
621 RlcmacDlEgprsDataBlock ret_val;
622 TTCN_Buffer ttcn_buffer(stream);
623 TTCN_Buffer aligned_buffer;
624 int num_llc_blocks = 0;
625 unsigned int data_block_bits, data_block_offsets[2];
626 unsigned int num_calls;
627 const uint8_t *ti_e;
628
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100629 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
630 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200631 case CodingScheme::MCS__0:
632 case CodingScheme::MCS__1:
633 case CodingScheme::MCS__2:
634 case CodingScheme::MCS__3:
635 case CodingScheme::MCS__4:
636 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type3(stream);
637 break;
638 case CodingScheme::MCS__5:
639 case CodingScheme::MCS__6:
640 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type2(stream);
641 break;
642 case CodingScheme::MCS__7:
643 case CodingScheme::MCS__8:
644 case CodingScheme::MCS__9:
645 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream);
646 break;
647 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100648 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), false,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200649 &num_calls, &data_block_bits, data_block_offsets);
650 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
651
652 ti_e = aligned_buffer.get_read_data();
653 ret_val.fbi() = *ti_e & 0x02 ? true : false;
654 ret_val.e() = *ti_e & 0x01 ? true : false;
655 aligned_buffer.increase_pos(1);
656
657 /* optional extension octets, containing LI+E of Llc blocks */
658 if (ret_val.e() == false) {
659 /* extension octet follows, i.e. optional Llc length octets */
660 while (1) {
661 /* decode one more extension octet with LlcBlocHdr inside */
662 EgprsLlcBlock lb;
663 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
664 ret_val.blocks()[num_llc_blocks++] = lb;
665
666 /* if E == '1'B, we can proceed further */
667 if (lb.hdr()().e() == true)
668 break;
669 }
670 }
671
672 /* RLC blocks at end */
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100673 if (ret_val.e() == true) {
674 EgprsLlcBlock lb;
675 unsigned int length = aligned_buffer.get_read_len();
676 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
677 * fills the current RLC data block precisely or continues in the following in-sequence RLC
678 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100679 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100680 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
681 aligned_buffer.increase_pos(length);
682 ret_val.blocks()[0] = lb;
683 } else {
684 /* RLC blocks at end */
685 if (ret_val.blocks().is_bound()) {
686 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
687 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
688 if (length > aligned_buffer.get_read_len())
689 length = aligned_buffer.get_read_len();
690 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
691 aligned_buffer.increase_pos(length);
692 }
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200693 }
694 }
695
696 return ret_val;
697}
698
699RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
700{
701 RlcmacDlBlock ret_val;
702 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100703 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200704 unsigned char pt;
705
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100706 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200707 case CodingScheme::CS__1:
708 case CodingScheme::CS__2:
709 case CodingScheme::CS__3:
710 case CodingScheme::CS__4:
711 pt = stream[0].get_octet() >> 6;
712 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
713 ret_val.data() = dec__RlcmacDlDataBlock(stream);
714 else
715 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
716 break;
717 case CodingScheme::MCS__0:
718 case CodingScheme::MCS__1:
719 case CodingScheme::MCS__2:
720 case CodingScheme::MCS__3:
721 case CodingScheme::MCS__4:
722 case CodingScheme::MCS__5:
723 case CodingScheme::MCS__6:
724 case CodingScheme::MCS__7:
725 case CodingScheme::MCS__8:
726 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100727 ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200728 break;
729 }
730 return ret_val;
731}
732
733/* DECODE UPLINK */
734
735RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
736{
737 RlcmacUlDataBlock ret_val;
738 TTCN_Buffer ttcn_buffer(stream);
739 int num_llc_blocks = 0;
740
741 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
742 TTCN_Logger::log_event_str("==================================\n"
743 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
744 stream.log();
745 TTCN_Logger::end_event();
746
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100747 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
748
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200749 /* use automatic/generated decoder for header */
750 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
751
752 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
753 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
754 ttcn_buffer.log();
755 TTCN_Logger::end_event();
756 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
757 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
758 ret_val.log();
759 TTCN_Logger::end_event();
760
761 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
762 * optional tlli, optional pfi and LLC Blocks */
763
764 /* optional extension octets, containing LI+M+E of Llc blocks */
765 if (ret_val.mac__hdr().e() == false) {
766 /* extension octet follows, i.e. optional Llc length octets */
767 while (1) {
768 /* decode one more extension octet with LlcBlocHdr inside */
769 LlcBlock lb;
770 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
771 ret_val.blocks()[num_llc_blocks++] = lb;
772
773 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
774 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
775 ttcn_buffer.log();
776 TTCN_Logger::end_event();
777 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
778 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
779 ret_val.log();
780 TTCN_Logger::end_event();
781
782 /* if E == '1'B, we can proceed further */
783 if (lb.hdr()().e() == true)
784 break;
785 }
786 }
787
788 /* parse optional TLLI */
789 if (ret_val.mac__hdr().tlli__ind()) {
790 ret_val.tlli() = OCTETSTRING(4, ttcn_buffer.get_read_data());
791 ttcn_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200792 } else {
793 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200794 }
795 /* parse optional PFI */
796 if (ret_val.mac__hdr().pfi__ind()) {
797 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200798 } else {
799 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200800 }
801
802 /* RLC blocks at end */
803 if (ret_val.mac__hdr().e() == true) {
804 LlcBlock lb;
805 unsigned int length = ttcn_buffer.get_read_len();
806 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
807 * fills the current RLC data block precisely or continues in the following in-sequence RLC
808 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100809 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200810 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
811 ttcn_buffer.increase_pos(length);
812 ret_val.blocks()[0] = lb;
813 } else {
814 if (ret_val.blocks().is_bound()) {
815 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
816 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
817 if (length > ttcn_buffer.get_read_len())
818 length = ttcn_buffer.get_read_len();
819 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
820 ttcn_buffer.increase_pos(length);
821 }
822 }
823 }
824
825 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
826 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
827 ttcn_buffer.log();
828 TTCN_Logger::end_event();
829 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
830 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
831 ret_val.log();
832 TTCN_Logger::end_event();
833
834 return ret_val;
835}
836
837static
838EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type1(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_type2(const OCTETSTRING& stream)
849{
850 EgprsUlMacDataHeader ret_val;
851
852 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
853
854 return ret_val;
855}
856
857static
858EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
859{
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200860 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200861 EgprsUlMacDataHeader ret_val;
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200862 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
863 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200864
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200865 egprs3 = static_cast<const struct gprs_rlc_ul_header_egprs_3 *>
866 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200867
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200868 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
869 ret_val.tfi() = egprs3->tfi_lo << 2 | egprs3->tfi_hi << 0;
870 ret_val.countdown() = egprs3->cv;
871 tmp = egprs3->si;
872 ret_val.foi__si() = BITSTRING(1, &tmp);
873 tmp = egprs3->r;
874 ret_val.r__ri() = BITSTRING(1, &tmp);
875 ret_val.bsn1() = egprs3->bsn1_lo << 5 | egprs3->bsn1_hi << 0;
876 ret_val.cps() = egprs3->cps_lo << 2 | egprs3->cps_hi << 0;
877 ret_val.pfi__ind() = egprs3->pi;
878 tmp = egprs3->rsb;
879 ret_val.rsb() = BITSTRING(1, &tmp);
880 tmp = egprs3->spb;
881 ret_val.spb() = BITSTRING(2, &tmp);
882
883 ttcn_buffer.increase_pos(sizeof(*egprs3));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200884 return ret_val;
885}
886
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100887RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200888{
889 RlcmacUlEgprsDataBlock ret_val;
890 TTCN_Buffer ttcn_buffer(stream);
891 TTCN_Buffer aligned_buffer;
892 int num_llc_blocks = 0;
893 unsigned int data_block_bits, data_block_offsets[2];
894 unsigned int num_calls;
895 const uint8_t *ti_e;
896
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100897 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
898 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200899 case CodingScheme::MCS__1:
900 case CodingScheme::MCS__2:
901 case CodingScheme::MCS__3:
902 case CodingScheme::MCS__4:
903 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
904 break;
905 case CodingScheme::MCS__5:
906 case CodingScheme::MCS__6:
907 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
908 break;
909 case CodingScheme::MCS__7:
910 case CodingScheme::MCS__8:
911 case CodingScheme::MCS__9:
912 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
913 break;
914 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100915 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), true,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200916 &num_calls, &data_block_bits, data_block_offsets);
917 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
918
919 ti_e = aligned_buffer.get_read_data();
920 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
921 ret_val.e() = *ti_e & 0x01 ? true : false;
922 aligned_buffer.increase_pos(1);
923
924 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
925 * optional tlli, optional pfi and LLC Blocks */
926
927 /* optional extension octets, containing LI+M+E of Llc blocks */
928 if (ret_val.e() == false) {
929 /* extension octet follows, i.e. optional Llc length octets */
930 while (1) {
931 /* decode one more extension octet with LlcBlocHdr inside */
932 EgprsLlcBlock lb;
933 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
934 ret_val.blocks()[num_llc_blocks++] = lb;
935
936 /* if E == '1'B, we can proceed further */
937 if (lb.hdr()().e() == true)
938 break;
939 }
940 }
941
942 /* parse optional TLLI */
943 if (ret_val.tlli__ind()) {
944 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
945 aligned_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200946 } else {
947 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200948 }
949 /* parse optional PFI */
950 if (ret_val.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +0200951 ret_val.pfi().decode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200952 } else {
953 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200954 }
955
956 /* RLC blocks at end */
957 if (ret_val.e() == true) {
958 EgprsLlcBlock lb;
959 unsigned int length = aligned_buffer.get_read_len();
960 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
961 * fills the current RLC data block precisely or continues in the following in-sequence RLC
962 * data block */
Pau Espin Pedrolff7c5ba2021-02-04 18:05:09 +0100963 lb.hdr() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200964 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
965 aligned_buffer.increase_pos(length);
966 ret_val.blocks()[0] = lb;
967 } else {
968 if (ret_val.blocks().is_bound()) {
969 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
970 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
971 if (length > aligned_buffer.get_read_len())
972 length = aligned_buffer.get_read_len();
973 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
974 aligned_buffer.increase_pos(length);
975 }
976 }
977 }
978
979 return ret_val;
980}
981
982RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
983{
984 RlcmacUlBlock ret_val;
985 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100986 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200987 unsigned char pt;
988
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100989 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200990 case CodingScheme::CS__1:
991 case CodingScheme::CS__2:
992 case CodingScheme::CS__3:
993 case CodingScheme::CS__4:
994 pt = stream[0].get_octet() >> 6;
995 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
996 ret_val.data() = dec__RlcmacUlDataBlock(stream);
997 else
998 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
999 break;
1000 case CodingScheme::MCS__1:
1001 case CodingScheme::MCS__2:
1002 case CodingScheme::MCS__3:
1003 case CodingScheme::MCS__4:
1004 case CodingScheme::MCS__5:
1005 case CodingScheme::MCS__6:
1006 case CodingScheme::MCS__7:
1007 case CodingScheme::MCS__8:
1008 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +01001009 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001010 break;
1011 }
1012
1013 return ret_val;
1014}
1015
1016
1017/////////////////////
1018// ENCODE
1019/////////////////////
1020
1021/* ENCODE DOWNLINK */
1022
1023OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
1024{
1025 RlcmacDlDataBlock in = si;
1026 OCTETSTRING ret_val;
1027 TTCN_Buffer ttcn_buffer;
1028 int i;
1029
1030 /* Fix 'e' bit of initial header based on following blocks */
1031 if (!in.blocks().is_bound() ||
1032 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1033 in.mac__hdr().hdr__ext().e() = true;
1034 else
1035 in.mac__hdr().hdr__ext().e() = false;
1036
1037 /* use automatic/generated decoder for header */
1038 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1039
1040 /* Add LI octets, if any */
1041 if (in.blocks().is_bound() &&
1042 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1043 /* first write LI octets */
1044 for (i = 0; i < in.blocks().size_of(); i++) {
1045 /* fix the 'E' bit in case it is not clear */
1046 if (i < in.blocks().size_of()-1)
1047 in.blocks()[i].hdr()().e() = false;
1048 else
1049 in.blocks()[i].hdr()().e() = true;
1050 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1051 }
1052 }
1053 if (in.blocks().is_bound()) {
1054 for (i = 0; i < in.blocks().size_of(); i++) {
1055 if (!in.blocks()[i].is_bound())
1056 continue;
1057 ttcn_buffer.put_string(in.blocks()[i].payload());
1058 }
1059 }
1060
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001061 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1062
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001063 ttcn_buffer.get_string(ret_val);
1064 return ret_val;
1065}
1066
1067static
1068void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1069{
1070 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1071}
1072
1073static
1074void enc__RlcmacDlEgprsDataHeader_type2(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1075{
1076 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1077}
1078
1079static
1080void enc__RlcmacDlEgprsDataHeader_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1081{
1082 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1083}
1084
1085OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
1086{
1087 RlcmacDlEgprsDataBlock in = si;
1088 OCTETSTRING ret_val;
1089 TTCN_Buffer ttcn_buffer;
1090 int i;
1091
1092 /* Fix 'e' bit of initial header based on following blocks */
1093 if (!in.blocks().is_bound() ||
1094 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1095 in.e() = true;
1096 else
1097 in.e() = false;
1098
1099 switch (in.mac__hdr().header__type()) {
1100 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
1101 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
1102 break;
1103 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
1104 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
1105 break;
1106 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
1107 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
1108 default:
1109 break; /* TODO: error */
1110 }
1111
1112 /* Add LI octets, if any */
1113 if (in.blocks().is_bound() &&
1114 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1115 /* first write LI octets */
1116 for (i = 0; i < in.blocks().size_of(); i++) {
1117 /* fix the 'E' bit in case it is not clear */
1118 if (i < in.blocks().size_of()-1)
1119 in.blocks()[i].hdr()().e() = false;
1120 else
1121 in.blocks()[i].hdr()().e() = true;
1122 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1123 }
1124 }
1125 if (in.blocks().is_bound()) {
1126 for (i = 0; i < in.blocks().size_of(); i++) {
1127 if (!in.blocks()[i].is_bound())
1128 continue;
1129 ttcn_buffer.put_string(in.blocks()[i].payload());
1130 }
1131 }
1132
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001133 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1134
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001135 ttcn_buffer.get_string(ret_val);
1136 return ret_val;
1137}
1138
1139OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
1140{
1141 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
1142 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
1143 else if (si.ischosen(RlcmacDlBlock::ALT_data))
1144 return enc__RlcmacDlDataBlock(si.data());
1145 else
1146 return enc__RlcmacDlCtrlBlock(si.ctrl());
1147}
1148
1149/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +02001150
1151OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
1152{
1153 RlcmacUlDataBlock in = si;
1154 OCTETSTRING ret_val;
1155 TTCN_Buffer ttcn_buffer;
1156 int i;
1157
Harald Welte060e27a2018-03-03 20:38:19 +01001158 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +02001159 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +01001160 in.mac__hdr().e() = false; /* E=0: extension octet follows */
1161 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1162 /* If there's only a single block, and that block has no HDR value defined, */
1163 in.mac__hdr().e() = true; /* E=0: extension octet follows */
1164 } else {
1165 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +02001166 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +01001167 }
Harald Welte43e060a2017-07-30 22:38:03 +02001168
1169 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +02001170 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1171 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +02001172
Harald Welte060e27a2018-03-03 20:38:19 +01001173 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +02001174 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1175
Harald Welte060e27a2018-03-03 20:38:19 +01001176 if (in.mac__hdr().e() == false) {
1177 /* Add LI octets, if any */
1178 if (!in.blocks().is_bound()) {
1179 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1180 } else {
1181 for (i = 0; i < in.blocks().size_of(); i++) {
1182#if 0
1183 /* check for penultimate block */
1184 if (i == in.blocks().size_of()-2) {
1185 /* if last block has no header, no more LI */
1186 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1187 in.blocks()[i].hdr()().more() = true;
1188 } else {
1189 /* header present, we have to encode LI */
1190 in.blocks()[i].hdr()().more() = false;
1191 in.blocks()[i].hdr()().length__ind() =
1192 in.blocks()[i+1].payload().lengthof();
1193 }
1194 } else if (i < in.blocks().size_of()-2) {
1195 /* one of the first blocks, before the penultimate or last */
1196 in.blocks()[i].hdr()().e() = false; /* LI present */
1197 /* re-compute length */
1198 in.blocks()[i].hdr()().length__ind() =
1199 in.blocks()[i+1].payload().lengthof();
1200 }
1201 /* Encode LI octet if E=0 */
1202 }
1203#endif
1204 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1205 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
1206 TTCN_EncDec::CT_RAW);
1207 }
1208 }
Harald Welte43e060a2017-07-30 22:38:03 +02001209 }
1210 }
1211
1212 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +01001213 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +02001214 }
1215
1216 if (in.mac__hdr().pfi__ind()) {
1217 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1218 }
1219
1220 if (in.blocks().is_bound()) {
1221 for (i = 0; i < in.blocks().size_of(); i++) {
1222 if (!in.blocks()[i].is_bound())
1223 continue;
1224 ttcn_buffer.put_string(in.blocks()[i].payload());
1225 }
1226 }
1227
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001228 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1229
Harald Welte43e060a2017-07-30 22:38:03 +02001230 ttcn_buffer.get_string(ret_val);
1231 return ret_val;
1232}
1233
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001234static
1235void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001236{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001237 struct gprs_rlc_ul_header_egprs_1 egprs1;
1238
1239 egprs1.r = bs2uint8(si.r__ri());
1240 egprs1.si = bs2uint8(si.foi__si());
1241 egprs1.cv = si.countdown();
1242 egprs1.tfi_hi = si.tfi() >> 0;
1243 egprs1.tfi_lo = si.tfi() >> 2;
1244 egprs1.bsn1_hi = si.bsn1() >> 0;
1245 egprs1.bsn1_lo = si.bsn1() >> 5;
1246 egprs1.bsn2_hi = si.bsn2__offset() >> 0;
1247 egprs1.bsn2_lo = si.bsn2__offset() >> 2;
1248 egprs1.cps = si.cps();
1249 egprs1.rsb = bs2uint8(si.rsb());
1250 egprs1.pi = si.pfi__ind();
1251 egprs1.spare_hi = 0;
1252 egprs1.spare_lo = 0;
1253 egprs1.dummy = 0;
1254
1255 ttcn_buffer.put_s(sizeof(egprs1), (const unsigned char *)&egprs1);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001256}
Harald Welte43e060a2017-07-30 22:38:03 +02001257
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001258static
1259void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1260{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001261 struct gprs_rlc_ul_header_egprs_2 egprs2;
1262
1263 egprs2.r = bs2uint8(si.r__ri());
1264 egprs2.si = bs2uint8(si.foi__si());
1265 egprs2.cv = si.countdown();
1266 egprs2.tfi_hi = si.tfi() >> 0;
1267 egprs2.tfi_lo = si.tfi() >> 2;
1268 egprs2.bsn1_hi = si.bsn1() >> 0;
1269 egprs2.bsn1_lo = si.bsn1() >> 5;
1270 egprs2.cps_hi = si.cps() >> 0;
1271 egprs2.cps_lo = si.cps() >> 2;
1272 egprs2.rsb = bs2uint8(si.rsb());
1273 egprs2.pi = si.pfi__ind();
1274 egprs2.spare_hi = 0;
1275 egprs2.spare_lo = 0;
1276 egprs2.dummy = 0;
1277
1278 ttcn_buffer.put_s(sizeof(egprs2), (const unsigned char *)&egprs2);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001279}
Harald Welte43e060a2017-07-30 22:38:03 +02001280
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001281static
1282void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1283{
1284 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001285
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001286 egprs3.r = bs2uint8(si.r__ri());
1287 egprs3.si = bs2uint8(si.foi__si());
1288 egprs3.cv = si.countdown();
1289 egprs3.tfi_hi = si.tfi() >> 0;
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001290 egprs3.tfi_lo = si.tfi() >> 2;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001291 egprs3.bsn1_hi = si.bsn1() >> 0;
1292 egprs3.bsn1_lo = si.bsn1() >> 5;
1293 egprs3.cps_hi = si.cps() >> 0;
1294 egprs3.cps_lo = si.cps() >> 2;
1295 egprs3.spb = bs2uint8(si.spb());
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001296 egprs3.rsb = bs2uint8(si.rsb());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001297 egprs3.pi = si.pfi__ind();
1298 egprs3.spare = 0;
1299 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001300
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001301 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1302}
Harald Welte43e060a2017-07-30 22:38:03 +02001303
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001304OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1305{
1306 RlcmacUlEgprsDataBlock in = si;
1307 OCTETSTRING ret_val;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001308 TTCN_Buffer ttcn_buffer, aligned_buffer;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001309 int i;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001310 unsigned int data_block_bits, data_block_offsets[2];
1311 unsigned int num_calls;
1312 CodingScheme mcs;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001313
1314 mcs = RLCMAC__Templates::f__rlcmac__cps__htype__to__mcs(in.mac__hdr().cps(), in.mac__hdr().header__type());
1315 //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 +02001316
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001317 if (!in.blocks().is_bound()) {
1318 /* we don't have nay blocks: Add length value (zero) */
1319 in.e() = false; /* E=0: extension octet follows */
1320 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1321 /* If there's only a single block, and that block has no HDR value defined, */
1322 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001323 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001324 /* Length value */
1325 in.e() = false;
1326 }
1327
1328 /* Fix other presence indications */
1329 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1330 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1331
1332 switch (in.mac__hdr().header__type()) {
1333 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001334 enc__RlcmacUlEgprsDataHeader_type1(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001335 break;
1336 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001337 enc__RlcmacUlEgprsDataHeader_type2(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001338 break;
1339 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001340 enc__RlcmacUlEgprsDataHeader_type3(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001341 default:
1342 break; /* TODO: error */
1343 }
1344
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001345 /* Put first TI + E byte */
Pau Espin Pedrol563bcd62020-11-06 19:51:23 +01001346 aligned_buffer.put_c((in.tlli__ind() & 0x01) << 1 | (in.e() & 0x01) << 0);
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001347 //printbuffer("After encoding first byte", aligned_buffer);
1348
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001349 if (in.e() == false) {
1350 /* Add LI octets, if any */
1351 if (!in.blocks().is_bound()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001352 aligned_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001353 } else {
1354 for (i = 0; i < in.blocks().size_of(); i++) {
1355#if 0
1356 /* check for penultimate block */
1357 if (i == in.blocks().size_of()-2) {
1358 /* if last block has no header, no more LI */
1359 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1360 in.blocks()[i].hdr()().more() = true;
1361 } else {
1362 /* header present, we have to encode LI */
1363 in.blocks()[i].hdr()().more() = false;
1364 in.blocks()[i].hdr()().length__ind() =
1365 in.blocks()[i+1].payload().lengthof();
1366 }
1367 } else if (i < in.blocks().size_of()-2) {
1368 /* one of the first blocks, before the penultimate or last */
1369 in.blocks()[i].hdr()().e() = false; /* LI present */
1370 /* re-compute length */
1371 in.blocks()[i].hdr()().length__ind() =
1372 in.blocks()[i+1].payload().lengthof();
1373 }
1374 /* Encode LI octet if E=0 */
1375 }
1376#endif
1377 if (in.blocks()[i].hdr() != OMIT_VALUE) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001378 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, aligned_buffer,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001379 TTCN_EncDec::CT_RAW);
1380 }
Harald Welte43e060a2017-07-30 22:38:03 +02001381 }
1382 }
1383 }
1384
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001385
1386
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001387 if (in.tlli__ind()) {
Pau Espin Pedrola05b2bc2020-11-06 20:38:21 +01001388 /* The TLLI is encoded in little endian for EGPRS (see
1389 * TS 44.060, figure 10.3a.2.1, note 2) */
1390 OCTETSTRING tlli = in.tlli();
1391 aligned_buffer.put_c(tlli[3].get_octet());
1392 aligned_buffer.put_c(tlli[2].get_octet());
1393 aligned_buffer.put_c(tlli[1].get_octet());
1394 aligned_buffer.put_c(tlli[0].get_octet());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001395 }
Harald Welte43e060a2017-07-30 22:38:03 +02001396
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001397 if (in.mac__hdr().pfi__ind()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001398 in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001399 }
1400
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001401 //printbuffer("Before encoding EgprsLlc payload", aligned_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001402 if (in.blocks().is_bound()) {
1403 for (i = 0; i < in.blocks().size_of(); i++) {
1404 if (!in.blocks()[i].is_bound())
1405 continue;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001406 aligned_buffer.put_string(in.blocks()[i].payload());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001407 }
1408 }
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001409 //printbuffer("After encoding EgprsLlc payload", aligned_buffer);
1410
1411 setup_rlc_mac_priv(mcs, in.mac__hdr().header__type(), true,
1412 &num_calls, &data_block_bits, data_block_offsets);
1413 //printbuffer("before merging data block", ttcn_buffer);
1414 put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer);
1415 //printbuffer("after merging data block", ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001416
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001417 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1418
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001419 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001420 return ret_val;
1421}
1422
Harald Welte78a1af62017-07-31 17:33:56 +02001423OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1424{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001425 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1426 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1427 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001428 return enc__RlcmacUlDataBlock(si.data());
1429 else
1430 return enc__RlcmacUlCtrlBlock(si.ctrl());
1431}
1432
Harald Welte43e060a2017-07-30 22:38:03 +02001433} // namespace