From eb08f86c0278bc6c6d1ba42c82c66d564a5f7c06 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Fri, 5 Feb 2016 17:07:12 +0100 Subject: edge: Add bitvec based DL window updating methods The current methods are based on the GRPS specific RBB and SSN values and formats which are not compatible with EGPRS. Add a second set of similar methods with the same semantics but which are based on a bitvec and the first BSN instead. The following methods are affected: - gprs_rlc_dl_window::update - gprs_rlcmac_dl_tbf::rcvd_dl_ack - gprs_rlcmac_dl_tbf::update_window Sponsored-by: On-Waves ehf --- src/rlc.cpp | 31 ++++++++++++++++++++++ src/rlc.h | 4 +++ src/tbf.h | 2 ++ src/tbf_dl.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+) (limited to 'src') diff --git a/src/rlc.cpp b/src/rlc.cpp index 1a8efdf6..6d3cfd59 100644 --- a/src/rlc.cpp +++ b/src/rlc.cpp @@ -114,6 +114,37 @@ 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) */ + + 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..161ec26f 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -717,6 +717,75 @@ 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 (first_bsn..behind_last_bsn-1) */ + if (num_blocks > 0) { + /* 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! + * TODO: check whether this FIXME still makes sense + */ + 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 +894,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)); -- cgit v1.2.3