aboutsummaryrefslogtreecommitdiffstats
path: root/src/decoding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/decoding.cpp')
-rw-r--r--src/decoding.cpp478
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;
-}