aboutsummaryrefslogtreecommitdiffstats
path: root/src/tbf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tbf.cpp')
-rw-r--r--src/tbf.cpp1051
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