aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bts.cpp187
-rw-r--r--src/tbf.cpp194
-rw-r--r--src/tbf.h4
3 files changed, 199 insertions, 186 deletions
diff --git a/src/bts.cpp b/src/bts.cpp
index 91436f70..96d1753f 100644
--- a/src/bts.cpp
+++ b/src/bts.cpp
@@ -511,9 +511,6 @@ void BTS::snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi)
* PDCH code below. TODO: move to a separate file
*/
-/* After receiving these frames, we send ack/nack. */
-#define SEND_ACK_AFTER_FRAMES 20
-
void gprs_rlcmac_pdch::enable()
{
/* TODO: Check if there are still allocated resources.. */
@@ -650,8 +647,6 @@ int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len, in
{
struct gprs_rlcmac_tbf *tbf;
struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
- uint16_t mod_sns, mod_sns_half, offset_v_q, offset_v_r, index;
- int rc;
switch (len) {
case 54:
@@ -682,188 +677,8 @@ int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len, in
rh->tfi);
return 0;
}
- tbf->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, tbf->dir.ul.v_q, tbf->dir.ul.v_r);
-
- /* process RSSI */
- gprs_rlcmac_rssi(tbf, rssi);
-
- /* get TLLI */
- if (!tbf->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;
- }
- tbf->update_tlli(tlli);
- LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
- "UL DATA TFI=%d.\n", tbf->tlli(), rh->tfi);
- if ((dl_tbf = bts()->tbf_by_tlli(tbf->tlli(), GPRS_RLCMAC_DL_TBF))) {
- LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
- "TLLI=0x%08x while %s still exists. "
- "Killing pending DL TBF\n", tbf->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(tbf->tlli(), GPRS_RLCMAC_UL_TBF))) {
- LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
- "TLLI=0x%08x while %s still exists. "
- "Killing pending UL TBF\n", tbf->tlli(),
- tbf_name(ul_tbf));
- tbf_free(ul_tbf);
- }
- /* mark TLLI valid now */
- tbf->tlli_mark_valid();
- /* store current timing advance */
- bts()->timing_advance()->remember(tbf->tlli(), tbf->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 != tbf->tlli()) {
- LOGP(DRLCMACUL, LOGL_NOTICE, "TLLI mismatch on UL "
- "DATA TFI=%d. (Ignoring due to contention "
- "resolution)\n", rh->tfi);
- return 0;
- }
- }
-
- mod_sns = tbf->sns - 1;
- mod_sns_half = (tbf->sns >> 1) - 1;
-
- /* restart T3169 */
- tbf_timer_start(tbf, 3169, bts_data()->t3169, 0);
- /* Increment RX-counter */
- tbf->dir.ul.rx_counter++;
-
- /* current block relative to lowest unreceived block */
- offset_v_q = (rh->bsn - tbf->dir.ul.v_q) & mod_sns;
- /* If out of window (may happen if blocks below V(Q) are received
- * again. */
- if (offset_v_q >= tbf->ws) {
- LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d out of window "
- "%d..%d (it's normal)\n", rh->bsn, tbf->dir.ul.v_q,
- (tbf->dir.ul.v_q + tbf->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(tbf->rlc_block[index], data, len); /* Copy block. */
- tbf->rlc_block_len[index] = len;
- tbf->dir.ul.v_n[index] = 'R'; /* Mark received block. */
- LOGP(DRLCMACUL, LOGL_DEBUG, "- BSN %d storing in window (%d..%d)\n",
- rh->bsn, tbf->dir.ul.v_q,
- (tbf->dir.ul.v_q + tbf->ws - 1) & mod_sns);
- /* Raise V(R) to highest received sequence number not received. */
- offset_v_r = (rh->bsn + 1 - tbf->dir.ul.v_r) & mod_sns;
- if (offset_v_r < (tbf->sns >> 1)) { /* Positive offset, so raise. */
- while (offset_v_r--) {
- if (offset_v_r) /* all except the received block */
- tbf->dir.ul.v_n[tbf->dir.ul.v_r & mod_sns_half]
- = 'N'; /* Mark block as not received */
- tbf->dir.ul.v_r = (tbf->dir.ul.v_r + 1) & mod_sns;
- /* Inc V(R). */
- }
- LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n",
- tbf->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 (tbf->dir.ul.v_q != tbf->dir.ul.v_r && tbf->dir.ul.v_n[
- (index = tbf->dir.ul.v_q & mod_sns_half)] == 'R') {
- LOGP(DRLCMACUL, LOGL_DEBUG, "- Taking block %d out, raising "
- "V(Q) to %d\n", tbf->dir.ul.v_q,
- (tbf->dir.ul.v_q + 1) & mod_sns);
- /* get LLC data from block */
- tbf->assemble_forward_llc(tbf->rlc_block[index], tbf->rlc_block_len[index]);
- /* raise V(Q), because block already received */
- tbf->dir.ul.v_q = (tbf->dir.ul.v_q + 1) & mod_sns;
- }
-
- /* Check CV of last frame in buffer */
- if (tbf->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */
- && tbf->dir.ul.v_q == tbf->dir.ul.v_r) { /* if complete */
- struct rlc_ul_header *last_rh = (struct rlc_ul_header *)
- tbf->rlc_block[(tbf->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(tbf, GPRS_RLCMAC_FINISHED);
- /* Reset N3103 counter. */
- tbf->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 || tbf->state_is(GPRS_RLCMAC_FINISHED)
- || (tbf->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 (tbf->state_is(GPRS_RLCMAC_FINISHED)) {
- LOGP(DRLCMACUL, LOGL_DEBUG, "- Scheduling Ack/Nack, "
- "because last block has CV==0.\n");
- }
- if ((tbf->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 (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_NONE) {
-#ifdef DEBUG_DIAGRAM
- if (rh->si)
- debug_diagram(bts->bts, tbf->diag, "sched UL-ACK stall");
- if (rh->ti)
- debug_diagram(bts->bts, tbf->diag, "sched UL-ACK TLLI");
- if (tbf->state_is(GPRS_RLCMAC_FINISHED))
- debug_diagram(bts->bts, tbf->diag, "sched UL-ACK CV==0");
- if ((tbf->dir.ul.rx_counter % SEND_ACK_AFTER_FRAMES) == 0)
- debug_diagram(bts->bts, tbf->diag, "sched UL-ACK n=%d",
- tbf->dir.ul.rx_counter);
-#endif
- /* trigger sending at next RTS */
- tbf->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;
+ return tbf->rcv_data_block_acknowledged(data, len, rssi);
}
void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, uint32_t fn)
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];
diff --git a/src/tbf.h b/src/tbf.h
index e31653d4..fb4a64c0 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -23,6 +23,7 @@
#include <stdint.h>
struct bssgp_bvc_ctx;
+struct rlc_ul_header;
/*
* TBF instance
@@ -105,6 +106,9 @@ struct gprs_rlcmac_tbf {
struct msgb *create_ul_ack(uint32_t fn);
int snd_dl_ack(uint8_t final, uint8_t ssn, uint8_t *rbb);
+ /* blocks were acked */
+ int rcv_data_block_acknowledged(const uint8_t *data, size_t len, int8_t rssi);
+
int rlcmac_diag();
int update();