blob: 007522cc701b18f21529be16b3e0f6d0cac1298f [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>
26}
27
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +020028#include <arpa/inet.h>
29
30#include <errno.h>
31#include <string.h>
32
Jacob Erlbeck4abc6862015-12-08 15:14:05 +010033#define LENGTH_TO_END 255
34/*
35 * \returns num extensions fields (num frames == offset) on success,
36 * -errno otherwise.
37 */
38static int parse_extensions_egprs(const uint8_t *data, unsigned int data_len,
39 unsigned int *offs,
40 bool is_last_block,
41 Decoding::RlcData *chunks, unsigned int chunks_size)
42{
43 const struct rlc_li_field_egprs *li;
44 uint8_t e;
45 unsigned int num_chunks = 0;
46 // unsigned int data_area = 0;
47
48 e = 0;
49 while (!e) {
50 if (*offs > data_len) {
51 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
52 "but no more data\n");
53 return -EINVAL;
54 }
55
56 /* get new E */
57 li = (struct rlc_li_field_egprs *)&data[*offs];
58 e = li->e;
59 *offs += 1;
60
61 if (!chunks)
62 continue;
63
64 if (num_chunks == chunks_size) {
65 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
66 "but no more chunks possible\n");
67 return -ENOSPC;
68 }
69 if (li->li == 0 && num_chunks == 0 && li->e == 0) {
70 /* TS 44.060, table 10.4.14a.1, row 2a */
71 chunks[num_chunks].length = 0;
72 chunks[num_chunks].is_complete = true;
73 } else if (li->li == 0 && num_chunks == 0 && li->e == 1) {
74 /* TS 44.060, table 10.4.14a.1, row 4 */
75 // chunks[num_chunks].length = data_len - *offs - data_area;
76 chunks[num_chunks].length = LENGTH_TO_END;
77 chunks[num_chunks].is_complete = is_last_block;
78 } else if (li->li == 127 && li->e == 1) {
79 /* TS 44.060, table 10.4.14a.1, row 3 & 5 */
80 /* only filling bytes left */
81 break;
82 } else if (li->li > 0) {
83 /* TS 44.060, table 10.4.14a.1, row 1 & 2b */
84 chunks[num_chunks].length = li->li;
85 chunks[num_chunks].is_complete = true;
86 } else {
87 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI contains "
88 "invalid extension octet: LI=%d, E=%d, count=%d\n",
89 li->li, li->e, num_chunks);
90 return -EINVAL;
91 }
92
93 num_chunks += 1;
94
95 if (e == 1) {
96 /* There is space after the last chunk, add a final one */
97 if (num_chunks == chunks_size) {
98 LOGP(DRLCMACUL, LOGL_NOTICE,
99 "UL DATA LI possibly extended, "
100 "but no more chunks possible\n");
101 return -ENOSPC;
102 }
103
104 // chunks[num_chunks].length = data_len - *offs - data_area;
105 chunks[num_chunks].length = LENGTH_TO_END;
106 chunks[num_chunks].is_complete = is_last_block;
107 // data_area += chunks[num_chunks].length;
108 num_chunks += 1;
109 }
110 }
111
112 return num_chunks;
113}
114
115static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len,
116 unsigned int *offs,
117 bool is_last_block,
118 Decoding::RlcData *chunks, unsigned int chunks_size)
119{
120 const struct rlc_li_field *li;
121 uint8_t m, e;
122 unsigned int num_chunks = 0;
123 // unsigned int data_area = 0;
124
125 e = 0;
126 while (!e) {
127 if (*offs > data_len) {
128 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
129 "but no more data\n");
130 return -EINVAL;
131 }
132
133 /* get new E */
134 li = (const struct rlc_li_field *)&data[*offs];
135 e = li->e;
136 m = li->m;
137 *offs += 1;
138
139 if (li->li == 0) {
140 /* TS 44.060, 10.4.14, par 6 */
141 e = 1;
142 m = 0;
143 }
144
145 /* TS 44.060, table 10.4.13.1 */
146 if (m == 0 && e == 0) {
147 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA "
148 "ignored, because M='0' and E='0'.\n");
149 return 0;
150 }
151
152 if (!chunks)
153 continue;
154
155 if (num_chunks == chunks_size) {
156 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
157 "but no more chunks possible\n");
158 return -ENOSPC;
159 }
160
161 if (li->li == 0)
162 /* e is 1 here */
163 // chunks[num_chunks].length = data_len - *offs - data_area;
164 chunks[num_chunks].length = LENGTH_TO_END;
165 else
166 chunks[num_chunks].length = li->li;
167
168 chunks[num_chunks].is_complete = li->li || is_last_block;
169
170 // data_area += chunks[num_chunks].length;
171 num_chunks += 1;
172
173 if (e == 1 && m == 1) {
174 if (num_chunks == chunks_size) {
175 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
176 "but no more chunks possible\n");
177 return -ENOSPC;
178 }
179 /* TS 44.060, 10.4.13.1, row 4 */
180 // chunks[num_chunks].length = data_len - *offs - data_area;
181 chunks[num_chunks].length = LENGTH_TO_END;
182 chunks[num_chunks].is_complete = is_last_block;
183 num_chunks += 1;
184 }
185 }
186
187 return num_chunks;
188}
189
190int Decoding::rlc_data_from_ul_data(
191 const struct gprs_rlc_ul_data_block_info *rdbi, GprsCodingScheme cs,
192 const uint8_t *data, RlcData *chunks, unsigned int chunks_size,
193 uint32_t *tlli)
194{
195 uint8_t e;
196 unsigned int data_len = rdbi->data_len;
Jacob Erlbeckead5e472016-01-08 10:14:50 +0100197 int num_chunks = 0, i;
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100198 unsigned int offs = 0;
199 bool is_last_block = (rdbi->cv == 0);
200
201 if (!chunks)
202 chunks_size = 0;
203
204 e = rdbi->e;
205 if (e) {
206 if (chunks_size > 0) {
207 chunks[num_chunks].offset = offs;
208 chunks[num_chunks].length = LENGTH_TO_END;
209 chunks[num_chunks].is_complete = is_last_block;
210 num_chunks += 1;
211 } else if (chunks) {
212 LOGP(DRLCMACUL, LOGL_NOTICE, "No extension, "
213 "but no more chunks possible\n");
214 return -ENOSPC;
215 }
216 } else if (cs.isEgprs()) {
217 /* if E is not set (LI follows), EGPRS */
218 num_chunks = parse_extensions_egprs(data, data_len, &offs,
219 is_last_block,
220 chunks, chunks_size);
221 } else {
222 /* if E is not set (LI follows), GPRS */
223 num_chunks = parse_extensions_gprs(data, data_len, &offs,
224 is_last_block,
225 chunks, chunks_size);
226 }
227
Jacob Erlbeckead5e472016-01-08 10:14:50 +0100228 if (num_chunks < 0)
229 return num_chunks;
230
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100231 /* TLLI */
232 if (rdbi->ti) {
233 uint32_t tlli_enc;
234 if (offs + 4 > data_len) {
235 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of block "
236 "border\n");
237 return -EINVAL;
238 }
239
240 memcpy(&tlli_enc, data + offs, sizeof(tlli_enc));
241 if (cs.isGprs())
242 /* The TLLI is encoded in big endian for GPRS (see
243 * TS 44.060, figure 10.2.2.1, note) */
244 *tlli = be32toh(tlli_enc);
245 else
246 /* The TLLI is encoded in little endian for EGPRS (see
247 * TS 44.060, figure 10.3a.2.1, note 2) */
248 *tlli = le32toh(tlli_enc);
249
250 offs += sizeof(tlli_enc);
251 } else {
252 *tlli = 0;
253 }
254
255 /* PFI */
256 if (rdbi->pi) {
257 LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, "
258 "please disable in SYSTEM INFORMATION\n");
259 return -ENOTSUP;
260
261 /* TODO: Skip all extensions with E=0 (see TS 44.060, 10.4.11 */
262 }
263
Jacob Erlbeckead5e472016-01-08 10:14:50 +0100264 if (chunks_size == 0)
265 return num_chunks;
266
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100267 /* LLC */
268 for (i = 0; i < num_chunks; i++) {
269 chunks[i].offset = offs;
270 if (chunks[i].length == LENGTH_TO_END) {
271 if (offs == data_len) {
272 /* There is no place for an additional chunk,
273 * so drop it (this may happen with EGPRS since
274 * there is no M flag. */
275 num_chunks -= 1;
276 break;;
277 }
278 chunks[i].length = data_len - offs;
279 }
280 offs += chunks[i].length;
281 if (offs > data_len) {
282 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA out of block "
283 "border, chunk idx: %d, size: %d\n",
284 i, chunks[i].length);
285 return -EINVAL;
286 }
287 }
288
289 return num_chunks;
290}
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200291
292int Decoding::tlli_from_ul_data(const uint8_t *data, uint8_t len,
293 uint32_t *tlli)
294{
295 struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
296 struct rlc_li_field *li;
297 uint8_t e;
298 uint32_t _tlli;
299
300 if (!rh->ti)
301 return -EINVAL;
302
303 data += 3;
304 len -= 3;
305 e = rh->e;
306 /* if E is not set (LI follows) */
307 while (!e) {
308 if (!len) {
309 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, "
310 "but no more data\n");
311 return -EINVAL;
312 }
313 /* get new E */
314 li = (struct rlc_li_field *)data;
315 if (li->e == 0) /* if LI==0, E is interpreted as '1' */
316 e = 1;
317 else
318 e = li->e;
319 data++;
320 len--;
321 }
322 if (len < 4) {
323 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of frame "
324 "border\n");
325 return -EINVAL;
326 }
327 memcpy(&_tlli, data, 4);
328 *tlli = ntohl(_tlli);
329
330 return 0;
331}
332
Holger Hans Peter Freytherfcbc7022013-10-26 17:38:37 +0200333uint8_t Decoding::get_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
334{
335 int i;
336
337 for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
338 if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
339 continue;
340 if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_GPRS_multislot_class)
341 continue;
342 return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.GPRS_multislot_class;
343 }
344
345 return 0;
346}
347
Jacob Erlbeckc3c58042015-09-28 17:55:32 +0200348uint8_t Decoding::get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap)
349{
350 int i;
351
352 for (i = 0; i < cap->Count_MS_RA_capability_value; i++) {
353 if (!cap->MS_RA_capability_value[i].u.Content.Exist_Multislot_capability)
354 continue;
355 if (!cap->MS_RA_capability_value[i].u.Content.Multislot_capability.Exist_EGPRS_multislot_class)
356 continue;
357 return cap->MS_RA_capability_value[i].u.Content.Multislot_capability.EGPRS_multislot_class;
358 }
359
360 return 0;
361}
362
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100363/**
364 * show_rbb needs to be an array with 65 elements
Daniel Willmann5e94cd42013-12-11 20:11:16 +0100365 * The index of the array is the bit position in the rbb
366 * (show_rbb[63] relates to BSN ssn-1)
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100367 */
368void Decoding::extract_rbb(const uint8_t *rbb, char *show_rbb)
369{
Daniel Willmann5e94cd42013-12-11 20:11:16 +0100370 for (int i = 0; i < 64; i++) {
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100371 uint8_t bit;
372
Daniel Willmann5e94cd42013-12-11 20:11:16 +0100373 bit = !!(rbb[i/8] & (1<<(7-i%8)));
Daniel Willmann6f7cb2c2013-12-11 14:25:20 +0100374 show_rbb[i] = bit ? 'R' : 'I';
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100375 }
376
377 show_rbb[64] = '\0';
378}
Jacob Erlbeck4abc6862015-12-08 15:14:05 +0100379
380int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_ul_header_egprs *rlc,
381 const uint8_t *data, GprsCodingScheme cs)
382{
383 const struct gprs_rlc_ul_header_egprs_3 *egprs3;
384 const struct rlc_ul_header *gprs;
385 unsigned int e_ti_header;
386 unsigned int cur_bit = 0;
387 unsigned int data_len = 0;
388
389 rlc->cs = cs;
390
391 data_len = cs.maxDataBlockBytes();
392
393 switch(cs.headerTypeData()) {
394 case GprsCodingScheme::HEADER_GPRS_DATA:
395 gprs = static_cast<struct rlc_ul_header *>
396 ((void *)data);
397 rlc->r = gprs->r;
398 rlc->si = gprs->si;
399 rlc->tfi = gprs->tfi;
400 rlc->cps = 0;
401 rlc->rsb = 0;
402
403 rlc->num_data_blocks = 1;
404 rlc->block_info[0].cv = gprs->cv;
405 rlc->block_info[0].pi = gprs->pi;
406 rlc->block_info[0].bsn = gprs->bsn;
407 rlc->block_info[0].e = gprs->e;
408 rlc->block_info[0].ti = gprs->ti;
409 rlc->block_info[0].spb = 0;
410
411 cur_bit += 3 * 8;
412
413 rlc->data_offs_bits[0] = cur_bit;
414 rlc->block_info[0].data_len = data_len;
415 cur_bit += data_len * 8;
416
417 break;
418 case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3:
419 egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_3 *>
420 ((void *)data);
421 rlc->r = egprs3->r;
422 rlc->si = egprs3->si;
423 rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2);
424 rlc->cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2);
425 rlc->rsb = egprs3->rsb;
426
427 rlc->num_data_blocks = 1;
428 rlc->block_info[0].cv = egprs3->cv;
429 rlc->block_info[0].pi = egprs3->pi;
430 rlc->block_info[0].spb = egprs3->spb;
431 rlc->block_info[0].bsn =
432 (egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5);
433
434 cur_bit += 3 * 8 + 7;
435
436 e_ti_header = (data[3] + (data[4] << 8)) >> 7;
437 rlc->block_info[0].e = !!(e_ti_header & 0x01);
438 rlc->block_info[0].ti = !!(e_ti_header & 0x02);
439 cur_bit += 2;
440
441 rlc->data_offs_bits[0] = cur_bit;
442 rlc->block_info[0].data_len = data_len;
443 cur_bit += data_len * 8;
444
445 break;
446
447 case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1:
448 case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2:
449 /* TODO: Support both header types */
450 /* fall through */
451 default:
452 LOGP(DRLCMACDL, LOGL_ERROR,
453 "Decoding of uplink %s data blocks not yet supported.\n",
454 cs.name());
455 return -ENOTSUP;
456 };
457
458 return cur_bit;
459}
460
461/**
462 * \brief Copy LSB bitstream RLC data block to byte aligned buffer.
463 *
464 * Note that the bitstream is encoded in LSB first order, so the two octets
465 * 654321xx xxxxxx87 contain the octet 87654321 starting at bit position 3
466 * (LSB has bit position 1). This is a different order than the one used by
467 * CSN.1.
468 *
469 * \param data_block_idx The block index, 0..1 for header type 1, 0 otherwise
470 * \param src A pointer to the start of the RLC block (incl. the header)
471 * \param buffer A data area of a least the size of the RLC block
472 * \returns the number of bytes copied
473 */
474unsigned int Decoding::rlc_copy_to_aligned_buffer(
475 const struct gprs_rlc_ul_header_egprs *rlc,
476 unsigned int data_block_idx,
477 const uint8_t *src, uint8_t *buffer)
478{
479 unsigned int hdr_bytes;
480 unsigned int extra_bits;
481 unsigned int i;
482
483 uint8_t c, last_c;
484 uint8_t *dst;
485 const struct gprs_rlc_ul_data_block_info *rdbi;
486
487 OSMO_ASSERT(data_block_idx < rlc->num_data_blocks);
488 rdbi = &rlc->block_info[data_block_idx];
489
490 hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
491 extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
492
493 if (extra_bits == 0) {
494 /* It is aligned already */
495 memmove(buffer, src + hdr_bytes, rdbi->data_len);
496 return rdbi->data_len;
497 }
498
499 dst = buffer;
500 src = src + hdr_bytes;
501 last_c = *(src++);
502
503 for (i = 0; i < rdbi->data_len; i++) {
504 c = src[i];
505 *(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits));
506 last_c = c;
507 }
508
509 return rdbi->data_len;
510}
511
512/**
513 * \brief Get a pointer to byte aligned RLC data.
514 *
515 * Since the RLC data may not be byte aligned to the RLC block data such that a
516 * single RLC data byte is spread over two RLC block bytes, this function
517 * eventually uses the provided buffer as data storage.
518 *
519 * \param src A pointer to the start of the RLC block (incl. the header)
520 * \param buffer A data area of a least the size of the RLC block
521 * \returns A pointer to the RLC data start within src if it is aligned, and
522 * buffer otherwise.
523 */
524const uint8_t *Decoding::rlc_get_data_aligned(
525 const struct gprs_rlc_ul_header_egprs *rlc,
526 unsigned int data_block_idx,
527 const uint8_t *src, uint8_t *buffer)
528{
529 unsigned int hdr_bytes;
530 unsigned int extra_bits;
531
532 OSMO_ASSERT(data_block_idx < ARRAY_SIZE(rlc->data_offs_bits));
533
534 hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3;
535 extra_bits = (rlc->data_offs_bits[data_block_idx] & 7);
536
537 if (extra_bits == 0)
538 /* It is aligned already, return a pointer that refers to the
539 * original data. */
540 return src + hdr_bytes;
541
542 Decoding::rlc_copy_to_aligned_buffer(rlc, data_block_idx, src, buffer);
543 return buffer;
544}