aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2016-01-13 13:55:44 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2016-02-08 00:45:34 +0100
commitae9c575d2c2e7f906c41d28682445e6c8cb53f03 (patch)
treeb9236fb18dc558431e8fa398b530de4fcb06641f
parentc2141c6064ddf5283937c7f77468bf2396787804 (diff)
edge: Handle EGPRS PACKET DOWNLINK ACK NACK
Currently this message is ignored. Support decoding and handling of this message. Use a bitvec for the decoder that just represents a BSN sequence without any encoding details (first bit -> first BSN). Return the corresponding BSN range (snsmod(bsn_begin + bits_in_bitvec) = bsn_end), so snsmod(bsn_end-1) is the last BSN if there is at least 1. If bsn_begin == bsn_end, no BSNs has been added. Note that this bitvec is not yet used for RBB handling. It just calls the old rcvd_dl_ack with a faked (all bits are 1) RBB map. Sponsored-by: On-Waves ehf
-rw-r--r--src/bts.cpp120
-rw-r--r--src/bts.h1
-rw-r--r--src/csn1.cpp1
-rw-r--r--src/decoding.cpp91
-rw-r--r--src/decoding.h6
5 files changed, 219 insertions, 0 deletions
diff --git a/src/bts.cpp b/src/bts.cpp
index 18bee66..1696145 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -946,6 +946,123 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n
}
}
+void gprs_rlcmac_pdch::rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *ack_nack, uint32_t fn)
+{
+ int8_t tfi = 0; /* must be signed */
+ struct gprs_rlcmac_dl_tbf *tbf;
+ struct pcu_l1_meas meas;
+ int rc;
+ int num_blocks;
+ uint8_t bits_data[RLC_EGPRS_MAX_WS/8];
+ char show_bits[RLC_EGPRS_MAX_WS + 1];
+ bitvec bits;
+ int bsn_begin, bsn_end;
+
+ tfi = ack_nack->DOWNLINK_TFI;
+ tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
+ if (!tbf) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
+ "unknown FN=%u TFI=%d (TRX %d TS %d)\n",
+ fn, tfi, trx_no(), ts_no);
+ return;
+ }
+ if (tbf->tfi() != tfi) {
+ LOGP(DRLCMAC, LOGL_NOTICE, "EGPRS PACKET DOWNLINK ACK with "
+ "wrong TFI=%d, ignoring!\n", tfi);
+ return;
+ }
+ tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_DL_ACK);
+ if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
+ tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
+ LOGP(DRLCMAC, LOGL_NOTICE, "Recovered EGPRS downlink ack "
+ "for %s\n", tbf_name(tbf));
+ }
+ /* reset N3105 */
+ tbf->n3105 = 0;
+ tbf->stop_t3191();
+ LOGP(DRLCMAC, LOGL_DEBUG,
+ "RX: [PCU <- BTS] %s EGPRS Packet Downlink Ack/Nack\n",
+ tbf_name(tbf));
+ tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
+
+ LOGP(DRLCMAC, LOGL_DEBUG, "EGPRS ACK/NACK: "
+ "ut: %d, final: %d, bow: %d, eow: %d, ssn: %d, have_crbb: %d, "
+ "urbb_len:%d, %p, %p, %d, %d, win: %d-%d, urbb: %s\n",
+ (int)ack_nack->EGPRS_AckNack.UnionType,
+ (int)ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
+ (int)ack_nack->EGPRS_AckNack.Desc.BEGINNING_OF_WINDOW,
+ (int)ack_nack->EGPRS_AckNack.Desc.END_OF_WINDOW,
+ (int)ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER,
+ (int)ack_nack->EGPRS_AckNack.Desc.Exist_CRBB,
+ (int)ack_nack->EGPRS_AckNack.Desc.URBB_LENGTH,
+ (void *)&ack_nack->EGPRS_AckNack.UnionType,
+ (void *)&ack_nack->EGPRS_AckNack.Desc,
+ (int)offsetof(EGPRS_AckNack_t, Desc),
+ (int)offsetof(EGPRS_AckNack_w_len_t, Desc),
+ tbf->m_window.v_a(),
+ tbf->m_window.v_s(),
+ osmo_hexdump((const uint8_t *)&ack_nack->EGPRS_AckNack.Desc.URBB,
+ sizeof(ack_nack->EGPRS_AckNack.Desc.URBB)));
+
+ bits.data = bits_data;
+ bits.data_len = sizeof(bits_data);
+ bits.cur_bit = 0;
+
+ num_blocks = Decoding::decode_egprs_acknack_bits(
+ &ack_nack->EGPRS_AckNack.Desc, &bits,
+ &bsn_begin, &bsn_end, &tbf->m_window);
+
+ for (int i = 0; i < num_blocks; i++) {
+ show_bits[i] = bitvec_get_bit_pos(&bits, i) ? 'R' : 'I';
+ }
+ show_bits[num_blocks] = 0;
+
+ LOGP(DRLCMAC, LOGL_DEBUG,
+ "EGPRS DL ACK bitmap: BSN %d to %d - 1 (%d blocks): %s\n",
+ bsn_begin, bsn_end, num_blocks, show_bits);
+
+ if (ack_nack->EGPRS_AckNack.Desc.URBB_LENGTH == 0 &&
+ !ack_nack->EGPRS_AckNack.Desc.Exist_CRBB)
+ {
+ /* Everything has been received successfully */
+ /* Fake a GPRS type ack */
+ uint64_t fake_map = -1;
+
+ rc = tbf->rcvd_dl_ack(
+ ack_nack->EGPRS_AckNack.Desc.FINAL_ACK_INDICATION,
+ tbf->m_window.mod_sns(ack_nack->EGPRS_AckNack.Desc.STARTING_SEQUENCE_NUMBER-1),
+ (uint8_t *)&fake_map);
+
+ if (rc == 1) {
+ tbf_free(tbf);
+ return;
+ }
+ }
+
+ /* check for channel request */
+ if (ack_nack->Exist_ChannelRequestDescription) {
+ LOGP(DRLCMAC, LOGL_DEBUG, "MS requests UL TBF in ack "
+ "message, so we provide one:\n");
+
+ /* This call will register the new TBF with the MS on success */
+ tbf_alloc_ul(bts_data(), tbf->trx->trx_no,
+ tbf->ms_class(), tbf->ms()->egprs_ms_class(),
+ tbf->tlli(), tbf->ta(), tbf->ms());
+
+ /* schedule uplink assignment */
+ tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
+ }
+
+ /* get measurements */
+ if (tbf->ms()) {
+ /* TODO: Implement Measurements parsing for EGPRS */
+ /*
+ get_meas(&meas, &ack_nack->Channel_Quality_Report);
+ tbf->ms()->update_l1_meas(&meas);
+ */
+ }
+}
+
void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn)
{
struct gprs_rlcmac_sba *sba;
@@ -1105,6 +1222,9 @@ int gprs_rlcmac_pdch::rcv_control_block(
case MT_PACKET_DOWNLINK_ACK_NACK:
rcv_control_dl_ack_nack(&ul_control_block->u.Packet_Downlink_Ack_Nack, fn);
break;
+ case MT_EGPRS_PACKET_DOWNLINK_ACK_NACK:
+ rcv_control_egprs_dl_ack_nack(&ul_control_block->u.Egprs_Packet_Downlink_Ack_Nack, fn);
+ break;
case MT_PACKET_RESOURCE_REQUEST:
rcv_resource_request(&ul_control_block->u.Packet_Resource_Request, fn);
break;
diff --git a/src/bts.h b/src/bts.h
index 0928f8d..52154cb 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -107,6 +107,7 @@ private:
void rcv_control_ack(Packet_Control_Acknowledgement_t *, uint32_t fn);
void rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *, uint32_t fn);
+ void rcv_control_egprs_dl_ack_nack(EGPRS_PD_AckNack_t *, uint32_t fn);
void rcv_resource_request(Packet_Resource_Request_t *t, uint32_t fn);
void rcv_measurement_report(Packet_Measurement_Report_t *t, uint32_t fn);
gprs_rlcmac_tbf *tbf_from_list_by_tfi(
diff --git a/src/csn1.cpp b/src/csn1.cpp
index 377c50f..54cc411 100644
--- a/src/csn1.cpp
+++ b/src/csn1.cpp
@@ -549,6 +549,7 @@ csnStreamDecoder(csnStream_t* ar, const CSN_DESCR* pDescr, bitvec *vector, unsig
csnStreamInit(&arT, bit_offset, length);
arT.direction = 1;
+ LOGPC(DCSN1, LOGL_NOTICE, "ptr = %p | offset = %d | ", (void *)data, (int)pDescr->offset);
Status = serialize(&arT, vector, readIndex, pvDATA(data, pDescr->offset));
if (Status >= 0)
diff --git a/src/decoding.cpp b/src/decoding.cpp
index cb1b34d..f4cd880 100644
--- a/src/decoding.cpp
+++ b/src/decoding.cpp
@@ -493,3 +493,94 @@ const uint8_t *Decoding::rlc_get_data_aligned(
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;
+
+ 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) {
+ /* 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;
+ /*
+ decode_t4_rle(bits, desc->CRBB, desc->CRBB_LENGTH,
+ desc->CRBB_STARTING_COLOR_CODE);
+ */
+
+ 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;
+ }
+
+ *bsn_begin = window->v_a();
+ *bsn_end = window->mod_sns(*bsn_begin + num_blocks);
+
+ return num_blocks;
+}
diff --git a/src/decoding.h b/src/decoding.h
index c75b19a..99cb318 100644
--- a/src/decoding.h
+++ b/src/decoding.h
@@ -24,6 +24,8 @@
#include <stdint.h>
+struct bitvec;
+
class Decoding {
public:
struct RlcData {
@@ -51,4 +53,8 @@ public:
const struct gprs_rlc_data_info *rlc,
unsigned int data_block_idx,
const uint8_t *src, uint8_t *buffer);
+ static int decode_egprs_acknack_bits(
+ const EGPRS_AckNack_Desc_t *desc,
+ struct bitvec *bits, int *bsn_begin, int *bsn_end,
+ struct gprs_rlc_dl_window *window);
};