blob: 8f3ff2f416acbdcc38e42bb5a16aff170c719b0d [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{
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200676 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200677 EgprsUlMacDataHeader ret_val;
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200678 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
679 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200680
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200681 egprs3 = static_cast<const struct gprs_rlc_ul_header_egprs_3 *>
682 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200683
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200684 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
685 ret_val.tfi() = egprs3->tfi_lo << 2 | egprs3->tfi_hi << 0;
686 ret_val.countdown() = egprs3->cv;
687 tmp = egprs3->si;
688 ret_val.foi__si() = BITSTRING(1, &tmp);
689 tmp = egprs3->r;
690 ret_val.r__ri() = BITSTRING(1, &tmp);
691 ret_val.bsn1() = egprs3->bsn1_lo << 5 | egprs3->bsn1_hi << 0;
692 ret_val.cps() = egprs3->cps_lo << 2 | egprs3->cps_hi << 0;
693 ret_val.pfi__ind() = egprs3->pi;
694 tmp = egprs3->rsb;
695 ret_val.rsb() = BITSTRING(1, &tmp);
696 tmp = egprs3->spb;
697 ret_val.spb() = BITSTRING(2, &tmp);
698
699 ttcn_buffer.increase_pos(sizeof(*egprs3));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200700 return ret_val;
701}
702
703RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream, CodingScheme::enum_type mcs)
704{
705 RlcmacUlEgprsDataBlock ret_val;
706 TTCN_Buffer ttcn_buffer(stream);
707 TTCN_Buffer aligned_buffer;
708 int num_llc_blocks = 0;
709 unsigned int data_block_bits, data_block_offsets[2];
710 unsigned int num_calls;
711 const uint8_t *ti_e;
712
713 switch (mcs) {
714 case CodingScheme::MCS__1:
715 case CodingScheme::MCS__2:
716 case CodingScheme::MCS__3:
717 case CodingScheme::MCS__4:
718 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
719 break;
720 case CodingScheme::MCS__5:
721 case CodingScheme::MCS__6:
722 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
723 break;
724 case CodingScheme::MCS__7:
725 case CodingScheme::MCS__8:
726 case CodingScheme::MCS__9:
727 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
728 break;
729 }
730 setup_rlc_mac_priv(mcs, ret_val.mac__hdr().header__type(), true,
731 &num_calls, &data_block_bits, data_block_offsets);
732 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
733
734 ti_e = aligned_buffer.get_read_data();
735 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
736 ret_val.e() = *ti_e & 0x01 ? true : false;
737 aligned_buffer.increase_pos(1);
738
739 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
740 * optional tlli, optional pfi and LLC Blocks */
741
742 /* optional extension octets, containing LI+M+E of Llc blocks */
743 if (ret_val.e() == false) {
744 /* extension octet follows, i.e. optional Llc length octets */
745 while (1) {
746 /* decode one more extension octet with LlcBlocHdr inside */
747 EgprsLlcBlock lb;
748 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
749 ret_val.blocks()[num_llc_blocks++] = lb;
750
751 /* if E == '1'B, we can proceed further */
752 if (lb.hdr()().e() == true)
753 break;
754 }
755 }
756
757 /* parse optional TLLI */
758 if (ret_val.tlli__ind()) {
759 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
760 aligned_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200761 } else {
762 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200763 }
764 /* parse optional PFI */
765 if (ret_val.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +0200766 ret_val.pfi().decode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200767 } else {
768 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200769 }
770
771 /* RLC blocks at end */
772 if (ret_val.e() == true) {
773 EgprsLlcBlock lb;
774 unsigned int length = aligned_buffer.get_read_len();
775 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
776 * fills the current RLC data block precisely or continues in the following in-sequence RLC
777 * data block */
778 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
779 aligned_buffer.increase_pos(length);
780 ret_val.blocks()[0] = lb;
781 } else {
782 if (ret_val.blocks().is_bound()) {
783 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
784 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
785 if (length > aligned_buffer.get_read_len())
786 length = aligned_buffer.get_read_len();
787 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
788 aligned_buffer.increase_pos(length);
789 }
790 }
791 }
792
793 return ret_val;
794}
795
796RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
797{
798 RlcmacUlBlock ret_val;
799 size_t stream_len = stream.lengthof();
800 CodingScheme::enum_type mcs = payload_len_2_coding_scheme(stream_len);
801 unsigned char pt;
802
803 switch (mcs) {
804 case CodingScheme::CS__1:
805 case CodingScheme::CS__2:
806 case CodingScheme::CS__3:
807 case CodingScheme::CS__4:
808 pt = stream[0].get_octet() >> 6;
809 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
810 ret_val.data() = dec__RlcmacUlDataBlock(stream);
811 else
812 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
813 break;
814 case CodingScheme::MCS__1:
815 case CodingScheme::MCS__2:
816 case CodingScheme::MCS__3:
817 case CodingScheme::MCS__4:
818 case CodingScheme::MCS__5:
819 case CodingScheme::MCS__6:
820 case CodingScheme::MCS__7:
821 case CodingScheme::MCS__8:
822 case CodingScheme::MCS__9:
823 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream, mcs);
824 break;
825 }
826
827 return ret_val;
828}
829
830
831/////////////////////
832// ENCODE
833/////////////////////
834
835/* ENCODE DOWNLINK */
836
837OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
838{
839 RlcmacDlDataBlock in = si;
840 OCTETSTRING ret_val;
841 TTCN_Buffer ttcn_buffer;
842 int i;
843
844 /* Fix 'e' bit of initial header based on following blocks */
845 if (!in.blocks().is_bound() ||
846 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
847 in.mac__hdr().hdr__ext().e() = true;
848 else
849 in.mac__hdr().hdr__ext().e() = false;
850
851 /* use automatic/generated decoder for header */
852 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
853
854 /* Add LI octets, if any */
855 if (in.blocks().is_bound() &&
856 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
857 /* first write LI octets */
858 for (i = 0; i < in.blocks().size_of(); i++) {
859 /* fix the 'E' bit in case it is not clear */
860 if (i < in.blocks().size_of()-1)
861 in.blocks()[i].hdr()().e() = false;
862 else
863 in.blocks()[i].hdr()().e() = true;
864 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
865 }
866 }
867 if (in.blocks().is_bound()) {
868 for (i = 0; i < in.blocks().size_of(); i++) {
869 if (!in.blocks()[i].is_bound())
870 continue;
871 ttcn_buffer.put_string(in.blocks()[i].payload());
872 }
873 }
874
875 ttcn_buffer.get_string(ret_val);
876 return ret_val;
877}
878
879static
880void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
881{
882 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
883}
884
885static
886void enc__RlcmacDlEgprsDataHeader_type2(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
887{
888 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
889}
890
891static
892void enc__RlcmacDlEgprsDataHeader_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
893{
894 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
895}
896
897OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
898{
899 RlcmacDlEgprsDataBlock in = si;
900 OCTETSTRING ret_val;
901 TTCN_Buffer ttcn_buffer;
902 int i;
903
904 /* Fix 'e' bit of initial header based on following blocks */
905 if (!in.blocks().is_bound() ||
906 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
907 in.e() = true;
908 else
909 in.e() = false;
910
911 switch (in.mac__hdr().header__type()) {
912 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
913 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
914 break;
915 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
916 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
917 break;
918 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
919 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
920 default:
921 break; /* TODO: error */
922 }
923
924 /* Add LI octets, if any */
925 if (in.blocks().is_bound() &&
926 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
927 /* first write LI octets */
928 for (i = 0; i < in.blocks().size_of(); i++) {
929 /* fix the 'E' bit in case it is not clear */
930 if (i < in.blocks().size_of()-1)
931 in.blocks()[i].hdr()().e() = false;
932 else
933 in.blocks()[i].hdr()().e() = true;
934 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
935 }
936 }
937 if (in.blocks().is_bound()) {
938 for (i = 0; i < in.blocks().size_of(); i++) {
939 if (!in.blocks()[i].is_bound())
940 continue;
941 ttcn_buffer.put_string(in.blocks()[i].payload());
942 }
943 }
944
945 ttcn_buffer.get_string(ret_val);
946 return ret_val;
947}
948
949OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
950{
951 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
952 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
953 else if (si.ischosen(RlcmacDlBlock::ALT_data))
954 return enc__RlcmacDlDataBlock(si.data());
955 else
956 return enc__RlcmacDlCtrlBlock(si.ctrl());
957}
958
959/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +0200960
961OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
962{
963 RlcmacUlDataBlock in = si;
964 OCTETSTRING ret_val;
965 TTCN_Buffer ttcn_buffer;
966 int i;
967
Harald Welte060e27a2018-03-03 20:38:19 +0100968 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +0200969 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +0100970 in.mac__hdr().e() = false; /* E=0: extension octet follows */
971 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
972 /* If there's only a single block, and that block has no HDR value defined, */
973 in.mac__hdr().e() = true; /* E=0: extension octet follows */
974 } else {
975 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +0200976 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +0100977 }
Harald Welte43e060a2017-07-30 22:38:03 +0200978
979 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +0200980 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
981 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +0200982
Harald Welte060e27a2018-03-03 20:38:19 +0100983 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +0200984 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
985
Harald Welte060e27a2018-03-03 20:38:19 +0100986 if (in.mac__hdr().e() == false) {
987 /* Add LI octets, if any */
988 if (!in.blocks().is_bound()) {
989 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
990 } else {
991 for (i = 0; i < in.blocks().size_of(); i++) {
992#if 0
993 /* check for penultimate block */
994 if (i == in.blocks().size_of()-2) {
995 /* if last block has no header, no more LI */
996 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
997 in.blocks()[i].hdr()().more() = true;
998 } else {
999 /* header present, we have to encode LI */
1000 in.blocks()[i].hdr()().more() = false;
1001 in.blocks()[i].hdr()().length__ind() =
1002 in.blocks()[i+1].payload().lengthof();
1003 }
1004 } else if (i < in.blocks().size_of()-2) {
1005 /* one of the first blocks, before the penultimate or last */
1006 in.blocks()[i].hdr()().e() = false; /* LI present */
1007 /* re-compute length */
1008 in.blocks()[i].hdr()().length__ind() =
1009 in.blocks()[i+1].payload().lengthof();
1010 }
1011 /* Encode LI octet if E=0 */
1012 }
1013#endif
1014 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1015 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
1016 TTCN_EncDec::CT_RAW);
1017 }
1018 }
Harald Welte43e060a2017-07-30 22:38:03 +02001019 }
1020 }
1021
1022 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +01001023 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +02001024 }
1025
1026 if (in.mac__hdr().pfi__ind()) {
1027 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1028 }
1029
1030 if (in.blocks().is_bound()) {
1031 for (i = 0; i < in.blocks().size_of(); i++) {
1032 if (!in.blocks()[i].is_bound())
1033 continue;
1034 ttcn_buffer.put_string(in.blocks()[i].payload());
1035 }
1036 }
1037
1038 ttcn_buffer.get_string(ret_val);
1039 return ret_val;
1040}
1041
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001042static
1043void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001044{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001045 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1046}
Harald Welte43e060a2017-07-30 22:38:03 +02001047
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001048static
1049void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1050{
1051 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1052}
Harald Welte43e060a2017-07-30 22:38:03 +02001053
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001054static
1055void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1056{
1057 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001058
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001059 egprs3.r = bs2uint8(si.r__ri());
1060 egprs3.si = bs2uint8(si.foi__si());
1061 egprs3.cv = si.countdown();
1062 egprs3.tfi_hi = si.tfi() >> 0;
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001063 egprs3.tfi_lo = si.tfi() >> 2;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001064 egprs3.bsn1_hi = si.bsn1() >> 0;
1065 egprs3.bsn1_lo = si.bsn1() >> 5;
1066 egprs3.cps_hi = si.cps() >> 0;
1067 egprs3.cps_lo = si.cps() >> 2;
1068 egprs3.spb = bs2uint8(si.spb());
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001069 egprs3.rsb = bs2uint8(si.rsb());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001070 egprs3.pi = si.pfi__ind();
1071 egprs3.spare = 0;
1072 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001073
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001074 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1075}
Harald Welte43e060a2017-07-30 22:38:03 +02001076
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001077OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1078{
1079 RlcmacUlEgprsDataBlock in = si;
1080 OCTETSTRING ret_val;
1081 TTCN_Buffer ttcn_buffer;
1082 int i;
Harald Welte43e060a2017-07-30 22:38:03 +02001083
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001084 if (!in.blocks().is_bound()) {
1085 /* we don't have nay blocks: Add length value (zero) */
1086 in.e() = false; /* E=0: extension octet follows */
1087 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1088 /* If there's only a single block, and that block has no HDR value defined, */
1089 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001090 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001091 /* Length value */
1092 in.e() = false;
1093 }
1094
1095 /* Fix other presence indications */
1096 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1097 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1098
1099 switch (in.mac__hdr().header__type()) {
1100 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001101 enc__RlcmacUlEgprsDataHeader_type1(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001102 break;
1103 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001104 enc__RlcmacUlEgprsDataHeader_type2(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001105 break;
1106 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001107 enc__RlcmacUlEgprsDataHeader_type3(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001108 default:
1109 break; /* TODO: error */
1110 }
1111
1112 if (in.e() == false) {
1113 /* Add LI octets, if any */
1114 if (!in.blocks().is_bound()) {
1115 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1116 } else {
1117 for (i = 0; i < in.blocks().size_of(); i++) {
1118#if 0
1119 /* check for penultimate block */
1120 if (i == in.blocks().size_of()-2) {
1121 /* if last block has no header, no more LI */
1122 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1123 in.blocks()[i].hdr()().more() = true;
1124 } else {
1125 /* header present, we have to encode LI */
1126 in.blocks()[i].hdr()().more() = false;
1127 in.blocks()[i].hdr()().length__ind() =
1128 in.blocks()[i+1].payload().lengthof();
1129 }
1130 } else if (i < in.blocks().size_of()-2) {
1131 /* one of the first blocks, before the penultimate or last */
1132 in.blocks()[i].hdr()().e() = false; /* LI present */
1133 /* re-compute length */
1134 in.blocks()[i].hdr()().length__ind() =
1135 in.blocks()[i+1].payload().lengthof();
1136 }
1137 /* Encode LI octet if E=0 */
1138 }
1139#endif
1140 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1141 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer,
1142 TTCN_EncDec::CT_RAW);
1143 }
Harald Welte43e060a2017-07-30 22:38:03 +02001144 }
1145 }
1146 }
1147
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001148 if (in.tlli__ind()) {
1149 ttcn_buffer.put_string(in.tlli());
1150 }
Harald Welte43e060a2017-07-30 22:38:03 +02001151
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001152 if (in.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +02001153 in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001154 }
1155
1156 if (in.blocks().is_bound()) {
1157 for (i = 0; i < in.blocks().size_of(); i++) {
1158 if (!in.blocks()[i].is_bound())
1159 continue;
1160 ttcn_buffer.put_string(in.blocks()[i].payload());
1161 }
1162 }
1163
1164 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001165 return ret_val;
1166}
1167
Harald Welte78a1af62017-07-31 17:33:56 +02001168OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1169{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001170 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1171 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1172 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001173 return enc__RlcmacUlDataBlock(si.data());
1174 else
1175 return enc__RlcmacUlCtrlBlock(si.ctrl());
1176}
1177
Harald Welte43e060a2017-07-30 22:38:03 +02001178} // namespace