blob: 7c20c48832d66574ceb9e0364595d45c345d4ad8 [file] [log] [blame]
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +02001/* decoding
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
4 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20#include <decoding.h>
21#include <rlc.h>
22#include <gprs_debug.h>
23
Jacob Erlbeck4abc6862015-12-08 15:14:05 +010024extern "C" {
25#include <osmocom/core/utils.h>
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +010026#if WITH_CRBB_DECODING
27#include <osmocom/core/bitcomp.h>
28#endif
Jacob Erlbeck4abc6862015-12-08 15:14:05 +010029}
30
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +020031#include <arpa/inet.h>
32
33#include <errno.h>
34#include <string.h>
35
Jacob Erlbeck4abc6862015-12-08 15:14:05 +010036#define LENGTH_TO_END 255
37/*
38 * \returns num extensions fields (num frames == offset) on success,
39 * -errno otherwise.
40 */
41static int parse_extensions_egprs(const uint8_t *data, unsigned int data_len,
42 unsigned int *offs,
43 bool is_last_block,
44 Decoding::RlcData *chunks, unsigned int chunks_size)
45{
46 const struct rlc_li_field_egprs *li;
47 uint8_t e;
48 unsigned int num_chunks = 0;
Jacob Erlbeck4abc6862015-12-08 15:14:05 +010049
50 e = 0;
51 while (!e) {
52 if (*offs > data_len) {
53 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
54 "but no more data\n");
55 return -EINVAL;
56 }
57
58 /* get new E */
59 li = (struct rlc_li_field_egprs *)&data[*offs];
60 e = li->e;
61 *offs += 1;
62
63 if (!chunks)
64 continue;
65
66 if (num_chunks == chunks_size) {
67 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
68 "but no more chunks possible\n");
69 return -ENOSPC;
70 }
71 if (li->li == 0 && num_chunks == 0 && li->e == 0) {
72 /* TS 44.060, table 10.4.14a.1, row 2a */
73 chunks[num_chunks].length = 0;
74 chunks[num_chunks].is_complete = true;
75 } else if (li->li == 0 && num_chunks == 0 && li->e == 1) {
76 /* TS 44.060, table 10.4.14a.1, row 4 */
Jacob Erlbeck4abc6862015-12-08 15:14:05 +010077 chunks[num_chunks].length = LENGTH_TO_END;
78 chunks[num_chunks].is_complete = is_last_block;
79 } else if (li->li == 127 && li->e == 1) {
80 /* TS 44.060, table 10.4.14a.1, row 3 & 5 */
81 /* only filling bytes left */
82 break;
83 } else if (li->li > 0) {
84 /* TS 44.060, table 10.4.14a.1, row 1 & 2b */
85 chunks[num_chunks].length = li->li;
86 chunks[num_chunks].is_complete = true;
87 } else {
88 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI contains "
89 "invalid extension octet: LI=%d, E=%d, count=%d\n",
90 li->li, li->e, num_chunks);
91 return -EINVAL;
92 }
93
94 num_chunks += 1;
95
96 if (e == 1) {
97 /* There is space after the last chunk, add a final one */
98 if (num_chunks == chunks_size) {
99 LOGP(DRLCMACUL, LOGL_NOTICE,
100 "UL DATA LI possibly extended, "
101 "but no more chunks possible\n");
102 return -ENOSPC;
103 }
104
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100105 chunks[num_chunks].length = LENGTH_TO_END;
106 chunks[num_chunks].is_complete = is_last_block;
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100107 num_chunks += 1;
108 }
109 }
110
111 return num_chunks;
112}
113
114static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
115 unsigned int *offs,
116 bool is_last_block,
117 Decoding::RlcData *chunks, unsigned int chunks_size)
118{
119 const struct rlc_li_field *li;
120 uint8_t m, e;
121 unsigned int num_chunks = 0;
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100122
123 e = 0;
124 while (!e) {
125 if (*offs > data_len) {
126 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
127 "but no more data\n");
128 return -EINVAL;
129 }
130
131 /* get new E */
132 li = (const struct rlc_li_field *)&data[*offs];
133 e = li->e;
134 m = li->m;
135 *offs += 1;
136
137 if (li->li == 0) {
138 /* TS 44.060, 10.4.14, par 6 */
139 e = 1;
140 m = 0;
141 }
142
143 /* TS 44.060, table 10.4.13.1 */
144 if (m == 0 && e == 0) {
145 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA "
146 "ignored, because M='0' and E='0'.\n");
147 return 0;
148 }
149
150 if (!chunks)
151 continue;
152
153 if (num_chunks == chunks_size) {
154 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
155 "but no more chunks possible\n");
156 return -ENOSPC;
157 }
158
159 if (li->li == 0)
160 /* e is 1 here */
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100161 chunks[num_chunks].length = LENGTH_TO_END;
162 else
163 chunks[num_chunks].length = li->li;
164
165 chunks[num_chunks].is_complete = li->li || is_last_block;
166
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100167 num_chunks += 1;
168
169 if (e == 1 && m == 1) {
170 if (num_chunks == chunks_size) {
171 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
172 "but no more chunks possible\n");
173 return -ENOSPC;
174 }
175 /* TS 44.060, 10.4.13.1, row 4 */
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100176 chunks[num_chunks].length = LENGTH_TO_END;
177 chunks[num_chunks].is_complete = is_last_block;
178 num_chunks += 1;
179 }
180 }
181
182 return num_chunks;
183}
184
185int Decoding::rlc_data_from_ul_data(
Jacob Erlbeckf2ba4cb2016-01-07 18:59:28 +0100186 const struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs,
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100187 const uint8_t *data, RlcData *chunks, unsigned int chunks_size,
188 uint32_t *tlli)
189{
190 uint8_t e;
191 unsigned int data_len = rdbi->data_len;
Jacob Erlbeckead5e472016-01-08 10:14:50 +0100192 int num_chunks = 0, i;
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100193 unsigned int offs = 0;
194 bool is_last_block = (rdbi->cv == 0);
195
196 if (!chunks)
197 chunks_size = 0;
198
199 e = rdbi->e;
200 if (e) {
201 if (chunks_size > 0) {
202 chunks[num_chunks].offset = offs;
203 chunks[num_chunks].length = LENGTH_TO_END;
204 chunks[num_chunks].is_complete = is_last_block;
205 num_chunks += 1;
206 } else if (chunks) {
207 LOGP(DRLCMACUL, LOGL_NOTICE, "No extension, "
208 "but no more chunks possible\n");
209 return -ENOSPC;
210 }
211 } else if (cs.isEgprs()) {
212 /* if E is not set (LI follows), EGPRS */
213 num_chunks = parse_extensions_egprs(data, data_len, &offs,
214 is_last_block,
215 chunks, chunks_size);
216 } else {
217 /* if E is not set (LI follows), GPRS */
218 num_chunks = parse_extensions_gprs(data, data_len, &offs,
219 is_last_block,
220 chunks, chunks_size);
221 }
222
Jacob Erlbeckead5e472016-01-08 10:14:50 +0100223 if (num_chunks < 0)
224 return num_chunks;
225
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100226 /* TLLI */
227 if (rdbi->ti) {
228 uint32_t tlli_enc;
229 if (offs + 4 > data_len) {
230 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of block "
231 "border\n");
232 return -EINVAL;
233 }
234
235 memcpy(&tlli_enc, data + offs, sizeof(tlli_enc));
236 if (cs.isGprs())
237 /* The TLLI is encoded in big endian for GPRS (see
238 * TS 44.060, figure 10.2.2.1, note) */
239 *tlli = be32toh(tlli_enc);
240 else
241 /* The TLLI is encoded in little endian for EGPRS (see
242 * TS 44.060, figure 10.3a.2.1, note 2) */
243 *tlli = le32toh(tlli_enc);
244
245 offs += sizeof(tlli_enc);
246 } else {
247 *tlli = 0;
248 }
249
250 /* PFI */
251 if (rdbi->pi) {
252 LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, "
253 "please disable in SYSTEM INFORMATION\n");
254 return -ENOTSUP;
255
256 /* TODO: Skip all extensions with E=0 (see TS 44.060, 10.4.11 */
257 }
258
Jacob Erlbeckead5e472016-01-08 10:14:50 +0100259 if (chunks_size == 0)
260 return num_chunks;
261
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100262 /* LLC */
263 for (i = 0; i < num_chunks; i++) {
264 chunks[i].offset = offs;
265 if (chunks[i].length == LENGTH_TO_END) {
266 if (offs == data_len) {
267 /* There is no place for an additional chunk,
268 * so drop it (this may happen with EGPRS since
269 * there is no M flag. */
270 num_chunks -= 1;
271 break;;
272 }
273 chunks[i].length = data_len - offs;
274 }
275 offs += chunks[i].length;
276 if (offs > data_len) {
277 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA out of block "
278 "border, chunk idx: %d, size: %d\n",
279 i, chunks[i].length);
280 return -EINVAL;
281 }
282 }
283
284 return num_chunks;
285}
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200286
Holger Hans Peter Freytherfcbc7022013-10-26 17:38:37 +0200287uint8_t Decoding::get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
288{
289 int i;
290
291 for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
292 if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
293 continue;
294 if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_GPRS_multislot_class)
295 continue;
296 return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.GPRS_multislot_class;
297 }
298
299 return 0;
300}
301
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200302uint8_t Decoding::get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
303{
304 int i;
305
306 for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
307 if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
308 continue;
309 if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_EGPRS_multislot_class)
310 continue;
311 return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.EGPRS_multislot_class;
312 }
313
314 return 0;
315}
316
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100317/**
318 * show_rbb needs to be an array with 65 elements
Daniel Willmann5e94cd42013-12-11 20:11:16 +0100319 * The index of the array is the bit position in the rbb
320 * (show_rbb[63] relates to BSN ssn-1)
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100321 */
322void Decoding::extract_rbb(const uint8_t *rbb, char *show_rbb)
323{
Daniel Willmann5e94cd42013-12-11 20:11:16 +0100324 for (int i = 0; i < 64; i++) {
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100325 uint8_t bit;
326
Daniel Willmann5e94cd42013-12-11 20:11:16 +0100327 bit = !!(rbb[i/8] & (1<<(7-i%8)));
Daniel Willmann6f7cb2c2013-12-11 14:25:20 +0100328 show_rbb[i] = bit ? 'R' : 'I';
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100329 }
330
331 show_rbb[64] = '\0';
332}
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100333
Jacob Erlbeckf2ba4cb2016-01-07 18:59:28 +0100334int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc,
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100335 const uint8_t *data, GprsCodingScheme cs)
336{
337 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
338 const struct rlc_ul_header *gprs;
339 unsigned int e_ti_header;
340 unsigned int cur_bit = 0;
341 unsigned int data_len = 0;
342
343 rlc->cs = cs;
344
345 data_len = cs.maxDataBlockBytes();
346
347 switch(cs.headerTypeData()) {
348 case GprsCodingScheme::HEADER_GPRS_DATA:
349 gprs = static_cast<struct rlc_ul_header *>
350 ((void *)data);
351 rlc->r = gprs->r;
352 rlc->si = gprs->si;
353 rlc->tfi = gprs->tfi;
354 rlc->cps = 0;
355 rlc->rsb = 0;
356
357 rlc->num_data_blocks = 1;
358 rlc->block_info[0].cv = gprs->cv;
359 rlc->block_info[0].pi = gprs->pi;
360 rlc->block_info[0].bsn = gprs->bsn;
361 rlc->block_info[0].e = gprs->e;
362 rlc->block_info[0].ti = gprs->ti;
363 rlc->block_info[0].spb = 0;
364
365 cur_bit += 3 * 8;
366
367 rlc->data_offs_bits[0] = cur_bit;
368 rlc->block_info[0].data_len = data_len;
369 cur_bit += data_len * 8;
370
371 break;
372 case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3:
373 egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_3 *>
374 ((void *)data);
375 rlc->r = egprs3->r;
376 rlc->si = egprs3->si;
377 rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2);
378 rlc->cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2);
379 rlc->rsb = egprs3->rsb;
380
381 rlc->num_data_blocks = 1;
382 rlc->block_info[0].cv = egprs3->cv;
383 rlc->block_info[0].pi = egprs3->pi;
384 rlc->block_info[0].spb = egprs3->spb;
385 rlc->block_info[0].bsn =
386 (egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
387
388 cur_bit += 3 * 8 + 7;
389
390 e_ti_header = (data[3] + (data[4] << 8)) >> 7;
391 rlc->block_info[0].e = !!(e_ti_header & 0x01);
392 rlc->block_info[0].ti = !!(e_ti_header & 0x02);
393 cur_bit += 2;
394
395 rlc->data_offs_bits[0] = cur_bit;
396 rlc->block_info[0].data_len = data_len;
397 cur_bit += data_len * 8;
398
399 break;
400
401 case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1:
402 case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2:
403 /* TODO: Support both header types */
404 /* fall through */
405 default:
406 LOGP(DRLCMACDL, LOGL_ERROR,
407 "Decoding of uplink %s data blocks not yet supported.\n",
408 cs.name());
409 return -ENOTSUP;
410 };
411
412 return cur_bit;
413}
414
415/**
416 * \brief Copy LSB bitstream RLC data block to byte aligned buffer.
417 *
418 * Note that the bitstream is encoded in LSB first order, so the two octets
419 * 654321xx xxxxxx87 contain the octet 87654321 starting at bit position 3
420 * (LSB has bit position 1). This is a different order than the one used by
421 * CSN.1.
422 *
423 * \param data_block_idx The block index, 0..1 for header type 1, 0 otherwise
424 * \param src A pointer to the start of the RLC block (incl. the header)
425 * \param buffer A data area of a least the size of the RLC block
426 * \returns the number of bytes copied
427 */
428unsigned int Decoding::rlc_copy_to_aligned_buffer(
Jacob Erlbeckf2ba4cb2016-01-07 18:59:28 +0100429 const struct gprs_rlc_data_info *rlc,
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100430 unsigned int data_block_idx,
431 const uint8_t *src, uint8_t *buffer)
432{
433 unsigned int hdr_bytes;
434 unsigned int extra_bits;
435 unsigned int i;
436
437 uint8_t c, last_c;
438 uint8_t *dst;
Jacob Erlbeckf2ba4cb2016-01-07 18:59:28 +0100439 const struct gprs_rlc_data_block_info *rdbi;
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100440
441 OSMO_ASSERT(data_block_idx < rlc->num_data_blocks);
442 rdbi = &rlc->block_info[data_block_idx];
443
444 hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
445 extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
446
447 if (extra_bits == 0) {
448 /* It is aligned already */
449 memmove(buffer, src + hdr_bytes, rdbi->data_len);
450 return rdbi->data_len;
451 }
452
453 dst = buffer;
454 src = src + hdr_bytes;
455 last_c = *(src++);
456
457 for (i = 0; i < rdbi->data_len; i++) {
458 c = src[i];
459 *(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits));
460 last_c = c;
461 }
462
463 return rdbi->data_len;
464}
465
466/**
467 * \brief Get a pointer to byte aligned RLC data.
468 *
469 * Since the RLC data may not be byte aligned to the RLC block data such that a
470 * single RLC data byte is spread over two RLC block bytes, this function
471 * eventually uses the provided buffer as data storage.
472 *
473 * \param src A pointer to the start of the RLC block (incl. the header)
474 * \param buffer A data area of a least the size of the RLC block
475 * \returns A pointer to the RLC data start within src if it is aligned, and
476 * buffer otherwise.
477 */
478const uint8_t *Decoding::rlc_get_data_aligned(
Jacob Erlbeckf2ba4cb2016-01-07 18:59:28 +0100479 const struct gprs_rlc_data_info *rlc,
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100480 unsigned int data_block_idx,
481 const uint8_t *src, uint8_t *buffer)
482{
483 unsigned int hdr_bytes;
484 unsigned int extra_bits;
485
486 OSMO_ASSERT(data_block_idx < ARRAY_SIZE(rlc->data_offs_bits));
487
488 hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
489 extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
490
491 if (extra_bits == 0)
492 /* It is aligned already, return a pointer that refers to the
493 * original data. */
494 return src + hdr_bytes;
495
496 Decoding::rlc_copy_to_aligned_buffer(rlc, data_block_idx, src, buffer);
497 return buffer;
498}
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100499
500static int handle_final_ack(bitvec *bits, int *bsn_begin, int *bsn_end,
501 gprs_rlc_dl_window *window)
502{
503 int num_blocks, i;
504
505 num_blocks = window->mod_sns(window->v_s() - window->v_a());
506 for (i = 0; i < num_blocks; i++)
507 bitvec_set_bit(bits, ONE);
508
509 *bsn_begin = window->v_a();
510 *bsn_end = window->mod_sns(*bsn_begin + num_blocks);
511 return num_blocks;
512}
513
514int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc,
515 bitvec *bits, int *bsn_begin, int *bsn_end, gprs_rlc_dl_window *window)
516{
517 int urbb_len = desc->URBB_LENGTH;
518 int crbb_len = 0;
519 int num_blocks = 0;
520 struct bitvec urbb;
521 int i;
522 bool have_bitmap;
523 int implicitly_acked_blocks;
524 int ssn = desc->STARTING_SEQUENCE_NUMBER;
525
526 if (desc->FINAL_ACK_INDICATION)
527 return handle_final_ack(bits, bsn_begin, bsn_end, window);
528
529 if (desc->Exist_CRBB)
530 crbb_len = desc->CRBB_LENGTH;
531
532 have_bitmap = (urbb_len + crbb_len) > 0;
533
534 /*
535 * bow & bitmap present:
536 * V(A)-> [ 11111...11111 0 SSN-> BBBBB...BBBBB ] (SSN+Nbits) .... V(S)
537 * bow & not bitmap present:
538 * V(A)-> [ 11111...11111 ] . SSN .... V(S)
539 * not bow & bitmap present:
540 * V(A)-> ... [ 0 SSN-> BBBBB...BBBBB ](SSN+N) .... V(S)
541 * not bow & not bitmap present:
542 * V(A)-> ... [] . SSN .... V(S)
543 */
544
545 if (desc->BEGINNING_OF_WINDOW) {
546 implicitly_acked_blocks = window->mod_sns(ssn - 1 - window->v_a());
547
548 for (i = 0; i < implicitly_acked_blocks; i++)
549 bitvec_set_bit(bits, ONE);
550
551 num_blocks += implicitly_acked_blocks;
552 }
553
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +0100554 if (!have_bitmap)
555 goto aborted;
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100556
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +0100557 /* next bit refers to V(Q) and thus is always zero (and not
558 * transmitted) */
559 bitvec_set_bit(bits, ZERO);
560 num_blocks += 1;
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100561
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +0100562 if (crbb_len > 0) {
563 int old_len = bits->cur_bit;
564#if WITH_CRBB_DECODING
565#warning "Experimental CRBB decoding enabled"
566 struct bitvec crbb;
567 int rc;
568
569 crbb.data = (uint8_t *)desc->CRBB;
570 crbb.data_len = sizeof(desc->CRBB);
571 crbb.cur_bit = desc->CRBB_LENGTH;
572
573 rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE,
574 bits);
575
576 if (rc < 0) {
577 LOGP(DRLCMACUL, LOGL_NOTICE,
578 "Failed to decode CRBB: "
579 "length %d, data '%s'\n",
580 desc->CRBB_LENGTH,
581 osmo_hexdump(crbb.data, crbb.data_len));
582 /* We don't know the SSN offset for the URBB,
583 * return what we have so far and assume the
584 * bitmap has stopped here */
585 goto aborted;
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100586 }
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +0100587#else
588 LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: CRBB not supported, "
589 "please set window size to 64\n");
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100590
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +0100591 /* We don't know the SSN offset for the URBB, return
592 * what we have so far and assume the bitmap has
593 * stopped here */
594 goto aborted;
595#endif
596 LOGP(DRLCMACDL, LOGL_DEBUG,
597 "CRBB len: %d, decoded len: %d, cc: %d, crbb: '%s'\n",
598 desc->CRBB_LENGTH, bits->cur_bit - old_len,
599 desc->CRBB_STARTING_COLOR_CODE,
600 osmo_hexdump(
601 desc->CRBB, (desc->CRBB_LENGTH + 7)/8)
602 );
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100603
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +0100604 num_blocks += (bits->cur_bit - old_len);
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100605 }
606
Jacob Erlbeck3fdcb2b2016-01-18 16:51:59 +0100607 urbb.cur_bit = 0;
608 urbb.data = (uint8_t *)desc->URBB;
609 urbb.data_len = sizeof(desc->URBB);
610
611 for (i = urbb_len; i > 0; i--) {
612 /*
613 * Set bit at the appropriate position (see 3GPP TS
614 * 44.060 12.3.1)
615 */
616 int is_ack = bitvec_get_bit_pos(&urbb, i-1);
617 bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO);
618 }
619 num_blocks += urbb_len;
620
621aborted:
Jacob Erlbeckae9c5752016-01-13 13:55:44 +0100622 *bsn_begin = window->v_a();
623 *bsn_end = window->mod_sns(*bsn_begin + num_blocks);
624
625 return num_blocks;
626}