aboutsummaryrefslogtreecommitdiffstats
path: root/src/tbf_dl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tbf_dl.cpp')
-rw-r--r--src/tbf_dl.cpp157
1 files changed, 104 insertions, 53 deletions
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index 21b2ba13..e2521f84 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -326,81 +326,136 @@ 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) {
- 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();
- return create_dl_acked_block(fn, ts, resend_bsn);
+ /* 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;
}
- /* if the window has stalled, or transfer is complete,
- * send an unacknowledged block */
- if (state_is(GPRS_RLCMAC_FINISHED)) {
+ 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 (bsn >= 0) {
+ if (previous_bsn == bsn)
+ return -1;
+
+ 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 */
- return create_new_bsn(fn, ts);
+ cs2 = force_cs ? force_cs : current_cs();
+ LOGP(DRLCMACDL, LOGL_DEBUG,
+ "- Sending new 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 */
- return 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.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()
@@ -425,12 +480,11 @@ void gprs_rlcmac_dl_tbf::schedule_next_frame()
m_last_dl_drained_fn = -1;
}
-struct msgb *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;
@@ -439,9 +493,6 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t
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) */
@@ -514,7 +565,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t
m_window.m_v_b.mark_unacked(bsn);
m_window.increment_send();
- return create_dl_acked_block(fn, ts, bsn);
+ return bsn;
}
struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block(