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.
This commit is contained in:
Holger Hans Peter Freyther 2013-11-06 19:16:43 +01:00
parent bc1626e5de
commit 77e05971b4
3 changed files with 199 additions and 186 deletions

View File

@ -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)

View File

@ -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];

View File

@ -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();