diff --git a/src/bts.cpp b/src/bts.cpp index b2336b88..6bdb4f3f 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -892,6 +892,9 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n struct gprs_rlcmac_dl_tbf *tbf; int rc; struct pcu_l1_meas meas; + uint8_t bits_data[RLC_GPRS_WS/8]; + bitvec bits; + int bsn_begin, bsn_end; tfi = ack_nack->DOWNLINK_TFI; tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no); @@ -918,10 +921,17 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] %s Packet Downlink Ack/Nack\n", tbf_name(tbf)); tbf->poll_state = GPRS_RLCMAC_POLL_NONE; + bits.data = bits_data; + bits.data_len = sizeof(bits_data); + bits.cur_bit = 0; + + Decoding::decode_gprs_acknack_bits( + &ack_nack->Ack_Nack_Description, &bits, + &bsn_begin, &bsn_end, &tbf->m_window); + rc = tbf->rcvd_dl_ack( ack_nack->Ack_Nack_Description.FINAL_ACK_INDICATION, - ack_nack->Ack_Nack_Description.STARTING_SEQUENCE_NUMBER, - ack_nack->Ack_Nack_Description.RECEIVED_BLOCK_BITMAP); + bsn_begin, &bits); if (rc == 1) { tbf_free(tbf); return; diff --git a/src/decoding.cpp b/src/decoding.cpp index 7fa77d7d..e2e22321 100644 --- a/src/decoding.cpp +++ b/src/decoding.cpp @@ -328,6 +328,18 @@ 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, const uint8_t *data, GprsCodingScheme cs) { @@ -534,9 +546,34 @@ int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc, urbb.data_len = sizeof(desc->URBB); for (int i = urbb_len; i > 0; i--) { - /* Set bit at the appropriate position (see 3GPP TS 04.60 12.3.1) */ + /* 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 ? ONE : ZERO); + bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO); + } + + 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; + + num_blocks = urbb_len; + + *bsn_end = desc->STARTING_SEQUENCE_NUMBER; + *bsn_begin = window->mod_sns(*bsn_end - RLC_GPRS_WS); + + urbb.cur_bit = 0; + urbb.data = (uint8_t *)desc->RECEIVED_BLOCK_BITMAP; + urbb.data_len = sizeof(desc->RECEIVED_BLOCK_BITMAP); + + for (int i = urbb_len; i > 0; i--) { + /* Set bit at the appropriate position (see 3GPP TS 44.060 12.3) */ + int is_ack = bitvec_get_bit_pos(&urbb, i-1); + bitvec_set_bit(bits, is_ack == 1 ? ONE : ZERO); } return num_blocks; diff --git a/src/decoding.h b/src/decoding.h index 99cb3187..58ecd18e 100644 --- a/src/decoding.h +++ b/src/decoding.h @@ -42,6 +42,7 @@ public: static uint8_t get_egprs_ms_class_by_capability(MS_Radio_Access_capability_t *cap); static void extract_rbb(const uint8_t *rbb, char *extracted_rbb); + static void extract_rbb(const struct bitvec *rbb, char *show_rbb); static int rlc_parse_ul_data_header(struct gprs_rlc_data_info *rlc, const uint8_t *data, GprsCodingScheme cs); @@ -57,4 +58,8 @@ public: const EGPRS_AckNack_Desc_t *desc, struct bitvec *bits, int *bsn_begin, int *bsn_end, struct gprs_rlc_dl_window *window); + static int decode_gprs_acknack_bits( + const Ack_Nack_Description_t *desc, + bitvec *bits, int *bsn_begin, int *bsn_end, + gprs_rlc_dl_window *window); }; diff --git a/src/rlc.cpp b/src/rlc.cpp index 1a8efdf6..27e8a5f2 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -114,6 +114,45 @@ static uint16_t bitnum_to_bsn(int bitnum, uint16_t ssn) return (ssn - 1 - bitnum); } +void gprs_rlc_dl_window::update(BTS *bts, const struct bitvec *rbb, + uint16_t first_bsn, uint16_t *lost, + uint16_t *received) +{ + unsigned num_blocks = rbb->cur_bit; + unsigned bsn; + + /* first_bsn is in range V(A)..V(S) */ + + /* All BSN before first_bsn are implicitly acknowledged */ + for (bsn = v_a(); bsn != first_bsn; bsn = mod_sns(bsn + 1)) { + LOGP(DRLCMACDL, LOGL_DEBUG, "- got implicit ack for BSN=%d\n", bsn); + if (!m_v_b.is_acked(bsn)) + *received += 1; + m_v_b.mark_acked(bsn); + } + + for (unsigned int bitpos = 0; bitpos < num_blocks; bitpos++) { + bool is_ack; + bsn = mod_sns(first_bsn + bitpos); + if (bsn == mod_sns(v_a() - 1)) + break; + + is_ack = bitvec_get_bit_pos(rbb, bitpos) == 1; + + if (is_ack) { + LOGP(DRLCMACDL, LOGL_DEBUG, "- got ack for BSN=%d\n", bsn); + if (!m_v_b.is_acked(bsn)) + *received += 1; + m_v_b.mark_acked(bsn); + } else { + LOGP(DRLCMACDL, LOGL_DEBUG, "- got NACK for BSN=%d\n", bsn); + m_v_b.mark_nacked(bsn); + bts->rlc_nacked(); + *lost += 1; + } + } +} + void gprs_rlc_dl_window::update(BTS *bts, char *show_rbb, uint16_t ssn, uint16_t *lost, uint16_t *received) { diff --git a/src/rlc.h b/src/rlc.h index 76af4e10..3f599d47 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -32,6 +32,7 @@ #define RLC_EGPRS_MAX_WS 1024 /* min window size */ #define RLC_EGPRS_SNS 2048 /* EGPRS, must be power of 2 */ #define RLC_MAX_SNS RLC_EGPRS_SNS +#define RLC_MAX_WS RLC_EGPRS_MAX_WS #define RLC_MAX_LEN 74 /* MCS-9 data unit */ struct BTS; @@ -173,6 +174,9 @@ struct gprs_rlc_dl_window { int mark_for_resend(); void update(BTS *bts, char *show_rbb, uint16_t ssn, uint16_t *lost, uint16_t *received); + void update(BTS *bts, const struct bitvec *rbb, + uint16_t first_bsn, uint16_t *lost, + uint16_t *received); int move_window(); void show_state(char *show_rbb); int count_unacked(); diff --git a/src/tbf.h b/src/tbf.h index cd982739..11e1fc73 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -344,6 +344,7 @@ struct gprs_rlcmac_dl_tbf : public gprs_rlcmac_tbf { const uint8_t *data, const uint16_t len); int rcvd_dl_ack(uint8_t final, uint8_t ssn, uint8_t *rbb); + int rcvd_dl_ack(uint8_t final_ack, unsigned first_bsn, struct bitvec *rbb); struct msgb *create_dl_acked_block(uint32_t fn, uint8_t ts); void request_dl_ack(); bool need_control_ts() const; @@ -395,6 +396,7 @@ protected: struct msgb *create_dl_acked_block(const uint32_t fn, const uint8_t ts, const int index); int update_window(const uint8_t ssn, const uint8_t *rbb); + int update_window(unsigned first_bsn, const struct bitvec *rbb); int maybe_start_new_window(); bool dl_window_stalled() const; void reuse_tbf(); diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index e742c799..ac14c478 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -644,9 +644,9 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn, { gprs_rlc_data *rlc_data; uint16_t lost = 0, received = 0, skipped = 0; - char info[65]; - memset(info, '.', sizeof(info)); - info[64] = 0; + char info[RLC_MAX_WS + 1]; + memset(info, '.', m_window.ws()); + info[m_window.ws()] = 0; uint16_t bsn = 0; unsigned received_bytes = 0, lost_bytes = 0; unsigned received_packets = 0, lost_packets = 0; @@ -717,6 +717,71 @@ int gprs_rlcmac_dl_tbf::analyse_errors(char *show_rbb, uint8_t ssn, return lost * 100 / (lost + received); } +int gprs_rlcmac_dl_tbf::update_window(unsigned first_bsn, + const struct bitvec *rbb) +{ + int16_t dist; /* must be signed */ + uint16_t lost = 0, received = 0; + char show_v_b[RLC_MAX_SNS + 1]; + char show_rbb[RLC_MAX_SNS + 1]; + int error_rate; + struct ana_result ana_res; + unsigned num_blocks = rbb->cur_bit; + unsigned behind_last_bsn = m_window.mod_sns(first_bsn + num_blocks); + + Decoding::extract_rbb(rbb, show_rbb); + /* show received array in debug */ + LOGP(DRLCMACDL, LOGL_DEBUG, "- ack: (BSN=%d)\"%s\"" + "(BSN=%d) R=ACK I=NACK\n", first_bsn, + show_rbb, m_window.mod_sns(behind_last_bsn - 1)); + + /* apply received array to receive state (SSN-64..SSN-1) */ + /* calculate distance of ssn from V(S) */ + dist = m_window.mod_sns(m_window.v_s() - behind_last_bsn); + /* check if distance is less than distance V(A)..V(S) */ + if (dist >= m_window.distance()) { + /* this might happpen, if the downlink assignment + * was not received by ms and the ack refers + * to previous TBF + * FIXME: we should implement polling for + * control ack!*/ + LOGP(DRLCMACDL, LOGL_NOTICE, "- ack range is out of " + "V(A)..V(S) range %s Free TBF!\n", tbf_name(this)); + return 1; /* indicate to free TBF */ + } + + error_rate = analyse_errors(show_rbb, behind_last_bsn, &ana_res); + + if (bts_data()->cs_adj_enabled && ms()) + ms()->update_error_rate(this, error_rate); + + m_window.update(bts, rbb, first_bsn, &lost, &received); + + /* report lost and received packets */ + gprs_rlcmac_received_lost(this, received, lost); + + /* Used to measure the leak rate */ + gprs_bssgp_update_bytes_received(ana_res.received_bytes, + ana_res.received_packets + ana_res.lost_packets); + + /* raise V(A), if possible */ + m_window.raise(m_window.move_window()); + + /* show receive state array in debug (V(A)..V(S)-1) */ + m_window.show_state(show_v_b); + LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\"" + "(V(S)-1=%d) A=Acked N=Nacked U=Unacked " + "X=Resend-Unacked I=Invalid\n", + m_window.v_a(), show_v_b, + m_window.v_s_mod(-1)); + + if (state_is(GPRS_RLCMAC_FINISHED) && m_window.window_empty()) { + LOGP(DRLCMACDL, LOGL_NOTICE, "Received acknowledge of " + "all blocks, but without final ack " + "inidcation (don't worry)\n"); + } + return 0; +} int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb) { @@ -825,6 +890,18 @@ int gprs_rlcmac_dl_tbf::release() } +int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, unsigned first_bsn, + struct bitvec *rbb) +{ + LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink acknowledge\n", tbf_name(this)); + + if (!final_ack) + return update_window(first_bsn, rbb); + + LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n"); + return maybe_start_new_window(); +} + int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb) { LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink acknowledge\n", tbf_name(this));