diff options
-rw-r--r-- | src/bts.cpp | 2 | ||||
-rw-r--r-- | src/tbf.cpp | 211 | ||||
-rw-r--r-- | src/tbf.h | 25 | ||||
-rw-r--r-- | src/tbf_dl.cpp | 14 | ||||
-rw-r--r-- | src/tbf_ul.cpp | 2 | ||||
-rw-r--r-- | tests/tbf/TbfTest.cpp | 4 |
6 files changed, 179 insertions, 79 deletions
diff --git a/src/bts.cpp b/src/bts.cpp index b2af7aac..9e8a6c83 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -687,7 +687,7 @@ int BTS::rcv_rach(uint16_t ra, uint32_t Fn, int16_t qta, uint8_t is_11bit, tbf->set_ta(ta); tbf->set_state(GPRS_RLCMAC_FLOW); tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_CCCH); - tbf_timer_start(tbf, 3169, m_bts.t3169, 0, "RACH (new UL-TBF)"); + tbf->t_start(T3169, m_bts.t3169, 0, "RACH (new UL-TBF)", true); LOGPTBF(tbf, LOGL_DEBUG, "[UPLINK] START\n"); LOGPTBF(tbf, LOGL_DEBUG, "RX: [PCU <- BTS] RACH " "qbit-ta=%d ra=0x%02x, Fn=%d " diff --git a/src/tbf.cpp b/src/tbf.cpp index 18059ace..a5eedd93 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -32,6 +32,7 @@ extern "C" { #include <osmocom/core/msgb.h> +#include <osmocom/core/utils.h> #include <osmocom/core/talloc.h> #include <osmocom/core/stats.h> } @@ -58,6 +59,14 @@ const struct value_string gprs_rlcmac_tbf_ul_ass_state_names[] = { { 0, NULL } }; +static const struct value_string tbf_timers_names[] = { + OSMO_VALUE_STRING(T3169), + OSMO_VALUE_STRING(T3191), + OSMO_VALUE_STRING(T3193), + OSMO_VALUE_STRING(T3195), + { 0, NULL } +}; + static const struct rate_ctr_desc tbf_ctr_description[] = { { "rlc.nacked", "RLC Nacked " }, }; @@ -182,6 +191,7 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(BTS *bts_, gprs_rlcmac_tbf_direction dir) : * Just set them to 0 like talloc_zero did */ memset(&pdch, 0, sizeof(pdch)); memset(&timer, 0, sizeof(timer)); + memset(&T31, 0, sizeof(T31)); memset(&m_rlc, 0, sizeof(m_rlc)); memset(&gsm_timer, 0, sizeof(gsm_timer)); @@ -323,7 +333,7 @@ void gprs_rlcmac_tbf::merge_and_clear_ms(GprsMs *old_ms) /* Clean up the old MS object */ /* TODO: Use timer? */ - if (old_ms->ul_tbf() && old_ms->ul_tbf()->T == 0) { + if (old_ms->ul_tbf() && !old_ms->ul_tbf()->timers_pending(T_MAX)) { if (old_ms->ul_tbf() == this) { LOGP(DRLCMAC, LOGL_ERROR, "%s is referred by the old MS " @@ -334,7 +344,7 @@ void gprs_rlcmac_tbf::merge_and_clear_ms(GprsMs *old_ms) tbf_free(old_ms->ul_tbf()); } } - if (old_ms->dl_tbf() && old_ms->dl_tbf()->T == 0) { + if (old_ms->dl_tbf() && !old_ms->dl_tbf()->timers_pending(T_MAX)) { if (old_ms->dl_tbf() == this) { LOGP(DRLCMAC, LOGL_ERROR, "%s is referred by the old MS " @@ -393,7 +403,7 @@ gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts, 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, "allocation (UL-TBF)"); + tbf->t_start(T3169, bts->t3169, 0, "allocation (UL-TBF)", true); tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF); OSMO_ASSERT(tbf->ms()); @@ -462,6 +472,7 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf) get_value_string(gprs_rlcmac_tbf_dl_ass_state_names, tbf->dl_ass_state)); tbf->stop_timer("freeing TBF"); + tbf->stop_timers("freeing TBF"); /* TODO: Could/Should generate bssgp_tx_llc_discarded */ tbf_unlink_pdch(tbf); llist_del(&tbf->list()); @@ -547,9 +558,40 @@ void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T, osmo_timer_schedule(&tbf->timer, seconds, microseconds); } -void gprs_rlcmac_tbf::stop_t3191() +void gprs_rlcmac_tbf::t_stop(enum tbf_timers t, const char *reason) { - return stop_timer("T3191"); + if (t >= T_MAX) { + LOGPTBF(this, LOGL_ERROR, "attempting to stop unknown timer %s [%s]\n", + get_value_string(tbf_timers_names, t), reason); + } + + if (osmo_timer_pending(&T31[t])) { + LOGPTBF(this, LOGL_DEBUG, "stopping timer %s [%s]\n", + get_value_string(tbf_timers_names, t), reason); + osmo_timer_del(&T31[t]); + } +} + +/* check if any of T31xx timer(s) are pending */ +bool gprs_rlcmac_tbf::timers_pending(enum tbf_timers t) +{ + uint8_t i; + + if (t != T_MAX) + return osmo_timer_pending(&T31[t]); + + for (i = T3169; i < T_MAX; i++) + if (osmo_timer_pending(&T31[i])) + return true; + + return false; +} + +void gprs_rlcmac_tbf::stop_timers(const char *reason) +{ + uint8_t i; + for (i = 0; i < T_MAX; i++) + t_stop((enum tbf_timers)i, reason); } void gprs_rlcmac_tbf::stop_timer(const char *reason) @@ -561,6 +603,60 @@ void gprs_rlcmac_tbf::stop_timer(const char *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) + tbf->rlcmac_diag(); + + tbf_free(tbf); +} + +#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) +T_CBACK(T3191, true) +T_CBACK(T3193, false) +T_CBACK(T3195, true) + +void gprs_rlcmac_tbf::t_start(enum tbf_timers t, uint32_t sec, uint32_t microsec, const char *reason, bool force) +{ + if (t >= T_MAX) { + LOGPTBF(this, LOGL_ERROR, "attempting to start unknown timer %s [%s]\n", + get_value_string(tbf_timers_names, t), reason); + } + + if (!force && osmo_timer_pending(&T31[t])) + return; + + LOGPTBF(this, LOGL_DEBUG, "%sstarting timer %s [%s] with %u sec. %u microsec.\n", + osmo_timer_pending(&T31[t]) ? "re" : "", get_value_string(tbf_timers_names, t), reason, sec, microsec); + + T31[t].data = this; + + switch(t) { + case T3169: + T31[t].cb = cb_T3169; + break; + case T3191: + T31[t].cb = cb_T3191; + break; + case T3193: + T31[t].cb = cb_T3193; + break; + case T3195: + T31[t].cb = cb_T3195; + break; + default: + LOGPTBF(this, LOGL_ERROR, "attempting to set callback for unknown timer %s [%s]\n", + get_value_string(tbf_timers_names, t), reason); + } + + osmo_timer_schedule(&T31[t], sec, microsec); +} + int gprs_rlcmac_tbf::check_polling(uint32_t fn, uint8_t ts, uint32_t *poll_fn_, unsigned int *rrbp_) { @@ -658,7 +754,7 @@ void gprs_rlcmac_tbf::poll_timeout() "- N3103 exceeded\n"); bts->pkt_ul_ack_nack_poll_failed(); ul_tbf->set_state(GPRS_RLCMAC_RELEASING); - tbf_timer_start(ul_tbf, 3169, ul_tbf->bts->bts_data()->t3169, 0, "MAX N3103 reached"); + ul_tbf->t_start(T3169, ul_tbf->bts->bts_data()->t3169, 0, "MAX N3103 reached", false); return; } /* reschedule UL ack */ @@ -680,7 +776,7 @@ void gprs_rlcmac_tbf::poll_timeout() 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, "MAX N3105 reached"); + t_start(T3195, bts_data()->t3195, 0, "MAX N3105 reached", true); bts->rlc_ass_failed(); bts->pua_poll_failed(); return; @@ -702,7 +798,7 @@ void gprs_rlcmac_tbf::poll_timeout() 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, "MAX N3105 reached"); + t_start(T3195, bts_data()->t3195, 0, "MAX N3105 reached", true); bts->rlc_ass_failed(); bts->pda_poll_failed(); return; @@ -728,7 +824,7 @@ void gprs_rlcmac_tbf::poll_timeout() 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, "MAX N3105 reached"); + dl_tbf->t_start(T3195, dl_tbf->bts_data()->t3195, 0, "MAX N3105 reached", true); bts->pkt_dl_ack_nack_poll_failed(); bts->rlc_ack_failed(); return; @@ -999,64 +1095,47 @@ void gprs_rlcmac_tbf::handle_timeout() { LOGPTBF(this, LOGL_DEBUG, "timer %u expired.\n", T); - switch (T) { - case 0: /* 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 */ - 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->update(); - - dl_tbf->trigger_ass(dl_tbf); - } else - LOGPTBF(dl_tbf, LOGL_NOTICE, - "Continue flow after IMM.ASS confirm\n"); - } - break; - case 3169: - case 3191: - case 3195: - LOGPTBF(this, LOGL_NOTICE, "T%d timeout during " - "transsmission\n", 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); + if (T) { + LOGPTBF(this, LOGL_ERROR, "%s timer expired in unknown mode: %u\n", T); return; - break; - default: - LOGP(DRLCMAC, LOGL_ERROR, - "%s timer expired in unknown mode: %u\n", tbf_name(this), T); + } + + /* 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 */ + dl_tbf->set_state(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(); + + dl_tbf->trigger_ass(dl_tbf); + } else + LOGPTBF(dl_tbf, LOGL_NOTICE, "Continue flow after IMM.ASS confirm\n"); } } @@ -138,6 +138,24 @@ enum tbf_egprs_ul_counters { #define LOGPTBFUL(tbf, level, fmt, args...) LOGP(DRLCMACUL, level, "%s " fmt, tbf_name(tbf), ## args) #define LOGPTBFDL(tbf, level, fmt, args...) LOGP(DRLCMACDL, level, "%s " fmt, tbf_name(tbf), ## args) +enum tbf_timers { + /* Wait for reuse of USF and TFI(s) after the MS uplink assignment for this TBF is invalid. */ + T3169, + + /* Wait for reuse of TFI(s) after sending of the last RLC Data Block on this TBF. + Wait for reuse of TFI(s) after sending the PACKET TBF RELEASE for an MBMS radio bearer. */ + T3191, + + /* Wait for reuse of TFI(s) after reception of the final PACKET DOWNLINK ACK/NACK from the + MS for this TBF. */ + T3193, + + /* Wait for reuse of TFI(s) when there is no response from the MS + (radio failure or cell change) for this TBF/MBMS radio bearer. */ + T3195, + T_MAX +}; + #define GPRS_RLCMAC_FLAG_CCCH 0 /* assignment on CCCH */ #define GPRS_RLCMAC_FLAG_PACCH 1 /* assignment on PACCH */ #define GPRS_RLCMAC_FLAG_UL_DATA 2 /* uplink data received */ @@ -177,7 +195,10 @@ struct gprs_rlcmac_tbf { int update(); void handle_timeout(); void stop_timer(const char *reason); - void stop_t3191(); + void stop_timers(const char *reason); + bool timers_pending(enum tbf_timers t); + void t_stop(enum tbf_timers t, const char *reason); + void t_start(enum tbf_timers t, uint32_t sec, uint32_t microsec, const char *reason, bool force); int establish_dl_tbf_on_pacch(); int check_polling(uint32_t fn, uint8_t ts, @@ -305,7 +326,7 @@ private: LListHead<gprs_rlcmac_tbf> m_list; LListHead<gprs_rlcmac_tbf> m_ms_list; bool m_egprs_enabled; - + struct osmo_timer_list T31[T_MAX]; mutable char m_name_buf[60]; }; diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp index 0bcb67b1..b0439892 100644 --- a/src/tbf_dl.cpp +++ b/src/tbf_dl.cpp @@ -216,9 +216,9 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts, } /* Clean up the old MS object */ /* TODO: Put this into a separate function, use timer? */ - if (ms_old->ul_tbf() && ms_old->ul_tbf()->T == 0) + if (ms_old->ul_tbf() && !ms_old->ul_tbf()->timers_pending(T_MAX)) tbf_free(ms_old->ul_tbf()); - if (ms_old->dl_tbf() && ms_old->dl_tbf()->T == 0) + if (ms_old->dl_tbf() && !ms_old->dl_tbf()->timers_pending(T_MAX)) tbf_free(ms_old->dl_tbf()); ms->merge_old_ms(ms_old); @@ -485,6 +485,7 @@ void gprs_rlcmac_dl_tbf::trigger_ass(struct gprs_rlcmac_tbf *old_tbf) { /* stop pending timer */ stop_timer("assignment (DL-TBF)"); + stop_timers("assignment (DL-TBF)"); /* check for downlink tbf: */ if (old_tbf) { @@ -651,7 +652,7 @@ bool gprs_rlcmac_dl_tbf::handle_ack_nack() /* reset N3105 */ n3105 = 0; - stop_t3191(); + t_stop(T3191, "ACK/NACK received"); poll_state = GPRS_RLCMAC_POLL_NONE; return ack_recovered; @@ -854,7 +855,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_dl_acked_block( m_tx_counter = 0; /* start timer whenever we send the final block */ if (is_final) - tbf_timer_start(this, 3191, bts_data()->t3191, 0, "final block (DL-TBF)"); + t_start(T3191, bts_data()->t3191, 0, "final block (DL-TBF)", true); clear_poll_timeout_flag(); @@ -1116,9 +1117,8 @@ int gprs_rlcmac_dl_tbf::release() set_state(GPRS_RLCMAC_WAIT_RELEASE); /* start T3193 */ - tbf_timer_start(this, 3193, - bts_data()->t3193_msec / 1000, - (bts_data()->t3193_msec % 1000) * 1000, "release (DL-TBF)"); + t_start(T3193, bts_data()->t3193_msec / 1000, (bts_data()->t3193_msec % 1000) * 1000, + "release (DL-TBF)", true); /* reset rlc states */ m_tx_counter = 0; diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp index 09ee1f04..8e4e57e8 100644 --- a/src/tbf_ul.cpp +++ b/src/tbf_ul.cpp @@ -191,7 +191,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged( unsigned int block_idx; /* restart T3169 */ - tbf_timer_start(this, 3169, bts_data()->t3169, 0, "acked (data)"); + t_start(T3169, bts_data()->t3169, 0, "acked (data)", true); /* Increment RX-counter */ this->m_rx_counter++; diff --git a/tests/tbf/TbfTest.cpp b/tests/tbf/TbfTest.cpp index d4b51fe2..18bbc76e 100644 --- a/tests/tbf/TbfTest.cpp +++ b/tests/tbf/TbfTest.cpp @@ -51,9 +51,9 @@ static void check_tbf(gprs_rlcmac_tbf *tbf) { OSMO_ASSERT(tbf); if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE)) - OSMO_ASSERT(tbf->T == 3191 || tbf->T == 3193); + OSMO_ASSERT(tbf->timers_pending(T3191) || tbf->timers_pending(T3193)); if (tbf->state_is(GPRS_RLCMAC_RELEASING)) - OSMO_ASSERT(tbf->T != 0); + OSMO_ASSERT(tbf->timers_pending(T_MAX)); } static void test_tbf_base() |