diff options
Diffstat (limited to 'src/decoding.cpp')
-rw-r--r-- | src/decoding.cpp | 478 |
1 files changed, 183 insertions, 295 deletions
diff --git a/src/decoding.cpp b/src/decoding.cpp index f2b548c..2a57bed 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -21,11 +21,6 @@ #include <rlc.h> #include <gprs_debug.h> -extern "C" { -#include <osmocom/core/utils.h> -#include <osmocom/core/bitcomp.h> -} - #include <arpa/inet.h> #include <errno.h> @@ -72,6 +67,7 @@ static int parse_extensions_egprs(const uint8_t *data, unsigned int data_len, chunks[num_chunks].is_complete = true; } else if (li->li == 0 && num_chunks == 0 && li->e == 1) { /* TS 44.060, table 10.4.14a.1, row 4 */ + // chunks[num_chunks].length = data_len - *offs - data_area; chunks[num_chunks].length = LENGTH_TO_END; chunks[num_chunks].is_complete = is_last_block; } else if (li->li == 127 && li->e == 1) { @@ -100,8 +96,10 @@ static int parse_extensions_egprs(const uint8_t *data, unsigned int data_len, return -ENOSPC; } + // chunks[num_chunks].length = data_len - *offs - data_area; chunks[num_chunks].length = LENGTH_TO_END; chunks[num_chunks].is_complete = is_last_block; + // data_area += chunks[num_chunks].length; num_chunks += 1; } } @@ -117,6 +115,7 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len, const struct rlc_li_field *li; uint8_t m, e; unsigned int num_chunks = 0; + // unsigned int data_area = 0; e = 0; while (!e) { @@ -156,12 +155,14 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len, if (li->li == 0) /* e is 1 here */ + // chunks[num_chunks].length = data_len - *offs - data_area; chunks[num_chunks].length = LENGTH_TO_END; else chunks[num_chunks].length = li->li; chunks[num_chunks].is_complete = li->li || is_last_block; + // data_area += chunks[num_chunks].length; num_chunks += 1; if (e == 1 && m == 1) { @@ -171,6 +172,7 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len, return -ENOSPC; } /* TS 44.060, 10.4.13.1, row 4 */ + // chunks[num_chunks].length = data_len - *offs - data_area; chunks[num_chunks].length = LENGTH_TO_END; chunks[num_chunks].is_complete = is_last_block; num_chunks += 1; @@ -181,13 +183,13 @@ static int parse_extensions_gprs(const uint8_t *data, unsigned int data_len, } int Decoding::rlc_data_from_ul_data( - const struct gprs_rlc_data_block_info *rdbi, GprsCodingScheme cs, + const struct gprs_rlc_ul_data_block_info *rdbi, GprsCodingScheme cs, const uint8_t *data, RlcData *chunks, unsigned int chunks_size, uint32_t *tlli) { uint8_t e; unsigned int data_len = rdbi->data_len; - int num_chunks = 0, i; + unsigned int num_chunks = 0, i; unsigned int offs = 0; bool is_last_block = (rdbi->cv == 0); @@ -206,7 +208,7 @@ int Decoding::rlc_data_from_ul_data( "but no more chunks possible\n"); return -ENOSPC; } - } else if (cs.isEgprs()) { + } else if (true == cs.isEgprs()) { /* if E is not set (LI follows), EGPRS */ num_chunks = parse_extensions_egprs(data, data_len, &offs, is_last_block, @@ -218,9 +220,6 @@ int Decoding::rlc_data_from_ul_data( chunks, chunks_size); } - if (num_chunks < 0) - return num_chunks; - /* TLLI */ if (rdbi->ti) { uint32_t tlli_enc; @@ -250,13 +249,8 @@ int Decoding::rlc_data_from_ul_data( LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, " "please disable in SYSTEM INFORMATION\n"); return -ENOTSUP; - - /* TODO: Skip all extensions with E=0 (see TS 44.060, 10.4.11 */ } - if (chunks_size == 0) - return num_chunks; - /* LLC */ for (i = 0; i < num_chunks; i++) { chunks[i].offset = offs; @@ -282,6 +276,47 @@ int Decoding::rlc_data_from_ul_data( return num_chunks; } +int Decoding::tlli_from_ul_data(const uint8_t *data, uint8_t len, + uint32_t *tlli) +{ + struct rlc_ul_header *rh = (struct rlc_ul_header *)data; + struct rlc_li_field *li; + uint8_t e; + uint32_t _tlli; + + if (!rh->ti) + return -EINVAL; + + data += 3; + len -= 3; + e = rh->e; + /* if E is not set (LI follows) */ + while (!e) { + if (!len) { + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA LI extended, " + "but no more data\n"); + return -EINVAL; + } + /* get new E */ + li = (struct rlc_li_field *)data; + if (li->e == 0) /* if LI==0, E is interpreted as '1' */ + e = 1; + else + e = li->e; + data++; + len--; + } + if (len < 4) { + LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of frame " + "border\n"); + return -EINVAL; + } + memcpy(&_tlli, data, 4); + *tlli = ntohl(_tlli); + + return 0; +} + uint8_t Decoding::get_ms_class_by_capability(MS_Radio_Access_capability_t *cap) { int i; @@ -312,6 +347,18 @@ uint8_t Decoding::get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t return 0; } +void Decoding::extract_egprs_urbb(uint16_t urbb_length, const uint8_t *urbb, char *show_rbb) +{ + for (int i = 0; i < urbb_length; i++) { + uint8_t bit; + + bit = !!(urbb[i/8] & (1<<(7-i%8))); + show_rbb[i] = bit ? 'R' : 'I'; + } + + show_rbb[urbb_length] = '\0'; +} + /** * show_rbb needs to be an array with 65 elements * The index of the array is the bit position in the rbb @@ -329,40 +376,26 @@ void Decoding::extract_rbb(const uint8_t *rbb, char *show_rbb) show_rbb[64] = '\0'; } -void Decoding::extract_rbb(const struct bitvec *rbb, char *show_rbb) -{ - unsigned int i; - for (i = 0; i < rbb->cur_bit; i++) { - uint8_t bit; - bit = bitvec_get_bit_pos(rbb, i); - show_rbb[i] = bit == 1 ? 'R' : 'I'; - } - - show_rbb[i] = '\0'; -} - -int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc, +int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_ul_header_generic *rlc, const uint8_t *data, GprsCodingScheme cs) { - const struct gprs_rlc_ul_header_egprs_3 *egprs3; const struct rlc_ul_header *gprs; - unsigned int e_ti_header; - unsigned int cur_bit = 0; - int punct, punct2, with_padding, cps; - unsigned int offs; + unsigned int data_len = 0; + uint8_t pad_bytes = 6; + rlc->cs = cs; + + data_len = cs.maxDataBlockBytes(); switch(cs.headerTypeData()) { case GprsCodingScheme::HEADER_GPRS_DATA: gprs = static_cast<struct rlc_ul_header *> ((void *)data); - - gprs_rlc_data_info_init_ul(rlc, cs, false); - rlc->r = gprs->r; rlc->si = gprs->si; rlc->tfi = gprs->tfi; rlc->cps = 0; rlc->rsb = 0; + rlc->pani= 0; rlc->num_data_blocks = 1; rlc->block_info[0].cv = gprs->cv; @@ -371,51 +404,126 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc, rlc->block_info[0].e = gprs->e; rlc->block_info[0].ti = gprs->ti; rlc->block_info[0].spb = 0; + rlc->data_offs_bytes[0] = 3; - cur_bit += rlc->data_offs_bits[0]; + rlc->block_info[0].data_len = data_len; - /* skip data area */ - cur_bit += cs.maxDataBlockBytes() * 8; break; case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3: + const struct gprs_rlc_ul_header_egprs_3 *egprs3; egprs3 = static_cast<struct gprs_rlc_ul_header_egprs_3 *> - ((void *)data); + ((void *)data); + rlc->r = egprs3->r; + rlc->si = egprs3->si; + rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2); + rlc->cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2); + rlc->rsb = egprs3->rsb; + rlc->cv = egprs3->cv; + /* pani 0 for fanr inactive */ + rlc->pani = 0; + + rlc->num_data_blocks = 1; + rlc->block_info[0].cv = egprs3->cv; + rlc->block_info[0].pi = egprs3->pi; + rlc->block_info[0].spb = egprs3->spb; + rlc->block_info[0].bsn = + (egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5); + + rlc->block_info[0].e = (data[4] & 0x01); + rlc->block_info[0].ti = (data[4] & 0x02) >> 1; + + rlc->block_info[0].data_len = data_len; + rlc->data_offs_bytes[0] = 5; + + if(rlc->block_info[0].spb == 2){ + if(cs == GprsCodingScheme::MCS3){ + if(rlc->cps == 6 || rlc->cps == 7 || rlc->cps == 8){ + rlc->block_info[0].data_len -= pad_bytes; + rlc->data_offs_bytes[0] += pad_bytes; + rlc->block_info[0].e = (data[4 + pad_bytes] & 0x01); + rlc->block_info[0].ti = (data[4 + pad_bytes] & 0x02) >> 1; + } + } + } + break; - cps = (egprs3->cps_a << 0) | (egprs3->cps_b << 2); - gprs_rlc_mcs_cps_decode(cps, cs, &punct, &punct2, &with_padding); - gprs_rlc_data_info_init_ul(rlc, cs, with_padding); + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2: + const struct gprs_rlc_ul_header_egprs_2 *egprs2; + egprs2 = static_cast<struct gprs_rlc_ul_header_egprs_2 *> + ((void *)data); + rlc->r = egprs2->r; + rlc->si = egprs2->si; + rlc->tfi = (egprs2->tfi_a << 0) | (egprs2->tfi_b << 2); + rlc->cps = (egprs2->cps_a << 0) | (egprs2->cps_b << 2); + rlc->rsb = egprs2->rsb; + rlc->cv = egprs2->cv; + /* pani 0 for fanr inactive */ + rlc->pani = 0; + + rlc->num_data_blocks = 1; + rlc->block_info[0].cv = egprs2->cv; + rlc->block_info[0].pi = egprs2->pi; + rlc->block_info[0].bsn = + (egprs2->bsn1_a << 0) | (egprs2->bsn1_b << 5); + + /* data base initialisation not from received block */ + rlc->block_info[0].spb = 0; - rlc->r = egprs3->r; - rlc->si = egprs3->si; - rlc->tfi = (egprs3->tfi_a << 0) | (egprs3->tfi_b << 2); - rlc->cps = cps; - rlc->rsb = egprs3->rsb; + rlc->block_info[0].e = (data[5] & 0x01); + rlc->block_info[0].ti = (data[5] & 0x02) >> 1; - rlc->num_data_blocks = 1; - rlc->block_info[0].cv = egprs3->cv; - rlc->block_info[0].pi = egprs3->pi; - rlc->block_info[0].spb = egprs3->spb; - rlc->block_info[0].bsn = - (egprs3->bsn1_a << 0) | (egprs3->bsn1_b << 5); + rlc->block_info[0].data_len = data_len; + rlc->data_offs_bytes[0] = 6; - cur_bit += rlc->data_offs_bits[0] - 2; + if(cs == GprsCodingScheme::MCS6){ + if(rlc->cps == 2 || rlc->cps == 3 ){ + rlc->block_info[0].data_len -= pad_bytes; + rlc->data_offs_bytes[0] += pad_bytes; + rlc->block_info[0].e = (data[5 + pad_bytes] & 0x01); + rlc->block_info[0].ti = (data[5 + pad_bytes] & 0x02) >> 1; + } + } + break; - offs = rlc->data_offs_bits[0] / 8; - OSMO_ASSERT(rlc->data_offs_bits[0] % 8 == 1); + case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1: + const struct gprs_rlc_ul_header_egprs_1 *egprs1; + egprs1 = static_cast<struct gprs_rlc_ul_header_egprs_1 *> + ((void *)data); + rlc->r = egprs1->r; + rlc->si = egprs1->si; + rlc->tfi = (egprs1->tfi_a << 0) | (egprs1->tfi_b << 2); + rlc->cps = egprs1->cps; + rlc->rsb = egprs1->rsb; + rlc->cv = egprs1->cv; + /* pani 0 for fanr inactive */ + rlc->pani = 0; + + rlc->num_data_blocks = 2; + rlc->block_info[0].cv = egprs1->cv; + rlc->block_info[0].pi = egprs1->pi; + rlc->block_info[0].bsn = + (egprs1->bsn1_a << 0) | (egprs1->bsn1_b << 5); + /* data base initialisation not from received block */ + rlc->block_info[0].spb = 0; - e_ti_header = (data[offs-1] + (data[offs] << 8)) >> 7; - rlc->block_info[0].e = !!(e_ti_header & 0x01); - rlc->block_info[0].ti = !!(e_ti_header & 0x02); - cur_bit += 2; + rlc->block_info[1].cv = egprs1->cv; + rlc->block_info[1].pi = egprs1->pi; + + rlc->block_info[1].bsn = rlc->block_info[0].bsn + ((egprs1->bsn2_a << 0) | (egprs1->bsn2_b << 2)); + rlc->block_info[1].bsn = (rlc->block_info[1].bsn + 2048) % 2047; - /* skip data area */ - cur_bit += cs.maxDataBlockBytes() * 8; - break; + rlc->block_info[0].e = (data[6] & 0x01); + rlc->block_info[0].ti = (data[6] & 0x02) >> 1; + rlc->block_info[1].e = (data[6 + data_len + 1] & 0x01); + rlc->block_info[1].ti = (data[6 + data_len + 1] & 0x02) >> 1; + rlc->block_info[1].spb = 0; - case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1: - case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2: - /* TODO: Support both header types */ - /* fall through */ + rlc->block_info[0].data_len = data_len; + rlc->block_info[1].data_len = data_len; + rlc->data_offs_bytes[0] = 7; + rlc->data_offs_bytes[1] = 7 + data_len + 1; + + break; default: LOGP(DRLCMACDL, LOGL_ERROR, "Decoding of uplink %s data blocks not yet supported.\n", @@ -423,7 +531,7 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc, return -ENOTSUP; }; - return cur_bit; + return 0; } /** @@ -440,238 +548,18 @@ int Decoding::rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc, * \returns the number of bytes copied */ unsigned int Decoding::rlc_copy_to_aligned_buffer( - const struct gprs_rlc_data_info *rlc, + const struct gprs_rlc_ul_header_generic *rlc, unsigned int data_block_idx, const uint8_t *src, uint8_t *buffer) { unsigned int hdr_bytes; - unsigned int extra_bits; - unsigned int i; - - uint8_t c, last_c; - uint8_t *dst; - const struct gprs_rlc_data_block_info *rdbi; - - OSMO_ASSERT(data_block_idx < rlc->num_data_blocks); + const struct gprs_rlc_ul_data_block_info *rdbi; rdbi = &rlc->block_info[data_block_idx]; - hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3; - extra_bits = (rlc->data_offs_bits[data_block_idx] & 7); - - if (extra_bits == 0) { - /* It is aligned already */ - memmove(buffer, src + hdr_bytes, rdbi->data_len); - return rdbi->data_len; - } - - dst = buffer; - src = src + hdr_bytes; - last_c = *(src++); - - for (i = 0; i < rdbi->data_len; i++) { - c = src[i]; - *(dst++) = (last_c >> extra_bits) | (c << (8 - extra_bits)); - last_c = c; - } + hdr_bytes = rlc->data_offs_bytes[data_block_idx] ; + /* It is aligned already */ + memmove(buffer , src + hdr_bytes, rdbi->data_len); return rdbi->data_len; } -/** - * \brief Get a pointer to byte aligned RLC data. - * - * Since the RLC data may not be byte aligned to the RLC block data such that a - * single RLC data byte is spread over two RLC block bytes, this function - * eventually uses the provided buffer as data storage. - * - * \param src A pointer to the start of the RLC block (incl. the header) - * \param buffer A data area of a least the size of the RLC block - * \returns A pointer to the RLC data start within src if it is aligned, and - * buffer otherwise. - */ -const uint8_t *Decoding::rlc_get_data_aligned( - const struct gprs_rlc_data_info *rlc, - unsigned int data_block_idx, - const uint8_t *src, uint8_t *buffer) -{ - unsigned int hdr_bytes; - unsigned int extra_bits; - - OSMO_ASSERT(data_block_idx < ARRAY_SIZE(rlc->data_offs_bits)); - - hdr_bytes = rlc->data_offs_bits[data_block_idx] >> 3; - extra_bits = (rlc->data_offs_bits[data_block_idx] & 7); - - if (extra_bits == 0) - /* It is aligned already, return a pointer that refers to the - * original data. */ - return src + hdr_bytes; - - Decoding::rlc_copy_to_aligned_buffer(rlc, data_block_idx, src, buffer); - return buffer; -} - -static int handle_final_ack(bitvec *bits, int *bsn_begin, int *bsn_end, - gprs_rlc_dl_window *window) -{ - int num_blocks, i; - - num_blocks = window->mod_sns(window->v_s() - window->v_a()); - for (i = 0; i < num_blocks; i++) - bitvec_set_bit(bits, ONE); - - *bsn_begin = window->v_a(); - *bsn_end = window->mod_sns(*bsn_begin + num_blocks); - return num_blocks; -} - -int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc, - bitvec *bits, int *bsn_begin, int *bsn_end, gprs_rlc_dl_window *window) -{ - int urbb_len = desc->URBB_LENGTH; - int crbb_len = 0; - int num_blocks = 0; - struct bitvec urbb; - int i; - bool have_bitmap; - int implicitly_acked_blocks; - int ssn = desc->STARTING_SEQUENCE_NUMBER; - int rc; - - if (desc->FINAL_ACK_INDICATION) - return handle_final_ack(bits, bsn_begin, bsn_end, window); - - if (desc->Exist_CRBB) - crbb_len = desc->CRBB_LENGTH; - - have_bitmap = (urbb_len + crbb_len) > 0; - - /* - * bow & bitmap present: - * V(A)-> [ 11111...11111 0 SSN-> BBBBB...BBBBB ] (SSN+Nbits) .... V(S) - * bow & not bitmap present: - * V(A)-> [ 11111...11111 ] . SSN .... V(S) - * not bow & bitmap present: - * V(A)-> ... [ 0 SSN-> BBBBB...BBBBB ](SSN+N) .... V(S) - * not bow & not bitmap present: - * V(A)-> ... [] . SSN .... V(S) - */ - - if (desc->BEGINNING_OF_WINDOW) { - implicitly_acked_blocks = window->mod_sns(ssn - 1 - window->v_a()); - - for (i = 0; i < implicitly_acked_blocks; i++) - bitvec_set_bit(bits, ONE); - - num_blocks += implicitly_acked_blocks; - } - - if (!have_bitmap) - goto aborted; - - /* next bit refers to V(Q) and thus is always zero (and not - * transmitted) */ - bitvec_set_bit(bits, ZERO); - num_blocks += 1; - - if (crbb_len > 0) { - int old_len = bits->cur_bit; - struct bitvec crbb; - - crbb.data = (uint8_t *)desc->CRBB; - crbb.data_len = sizeof(desc->CRBB); - crbb.cur_bit = desc->CRBB_LENGTH; - - rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE, - bits); - - if (rc < 0) { - LOGP(DRLCMACUL, LOGL_NOTICE, - "Failed to decode CRBB: " - "length %d, data '%s'\n", - desc->CRBB_LENGTH, - osmo_hexdump(crbb.data, crbb.data_len)); - /* We don't know the SSN offset for the URBB, - * return what we have so far and assume the - * bitmap has stopped here */ - goto aborted; - } - - LOGP(DRLCMACDL, LOGL_DEBUG, - "CRBB len: %d, decoded len: %d, cc: %d, crbb: '%s'\n", - desc->CRBB_LENGTH, bits->cur_bit - old_len, - desc->CRBB_STARTING_COLOR_CODE, - osmo_hexdump( - desc->CRBB, (desc->CRBB_LENGTH + 7)/8) - ); - - num_blocks += (bits->cur_bit - old_len); - } - - urbb.cur_bit = 0; - urbb.data = (uint8_t *)desc->URBB; - urbb.data_len = sizeof(desc->URBB); - - for (i = urbb_len; i > 0; i--) { - /* - * Set bit at the appropriate position (see 3GPP TS - * 44.060 12.3.1) - */ - int is_ack = bitvec_get_bit_pos(&urbb, i-1); - bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO); - } - num_blocks += urbb_len; - -aborted: - *bsn_begin = window->v_a(); - *bsn_end = window->mod_sns(*bsn_begin + num_blocks); - - return num_blocks; -} - -int Decoding::decode_gprs_acknack_bits(const Ack_Nack_Description_t *desc, - bitvec *bits, int *bsn_begin, int *bsn_end, gprs_rlc_dl_window *window) -{ - int urbb_len = RLC_GPRS_WS; - int num_blocks; - struct bitvec urbb; - - if (desc->FINAL_ACK_INDICATION) - return handle_final_ack(bits, bsn_begin, bsn_end, window); - - *bsn_begin = window->v_a(); - *bsn_end = desc->STARTING_SEQUENCE_NUMBER; - - num_blocks = window->mod_sns(*bsn_end - *bsn_begin); - - if (num_blocks < 0 || num_blocks > urbb_len) { - *bsn_end = *bsn_begin; - LOGP(DRLCMACUL, LOGL_NOTICE, - "Invalid GPRS Ack/Nack window %d:%d (length %d)\n", - *bsn_begin, *bsn_end, num_blocks); - return -EINVAL; - } - - urbb.cur_bit = 0; - urbb.data = (uint8_t *)desc->RECEIVED_BLOCK_BITMAP; - urbb.data_len = sizeof(desc->RECEIVED_BLOCK_BITMAP); - - /* - * TS 44.060, 12.3: - * BSN = (SSN - bit_number) modulo 128, for bit_number = 1 to 64. - * The BSN values represented range from (SSN - 1) mod 128 to (SSN - 64) mod 128. - * - * We are only interested in the range from V(A) to SSN-1 which is - * num_blocks large. The RBB is laid out as - * [SSN-1] [SSN-2] ... [V(A)] ... [SSN-64] - * so we want to start with [V(A)] and go backwards until we reach - * [SSN-1] to get the needed BSNs in an increasing order. Note that - * the bit numbers are counted from the end of the buffer. - */ - for (int i = num_blocks; i > 0; i--) { - int is_ack = bitvec_get_bit_pos(&urbb, urbb_len - i); - bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO); - } - - return num_blocks; -} |