diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2016-02-03 15:29:16 +0100 |
---|---|---|
committer | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2016-02-03 19:23:49 +0100 |
commit | 21252bd737c9a33e1fdce1da9d20474fed9bcd2a (patch) | |
tree | 3a9a26f75e7e8ba2141da3c7c1440d00c76b9514 | |
parent | c0f419b0756538e6a35b231026278191bb8a88c9 (diff) |
WIP: second BSN (TODO)
Ticket: OW#????
Sponsored-by: On-Waves ehf
-rw-r--r-- | src/rlc.h | 1 | ||||
-rw-r--r-- | src/tbf.h | 5 | ||||
-rw-r--r-- | src/tbf_dl.cpp | 165 |
3 files changed, 105 insertions, 66 deletions
@@ -31,6 +31,7 @@ #define RLC_EGPRS_MIN_WS 64 /* min window size */ #define RLC_EGPRS_MAX_WS 1024 /* min window size */ #define RLC_EGPRS_SNS 2048 /* EGPRS, must be power of 2 */ +#define RLC_EGPRS_MAX_BSN_DELTA 512 #define RLC_MAX_SNS RLC_EGPRS_SNS #define RLC_MAX_WS RLC_EGPRS_MAX_WS #define RLC_MAX_LEN 74 /* MCS-9 data unit */ @@ -407,7 +407,10 @@ protected: unsigned lost_bytes; }; - int create_new_bsn(const uint32_t fn, const uint8_t ts); + int take_next_bsn(uint32_t fn, int previous_bsn, + GprsCodingScheme *next_cs); + bool restart_bsn_cycle(); + int create_new_bsn(const uint32_t fn, GprsCodingScheme cs); struct msgb *create_dl_acked_block(const uint32_t fn, const uint8_t ts, int index, int index2 = -1); int update_window(const uint8_t ssn, const uint8_t *rbb); diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index c4334586..27b80bdd 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -326,94 +326,133 @@ drop_frame: return msg; } -/* - * Create DL data block - * The messages are fragmented and forwarded as data blocks. - */ -struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts) +bool gprs_rlcmac_dl_tbf::restart_bsn_cycle() { - LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink (V(A)==%d .. " - "V(S)==%d)\n", tbf_name(this), - m_window.v_a(), m_window.v_s()); + /* If V(S) == V(A) and finished state, we would have received + * acknowledgement of all transmitted block. In this case we would + * have transmitted the final block, and received ack from MS. But in + * this case we did not receive the final ack indication from MS. This + * should never happen if MS works correctly. + */ + if (m_window.window_empty()) { + LOGP(DRLCMACDL, LOGL_DEBUG, "- MS acked all blocks\n"); + return false; + } -do_resend: - /* check if there is a block with negative acknowledgement */ - int resend_bsn = m_window.resend_needed(); - if (resend_bsn >= 0) { - int resend_bsn2 = -1; - LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", resend_bsn); - /* re-send block with negative aknowlegement */ - m_window.m_v_b.mark_unacked(resend_bsn); - bts->rlc_resent(); - if (m_rlc.block(resend_bsn)->cs.headerTypeData() == GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) - { - resend_bsn2 = m_window.resend_needed(); - if (resend_bsn >= 0) { - LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d (second)\n", resend_bsn2); - /* re-send block with negative aknowlegement */ - m_window.m_v_b.mark_unacked(resend_bsn2); - bts->rlc_resent(); - } - } - return create_dl_acked_block(fn, ts, resend_bsn, resend_bsn2); + /* cycle through all unacked blocks */ + int resend = m_window.mark_for_resend(); + + /* At this point there should be at least one unacked block + * to be resent. If not, this is an software error. */ + if (resend == 0) { + LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " + "There are no unacknowledged blocks, but V(A) " + " != V(S). PLEASE FIX!\n"); + return false; + } + + return true; +} + +int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn, + int previous_bsn, GprsCodingScheme *next_cs) +{ + int bsn; + GprsCodingScheme cs2; + GprsCodingScheme force_cs; + + bsn = m_window.resend_needed(); + + if (previous_bsn >= 0) { + force_cs = m_rlc.block(previous_bsn)->cs; + if (!force_cs.isEgprs()) + return -1; } - /* if the window has stalled, or transfer is complete, - * send an unacknowledged block */ - if (state_is(GPRS_RLCMAC_FINISHED)) { + if (bsn >= 0) { + if (previous_bsn >= 0 && + m_window.mod_sns(bsn - previous_bsn) > RLC_EGPRS_MAX_BSN_DELTA) + return -1; + + cs2 = m_rlc.block(bsn)->cs; + if (force_cs && !cs2.isCombinable(force_cs)) + return -1; + LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n", bsn); + /* re-send block with negative aknowlegement */ + m_window.m_v_b.mark_unacked(bsn); + bts->rlc_resent(); + } else if (state_is(GPRS_RLCMAC_FINISHED)) { LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, " "because all blocks have been transmitted.\n", m_window.v_a()); bts->rlc_restarted(); + if (restart_bsn_cycle()) + return take_next_bsn(fn, previous_bsn, next_cs); } else if (dl_window_stalled()) { LOGP(DRLCMACDL, LOGL_NOTICE, "- Restarting at BSN %d, " - "because all window is stalled.\n", + "because the window is stalled.\n", m_window.v_a()); bts->rlc_stalled(); + if (restart_bsn_cycle()) + return take_next_bsn(fn, previous_bsn, next_cs); } else if (have_data()) { /* New blocks may be send */ - int bsn = create_new_bsn(fn, ts); - if (have_data() && m_rlc.block(bsn)->cs.headerTypeData() == GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1) - create_new_bsn(fn, ts); + cs2 = force_cs ? force_cs : current_cs(); + LOGP(DRLCMACDL, LOGL_DEBUG, + "- Sending new data block at BSN %d, CS=%s\n", + m_window.v_s(), cs2.name()); + + bsn = create_new_bsn(fn, cs2); } else if (!m_window.window_empty()) { LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, " "because all blocks have been transmitted (FLOW).\n", m_window.v_a()); bts->rlc_restarted(); + if (restart_bsn_cycle()) + return take_next_bsn(fn, previous_bsn, next_cs); } else { /* Nothing left to send, create dummy LLC commands */ - create_new_bsn(fn, ts); + LOGP(DRLCMACDL, LOGL_DEBUG, + "- Sending new dummy block at BSN %d, CS=%s\n", + m_window.v_s(), current_cs().name()); + bsn = create_new_bsn(fn, current_cs()); + /* Don't send a second block */ } - /* If V(S) == V(A) and finished state, we would have received - * acknowledgement of all transmitted block. In this case we - * would have transmitted the final block, and received ack - * from MS. But in this case we did not receive the final ack - * indication from MS. This should never happen if MS works - * correctly. */ - if (m_window.window_empty()) { - LOGP(DRLCMACDL, LOGL_DEBUG, "- MS acked all blocks, " - "so we re-transmit final block!\n"); + if (bsn < 0) { /* we just send final block again */ - int16_t index = m_window.v_s_mod(-1); + LOGP(DRLCMACDL, LOGL_DEBUG, + "- Nothing else to send, Re-transmit final block!\n"); + bsn = m_window.v_s_mod(-1); bts->rlc_resent(); - return create_dl_acked_block(fn, ts, index); } - /* cycle through all unacked blocks */ - int resend = m_window.mark_for_resend(); + *next_cs = cs2; - /* At this point there should be at least one unacked block - * to be resent. If not, this is an software error. */ - if (resend == 0) { - LOGP(DRLCMACDL, LOGL_ERROR, "Software error: " - "There are no unacknowledged blocks, but V(A) " - " != V(S). PLEASE FIX!\n"); - /* we just send final block again */ - int16_t index = m_window.v_s_mod(-1); - return create_dl_acked_block(fn, ts, index); - } - goto do_resend; + return bsn; +} + +/* + * Create DL data block + * The messages are fragmented and forwarded as data blocks. + */ +struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(uint32_t fn, uint8_t ts) +{ + int bsn, bsn2 = -1; + GprsCodingScheme cs, next_cs; + + LOGP(DRLCMACDL, LOGL_DEBUG, "%s downlink (V(A)==%d .. " + "V(S)==%d)\n", tbf_name(this), + m_window.v_a(), m_window.v_s()); + + bsn = take_next_bsn(fn, -1, &next_cs); + if (bsn < 0) + return NULL; + + if (next_cs && next_cs.numDataBlocks() > 1) + bsn2 = take_next_bsn(fn, bsn, &next_cs); + + return create_dl_acked_block(fn, ts, bsn, bsn2); } void gprs_rlcmac_dl_tbf::schedule_next_frame() @@ -438,12 +477,11 @@ void gprs_rlcmac_dl_tbf::schedule_next_frame() m_last_dl_drained_fn = -1; } -int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts) +int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, GprsCodingScheme cs) { uint8_t *data; gprs_rlc_data *rlc_data; const uint16_t bsn = m_window.v_s(); - GprsCodingScheme cs = current_cs(); gprs_rlc_data_block_info *rdbi; int num_chunks = 0; int write_offset = 0; @@ -452,9 +490,6 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts) if (m_llc.frame_length() == 0) schedule_next_frame(); - LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d, CS=%s\n", - m_window.v_s(), cs.name()); - OSMO_ASSERT(cs.isValid()); /* length of usable data block (single data unit w/o header) */ |