aboutsummaryrefslogtreecommitdiffstats
path: root/src/tbf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tbf.cpp')
-rw-r--r--src/tbf.cpp431
1 files changed, 192 insertions, 239 deletions
diff --git a/src/tbf.cpp b/src/tbf.cpp
index 07732dc4..840a1f71 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -13,10 +13,6 @@
* 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 <new>
@@ -32,9 +28,9 @@
#include <gprs_debug.h>
#include <gprs_ms.h>
#include <pcu_utils.h>
-#include <gprs_ms_storage.h>
#include <sba.h>
#include <pdch.h>
+#include <alloc_algo.h>
extern "C" {
#include <osmocom/core/msgb.h>
@@ -94,14 +90,12 @@ gprs_rlcmac_tbf::Meas::Meas() :
gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir) :
direction(dir),
trx(NULL),
- first_ts(0),
- first_common_ts(0),
- control_ts(TBF_CONTROL_TS_UNSET),
+ control_ts(NULL),
fT(0),
num_fT_exp(0),
upgrade_to_multislot(false),
bts(bts_),
- m_tfi(0),
+ m_tfi(TBF_TFI_UNSET),
m_created_ts(0),
m_ctrs(NULL),
m_ms(ms),
@@ -119,11 +113,6 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_
memset(&m_trx_list, 0, sizeof(m_trx_list));
m_trx_list.entry = this;
- memset(&state_fsm, 0, sizeof(state_fsm));
- state_fsm.tbf = this;
- state_fsm.fi = osmo_fsm_inst_alloc(&tbf_fsm, this, &state_fsm, LOGL_INFO, NULL);
- OSMO_ASSERT(state_fsm.fi);
-
memset(&ul_ass_fsm, 0, sizeof(ul_ass_fsm));
ul_ass_fsm.tbf = this;
ul_ass_fsm.fi = osmo_fsm_inst_alloc(&tbf_ul_ass_fsm, this, &ul_ass_fsm, LOGL_INFO, NULL);
@@ -134,16 +123,23 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_
OSMO_ASSERT(dl_ass_fsm.fi);
m_rlc.init();
- m_llc.init();
+ llc_init(&m_llc);
m_name_buf[0] = '\0';
+
+ m_created_ts = time(NULL);
+ /* set timestamp */
+ osmo_clock_gettime(CLOCK_MONOTONIC, &meas.rssi_tv);
+
+ m_ctrs = rate_ctr_group_alloc(this, &tbf_ctrg_desc, next_tbf_ctr_group_id++);
+ OSMO_ASSERT(m_ctrs);
}
gprs_rlcmac_tbf::~gprs_rlcmac_tbf()
{
- osmo_fsm_inst_free(state_fsm.fi);
- state_fsm.fi = NULL;
+ osmo_fsm_inst_free(state_fi);
+ state_fi = NULL;
osmo_fsm_inst_free(ul_ass_fsm.fi);
ul_ass_fsm.fi = NULL;
@@ -215,30 +211,7 @@ void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
ms_attach_tbf(m_ms, this);
}
-void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
-{
- if (tlli == GSM_RESERVED_TMSI)
- return;
-
- /* TODO: When the TLLI does not match the ms, check if there is another
- * MS object that belongs to that TLLI and if yes make sure one of them
- * gets deleted. This is the same problem that can arise with
- * IMSI in gprs_rlcmac_dl_tbf::handle() so there should be a unified solution */
- if (!ms_check_tlli(ms(), tlli)) {
- GprsMs *old_ms;
-
- old_ms = bts_ms_store(bts)->get_ms(tlli, 0, NULL);
- if (old_ms)
- ms_merge_and_clear_ms(ms(), old_ms);
- }
-
- if (dir == GPRS_RLCMAC_UL_TBF)
- ms_set_tlli(ms(), tlli);
- else
- ms_confirm_tlli(ms(), tlli);
-}
-
-static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
+void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
{
int ts;
@@ -249,8 +222,10 @@ static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
* confirmation from the MS and goes through the FLOW state. Hence, we
* may have ULC pollings ongoing and we need to make sure we drop all
* reserved nodes there: */
- if (tbf->control_ts != TBF_CONTROL_TS_UNSET && !tbf->pdch[tbf->control_ts])
- pdch_ulc_release_tbf(tbf->trx->pdch[tbf->control_ts].ulc, tbf);
+ if (tbf->control_ts) {
+ pdch_ulc_release_tbf(tbf->control_ts->ulc, tbf);
+ tbf->control_ts = NULL;
+ }
/* Now simply detach from all attached PDCHs */
for (ts = 0; ts < 8; ts++) {
@@ -260,6 +235,12 @@ static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
tbf->pdch[ts]->detach_tbf(tbf);
tbf->pdch[ts] = NULL;
}
+
+ /* Detach from TRX: */
+ if (tbf->trx) {
+ llist_del(tbf_trx_list(tbf));
+ tbf->trx = NULL;
+ }
}
void tbf_free(struct gprs_rlcmac_tbf *tbf)
@@ -270,7 +251,7 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
if (tbf->state_is(TBF_ST_FLOW))
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_ABORTED);
} else {
- gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf);
+ gprs_rlcmac_dl_tbf *dl_tbf = tbf_as_dl_tbf(tbf);
gprs_rlc_dl_window *win = static_cast<gprs_rlc_dl_window *>(dl_tbf->window());
bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_DL_FREED);
@@ -291,7 +272,6 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
tbf->stop_timers("freeing TBF");
/* TODO: Could/Should generate bssgp_tx_llc_discarded */
tbf_unlink_pdch(tbf);
- llist_del(tbf_trx_list(tbf));
if (tbf->ms())
tbf->set_ms(NULL);
@@ -309,50 +289,38 @@ uint16_t egprs_window_size(const struct gprs_rlcmac_bts *bts, uint8_t slots)
OSMO_MAX(64, (the_pcu->vty.ws_base + num_pdch * the_pcu->vty.ws_pdch) / 32 * 32));
}
-int gprs_rlcmac_tbf::update()
-{
- int rc;
-
- LOGP(DTBF, LOGL_DEBUG, "********** DL-TBF update **********\n");
- OSMO_ASSERT(direction == GPRS_RLCMAC_DL_TBF);
-
- tbf_unlink_pdch(this);
- rc = the_pcu->alloc_algorithm(bts, this, false, -1);
- /* if no resource */
- if (rc < 0) {
- LOGPTBF(this, LOGL_ERROR, "No resource after update???\n");
- bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_FAIL);
- return rc;
- }
-
- if (is_egprs_enabled()) {
- gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this);
- if (dl_tbf)
- dl_tbf->set_window_size();
- }
-
- tbf_update_state_fsm_name(this);
-
- return 0;
-}
-
void tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
{
- if (tbf->control_ts == TBF_CONTROL_TS_UNSET)
- LOGPTBF(tbf, LOGL_INFO, "Setting Control TS %d\n",
- tbf->first_common_ts);
- else if (tbf->control_ts != tbf->first_common_ts)
- LOGPTBF(tbf, LOGL_INFO, "Changing Control TS %d -> %d\n",
- tbf->control_ts, tbf->first_common_ts);
- tbf->control_ts = tbf->first_common_ts;
+ char buf[128];
+ struct gprs_rlcmac_pdch *first_common = ms_first_common_ts(tbf_ms(tbf));
+ OSMO_ASSERT(first_common);
+
+ if (!tbf->control_ts)
+ LOGPTBF(tbf, LOGL_INFO, "Setting Control TS %s\n",
+ pdch_name(first_common));
+ else if (tbf->control_ts != first_common)
+ LOGPTBF(tbf, LOGL_INFO, "Changing Control TS %s -> %s\n",
+ pdch_name_buf(tbf->control_ts, buf, sizeof(buf)),
+ pdch_name(first_common));
+ tbf->control_ts = first_common;
}
void gprs_rlcmac_tbf::n_reset(enum tbf_counters n)
{
- if (n >= N_MAX) {
- LOGPTBF(this, LOGL_ERROR, "attempting to reset unknown counter %s\n",
- get_value_string(tbf_counters_names, n));
- return;
+ OSMO_ASSERT(n < N_MAX);
+
+ switch(n) {
+ case N3101:
+ OSMO_ASSERT(direction == GPRS_RLCMAC_UL_TBF);
+ break;
+ case N3103:
+ OSMO_ASSERT(direction == GPRS_RLCMAC_UL_TBF);
+ break;
+ case N3105:
+ OSMO_ASSERT(direction == GPRS_RLCMAC_DL_TBF);
+ break;
+ default:
+ break;
}
Narr[n] = 0;
@@ -363,22 +331,21 @@ bool gprs_rlcmac_tbf::n_inc(enum tbf_counters n)
{
uint8_t chk;
- if (n >= N_MAX) {
- LOGPTBF(this, LOGL_ERROR, "attempting to increment unknown counter %s\n",
- get_value_string(tbf_counters_names, n));
- return true;
- }
+ OSMO_ASSERT(n < N_MAX);
Narr[n]++;
switch(n) {
case N3101:
+ OSMO_ASSERT(direction == GPRS_RLCMAC_UL_TBF);
chk = bts->n3101;
break;
case N3103:
+ OSMO_ASSERT(direction == GPRS_RLCMAC_UL_TBF);
chk = bts->n3103;
break;
case N3105:
+ OSMO_ASSERT(direction == GPRS_RLCMAC_DL_TBF);
chk = bts->n3105;
break;
default:
@@ -491,8 +458,8 @@ void gprs_rlcmac_tbf::t_start(enum tbf_timers t, int T, const char *reason, bool
OSMO_ASSERT(false);
}
- LOGPSRC(DTBF, LOGL_DEBUG, file, line, "%s %sstarting timer %s [%s] with %u sec. %u microsec, cur_fn=%d\n",
- tbf_name(this), osmo_timer_pending(&Tarr[t]) ? "re" : "",
+ LOGPSRC(DTBF, LOGL_DEBUG, file, line, "%s %starting timer %s [%s] with %u sec. %u microsec, cur_fn=%d\n",
+ tbf_name(this), osmo_timer_pending(&Tarr[t]) ? "Res" : "S",
get_value_string(tbf_timers_names, t), reason, sec, microsec, current_fn);
Tarr[t].data = this;
@@ -512,46 +479,18 @@ void gprs_rlcmac_tbf::t_start(enum tbf_timers t, int T, const char *reason, bool
osmo_timer_schedule(&Tarr[t], sec, microsec);
}
-int gprs_rlcmac_tbf::check_polling(uint32_t fn, uint8_t ts,
- uint32_t *poll_fn_, unsigned int *rrbp_) const
-{
- int rc;
- if (!is_control_ts(ts)) {
- LOGPTBF(this, LOGL_DEBUG, "Polling cannot be "
- "scheduled in this TS %d (first control TS %d)\n",
- ts, control_ts);
- return -EINVAL;
- }
-
- if ((rc = pdch_ulc_get_next_free_rrbp_fn(trx->pdch[ts].ulc, fn, poll_fn_, rrbp_)) < 0) {
- LOGPTBF(this, LOGL_DEBUG,
- "(bts=%u,trx=%u,ts=%u) FN=%u No suitable free RRBP offset found!\n",
- trx->bts->nr, trx->trx_no, ts, fn);
- return rc;
- }
-
- return 0;
-}
-
-void gprs_rlcmac_tbf::set_polling(uint32_t new_poll_fn, uint8_t ts, enum pdch_ulc_tbf_poll_reason reason)
-{
- /* schedule polling */
- if (pdch_ulc_reserve_tbf_poll(trx->pdch[ts].ulc, new_poll_fn, this, reason) < 0)
- LOGPTBFDL(this, LOGL_ERROR, "Failed scheduling poll on PACCH (FN=%d, TS=%d)\n",
- new_poll_fn, ts);
-}
-
void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_fn, enum pdch_ulc_tbf_poll_reason reason)
{
gprs_rlcmac_ul_tbf *ul_tbf;
gprs_rlcmac_dl_tbf *dl_tbf;
- LOGPTBF(this, LOGL_NOTICE, "poll timeout for FN=%d, TS=%d (curr FN %d)\n",
- poll_fn, pdch->ts_no, bts_current_frame_number(bts));
+ LOGPTBF(this, LOGL_NOTICE, "poll timeout for FN=%d, TS=%d (curr FN %d), reason=%s\n",
+ poll_fn, pdch->ts_no, bts_current_frame_number(bts),
+ get_value_string(pdch_ulc_tbf_poll_reason_names, reason));
switch (reason) {
case PDCH_ULC_POLL_UL_ACK:
- ul_tbf = as_ul_tbf(this);
+ ul_tbf = tbf_as_ul_tbf(this);
OSMO_ASSERT(ul_tbf);
if (!tbf_ul_ack_exp_ctrl_ack(ul_tbf, poll_fn, pdch->ts_no)) {
LOGPTBF(this, LOGL_NOTICE, "FN=%d, TS=%d (curr FN %d): POLL_UL_ACK not expected!\n",
@@ -563,7 +502,7 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
if (state_is(TBF_ST_FINISHED)) {
if (ul_tbf->n_inc(N3103)) {
bts_do_rate_ctr_inc(bts, CTR_PUAN_POLL_FAILED);
- osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_MAX_N3103, NULL);
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_MAX_N3103, NULL);
return;
}
}
@@ -579,8 +518,8 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
}
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT);
bts_do_rate_ctr_inc(bts, CTR_PUA_POLL_TIMEDOUT);
- if (n_inc(N3105)) {
- osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_MAX_N3105, NULL);
+ if (this->direction == GPRS_RLCMAC_DL_TBF && n_inc(N3105)) {
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_MAX_N3105, NULL);
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_FAILED);
bts_do_rate_ctr_inc(bts, CTR_PUA_POLL_FAILED);
return;
@@ -598,8 +537,8 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
}
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT);
bts_do_rate_ctr_inc(bts, CTR_PDA_POLL_TIMEDOUT);
- if (n_inc(N3105)) {
- osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_MAX_N3105, NULL);
+ if (this->direction == GPRS_RLCMAC_DL_TBF && n_inc(N3105)) {
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_MAX_N3105, NULL);
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_FAILED);
bts_do_rate_ctr_inc(bts, CTR_PDA_POLL_FAILED);
return;
@@ -619,14 +558,14 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
break;
case PDCH_ULC_POLL_DL_ACK:
- dl_tbf = as_dl_tbf(this);
+ dl_tbf = tbf_as_dl_tbf(this);
/* POLL Timeout expecting DL ACK/NACK: implies direction == GPRS_RLCMAC_DL_TBF */
OSMO_ASSERT(dl_tbf);
- if (!(dl_tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) {
+ if (!dl_tbf->m_last_dl_poll_ack_lost) {
LOGPTBF(this, LOGL_NOTICE,
"Timeout for polling PACKET DOWNLINK ACK: %s\n",
tbf_rlcmac_diag(dl_tbf));
- dl_tbf->state_fsm.state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
+ dl_tbf->m_last_dl_poll_ack_lost = true;
}
if (dl_tbf->state_is(TBF_ST_RELEASING))
bts_do_rate_ctr_inc(bts, CTR_RLC_REL_TIMEDOUT);
@@ -635,13 +574,13 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
bts_do_rate_ctr_inc(bts, CTR_PDAN_POLL_TIMEDOUT);
}
if (dl_tbf->n_inc(N3105)) {
- osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_MAX_N3105, NULL);
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_MAX_N3105, NULL);
bts_do_rate_ctr_inc(bts, CTR_PDAN_POLL_FAILED);
bts_do_rate_ctr_inc(bts, CTR_RLC_ACK_FAILED);
return;
}
/* resend IMM.ASS on CCCH on timeout */
- osmo_fsm_inst_dispatch(this->state_fsm.fi, TBF_EV_DL_ACKNACK_MISS, NULL);
+ osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_DL_ACKNACK_MISS, NULL);
break;
default:
@@ -650,99 +589,46 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
}
}
-int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
-{
- int rc;
-
- if (ms_mode(m_ms) != GPRS)
- enable_egprs();
-
- m_created_ts = time(NULL);
- /* select algorithm */
- rc = the_pcu->alloc_algorithm(bts, this, single_slot, use_trx);
- /* if no resource */
- if (rc < 0) {
- LOGPTBF(this, LOGL_NOTICE,
- "Timeslot Allocation failed: trx = %d, single_slot = %d\n",
- use_trx, single_slot);
- bts_do_rate_ctr_inc(bts, CTR_TBF_ALLOC_FAIL);
- return -1;
- }
- /* assign initial control ts */
- tbf_assign_control_ts(this);
-
- /* set timestamp */
- osmo_clock_gettime(CLOCK_MONOTONIC, &meas.rssi_tv);
-
- LOGPTBF(this, LOGL_INFO,
- "Allocated: trx = %d, ul_slots = %02x, dl_slots = %02x\n",
- this->trx->trx_no, ul_slots(), dl_slots());
-
- m_ctrs = rate_ctr_group_alloc(this, &tbf_ctrg_desc, next_tbf_ctr_group_id++);
- if (!m_ctrs) {
- LOGPTBF(this, LOGL_ERROR, "Couldn't allocate TBF counters\n");
- return -1;
- }
-
- tbf_update_state_fsm_name(this);
-
- ms_attach_tbf(m_ms, this);
-
- return 0;
-}
-
-int gprs_rlcmac_tbf::establish_dl_tbf_on_pacch()
-{
- struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
-
- bts_do_rate_ctr_inc(bts, CTR_TBF_REUSED);
-
- new_tbf = tbf_alloc_dl_tbf(bts, ms(),
- this->trx->trx_no, false);
-
- if (!new_tbf) {
- LOGP(DTBF, LOGL_NOTICE, "No PDCH resource\n");
- return -1;
- }
-
- LOGPTBF(this, LOGL_DEBUG, "Trigger downlink assignment on PACCH\n");
- new_tbf->trigger_ass(this);
-
- return 0;
-}
-
const char *tbf_name(const gprs_rlcmac_tbf *tbf)
{
return tbf ? tbf->name() : "(no TBF)";
}
-const char *gprs_rlcmac_tbf::name() const
+const char *gprs_rlcmac_tbf::name(bool enclousure) const
{
- snprintf(m_name_buf, sizeof(m_name_buf) - 1,
- "TBF(TFI=%d TLLI=0x%08x DIR=%s STATE=%s%s)",
- m_tfi, tlli(),
- direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
- state_name(),
- is_egprs_enabled() ? " EGPRS" : ""
- );
- m_name_buf[sizeof(m_name_buf) - 1] = '\0';
+ struct osmo_strbuf sb = { .buf = m_name_buf, .len = sizeof(m_name_buf) };
+
+ if (enclousure)
+ OSMO_STRBUF_PRINTF(sb, "TBF(");
+ OSMO_STRBUF_PRINTF(sb, "%s", direction == GPRS_RLCMAC_UL_TBF ? "UL" : "DL");
+ if (this->trx) { /* This may not be available during TBF alloc func time */
+ int8_t tfi = (m_tfi == TBF_TFI_UNSET) ? -1 : m_tfi;
+ OSMO_STRBUF_PRINTF(sb, ":TFI-%u-%u-%d",
+ this->trx->bts->nr, this->trx->trx_no, tfi);
+ }
+ OSMO_STRBUF_PRINTF(sb, ":%c", is_egprs_enabled() ? 'E' : 'G');
+ if (m_ms) {
+ uint32_t tlli = ms_tlli(m_ms);
+ if (ms_imsi_is_valid(m_ms))
+ OSMO_STRBUF_PRINTF(sb, ":IMSI-%s", ms_imsi(m_ms));
+ if (tlli != GSM_RESERVED_TMSI)
+ OSMO_STRBUF_PRINTF(sb, ":TLLI-0x%08x", tlli);
+ }
+ if (enclousure)
+ OSMO_STRBUF_PRINTF(sb, "){%s}", state_name());
return m_name_buf;
}
void tbf_update_state_fsm_name(struct gprs_rlcmac_tbf *tbf)
{
- char buf[64];
- snprintf(buf, sizeof(buf), "%s-TFI_%d",
- tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
- tbf_tfi(tbf));
- osmo_identifier_sanitize_buf(buf, NULL, '_');
+ const char *buf = tbf->name(false);
- osmo_fsm_inst_update_id(tbf->state_fsm.fi, buf);
+ osmo_fsm_inst_update_id(tbf->state_fi, buf);
osmo_fsm_inst_update_id(tbf->ul_ass_fsm.fi, buf);
osmo_fsm_inst_update_id(tbf->dl_ass_fsm.fi, buf);
if (tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF) {
- struct gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf);
+ struct gprs_rlcmac_ul_tbf *ul_tbf = tbf_as_ul_tbf(tbf);
osmo_fsm_inst_update_id(ul_tbf->ul_ack_fsm.fi, buf);
}
@@ -776,12 +662,14 @@ uint8_t gprs_rlcmac_tbf::ul_slots() const
{
uint8_t slots = 0;
size_t i;
+ struct gprs_rlcmac_pdch *first_common;
if (direction == GPRS_RLCMAC_DL_TBF) {
- if (control_ts < 8)
- slots |= 1 << control_ts;
- if (first_common_ts < 8)
- slots |= 1 << first_common_ts;
+ if (control_ts)
+ slots |= 1 << control_ts->ts_no;
+ first_common = ms_first_common_ts(tbf_ms(this));
+ if (first_common)
+ slots |= 1 << first_common->ts_no;
return slots;
}
@@ -793,11 +681,6 @@ uint8_t gprs_rlcmac_tbf::ul_slots() const
return slots;
}
-bool gprs_rlcmac_tbf::is_control_ts(uint8_t ts) const
-{
- return ts == control_ts;
-}
-
void gprs_rlcmac_tbf::enable_egprs()
{
/* Decrease GPRS TBF count of attached PDCHs */
@@ -819,7 +702,12 @@ void gprs_rlcmac_tbf::enable_egprs()
/* C API */
enum tbf_fsm_states tbf_state(const struct gprs_rlcmac_tbf *tbf)
{
- return (enum tbf_fsm_states)tbf->state_fsm.fi->state;
+ return (enum tbf_fsm_states)tbf->state_fi->state;
+}
+
+struct osmo_fsm_inst *tbf_state_fi(const struct gprs_rlcmac_tbf *tbf)
+{
+ return tbf->state_fi;
}
struct osmo_fsm_inst *tbf_ul_ass_fi(const struct gprs_rlcmac_tbf *tbf)
@@ -867,11 +755,6 @@ struct gprs_llc *tbf_llc(struct gprs_rlcmac_tbf *tbf)
return &tbf->m_llc;
}
-uint8_t tbf_first_common_ts(const struct gprs_rlcmac_tbf *tbf)
-{
- return tbf->first_common_ts;
-}
-
uint8_t tbf_dl_slots(const struct gprs_rlcmac_tbf *tbf)
{
return tbf->dl_slots();
@@ -883,7 +766,19 @@ uint8_t tbf_ul_slots(const struct gprs_rlcmac_tbf *tbf)
bool tbf_is_tfi_assigned(const struct gprs_rlcmac_tbf *tbf)
{
- return tbf->is_tfi_assigned();
+ const struct gprs_rlcmac_dl_tbf *dl_tbf;
+
+ /* The TBF is established: */
+ if (tbf->state_fi->state > TBF_ST_ASSIGN)
+ return true;
+
+ /* The DL TBF has been assigned by a IMM.ASS: */
+ dl_tbf = tbf_as_dl_tbf_const(tbf);
+ if (tbf->state_fi->state == TBF_ST_ASSIGN && dl_tbf &&
+ (dl_tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)))
+ return true;
+
+ return false;
}
uint8_t tbf_tfi(const struct gprs_rlcmac_tbf *tbf)
@@ -896,14 +791,37 @@ bool tbf_is_egprs_enabled(const struct gprs_rlcmac_tbf *tbf)
return tbf->is_egprs_enabled();
}
-int tbf_check_polling(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts, uint32_t *poll_fn, unsigned int *rrbp)
+int tbf_check_polling(const struct gprs_rlcmac_tbf *tbf, const struct gprs_rlcmac_pdch *pdch,
+ uint32_t fn, uint32_t *poll_fn, unsigned int *rrbp)
{
- return tbf->check_polling(fn, ts, poll_fn, rrbp);
+ int rc;
+ OSMO_ASSERT(pdch);
+
+ if (!tbf_is_control_ts(tbf, pdch)) {
+ char buf[128];
+ LOGPTBF(tbf, LOGL_NOTICE, "Polling cannot be "
+ "scheduled in this TS %s (control TS %s)\n",
+ pdch_name(pdch),
+ tbf->control_ts ? pdch_name_buf(tbf->control_ts, buf, sizeof(buf)) : "none");
+ return -EINVAL;
+ }
+
+ if ((rc = pdch_ulc_get_next_free_rrbp_fn(pdch->ulc, fn, poll_fn, rrbp)) < 0) {
+ LOGPTBF(tbf, LOGL_NOTICE,
+ "FN=%u No suitable free RRBP offset found on %s!\n",
+ fn, pdch_name(pdch));
+ return rc;
+ }
+
+ return 0;
}
-void tbf_set_polling(struct gprs_rlcmac_tbf *tbf, uint32_t new_poll_fn, uint8_t ts, enum pdch_ulc_tbf_poll_reason t)
+void tbf_set_polling(struct gprs_rlcmac_tbf *tbf, const struct gprs_rlcmac_pdch *pdch, uint32_t new_poll_fn, enum pdch_ulc_tbf_poll_reason t)
{
- return tbf->set_polling(new_poll_fn, ts, t);
+ /* schedule polling */
+ if (pdch_ulc_reserve_tbf_poll(pdch->ulc, new_poll_fn, tbf, t) < 0)
+ LOGPTBF(tbf, LOGL_ERROR, "FN=%u Failed scheduling poll on PACCH %s\n",
+ new_poll_fn, pdch_name(pdch));
}
void tbf_poll_timeout(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_pdch *pdch, uint32_t poll_fn, enum pdch_ulc_tbf_poll_reason reason)
@@ -911,19 +829,39 @@ void tbf_poll_timeout(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_pdch *pdch
tbf->poll_timeout(pdch, poll_fn, reason);
}
-bool tbf_is_control_ts(const struct gprs_rlcmac_tbf *tbf, uint8_t ts)
+bool tbf_is_control_ts(const struct gprs_rlcmac_tbf *tbf, const struct gprs_rlcmac_pdch *pdch)
{
- return tbf->is_control_ts(ts);
+ return tbf->control_ts == pdch;
}
bool tbf_can_upgrade_to_multislot(const struct gprs_rlcmac_tbf *tbf)
{
return tbf->upgrade_to_multislot;
}
+/* first TS used by TBF */
+struct gprs_rlcmac_pdch *tbf_get_first_ts(struct gprs_rlcmac_tbf *tbf)
+{
+ unsigned int i;
-int tbf_update(struct gprs_rlcmac_tbf *tbf)
+ for (i = 0; i < ARRAY_SIZE(tbf->pdch); i++) {
+ struct gprs_rlcmac_pdch *pdch;
+ pdch = tbf->pdch[i];
+ if (pdch)
+ return pdch;
+ }
+ return NULL;
+}
+const struct gprs_rlcmac_pdch *tbf_get_first_ts_const(const struct gprs_rlcmac_tbf *tbf)
{
- return tbf->update();
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(tbf->pdch); i++) {
+ const struct gprs_rlcmac_pdch *pdch;
+ pdch = tbf->pdch[i];
+ if (pdch)
+ return pdch;
+ }
+ return NULL;
}
const char* tbf_rlcmac_diag(const struct gprs_rlcmac_tbf *tbf)
@@ -932,18 +870,23 @@ const char* tbf_rlcmac_diag(const struct gprs_rlcmac_tbf *tbf)
struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
OSMO_STRBUF_PRINTF(sb, "|");
- if (tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))
- OSMO_STRBUF_PRINTF(sb, "Assignment was on CCCH|");
- if (tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))
- OSMO_STRBUF_PRINTF(sb, "Assignment was on PACCH|");
if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
- const struct gprs_rlcmac_ul_tbf *ul_tbf = static_cast<const gprs_rlcmac_ul_tbf *>(tbf);
+ const struct gprs_rlcmac_ul_tbf *ul_tbf = tbf_as_ul_tbf_const(tbf);
+ if (ul_tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))
+ OSMO_STRBUF_PRINTF(sb, "Assignment was on CCCH|");
+ if (ul_tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))
+ OSMO_STRBUF_PRINTF(sb, "Assignment was on PACCH|");
if (ul_tbf->m_rx_counter)
OSMO_STRBUF_PRINTF(sb, "Uplink data was received|");
else
OSMO_STRBUF_PRINTF(sb, "No uplink data received yet|");
} else {
- if (tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))
+ const struct gprs_rlcmac_dl_tbf *dl_tbf = tbf_as_dl_tbf_const(tbf);
+ if (dl_tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))
+ OSMO_STRBUF_PRINTF(sb, "Assignment was on CCCH|");
+ if (dl_tbf->state_fsm.state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))
+ OSMO_STRBUF_PRINTF(sb, "Assignment was on PACCH|");
+ if (dl_tbf->m_first_dl_ack_rcvd)
OSMO_STRBUF_PRINTF(sb, "Downlink ACK was received|");
else
OSMO_STRBUF_PRINTF(sb, "No downlink ACK received yet|");
@@ -951,3 +894,13 @@ const char* tbf_rlcmac_diag(const struct gprs_rlcmac_tbf *tbf)
return buf;
}
+
+struct gprs_rlcmac_trx *tbf_get_trx(struct gprs_rlcmac_tbf *tbf)
+{
+ return tbf->trx;
+}
+
+void tbf_stop_timers(struct gprs_rlcmac_tbf *tbf, const char *reason)
+{
+ tbf->stop_timers(reason);
+} \ No newline at end of file