diff options
author | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2013-11-06 19:16:43 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2013-11-06 19:16:43 +0100 |
commit | 77e05971b461ec420cc6c3f1f82a97f681c100a9 (patch) | |
tree | d58f2d8774be19840a337d48c925e6ef93d28e2d /src/tbf.cpp | |
parent | bc1626e5de38d7efbea272596d0ec5cc37f4b424 (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.cpp | 194 |
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]; |