aboutsummaryrefslogtreecommitdiffstats
path: root/src/tbf.cpp
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2013-11-06 19:16:43 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2013-11-06 19:16:43 +0100
commit77e05971b461ec420cc6c3f1f82a97f681c100a9 (patch)
treed58f2d8774be19840a337d48c925e6ef93d28e2d /src/tbf.cpp
parentbc1626e5de38d7efbea272596d0ec5cc37f4b424 (diff)
tbf: Move the llc handling into the tbf (from the bts)
This will be moved to a LLC class in the future but after this we can make the sns/ws private now and have little to update outside the tbf.
Diffstat (limited to 'src/tbf.cpp')
-rw-r--r--src/tbf.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 356984f5..e571f703 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -26,6 +26,7 @@
#include <gprs_rlcmac.h>
#include <gprs_debug.h>
#include <gprs_bssgp_pcu.h>
+#include <decoding.h>
extern "C" {
#include <osmocom/core/msgb.h>
@@ -37,6 +38,9 @@ extern "C" {
/* After sending these frames, we poll for ack/nack. */
#define POLL_ACK_AFTER_FRAMES 20
+/* After receiving these frames, we send ack/nack. */
+#define SEND_ACK_AFTER_FRAMES 20
+
/* If acknowledgement to downlink assignment should be polled */
#define POLLING_ASSIGNMENT_DL 1
@@ -1650,6 +1654,196 @@ void gprs_rlcmac_tbf::update_tlli(uint32_t tlli)
m_tlli = tlli;
}
+int gprs_rlcmac_tbf::rcv_data_block_acknowledged(const uint8_t *data, size_t len, int8_t rssi)
+{
+ uint16_t mod_sns, mod_sns_half, offset_v_q, offset_v_r, index;
+ struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
+ int rc;
+
+ this->state_flags |= (1 << GPRS_RLCMAC_FLAG_UL_DATA);
+
+ LOGP(DRLCMACUL, LOGL_DEBUG, "UL DATA TFI=%d received (V(Q)=%d .. "
+ "V(R)=%d)\n", rh->tfi, this->dir.ul.v_q, this->dir.ul.v_r);
+
+ /* process RSSI */
+ gprs_rlcmac_rssi(this, rssi);
+
+ /* get TLLI */
+ if (!this->is_tlli_valid()) {
+ struct gprs_rlcmac_tbf *dl_tbf, *ul_tbf;
+ uint32_t tlli;
+
+ /* no TLLI yet */
+ if (!rh->ti) {
+ LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d without "
+ "TLLI, but no TLLI received yet\n", rh->tfi);
+ return 0;
+ }
+ rc = Decoding::tlli_from_ul_data(data, len, &tlli);
+ if (rc) {
+ bts->decode_error();
+ LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI "
+ "of UL DATA TFI=%d.\n", rh->tfi);
+ return 0;
+ }
+ this->update_tlli(tlli);
+ LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
+ "UL DATA TFI=%d.\n", this->tlli(), rh->tfi);
+ if ((dl_tbf = bts->tbf_by_tlli(this->tlli(), GPRS_RLCMAC_DL_TBF))) {
+ LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
+ "TLLI=0x%08x while %s still exists. "
+ "Killing pending DL TBF\n", this->tlli(),
+ tbf_name(dl_tbf));
+ tbf_free(dl_tbf);
+ }
+ /* tbf_by_tlli will not find your TLLI, because it is not
+ * yet marked valid */
+ if ((ul_tbf = bts->tbf_by_tlli(this->tlli(), GPRS_RLCMAC_UL_TBF))) {
+ LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
+ "TLLI=0x%08x while %s still exists. "
+ "Killing pending UL TBF\n", this->tlli(),
+ tbf_name(ul_tbf));
+ tbf_free(ul_tbf);
+ }
+ /* mark TLLI valid now */
+ this->tlli_mark_valid();
+ /* store current timing advance */
+ bts->timing_advance()->remember(this->tlli(), this->ta);
+ /* already have TLLI, but we stille get another one */
+ } else if (rh->ti) {
+ uint32_t tlli;
+ rc = Decoding::tlli_from_ul_data(data, len, &tlli);
+ if (rc) {
+ LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI "
+ "of UL DATA TFI=%d.\n", rh->tfi);
+ return 0;
+ }
+ if (tlli != this->tlli()) {
+ LOGP(DRLCMACUL, LOGL_NOTICE, "TLLI mismatch on UL "
+ "DATA TFI=%d. (Ignoring due to contention "
+ "resolution)\n", rh->tfi);
+ return 0;
+ }
+ }
+
+ mod_sns = this->sns - 1;
+ mod_sns_half = (this->sns >> 1) - 1;
+
+ /* restart T3169 */
+ tbf_timer_start(this, 3169, bts_data()->t3169, 0);
+
+ /* Increment RX-counter */
+ this->dir.ul.rx_counter++;
+
+ /* current block relative to lowest unreceived block */
+ offset_v_q = (rh->bsn - this->dir.ul.v_q) & mod_sns;
+ /* If out of window (may happen if blocks below V(Q) are received
+ * again. */
+ if (offset_v_q >= this->ws) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d out of window "
+ "%d..%d (it's normal)\n", rh->bsn, this->dir.ul.v_q,
+ (this->dir.ul.v_q + this->ws - 1) & mod_sns);
+ return 0;
+ }
+ /* Write block to buffer and set receive state array. */
+ index = rh->bsn & mod_sns_half; /* memory index of block */
+ memcpy(this->rlc_block[index], data, len); /* Copy block. */
+ this->rlc_block_len[index] = len;
+ this->dir.ul.v_n[index] = 'R'; /* Mark received block. */
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n",
+ rh->bsn, this->dir.ul.v_q,
+ (this->dir.ul.v_q + this->ws - 1) & mod_sns);
+ /* Raise V(R) to highest received sequence number not received. */
+ offset_v_r = (rh->bsn + 1 - this->dir.ul.v_r) & mod_sns;
+ if (offset_v_r < (this->sns >> 1)) { /* Positive offset, so raise. */
+ while (offset_v_r--) {
+ if (offset_v_r) /* all except the received block */
+ this->dir.ul.v_n[this->dir.ul.v_r & mod_sns_half]
+ = 'N'; /* Mark block as not received */
+ this->dir.ul.v_r = (this->dir.ul.v_r + 1) & mod_sns;
+ /* Inc V(R). */
+ }
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n",
+ this->dir.ul.v_r);
+ }
+
+ #warning "Move to TBF and remove the index side effect.."
+ /* Raise V(Q) if possible, and retrieve LLC frames from blocks.
+ * This is looped until there is a gap (non received block) or
+ * the window is empty.*/
+ while (this->dir.ul.v_q != this->dir.ul.v_r && this->dir.ul.v_n[
+ (index = this->dir.ul.v_q & mod_sns_half)] == 'R') {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising "
+ "V(Q) to %d\n", this->dir.ul.v_q,
+ (this->dir.ul.v_q + 1) & mod_sns);
+ /* get LLC data from block */
+ this->assemble_forward_llc(this->rlc_block[index], this->rlc_block_len[index]);
+ /* raise V(Q), because block already received */
+ this->dir.ul.v_q = (this->dir.ul.v_q + 1) & mod_sns;
+ }
+
+ /* Check CV of last frame in buffer */
+ if (this->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */
+ && this->dir.ul.v_q == this->dir.ul.v_r) { /* if complete */
+ struct rlc_ul_header *last_rh = (struct rlc_ul_header *)
+ this->rlc_block[(this->dir.ul.v_r - 1) & mod_sns_half];
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- No gaps in received block, "
+ "last block: BSN=%d CV=%d\n", last_rh->bsn,
+ last_rh->cv);
+ if (last_rh->cv == 0) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Finished with UL "
+ "TBF\n");
+ tbf_new_state(this, GPRS_RLCMAC_FINISHED);
+ /* Reset N3103 counter. */
+ this->dir.ul.n3103 = 0;
+ }
+ }
+
+ /* If TLLI is included or if we received half of the window, we send
+ * an ack/nack */
+ if (rh->si || rh->ti || this->state_is(GPRS_RLCMAC_FINISHED)
+ || (this->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
+ if (rh->si) {
+ LOGP(DRLCMACUL, LOGL_NOTICE, "- Scheduling Ack/Nack, "
+ "because MS is stalled.\n");
+ }
+ if (rh->ti) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
+ "because TLLI is included.\n");
+ }
+ if (this->state_is(GPRS_RLCMAC_FINISHED)) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
+ "because last block has CV==0.\n");
+ }
+ if ((this->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0) {
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
+ "because %d frames received.\n",
+ SEND_ACK_AFTER_FRAMES);
+ }
+ if (this->ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) {
+#ifdef DEBUG_DIAGRAM
+ if (rh->si)
+ debug_diagram(bts->bts, this->diag, "sched UL-ACK stall");
+ if (rh->ti)
+ debug_diagram(bts->bts, this->diag, "sched UL-ACK TLLI");
+ if (this->state_is(GPRS_RLCMAC_FINISHED))
+ debug_diagram(bts->bts, this->diag, "sched UL-ACK CV==0");
+ if ((this->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0)
+ debug_diagram(bts->bts, this->diag, "sched UL-ACK n=%d",
+ this->dir.ul.rx_counter);
+#endif
+ /* trigger sending at next RTS */
+ this->ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK;
+ } else {
+ /* already triggered */
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Sending Ack/Nack is "
+ "already triggered, don't schedule!\n");
+ }
+ }
+
+ return 0;
+}
+
const char *tbf_name(gprs_rlcmac_tbf *tbf)
{
static char buf[40];