blob: f4735e9f24f748577c6d16708fd1adb215d885e4 [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"
5#include "GSM_Types.hh"
6/* Decoding of TS 44.060 GPRS RLC/MAC blocks, portions requiring manual functions
7 * beyond what TITAN RAW coder can handle internally.
8 *
9 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
Harald Welte34b5a952019-05-27 11:54:11 +020010 * All rights reserved.
11 *
12 * Released under the terms of GNU General Public License, Version 2 or
13 * (at your option) any later version.
14 *
15 * SPDX-License-Identifier: GPL-2.0-or-later
Harald Welte43e060a2017-07-30 22:38:03 +020016 */
17
18namespace RLCMAC__Types {
19
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020020/////////////////////
21// INTENRAL HELPERS
22/////////////////////
Harald Welte43e060a2017-07-30 22:38:03 +020023
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020024/* TS 04.60 10.3a.4.1.1 */
25struct gprs_rlc_ul_header_egprs_1 {
26#if __BYTE_ORDER == __LITTLE_ENDIAN
27 uint8_t r:1,
28 si:1,
29 cv:4,
30 tfi_hi:2;
31 uint8_t tfi_lo:3,
32 bsn1_hi:5;
33 uint8_t bsn1_lo:6,
34 bsn2_hi:2;
35 uint8_t bsn2_lo:8;
36 uint8_t cps:5,
37 rsb:1,
38 pi:1,
39 spare_hi:1;
40 uint8_t spare_lo:6,
41 dummy:2;
42#else
43/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
44 uint8_t tfi_hi:2, cv:4, si:1, r:1;
45 uint8_t bsn1_hi:5, tfi_lo:3;
46 uint8_t bsn2_hi:2, bsn1_lo:6;
47 uint8_t bsn2_lo:8;
48 uint8_t spare_hi:1, pi:1, rsb:1, cps:5;
49 uint8_t dummy:2, spare_lo:6;
50#endif
51} __attribute__ ((packed));
Harald Welte43e060a2017-07-30 22:38:03 +020052
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020053/* TS 04.60 10.3a.4.2.1 */
54struct gprs_rlc_ul_header_egprs_2 {
55#if __BYTE_ORDER == __LITTLE_ENDIAN
56 uint8_t r:1,
57 si:1,
58 cv:4,
59 tfi_hi:2;
60 uint8_t tfi_lo:3,
61 bsn1_hi:5;
62 uint8_t bsn1_lo:6,
63 cps_hi:2;
64 uint8_t cps_lo:1,
65 rsb:1,
66 pi:1,
67 spare_hi:5;
68 uint8_t spare_lo:5,
69 dummy:3;
70#else
71/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
72 uint8_t tfi_hi:2, cv:4, si:1, r:1;
73 uint8_t bsn1_hi:5, tfi_lo:3;
74 uint8_t cps_hi:2, bsn1_lo:6;
75 uint8_t spare_hi:5, pi:1, rsb:1, cps_lo:1;
76 uint8_t dummy:3, spare_lo:5;
77#endif
78} __attribute__ ((packed));
Harald Welte43e060a2017-07-30 22:38:03 +020079
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020080/* TS 04.60 10.3a.4.3.1 */
81struct gprs_rlc_ul_header_egprs_3 {
82#if __BYTE_ORDER == __LITTLE_ENDIAN
83 uint8_t r:1,
84 si:1,
85 cv:4,
86 tfi_hi:2;
87 uint8_t tfi_lo:3,
88 bsn1_hi:5;
89 uint8_t bsn1_lo:6,
90 cps_hi:2;
91 uint8_t cps_lo:2,
92 spb:2,
93 rsb:1,
94 pi:1,
95 spare:1,
96 dummy:1;
97#else
98/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
99 uint8_t tfi_hi:2, cv:4, si:1, r:1;
100 uint8_t bsn1_hi:5, tfi_lo:3;
101 uint8_t cps_hi:2, bsn1_lo:6;
102 uint8_t dummy:1, spare:1, pi:1, rsb:1, spb:2, cps_lo:2;
103#endif
104} __attribute__ ((packed));
105
106struct gprs_rlc_dl_header_egprs_1 {
107#if __BYTE_ORDER == __LITTLE_ENDIAN
108 uint8_t usf:3,
109 es_p:2,
110 rrbp:2,
111 tfi_hi:1;
112 uint8_t tfi_lo:4,
113 pr:2,
114 bsn1_hi:2;
115 uint8_t bsn1_mid:8;
116 uint8_t bsn1_lo:1,
117 bsn2_hi:7;
118 uint8_t bsn2_lo:3,
119 cps:5;
120#else
121/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
122 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
123 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
124 uint8_t bsn1_mid:8;
125 uint8_t bsn2_hi:7, bsn1_lo:1;
126 uint8_t cps:5, bsn2_lo:3;
127#endif
128} __attribute__ ((packed));
129
130struct gprs_rlc_dl_header_egprs_2 {
131#if __BYTE_ORDER == __LITTLE_ENDIAN
132 uint8_t usf:3,
133 es_p:2,
134 rrbp:2,
135 tfi_hi:1;
136 uint8_t tfi_lo:4,
137 pr:2,
138 bsn1_hi:2;
139 uint8_t bsn1_mid:8;
140 uint8_t bsn1_lo:1,
141 cps:3,
142 dummy:4;
143#else
144/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
145 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
146 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
147 uint8_t bsn1_mid:8;
148 uint8_t dummy:4, cps:3, bsn1_lo:1;
149#endif
150} __attribute__ ((packed));
151
152struct gprs_rlc_dl_header_egprs_3 {
153#if __BYTE_ORDER == __LITTLE_ENDIAN
154 uint8_t usf:3,
155 es_p:2,
156 rrbp:2,
157 tfi_hi:1;
158 uint8_t tfi_lo:4,
159 pr:2,
160 bsn1_hi:2;
161 uint8_t bsn1_mid:8;
162 uint8_t bsn1_lo:1,
163 cps:4,
164 spb:2,
165 dummy:1;
166#else
167/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
168 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
169 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
170 uint8_t bsn1_mid:8;
171 uint8_t dummy:1, spb:2, cps:4, bsn1_lo:1;
172#endif
173} __attribute__ ((packed));
174
175static CodingScheme::enum_type payload_len_2_coding_scheme(size_t payload_len) {
176 switch (payload_len) {
177 case 23:
178 return CodingScheme::CS__1;
179 case 34:
180 return CodingScheme::CS__2;
181 case 40:
182 return CodingScheme::CS__3;
183 case 54:
184 return CodingScheme::CS__4;
185 case 27:
186 return CodingScheme::MCS__1;
187 case 33:
188 return CodingScheme::MCS__2;
189 case 42:
190 return CodingScheme::MCS__3;
191 case 49:
192 return CodingScheme::MCS__4;
193 case 61:
194 return CodingScheme::MCS__5;
195 case 79:
196 return CodingScheme::MCS__6;
197 case 119:
198 return CodingScheme::MCS__7;
199 case 142:
200 return CodingScheme::MCS__8;
201 case 155:
202 return CodingScheme::MCS__9;
203 default:
204 return CodingScheme::CS__1;
Harald Welte43e060a2017-07-30 22:38:03 +0200205 }
Harald Welte43e060a2017-07-30 22:38:03 +0200206}
207
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200208static unsigned int coding_scheme_2_data_block_len(CodingScheme::enum_type mcs) {
209 switch (mcs) {
210 case CodingScheme::MCS__0:
211 return 0;
212 case CodingScheme::MCS__1:
213 return 22;
214 case CodingScheme::MCS__2:
215 return 28;
216 case CodingScheme::MCS__3:
217 return 37;
218 case CodingScheme::MCS__4:
219 return 44;
220 case CodingScheme::MCS__5:
221 return 56;
222 case CodingScheme::MCS__6:
223 return 74;
224 case CodingScheme::MCS__7:
225 return 56;
226 case CodingScheme::MCS__8:
227 return 68;
228 case CodingScheme::MCS__9:
229 return 74;
230 default:
231 return 22; /* MCS1*/
232 }
233}
234
235static uint8_t bs2uint8(const BITSTRING& bs)
236{
237 int len = bs.lengthof();
238 int i;
239 uint8_t res = 0;
240 for (i = 0; i < len; i++) {
241 res = res << 1;
242 res |= (bs[i].get_bit() ? 1 : 0);
243 }
244 return res;
245}
246
247/* determine the number of rlc data blocks and their size / offsets */
248static void
249setup_rlc_mac_priv(CodingScheme::enum_type mcs, EgprsHeaderType::enum_type hdrtype, boolean is_uplink,
250 unsigned int *n_calls, unsigned int *data_block_bits, unsigned int *data_block_offsets)
251{
252 unsigned int nc, dbl = 0, dbo[2] = {0,0};
253
254 dbl = coding_scheme_2_data_block_len(mcs);
255
256 switch (hdrtype) {
257 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
258 nc = 3;
259 dbo[0] = is_uplink ? 5*8 + 6 : 5*8 + 0;
260 dbo[1] = dbo[0] + dbl * 8 + 2;
261 break;
262 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
263 nc = 2;
264 dbo[0] = is_uplink ? 4*8 + 5 : 3*8 + 4;
265 break;
266 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
267 nc = 2;
268 dbo[0] = 3*8 + 7;
269 break;
270 default:
271 nc = 1;
272 break;
273 }
274
275 *n_calls = nc;
276 *data_block_bits = dbl * 8 + 2;
277 data_block_offsets[0] = dbo[0];
278 data_block_offsets[1] = dbo[1];
279}
280
281/* bit-shift the entire 'src' of length 'length_bytes' by 'offset_bits'
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +0200282 * and store the result to caller-allocated 'buffer'. The shifting is
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200283 * done lsb-first. */
284static void clone_aligned_buffer_lsbf(unsigned int offset_bits, unsigned int length_bytes,
285 const uint8_t *src, uint8_t *buffer)
286{
287 unsigned int hdr_bytes;
288 unsigned int extra_bits;
289 unsigned int i;
290
291 uint8_t c, last_c;
292 uint8_t *dst;
293
294 hdr_bytes = offset_bits / 8;
295 extra_bits = offset_bits % 8;
296
297 fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
298
299 if (extra_bits == 0) {
300 /* It is aligned already */
301 memcpy(buffer, src + hdr_bytes, length_bytes);
302 return;
303 }
304
305 dst = buffer;
306 src = src + hdr_bytes;
307 last_c = *(src++);
308
309 for (i = 0; i < length_bytes; i++) {
310 c = src[i];
311 *(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits));
312 last_c = c;
313 }
314}
315
316/* obtain an (aligned) EGPRS data block with given bit-offset and
317 * bit-length from the parent buffer */
318static void get_egprs_data_block(const TTCN_Buffer& orig_ttcn_buffer, unsigned int offset_bits,
319 unsigned int length_bits, TTCN_Buffer& dst_ttcn_buffer)
320{
321 const unsigned int initial_spare_bits = 6;
322 unsigned char *aligned_buf = NULL;
323 size_t min_src_length_bytes = (offset_bits + length_bits + 7) / 8;
324 size_t length_bytes = (initial_spare_bits + length_bits + 7) / 8;
325 size_t accepted_len = length_bytes;
326
327 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());
328 dst_ttcn_buffer.get_end(aligned_buf, accepted_len);
329 fprintf(stderr, "RLMAC: For dst ptr=%p with length=%zu\n", aligned_buf, accepted_len);
330 if (accepted_len < length_bytes) {
331 fprintf(stderr, "RLMAC: ERROR! asked for %zu bytes but got %zu\n", length_bytes, accepted_len);
332 }
333
334 /* Copy the data out of the tvb to an aligned buffer */
335 clone_aligned_buffer_lsbf(
336 offset_bits - initial_spare_bits, length_bytes,
337 orig_ttcn_buffer.get_data(),
338 aligned_buf);
339
340 fprintf(stderr, "RLMAC: clone_aligned_buffer_lsbf success\n");
341
342 /* clear spare bits and move block header bits to the right */
343 aligned_buf[0] = aligned_buf[0] >> initial_spare_bits;
344
345 dst_ttcn_buffer.increase_length(length_bytes);
346}
347
348
349/////////////////////
350// DECODE
351/////////////////////
352
353/* DECODE DOWNLINK */
354
Harald Welte43e060a2017-07-30 22:38:03 +0200355RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
356{
357 RlcmacDlDataBlock ret_val;
358 TTCN_Buffer ttcn_buffer(stream);
359 int num_llc_blocks = 0;
360
361 /* use automatic/generated decoder for header */
362 ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
363
364 /* optional extension octets, containing LI+M+E of Llc blocks */
365 if (ret_val.mac__hdr().hdr__ext().e() == false) {
366 /* extension octet follows, i.e. optional Llc length octets */
367 while (1) {
368 /* decode one more extension octet with LlcBlocHdr inside */
369 LlcBlock lb;
Harald Welte439e5462018-03-08 23:21:17 +0100370 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Harald Welte43e060a2017-07-30 22:38:03 +0200371 ret_val.blocks()[num_llc_blocks++] = lb;
372
373 /* if E == '1'B, we can proceed further */
Harald Welte060e27a2018-03-03 20:38:19 +0100374 if (lb.hdr()().e() == true)
Harald Welte43e060a2017-07-30 22:38:03 +0200375 break;
376 }
377 }
378
379 /* RLC blocks at end */
380 if (ret_val.mac__hdr().hdr__ext().e() == true) {
381 LlcBlock lb;
382 unsigned int length = ttcn_buffer.get_read_len();
383 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
384 * fills the current RLC data block precisely or continues in the following in-sequence RLC
385 * data block */
386 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
387 ttcn_buffer.increase_pos(length);
388 ret_val.blocks()[0] = lb;
389 } else {
390 if (ret_val.blocks().is_bound()) {
391 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
Harald Welte060e27a2018-03-03 20:38:19 +0100392 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
Harald Welte43e060a2017-07-30 22:38:03 +0200393 if (length > ttcn_buffer.get_read_len())
394 length = ttcn_buffer.get_read_len();
395 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
396 ttcn_buffer.increase_pos(length);
397 }
398 }
399 }
400
401 return ret_val;
402}
403
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200404static
405EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream)
406{
407 EgprsDlMacDataHeader ret_val;
408
409 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
410
411 return ret_val;
412}
413
414static
415EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream)
416{
417 EgprsDlMacDataHeader ret_val;
418
419 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
420
421 return ret_val;
422}
423
424static
425EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream)
426{
427 TTCN_Buffer ttcn_buffer(stream);
428 EgprsDlMacDataHeader ret_val;
429 const struct gprs_rlc_dl_header_egprs_3 *egprs3;
430 uint8_t tmp;
431
432 egprs3 = static_cast<const struct gprs_rlc_dl_header_egprs_3 *>
433 ((const void *)ttcn_buffer.get_data());
434
435 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
436 ret_val.tfi() = egprs3->tfi_lo << 1 | egprs3->tfi_hi << 0;
437 ret_val.rrbp() = egprs3->rrbp;
438 tmp = egprs3->es_p;
439 ret_val.esp() = BITSTRING(2, &tmp);
440 ret_val.usf() = egprs3->usf;
441 ret_val.bsn1() = egprs3->bsn1_lo << 10 | egprs3->bsn1_mid << 2 | egprs3->bsn1_hi;
442 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
443 ret_val.pr() = egprs3->pr;
444 ret_val.spb() = egprs3->spb;
445 ret_val.cps() = egprs3->cps;
446
447 ttcn_buffer.increase_pos(sizeof(*egprs3));
448 return ret_val;
449}
450
451static
452RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs)
453{
454 RlcmacDlEgprsDataBlock ret_val;
455 TTCN_Buffer ttcn_buffer(stream);
456 TTCN_Buffer aligned_buffer;
457 int num_llc_blocks = 0;
458 unsigned int data_block_bits, data_block_offsets[2];
459 unsigned int num_calls;
460 const uint8_t *ti_e;
461
462 switch (mcs) {
463 case CodingScheme::MCS__0:
464 case CodingScheme::MCS__1:
465 case CodingScheme::MCS__2:
466 case CodingScheme::MCS__3:
467 case CodingScheme::MCS__4:
468 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type3(stream);
469 break;
470 case CodingScheme::MCS__5:
471 case CodingScheme::MCS__6:
472 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type2(stream);
473 break;
474 case CodingScheme::MCS__7:
475 case CodingScheme::MCS__8:
476 case CodingScheme::MCS__9:
477 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream);
478 break;
479 }
480 setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), false,
481 &num_calls, &data_block_bits, data_block_offsets);
482 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
483
484 ti_e = aligned_buffer.get_read_data();
485 ret_val.fbi() = *ti_e & 0x02 ? true : false;
486 ret_val.e() = *ti_e & 0x01 ? true : false;
487 aligned_buffer.increase_pos(1);
488
489 /* optional extension octets, containing LI+E of Llc blocks */
490 if (ret_val.e() == false) {
491 /* extension octet follows, i.e. optional Llc length octets */
492 while (1) {
493 /* decode one more extension octet with LlcBlocHdr inside */
494 EgprsLlcBlock lb;
495 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
496 ret_val.blocks()[num_llc_blocks++] = lb;
497
498 /* if E == '1'B, we can proceed further */
499 if (lb.hdr()().e() == true)
500 break;
501 }
502 }
503
504 /* RLC blocks at end */
505 if (ret_val.blocks().is_bound()) {
506 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
507 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
508 if (length > aligned_buffer.get_read_len())
509 length = aligned_buffer.get_read_len();
510 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
511 aligned_buffer.increase_pos(length);
512 }
513 }
514
515 return ret_val;
516}
517
518RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
519{
520 RlcmacDlBlock ret_val;
521 size_t stream_len = stream.lengthof();
522 CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len);
523 unsigned char pt;
524
525 switch (mcs) {
526 case CodingScheme::CS__1:
527 case CodingScheme::CS__2:
528 case CodingScheme::CS__3:
529 case CodingScheme::CS__4:
530 pt = stream[0].get_octet() >> 6;
531 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
532 ret_val.data() = dec__RlcmacDlDataBlock(stream);
533 else
534 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
535 break;
536 case CodingScheme::MCS__0:
537 case CodingScheme::MCS__1:
538 case CodingScheme::MCS__2:
539 case CodingScheme::MCS__3:
540 case CodingScheme::MCS__4:
541 case CodingScheme::MCS__5:
542 case CodingScheme::MCS__6:
543 case CodingScheme::MCS__7:
544 case CodingScheme::MCS__8:
545 case CodingScheme::MCS__9:
546 ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream, mcs);
547 break;
548 }
549 return ret_val;
550}
551
552/* DECODE UPLINK */
553
554RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
555{
556 RlcmacUlDataBlock ret_val;
557 TTCN_Buffer ttcn_buffer(stream);
558 int num_llc_blocks = 0;
559
560 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
561 TTCN_Logger::log_event_str("==================================\n"
562 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
563 stream.log();
564 TTCN_Logger::end_event();
565
566 /* use automatic/generated decoder for header */
567 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
568
569 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
570 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
571 ttcn_buffer.log();
572 TTCN_Logger::end_event();
573 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
574 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
575 ret_val.log();
576 TTCN_Logger::end_event();
577
578 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
579 * optional tlli, optional pfi and LLC Blocks */
580
581 /* optional extension octets, containing LI+M+E of Llc blocks */
582 if (ret_val.mac__hdr().e() == false) {
583 /* extension octet follows, i.e. optional Llc length octets */
584 while (1) {
585 /* decode one more extension octet with LlcBlocHdr inside */
586 LlcBlock lb;
587 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
588 ret_val.blocks()[num_llc_blocks++] = lb;
589
590 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
591 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
592 ttcn_buffer.log();
593 TTCN_Logger::end_event();
594 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
595 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
596 ret_val.log();
597 TTCN_Logger::end_event();
598
599 /* if E == '1'B, we can proceed further */
600 if (lb.hdr()().e() == true)
601 break;
602 }
603 }
604
605 /* parse optional TLLI */
606 if (ret_val.mac__hdr().tlli__ind()) {
607 ret_val.tlli() = OCTETSTRING(4, ttcn_buffer.get_read_data());
608 ttcn_buffer.increase_pos(4);
609 }
610 /* parse optional PFI */
611 if (ret_val.mac__hdr().pfi__ind()) {
612 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
613 }
614
615 /* RLC blocks at end */
616 if (ret_val.mac__hdr().e() == true) {
617 LlcBlock lb;
618 unsigned int length = ttcn_buffer.get_read_len();
619 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
620 * fills the current RLC data block precisely or continues in the following in-sequence RLC
621 * data block */
622 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
623 ttcn_buffer.increase_pos(length);
624 ret_val.blocks()[0] = lb;
625 } else {
626 if (ret_val.blocks().is_bound()) {
627 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
628 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
629 if (length > ttcn_buffer.get_read_len())
630 length = ttcn_buffer.get_read_len();
631 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
632 ttcn_buffer.increase_pos(length);
633 }
634 }
635 }
636
637 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
638 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
639 ttcn_buffer.log();
640 TTCN_Logger::end_event();
641 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
642 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
643 ret_val.log();
644 TTCN_Logger::end_event();
645
646 return ret_val;
647}
648
649static
650EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type1(const OCTETSTRING& stream)
651{
652 EgprsUlMacDataHeader ret_val;
653
654 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
655
656 return ret_val;
657}
658
659static
660EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type2(const OCTETSTRING& stream)
661{
662 EgprsUlMacDataHeader ret_val;
663
664 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
665
666 return ret_val;
667}
668
669static
670EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
671{
672 EgprsUlMacDataHeader ret_val;
673
674 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
675
676 return ret_val;
677}
678
679RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs)
680{
681 RlcmacUlEgprsDataBlock ret_val;
682 TTCN_Buffer ttcn_buffer(stream);
683 TTCN_Buffer aligned_buffer;
684 int num_llc_blocks = 0;
685 unsigned int data_block_bits, data_block_offsets[2];
686 unsigned int num_calls;
687 const uint8_t *ti_e;
688
689 switch (mcs) {
690 case CodingScheme::MCS__1:
691 case CodingScheme::MCS__2:
692 case CodingScheme::MCS__3:
693 case CodingScheme::MCS__4:
694 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
695 break;
696 case CodingScheme::MCS__5:
697 case CodingScheme::MCS__6:
698 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
699 break;
700 case CodingScheme::MCS__7:
701 case CodingScheme::MCS__8:
702 case CodingScheme::MCS__9:
703 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
704 break;
705 }
706 setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), true,
707 &num_calls, &data_block_bits, data_block_offsets);
708 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
709
710 ti_e = aligned_buffer.get_read_data();
711 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
712 ret_val.e() = *ti_e & 0x01 ? true : false;
713 aligned_buffer.increase_pos(1);
714
715 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
716 * optional tlli, optional pfi and LLC Blocks */
717
718 /* optional extension octets, containing LI+M+E of Llc blocks */
719 if (ret_val.e() == false) {
720 /* extension octet follows, i.e. optional Llc length octets */
721 while (1) {
722 /* decode one more extension octet with LlcBlocHdr inside */
723 EgprsLlcBlock lb;
724 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
725 ret_val.blocks()[num_llc_blocks++] = lb;
726
727 /* if E == '1'B, we can proceed further */
728 if (lb.hdr()().e() == true)
729 break;
730 }
731 }
732
733 /* parse optional TLLI */
734 if (ret_val.tlli__ind()) {
735 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
736 aligned_buffer.increase_pos(4);
737 }
738 /* parse optional PFI */
739 if (ret_val.mac__hdr().pfi__ind()) {
740 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
741 }
742
743 /* RLC blocks at end */
744 if (ret_val.e() == true) {
745 EgprsLlcBlock lb;
746 unsigned int length = aligned_buffer.get_read_len();
747 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
748 * fills the current RLC data block precisely or continues in the following in-sequence RLC
749 * data block */
750 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
751 aligned_buffer.increase_pos(length);
752 ret_val.blocks()[0] = lb;
753 } else {
754 if (ret_val.blocks().is_bound()) {
755 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
756 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
757 if (length > aligned_buffer.get_read_len())
758 length = aligned_buffer.get_read_len();
759 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
760 aligned_buffer.increase_pos(length);
761 }
762 }
763 }
764
765 return ret_val;
766}
767
768RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
769{
770 RlcmacUlBlock ret_val;
771 size_t stream_len = stream.lengthof();
772 CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len);
773 unsigned char pt;
774
775 switch (mcs) {
776 case CodingScheme::CS__1:
777 case CodingScheme::CS__2:
778 case CodingScheme::CS__3:
779 case CodingScheme::CS__4:
780 pt = stream[0].get_octet() >> 6;
781 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
782 ret_val.data() = dec__RlcmacUlDataBlock(stream);
783 else
784 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
785 break;
786 case CodingScheme::MCS__1:
787 case CodingScheme::MCS__2:
788 case CodingScheme::MCS__3:
789 case CodingScheme::MCS__4:
790 case CodingScheme::MCS__5:
791 case CodingScheme::MCS__6:
792 case CodingScheme::MCS__7:
793 case CodingScheme::MCS__8:
794 case CodingScheme::MCS__9:
795 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream, mcs);
796 break;
797 }
798
799 return ret_val;
800}
801
802
803/////////////////////
804// ENCODE
805/////////////////////
806
807/* ENCODE DOWNLINK */
808
809OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
810{
811 RlcmacDlDataBlock in = si;
812 OCTETSTRING ret_val;
813 TTCN_Buffer ttcn_buffer;
814 int i;
815
816 /* Fix 'e' bit of initial header based on following blocks */
817 if (!in.blocks().is_bound() ||
818 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
819 in.mac__hdr().hdr__ext().e() = true;
820 else
821 in.mac__hdr().hdr__ext().e() = false;
822
823 /* use automatic/generated decoder for header */
824 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
825
826 /* Add LI octets, if any */
827 if (in.blocks().is_bound() &&
828 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
829 /* first write LI octets */
830 for (i = 0; i < in.blocks().size_of(); i++) {
831 /* fix the 'E' bit in case it is not clear */
832 if (i < in.blocks().size_of()-1)
833 in.blocks()[i].hdr()().e() = false;
834 else
835 in.blocks()[i].hdr()().e() = true;
836 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
837 }
838 }
839 if (in.blocks().is_bound()) {
840 for (i = 0; i < in.blocks().size_of(); i++) {
841 if (!in.blocks()[i].is_bound())
842 continue;
843 ttcn_buffer.put_string(in.blocks()[i].payload());
844 }
845 }
846
847 ttcn_buffer.get_string(ret_val);
848 return ret_val;
849}
850
851static
852void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
853{
854 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
855}
856
857static
858void enc__RlcmacDlEgprsDataHeader_type2(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
859{
860 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
861}
862
863static
864void enc__RlcmacDlEgprsDataHeader_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
865{
866 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
867}
868
869OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
870{
871 RlcmacDlEgprsDataBlock in = si;
872 OCTETSTRING ret_val;
873 TTCN_Buffer ttcn_buffer;
874 int i;
875
876 /* Fix 'e' bit of initial header based on following blocks */
877 if (!in.blocks().is_bound() ||
878 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
879 in.e() = true;
880 else
881 in.e() = false;
882
883 switch (in.mac__hdr().header__type()) {
884 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
885 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
886 break;
887 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
888 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
889 break;
890 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
891 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
892 default:
893 break; /* TODO: error */
894 }
895
896 /* Add LI octets, if any */
897 if (in.blocks().is_bound() &&
898 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
899 /* first write LI octets */
900 for (i = 0; i < in.blocks().size_of(); i++) {
901 /* fix the 'E' bit in case it is not clear */
902 if (i < in.blocks().size_of()-1)
903 in.blocks()[i].hdr()().e() = false;
904 else
905 in.blocks()[i].hdr()().e() = true;
906 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
907 }
908 }
909 if (in.blocks().is_bound()) {
910 for (i = 0; i < in.blocks().size_of(); i++) {
911 if (!in.blocks()[i].is_bound())
912 continue;
913 ttcn_buffer.put_string(in.blocks()[i].payload());
914 }
915 }
916
917 ttcn_buffer.get_string(ret_val);
918 return ret_val;
919}
920
921OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
922{
923 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
924 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
925 else if (si.ischosen(RlcmacDlBlock::ALT_data))
926 return enc__RlcmacDlDataBlock(si.data());
927 else
928 return enc__RlcmacDlCtrlBlock(si.ctrl());
929}
930
931/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +0200932
933OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
934{
935 RlcmacUlDataBlock in = si;
936 OCTETSTRING ret_val;
937 TTCN_Buffer ttcn_buffer;
938 int i;
939
Harald Welte060e27a2018-03-03 20:38:19 +0100940 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +0200941 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +0100942 in.mac__hdr().e() = false; /* E=0: extension octet follows */
943 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
944 /* If there's only a single block, and that block has no HDR value defined, */
945 in.mac__hdr().e() = true; /* E=0: extension octet follows */
946 } else {
947 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +0200948 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +0100949 }
Harald Welte43e060a2017-07-30 22:38:03 +0200950
951 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +0200952 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
953 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +0200954
Harald Welte060e27a2018-03-03 20:38:19 +0100955 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +0200956 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
957
Harald Welte060e27a2018-03-03 20:38:19 +0100958 if (in.mac__hdr().e() == false) {
959 /* Add LI octets, if any */
960 if (!in.blocks().is_bound()) {
961 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
962 } else {
963 for (i = 0; i < in.blocks().size_of(); i++) {
964#if 0
965 /* check for penultimate block */
966 if (i == in.blocks().size_of()-2) {
967 /* if last block has no header, no more LI */
968 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
969 in.blocks()[i].hdr()().more() = true;
970 } else {
971 /* header present, we have to encode LI */
972 in.blocks()[i].hdr()().more() = false;
973 in.blocks()[i].hdr()().length__ind() =
974 in.blocks()[i+1].payload().lengthof();
975 }
976 } else if (i < in.blocks().size_of()-2) {
977 /* one of the first blocks, before the penultimate or last */
978 in.blocks()[i].hdr()().e() = false; /* LI present */
979 /* re-compute length */
980 in.blocks()[i].hdr()().length__ind() =
981 in.blocks()[i+1].payload().lengthof();
982 }
983 /* Encode LI octet if E=0 */
984 }
985#endif
986 if (in.blocks()[i].hdr() != OMIT_VALUE) {
987 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
988 TTCN_EncDec::CT_RAW);
989 }
990 }
Harald Welte43e060a2017-07-30 22:38:03 +0200991 }
992 }
993
994 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +0100995 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +0200996 }
997
998 if (in.mac__hdr().pfi__ind()) {
999 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1000 }
1001
1002 if (in.blocks().is_bound()) {
1003 for (i = 0; i < in.blocks().size_of(); i++) {
1004 if (!in.blocks()[i].is_bound())
1005 continue;
1006 ttcn_buffer.put_string(in.blocks()[i].payload());
1007 }
1008 }
1009
1010 ttcn_buffer.get_string(ret_val);
1011 return ret_val;
1012}
1013
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001014static
1015void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001016{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001017 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1018}
Harald Welte43e060a2017-07-30 22:38:03 +02001019
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001020static
1021void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1022{
1023 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1024}
Harald Welte43e060a2017-07-30 22:38:03 +02001025
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001026static
1027void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1028{
1029 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001030
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001031 egprs3.r = bs2uint8(si.r__ri());
1032 egprs3.si = bs2uint8(si.foi__si());
1033 egprs3.cv = si.countdown();
1034 egprs3.tfi_hi = si.tfi() >> 0;
1035 egprs3.tfi_lo = si.tfi() >> 1;
1036 egprs3.bsn1_hi = si.bsn1() >> 0;
1037 egprs3.bsn1_lo = si.bsn1() >> 5;
1038 egprs3.cps_hi = si.cps() >> 0;
1039 egprs3.cps_lo = si.cps() >> 2;
1040 egprs3.spb = bs2uint8(si.spb());
1041 egprs3.rsb = bs2uint8(si.spb());
1042 egprs3.pi = si.pfi__ind();
1043 egprs3.spare = 0;
1044 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001045
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001046 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1047}
Harald Welte43e060a2017-07-30 22:38:03 +02001048
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001049OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1050{
1051 RlcmacUlEgprsDataBlock in = si;
1052 OCTETSTRING ret_val;
1053 TTCN_Buffer ttcn_buffer;
1054 int i;
Harald Welte43e060a2017-07-30 22:38:03 +02001055
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001056 if (!in.blocks().is_bound()) {
1057 /* we don't have nay blocks: Add length value (zero) */
1058 in.e() = false; /* E=0: extension octet follows */
1059 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1060 /* If there's only a single block, and that block has no HDR value defined, */
1061 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001062 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001063 /* Length value */
1064 in.e() = false;
1065 }
1066
1067 /* Fix other presence indications */
1068 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1069 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1070
1071 switch (in.mac__hdr().header__type()) {
1072 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
1073 enc__RlcmacUlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
1074 break;
1075 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
1076 enc__RlcmacUlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
1077 break;
1078 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
1079 enc__RlcmacUlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
1080 default:
1081 break; /* TODO: error */
1082 }
1083
1084 if (in.e() == false) {
1085 /* Add LI octets, if any */
1086 if (!in.blocks().is_bound()) {
1087 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1088 } else {
1089 for (i = 0; i < in.blocks().size_of(); i++) {
1090#if 0
1091 /* check for penultimate block */
1092 if (i == in.blocks().size_of()-2) {
1093 /* if last block has no header, no more LI */
1094 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1095 in.blocks()[i].hdr()().more() = true;
1096 } else {
1097 /* header present, we have to encode LI */
1098 in.blocks()[i].hdr()().more() = false;
1099 in.blocks()[i].hdr()().length__ind() =
1100 in.blocks()[i+1].payload().lengthof();
1101 }
1102 } else if (i < in.blocks().size_of()-2) {
1103 /* one of the first blocks, before the penultimate or last */
1104 in.blocks()[i].hdr()().e() = false; /* LI present */
1105 /* re-compute length */
1106 in.blocks()[i].hdr()().length__ind() =
1107 in.blocks()[i+1].payload().lengthof();
1108 }
1109 /* Encode LI octet if E=0 */
1110 }
1111#endif
1112 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1113 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer,
1114 TTCN_EncDec::CT_RAW);
1115 }
Harald Welte43e060a2017-07-30 22:38:03 +02001116 }
1117 }
1118 }
1119
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001120 if (in.tlli__ind()) {
1121 ttcn_buffer.put_string(in.tlli());
1122 }
Harald Welte43e060a2017-07-30 22:38:03 +02001123
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001124 if (in.mac__hdr().pfi__ind()) {
1125 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1126 }
1127
1128 if (in.blocks().is_bound()) {
1129 for (i = 0; i < in.blocks().size_of(); i++) {
1130 if (!in.blocks()[i].is_bound())
1131 continue;
1132 ttcn_buffer.put_string(in.blocks()[i].payload());
1133 }
1134 }
1135
1136 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001137 return ret_val;
1138}
1139
Harald Welte78a1af62017-07-31 17:33:56 +02001140OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1141{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001142 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1143 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1144 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001145 return enc__RlcmacUlDataBlock(si.data());
1146 else
1147 return enc__RlcmacUlCtrlBlock(si.ctrl());
1148}
1149
Harald Welte43e060a2017-07-30 22:38:03 +02001150} // namespace