diff options
Diffstat (limited to 'src/tbf.cpp')
-rw-r--r-- | src/tbf.cpp | 431 |
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 |