blob: 88138c6e38333f7900d10e89f00209e35ea077fe [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);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200609 } else {
610 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200611 }
612 /* parse optional PFI */
613 if (ret_val.mac__hdr().pfi__ind()) {
614 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200615 } else {
616 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200617 }
618
619 /* RLC blocks at end */
620 if (ret_val.mac__hdr().e() == true) {
621 LlcBlock lb;
622 unsigned int length = ttcn_buffer.get_read_len();
623 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
624 * fills the current RLC data block precisely or continues in the following in-sequence RLC
625 * data block */
626 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
627 ttcn_buffer.increase_pos(length);
628 ret_val.blocks()[0] = lb;
629 } else {
630 if (ret_val.blocks().is_bound()) {
631 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
632 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
633 if (length > ttcn_buffer.get_read_len())
634 length = ttcn_buffer.get_read_len();
635 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
636 ttcn_buffer.increase_pos(length);
637 }
638 }
639 }
640
641 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
642 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
643 ttcn_buffer.log();
644 TTCN_Logger::end_event();
645 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
646 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
647 ret_val.log();
648 TTCN_Logger::end_event();
649
650 return ret_val;
651}
652
653static
654EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type1(const OCTETSTRING& stream)
655{
656 EgprsUlMacDataHeader ret_val;
657
658 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
659
660 return ret_val;
661}
662
663static
664EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type2(const OCTETSTRING& stream)
665{
666 EgprsUlMacDataHeader ret_val;
667
668 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
669
670 return ret_val;
671}
672
673static
674EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
675{
676 EgprsUlMacDataHeader ret_val;
677
678 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
679
680 return ret_val;
681}
682
683RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs)
684{
685 RlcmacUlEgprsDataBlock ret_val;
686 TTCN_Buffer ttcn_buffer(stream);
687 TTCN_Buffer aligned_buffer;
688 int num_llc_blocks = 0;
689 unsigned int data_block_bits, data_block_offsets[2];
690 unsigned int num_calls;
691 const uint8_t *ti_e;
692
693 switch (mcs) {
694 case CodingScheme::MCS__1:
695 case CodingScheme::MCS__2:
696 case CodingScheme::MCS__3:
697 case CodingScheme::MCS__4:
698 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
699 break;
700 case CodingScheme::MCS__5:
701 case CodingScheme::MCS__6:
702 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
703 break;
704 case CodingScheme::MCS__7:
705 case CodingScheme::MCS__8:
706 case CodingScheme::MCS__9:
707 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
708 break;
709 }
710 setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), true,
711 &num_calls, &data_block_bits, data_block_offsets);
712 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
713
714 ti_e = aligned_buffer.get_read_data();
715 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
716 ret_val.e() = *ti_e & 0x01 ? true : false;
717 aligned_buffer.increase_pos(1);
718
719 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
720 * optional tlli, optional pfi and LLC Blocks */
721
722 /* optional extension octets, containing LI+M+E of Llc blocks */
723 if (ret_val.e() == false) {
724 /* extension octet follows, i.e. optional Llc length octets */
725 while (1) {
726 /* decode one more extension octet with LlcBlocHdr inside */
727 EgprsLlcBlock lb;
728 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
729 ret_val.blocks()[num_llc_blocks++] = lb;
730
731 /* if E == '1'B, we can proceed further */
732 if (lb.hdr()().e() == true)
733 break;
734 }
735 }
736
737 /* parse optional TLLI */
738 if (ret_val.tlli__ind()) {
739 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
740 aligned_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200741 } else {
742 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200743 }
744 /* parse optional PFI */
745 if (ret_val.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +0200746 ret_val.pfi().decode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200747 } else {
748 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200749 }
750
751 /* RLC blocks at end */
752 if (ret_val.e() == true) {
753 EgprsLlcBlock lb;
754 unsigned int length = aligned_buffer.get_read_len();
755 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
756 * fills the current RLC data block precisely or continues in the following in-sequence RLC
757 * data block */
758 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
759 aligned_buffer.increase_pos(length);
760 ret_val.blocks()[0] = lb;
761 } else {
762 if (ret_val.blocks().is_bound()) {
763 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
764 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
765 if (length > aligned_buffer.get_read_len())
766 length = aligned_buffer.get_read_len();
767 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
768 aligned_buffer.increase_pos(length);
769 }
770 }
771 }
772
773 return ret_val;
774}
775
776RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
777{
778 RlcmacUlBlock ret_val;
779 size_t stream_len = stream.lengthof();
780 CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len);
781 unsigned char pt;
782
783 switch (mcs) {
784 case CodingScheme::CS__1:
785 case CodingScheme::CS__2:
786 case CodingScheme::CS__3:
787 case CodingScheme::CS__4:
788 pt = stream[0].get_octet() >> 6;
789 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
790 ret_val.data() = dec__RlcmacUlDataBlock(stream);
791 else
792 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
793 break;
794 case CodingScheme::MCS__1:
795 case CodingScheme::MCS__2:
796 case CodingScheme::MCS__3:
797 case CodingScheme::MCS__4:
798 case CodingScheme::MCS__5:
799 case CodingScheme::MCS__6:
800 case CodingScheme::MCS__7:
801 case CodingScheme::MCS__8:
802 case CodingScheme::MCS__9:
803 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream, mcs);
804 break;
805 }
806
807 return ret_val;
808}
809
810
811/////////////////////
812// ENCODE
813/////////////////////
814
815/* ENCODE DOWNLINK */
816
817OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
818{
819 RlcmacDlDataBlock in = si;
820 OCTETSTRING ret_val;
821 TTCN_Buffer ttcn_buffer;
822 int i;
823
824 /* Fix 'e' bit of initial header based on following blocks */
825 if (!in.blocks().is_bound() ||
826 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
827 in.mac__hdr().hdr__ext().e() = true;
828 else
829 in.mac__hdr().hdr__ext().e() = false;
830
831 /* use automatic/generated decoder for header */
832 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
833
834 /* Add LI octets, if any */
835 if (in.blocks().is_bound() &&
836 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
837 /* first write LI octets */
838 for (i = 0; i < in.blocks().size_of(); i++) {
839 /* fix the 'E' bit in case it is not clear */
840 if (i < in.blocks().size_of()-1)
841 in.blocks()[i].hdr()().e() = false;
842 else
843 in.blocks()[i].hdr()().e() = true;
844 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
845 }
846 }
847 if (in.blocks().is_bound()) {
848 for (i = 0; i < in.blocks().size_of(); i++) {
849 if (!in.blocks()[i].is_bound())
850 continue;
851 ttcn_buffer.put_string(in.blocks()[i].payload());
852 }
853 }
854
855 ttcn_buffer.get_string(ret_val);
856 return ret_val;
857}
858
859static
860void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
861{
862 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
863}
864
865static
866void enc__RlcmacDlEgprsDataHeader_type2(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
867{
868 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
869}
870
871static
872void enc__RlcmacDlEgprsDataHeader_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
873{
874 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
875}
876
877OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
878{
879 RlcmacDlEgprsDataBlock in = si;
880 OCTETSTRING ret_val;
881 TTCN_Buffer ttcn_buffer;
882 int i;
883
884 /* Fix 'e' bit of initial header based on following blocks */
885 if (!in.blocks().is_bound() ||
886 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
887 in.e() = true;
888 else
889 in.e() = false;
890
891 switch (in.mac__hdr().header__type()) {
892 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
893 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
894 break;
895 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
896 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
897 break;
898 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
899 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
900 default:
901 break; /* TODO: error */
902 }
903
904 /* Add LI octets, if any */
905 if (in.blocks().is_bound() &&
906 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
907 /* first write LI octets */
908 for (i = 0; i < in.blocks().size_of(); i++) {
909 /* fix the 'E' bit in case it is not clear */
910 if (i < in.blocks().size_of()-1)
911 in.blocks()[i].hdr()().e() = false;
912 else
913 in.blocks()[i].hdr()().e() = true;
914 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
915 }
916 }
917 if (in.blocks().is_bound()) {
918 for (i = 0; i < in.blocks().size_of(); i++) {
919 if (!in.blocks()[i].is_bound())
920 continue;
921 ttcn_buffer.put_string(in.blocks()[i].payload());
922 }
923 }
924
925 ttcn_buffer.get_string(ret_val);
926 return ret_val;
927}
928
929OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
930{
931 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
932 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
933 else if (si.ischosen(RlcmacDlBlock::ALT_data))
934 return enc__RlcmacDlDataBlock(si.data());
935 else
936 return enc__RlcmacDlCtrlBlock(si.ctrl());
937}
938
939/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +0200940
941OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
942{
943 RlcmacUlDataBlock in = si;
944 OCTETSTRING ret_val;
945 TTCN_Buffer ttcn_buffer;
946 int i;
947
Harald Welte060e27a2018-03-03 20:38:19 +0100948 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +0200949 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +0100950 in.mac__hdr().e() = false; /* E=0: extension octet follows */
951 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
952 /* If there's only a single block, and that block has no HDR value defined, */
953 in.mac__hdr().e() = true; /* E=0: extension octet follows */
954 } else {
955 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +0200956 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +0100957 }
Harald Welte43e060a2017-07-30 22:38:03 +0200958
959 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +0200960 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
961 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +0200962
Harald Welte060e27a2018-03-03 20:38:19 +0100963 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +0200964 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
965
Harald Welte060e27a2018-03-03 20:38:19 +0100966 if (in.mac__hdr().e() == false) {
967 /* Add LI octets, if any */
968 if (!in.blocks().is_bound()) {
969 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
970 } else {
971 for (i = 0; i < in.blocks().size_of(); i++) {
972#if 0
973 /* check for penultimate block */
974 if (i == in.blocks().size_of()-2) {
975 /* if last block has no header, no more LI */
976 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
977 in.blocks()[i].hdr()().more() = true;
978 } else {
979 /* header present, we have to encode LI */
980 in.blocks()[i].hdr()().more() = false;
981 in.blocks()[i].hdr()().length__ind() =
982 in.blocks()[i+1].payload().lengthof();
983 }
984 } else if (i < in.blocks().size_of()-2) {
985 /* one of the first blocks, before the penultimate or last */
986 in.blocks()[i].hdr()().e() = false; /* LI present */
987 /* re-compute length */
988 in.blocks()[i].hdr()().length__ind() =
989 in.blocks()[i+1].payload().lengthof();
990 }
991 /* Encode LI octet if E=0 */
992 }
993#endif
994 if (in.blocks()[i].hdr() != OMIT_VALUE) {
995 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
996 TTCN_EncDec::CT_RAW);
997 }
998 }
Harald Welte43e060a2017-07-30 22:38:03 +0200999 }
1000 }
1001
1002 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +01001003 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +02001004 }
1005
1006 if (in.mac__hdr().pfi__ind()) {
1007 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1008 }
1009
1010 if (in.blocks().is_bound()) {
1011 for (i = 0; i < in.blocks().size_of(); i++) {
1012 if (!in.blocks()[i].is_bound())
1013 continue;
1014 ttcn_buffer.put_string(in.blocks()[i].payload());
1015 }
1016 }
1017
1018 ttcn_buffer.get_string(ret_val);
1019 return ret_val;
1020}
1021
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001022static
1023void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001024{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001025 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1026}
Harald Welte43e060a2017-07-30 22:38:03 +02001027
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001028static
1029void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1030{
1031 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1032}
Harald Welte43e060a2017-07-30 22:38:03 +02001033
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001034static
1035void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1036{
1037 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001038
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001039 egprs3.r = bs2uint8(si.r__ri());
1040 egprs3.si = bs2uint8(si.foi__si());
1041 egprs3.cv = si.countdown();
1042 egprs3.tfi_hi = si.tfi() >> 0;
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001043 egprs3.tfi_lo = si.tfi() >> 2;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001044 egprs3.bsn1_hi = si.bsn1() >> 0;
1045 egprs3.bsn1_lo = si.bsn1() >> 5;
1046 egprs3.cps_hi = si.cps() >> 0;
1047 egprs3.cps_lo = si.cps() >> 2;
1048 egprs3.spb = bs2uint8(si.spb());
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001049 egprs3.rsb = bs2uint8(si.rsb());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001050 egprs3.pi = si.pfi__ind();
1051 egprs3.spare = 0;
1052 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001053
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001054 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1055}
Harald Welte43e060a2017-07-30 22:38:03 +02001056
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001057OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1058{
1059 RlcmacUlEgprsDataBlock in = si;
1060 OCTETSTRING ret_val;
1061 TTCN_Buffer ttcn_buffer;
1062 int i;
Harald Welte43e060a2017-07-30 22:38:03 +02001063
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001064 if (!in.blocks().is_bound()) {
1065 /* we don't have nay blocks: Add length value (zero) */
1066 in.e() = false; /* E=0: extension octet follows */
1067 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1068 /* If there's only a single block, and that block has no HDR value defined, */
1069 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001070 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001071 /* Length value */
1072 in.e() = false;
1073 }
1074
1075 /* Fix other presence indications */
1076 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1077 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1078
1079 switch (in.mac__hdr().header__type()) {
1080 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
1081 enc__RlcmacUlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
1082 break;
1083 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
1084 enc__RlcmacUlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
1085 break;
1086 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
1087 enc__RlcmacUlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
1088 default:
1089 break; /* TODO: error */
1090 }
1091
1092 if (in.e() == false) {
1093 /* Add LI octets, if any */
1094 if (!in.blocks().is_bound()) {
1095 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1096 } else {
1097 for (i = 0; i < in.blocks().size_of(); i++) {
1098#if 0
1099 /* check for penultimate block */
1100 if (i == in.blocks().size_of()-2) {
1101 /* if last block has no header, no more LI */
1102 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1103 in.blocks()[i].hdr()().more() = true;
1104 } else {
1105 /* header present, we have to encode LI */
1106 in.blocks()[i].hdr()().more() = false;
1107 in.blocks()[i].hdr()().length__ind() =
1108 in.blocks()[i+1].payload().lengthof();
1109 }
1110 } else if (i < in.blocks().size_of()-2) {
1111 /* one of the first blocks, before the penultimate or last */
1112 in.blocks()[i].hdr()().e() = false; /* LI present */
1113 /* re-compute length */
1114 in.blocks()[i].hdr()().length__ind() =
1115 in.blocks()[i+1].payload().lengthof();
1116 }
1117 /* Encode LI octet if E=0 */
1118 }
1119#endif
1120 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1121 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer,
1122 TTCN_EncDec::CT_RAW);
1123 }
Harald Welte43e060a2017-07-30 22:38:03 +02001124 }
1125 }
1126 }
1127
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001128 if (in.tlli__ind()) {
1129 ttcn_buffer.put_string(in.tlli());
1130 }
Harald Welte43e060a2017-07-30 22:38:03 +02001131
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001132 if (in.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +02001133 in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001134 }
1135
1136 if (in.blocks().is_bound()) {
1137 for (i = 0; i < in.blocks().size_of(); i++) {
1138 if (!in.blocks()[i].is_bound())
1139 continue;
1140 ttcn_buffer.put_string(in.blocks()[i].payload());
1141 }
1142 }
1143
1144 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001145 return ret_val;
1146}
1147
Harald Welte78a1af62017-07-31 17:33:56 +02001148OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1149{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001150 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1151 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1152 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001153 return enc__RlcmacUlDataBlock(si.data());
1154 else
1155 return enc__RlcmacUlCtrlBlock(si.ctrl());
1156}
1157
Harald Welte43e060a2017-07-30 22:38:03 +02001158} // namespace