aboutsummaryrefslogtreecommitdiffstats
path: root/src/decoding.cpp
diff options
context:
space:
mode:
authorSaurabh Sharan <saurabh.sharan@radisys.com>2016-02-24 17:59:47 +0530
committerSaurabh Sharan <saurabh.sharan@radisys.com>2016-02-25 18:45:57 +0530
commitbb549f4341f029599599b993e48af718c371ccde (patch)
treed6697ee04c05a512a8c42119443406a31619650d /src/decoding.cpp
parentf3f1bde4fcabf20d00b60de934e1c1e07ab0b16c (diff)
EGPRS support MCS1 to MCS9 in UL and DLssharan/egprs
This release contains our EGPRS development done from December 2015 till February 2016. It includes rebase from Jan 2016 Master branch of Git but not the latest master available on date 22nd Feb 2016. The code has been Unit tested. It has not been tested in any integration environment. For details on the feature changes please refer the README.
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;
-}