From ae9c575d2c2e7f906c41d28682445e6c8cb53f03 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Wed, 13 Jan 2016 13:55:44 +0100 Subject: 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 --- src/bts.cpp | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bts.h | 1 + src/csn1.cpp | 1 + src/decoding.cpp | 91 +++++++++++++++++++++++++++++++++++++++++ src/decoding.h | 6 +++ 5 files changed, 219 insertions(+) (limited to 'src') diff --git a/src/bts.cpp b/src/bts.cpp index 18bee665..16961454 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 0928f8d7..52154cb2 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 377c50f4..54cc411c 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 cb1b34d4..f4cd8802 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 c75b19a1..99cb3187 100644 --- a/src/decoding.h +++ b/src/decoding.h @@ -24,6 +24,8 @@ #include +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); }; -- cgit v1.2.3