aboutsummaryrefslogtreecommitdiffstats
path: root/src/sgsn/gprs_mm_state_gb_fsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sgsn/gprs_mm_state_gb_fsm.c')
-rw-r--r--src/sgsn/gprs_mm_state_gb_fsm.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/sgsn/gprs_mm_state_gb_fsm.c b/src/sgsn/gprs_mm_state_gb_fsm.c
new file mode 100644
index 000000000..2056540db
--- /dev/null
+++ b/src/sgsn/gprs_mm_state_gb_fsm.c
@@ -0,0 +1,112 @@
+#include <osmocom/core/tdef.h>
+
+#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
+
+#include <osmocom/sgsn/debug.h>
+#include <osmocom/sgsn/sgsn.h>
+
+#define X(s) (1 << (s))
+
+static const struct osmo_tdef_state_timeout mm_state_gb_fsm_timeouts[32] = {
+ [ST_MM_IDLE] = { },
+ [ST_MM_READY] = { .T=3314 },
+ [ST_MM_STANDBY] = { },
+};
+
+#define mm_state_gb_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, mm_state_gb_fsm_timeouts, sgsn->cfg.T_defs, -1)
+
+static void st_mm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch(event) {
+ case E_MM_GPRS_ATTACH:
+ mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
+ break;
+ case E_MM_PDU_RECEPTION:
+ break;
+ }
+}
+
+static void st_mm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ unsigned long t_secs;
+
+ switch(event) {
+ case E_MM_READY_TIMER_EXPIRY:
+ case E_MM_IMPLICIT_DETACH:
+ mm_state_gb_fsm_state_chg(fi, ST_MM_STANDBY);
+ break;
+ case E_MM_PDU_RECEPTION:
+ /* RE-arm the READY timer upon receival of Gb PDUs */
+ t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3314, OSMO_TDEF_S, -1);
+ osmo_timer_schedule(&fi->timer, t_secs, 0);
+ break;
+ case E_MM_RA_UPDATE:
+ break;
+ }
+}
+
+static void st_mm_standby(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch(event) {
+ case E_MM_PDU_RECEPTION:
+ mm_state_gb_fsm_state_chg(fi, ST_MM_READY);
+ break;
+ }
+}
+
+static struct osmo_fsm_state mm_state_gb_fsm_states[] = {
+ [ST_MM_IDLE] = {
+ .in_event_mask = X(E_MM_GPRS_ATTACH) | X(E_MM_PDU_RECEPTION),
+ .out_state_mask = X(ST_MM_READY),
+ .name = "Idle",
+ .action = st_mm_idle,
+ },
+ [ST_MM_READY] = {
+ .in_event_mask = X(E_MM_READY_TIMER_EXPIRY) | X(E_MM_RA_UPDATE) | X(E_MM_IMPLICIT_DETACH) | X(E_MM_PDU_RECEPTION),
+ .out_state_mask = X(ST_MM_IDLE) | X(ST_MM_STANDBY),
+ .name = "Ready",
+ .action = st_mm_ready,
+ },
+ [ST_MM_STANDBY] = {
+ .in_event_mask = X(E_MM_PDU_RECEPTION),
+ .out_state_mask = X(ST_MM_IDLE) | X(ST_MM_READY),
+ .name = "Standby",
+ .action = st_mm_standby,
+ },
+};
+
+const struct value_string mm_state_gb_fsm_event_names[] = {
+ OSMO_VALUE_STRING(E_MM_GPRS_ATTACH),
+ OSMO_VALUE_STRING(E_MM_PDU_RECEPTION),
+ OSMO_VALUE_STRING(E_MM_IMPLICIT_DETACH),
+ OSMO_VALUE_STRING(E_MM_READY_TIMER_EXPIRY),
+ OSMO_VALUE_STRING(E_MM_RA_UPDATE),
+ { 0, NULL }
+};
+
+int mm_state_gb_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ switch(fi->state) {
+ case ST_MM_READY:
+ /* timer for mm state. state=READY: T3314 (aka TS 23.060 "READY timer") */
+ osmo_fsm_inst_dispatch(fi, E_MM_READY_TIMER_EXPIRY, NULL);
+ break;
+ }
+
+ return 0;
+}
+
+struct osmo_fsm mm_state_gb_fsm = {
+ .name = "MM_STATE_Gb",
+ .states = mm_state_gb_fsm_states,
+ .num_states = ARRAY_SIZE(mm_state_gb_fsm_states),
+ .event_names = mm_state_gb_fsm_event_names,
+ .log_subsys = DMM,
+ .timer_cb = mm_state_gb_fsm_timer_cb,
+};
+
+static __attribute__((constructor)) void mm_state_gb_fsm_init(void)
+{
+ osmo_fsm_register(&mm_state_gb_fsm);
+}