aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs
diff options
context:
space:
mode:
Diffstat (limited to 'src/gprs')
-rw-r--r--src/gprs/Makefile.am1
-rw-r--r--src/gprs/gprs_gb.c20
-rw-r--r--src/gprs/gprs_gmm.c93
-rw-r--r--src/gprs/gprs_mm_state_gb_fsm.c112
-rw-r--r--src/gprs/gprs_sgsn.c12
5 files changed, 125 insertions, 113 deletions
diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am
index 85ba9065b..94861e297 100644
--- a/src/gprs/Makefile.am
+++ b/src/gprs/Makefile.am
@@ -63,6 +63,7 @@ osmo_sgsn_SOURCES = \
gprs_gb.c \
gprs_gmm_attach.c \
gprs_gmm.c \
+ gprs_mm_state_gb_fsm.c \
gprs_ranap.c \
gprs_sgsn.c \
gprs_sndcp.c \
diff --git a/src/gprs/gprs_gb.c b/src/gprs/gprs_gb.c
index 43af4347e..65342cf22 100644
--- a/src/gprs/gprs_gb.c
+++ b/src/gprs/gprs_gb.c
@@ -28,25 +28,11 @@
#include "bscconfig.h"
+#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
#include <osmocom/sgsn/gprs_sgsn.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/debug.h>
-/* Update the MM context state */
-static void gsm0408_gprs_notify_pdu_gb(struct sgsn_mm_ctx *mmctx)
-{
- switch (mmctx->gb.mm_state) {
- case MM_STANDBY:
- mmctx_set_mm_state(mmctx, MM_READY);
- break;
- case MM_READY: /* RE-arm the timer upon receival of Gb PDUs */
- mmctx_state_timer_start(mmctx, 3314);
- break;
- default:
- break;
- }
-}
-
/* Main entry point for incoming 04.08 GPRS messages from Gb */
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bool drop_cipherable)
@@ -63,13 +49,11 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
msgid2mmctx(mmctx, msg);
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
mmctx->gb.llme = llme;
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_PDU_RECEPTION, NULL);
}
/* MMCTX can be NULL */
- if (mmctx)
- gsm0408_gprs_notify_pdu_gb(mmctx);
-
switch (pdisc) {
case GSM48_PDISC_MM_GPRS:
rc = gsm0408_rcv_gmm(mmctx, msg, llme, drop_cipherable);
diff --git a/src/gprs/gprs_gmm.c b/src/gprs/gprs_gmm.c
index b28a4a13c..81f42737e 100644
--- a/src/gprs/gprs_gmm.c
+++ b/src/gprs/gprs_gmm.c
@@ -55,6 +55,7 @@
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
+#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_ranap.h>
@@ -102,13 +103,6 @@ static const struct tlv_definition gsm48_sm_att_tlvdef = {
},
};
-static const struct value_string gprs_mm_state_gb_names[] = {
- OSMO_VALUE_STRING(MM_IDLE),
- OSMO_VALUE_STRING(MM_READY),
- OSMO_VALUE_STRING(MM_STANDBY),
- { 0, NULL }
-};
-
static const struct value_string gprs_mm_state_iu_names[] = {
OSMO_VALUE_STRING(PMM_DETACHED),
OSMO_VALUE_STRING(PMM_CONNECTED),
@@ -130,56 +124,6 @@ static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx)
}
}
-static void mmctx_state_timer_cb(void *_mm)
-{
- struct sgsn_mm_ctx *mm = _mm;
-
- switch (mm->gb.state_T) {
- case 3314:
- switch (mm->gb.mm_state) {
- case MM_READY:
- LOGMMCTXP(LOGL_INFO, mm, "T3314 expired\n");
- mmctx_set_mm_state(mm, MM_STANDBY);
- break;
- default:
- LOGMMCTXP(LOGL_ERROR, mm, "T3314 expired in state %s != MM_READY\n",
- get_value_string(gprs_mm_state_gb_names, mm->gb.mm_state));
- break;
- }
- break;
- default:
- LOGMMCTXP(LOGL_ERROR, mm, "state timer expired in unknown mode %u\n",
- mm->gb.state_T);
- break;
- }
-}
-
-void mmctx_state_timer_start(struct sgsn_mm_ctx *mm, unsigned int T)
-{
- unsigned long seconds;
-
- if (mm->gb.state_T && mm->gb.state_T != T)
- LOGMMCTXP(LOGL_ERROR, mm, "Attempting to start timer %u but %u is active!\n",
- T, mm->gb.state_T);
-
- mm->gb.state_T = T;
- mm->gb.state_timer.data = mm;
- mm->gb.state_timer.cb = &mmctx_state_timer_cb;
-
- seconds = osmo_tdef_get(sgsn->cfg.T_defs, T, OSMO_TDEF_S, -1);
- osmo_timer_schedule(&mm->gb.state_timer, seconds, 0);
-}
-
-static void mmctx_state_timer_stop(struct sgsn_mm_ctx *mm, unsigned int T)
-{
- if (mm->gb.state_T == T)
- osmo_timer_del(&mm->gb.state_timer);
- else
- LOGMMCTXP(LOGL_ERROR, mm, "Attempting to stop timer %u but %u is active!\n",
- T, mm->gb.state_T);
- mm->gb.state_T = 0;
-}
-
void mmctx_set_pmm_state(struct sgsn_mm_ctx *ctx, enum gprs_mm_state_iu state)
{
OSMO_ASSERT(ctx->ran_type == MM_CTX_T_UTRAN_Iu);
@@ -205,35 +149,6 @@ void mmctx_set_pmm_state(struct sgsn_mm_ctx *ctx, enum gprs_mm_state_iu state)
ctx->iu.mm_state = state;
}
-void mmctx_set_mm_state(struct sgsn_mm_ctx *ctx, enum gprs_mm_state_gb state)
-{
- OSMO_ASSERT(ctx->ran_type == MM_CTX_T_GERAN_Gb);
-
- if (ctx->gb.mm_state == state)
- return;
-
- LOGMMCTXP(LOGL_INFO, ctx, "Changing MM state from %s to %s\n",
- get_value_string(gprs_mm_state_gb_names, ctx->gb.mm_state),
- get_value_string(gprs_mm_state_gb_names, state));
-
- switch (state) {
- case MM_READY:
- /* on expiration, T3314 moves mm state back to MM_STANDBY */
- mmctx_state_timer_start(ctx, 3314);
- break;
- case MM_IDLE:
- if (ctx->gb.mm_state == MM_READY)
- mmctx_state_timer_stop(ctx, 3314);
- break;
- case MM_STANDBY:
- if (ctx->gb.mm_state == MM_READY)
- mmctx_state_timer_stop(ctx, 3314);
- break;
- }
-
- ctx->gb.mm_state = state;
-}
-
/* Our implementation, should be kept in SGSN */
static void mmctx_timer_cb(void *_mm);
@@ -348,7 +263,7 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
mmctx_set_pmm_state(ctx, PMM_DETACHED);
break;
case MM_CTX_T_GERAN_Gb:
- mmctx_set_mm_state(ctx, MM_IDLE);
+ osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
break;
}
@@ -2107,7 +2022,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
gprs_llme_copy_key(mmctx, mmctx->gb.llme);
gprs_llgmm_assign(mmctx->gb.llme, TLLI_UNASSIGNED,
mmctx->gb.tlli_new);
- mmctx_set_mm_state(mmctx, MM_READY);
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_ATTACH, NULL);
break;
}
rc = 0;
@@ -2136,7 +2051,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->gb.tlli = mmctx->gb.tlli_new;
gprs_llgmm_assign(mmctx->gb.llme, TLLI_UNASSIGNED,
mmctx->gb.tlli_new);
- mmctx_set_mm_state(mmctx, MM_READY);
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_RA_UPDATE, NULL);
break;
}
rc = 0;
diff --git a/src/gprs/gprs_mm_state_gb_fsm.c b/src/gprs/gprs_mm_state_gb_fsm.c
new file mode 100644
index 000000000..2056540db
--- /dev/null
+++ b/src/gprs/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);
+}
diff --git a/src/gprs/gprs_sgsn.c b/src/gprs/gprs_sgsn.c
index 6acc66e9c..82855a6eb 100644
--- a/src/gprs/gprs_sgsn.c
+++ b/src/gprs/gprs_sgsn.c
@@ -42,6 +42,7 @@
#include <osmocom/sgsn/gprs_utils.h>
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
+#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <pdp.h>
@@ -243,6 +244,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
const struct gprs_ra_id *raid)
{
struct sgsn_mm_ctx *ctx;
+ char buf[32];
ctx = sgsn_mm_ctx_alloc(tlli);
if (!ctx)
@@ -251,8 +253,9 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
ctx->ran_type = MM_CTX_T_GERAN_Gb;
ctx->gb.tlli = tlli;
- ctx->gb.mm_state = MM_IDLE;
ctx->ciph_algo = sgsn->cfg.cipher;
+ snprintf(buf, sizeof(buf), "%" PRIu32, tlli);
+ ctx->gb.mm_state_fsm = osmo_fsm_inst_alloc(&mm_state_gb_fsm, ctx, ctx, LOGL_DEBUG, buf);
LOGMMCTXP(LOGL_DEBUG, ctx, "Allocated with %s cipher.\n",
get_value_string(gprs_cipher_names, ctx->ciph_algo));
@@ -334,11 +337,6 @@ void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
osmo_timer_del(&mm->timer);
}
- if (osmo_timer_pending(&mm->gb.state_timer)) {
- LOGMMCTXP(LOGL_INFO, mm, "Cancelling MM state timer %u\n", mm->gb.state_T);
- osmo_timer_del(&mm->gb.state_timer);
- }
-
memset(&sig_data, 0, sizeof(sig_data));
sig_data.mm = mm;
osmo_signal_dispatch(SS_SGSN, S_SGSN_MM_FREE, &sig_data);
@@ -353,6 +351,8 @@ void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
if (mm->gmm_att_req.fsm)
gmm_att_req_free(mm);
+ if (mm->gb.mm_state_fsm)
+ osmo_fsm_inst_free(mm->gb.mm_state_fsm);
sgsn_mm_ctx_free(mm);
mm = NULL;