aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2021-05-14 12:50:46 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2021-05-19 12:50:25 +0200
commitdc2aaac29fb5070e4a80d81ad1222d639b084f5c (patch)
treec7e20ae9868f615c13d87d3626a1a509cfa2dac0 /src
parent38f80be73b59f5b1d63abef2002a9c3d1b05e01e (diff)
tbf: Move existing tbf_state implementation to osmo_fsm
This is only an initial implementation, where all state changes are still done outside the FSM itself. The idea is to do the move in several commits so that they can be digested better in logical steps and avoid major break up. Related: OS#2709 Change-Id: I6bb4baea2dee191ba5bbcbec2ea9dcf681aa1237
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gprs_ms.h2
-rw-r--r--src/gprs_rlcmac_sched.cpp8
-rw-r--r--src/pdch.cpp10
-rw-r--r--src/tbf.cpp57
-rw-r--r--src/tbf.h51
-rw-r--r--src/tbf_dl.cpp24
-rw-r--r--src/tbf_fsm.c137
-rw-r--r--src/tbf_fsm.h57
-rw-r--r--src/tbf_ul.cpp14
10 files changed, 275 insertions, 87 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e1225b0a..8070fda3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,6 +58,7 @@ libgprs_la_SOURCES = \
nacc_fsm.c \
neigh_cache.c \
tbf.cpp \
+ tbf_fsm.c \
tbf_ul.cpp \
tbf_dl.cpp \
bts.cpp \
@@ -96,6 +97,7 @@ noinst_HEADERS = \
nacc_fsm.h \
neigh_cache.h \
tbf.h \
+ tbf_fsm.h \
tbf_ul.h \
tbf_dl.h \
bts.h \
diff --git a/src/gprs_ms.h b/src/gprs_ms.h
index 6674261a..4438a4c9 100644
--- a/src/gprs_ms.h
+++ b/src/gprs_ms.h
@@ -159,7 +159,7 @@ static inline struct gprs_llc_queue *ms_llc_queue(struct GprsMs *ms)
static inline bool ms_need_dl_tbf(struct GprsMs *ms)
{
if (ms_dl_tbf(ms) != NULL &&
- tbf_state((const struct gprs_rlcmac_tbf *)ms_dl_tbf(ms)) != GPRS_RLCMAC_WAIT_RELEASE)
+ tbf_state((const struct gprs_rlcmac_tbf *)ms_dl_tbf(ms)) != TBF_ST_WAIT_RELEASE)
return false;
return llc_queue_size(ms_llc_queue(ms)) > 0;
diff --git a/src/gprs_rlcmac_sched.cpp b/src/gprs_rlcmac_sched.cpp
index cd326538..fa86b765 100644
--- a/src/gprs_rlcmac_sched.cpp
+++ b/src/gprs_rlcmac_sched.cpp
@@ -100,7 +100,7 @@ static struct gprs_rlcmac_ul_tbf *sched_select_uplink(struct gprs_rlcmac_pdch *p
/* we don't need to give resources in FINISHED state,
* because we have received all blocks and only poll
* for packet control ack. */
- if (tbf->state_is_not(GPRS_RLCMAC_FLOW))
+ if (tbf->state_is_not(TBF_ST_FLOW))
continue;
if (require_gprs_only && tbf->is_egprs_enabled())
@@ -247,7 +247,7 @@ static inline enum tbf_dl_prio tbf_compute_priority(const struct gprs_rlcmac_bts
if (tbf->is_control_ts(ts) && age > age_thresh2 && age_thresh2 > 0)
return DL_PRIO_HIGH_AGE;
- if ((tbf->state_is(GPRS_RLCMAC_FLOW) && tbf->have_data()) || w->resend_needed() >= 0)
+ if ((tbf->state_is(TBF_ST_FLOW) && tbf->have_data()) || w->resend_needed() >= 0)
return DL_PRIO_NEW_DATA;
if (tbf->is_control_ts(ts) && age > age_thresh1 && tbf->keep_open(fn))
@@ -306,8 +306,8 @@ static struct msgb *sched_select_downlink(struct gprs_rlcmac_bts *bts, struct gp
if (tbf->direction != GPRS_RLCMAC_DL_TBF)
continue;
/* no DL resources needed, go next */
- if (tbf->state_is_not(GPRS_RLCMAC_FLOW)
- && tbf->state_is_not(GPRS_RLCMAC_FINISHED))
+ if (tbf->state_is_not(TBF_ST_FLOW)
+ && tbf->state_is_not(TBF_ST_FINISHED))
continue;
/* waiting for CCCH IMM.ASS confirm */
diff --git a/src/pdch.cpp b/src/pdch.cpp
index 96bab54e..cab81dfd 100644
--- a/src/pdch.cpp
+++ b/src/pdch.cpp
@@ -358,7 +358,7 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
"TBF is gone TLLI=0x%08x\n", tlli);
return;
}
- if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE) &&
+ if (tbf->state_is(TBF_ST_WAIT_RELEASE) &&
tbf->direction == new_tbf->direction)
tbf_free(tbf);
@@ -369,7 +369,7 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
"changed type from CCCH to PACCH\n");
TBF_ASS_TYPE_SET(new_tbf, GPRS_RLCMAC_FLAG_PACCH);
}
- TBF_SET_STATE(new_tbf, GPRS_RLCMAC_FLOW);
+ TBF_SET_STATE(new_tbf, TBF_ST_FLOW);
/* stop pending assignment timer */
new_tbf->t_stop(T0, "control acked (DL-TBF)");
if (new_tbf->check_n_clear(GPRS_RLCMAC_FLAG_TO_DL_ASS))
@@ -390,11 +390,11 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
"TBF is gone TLLI=0x%08x\n", tlli);
return;
}
- if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE) &&
+ if (tbf->state_is(TBF_ST_WAIT_RELEASE) &&
tbf->direction == new_tbf->direction)
tbf_free(tbf);
- TBF_SET_STATE(new_tbf, GPRS_RLCMAC_FLOW);
+ TBF_SET_STATE(new_tbf, TBF_ST_FLOW);
if (new_tbf->check_n_clear(GPRS_RLCMAC_FLAG_TO_UL_ASS))
LOGPTBF(new_tbf, LOGL_NOTICE, "Recovered uplink assignment for UL\n");
@@ -677,7 +677,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
/* Get rid of previous finished UL TBF before providing a new one */
if (ul_tbf) {
- if (!ul_tbf->state_is(GPRS_RLCMAC_FINISHED))
+ if (!ul_tbf->state_is(TBF_ST_FINISHED))
LOGPTBFUL(ul_tbf, LOGL_NOTICE,
"Got PACKET RESOURCE REQ while TBF not finished, killing pending UL TBF\n");
tbf_free(ul_tbf);
diff --git a/src/tbf.cpp b/src/tbf.cpp
index afbb0b13..e83f4723 100644
--- a/src/tbf.cpp
+++ b/src/tbf.cpp
@@ -134,7 +134,6 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_
m_tfi(0),
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),
@@ -153,12 +152,22 @@ gprs_rlcmac_tbf::gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_
memset(&m_trx_list, 0, sizeof(m_trx_list));
m_trx_list.entry = this;
+ state_fsm.tbf = this;
+ state_fsm.fi = osmo_fsm_inst_alloc(&tbf_fsm, this, &state_fsm, LOGL_INFO, NULL);
+
m_rlc.init();
m_llc.init();
m_name_buf[0] = '\0';
}
+
+gprs_rlcmac_tbf::~gprs_rlcmac_tbf()
+{
+ osmo_fsm_inst_free(state_fsm.fi);
+ state_fsm.fi = NULL;
+}
+
uint32_t gprs_rlcmac_tbf::tlli() const
{
return m_ms ? ms_tlli(m_ms) : GSM_RESERVED_TMSI;
@@ -264,7 +273,7 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
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);
@@ -276,7 +285,7 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
rate_ctr_group_free(dl_tbf->m_dl_gprs_ctrs);
}
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);
}
@@ -353,15 +362,6 @@ int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
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) {
@@ -636,10 +636,10 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
}
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);
+ TBF_SET_STATE(ul_tbf, TBF_ST_RELEASING);
T_START(ul_tbf, T3169, 3169, "MAX N3103 reached", false);
return;
}
@@ -658,7 +658,7 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT);
bts_do_rate_ctr_inc(bts, CTR_PUA_POLL_TIMEDOUT);
if (n_inc(N3105)) {
- TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING);
+ TBF_SET_STATE(this, TBF_ST_RELEASING);
T_START(this, T3195, 3195, "MAX N3105 reached", true);
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_FAILED);
bts_do_rate_ctr_inc(bts, CTR_PUA_POLL_FAILED);
@@ -677,7 +677,7 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_TIMEDOUT);
bts_do_rate_ctr_inc(bts, CTR_PDA_POLL_TIMEDOUT);
if (n_inc(N3105)) {
- TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING);
+ TBF_SET_STATE(this, TBF_ST_RELEASING);
T_START(this, T3195, 3195, "MAX N3105 reached", true);
bts_do_rate_ctr_inc(bts, CTR_RLC_ASS_FAILED);
bts_do_rate_ctr_inc(bts, CTR_PDA_POLL_FAILED);
@@ -700,7 +700,7 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK);
}
- 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);
@@ -708,7 +708,7 @@ void gprs_rlcmac_tbf::poll_timeout(struct gprs_rlcmac_pdch *pdch, uint32_t poll_
}
if (dl_tbf->n_inc(N3105)) {
- TBF_SET_STATE(dl_tbf, GPRS_RLCMAC_RELEASING);
+ TBF_SET_STATE(dl_tbf, TBF_ST_RELEASING);
T_START(dl_tbf, T3195, 3195, "MAX N3105 reached", true);
bts_do_rate_ctr_inc(bts, CTR_PDAN_POLL_FAILED);
bts_do_rate_ctr_inc(bts, CTR_RLC_ACK_FAILED);
@@ -768,6 +768,8 @@ int gprs_rlcmac_tbf::setup(int8_t use_trx, bool single_slot)
return -1;
}
+ tbf_update_state_fsm_name(this);
+
ms_attach_tbf(m_ms, this);
return 0;
@@ -787,7 +789,7 @@ void gprs_rlcmac_tbf::handle_timeout()
/* PACCH assignment timeout (see timers X2000, X2001) */
if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) {
- if (state_is(GPRS_RLCMAC_ASSIGN)) {
+ if (state_is(TBF_ST_ASSIGN)) {
LOGPTBF(this, LOGL_NOTICE, "releasing due to PACCH assignment timeout.\n");
tbf_free(this);
return;
@@ -799,13 +801,13 @@ void gprs_rlcmac_tbf::handle_timeout()
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)) {
+ if (dl_tbf->state_is(TBF_ST_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);
+ TBF_SET_STATE(dl_tbf, TBF_ST_FLOW);
return;
}
@@ -940,7 +942,7 @@ struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts)
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_SET_STATE(new_dl_tbf, TBF_ST_FLOW);
tbf_assign_control_ts(new_dl_tbf);
/* stop pending assignment timer */
new_dl_tbf->t_stop(T0, "assignment (DL-TBF)");
@@ -1090,6 +1092,13 @@ const char *gprs_rlcmac_tbf::name() const
return m_name_buf;
}
+void tbf_update_state_fsm_name(struct gprs_rlcmac_tbf *tbf)
+{
+ osmo_fsm_inst_update_id_f_sanitize(tbf->state_fsm.fi, '_', "%s-TFI_%d",
+ tbf_direction(tbf) == GPRS_RLCMAC_UL_TBF ? "UL" : "DL",
+ tbf_tfi(tbf));
+}
+
void gprs_rlcmac_tbf::rotate_in_list()
{
llist_del(tbf_trx_list((struct gprs_rlcmac_tbf *)this));
@@ -1146,9 +1155,9 @@ bool gprs_rlcmac_tbf::is_control_ts(uint8_t ts) const
}
/* 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 tbf->state;
+ return (enum tbf_fsm_states)tbf->state_fsm.fi->state;
}
enum gprs_rlcmac_tbf_direction tbf_direction(const struct gprs_rlcmac_tbf *tbf)
diff --git a/src/tbf.h b/src/tbf.h
index 1bca82c0..d9fdaacc 100644
--- a/src/tbf.h
+++ b/src/tbf.h
@@ -47,6 +47,7 @@ extern "C" {
#include "coding_scheme.h"
#include <pdch_ul_controller.h>
+#include <tbf_fsm.h>
#ifdef __cplusplus
}
#endif
@@ -55,15 +56,6 @@ extern "C" {
* TBF instance
*/
-enum gprs_rlcmac_tbf_state {
- GPRS_RLCMAC_NULL = 0, /* new created TBF */
- GPRS_RLCMAC_ASSIGN, /* wait for downlink assignment */
- GPRS_RLCMAC_FLOW, /* RLC/MAC flow, resource needed */
- GPRS_RLCMAC_FINISHED, /* flow finished, wait for release */
- GPRS_RLCMAC_WAIT_RELEASE,/* wait for release or restart of DL TBF */
- GPRS_RLCMAC_RELEASING, /* releasing, wait to free TBI/USF */
-};
-
enum gprs_rlcmac_tbf_dl_ass_state {
GPRS_RLCMAC_DL_ASS_NONE = 0,
GPRS_RLCMAC_DL_ASS_SEND_ASS, /* send downlink assignment on next RTS */
@@ -166,7 +158,7 @@ enum tbf_counters { /* TBF counters from 3GPP TS 44.060 ยง13.4 */
#define T_START(tbf, t, T, r, f) tbf->t_start(t, T, r, f, __FILE__, __LINE__)
-#define TBF_SET_STATE(t, st) do { t->set_state(st, __FILE__, __LINE__); } while(0)
+#define TBF_SET_STATE(t, st) do { tbf_fsm_state_chg(t->state_fsm.fi, st); } while(0)
#define TBF_SET_ASS_STATE_DL(t, st) do { t->set_ass_state_dl(st, __FILE__, __LINE__); } while(0)
#define TBF_SET_ASS_STATE_UL(t, st) do { t->set_ass_state_ul(st, __FILE__, __LINE__); } while(0)
#define TBF_SET_ACK_STATE(t, st) do { t->set_ack_state(st, __FILE__, __LINE__); } while(0)
@@ -179,7 +171,7 @@ extern "C" {
#endif
struct gprs_rlcmac_tbf;
const char *tbf_name(const struct gprs_rlcmac_tbf *tbf);
-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);
enum gprs_rlcmac_tbf_direction tbf_direction(const struct gprs_rlcmac_tbf *tbf);
void tbf_set_ms(struct gprs_rlcmac_tbf *tbf, struct GprsMs *ms);
struct llist_head *tbf_ms_list(struct gprs_rlcmac_tbf *tbf);
@@ -197,6 +189,7 @@ int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf);
int tbf_check_polling(const struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts, uint32_t *poll_fn, unsigned int *rrbp);
void tbf_set_polling(struct gprs_rlcmac_tbf *tbf, uint32_t new_poll_fn, uint8_t ts, enum pdch_ulc_tbf_poll_reason t);
void tbf_poll_timeout(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_pdch *pdch, uint32_t poll_fn, enum pdch_ulc_tbf_poll_reason reason);
+void tbf_update_state_fsm_name(struct gprs_rlcmac_tbf *tbf);
#ifdef __cplusplus
}
#endif
@@ -205,17 +198,16 @@ void tbf_poll_timeout(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_pdch *pdch
struct gprs_rlcmac_tbf {
gprs_rlcmac_tbf(struct gprs_rlcmac_bts *bts_, GprsMs *ms, gprs_rlcmac_tbf_direction dir);
- virtual ~gprs_rlcmac_tbf() {}
+ virtual ~gprs_rlcmac_tbf();
virtual gprs_rlc_window *window() = 0;
int setup(int8_t use_trx, bool single_slot);
- bool state_is(enum gprs_rlcmac_tbf_state rhs) const;
- bool state_is_not(enum gprs_rlcmac_tbf_state rhs) const;
+ bool state_is(enum tbf_fsm_states rhs) const;
+ bool state_is_not(enum tbf_fsm_states rhs) const;
bool dl_ass_state_is(enum gprs_rlcmac_tbf_dl_ass_state rhs) const;
bool ul_ass_state_is(enum gprs_rlcmac_tbf_ul_ass_state rhs) const;
bool ul_ack_state_is(enum gprs_rlcmac_tbf_ul_ack_state rhs) const;
- void set_state(enum gprs_rlcmac_tbf_state new_state, const char *file, int line);
void set_ass_state_dl(enum gprs_rlcmac_tbf_dl_ass_state new_state, const char *file, int line);
void set_ass_state_ul(enum gprs_rlcmac_tbf_ul_ass_state new_state, const char *file, int line);
void set_ack_state(enum gprs_rlcmac_tbf_ul_ack_state new_state, const char *file, int line);
@@ -325,7 +317,7 @@ struct gprs_rlcmac_tbf {
time_t m_created_ts;
struct rate_ctr_group *m_ctrs;
- enum gprs_rlcmac_tbf_state state;
+ struct tbf_fsm_ctx state_fsm;
struct llist_item m_ms_list;
struct llist_item m_trx_list;
@@ -335,8 +327,6 @@ protected:
gprs_llc_queue *llc_queue();
const gprs_llc_queue *llc_queue() const;
- static const char *tbf_state_name[6];
-
struct GprsMs *m_ms;
private:
void enable_egprs();
@@ -349,9 +339,9 @@ private:
mutable char m_name_buf[60];
};
-inline bool gprs_rlcmac_tbf::state_is(enum gprs_rlcmac_tbf_state rhs) const
+inline bool gprs_rlcmac_tbf::state_is(enum tbf_fsm_states rhs) const
{
- return state == rhs;
+ return tbf_state(this) == rhs;
}
inline bool gprs_rlcmac_tbf::dl_ass_state_is(enum gprs_rlcmac_tbf_dl_ass_state rhs) const
@@ -369,20 +359,21 @@ inline bool gprs_rlcmac_tbf::ul_ack_state_is(enum gprs_rlcmac_tbf_ul_ack_state r
return ul_ack_state == rhs;
}
-inline bool gprs_rlcmac_tbf::state_is_not(enum gprs_rlcmac_tbf_state rhs) const
+inline bool gprs_rlcmac_tbf::state_is_not(enum tbf_fsm_states rhs) const
{
- return state != rhs;
+ return tbf_state(this) != rhs;
}
+
inline const char *gprs_rlcmac_tbf::state_name() const
{
- return tbf_state_name[state];
+ return osmo_fsm_inst_state_name(state_fsm.fi);
}
/* Set assignment state and corrsponding flags */
inline void gprs_rlcmac_tbf::set_assigned_on(uint8_t state_flag, bool check_ccch, const char *file, int line)
{
- set_state(GPRS_RLCMAC_ASSIGN, file, line);
+ tbf_fsm_state_chg(state_fsm.fi, TBF_ST_ASSIGN);
if (check_ccch) {
if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)))
ass_type_mod(state_flag, false, file, line);
@@ -436,14 +427,6 @@ inline void gprs_rlcmac_tbf::ass_type_mod(uint8_t t, bool unset, const char *fil
state_flags |= (1 << t);
}
-inline void gprs_rlcmac_tbf::set_state(enum gprs_rlcmac_tbf_state new_state, const char *file, int line)
-{
- LOGPSRC(DTBF, LOGL_DEBUG, file, line, "%s changes state from %s to %s\n",
- tbf_name(this),
- tbf_state_name[state], tbf_state_name[new_state]);
- state = new_state;
-}
-
inline void gprs_rlcmac_tbf::set_ass_state_dl(enum gprs_rlcmac_tbf_dl_ass_state new_state, const char *file, int line)
{
LOGPSRC(DTBF, LOGL_DEBUG, file, line, "%s changes DL ASS state from %s to %s\n",
@@ -495,9 +478,9 @@ inline bool gprs_rlcmac_tbf::is_tfi_assigned() const
{
/* The TBF is established or has been assigned by a IMM.ASS for
* download */
- return state > GPRS_RLCMAC_ASSIGN ||
+ return state_fsm.fi->state > TBF_ST_ASSIGN ||
(direction == GPRS_RLCMAC_DL_TBF &&
- state == GPRS_RLCMAC_ASSIGN &&
+ state_fsm.fi->state == TBF_ST_ASSIGN &&
(state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)));
}
diff --git a/src/tbf_dl.cpp b/src/tbf_dl.cpp
index 45856e8a..9ed389d2 100644
--- a/src/tbf_dl.cpp
+++ b/src/tbf_dl.cpp
@@ -98,7 +98,7 @@ static void llc_timer_cb(void *_tbf)
{
struct gprs_rlcmac_dl_tbf *tbf = (struct gprs_rlcmac_dl_tbf *)_tbf;
- if (tbf->state_is_not(GPRS_RLCMAC_FLOW))
+ if (tbf->state_is_not(TBF_ST_FLOW))
return;
LOGPTBFDL(tbf, LOGL_DEBUG, "LLC receive timeout, requesting DL ACK\n");
@@ -221,7 +221,7 @@ int gprs_rlcmac_dl_tbf::append_data(uint16_t pdu_delay_csec,
llc_queue()->enqueue(llc_msg, &expire_time);
start_llc_timer();
- if (state_is(GPRS_RLCMAC_WAIT_RELEASE)) {
+ if (state_is(TBF_ST_WAIT_RELEASE)) {
LOGPTBFDL(this, LOGL_DEBUG, "in WAIT RELEASE state (T3193), so reuse TBF\n");
establish_dl_tbf_on_pacch();
}
@@ -510,7 +510,7 @@ int gprs_rlcmac_dl_tbf::take_next_bsn(uint32_t fn,
/* re-send block with negative aknowlegement */
m_window.m_v_b.mark_unacked(bsn);
bts_do_rate_ctr_inc(bts, CTR_RLC_RESENT);
- } else if (state_is(GPRS_RLCMAC_FINISHED)) {
+ } else if (state_is(TBF_ST_FINISHED)) {
/* If the TBF is in finished, we already sent all packages at least once.
* If any packages could have been sent (because of unacked) it should have
* been catched up by the upper if(bsn >= 0) */
@@ -602,7 +602,7 @@ void gprs_rlcmac_dl_tbf::trigger_ass(struct gprs_rlcmac_tbf *old_tbf)
if (old_tbf) {
LOGPTBFDL(this, LOGL_DEBUG, "Send dowlink assignment on PACCH, because %s exists\n", old_tbf->name());
TBF_SET_ASS_STATE_DL(old_tbf, GPRS_RLCMAC_DL_ASS_SEND_ASS);
- old_tbf->was_releasing = old_tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE);
+ old_tbf->was_releasing = old_tbf->state_is(TBF_ST_WAIT_RELEASE);
/* change state */
TBF_SET_ASS_ON(this, GPRS_RLCMAC_FLAG_PACCH, true);
@@ -612,7 +612,7 @@ void gprs_rlcmac_dl_tbf::trigger_ass(struct gprs_rlcmac_tbf *old_tbf)
} else {
LOGPTBFDL(this, LOGL_DEBUG, "Send dowlink assignment on PCH, no TBF exist (IMSI=%s)\n",
imsi());
- was_releasing = state_is(GPRS_RLCMAC_WAIT_RELEASE);
+ was_releasing = state_is(TBF_ST_WAIT_RELEASE);
/* change state */
TBF_SET_ASS_ON(this, GPRS_RLCMAC_FLAG_CCCH, false);
@@ -711,7 +711,7 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, enum CodingScheme cs)
is_final = llc_queue_size(llc_queue()) == 0 && !keep_open(fn);
if (is_final) {
rdbi->cv = 0;
- TBF_SET_STATE(this, GPRS_RLCMAC_FINISHED);
+ TBF_SET_STATE(this, TBF_ST_FINISHED);
}
if (mcs_is_edge(cs)) {
@@ -756,7 +756,7 @@ int gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, enum CodingScheme cs)
if (is_final) {
request_dl_ack();
- TBF_SET_STATE(this, GPRS_RLCMAC_FINISHED);
+ TBF_SET_STATE(this, TBF_ST_FINISHED);
}
/* dequeue next LLC frame, if any */
@@ -1211,7 +1211,7 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
"V(B): (V(A)=%d)\"%s\"(V(S)-1=%d) A=Acked N=Nacked U=Unacked X=Resend-Unacked I=Invalid\n",
m_window.v_a(), show_v_b, m_window.v_s_mod(-1));
- if (state_is(GPRS_RLCMAC_FINISHED) && m_window.window_empty()) {
+ if (state_is(TBF_ST_FINISHED) && m_window.window_empty()) {
LOGPTBFDL(this, LOGL_NOTICE,
"Received acknowledge of all blocks, but without final ack inidcation (don't worry)\n");
}
@@ -1241,7 +1241,7 @@ int gprs_rlcmac_dl_tbf::release()
/* report all outstanding packets as received */
gprs_rlcmac_received_lost(this, received, 0);
- TBF_SET_STATE(this, GPRS_RLCMAC_WAIT_RELEASE);
+ TBF_SET_STATE(this, TBF_ST_WAIT_RELEASE);
/* start T3193 */
T_START(this, T3193, 3193, "release (DL-TBF)", true);
@@ -1260,7 +1260,7 @@ int gprs_rlcmac_dl_tbf::abort()
{
uint16_t lost;
- if (state_is(GPRS_RLCMAC_FLOW)) {
+ if (state_is(TBF_ST_FLOW)) {
/* range V(A)..V(S)-1 */
lost = m_window.count_unacked();
@@ -1272,7 +1272,7 @@ int gprs_rlcmac_dl_tbf::abort()
* (partly) encoded in chunk 1 of block V(A). (optional) */
}
- TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING);
+ TBF_SET_STATE(this, TBF_ST_RELEASING);
/* reset rlc states */
m_window.reset();
@@ -1293,7 +1293,7 @@ int gprs_rlcmac_dl_tbf::rcvd_dl_ack(bool final_ack, unsigned first_bsn,
if (final_ack) {
LOGPTBFDL(this, LOGL_DEBUG, "Final ACK received.\n");
rc = maybe_start_new_window();
- } else if (state_is(GPRS_RLCMAC_FINISHED) && m_window.window_empty()) {
+ } else if (state_is(TBF_ST_FINISHED) && m_window.window_empty()) {
LOGPTBFDL(this, LOGL_NOTICE,
"Received acknowledge of all blocks, but without final ack indication (don't worry)\n");
}
diff --git a/src/tbf_fsm.c b/src/tbf_fsm.c
new file mode 100644
index 00000000..3bf701a4
--- /dev/null
+++ b/src/tbf_fsm.c
@@ -0,0 +1,137 @@
+/* tbf_fsm.c
+ *
+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * 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 <unistd.h>
+
+#include <talloc.h>
+
+#include <tbf_fsm.h>
+#include <gprs_rlcmac.h>
+#include <gprs_debug.h>
+#include <gprs_ms.h>
+#include <encoding.h>
+#include <bts.h>
+
+#define X(s) (1 << (s))
+
+const struct osmo_tdef_state_timeout tbf_fsm_timeouts[32] = {
+ [TBF_ST_NULL] = {},
+ [TBF_ST_ASSIGN] = { },
+ [TBF_ST_FLOW] = { },
+ [TBF_ST_FINISHED] = {},
+ [TBF_ST_WAIT_RELEASE] = {},
+ [TBF_ST_RELEASING] = {},
+};
+
+const struct value_string tbf_fsm_event_names[] = {
+ { TBF_EV_FOOBAR, "FOOBAR" },
+ { 0, NULL }
+};
+
+static void tbf_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ /* TODO: needed ?
+ * struct tbf_fsm_ctx *ctx = (struct tbf_fsm_ctx *)fi->priv;
+ */
+}
+
+static int tbf_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ switch (fi->T) {
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct osmo_fsm_state tbf_fsm_states[] = {
+ [TBF_ST_NULL] = {
+ .in_event_mask =
+ 0,
+ .out_state_mask =
+ X(TBF_ST_ASSIGN) |
+ X(TBF_ST_FLOW) |
+ X(TBF_ST_RELEASING),
+ .name = "NULL",
+ //.action = st_null,
+ },
+ [TBF_ST_ASSIGN] = {
+ .in_event_mask =
+ 0,
+ .out_state_mask =
+ X(TBF_ST_FLOW) |
+ X(TBF_ST_FINISHED) |
+ X(TBF_ST_RELEASING),
+ .name = "ASSIGN",
+ //.onenter = st_assign_on_enter,
+ //.action = st_assign,
+ },
+ [TBF_ST_FLOW] = {
+ .in_event_mask =
+ 0,
+ .out_state_mask =
+ X(TBF_ST_FINISHED) |
+ X(TBF_ST_WAIT_RELEASE) |
+ X(TBF_ST_RELEASING),
+ .name = "FLOW",
+ //.onenter = st_flow_on_enter,
+ //.action = st_flow,
+ },
+ [TBF_ST_FINISHED] = {
+ .in_event_mask =
+ 0,
+ .out_state_mask =
+ X(TBF_ST_WAIT_RELEASE),
+ .name = "FINISHED",
+ //.onenter = st_finished_on_enter,
+ //.action = st_finished,
+ },
+ [TBF_ST_WAIT_RELEASE] = {
+ .in_event_mask =
+ 0,
+ .out_state_mask =
+ X(TBF_ST_RELEASING),
+ .name = "WAIT_RELEASE",
+ //.action = st_wait_release,
+ },
+ [TBF_ST_RELEASING] = {
+ .in_event_mask =
+ 0,
+ .out_state_mask =
+ 0,
+ .name = "RELEASING",
+ //.action = st_releasing,
+ },
+};
+
+struct osmo_fsm tbf_fsm = {
+ .name = "TBF",
+ .states = tbf_fsm_states,
+ .num_states = ARRAY_SIZE(tbf_fsm_states),
+ .timer_cb = tbf_fsm_timer_cb,
+ .cleanup = tbf_fsm_cleanup,
+ .log_subsys = DTBF,
+ .event_names = tbf_fsm_event_names,
+};
+
+static __attribute__((constructor)) void tbf_fsm_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&tbf_fsm) == 0);
+}
diff --git a/src/tbf_fsm.h b/src/tbf_fsm.h
new file mode 100644
index 00000000..84bb4373
--- /dev/null
+++ b/src/tbf_fsm.h
@@ -0,0 +1,57 @@
+/* tbf_fsm.h
+ *
+ * Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * 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.
+ */
+#pragma once
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+
+#include <gprs_pcu.h>
+
+struct gprs_rlcmac_tbf;
+
+enum tbf_fsm_event {
+ TBF_EV_FOOBAR,
+};
+
+enum tbf_fsm_states {
+ TBF_ST_NULL = 0, /* new created TBF */
+ TBF_ST_ASSIGN, /* wait for downlink assignment */
+ TBF_ST_FLOW, /* RLC/MAC flow, resource needed */
+ TBF_ST_FINISHED, /* flow finished, wait for release */
+ TBF_ST_WAIT_RELEASE,/* wait for release or restart of DL TBF */
+ TBF_ST_RELEASING, /* releasing, wait to free TBI/USF */
+};
+
+struct tbf_fsm_ctx {
+ struct osmo_fsm_inst *fi;
+ struct gprs_rlcmac_tbf* tbf; /* back pointer */
+};
+
+extern const struct osmo_tdef_state_timeout tbf_fsm_timeouts[32];
+/* Transition to a state, using the T timer defined in assignment_fsm_timeouts.
+ * The actual timeout value is in turn obtained from conn->T_defs.
+ * Assumes local variable fi exists. */
+#define tbf_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, \
+ tbf_fsm_timeouts, \
+ the_pcu->T_defs, \
+ -1)
+
+extern struct osmo_fsm tbf_fsm;
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 44506843..9cbb9fb7 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -171,7 +171,7 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_ccch(struct gprs_rlcmac_bts *bts, struct
/* Caller will most probably send a Imm Ass Reject after return */
return NULL;
}
- TBF_SET_STATE(tbf, GPRS_RLCMAC_FLOW);
+ TBF_SET_STATE(tbf, TBF_ST_FLOW);
TBF_ASS_TYPE_SET(tbf, GPRS_RLCMAC_FLAG_CCCH);
tbf->contention_resolution_start();
OSMO_ASSERT(tbf->ms());
@@ -334,7 +334,7 @@ void gprs_rlcmac_ul_tbf::contention_resolution_success()
struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn, uint8_t ts)
{
- int final = (state_is(GPRS_RLCMAC_FINISHED));
+ int final = (state_is(TBF_ST_FINISHED));
struct msgb *msg;
int rc;
unsigned int rrbp = 0;
@@ -527,7 +527,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
rdbi = &block->block_info;
/* Check if we already received all data TBF had to send: */
- if (this->state_is(GPRS_RLCMAC_FLOW) /* still in flow state */
+ if (this->state_is(TBF_ST_FLOW) /* still in flow state */
&& this->m_window.v_q() == this->m_window.v_r() /* if complete */
&& block->len) { /* if there was ever a last block received */
LOGPTBFUL(this, LOGL_DEBUG,
@@ -535,7 +535,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
rdbi->bsn, rdbi->cv);
if (rdbi->cv == 0) {
LOGPTBFUL(this, LOGL_DEBUG, "Finished with UL TBF\n");
- TBF_SET_STATE(this, GPRS_RLCMAC_FINISHED);
+ TBF_SET_STATE(this, TBF_ST_FINISHED);
/* Reset N3103 counter. */
this->n_reset(N3103);
}
@@ -567,10 +567,10 @@ void gprs_rlcmac_ul_tbf::maybe_schedule_uplink_acknack(
}
if (countdown_finished) {
require_ack = true;
- if (state_is(GPRS_RLCMAC_FLOW))
+ if (state_is(TBF_ST_FLOW))
LOGPTBFUL(this, LOGL_DEBUG,
"Scheduling Ack/Nack, because some data is missing and last block has CV==0.\n");
- else if (state_is(GPRS_RLCMAC_FINISHED))
+ else if (state_is(TBF_ST_FINISHED))
LOGPTBFUL(this, LOGL_DEBUG,
"Scheduling final Ack/Nack, because all data was received and last block has CV==0.\n");
}
@@ -816,7 +816,7 @@ gprs_rlc_window *gprs_rlcmac_ul_tbf::window()
void gprs_rlcmac_ul_tbf::usf_timeout()
{
if (n_inc(N3101)) {
- TBF_SET_STATE(this, GPRS_RLCMAC_RELEASING);
+ TBF_SET_STATE(this, TBF_ST_RELEASING);
T_START(this, T3169, 3169, "MAX N3101 reached", false);
return;
}