blob: 16291dedff2abb77d76587309e5f5a755e22cc15 [file] [log] [blame]
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001#include <stdint.h>
2#include <endian.h>
3
Harald Welte43e060a2017-07-30 22:38:03 +02004#include "RLCMAC_Types.hh"
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02005#include "RLCMAC_Templates.hh"
Harald Welte43e060a2017-07-30 22:38:03 +02006#include "GSM_Types.hh"
7/* Decoding of TS 44.060 GPRS RLC/MAC blocks, portions requiring manual functions
8 * beyond what TITAN RAW coder can handle internally.
9 *
10 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
Harald Welte34b5a952019-05-27 11:54:11 +020011 * All rights reserved.
12 *
13 * Released under the terms of GNU General Public License, Version 2 or
14 * (at your option) any later version.
15 *
16 * SPDX-License-Identifier: GPL-2.0-or-later
Harald Welte43e060a2017-07-30 22:38:03 +020017 */
18
19namespace RLCMAC__Types {
20
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020021/////////////////////
22// INTENRAL HELPERS
23/////////////////////
Harald Welte43e060a2017-07-30 22:38:03 +020024
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020025/* TS 04.60 10.3a.4.1.1 */
26struct gprs_rlc_ul_header_egprs_1 {
27#if __BYTE_ORDER == __LITTLE_ENDIAN
28 uint8_t r:1,
29 si:1,
30 cv:4,
31 tfi_hi:2;
32 uint8_t tfi_lo:3,
33 bsn1_hi:5;
34 uint8_t bsn1_lo:6,
35 bsn2_hi:2;
36 uint8_t bsn2_lo:8;
37 uint8_t cps:5,
38 rsb:1,
39 pi:1,
40 spare_hi:1;
41 uint8_t spare_lo:6,
42 dummy:2;
43#else
44/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
45 uint8_t tfi_hi:2, cv:4, si:1, r:1;
46 uint8_t bsn1_hi:5, tfi_lo:3;
47 uint8_t bsn2_hi:2, bsn1_lo:6;
48 uint8_t bsn2_lo:8;
49 uint8_t spare_hi:1, pi:1, rsb:1, cps:5;
50 uint8_t dummy:2, spare_lo:6;
51#endif
52} __attribute__ ((packed));
Harald Welte43e060a2017-07-30 22:38:03 +020053
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020054/* TS 04.60 10.3a.4.2.1 */
55struct gprs_rlc_ul_header_egprs_2 {
56#if __BYTE_ORDER == __LITTLE_ENDIAN
57 uint8_t r:1,
58 si:1,
59 cv:4,
60 tfi_hi:2;
61 uint8_t tfi_lo:3,
62 bsn1_hi:5;
63 uint8_t bsn1_lo:6,
64 cps_hi:2;
65 uint8_t cps_lo:1,
66 rsb:1,
67 pi:1,
68 spare_hi:5;
69 uint8_t spare_lo:5,
70 dummy:3;
71#else
72/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
73 uint8_t tfi_hi:2, cv:4, si:1, r:1;
74 uint8_t bsn1_hi:5, tfi_lo:3;
75 uint8_t cps_hi:2, bsn1_lo:6;
76 uint8_t spare_hi:5, pi:1, rsb:1, cps_lo:1;
77 uint8_t dummy:3, spare_lo:5;
78#endif
79} __attribute__ ((packed));
Harald Welte43e060a2017-07-30 22:38:03 +020080
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +020081/* TS 04.60 10.3a.4.3.1 */
82struct gprs_rlc_ul_header_egprs_3 {
83#if __BYTE_ORDER == __LITTLE_ENDIAN
84 uint8_t r:1,
85 si:1,
86 cv:4,
87 tfi_hi:2;
88 uint8_t tfi_lo:3,
89 bsn1_hi:5;
90 uint8_t bsn1_lo:6,
91 cps_hi:2;
92 uint8_t cps_lo:2,
93 spb:2,
94 rsb:1,
95 pi:1,
96 spare:1,
97 dummy:1;
98#else
99/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
100 uint8_t tfi_hi:2, cv:4, si:1, r:1;
101 uint8_t bsn1_hi:5, tfi_lo:3;
102 uint8_t cps_hi:2, bsn1_lo:6;
103 uint8_t dummy:1, spare:1, pi:1, rsb:1, spb:2, cps_lo:2;
104#endif
105} __attribute__ ((packed));
106
107struct gprs_rlc_dl_header_egprs_1 {
108#if __BYTE_ORDER == __LITTLE_ENDIAN
109 uint8_t usf:3,
110 es_p:2,
111 rrbp:2,
112 tfi_hi:1;
113 uint8_t tfi_lo:4,
114 pr:2,
115 bsn1_hi:2;
116 uint8_t bsn1_mid:8;
117 uint8_t bsn1_lo:1,
118 bsn2_hi:7;
119 uint8_t bsn2_lo:3,
120 cps:5;
121#else
122/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
123 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
124 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
125 uint8_t bsn1_mid:8;
126 uint8_t bsn2_hi:7, bsn1_lo:1;
127 uint8_t cps:5, bsn2_lo:3;
128#endif
129} __attribute__ ((packed));
130
131struct gprs_rlc_dl_header_egprs_2 {
132#if __BYTE_ORDER == __LITTLE_ENDIAN
133 uint8_t usf:3,
134 es_p:2,
135 rrbp:2,
136 tfi_hi:1;
137 uint8_t tfi_lo:4,
138 pr:2,
139 bsn1_hi:2;
140 uint8_t bsn1_mid:8;
141 uint8_t bsn1_lo:1,
142 cps:3,
143 dummy:4;
144#else
145/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
146 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
147 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
148 uint8_t bsn1_mid:8;
149 uint8_t dummy:4, cps:3, bsn1_lo:1;
150#endif
151} __attribute__ ((packed));
152
153struct gprs_rlc_dl_header_egprs_3 {
154#if __BYTE_ORDER == __LITTLE_ENDIAN
155 uint8_t usf:3,
156 es_p:2,
157 rrbp:2,
158 tfi_hi:1;
159 uint8_t tfi_lo:4,
160 pr:2,
161 bsn1_hi:2;
162 uint8_t bsn1_mid:8;
163 uint8_t bsn1_lo:1,
164 cps:4,
165 spb:2,
166 dummy:1;
167#else
168/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */
169 uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3;
170 uint8_t bsn1_hi:2, pr:2, tfi_lo:4;
171 uint8_t bsn1_mid:8;
172 uint8_t dummy:1, spb:2, cps:4, bsn1_lo:1;
173#endif
174} __attribute__ ((packed));
175
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200176/*
177static const char hex_chars[] = "0123456789abcdef";
178void printbuffer(const char* ptr, TTCN_Buffer& buf) {
179 int len = buf.get_len();
180 const unsigned char* cbuf = buf.get_data();
181
182 fprintf(stderr, "printbuffer %s (len=%d): [", ptr, len);
183
184 for (int i = 0; i < len; i++) {
185 fprintf(stderr, " %c%c", hex_chars[cbuf[i] >> 4], hex_chars[cbuf[i] & 0xf]);
186 }
187
188 fprintf(stderr, " ]\n");
189}
190*/
191
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200192static CodingScheme::enum_type payload_len_2_coding_scheme(size_t payload_len) {
193 switch (payload_len) {
194 case 23:
195 return CodingScheme::CS__1;
196 case 34:
197 return CodingScheme::CS__2;
198 case 40:
199 return CodingScheme::CS__3;
200 case 54:
201 return CodingScheme::CS__4;
202 case 27:
203 return CodingScheme::MCS__1;
204 case 33:
205 return CodingScheme::MCS__2;
206 case 42:
207 return CodingScheme::MCS__3;
208 case 49:
209 return CodingScheme::MCS__4;
210 case 61:
211 return CodingScheme::MCS__5;
212 case 79:
213 return CodingScheme::MCS__6;
214 case 119:
215 return CodingScheme::MCS__7;
216 case 142:
217 return CodingScheme::MCS__8;
218 case 155:
219 return CodingScheme::MCS__9;
220 default:
221 return CodingScheme::CS__1;
Harald Welte43e060a2017-07-30 22:38:03 +0200222 }
Harald Welte43e060a2017-07-30 22:38:03 +0200223}
224
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200225static unsigned int coding_scheme_2_data_block_len(CodingScheme::enum_type mcs) {
226 switch (mcs) {
227 case CodingScheme::MCS__0:
228 return 0;
229 case CodingScheme::MCS__1:
230 return 22;
231 case CodingScheme::MCS__2:
232 return 28;
233 case CodingScheme::MCS__3:
234 return 37;
235 case CodingScheme::MCS__4:
236 return 44;
237 case CodingScheme::MCS__5:
238 return 56;
239 case CodingScheme::MCS__6:
240 return 74;
241 case CodingScheme::MCS__7:
242 return 56;
243 case CodingScheme::MCS__8:
244 return 68;
245 case CodingScheme::MCS__9:
246 return 74;
247 default:
248 return 22; /* MCS1*/
249 }
250}
251
252static uint8_t bs2uint8(const BITSTRING& bs)
253{
254 int len = bs.lengthof();
255 int i;
256 uint8_t res = 0;
257 for (i = 0; i < len; i++) {
258 res = res << 1;
259 res |= (bs[i].get_bit() ? 1 : 0);
260 }
261 return res;
262}
263
264/* determine the number of rlc data blocks and their size / offsets */
265static void
266setup_rlc_mac_priv(CodingScheme::enum_type mcs, EgprsHeaderType::enum_type hdrtype, boolean is_uplink,
267 unsigned int *n_calls, unsigned int *data_block_bits, unsigned int *data_block_offsets)
268{
269 unsigned int nc, dbl = 0, dbo[2] = {0,0};
270
271 dbl = coding_scheme_2_data_block_len(mcs);
272
273 switch (hdrtype) {
274 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
275 nc = 3;
276 dbo[0] = is_uplink ? 5*8 + 6 : 5*8 + 0;
277 dbo[1] = dbo[0] + dbl * 8 + 2;
278 break;
279 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
280 nc = 2;
281 dbo[0] = is_uplink ? 4*8 + 5 : 3*8 + 4;
282 break;
283 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
284 nc = 2;
285 dbo[0] = 3*8 + 7;
286 break;
287 default:
288 nc = 1;
289 break;
290 }
291
292 *n_calls = nc;
293 *data_block_bits = dbl * 8 + 2;
294 data_block_offsets[0] = dbo[0];
295 data_block_offsets[1] = dbo[1];
296}
297
298/* bit-shift the entire 'src' of length 'length_bytes' by 'offset_bits'
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +0200299 * and store the result to caller-allocated 'buffer'. The shifting is
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200300 * done lsb-first. */
301static void clone_aligned_buffer_lsbf(unsigned int offset_bits, unsigned int length_bytes,
302 const uint8_t *src, uint8_t *buffer)
303{
304 unsigned int hdr_bytes;
305 unsigned int extra_bits;
306 unsigned int i;
307
308 uint8_t c, last_c;
309 uint8_t *dst;
310
311 hdr_bytes = offset_bits / 8;
312 extra_bits = offset_bits % 8;
313
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200314 //fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200315
316 if (extra_bits == 0) {
317 /* It is aligned already */
318 memcpy(buffer, src + hdr_bytes, length_bytes);
319 return;
320 }
321
322 dst = buffer;
323 src = src + hdr_bytes;
324 last_c = *(src++);
325
326 for (i = 0; i < length_bytes; i++) {
327 c = src[i];
328 *(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits));
329 last_c = c;
330 }
331}
332
333/* obtain an (aligned) EGPRS data block with given bit-offset and
334 * bit-length from the parent buffer */
335static void get_egprs_data_block(const TTCN_Buffer& orig_ttcn_buffer, unsigned int offset_bits,
336 unsigned int length_bits, TTCN_Buffer& dst_ttcn_buffer)
337{
338 const unsigned int initial_spare_bits = 6;
339 unsigned char *aligned_buf = NULL;
340 size_t min_src_length_bytes = (offset_bits + length_bits + 7) / 8;
341 size_t length_bytes = (initial_spare_bits + length_bits + 7) / 8;
342 size_t accepted_len = length_bytes;
343
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200344 //fprintf(stderr, "RLMAC: trying to allocate %u bytes (orig is %zu bytes long with read pos %zu)\n", length_bytes, orig_ttcn_buffer.get_len(), orig_ttcn_buffer.get_pos());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200345 dst_ttcn_buffer.get_end(aligned_buf, accepted_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200346 if (accepted_len < length_bytes) {
347 fprintf(stderr, "RLMAC: ERROR! asked for %zu bytes but got %zu\n", length_bytes, accepted_len);
348 }
349
350 /* Copy the data out of the tvb to an aligned buffer */
351 clone_aligned_buffer_lsbf(
352 offset_bits - initial_spare_bits, length_bytes,
353 orig_ttcn_buffer.get_data(),
354 aligned_buf);
355
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200356 /* clear spare bits and move block header bits to the right */
357 aligned_buf[0] = aligned_buf[0] >> initial_spare_bits;
358
359 dst_ttcn_buffer.increase_length(length_bytes);
360}
361
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +0200362/* bit-shift the entire 'src' of length 'length_bytes'
363 * and store the result to caller-allocated 'buffer' by 'offset_bits'. The shifting is
364 * done lsb-first. */
365static void clone_unaligned_buffer_lsbf(unsigned int offset_bits, unsigned int length_bytes,
366 const uint8_t *src, uint8_t *buffer)
367{
368 unsigned int hdr_bytes;
369 unsigned int extra_bits;
370 unsigned int i;
371
372 uint8_t c, last_hdr_c, last_c;
373 uint8_t *dst;
374
375 hdr_bytes = offset_bits / 8;
376 extra_bits = offset_bits % 8;
377
378 //fprintf(stderr, "RLMAC: clone: hdr_bytes=%u extra_bits=%u (length_bytes=%u)\n", hdr_bytes, extra_bits, length_bytes);
379
380 if (extra_bits == 0) {
381 /* It is aligned already */
382 memcpy(buffer, src + hdr_bytes, length_bytes);
383 return;
384 }
385
386 /* Copy first header+data byte, it's not handled correctly by loop */
387 dst = buffer + hdr_bytes;
388 last_hdr_c = *dst;
389 last_c = *dst << (8 - extra_bits);
390
391 for (i = 0; i < length_bytes; i++) {
392 c = src[i];
393 *(dst++) = (last_c >> (8 - extra_bits)) | (c << extra_bits);
394 last_c = c;
395 }
396 /* overwrite the lower extra_bits */
397 *dst = (*dst & (0xff << extra_bits)) | (last_c >> (8 - extra_bits));
398
399 /* Copy back first header+data byte */
400 dst = buffer + hdr_bytes;
401 *(dst++) = last_hdr_c | (src[0] << (8 - extra_bits));
402 *dst |= (src[0] >> (extra_bits)) & (0xff >> (8 - extra_bits));
403}
404
405/* put an (aligned) EGPRS data block with given bit-offset and
406 * bit-length into parent buffer */
407static void put_egprs_data_block(const TTCN_Buffer& aligned_data_block_buffer, unsigned int offset_bits,
408 unsigned int length_bits, TTCN_Buffer& dst_ttcn_buffer)
409{
410 const unsigned int initial_spare_bits = 6;
411 unsigned char *unaligned_buf = NULL;
412 char tmpbuf[120];
413 int tmplen = dst_ttcn_buffer.get_len();
414 //size_t max_length_bytes = (initial_spare_bits + length_bits + 7) / 8;
415 size_t length_bytes = tmplen + aligned_data_block_buffer.get_len();
416 size_t accepted_len = length_bytes;
417
418 //fprintf(stderr, "RLMAC: trying to allocate %u bytes\n", length_bytes);
419
420 /* API .get_end() is the only one I could find to access writeable
421 memory in the buffer. It points to the end. Hence, we first copy
422 (readonly) data to tmpbuf and later clear() so that .get_end()
423 provides us with a pointer to the start of the buffer. */
424 memcpy(tmpbuf, dst_ttcn_buffer.get_data(), tmplen);
425 dst_ttcn_buffer.clear();
426 dst_ttcn_buffer.get_end(unaligned_buf, accepted_len);
427 if (accepted_len < tmplen) {
428 fprintf(stderr, "RLMAC: ERROR! asked for %zu bytes but got %zu\n", length_bytes, accepted_len);
429 }
430 memcpy(unaligned_buf, tmpbuf, tmplen);
431
432 /* Copy the data out of the tvb to an aligned buffer */
433 clone_unaligned_buffer_lsbf(
434 offset_bits - initial_spare_bits, length_bytes,
435 aligned_data_block_buffer.get_data(),
436 unaligned_buf);
437
438 dst_ttcn_buffer.increase_length(length_bytes);
439}
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200440
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +0100441/* Append padding bytes and spare bits at the end of ttcn_buffer, based on requested CS */
442static void encode_trailing_padding_spb(TTCN_Buffer& ttcn_buffer, CodingScheme cs)
443{
444 uint8_t buf[256]; /* enough to fit any RLCMAC buffer*/
445 uint32_t blk_len = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len(cs);
446 uint32_t blk_len_no_spb = RLCMAC__Templates::f__rlcmac__cs__mcs2block__len__no__spare__bits(cs);
447 uint32_t data_len = ttcn_buffer.get_len();
448
449 if (data_len > blk_len_no_spb) {
450 fprintf(stderr, "Buffer too large for requested CS! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
451 // TODO: throw exception?
452 }
453
454 for (int i = 0; i < blk_len_no_spb - data_len; i++)
455 buf[i] = 0x2b; /* Padding bits if needed */
456 for (int i = blk_len_no_spb - data_len; i < blk_len - data_len; i++)
457 buf[i] = 0x00; /* Spare bits if needed */
458
459 const OCTETSTRING& pad_octstr = OCTETSTRING(blk_len - data_len, buf);
460 ttcn_buffer.put_string(pad_octstr);
461}
462
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200463/////////////////////
464// DECODE
465/////////////////////
466
467/* DECODE DOWNLINK */
468
Harald Welte43e060a2017-07-30 22:38:03 +0200469RlcmacDlDataBlock dec__RlcmacDlDataBlock(const OCTETSTRING& stream)
470{
471 RlcmacDlDataBlock ret_val;
472 TTCN_Buffer ttcn_buffer(stream);
473 int num_llc_blocks = 0;
474
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100475 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
476
Harald Welte43e060a2017-07-30 22:38:03 +0200477 /* use automatic/generated decoder for header */
478 ret_val.mac__hdr().decode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
479
480 /* optional extension octets, containing LI+M+E of Llc blocks */
481 if (ret_val.mac__hdr().hdr__ext().e() == false) {
482 /* extension octet follows, i.e. optional Llc length octets */
483 while (1) {
484 /* decode one more extension octet with LlcBlocHdr inside */
485 LlcBlock lb;
Harald Welte439e5462018-03-08 23:21:17 +0100486 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Harald Welte43e060a2017-07-30 22:38:03 +0200487 ret_val.blocks()[num_llc_blocks++] = lb;
488
489 /* if E == '1'B, we can proceed further */
Harald Welte060e27a2018-03-03 20:38:19 +0100490 if (lb.hdr()().e() == true)
Harald Welte43e060a2017-07-30 22:38:03 +0200491 break;
492 }
493 }
494
495 /* RLC blocks at end */
496 if (ret_val.mac__hdr().hdr__ext().e() == true) {
497 LlcBlock lb;
498 unsigned int length = ttcn_buffer.get_read_len();
499 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
500 * fills the current RLC data block precisely or continues in the following in-sequence RLC
501 * data block */
502 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
503 ttcn_buffer.increase_pos(length);
504 ret_val.blocks()[0] = lb;
505 } else {
506 if (ret_val.blocks().is_bound()) {
507 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
Harald Welte060e27a2018-03-03 20:38:19 +0100508 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
Harald Welte43e060a2017-07-30 22:38:03 +0200509 if (length > ttcn_buffer.get_read_len())
510 length = ttcn_buffer.get_read_len();
511 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
512 ttcn_buffer.increase_pos(length);
513 }
514 }
515 }
516
517 return ret_val;
518}
519
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200520static
521EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type1(const OCTETSTRING& stream)
522{
523 EgprsDlMacDataHeader ret_val;
524
525 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
526
527 return ret_val;
528}
529
530static
531EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type2(const OCTETSTRING& stream)
532{
533 EgprsDlMacDataHeader ret_val;
534
535 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
536
537 return ret_val;
538}
539
540static
541EgprsDlMacDataHeader dec__EgprsDlMacDataHeader_type3(const OCTETSTRING& stream)
542{
543 TTCN_Buffer ttcn_buffer(stream);
544 EgprsDlMacDataHeader ret_val;
545 const struct gprs_rlc_dl_header_egprs_3 *egprs3;
546 uint8_t tmp;
547
548 egprs3 = static_cast<const struct gprs_rlc_dl_header_egprs_3 *>
549 ((const void *)ttcn_buffer.get_data());
550
551 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
552 ret_val.tfi() = egprs3->tfi_lo << 1 | egprs3->tfi_hi << 0;
553 ret_val.rrbp() = egprs3->rrbp;
554 tmp = egprs3->es_p;
555 ret_val.esp() = BITSTRING(2, &tmp);
556 ret_val.usf() = egprs3->usf;
557 ret_val.bsn1() = egprs3->bsn1_lo << 10 | egprs3->bsn1_mid << 2 | egprs3->bsn1_hi;
558 ret_val.bsn2__offset() = 0; /*TODO: mark optional and not set ? */
559 ret_val.pr() = egprs3->pr;
560 ret_val.spb() = egprs3->spb;
561 ret_val.cps() = egprs3->cps;
562
563 ttcn_buffer.increase_pos(sizeof(*egprs3));
564 return ret_val;
565}
566
567static
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100568RlcmacDlEgprsDataBlock dec__RlcmacDlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200569{
570 RlcmacDlEgprsDataBlock ret_val;
571 TTCN_Buffer ttcn_buffer(stream);
572 TTCN_Buffer aligned_buffer;
573 int num_llc_blocks = 0;
574 unsigned int data_block_bits, data_block_offsets[2];
575 unsigned int num_calls;
576 const uint8_t *ti_e;
577
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100578 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
579 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200580 case CodingScheme::MCS__0:
581 case CodingScheme::MCS__1:
582 case CodingScheme::MCS__2:
583 case CodingScheme::MCS__3:
584 case CodingScheme::MCS__4:
585 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type3(stream);
586 break;
587 case CodingScheme::MCS__5:
588 case CodingScheme::MCS__6:
589 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type2(stream);
590 break;
591 case CodingScheme::MCS__7:
592 case CodingScheme::MCS__8:
593 case CodingScheme::MCS__9:
594 ret_val.mac__hdr() = dec__EgprsDlMacDataHeader_type1(stream);
595 break;
596 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100597 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), false,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200598 &num_calls, &data_block_bits, data_block_offsets);
599 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
600
601 ti_e = aligned_buffer.get_read_data();
602 ret_val.fbi() = *ti_e & 0x02 ? true : false;
603 ret_val.e() = *ti_e & 0x01 ? true : false;
604 aligned_buffer.increase_pos(1);
605
606 /* optional extension octets, containing LI+E of Llc blocks */
607 if (ret_val.e() == false) {
608 /* extension octet follows, i.e. optional Llc length octets */
609 while (1) {
610 /* decode one more extension octet with LlcBlocHdr inside */
611 EgprsLlcBlock lb;
612 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
613 ret_val.blocks()[num_llc_blocks++] = lb;
614
615 /* if E == '1'B, we can proceed further */
616 if (lb.hdr()().e() == true)
617 break;
618 }
619 }
620
621 /* RLC blocks at end */
Pau Espin Pedrolcca530f2020-11-11 14:06:52 +0100622 if (ret_val.e() == true) {
623 EgprsLlcBlock lb;
624 unsigned int length = aligned_buffer.get_read_len();
625 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
626 * fills the current RLC data block precisely or continues in the following in-sequence RLC
627 * data block */
628 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
629 aligned_buffer.increase_pos(length);
630 ret_val.blocks()[0] = lb;
631 } else {
632 /* RLC blocks at end */
633 if (ret_val.blocks().is_bound()) {
634 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
635 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
636 if (length > aligned_buffer.get_read_len())
637 length = aligned_buffer.get_read_len();
638 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
639 aligned_buffer.increase_pos(length);
640 }
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200641 }
642 }
643
644 return ret_val;
645}
646
647RlcmacDlBlock dec__RlcmacDlBlock(const OCTETSTRING& stream)
648{
649 RlcmacDlBlock ret_val;
650 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100651 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200652 unsigned char pt;
653
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100654 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200655 case CodingScheme::CS__1:
656 case CodingScheme::CS__2:
657 case CodingScheme::CS__3:
658 case CodingScheme::CS__4:
659 pt = stream[0].get_octet() >> 6;
660 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
661 ret_val.data() = dec__RlcmacDlDataBlock(stream);
662 else
663 ret_val.ctrl() = dec__RlcmacDlCtrlBlock(stream);
664 break;
665 case CodingScheme::MCS__0:
666 case CodingScheme::MCS__1:
667 case CodingScheme::MCS__2:
668 case CodingScheme::MCS__3:
669 case CodingScheme::MCS__4:
670 case CodingScheme::MCS__5:
671 case CodingScheme::MCS__6:
672 case CodingScheme::MCS__7:
673 case CodingScheme::MCS__8:
674 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100675 ret_val.data__egprs() = dec__RlcmacDlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200676 break;
677 }
678 return ret_val;
679}
680
681/* DECODE UPLINK */
682
683RlcmacUlDataBlock dec__RlcmacUlDataBlock(const OCTETSTRING& stream)
684{
685 RlcmacUlDataBlock ret_val;
686 TTCN_Buffer ttcn_buffer(stream);
687 int num_llc_blocks = 0;
688
689 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
690 TTCN_Logger::log_event_str("==================================\n"
691 "dec_RlcmacUlDataBlock(): Stream before decoding: ");
692 stream.log();
693 TTCN_Logger::end_event();
694
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100695 ret_val.cs() = payload_len_2_coding_scheme(stream.lengthof());
696
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200697 /* use automatic/generated decoder for header */
698 ret_val.mac__hdr().decode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
699
700 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
701 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding hdr: ");
702 ttcn_buffer.log();
703 TTCN_Logger::end_event();
704 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
705 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding hdr: ");
706 ret_val.log();
707 TTCN_Logger::end_event();
708
709 /* Manually decoder remainder of ttcn_buffer, containing optional header octets,
710 * optional tlli, optional pfi and LLC Blocks */
711
712 /* optional extension octets, containing LI+M+E of Llc blocks */
713 if (ret_val.mac__hdr().e() == false) {
714 /* extension octet follows, i.e. optional Llc length octets */
715 while (1) {
716 /* decode one more extension octet with LlcBlocHdr inside */
717 LlcBlock lb;
718 lb.hdr()().decode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
719 ret_val.blocks()[num_llc_blocks++] = lb;
720
721 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
722 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream after decoding ExtOct: ");
723 ttcn_buffer.log();
724 TTCN_Logger::end_event();
725 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
726 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val after decoding ExtOct: ");
727 ret_val.log();
728 TTCN_Logger::end_event();
729
730 /* if E == '1'B, we can proceed further */
731 if (lb.hdr()().e() == true)
732 break;
733 }
734 }
735
736 /* parse optional TLLI */
737 if (ret_val.mac__hdr().tlli__ind()) {
738 ret_val.tlli() = OCTETSTRING(4, ttcn_buffer.get_read_data());
739 ttcn_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200740 } else {
741 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200742 }
743 /* parse optional PFI */
744 if (ret_val.mac__hdr().pfi__ind()) {
745 ret_val.pfi().decode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200746 } else {
747 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200748 }
749
750 /* RLC blocks at end */
751 if (ret_val.mac__hdr().e() == true) {
752 LlcBlock lb;
753 unsigned int length = ttcn_buffer.get_read_len();
754 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
755 * fills the current RLC data block precisely or continues in the following in-sequence RLC
756 * data block */
757 lb.payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
758 ttcn_buffer.increase_pos(length);
759 ret_val.blocks()[0] = lb;
760 } else {
761 if (ret_val.blocks().is_bound()) {
762 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
763 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
764 if (length > ttcn_buffer.get_read_len())
765 length = ttcn_buffer.get_read_len();
766 ret_val.blocks()[i].payload() = OCTETSTRING(length, ttcn_buffer.get_read_data());
767 ttcn_buffer.increase_pos(length);
768 }
769 }
770 }
771
772 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
773 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): Stream before return: ");
774 ttcn_buffer.log();
775 TTCN_Logger::end_event();
776 TTCN_Logger::begin_event(TTCN_Logger::DEBUG_ENCDEC);
777 TTCN_Logger::log_event_str("dec_RlcmacUlDataBlock(): ret_val before return: ");
778 ret_val.log();
779 TTCN_Logger::end_event();
780
781 return ret_val;
782}
783
784static
785EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type1(const OCTETSTRING& stream)
786{
787 EgprsUlMacDataHeader ret_val;
788
789 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
790
791 return ret_val;
792}
793
794static
795EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type2(const OCTETSTRING& stream)
796{
797 EgprsUlMacDataHeader ret_val;
798
799 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
800
801 return ret_val;
802}
803
804static
805EgprsUlMacDataHeader dec__EgprsUlMacDataHeader_type3(const OCTETSTRING& stream)
806{
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200807 TTCN_Buffer ttcn_buffer(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200808 EgprsUlMacDataHeader ret_val;
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200809 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
810 uint8_t tmp;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200811
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200812 egprs3 = static_cast<const struct gprs_rlc_ul_header_egprs_3 *>
813 ((const void *)ttcn_buffer.get_data());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200814
Pau Espin Pedrol0b8e22b2020-04-30 20:10:17 +0200815 ret_val.header__type() = EgprsHeaderType::RLCMAC__HDR__TYPE__3;
816 ret_val.tfi() = egprs3->tfi_lo << 2 | egprs3->tfi_hi << 0;
817 ret_val.countdown() = egprs3->cv;
818 tmp = egprs3->si;
819 ret_val.foi__si() = BITSTRING(1, &tmp);
820 tmp = egprs3->r;
821 ret_val.r__ri() = BITSTRING(1, &tmp);
822 ret_val.bsn1() = egprs3->bsn1_lo << 5 | egprs3->bsn1_hi << 0;
823 ret_val.cps() = egprs3->cps_lo << 2 | egprs3->cps_hi << 0;
824 ret_val.pfi__ind() = egprs3->pi;
825 tmp = egprs3->rsb;
826 ret_val.rsb() = BITSTRING(1, &tmp);
827 tmp = egprs3->spb;
828 ret_val.spb() = BITSTRING(2, &tmp);
829
830 ttcn_buffer.increase_pos(sizeof(*egprs3));
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200831 return ret_val;
832}
833
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100834RlcmacUlEgprsDataBlock dec__RlcmacUlEgprsDataBlock(const OCTETSTRING& stream)
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200835{
836 RlcmacUlEgprsDataBlock ret_val;
837 TTCN_Buffer ttcn_buffer(stream);
838 TTCN_Buffer aligned_buffer;
839 int num_llc_blocks = 0;
840 unsigned int data_block_bits, data_block_offsets[2];
841 unsigned int num_calls;
842 const uint8_t *ti_e;
843
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100844 ret_val.mcs() = payload_len_2_coding_scheme(stream.lengthof());
845 switch (ret_val.mcs()) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200846 case CodingScheme::MCS__1:
847 case CodingScheme::MCS__2:
848 case CodingScheme::MCS__3:
849 case CodingScheme::MCS__4:
850 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type3(stream);
851 break;
852 case CodingScheme::MCS__5:
853 case CodingScheme::MCS__6:
854 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type2(stream);
855 break;
856 case CodingScheme::MCS__7:
857 case CodingScheme::MCS__8:
858 case CodingScheme::MCS__9:
859 ret_val.mac__hdr() = dec__EgprsUlMacDataHeader_type1(stream);
860 break;
861 }
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100862 setup_rlc_mac_priv(ret_val.mcs(), ret_val.mac__hdr().header__type(), true,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200863 &num_calls, &data_block_bits, data_block_offsets);
864 get_egprs_data_block(ttcn_buffer, data_block_offsets[0], data_block_bits, aligned_buffer);
865
866 ti_e = aligned_buffer.get_read_data();
867 ret_val.tlli__ind() = *ti_e & 0x02 ? true : false;
868 ret_val.e() = *ti_e & 0x01 ? true : false;
869 aligned_buffer.increase_pos(1);
870
871 /* Manually decoder remainder of aligned_buffer, containing optional header octets,
872 * optional tlli, optional pfi and LLC Blocks */
873
874 /* optional extension octets, containing LI+M+E of Llc blocks */
875 if (ret_val.e() == false) {
876 /* extension octet follows, i.e. optional Llc length octets */
877 while (1) {
878 /* decode one more extension octet with LlcBlocHdr inside */
879 EgprsLlcBlock lb;
880 lb.hdr()().decode(EgprsLlcBlockHdr_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
881 ret_val.blocks()[num_llc_blocks++] = lb;
882
883 /* if E == '1'B, we can proceed further */
884 if (lb.hdr()().e() == true)
885 break;
886 }
887 }
888
889 /* parse optional TLLI */
890 if (ret_val.tlli__ind()) {
891 ret_val.tlli() = OCTETSTRING(4, aligned_buffer.get_read_data());
892 aligned_buffer.increase_pos(4);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200893 } else {
894 ret_val.tlli() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200895 }
896 /* parse optional PFI */
897 if (ret_val.mac__hdr().pfi__ind()) {
Pau Espin Pedrol331f5252020-04-30 20:05:29 +0200898 ret_val.pfi().decode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrola2c5b6e2020-04-30 19:59:13 +0200899 } else {
900 ret_val.pfi() = OMIT_VALUE;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200901 }
902
903 /* RLC blocks at end */
904 if (ret_val.e() == true) {
905 EgprsLlcBlock lb;
906 unsigned int length = aligned_buffer.get_read_len();
907 /* LI not present: The Upper Layer PDU that starts with the current RLC data block either
908 * fills the current RLC data block precisely or continues in the following in-sequence RLC
909 * data block */
910 lb.payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
911 aligned_buffer.increase_pos(length);
912 ret_val.blocks()[0] = lb;
913 } else {
914 if (ret_val.blocks().is_bound()) {
915 for (int i = 0; i < ret_val.blocks().size_of(); i++) {
916 unsigned int length = ret_val.blocks()[i].hdr()().length__ind();
917 if (length > aligned_buffer.get_read_len())
918 length = aligned_buffer.get_read_len();
919 ret_val.blocks()[i].payload() = OCTETSTRING(length, aligned_buffer.get_read_data());
920 aligned_buffer.increase_pos(length);
921 }
922 }
923 }
924
925 return ret_val;
926}
927
928RlcmacUlBlock dec__RlcmacUlBlock(const OCTETSTRING& stream)
929{
930 RlcmacUlBlock ret_val;
931 size_t stream_len = stream.lengthof();
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100932 CodingScheme::enum_type cs_mcs = payload_len_2_coding_scheme(stream_len);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200933 unsigned char pt;
934
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100935 switch (cs_mcs) {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200936 case CodingScheme::CS__1:
937 case CodingScheme::CS__2:
938 case CodingScheme::CS__3:
939 case CodingScheme::CS__4:
940 pt = stream[0].get_octet() >> 6;
941 if (pt == MacPayloadType::MAC__PT__RLC__DATA)
942 ret_val.data() = dec__RlcmacUlDataBlock(stream);
943 else
944 ret_val.ctrl() = dec__RlcmacUlCtrlBlock(stream);
945 break;
946 case CodingScheme::MCS__1:
947 case CodingScheme::MCS__2:
948 case CodingScheme::MCS__3:
949 case CodingScheme::MCS__4:
950 case CodingScheme::MCS__5:
951 case CodingScheme::MCS__6:
952 case CodingScheme::MCS__7:
953 case CodingScheme::MCS__8:
954 case CodingScheme::MCS__9:
Pau Espin Pedrol5abfded2020-11-03 17:30:44 +0100955 ret_val.data__egprs() = dec__RlcmacUlEgprsDataBlock(stream);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +0200956 break;
957 }
958
959 return ret_val;
960}
961
962
963/////////////////////
964// ENCODE
965/////////////////////
966
967/* ENCODE DOWNLINK */
968
969OCTETSTRING enc__RlcmacDlDataBlock(const RlcmacDlDataBlock& si)
970{
971 RlcmacDlDataBlock in = si;
972 OCTETSTRING ret_val;
973 TTCN_Buffer ttcn_buffer;
974 int i;
975
976 /* Fix 'e' bit of initial header based on following blocks */
977 if (!in.blocks().is_bound() ||
978 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
979 in.mac__hdr().hdr__ext().e() = true;
980 else
981 in.mac__hdr().hdr__ext().e() = false;
982
983 /* use automatic/generated decoder for header */
984 in.mac__hdr().encode(DlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
985
986 /* Add LI octets, if any */
987 if (in.blocks().is_bound() &&
988 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
989 /* first write LI octets */
990 for (i = 0; i < in.blocks().size_of(); i++) {
991 /* fix the 'E' bit in case it is not clear */
992 if (i < in.blocks().size_of()-1)
993 in.blocks()[i].hdr()().e() = false;
994 else
995 in.blocks()[i].hdr()().e() = true;
996 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
997 }
998 }
999 if (in.blocks().is_bound()) {
1000 for (i = 0; i < in.blocks().size_of(); i++) {
1001 if (!in.blocks()[i].is_bound())
1002 continue;
1003 ttcn_buffer.put_string(in.blocks()[i].payload());
1004 }
1005 }
1006
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001007 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1008
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001009 ttcn_buffer.get_string(ret_val);
1010 return ret_val;
1011}
1012
1013static
1014void enc__RlcmacDlEgprsDataHeader_type1(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1015{
1016 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1017}
1018
1019static
1020void enc__RlcmacDlEgprsDataHeader_type2(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1021{
1022 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1023}
1024
1025static
1026void enc__RlcmacDlEgprsDataHeader_type3(const EgprsDlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1027{
1028 fprintf(stderr, "FIXME: Not implemented! %s (%s:%u)\n", __func__, __FILE__, __LINE__);
1029}
1030
1031OCTETSTRING enc__RlcmacDlEgprsDataBlock(const RlcmacDlEgprsDataBlock& si)
1032{
1033 RlcmacDlEgprsDataBlock in = si;
1034 OCTETSTRING ret_val;
1035 TTCN_Buffer ttcn_buffer;
1036 int i;
1037
1038 /* Fix 'e' bit of initial header based on following blocks */
1039 if (!in.blocks().is_bound() ||
1040 (in.blocks().size_of() == 1 && !in.blocks()[0].hdr().is_bound()))
1041 in.e() = true;
1042 else
1043 in.e() = false;
1044
1045 switch (in.mac__hdr().header__type()) {
1046 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
1047 enc__RlcmacDlEgprsDataHeader_type1(si.mac__hdr(), ttcn_buffer);
1048 break;
1049 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
1050 enc__RlcmacDlEgprsDataHeader_type2(si.mac__hdr(), ttcn_buffer);
1051 break;
1052 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
1053 enc__RlcmacDlEgprsDataHeader_type3(si.mac__hdr(), ttcn_buffer);
1054 default:
1055 break; /* TODO: error */
1056 }
1057
1058 /* Add LI octets, if any */
1059 if (in.blocks().is_bound() &&
1060 (in.blocks().size_of() != 1 || in.blocks()[0].hdr().is_bound())) {
1061 /* first write LI octets */
1062 for (i = 0; i < in.blocks().size_of(); i++) {
1063 /* fix the 'E' bit in case it is not clear */
1064 if (i < in.blocks().size_of()-1)
1065 in.blocks()[i].hdr()().e() = false;
1066 else
1067 in.blocks()[i].hdr()().e() = true;
1068 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1069 }
1070 }
1071 if (in.blocks().is_bound()) {
1072 for (i = 0; i < in.blocks().size_of(); i++) {
1073 if (!in.blocks()[i].is_bound())
1074 continue;
1075 ttcn_buffer.put_string(in.blocks()[i].payload());
1076 }
1077 }
1078
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001079 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1080
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001081 ttcn_buffer.get_string(ret_val);
1082 return ret_val;
1083}
1084
1085OCTETSTRING enc__RlcmacDlBlock(const RlcmacDlBlock& si)
1086{
1087 if (si.ischosen(RlcmacDlBlock::ALT_data__egprs))
1088 return enc__RlcmacDlEgprsDataBlock(si.data__egprs());
1089 else if (si.ischosen(RlcmacDlBlock::ALT_data))
1090 return enc__RlcmacDlDataBlock(si.data());
1091 else
1092 return enc__RlcmacDlCtrlBlock(si.ctrl());
1093}
1094
1095/* ENCODE UPLINK */
Harald Welte43e060a2017-07-30 22:38:03 +02001096
1097OCTETSTRING enc__RlcmacUlDataBlock(const RlcmacUlDataBlock& si)
1098{
1099 RlcmacUlDataBlock in = si;
1100 OCTETSTRING ret_val;
1101 TTCN_Buffer ttcn_buffer;
1102 int i;
1103
Harald Welte060e27a2018-03-03 20:38:19 +01001104 if (!in.blocks().is_bound()) {
Pau Espin Pedrolecaeb892020-04-30 19:58:15 +02001105 /* we don't have any blocks: Add length value (zero) */
Harald Welte060e27a2018-03-03 20:38:19 +01001106 in.mac__hdr().e() = false; /* E=0: extension octet follows */
1107 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1108 /* If there's only a single block, and that block has no HDR value defined, */
1109 in.mac__hdr().e() = true; /* E=0: extension octet follows */
1110 } else {
1111 /* Length value */
Harald Welte43e060a2017-07-30 22:38:03 +02001112 in.mac__hdr().e() = false;
Harald Welte060e27a2018-03-03 20:38:19 +01001113 }
Harald Welte43e060a2017-07-30 22:38:03 +02001114
1115 /* Fix other presence indications */
Harald Welte2072ab62017-07-31 18:33:35 +02001116 in.mac__hdr().tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1117 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
Harald Welte43e060a2017-07-30 22:38:03 +02001118
Harald Welte060e27a2018-03-03 20:38:19 +01001119 /* use automatic/generated encoder for header */
Harald Welte43e060a2017-07-30 22:38:03 +02001120 in.mac__hdr().encode(UlMacDataHeader_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1121
Harald Welte060e27a2018-03-03 20:38:19 +01001122 if (in.mac__hdr().e() == false) {
1123 /* Add LI octets, if any */
1124 if (!in.blocks().is_bound()) {
1125 ttcn_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
1126 } else {
1127 for (i = 0; i < in.blocks().size_of(); i++) {
1128#if 0
1129 /* check for penultimate block */
1130 if (i == in.blocks().size_of()-2) {
1131 /* if last block has no header, no more LI */
1132 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1133 in.blocks()[i].hdr()().more() = true;
1134 } else {
1135 /* header present, we have to encode LI */
1136 in.blocks()[i].hdr()().more() = false;
1137 in.blocks()[i].hdr()().length__ind() =
1138 in.blocks()[i+1].payload().lengthof();
1139 }
1140 } else if (i < in.blocks().size_of()-2) {
1141 /* one of the first blocks, before the penultimate or last */
1142 in.blocks()[i].hdr()().e() = false; /* LI present */
1143 /* re-compute length */
1144 in.blocks()[i].hdr()().length__ind() =
1145 in.blocks()[i+1].payload().lengthof();
1146 }
1147 /* Encode LI octet if E=0 */
1148 }
1149#endif
1150 if (in.blocks()[i].hdr() != OMIT_VALUE) {
1151 in.blocks()[i].hdr()().encode(LlcBlockHdr_descr_, ttcn_buffer,
1152 TTCN_EncDec::CT_RAW);
1153 }
1154 }
Harald Welte43e060a2017-07-30 22:38:03 +02001155 }
1156 }
1157
1158 if (in.mac__hdr().tlli__ind()) {
Harald Welteacc93ab2018-03-02 21:39:09 +01001159 ttcn_buffer.put_string(in.tlli());
Harald Welte43e060a2017-07-30 22:38:03 +02001160 }
1161
1162 if (in.mac__hdr().pfi__ind()) {
1163 in.pfi().encode(RlcmacUlDataBlock_pfi_descr_, ttcn_buffer, TTCN_EncDec::CT_RAW);
1164 }
1165
1166 if (in.blocks().is_bound()) {
1167 for (i = 0; i < in.blocks().size_of(); i++) {
1168 if (!in.blocks()[i].is_bound())
1169 continue;
1170 ttcn_buffer.put_string(in.blocks()[i].payload());
1171 }
1172 }
1173
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001174 encode_trailing_padding_spb(ttcn_buffer, in.cs());
1175
Harald Welte43e060a2017-07-30 22:38:03 +02001176 ttcn_buffer.get_string(ret_val);
1177 return ret_val;
1178}
1179
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001180static
1181void enc__RlcmacUlEgprsDataHeader_type1(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
Harald Welte43e060a2017-07-30 22:38:03 +02001182{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001183 struct gprs_rlc_ul_header_egprs_1 egprs1;
1184
1185 egprs1.r = bs2uint8(si.r__ri());
1186 egprs1.si = bs2uint8(si.foi__si());
1187 egprs1.cv = si.countdown();
1188 egprs1.tfi_hi = si.tfi() >> 0;
1189 egprs1.tfi_lo = si.tfi() >> 2;
1190 egprs1.bsn1_hi = si.bsn1() >> 0;
1191 egprs1.bsn1_lo = si.bsn1() >> 5;
1192 egprs1.bsn2_hi = si.bsn2__offset() >> 0;
1193 egprs1.bsn2_lo = si.bsn2__offset() >> 2;
1194 egprs1.cps = si.cps();
1195 egprs1.rsb = bs2uint8(si.rsb());
1196 egprs1.pi = si.pfi__ind();
1197 egprs1.spare_hi = 0;
1198 egprs1.spare_lo = 0;
1199 egprs1.dummy = 0;
1200
1201 ttcn_buffer.put_s(sizeof(egprs1), (const unsigned char *)&egprs1);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001202}
Harald Welte43e060a2017-07-30 22:38:03 +02001203
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001204static
1205void enc__RlcmacUlEgprsDataHeader_type2(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1206{
Pau Espin Pedrol081b1682020-11-06 17:15:52 +01001207 struct gprs_rlc_ul_header_egprs_2 egprs2;
1208
1209 egprs2.r = bs2uint8(si.r__ri());
1210 egprs2.si = bs2uint8(si.foi__si());
1211 egprs2.cv = si.countdown();
1212 egprs2.tfi_hi = si.tfi() >> 0;
1213 egprs2.tfi_lo = si.tfi() >> 2;
1214 egprs2.bsn1_hi = si.bsn1() >> 0;
1215 egprs2.bsn1_lo = si.bsn1() >> 5;
1216 egprs2.cps_hi = si.cps() >> 0;
1217 egprs2.cps_lo = si.cps() >> 2;
1218 egprs2.rsb = bs2uint8(si.rsb());
1219 egprs2.pi = si.pfi__ind();
1220 egprs2.spare_hi = 0;
1221 egprs2.spare_lo = 0;
1222 egprs2.dummy = 0;
1223
1224 ttcn_buffer.put_s(sizeof(egprs2), (const unsigned char *)&egprs2);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001225}
Harald Welte43e060a2017-07-30 22:38:03 +02001226
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001227static
1228void enc__RlcmacUlEgprsDataHeader_type3(const EgprsUlMacDataHeader& si, TTCN_Buffer& ttcn_buffer)
1229{
1230 struct gprs_rlc_ul_header_egprs_3 egprs3;
Harald Welte43e060a2017-07-30 22:38:03 +02001231
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001232 egprs3.r = bs2uint8(si.r__ri());
1233 egprs3.si = bs2uint8(si.foi__si());
1234 egprs3.cv = si.countdown();
1235 egprs3.tfi_hi = si.tfi() >> 0;
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001236 egprs3.tfi_lo = si.tfi() >> 2;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001237 egprs3.bsn1_hi = si.bsn1() >> 0;
1238 egprs3.bsn1_lo = si.bsn1() >> 5;
1239 egprs3.cps_hi = si.cps() >> 0;
1240 egprs3.cps_lo = si.cps() >> 2;
1241 egprs3.spb = bs2uint8(si.spb());
Pau Espin Pedrold3da7972020-04-30 20:06:52 +02001242 egprs3.rsb = bs2uint8(si.rsb());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001243 egprs3.pi = si.pfi__ind();
1244 egprs3.spare = 0;
1245 egprs3.dummy = 0;
Harald Welte43e060a2017-07-30 22:38:03 +02001246
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001247 ttcn_buffer.put_s(sizeof(egprs3), (const unsigned char *)&egprs3);
1248}
Harald Welte43e060a2017-07-30 22:38:03 +02001249
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001250OCTETSTRING enc__RlcmacUlEgprsDataBlock(const RlcmacUlEgprsDataBlock& si)
1251{
1252 RlcmacUlEgprsDataBlock in = si;
1253 OCTETSTRING ret_val;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001254 TTCN_Buffer ttcn_buffer, aligned_buffer;
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001255 int i;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001256 unsigned int data_block_bits, data_block_offsets[2];
1257 unsigned int num_calls;
1258 CodingScheme mcs;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001259
1260 mcs = RLCMAC__Templates::f__rlcmac__cps__htype__to__mcs(in.mac__hdr().cps(), in.mac__hdr().header__type());
1261 //fprintf(stderr, "RLCMAC: infered MCS %s (%d)\n", mcs.enum_to_str(static_cast<CodingScheme::enum_type>(mcs.as_int())), mcs.as_int());
Harald Welte43e060a2017-07-30 22:38:03 +02001262
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001263 if (!in.blocks().is_bound()) {
1264 /* we don't have nay blocks: Add length value (zero) */
1265 in.e() = false; /* E=0: extension octet follows */
1266 } else if (in.blocks().size_of() == 1 && in.blocks()[0].hdr() == OMIT_VALUE) {
1267 /* If there's only a single block, and that block has no HDR value defined, */
1268 in.e() = true; /* E=0: extension octet follows */
Harald Welte43e060a2017-07-30 22:38:03 +02001269 } else {
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001270 /* Length value */
1271 in.e() = false;
1272 }
1273
1274 /* Fix other presence indications */
1275 in.tlli__ind() = in.tlli().is_bound() && in.tlli() != OMIT_VALUE;
1276 in.mac__hdr().pfi__ind() = in.pfi().is_bound() && in.pfi() != OMIT_VALUE;
1277
1278 switch (in.mac__hdr().header__type()) {
1279 case EgprsHeaderType::RLCMAC__HDR__TYPE__1:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001280 enc__RlcmacUlEgprsDataHeader_type1(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001281 break;
1282 case EgprsHeaderType::RLCMAC__HDR__TYPE__2:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001283 enc__RlcmacUlEgprsDataHeader_type2(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001284 break;
1285 case EgprsHeaderType::RLCMAC__HDR__TYPE__3:
Pau Espin Pedrol82d22bc2020-04-30 20:09:12 +02001286 enc__RlcmacUlEgprsDataHeader_type3(in.mac__hdr(), ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001287 default:
1288 break; /* TODO: error */
1289 }
1290
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001291 /* Put first TI + E byte */
Pau Espin Pedrol563bcd62020-11-06 19:51:23 +01001292 aligned_buffer.put_c((in.tlli__ind() & 0x01) << 1 | (in.e() & 0x01) << 0);
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001293 //printbuffer("After encoding first byte", aligned_buffer);
1294
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001295 if (in.e() == false) {
1296 /* Add LI octets, if any */
1297 if (!in.blocks().is_bound()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001298 aligned_buffer.put_c(0x01); /* M=0, E=1 LEN=0 */
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001299 } else {
1300 for (i = 0; i < in.blocks().size_of(); i++) {
1301#if 0
1302 /* check for penultimate block */
1303 if (i == in.blocks().size_of()-2) {
1304 /* if last block has no header, no more LI */
1305 if (in.blocks()[i+1].hdr() == OMIT_VALUE) {
1306 in.blocks()[i].hdr()().more() = true;
1307 } else {
1308 /* header present, we have to encode LI */
1309 in.blocks()[i].hdr()().more() = false;
1310 in.blocks()[i].hdr()().length__ind() =
1311 in.blocks()[i+1].payload().lengthof();
1312 }
1313 } else if (i < in.blocks().size_of()-2) {
1314 /* one of the first blocks, before the penultimate or last */
1315 in.blocks()[i].hdr()().e() = false; /* LI present */
1316 /* re-compute length */
1317 in.blocks()[i].hdr()().length__ind() =
1318 in.blocks()[i+1].payload().lengthof();
1319 }
1320 /* Encode LI octet if E=0 */
1321 }
1322#endif
1323 if (in.blocks()[i].hdr() != OMIT_VALUE) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001324 in.blocks()[i].hdr()().encode(EgprsLlcBlockHdr_descr_, aligned_buffer,
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001325 TTCN_EncDec::CT_RAW);
1326 }
Harald Welte43e060a2017-07-30 22:38:03 +02001327 }
1328 }
1329 }
1330
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001331
1332
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001333 if (in.tlli__ind()) {
Pau Espin Pedrola05b2bc2020-11-06 20:38:21 +01001334 /* The TLLI is encoded in little endian for EGPRS (see
1335 * TS 44.060, figure 10.3a.2.1, note 2) */
1336 OCTETSTRING tlli = in.tlli();
1337 aligned_buffer.put_c(tlli[3].get_octet());
1338 aligned_buffer.put_c(tlli[2].get_octet());
1339 aligned_buffer.put_c(tlli[1].get_octet());
1340 aligned_buffer.put_c(tlli[0].get_octet());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001341 }
Harald Welte43e060a2017-07-30 22:38:03 +02001342
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001343 if (in.mac__hdr().pfi__ind()) {
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001344 in.pfi().encode(RlcmacUlEgprsDataBlock_pfi_descr_, aligned_buffer, TTCN_EncDec::CT_RAW);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001345 }
1346
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001347 //printbuffer("Before encoding EgprsLlc payload", aligned_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001348 if (in.blocks().is_bound()) {
1349 for (i = 0; i < in.blocks().size_of(); i++) {
1350 if (!in.blocks()[i].is_bound())
1351 continue;
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001352 aligned_buffer.put_string(in.blocks()[i].payload());
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001353 }
1354 }
Pau Espin Pedrol2456dad2020-04-30 20:22:38 +02001355 //printbuffer("After encoding EgprsLlc payload", aligned_buffer);
1356
1357 setup_rlc_mac_priv(mcs, in.mac__hdr().header__type(), true,
1358 &num_calls, &data_block_bits, data_block_offsets);
1359 //printbuffer("before merging data block", ttcn_buffer);
1360 put_egprs_data_block(aligned_buffer, data_block_offsets[0], data_block_bits, ttcn_buffer);
1361 //printbuffer("after merging data block", ttcn_buffer);
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001362
Pau Espin Pedrolcb00c522020-11-06 19:52:05 +01001363 encode_trailing_padding_spb(ttcn_buffer, in.mcs());
1364
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001365 ttcn_buffer.get_string(ret_val);
Harald Welte43e060a2017-07-30 22:38:03 +02001366 return ret_val;
1367}
1368
Harald Welte78a1af62017-07-31 17:33:56 +02001369OCTETSTRING enc__RlcmacUlBlock(const RlcmacUlBlock& si)
1370{
Pau Espin Pedrol372af7a2020-04-27 17:32:01 +02001371 if (si.ischosen(RlcmacUlBlock::ALT_data__egprs))
1372 return enc__RlcmacUlEgprsDataBlock(si.data__egprs());
1373 else if (si.ischosen(RlcmacUlBlock::ALT_data))
Harald Welte78a1af62017-07-31 17:33:56 +02001374 return enc__RlcmacUlDataBlock(si.data());
1375 else
1376 return enc__RlcmacUlCtrlBlock(si.ctrl());
1377}
1378
Harald Welte43e060a2017-07-30 22:38:03 +02001379} // namespace