diff options
Diffstat (limited to 'src/tbf.cpp')
-rw-r--r-- | src/tbf.cpp | 1051 |
1 files changed, 371 insertions, 680 deletions
diff --git a/src/tbf.cpp b/src/tbf.cpp index 92dede57..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> @@ -59,30 +55,6 @@ extern void *tall_pcu_ctx; unsigned int next_tbf_ctr_group_id = 0; /* Incrementing group id */ -static void tbf_timer_cb(void *_tbf); - -const struct value_string gprs_rlcmac_tbf_dl_ass_state_names[] = { - OSMO_VALUE_STRING(GPRS_RLCMAC_DL_ASS_NONE), - OSMO_VALUE_STRING(GPRS_RLCMAC_DL_ASS_SEND_ASS), - OSMO_VALUE_STRING(GPRS_RLCMAC_DL_ASS_WAIT_ACK), - { 0, NULL } -}; - -const struct value_string gprs_rlcmac_tbf_ul_ass_state_names[] = { - OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_NONE), - OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_SEND_ASS), - OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_SEND_ASS_REJ), - OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ASS_WAIT_ACK), - { 0, NULL } -}; - -const struct value_string gprs_rlcmac_tbf_ul_ack_state_names[] = { - OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ACK_NONE), - OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ACK_SEND_ACK), /* send acknowledge on next RTS */ - OSMO_VALUE_STRING(GPRS_RLCMAC_UL_ACK_WAIT_ACK), /* wait for PACKET CONTROL ACK */ - { 0, NULL } -}; - static const struct value_string tbf_counters_names[] = { OSMO_VALUE_STRING(N3101), OSMO_VALUE_STRING(N3103), @@ -91,11 +63,8 @@ static const struct value_string tbf_counters_names[] = { }; static const struct value_string tbf_timers_names[] = { - OSMO_VALUE_STRING(T0), - OSMO_VALUE_STRING(T3169), + OSMO_VALUE_STRING(T3141), OSMO_VALUE_STRING(T3191), - OSMO_VALUE_STRING(T3193), - OSMO_VALUE_STRING(T3195), { 0, NULL } }; @@ -119,26 +88,17 @@ gprs_rlcmac_tbf::Meas::Meas() : } gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir) : - state_flags(0), direction(dir), trx(NULL), - first_ts(0), - first_common_ts(0), - control_ts(0xff), - poll_ts(0), + control_ts(NULL), fT(0), num_fT_exp(0), - was_releasing(0), - upgrade_to_multislot(0), + upgrade_to_multislot(false), bts(bts_), - m_tfi(0), + m_tfi(TBF_TFI_UNSET), m_created_ts(0), m_ctrs(NULL), - state(GPRS_RLCMAC_NULL), m_ms(ms), - dl_ass_state(GPRS_RLCMAC_DL_ASS_NONE), - ul_ass_state(GPRS_RLCMAC_UL_ASS_NONE), - ul_ack_state(GPRS_RLCMAC_UL_ACK_NONE), m_egprs_enabled(false) { /* The classes of these members do not have proper constructors yet. @@ -150,13 +110,43 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_ memset(&m_ms_list, 0, sizeof(m_ms_list)); m_ms_list.entry = this; - memset(&m_bts_list, 0, sizeof(m_bts_list)); - m_bts_list.entry = this; + memset(&m_trx_list, 0, sizeof(m_trx_list)); + m_trx_list.entry = this; + + 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); + OSMO_ASSERT(ul_ass_fsm.fi); + memset(&dl_ass_fsm, 0, sizeof(dl_ass_fsm)); + dl_ass_fsm.tbf = this; + dl_ass_fsm.fi = osmo_fsm_inst_alloc(&tbf_dl_ass_fsm, this, &dl_ass_fsm, LOGL_INFO, NULL); + 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_fi); + state_fi = NULL; + + osmo_fsm_inst_free(ul_ass_fsm.fi); + ul_ass_fsm.fi = NULL; + osmo_fsm_inst_free(dl_ass_fsm.fi); + dl_ass_fsm.fi = NULL; + + rate_ctr_group_free(m_ctrs); } uint32_t gprs_rlcmac_tbf::tlli() const @@ -212,9 +202,8 @@ void gprs_rlcmac_tbf::set_ms(GprsMs *ms) if (m_ms == ms) return; - if (m_ms) { + if (m_ms) ms_detach_tbf(m_ms, this); - } m_ms = ms; @@ -222,33 +211,23 @@ 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) +void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf) { - 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; + int ts; - old_ms = bts_ms_store(bts)->get_ms(tlli, 0, NULL); - if (old_ms) - ms_merge_and_clear_ms(ms(), old_ms); + /* During assignment (state=ASSIGN), tbf may be temporarily using + * tbf->control_ts from a previous TBF/SBA to transmit the UL/DL + * Assignment, which may not be necessarily be a TS where the current TBF + * is attached to. This will be the case until a TBF receives proper + * 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) { + pdch_ulc_release_tbf(tbf->control_ts->ulc, tbf); + tbf->control_ts = NULL; } - 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) -{ - int ts; - + /* Now simply detach from all attached PDCHs */ for (ts = 0; ts < 8; ts++) { if (!tbf->pdch[ts]) continue; @@ -256,50 +235,47 @@ 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) { /* update counters */ if (tbf->direction == GPRS_RLCMAC_UL_TBF) { - gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(tbf); bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_FREED); - if (tbf->state_is(GPRS_RLCMAC_FLOW)) + if (tbf->state_is(TBF_ST_FLOW)) bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_UL_ABORTED); - rate_ctr_group_free(ul_tbf->m_ul_egprs_ctrs); - rate_ctr_group_free(ul_tbf->m_ul_gprs_ctrs); } else { - gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf); - if (tbf->is_egprs_enabled()) { - rate_ctr_group_free(dl_tbf->m_dl_egprs_ctrs); - } else { - rate_ctr_group_free(dl_tbf->m_dl_gprs_ctrs); - } + 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); - if (tbf->state_is(GPRS_RLCMAC_FLOW)) + if (tbf->state_is(TBF_ST_FLOW)) { bts_do_rate_ctr_inc(tbf->bts, CTR_TBF_DL_ABORTED); - } - - /* Give final measurement report */ - gprs_rlcmac_rssi_rep(tbf); - if (tbf->direction == GPRS_RLCMAC_DL_TBF) { - gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(tbf); - - dl_tbf->abort(); - dl_tbf->cleanup(); + /* range V(A)..V(S)-1 */ + uint16_t lost = win->count_unacked(); + /* report all outstanding packets as lost */ + gprs_rlcmac_received_lost(dl_tbf, 0, lost); + /* TODO: Reschedule all LLC frames starting with the one that is + * (partly) encoded in chunk 1 of block V(A). (optional) */ + } + /* reset rlc states */ + win->reset(); } LOGPTBF(tbf, LOGL_INFO, "free\n"); tbf->stop_timers("freeing TBF"); /* TODO: Could/Should generate bssgp_tx_llc_discarded */ tbf_unlink_pdch(tbf); - llist_del(tbf_bts_list(tbf)); if (tbf->ms()) tbf->set_ms(NULL); - rate_ctr_group_free(tbf->m_ctrs); - LOGP(DTBF, LOGL_DEBUG, "********** %s-TBF ends here **********\n", (tbf->direction != GPRS_RLCMAC_UL_TBF) ? "DL" : "UL"); talloc_free(tbf); @@ -313,61 +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() +void tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf) { - int rc; - - if (direction != GPRS_RLCMAC_DL_TBF) - return -EINVAL; - - LOGP(DTBF, LOGL_DEBUG, "********** DL-TBF update **********\n"); - - 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; - } + char buf[128]; + struct gprs_rlcmac_pdch *first_common = ms_first_common_ts(tbf_ms(tbf)); + OSMO_ASSERT(first_common); - if (is_egprs_enabled()) { - gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this); - if (dl_tbf) - dl_tbf->set_window_size(); - } - - return 0; + 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; } -int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf) -{ - if (tbf->control_ts == 0xff) - 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; - - return 0; -} - -const char *gprs_rlcmac_tbf::tbf_state_name[] = { - "NULL", - "ASSIGN", - "FLOW", - "FINISHED", - "WAIT RELEASE", - "RELEASING", -}; - 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; @@ -378,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: @@ -436,8 +388,7 @@ bool gprs_rlcmac_tbf::timers_pending(enum tbf_timers t) if (t != T_MAX) return osmo_timer_pending(&Tarr[t]); - /* we don't start with T0 because it's internal timer which requires special handling */ - for (i = T3169; i < T_MAX; i++) + for (i = T3141; i < T_MAX; i++) if (osmo_timer_pending(&Tarr[i])) return true; @@ -447,19 +398,15 @@ bool gprs_rlcmac_tbf::timers_pending(enum tbf_timers t) void gprs_rlcmac_tbf::stop_timers(const char *reason) { uint8_t i; - /* we start with T0 because timer reset does not require any special handling */ - for (i = T0; i < T_MAX; i++) + for (i = T3141; i < T_MAX; i++) t_stop((enum tbf_timers)i, reason); } static inline void tbf_timeout_free(struct gprs_rlcmac_tbf *tbf, enum tbf_timers t, bool run_diag) { - LOGPTBF(tbf, LOGL_NOTICE, "%s timeout expired, freeing TBF\n", - get_value_string(tbf_timers_names, t)); - if (run_diag) { LOGPTBF(tbf, LOGL_NOTICE, "%s timeout expired, freeing TBF: %s\n", - get_value_string(tbf_timers_names, t), tbf->rlcmac_diag().c_str()); + get_value_string(tbf_timers_names, t), tbf_rlcmac_diag(tbf)); } else { LOGPTBF(tbf, LOGL_NOTICE, "%s timeout expired, freeing TBF\n", get_value_string(tbf_timers_names, t)); @@ -470,10 +417,12 @@ static inline void tbf_timeout_free(struct gprs_rlcmac_tbf *tbf, enum tbf_timers #define T_CBACK(t, diag) static void cb_##t(void *_tbf) { tbf_timeout_free((struct gprs_rlcmac_tbf *)_tbf, t, diag); } -T_CBACK(T3169, true) +/* 3GPP TS 44.018 sec 3.5.2.1.5: On the network side, if timer T3141 elapses + * before a successful contention resolution procedure is completed, the newly + * allocated temporary block flow is released as specified in 3GPP TS 44.060 and + * the packet access is forgotten.*/ +T_CBACK(T3141, true) T_CBACK(T3191, true) -T_CBACK(T3193, false) -T_CBACK(T3195, true) void gprs_rlcmac_tbf::t_start(enum tbf_timers t, int T, const char *reason, bool force, const char *file, unsigned line) @@ -509,28 +458,19 @@ 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; switch(t) { - case T0: - Tarr[t].cb = tbf_timer_cb; - break; - case T3169: - Tarr[t].cb = cb_T3169; + case T3141: + Tarr[t].cb = cb_T3141; break; case T3191: Tarr[t].cb = cb_T3191; break; - case T3193: - Tarr[t].cb = cb_T3193; - break; - case T3195: - Tarr[t].cb = cb_T3195; - break; default: LOGPSRC(DTBF, LOGL_ERROR, file, line, "%s attempting to set callback for unknown timer %s [%s], cur_fn=%d\n", tbf_name(this), get_value_string(tbf_timers_names, t), reason, current_fn); @@ -539,558 +479,168 @@ 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 +void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_fn, enum pdch_ulc_tbf_poll_reason reason) { - 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; - } + gprs_rlcmac_ul_tbf *ul_tbf; + gprs_rlcmac_dl_tbf *dl_tbf; - return 0; -} - -void gprs_rlcmac_tbf::set_polling(uint32_t new_poll_fn, uint8_t ts, enum pdch_ulc_tbf_poll_reason reason) -{ - const char *chan = "UNKNOWN"; - - if (state_flags & (1 << (GPRS_RLCMAC_FLAG_CCCH))) - chan = "CCCH"; - - if (state_flags & (1 << (GPRS_RLCMAC_FLAG_PACCH))) - chan = "PACCH"; - - if ((state_flags & (1 << (GPRS_RLCMAC_FLAG_PACCH))) && (state_flags & (1 << (GPRS_RLCMAC_FLAG_CCCH)))) - LOGPTBFDL(this, LOGL_ERROR, - "Attempt to schedule polling on %s (FN=%d, TS=%d) with both CCCH and PACCH flags set - FIXME!\n", - chan, new_poll_fn, ts); - - /* 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 %s (FN=%d, TS=%d)\n", - chan, new_poll_fn, ts); - return; - } - poll_ts = ts; + 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_ASS: - ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK; - - LOGPTBFDL(this, LOGL_INFO, "Scheduled UL Assignment polling on %s (FN=%d, TS=%d)\n", - chan, new_poll_fn, poll_ts); - break; - case PDCH_ULC_POLL_DL_ASS: - dl_ass_state = GPRS_RLCMAC_DL_ASS_WAIT_ACK; - - LOGPTBFDL(this, LOGL_INFO, "Scheduled DL Assignment polling on %s (FN=%d, TS=%d)\n", - chan, new_poll_fn, poll_ts); - break; case PDCH_ULC_POLL_UL_ACK: - ul_ack_state = GPRS_RLCMAC_UL_ACK_WAIT_ACK; - - LOGPTBFUL(this, LOGL_DEBUG, "Scheduled UL Acknowledgement polling on %s (FN=%d, TS=%d)\n", - chan, new_poll_fn, poll_ts); - break; - case PDCH_ULC_POLL_DL_ACK: - LOGPTBFDL(this, LOGL_DEBUG, "Scheduled DL Acknowledgement polling on %s (FN=%d, TS=%d)\n", - chan, new_poll_fn, poll_ts); - break; - case PDCH_ULC_POLL_CELL_CHG_CONTINUE: - LOGPTBFDL(this, LOGL_DEBUG, "Scheduled 'Packet Cell Change Continue' polling on %s (FN=%d, TS=%d)\n", - chan, new_poll_fn, poll_ts); - break; - } -} - -void gprs_rlcmac_tbf::poll_timeout(uint32_t poll_fn, enum pdch_ulc_tbf_poll_reason reason) -{ - uint16_t pgroup; - gprs_rlcmac_ul_tbf *ul_tbf = as_ul_tbf(this); - - LOGPTBF(this, LOGL_NOTICE, "poll timeout for FN=%d, TS=%d (curr FN %d)\n", - poll_fn, poll_ts, bts_current_frame_number(bts)); - - if (ul_tbf && ul_tbf->handle_ctrl_ack(reason)) { - if (!ul_tbf->ctrl_ack_to_toggle()) { - LOGPTBF(this, LOGL_NOTICE, - "Timeout for polling PACKET CONTROL ACK for PACKET UPLINK ACK: %s\n", - rlcmac_diag().c_str()); + 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", + poll_fn, pdch->ts_no, bts_current_frame_number(bts)); + return; } bts_do_rate_ctr_inc(bts, CTR_RLC_ACK_TIMEDOUT); bts_do_rate_ctr_inc(bts, CTR_PUAN_POLL_TIMEDOUT); - if (state_is(GPRS_RLCMAC_FINISHED)) { + if (state_is(TBF_ST_FINISHED)) { if (ul_tbf->n_inc(N3103)) { bts_do_rate_ctr_inc(bts, CTR_PUAN_POLL_FAILED); - TBF_SET_STATE(ul_tbf, GPRS_RLCMAC_RELEASING); - T_START(ul_tbf, T3169, 3169, "MAX N3103 reached", false); + osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_MAX_N3103, NULL); return; } - /* reschedule UL ack */ - ul_tbf->ul_ack_state = GPRS_RLCMAC_UL_ACK_SEND_ACK; } + osmo_fsm_inst_dispatch(ul_tbf->ul_ack_fsm.fi, TBF_UL_ACK_EV_POLL_TIMEOUT, NULL); + break; - } else if (ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { - if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS))) { - LOGPTBF(this, LOGL_NOTICE, - "Timeout for polling PACKET CONTROL ACK for PACKET UPLINK ASSIGNMENT: %s\n", - rlcmac_diag().c_str()); - state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS); + case PDCH_ULC_POLL_UL_ASS: + if (!ul_ass_state_is(TBF_UL_ASS_WAIT_ACK)) { + LOGPTBF(this, LOGL_NOTICE, "FN=%d, TS=%d (curr FN %d): POLL_UL_ASS not expected! state is %s\n", + poll_fn, pdch->ts_no, bts_current_frame_number(bts), + osmo_fsm_inst_state_name(tbf_ul_ass_fi(this))); + return; } - ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT); bts_do_rate_ctr_inc(bts, CTR_PUA_POLL_TIMEDOUT); - if (n_inc(N3105)) { - TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING); - T_START(this, T3195, 3195, "MAX N3105 reached", true); + 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; } - /* 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))) { - LOGPTBF(this, LOGL_NOTICE, - "Timeout for polling PACKET CONTROL ACK for PACKET DOWNLINK ASSIGNMENT: %s\n", - rlcmac_diag().c_str()); - state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS); + /* Signal timeout to FSM to reschedule UL assignment */ + osmo_fsm_inst_dispatch(this->ul_ass_fsm.fi, TBF_UL_ASS_EV_ASS_POLL_TIMEOUT, NULL); + break; + + case PDCH_ULC_POLL_DL_ASS: + if (!dl_ass_state_is(TBF_DL_ASS_WAIT_ACK)) { + LOGPTBF(this, LOGL_NOTICE, "FN=%d, TS=%d (curr FN %d): POLL_DL_ASS not expected! state is %s\n", + poll_fn, pdch->ts_no, bts_current_frame_number(bts), + osmo_fsm_inst_state_name(tbf_dl_ass_fi(this))); + return; } - dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT); bts_do_rate_ctr_inc(bts, CTR_PDA_POLL_TIMEDOUT); - if (n_inc(N3105)) { - TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING); - T_START(this, T3195, 3195, "MAX N3105 reached", true); + 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; } - /* reschedule DL assignment */ - dl_ass_state = GPRS_RLCMAC_DL_ASS_SEND_ASS; - } else if (m_ms->nacc && m_ms->nacc->fi->state == NACC_ST_WAIT_CELL_CHG_CONTINUE_ACK && - m_ms->nacc->continue_poll_fn == poll_fn && m_ms->nacc->continue_poll_ts == poll_ts) { + /* Signal timeout to FSM to reschedule DL assignment */ + osmo_fsm_inst_dispatch(this->dl_ass_fsm.fi, TBF_DL_ASS_EV_ASS_POLL_TIMEOUT, NULL); + break; + + case PDCH_ULC_POLL_CELL_CHG_CONTINUE: + if (!m_ms->nacc || !nacc_fsm_exp_ctrl_ack(m_ms->nacc, poll_fn, pdch->ts_no)) { + LOGPTBF(this, LOGL_NOTICE, "FN=%d, TS=%d (curr FN %d): POLL_CELL_CHG_CONTINUE not expected!\n", + poll_fn, pdch->ts_no, bts_current_frame_number(bts)); + return; + } /* Timeout waiting for CTRL ACK acking Pkt Cell Change Continue */ osmo_fsm_inst_dispatch(m_ms->nacc->fi, NACC_EV_TIMEOUT_CELL_CHG_CONTINUE, NULL); - return; - } else if (direction == GPRS_RLCMAC_DL_TBF) { - gprs_rlcmac_dl_tbf *dl_tbf = as_dl_tbf(this); + break; - if (!(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) { + case PDCH_ULC_POLL_DL_ACK: + 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->m_last_dl_poll_ack_lost) { LOGPTBF(this, LOGL_NOTICE, "Timeout for polling PACKET DOWNLINK ACK: %s\n", - dl_tbf->rlcmac_diag().c_str()); - dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK); + tbf_rlcmac_diag(dl_tbf)); + dl_tbf->m_last_dl_poll_ack_lost = true; } - - if (dl_tbf->state_is(GPRS_RLCMAC_RELEASING)) + if (dl_tbf->state_is(TBF_ST_RELEASING)) bts_do_rate_ctr_inc(bts, CTR_RLC_REL_TIMEDOUT); else { bts_do_rate_ctr_inc(bts, CTR_RLC_ACK_TIMEDOUT); bts_do_rate_ctr_inc(bts, CTR_PDAN_POLL_TIMEDOUT); } - if (dl_tbf->n_inc(N3105)) { - TBF_SET_STATE(dl_tbf, GPRS_RLCMAC_RELEASING); - T_START(dl_tbf, T3195, 3195, "MAX N3105 reached", true); + 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 */ - if ((dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)) - && !(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))) { - LOGPTBF(dl_tbf, LOGL_DEBUG, "Re-send dowlink assignment on PCH (IMSI=%s)\n", - imsi()); - /* send immediate assignment */ - if ((pgroup = imsi2paging_group(imsi())) > 999) - LOGPTBF(dl_tbf, LOGL_ERROR, "IMSI to paging group failed! (%s)\n", imsi()); - bts_snd_dl_ass(dl_tbf->bts, dl_tbf, pgroup); - dl_tbf->m_wait_confirm = 1; - } - } else - LOGPTBF(this, LOGL_ERROR, "Poll Timeout, but no event!\n"); -} - -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 control ts */ - rc = tbf_assign_control_ts(this); - /* if no resource */ - if (rc < 0) { - return -1; - } - - /* 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; - } - - ms_attach_tbf(m_ms, this); - - return 0; -} - -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() -{ - int current_fn = bts_current_frame_number(bts); - - LOGPTBF(this, LOGL_DEBUG, "timer 0 expired. cur_fn=%d\n", current_fn); - - /* assignment */ - if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) { - if (state_is(GPRS_RLCMAC_ASSIGN)) { - LOGPTBF(this, LOGL_NOTICE, "releasing due to PACCH assignment timeout.\n"); - tbf_free(this); - return; - } else - LOGPTBF(this, LOGL_ERROR, "Error: TBF is not in assign state\n"); - } - - if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) { - gprs_rlcmac_dl_tbf *dl_tbf = as_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 */ - TBF_SET_STATE(dl_tbf, GPRS_RLCMAC_FLOW); - return; - } - - /* 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->update(); + osmo_fsm_inst_dispatch(this->state_fi, TBF_EV_DL_ACKNACK_MISS, NULL); + break; - dl_tbf->trigger_ass(dl_tbf); - } else - LOGPTBF(dl_tbf, LOGL_NOTICE, "Continue flow after IMM.ASS confirm\n"); + default: + LOGPTBF(this, LOGL_ERROR, "Poll Timeout, reason %s unhandled!\n", + get_value_string(pdch_ulc_tbf_poll_reason_names, reason)); } } -std::string gprs_rlcmac_tbf::rlcmac_diag() +const char *tbf_name(const gprs_rlcmac_tbf *tbf) { - std::ostringstream os; - os << "|"; - if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) - os << "Assignment was on CCCH|"; - if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) - os << "Assignment was on PACCH|"; - if ((state_flags & (1 << GPRS_RLCMAC_FLAG_UL_DATA))) - os << "Uplink data was received|"; - else if (direction == GPRS_RLCMAC_UL_TBF) - os << "No uplink data received yet|"; - if ((state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK))) - os << "Downlink ACK was received|"; - else if (direction == GPRS_RLCMAC_DL_TBF) - os << "No downlink ACK received yet|"; - - return os.str(); + return tbf ? tbf->name() : "(no TBF)"; } -struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts) +const char *gprs_rlcmac_tbf::name(bool enclousure) const { - struct msgb *msg; - struct gprs_rlcmac_dl_tbf *new_dl_tbf = NULL; - RlcMacDownlink_t *mac_control_block = NULL; - int poll_ass_dl = 1; - unsigned int rrbp = 0; - uint32_t new_poll_fn = 0; - int rc; - bool old_tfi_is_valid = is_tfi_assigned(); - - if (direction == GPRS_RLCMAC_DL_TBF && !is_control_ts(ts)) { - LOGPTBF(this, LOGL_NOTICE, - "Cannot poll for downlink assignment, because MS cannot reply. (TS=%d, first common TS=%d)\n", - ts, first_common_ts); - poll_ass_dl = 0; - } - if (poll_ass_dl) { - if (ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) - { - LOGPTBF(this, LOGL_DEBUG, - "Polling is already scheduled, so we must wait for the uplink assignment...\n"); - return NULL; - } - rc = check_polling(fn, ts, &new_poll_fn, &rrbp); - if (rc < 0) - return NULL; - } + struct osmo_strbuf sb = { .buf = m_name_buf, .len = sizeof(m_name_buf) }; - /* on uplink TBF we get the downlink TBF to be assigned. */ - if (direction == GPRS_RLCMAC_UL_TBF) { - gprs_rlcmac_ul_tbf *ul_tbf = as_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) { - LOGPTBF(this, LOGL_DEBUG, - "Cannot assign DL TBF now, because contention resolution is not finished.\n"); - return NULL; - } + 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); } - - if (ms()) - new_dl_tbf = ms_dl_tbf(ms()); - - if (!new_dl_tbf) { - LOGPTBFDL(this, LOGL_ERROR, - "We have a schedule for downlink assignment, but there is no downlink TBF\n"); - dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; - return NULL; - } - - if (new_dl_tbf == as_dl_tbf(this)) - LOGPTBF(this, LOGL_DEBUG, "New and old TBF are the same.\n"); - - if (old_tfi_is_valid && !new_dl_tbf->is_tlli_valid()) { - LOGPTBF(this, LOGL_ERROR, - "The old TFI is not assigned and there is no TLLI. New TBF %s\n", - new_dl_tbf->name()); - dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; - return NULL; - } - - new_dl_tbf->was_releasing = was_releasing; - msg = msgb_alloc(GSM_MACBLOCK_LEN, "rlcmac_dl_ass"); - if (!msg) - return NULL; - - /* Initialize a bit vector that uses allocated msgb as the data buffer. - * Old G++ does not support non-trivial designated initializers. Sigh. */ - struct bitvec bv = { }; - bv.data = msgb_put(msg, GSM_MACBLOCK_LEN); - bv.data_len = GSM_MACBLOCK_LEN; - bitvec_unhex(&bv, DUMMY_VEC); - - LOGPTBF(new_dl_tbf, LOGL_INFO, "start Packet Downlink Assignment (PACCH)\n"); - mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); - Encoding::write_packet_downlink_assignment(mac_control_block, - old_tfi_is_valid, m_tfi, (direction == GPRS_RLCMAC_DL_TBF), - new_dl_tbf, poll_ass_dl, rrbp, - bts_get_ms_pwr_alpha(new_dl_tbf->bts), the_pcu->vty.gamma, -1, 0, - is_egprs_enabled()); - LOGP(DTBF, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Downlink Assignment +++++++++++++++++++++++++\n"); - rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block); - if (rc < 0) { - LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Downlink Ass failed (%d)\n", rc); - goto free_ret; - } - LOGP(DTBF, LOGL_DEBUG, "------------------------- TX : Packet Downlink Assignment -------------------------\n"); - bts_do_rate_ctr_inc(bts, CTR_PKT_DL_ASSIGNMENT); - - if (poll_ass_dl) { - set_polling(new_poll_fn, ts, PDCH_ULC_POLL_DL_ASS); - } else { - dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; - TBF_SET_STATE(new_dl_tbf, GPRS_RLCMAC_FLOW); - tbf_assign_control_ts(new_dl_tbf); - /* stop pending assignment timer */ - new_dl_tbf->t_stop(T0, "assignment (DL-TBF)"); - - } - - talloc_free(mac_control_block); - return msg; - -free_ret: - talloc_free(mac_control_block); - msgb_free(msg); - return NULL; -} - -struct msgb *gprs_rlcmac_tbf::create_packet_access_reject() -{ - struct msgb *msg; - - msg = msgb_alloc(GSM_MACBLOCK_LEN, "rlcmac_ul_ass_rej"); - - bitvec *packet_access_rej = bitvec_alloc(GSM_MACBLOCK_LEN, tall_pcu_ctx); - - bitvec_unhex(packet_access_rej, DUMMY_VEC); - - Encoding::write_packet_access_reject( - packet_access_rej, tlli()); - - bts_do_rate_ctr_inc(bts, CTR_PKT_ACCESS_REJ); - - bitvec_pack(packet_access_rej, msgb_put(msg, GSM_MACBLOCK_LEN)); - - bitvec_free(packet_access_rej); - ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; - - /* Start Tmr only if it is UL TBF */ - if (direction == GPRS_RLCMAC_UL_TBF) - T_START(this, T0, -2000, "reject (PACCH)", true); - - return msg; - + 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; } -struct msgb *gprs_rlcmac_tbf::create_ul_ass(uint32_t fn, uint8_t ts) +void tbf_update_state_fsm_name(struct gprs_rlcmac_tbf *tbf) { - struct msgb *msg = NULL; - struct gprs_rlcmac_ul_tbf *new_tbf = NULL; - RlcMacDownlink_t *mac_control_block = NULL; - int rc; - unsigned int rrbp; - uint32_t new_poll_fn; - - if (ul_ass_state == GPRS_RLCMAC_UL_ASS_WAIT_ACK) { - LOGPTBFUL(this, LOGL_DEBUG, - "Polling is already scheduled, so we must wait for the uplink assignment...\n"); - return NULL; - } + const char *buf = tbf->name(false); - rc = check_polling(fn, ts, &new_poll_fn, &rrbp); - if (rc < 0) - return NULL; - - if (ms()) - new_tbf = ms_ul_tbf(ms()); - if (!new_tbf) { - LOGPTBFUL(this, LOGL_ERROR, - "We have a schedule for uplink assignment, but there is no uplink TBF\n"); - ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; - return NULL; - } + 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); - msg = msgb_alloc(GSM_MACBLOCK_LEN, "rlcmac_ul_ass"); - if (!msg) - return NULL; - - /* Initialize a bit vector that uses allocated msgb as the data buffer. - * Old G++ does not support non-trivial designated initializers. Sigh. */ - struct bitvec bv = { }; - bv.data = msgb_put(msg, GSM_MACBLOCK_LEN); - bv.data_len = GSM_MACBLOCK_LEN; - bitvec_unhex(&bv, DUMMY_VEC); - - LOGPTBF(new_tbf, LOGL_INFO, "start Packet Uplink Assignment (PACCH)\n"); - mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t); - Encoding::write_packet_uplink_assignment(mac_control_block, m_tfi, - (direction == GPRS_RLCMAC_DL_TBF), tlli(), - is_tlli_valid(), new_tbf, 1, rrbp, bts_get_ms_pwr_alpha(new_tbf->bts), - the_pcu->vty.gamma, -1, is_egprs_enabled()); - - LOGP(DTBF, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n"); - rc = encode_gsm_rlcmac_downlink(&bv, mac_control_block); - if (rc < 0) { - LOGP(DTBF, LOGL_ERROR, "Encoding of Packet Uplink Ass failed (%d)\n", rc); - goto free_ret; + if (tbf_direction(tbf) == GPRS_RLCMAC_UL_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); } - LOGP(DTBF, LOGL_DEBUG, "------------------------- TX : Packet Uplink Assignment -------------------------\n"); - bts_do_rate_ctr_inc(bts, CTR_PKT_UL_ASSIGNMENT); - - set_polling(new_poll_fn, ts, PDCH_ULC_POLL_UL_ASS); - talloc_free(mac_control_block); - return msg; - -free_ret: - talloc_free(mac_control_block); - msgb_free(msg); - return NULL; -} - -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 -{ - 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'; - return m_name_buf; } void gprs_rlcmac_tbf::rotate_in_list() { - llist_del(tbf_bts_list((struct gprs_rlcmac_tbf *)this)); + llist_del(tbf_trx_list((struct gprs_rlcmac_tbf *)this)); if (direction == GPRS_RLCMAC_UL_TBF) - llist_add(tbf_bts_list((struct gprs_rlcmac_tbf *)this), &bts->ul_tbfs); + llist_add(tbf_trx_list((struct gprs_rlcmac_tbf *)this), &trx->ul_tbfs); else - llist_add(tbf_bts_list((struct gprs_rlcmac_tbf *)this), &bts->dl_tbfs); -} - -uint8_t gprs_rlcmac_tbf::tsc() const -{ - return trx->pdch[first_ts].tsc; + llist_add(tbf_trx_list((struct gprs_rlcmac_tbf *)this), &trx->dl_tbfs); } uint8_t gprs_rlcmac_tbf::dl_slots() const @@ -1112,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; } @@ -1129,15 +681,43 @@ uint8_t gprs_rlcmac_tbf::ul_slots() const return slots; } -bool gprs_rlcmac_tbf::is_control_ts(uint8_t ts) const +void gprs_rlcmac_tbf::enable_egprs() { - return ts == control_ts; + /* Decrease GPRS TBF count of attached PDCHs */ + for (size_t ts = 0; ts < ARRAY_SIZE(pdch); ts++) { + if (pdch[ts]) + pdch[ts]->num_tbfs_update(this, false); + } + + m_egprs_enabled = true; + window()->set_sns(RLC_EGPRS_SNS); + + /* Increase EGPRS TBF count of attached PDCHs */ + for (size_t ts = 0; ts < ARRAY_SIZE(pdch); ts++) { + if (pdch[ts]) + pdch[ts]->num_tbfs_update(this, true); + } } /* C API */ -enum gprs_rlcmac_tbf_state tbf_state(const struct gprs_rlcmac_tbf *tbf) +enum tbf_fsm_states tbf_state(const struct gprs_rlcmac_tbf *tbf) +{ + 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) +{ + return tbf->ul_ass_fsm.fi; +} + +struct osmo_fsm_inst *tbf_dl_ass_fi(const struct gprs_rlcmac_tbf *tbf) { - return tbf->state; + return tbf->dl_ass_fsm.fi; } enum gprs_rlcmac_tbf_direction tbf_direction(const struct gprs_rlcmac_tbf *tbf) @@ -1155,9 +735,9 @@ struct llist_head *tbf_ms_list(struct gprs_rlcmac_tbf *tbf) return &tbf->m_ms_list.list; } -struct llist_head *tbf_bts_list(struct gprs_rlcmac_tbf *tbf) +struct llist_head *tbf_trx_list(struct gprs_rlcmac_tbf *tbf) { - return &tbf->m_bts_list.list; + return &tbf->m_trx_list.list; } struct GprsMs *tbf_ms(const struct gprs_rlcmac_tbf *tbf) @@ -1175,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(); @@ -1191,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) @@ -1199,17 +786,121 @@ uint8_t tbf_tfi(const struct gprs_rlcmac_tbf *tbf) return tbf->tfi(); } -int tbf_check_polling(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts, uint32_t *poll_fn, unsigned int *rrbp) +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, 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, const struct gprs_rlcmac_pdch *pdch, uint32_t new_poll_fn, enum pdch_ulc_tbf_poll_reason 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) +{ + tbf->poll_timeout(pdch, poll_fn, reason); +} + +bool tbf_is_control_ts(const struct gprs_rlcmac_tbf *tbf, const struct gprs_rlcmac_pdch *pdch) +{ + 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; -void tbf_set_polling(struct gprs_rlcmac_tbf *tbf, uint32_t new_poll_fn, uint8_t ts, enum pdch_ulc_tbf_poll_reason t) + 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->set_polling(new_poll_fn, ts, t); + 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; } -void tbf_poll_timeout(struct gprs_rlcmac_tbf *tbf, uint32_t poll_fn, enum pdch_ulc_tbf_poll_reason reason) +const char* tbf_rlcmac_diag(const struct gprs_rlcmac_tbf *tbf) { - tbf->poll_timeout(poll_fn, reason); + static char buf[256]; + struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) }; + + OSMO_STRBUF_PRINTF(sb, "|"); + if (tbf->direction == GPRS_RLCMAC_UL_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 { + 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|"); + } + + 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 |