osmo-pcu/src/tbf.cpp

933 lines
25 KiB
C++
Raw Normal View History

/* Copied from gprs_bssgp_pcu.cpp
*
* Copyright (C) 2012 Ivan Klyuchnikov
* Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
* Copyright (C) 2013 by Holger Hans Peter Freyther
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <bts.h>
#include <tbf.h>
#include <rlc.h>
#include <encoding.h>
#include <gprs_rlcmac.h>
#include <gprs_debug.h>
#include <gprs_bssgp_pcu.h>
#include <gprs_ms.h>
#include <decoding.h>
extern "C" {
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
}
#include <errno.h>
#include <string.h>
extern void *tall_pcu_ctx;
static void tbf_timer_cb(void *_tbf);
gprs_rlcmac_bts *gprs_rlcmac_tbf::bts_data() const
{
return bts->bts_data();
}
uint32_t gprs_rlcmac_tbf::tlli() const
{
return m_ms ? m_ms->tlli() : 0;
}
const char *gprs_rlcmac_tbf::imsi() const
{
static const char nullc = 0;
return m_ms ? m_ms->imsi() : &nullc;
}
void gprs_rlcmac_tbf::assign_imsi(const char *imsi_)
{
GprsMs *old_ms;
if (!imsi_ || !m_ms) {
LOGP(DRLCMAC, LOGL_ERROR,
"%s failed to assign IMSI: missing IMSI or MS object\n",
name());
return;
}
if (strcmp(imsi_, imsi()) == 0)
return;
/* really change the IMSI */
old_ms = bts->ms_store().get_ms(0, 0, imsi_);
if (old_ms) {
/* We cannot find m_ms by IMSI since we know that it has a
* different IMSI */
OSMO_ASSERT(old_ms != m_ms);
LOGP(DRLCMAC, LOGL_INFO,
"%s the IMSI '%s' was already assigned to another "
"MS object: TLLI = 0x%08x, that IMSI will be removed\n",
name(), imsi_, old_ms->tlli());
old_ms->set_imsi("");
}
m_ms->set_imsi(imsi_);
}
uint8_t gprs_rlcmac_tbf::ta() const
{
return m_ms ? m_ms->ta() : m_ta;
}
void gprs_rlcmac_tbf::set_ta(uint8_t ta)
{
if (ms())
ms()->set_ta(ta);
m_ta = ta;
}
gprs_llc_queue *gprs_rlcmac_tbf::llc_queue()
{
return m_ms ? m_ms->llc_queue() : NULL;
}
const gprs_llc_queue *gprs_rlcmac_tbf::llc_queue() const
{
return m_ms ? m_ms->llc_queue() : NULL;
}
void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
{
if (m_ms == ms)
return;
if (m_ms) {
/* Save the TA locally. This will also be called, if the MS
* object detaches itself from the TBF, for instance if
* attach_tbf() is called */
m_ta = m_ms->ta();
m_ms->detach_tbf(this);
}
m_ms = ms;
if (m_ms)
m_ms->attach_tbf(this);
}
void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
{
if (!ms()) {
GprsMs *new_ms = bts->ms_store().get_ms(tlli);
if (!new_ms) {
new_ms = bts->ms_store().create_ms(tlli, dir);
new_ms->set_timeout(bts->bts_data()->ms_idle_sec);
}
if (dir == GPRS_RLCMAC_UL_TBF)
new_ms->set_ta(m_ta);
set_ms(new_ms);
return;
}
if (dir == GPRS_RLCMAC_UL_TBF)
ms()->set_tlli(tlli);
else
ms()->confirm_tlli(tlli);
tbf,bts: Keep track of new TBF for dl/ul assignment in m_new_tbf There are a couple of possibilities where one TBF is used to assign a new one: 1. Assign a DL TBF from a UL TBF 2. Assign a UL TBF from a DL TBF 3. Assign a DL TBF from a DL TBF which is in wait-release state (T3193 is running) In these cases the assignment is sent on the existing TBF and triggers the assignement of the new TBF (with different TFI/direction). The current code detects these situations by looking at dl/ul_ass_state and then chosing the TBF with the opposite direction (DL/UL) that has the same TLLI. This does not work in the case 3 above where a new DL TBF is triggered for a DL TBF. The current code reuses the old TBF (and TFI), but this violates the spec. This patch introduces a m_new_tbf member which is set to the new TBF to be assigned. When receiving a control ack the code looks up the n_new_tbf member of the tbf that requested the control ack and completes the ul/dl assignment. If the old TBF was in the wait release state (T3193 is running) it is released. From 3GPP TS 04.60 9.3.2.6: """ If the network has received the PACKET DOWNLINK ACK/NACK message with the Final Ack Indicator bit set to '1' and has new data to transmit for the mobile station, the network may establish a new downlink TBF for the mobile station by sending the PACKET DOWNLINK ASSIGNMENT or PACKET TIMESLOT RECONFIGURE message with the Control Ack bit set to '1' on PACCH. In case the network establishes a new downlink TBF for the mobile station, the network shall stop timer T3193. """ reuse_tbf() is modified to allocate a new TBF with a new TFI and trigger a dl assignment for that TBF on the old TBF. All pending data is moved to the new TBF. Ticket: SYS#382 Sponsored-by: On-Waves ehf
2014-08-15 14:52:09 +00:00
}
gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
int8_t use_trx, uint8_t ms_class,
uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf)
{
uint8_t trx;
struct gprs_rlcmac_ul_tbf *tbf;
int8_t tfi; /* must be signed */
#warning "Copy and paste with tbf_new_dl_assignment"
2013-12-25 18:15:57 +00:00
/* create new TBF, use same TRX as DL TBF */
tfi = bts->bts->tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx, use_trx);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
/* FIXME: send reject */
return NULL;
}
/* use multislot class of downlink TBF */
tbf = tbf_alloc_ul_tbf(bts, dl_tbf, tfi, trx, ms_class, 0);
if (!tbf) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
/* FIXME: send reject */
return NULL;
}
tbf->m_contention_resolution_done = 1;
tbf->set_state(GPRS_RLCMAC_ASSIGN);
tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
tbf_timer_start(tbf, 3169, bts->t3169, 0);
tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
OSMO_ASSERT(tbf->ms());
tbf->ms()->set_ta(ta);
return tbf;
}
static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
{
int ts;
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
tbf->trx->ul_tbf[tbf->tfi()] = NULL;
for (ts = 0; ts < 8; ts++)
tbf->pdch[ts] = NULL;
} else {
tbf->trx->dl_tbf[tbf->tfi()] = NULL;
for (ts = 0; ts < 8; ts++)
tbf->pdch[ts] = NULL;
}
}
void tbf_free(struct gprs_rlcmac_tbf *tbf)
{
/* Give final measurement report */
gprs_rlcmac_rssi_rep(tbf);
if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(tbf);
gprs_rlcmac_lost_rep(dl_tbf);
dl_tbf->cleanup();
}
LOGP(DRLCMAC, LOGL_INFO, "%s free\n", tbf_name(tbf));
if (tbf->ul_ass_state != GPRS_RLCMAC_UL_ASS_NONE)
LOGP(DRLCMAC, LOGL_ERROR, "%s Software error: Pending uplink "
"assignment. This may not happen, because the "
"assignment message never gets transmitted. Please "
"be sure not to free in this state. PLEASE FIX!\n",
tbf_name(tbf));
if (tbf->dl_ass_state != GPRS_RLCMAC_DL_ASS_NONE)
LOGP(DRLCMAC, LOGL_ERROR, "%s Software error: Pending downlink "
"assignment. This may not happen, because the "
"assignment message never gets transmitted. Please "
"be sure not to free in this state. PLEASE FIX!\n",
tbf_name(tbf));
tbf->stop_timer();
#warning "TODO: Could/Should generate bssgp_tx_llc_discarded"
tbf_unlink_pdch(tbf);
llist_del(&tbf->list.list);
2013-10-27 08:50:15 +00:00
if (tbf->direction == GPRS_RLCMAC_UL_TBF)
tbf->bts->tbf_ul_freed();
else
tbf->bts->tbf_dl_freed();
if (tbf->ms())
tbf->set_ms(NULL);
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF ends here **********\n");
talloc_free(tbf);
}
int gprs_rlcmac_tbf::update()
{
struct gprs_rlcmac_tbf *ul_tbf = NULL;
struct gprs_rlcmac_bts *bts_data = bts->bts_data();
int rc;
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF update **********\n");
if (direction != GPRS_RLCMAC_DL_TBF)
return -EINVAL;
if (ms())
ul_tbf = ms()->ul_tbf();
tbf_unlink_pdch(this);
rc = bts_data->alloc_algorithm(bts_data, ul_tbf, this, bts_data->alloc_algorithm_curst, 0);
/* if no resource */
if (rc < 0) {
LOGP(DRLCMAC, LOGL_ERROR, "No resource after update???\n");
return -rc;
}
return 0;
}
int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
{
if (tbf->control_ts == 0xff)
LOGP(DRLCMAC, LOGL_INFO, "- Setting Control TS %d\n",
tbf->first_common_ts);
else if (tbf->control_ts != tbf->first_common_ts)
LOGP(DRLCMAC, LOGL_INFO, "- Changing Control TS %d\n",
tbf->first_common_ts);
tbf->control_ts = tbf->first_common_ts;
return 0;
}
const char *gprs_rlcmac_tbf::tbf_state_name[] = {
"NULL",
"ASSIGN",
"FLOW",
"FINISHED",
"WAIT RELEASE",
"RELEASING",
};
void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
unsigned int seconds, unsigned int microseconds)
{
if (!osmo_timer_pending(&tbf->timer))
LOGP(DRLCMAC, LOGL_DEBUG, "%s starting timer %u.\n",
tbf_name(tbf), T);
else
LOGP(DRLCMAC, LOGL_DEBUG, "%s restarting timer %u "
"while old timer %u pending \n",
tbf_name(tbf), T, tbf->T);
tbf->T = T;
tbf->num_T_exp = 0;
/* Tunning timers can be safely re-scheduled. */
tbf->timer.data = tbf;
tbf->timer.cb = &tbf_timer_cb;
osmo_timer_schedule(&tbf->timer, seconds, microseconds);
}
void gprs_rlcmac_tbf::stop_t3191()
{
return stop_timer();
}
void gprs_rlcmac_tbf::stop_timer()
{
if (osmo_timer_pending(&timer)) {
LOGP(DRLCMAC, LOGL_DEBUG, "%s stopping timer %u.\n",
tbf_name(this), T);
osmo_timer_del(&timer);
}
}
void gprs_rlcmac_tbf::poll_timeout()
{
LOGP(DRLCMAC, LOGL_NOTICE, "%s poll timeout\n",
tbf_name(this));
poll_state = GPRS_RLCMAC_POLL_NONE;
if (ul_ack_state == GPRS_RLCMAC_UL_ACK_WAIT_ACK) {
if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK))) {
LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling "
"PACKET CONTROL ACK for PACKET UPLINK ACK\n");
rlcmac_diag();
state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK);
}
ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE;
if (state_is(GPRS_RLCMAC_FINISHED)) {
gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(this);
ul_tbf->m_n3103++;
if (ul_tbf->m_n3103 == ul_tbf->bts->bts_data()->n3103) {
LOGP(DRLCMAC, LOGL_NOTICE,
"- N3103 exceeded\n");
ul_tbf->set_state(GPRS_RLCMAC_RELEASING);
tbf_timer_start(ul_tbf, 3169, ul_tbf->bts->bts_data()->t3169, 0);
return;
}
/* reschedule UL ack */
ul_tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK;
}
} else if (ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) {
if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS))) {
LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling "
"PACKET CONTROL ACK for PACKET UPLINK "
"ASSIGNMENT.\n");
rlcmac_diag();
state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS);
}
ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
n3105++;
if (n3105 == bts_data()->n3105) {
LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n");
set_state(GPRS_RLCMAC_RELEASING);
tbf_timer_start(this, 3195, bts_data()->t3195, 0);
return;
}
/* reschedule UL assignment */
ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
} else if (dl_ass_state == GPRS_RLCMAC_DL_ASS_WAIT_ACK) {
if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS))) {
LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling "
"PACKET CONTROL ACK for PACKET DOWNLINK "
"ASSIGNMENT.\n");
rlcmac_diag();
state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS);
}
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
n3105++;
if (n3105 == bts->bts_data()->n3105) {
LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n");
set_state(GPRS_RLCMAC_RELEASING);
tbf_timer_start(this, 3195, bts_data()->t3195, 0);
return;
}
/* reschedule DL assignment */
dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS;
} else if (direction == GPRS_RLCMAC_DL_TBF) {
gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(this);
if (!(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling "
"PACKET DOWNLINK ACK.\n");
dl_tbf->rlcmac_diag();
dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
}
dl_tbf->n3105++;
if (dl_tbf->n3105 == dl_tbf->bts->bts_data()->n3105) {
LOGP(DRLCMAC, LOGL_NOTICE, "- N3105 exceeded\n");
dl_tbf->set_state(GPRS_RLCMAC_RELEASING);
tbf_timer_start(dl_tbf, 3195, dl_tbf->bts_data()->t3195, 0);
return;
}
/* resend IMM.ASS on CCCH on timeout */
if ((dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))
&& !(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))) {
LOGP(DRLCMAC, LOGL_DEBUG, "Re-send dowlink assignment "
"for %s on PCH (IMSI=%s)\n",
tbf_name(dl_tbf),
imsi());
/* send immediate assignment */
dl_tbf->bts->snd_dl_ass(dl_tbf, 0, imsi());
dl_tbf->m_wait_confirm = 1;
}
} else
LOGP(DRLCMAC, LOGL_ERROR, "- Poll Timeout, but no event!\n");
}
static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot)
{
int rc;
if (trx >= 8 || tfi >= 32)
return -1;
if (!tbf)
return -1;
/* Back pointer for PODS llist compatibility */
tbf->list.back = tbf;
tbf->m_created_ts = time(NULL);
tbf->bts = bts->bts;
tbf->m_tfi = tfi;
tbf->trx = &bts->trx[trx];
tbf->ms_class = ms_class;
/* select algorithm */
rc = bts->alloc_algorithm(bts, old_tbf, tbf, bts->alloc_algorithm_curst,
single_slot);
/* if no resource */
if (rc < 0) {
return -1;
}
/* assign control ts */
tbf->control_ts = 0xff;
rc = tbf_assign_control_ts(tbf);
/* if no resource */
if (rc < 0) {
return -1;
}
/* set timestamp */
gettimeofday(&tbf->meas.rssi_tv, NULL);
tbf->m_llc.init();
return 0;
}
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot)
{
struct gprs_rlcmac_ul_tbf *tbf;
int rc;
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n");
LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: TFI=%d TRX=%d "
"MS_CLASS=%d\n", "UL", tfi, trx, ms_class);
if (trx >= 8 || tfi >= 32)
return NULL;
tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ul_tbf);
if (!tbf)
return NULL;
tbf->direction = GPRS_RLCMAC_UL_TBF;
rc = setup_tbf(tbf, bts, old_tbf, tfi, trx, ms_class, single_slot);
/* if no resource */
if (rc < 0) {
talloc_free(tbf);
return NULL;
}
llist_add(&tbf->list.list, &bts->ul_tbfs);
tbf->bts->tbf_ul_created();
if (old_tbf && old_tbf->ms())
tbf->set_ms(old_tbf->ms());
if (tbf->ms())
tbf->ms()->attach_ul_tbf(tbf);
return tbf;
}
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
uint8_t ms_class, uint8_t single_slot)
{
struct gprs_rlcmac_dl_tbf *tbf;
int rc;
LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n");
LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: TFI=%d TRX=%d "
"MS_CLASS=%d\n", "DL", tfi, trx, ms_class);
if (trx >= 8 || tfi >= 32)
return NULL;
tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
if (!tbf)
return NULL;
tbf->direction = GPRS_RLCMAC_DL_TBF;
rc = setup_tbf(tbf, bts, old_tbf, tfi, trx, ms_class, single_slot);
/* if no resource */
if (rc < 0) {
talloc_free(tbf);
return NULL;
2013-10-27 08:50:15 +00:00
}
llist_add(&tbf->list.list, &bts->dl_tbfs);
tbf->bts->tbf_dl_created();
tbf->m_last_dl_poll_fn = -1;
tbf->m_last_dl_drained_fn = -1;
gettimeofday(&tbf->m_bw.dl_bw_tv, NULL);
gettimeofday(&tbf->m_bw.dl_loss_tv, NULL);
if (old_tbf && old_tbf->ms())
tbf->set_ms(old_tbf->ms());
if (tbf->ms())
tbf->ms()->attach_dl_tbf(tbf);
return tbf;
}
static void tbf_timer_cb(void *_tbf)
{
struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf;
tbf->handle_timeout();
}
void gprs_rlcmac_tbf::handle_timeout()
{
LOGP(DRLCMAC, LOGL_DEBUG, "%s timer %u expired.\n",
tbf_name(this), T);
num_T_exp++;
switch (T) {
case 0: /* assignment */
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) {
if (state_is(GPRS_RLCMAC_ASSIGN)) {
LOGP(DRLCMAC, LOGL_NOTICE, "%s releasing due to "
"PACCH assignment timeout.\n", tbf_name(this));
tbf_free(this);
return;
} else
LOGP(DRLCMAC, LOGL_ERROR, "Error: %s is not "
"in assign state\n", tbf_name(this));
}
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) {
gprs_rlcmac_dl_tbf *dl_tbf = static_cast<gprs_rlcmac_dl_tbf *>(this);
dl_tbf->m_wait_confirm = 0;
if (dl_tbf->state_is(GPRS_RLCMAC_ASSIGN)) {
tbf_assign_control_ts(dl_tbf);
if (!dl_tbf->upgrade_to_multislot) {
/* change state to FLOW, so scheduler
* will start transmission */
dl_tbf->set_state(GPRS_RLCMAC_FLOW);
break;
}
/* This tbf can be upgraded to use multiple DL
* timeslots and now that there is already one
* slot assigned send another DL assignment via
* PDCH. */
/* keep to flags */
dl_tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
dl_tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
dl_tbf->update();
dl_tbf->bts->trigger_dl_ass(dl_tbf, dl_tbf);
} else
LOGP(DRLCMAC, LOGL_NOTICE, "%s Continue flow after "
"IMM.ASS confirm\n", tbf_name(dl_tbf));
}
break;
case 3169:
case 3191:
case 3195:
LOGP(DRLCMAC, LOGL_NOTICE, "%s T%d timeout during "
"transsmission\n", tbf_name(this), T);
rlcmac_diag();
/* fall through */
case 3193:
LOGP(DRLCMAC, LOGL_DEBUG,
"%s will be freed due to timeout\n", tbf_name(this));
/* free TBF */
tbf_free(this);
return;
break;
default:
LOGP(DRLCMAC, LOGL_ERROR,
"%s timer expired in unknown mode: %u\n", tbf_name(this), T);
}
}
int gprs_rlcmac_tbf::rlcmac_diag()
{
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)))
LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment was on CCCH\n");
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH)))
LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment was on PACCH\n");
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_UL_DATA)))
LOGP(DRLCMAC, LOGL_NOTICE, "- Uplink data was received\n");
else if (direction == GPRS_RLCMAC_UL_TBF)
LOGP(DRLCMAC, LOGL_NOTICE, "- No uplink data received yet\n");
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK)))
LOGP(DRLCMAC, LOGL_NOTICE, "- Downlink ACK was received\n");
else if (direction == GPRS_RLCMAC_DL_TBF)
LOGP(DRLCMAC, LOGL_NOTICE, "- No downlink ACK received yet\n");
return 0;
}
struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn)
{
struct msgb *msg;
struct gprs_rlcmac_dl_tbf *new_dl_tbf = NULL;
int poll_ass_dl = 1;
if (direction == GPRS_RLCMAC_DL_TBF && control_ts != first_common_ts) {
LOGP(DRLCMAC, LOGL_NOTICE, "Cannot poll for downlink "
"assigment, because MS cannot reply. (control TS=%d, "
"first common TS=%d)\n", control_ts,
first_common_ts);
poll_ass_dl = 0;
}
if (poll_ass_dl) {
if (poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already sheduled "
"for %s, so we must wait for downlink "
"assignment...\n", tbf_name(this));
return NULL;
}
if (bts->sba()->find(trx->trx_no, control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"scheduled for single block allocation...\n");
return NULL;
}
}
/* on uplink TBF we get the downlink TBF to be assigned. */
if (direction == GPRS_RLCMAC_UL_TBF) {
gprs_rlcmac_ul_tbf *ul_tbf = static_cast<gprs_rlcmac_ul_tbf *>(this);
/* be sure to check first, if contention resolution is done,
* otherwise we cannot send the assignment yet */
if (!ul_tbf->m_contention_resolution_done) {
LOGP(DRLCMAC, LOGL_DEBUG, "Cannot assign DL TBF now, "
"because contention resolution is not "
"finished.\n");
return NULL;
}
tbf,bts: Keep track of new TBF for dl/ul assignment in m_new_tbf There are a couple of possibilities where one TBF is used to assign a new one: 1. Assign a DL TBF from a UL TBF 2. Assign a UL TBF from a DL TBF 3. Assign a DL TBF from a DL TBF which is in wait-release state (T3193 is running) In these cases the assignment is sent on the existing TBF and triggers the assignement of the new TBF (with different TFI/direction). The current code detects these situations by looking at dl/ul_ass_state and then chosing the TBF with the opposite direction (DL/UL) that has the same TLLI. This does not work in the case 3 above where a new DL TBF is triggered for a DL TBF. The current code reuses the old TBF (and TFI), but this violates the spec. This patch introduces a m_new_tbf member which is set to the new TBF to be assigned. When receiving a control ack the code looks up the n_new_tbf member of the tbf that requested the control ack and completes the ul/dl assignment. If the old TBF was in the wait release state (T3193 is running) it is released. From 3GPP TS 04.60 9.3.2.6: """ If the network has received the PACKET DOWNLINK ACK/NACK message with the Final Ack Indicator bit set to '1' and has new data to transmit for the mobile station, the network may establish a new downlink TBF for the mobile station by sending the PACKET DOWNLINK ASSIGNMENT or PACKET TIMESLOT RECONFIGURE message with the Control Ack bit set to '1' on PACCH. In case the network establishes a new downlink TBF for the mobile station, the network shall stop timer T3193. """ reuse_tbf() is modified to allocate a new TBF with a new TFI and trigger a dl assignment for that TBF on the old TBF. All pending data is moved to the new TBF. Ticket: SYS#382 Sponsored-by: On-Waves ehf
2014-08-15 14:52:09 +00:00
}
if (ms())
new_dl_tbf = ms()->dl_tbf();
if (!new_dl_tbf) {
LOGP(DRLCMACDL, LOGL_ERROR, "We have a schedule for downlink "
"assignment at uplink %s, but there is no downlink "
"TBF\n", tbf_name(this));
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
return NULL;
}
new_dl_tbf->was_releasing = was_releasing;
msg = msgb_alloc(23, "rlcmac_dl_ass");
if (!msg)
return NULL;
bitvec *ass_vec = bitvec_alloc(23);
if (!ass_vec) {
msgb_free(msg);
return NULL;
}
bitvec_unhex(ass_vec,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
LOGP(DRLCMAC, LOGL_INFO, "%s start Packet Downlink Assignment (PACCH)\n", tbf_name(new_dl_tbf));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
Encoding::write_packet_downlink_assignment(mac_control_block, m_tfi,
(direction == GPRS_RLCMAC_DL_TBF), new_dl_tbf,
poll_ass_dl, bts_data()->alpha, bts_data()->gamma, -1, 0);
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n");
encode_gsm_rlcmac_downlink(ass_vec, mac_control_block);
LOGPC(DCSN1, LOGL_NOTICE, "\n");
LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Downlink Assignment -------------------------\n");
bitvec_pack(ass_vec, msgb_put(msg, 23));
bitvec_free(ass_vec);
talloc_free(mac_control_block);
if (poll_ass_dl) {
poll_state = GPRS_RLCMAC_POLL_SCHED;
poll_fn = (fn + 13) % 2715648;
dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK;
} else {
dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE;
new_dl_tbf->set_state(GPRS_RLCMAC_FLOW);
tbf_assign_control_ts(new_dl_tbf);
/* stop pending assignment timer */
new_dl_tbf->stop_timer();
}
return msg;
}
struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn)
{
struct msgb *msg;
struct gprs_rlcmac_ul_tbf *new_tbf = NULL;
if (poll_state != GPRS_RLCMAC_POLL_NONE) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
"sheduled for %s, so we must wait for uplink "
"assignment...\n", tbf_name(this));
return NULL;
}
if (bts->sba()->find(trx->trx_no, control_ts, (fn + 13) % 2715648)) {
LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already scheduled for "
"single block allocation...\n");
return NULL;
}
if (ms())
new_tbf = ms()->ul_tbf();
if (!new_tbf) {
LOGP(DRLCMACUL, LOGL_ERROR, "We have a schedule for uplink "
"assignment at downlink %s, but there is no uplink "
"TBF\n", tbf_name(this));
ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
return NULL;
}
msg = msgb_alloc(23, "rlcmac_ul_ass");
if (!msg)
return NULL;
LOGP(DRLCMAC, LOGL_INFO, "%ss start Packet Uplink Assignment (PACCH)\n", tbf_name(new_tbf));
bitvec *ass_vec = bitvec_alloc(23);
if (!ass_vec) {
msgb_free(msg);
return NULL;
}
bitvec_unhex(ass_vec,
"2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
Encoding::write_packet_uplink_assignment(bts_data(), ass_vec, m_tfi,
(direction == GPRS_RLCMAC_DL_TBF), tlli(),
is_tlli_valid(), new_tbf, 1, bts_data()->alpha,
bts_data()->gamma, -1);
bitvec_pack(ass_vec, msgb_put(msg, 23));
RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
decode_gsm_rlcmac_downlink(ass_vec, mac_control_block);
LOGPC(DCSN1, LOGL_NOTICE, "\n");
LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Uplink Assignment -------------------------\n");
bitvec_free(ass_vec);
talloc_free(mac_control_block);
poll_state = GPRS_RLCMAC_POLL_SCHED;
poll_fn = (fn + 13) % 2715648;
ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK;
return msg;
}
void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_trx *trx)
{
for (uint8_t tfi = 0; tfi < 32; tfi++) {
struct gprs_rlcmac_tbf *tbf;
tbf = trx->ul_tbf[tfi];
if (tbf)
tbf_free(tbf);
tbf = trx->dl_tbf[tfi];
if (tbf)
tbf_free(tbf);
}
}
void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_pdch *pdch)
{
for (uint8_t tfi = 0; tfi < 32; tfi++) {
struct gprs_rlcmac_tbf *tbf;
tbf = pdch->ul_tbf_by_tfi(tfi);
if (tbf)
tbf_free(tbf);
tbf = pdch->dl_tbf_by_tfi(tfi);
if (tbf)
tbf_free(tbf);
}
}
void gprs_rlcmac_tbf::update_tlli(uint32_t tlli)
{
}
int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
{
struct gprs_rlcmac_tbf *dl_tbf = NULL;
struct gprs_rlcmac_tbf *ul_tbf = NULL;
struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
uint32_t new_tlli;
int rc;
GprsMs *old_ms;
/* 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, &new_tlli);
if (rc) {
bts->decode_error();
LOGP(DRLCMACUL, LOGL_NOTICE, "Failed to decode TLLI "
"of UL DATA TFI=%d.\n", rh->tfi);
return 0;
}
old_ms = bts->ms_by_tlli(new_tlli);
if (old_ms) {
/* Get them before calling set_ms() */
dl_tbf = old_ms->dl_tbf();
ul_tbf = old_ms->ul_tbf();
set_ms(old_ms);
}
update_tlli(new_tlli);
/* The TLLI has been taken from an UL message */
update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
"UL DATA TFI=%d.\n", tlli(), rh->tfi);
if (dl_tbf) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
"TLLI=0x%08x while %s still exists. "
"Killing pending DL TBF\n", tlli(),
tbf_name(dl_tbf));
tbf_free(dl_tbf);
dl_tbf = NULL;
}
if (ul_tbf) {
LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
"TLLI=0x%08x while %s still exists. "
"Killing pending UL TBF\n", tlli(),
tbf_name(ul_tbf));
tbf_free(ul_tbf);
ul_tbf = NULL;
}
return 1;
}
const char *tbf_name(gprs_rlcmac_tbf *tbf)
{
return tbf->name();
}
const char *gprs_rlcmac_tbf::name() const
{
snprintf(m_name_buf, sizeof(m_name_buf) - 1,
"TBF(TFI=%d TLLI=0x%08x DIR=%s STATE=%s)",
m_tfi, tlli(),
direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
state_name()
);
m_name_buf[sizeof(m_name_buf) - 1] = '\0';
return m_name_buf;
}
void gprs_rlcmac_tbf::rotate_in_list()
{
llist_del(&list.list);
if (direction == GPRS_RLCMAC_UL_TBF)
llist_add(&list.list, &bts->bts_data()->ul_tbfs);
else
llist_add(&list.list, &bts->bts_data()->dl_tbfs);
}
uint8_t gprs_rlcmac_tbf::tsc() const
{
return trx->pdch[first_ts].tsc;
}
void tbf_print_vty_info(struct vty *vty, struct llist_head *ltbf)
{
gprs_rlcmac_tbf *tbf = llist_pods_entry(ltbf, gprs_rlcmac_tbf);
vty_out(vty, "TBF: TFI=%d TLLI=0x%08x (%s) DIR=%s IMSI=%s%s", tbf->tfi(),
tbf->tlli(), tbf->is_tlli_valid() ? "valid" : "invalid",
tbf->direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
tbf->imsi(), VTY_NEWLINE);
vty_out(vty, " created=%lu state=%08x 1st_TS=%d 1st_cTS=%d ctrl_TS=%d "
"MS_CLASS=%d%s",
tbf->created_ts(), tbf->state_flags, tbf->first_ts,
tbf->first_common_ts, tbf->control_ts, tbf->ms_class,
VTY_NEWLINE);
vty_out(vty, " TS_alloc=");
for (int i = 0; i < 8; i++) {
if (tbf->pdch[i])
vty_out(vty, "%d ", i);
}
vty_out(vty, " CS=%d%s%s", tbf->cs, VTY_NEWLINE, VTY_NEWLINE);
}