aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2019-08-30 17:06:36 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2019-09-02 11:44:58 +0200
commitccd1252bd76169439cb66f3a50e4575e0f03ec0b (patch)
treefe1bb807c01383609b0d74ad1ac25759952d8d69
parent02514bc592923b9c082942d64fcf06db2e4bfd44 (diff)
Introduce FSM mm_state_iu_fsm
Implement TS 23.060 6.1.2 Mobility Management States (Iu mode) using osmocom FSM and drop old implementation. Most of the logic on each state is still kept in gprs_gmm.c, will be inserted into the FSM later. Change-Id: I4c9cf8c27194817c56e8949af0205e1cc14af317
-rw-r--r--include/osmocom/sgsn/Makefile.am1
-rw-r--r--include/osmocom/sgsn/gprs_gmm.h2
-rw-r--r--include/osmocom/sgsn/gprs_mm_state_iu_fsm.h24
-rw-r--r--include/osmocom/sgsn/gprs_sgsn.h9
-rw-r--r--src/gprs/Makefile.am1
-rw-r--r--src/gprs/gprs_gmm.c55
-rw-r--r--src/gprs/gprs_mm_state_iu_fsm.c121
-rw-r--r--src/gprs/gprs_ranap.c8
-rw-r--r--src/gprs/gprs_sgsn.c8
-rw-r--r--tests/sgsn/Makefile.am1
10 files changed, 165 insertions, 65 deletions
diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am
index d6ee4451..0ab00fe4 100644
--- a/include/osmocom/sgsn/Makefile.am
+++ b/include/osmocom/sgsn/Makefile.am
@@ -8,6 +8,7 @@ noinst_HEADERS = \
gprs_gmm.h \
gprs_gmm_attach.h \
gprs_mm_state_gb_fsm.h \
+ gprs_mm_state_iu_fsm.h \
gprs_llc.h \
gprs_llc_xid.h \
gprs_ranap.h \
diff --git a/include/osmocom/sgsn/gprs_gmm.h b/include/osmocom/sgsn/gprs_gmm.h
index 2fa12e59..982cd93d 100644
--- a/include/osmocom/sgsn/gprs_gmm.h
+++ b/include/osmocom/sgsn/gprs_gmm.h
@@ -49,7 +49,5 @@ void extract_subscr_hlr(struct sgsn_mm_ctx *ctx);
void pdp_ctx_detach_mm_ctx(struct sgsn_pdp_ctx *pdp);
-void mmctx_set_pmm_state(struct sgsn_mm_ctx *ctx, enum gprs_mm_state_iu state);
-
void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg);
#endif /* _GPRS_GMM_H */
diff --git a/include/osmocom/sgsn/gprs_mm_state_iu_fsm.h b/include/osmocom/sgsn/gprs_mm_state_iu_fsm.h
new file mode 100644
index 00000000..7f02bcc4
--- /dev/null
+++ b/include/osmocom/sgsn/gprs_mm_state_iu_fsm.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <osmocom/core/fsm.h>
+
+struct sgsn_mm_ctx;
+
+
+/* TS 23.060 6.1.1 Mobility Management States (A/Gb mode) */
+enum mm_state_iu_fsm_states {
+ ST_PMM_DETACHED,
+ ST_PMM_CONNECTED,
+ ST_PMM_IDLE
+};
+
+enum mm_state_iu_fsm_events {
+ E_PMM_PS_ATTACH,
+ /* E_PS_DETACH, TODO: not used */
+ E_PMM_PS_CONN_RELEASE,
+ E_PMM_PS_CONN_ESTABLISH,
+ E_PMM_IMPLICIT_DETACH, /* = E_PS_ATTACH_REJECT, E_RAU_REJECT */
+ E_PMM_RA_UPDATE, /* = Serving RNC relocation */
+};
+
+extern struct osmo_fsm mm_state_iu_fsm;
diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h
index 382019c2..8f16c5b3 100644
--- a/include/osmocom/sgsn/gprs_sgsn.h
+++ b/include/osmocom/sgsn/gprs_sgsn.h
@@ -32,13 +32,6 @@ enum gprs_gmm_state {
GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */
};
-/* TS 23.060 6.1.2 Mobility Management States (Iu mode) */
-enum gprs_mm_state_iu {
- PMM_DETACHED,
- PMM_CONNECTED,
- PMM_IDLE
-};
-
enum gprs_mm_ctr {
GMM_CTR_PKTS_SIG_IN,
GMM_CTR_PKTS_SIG_OUT,
@@ -171,7 +164,7 @@ struct sgsn_mm_ctx {
struct ranap_ue_conn_ctx *ue_ctx;
struct service_info service;
/* TS 23.060 6.1.2 Mobility Management States (Iu mode) */
- enum gprs_mm_state_iu mm_state;
+ struct osmo_fsm_inst *mm_state_fsm;
} iu;
struct {
struct osmo_fsm_inst *fsm;
diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am
index 94861e29..05d5b4c3 100644
--- a/src/gprs/Makefile.am
+++ b/src/gprs/Makefile.am
@@ -64,6 +64,7 @@ osmo_sgsn_SOURCES = \
gprs_gmm_attach.c \
gprs_gmm.c \
gprs_mm_state_gb_fsm.c \
+ gprs_mm_state_iu_fsm.c \
gprs_ranap.c \
gprs_sgsn.c \
gprs_sndcp.c \
diff --git a/src/gprs/gprs_gmm.c b/src/gprs/gprs_gmm.c
index 81f42737..edb7eea1 100644
--- a/src/gprs/gprs_gmm.c
+++ b/src/gprs/gprs_gmm.c
@@ -56,6 +56,7 @@
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
+#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/signal.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_ranap.h>
@@ -103,52 +104,6 @@ static const struct tlv_definition gsm48_sm_att_tlvdef = {
},
};
-static const struct value_string gprs_mm_state_iu_names[] = {
- OSMO_VALUE_STRING(PMM_DETACHED),
- OSMO_VALUE_STRING(PMM_CONNECTED),
- OSMO_VALUE_STRING(PMM_IDLE),
- { 0, NULL }
-};
-
-static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx)
-{
- char buf[INET_ADDRSTRLEN];
- struct sgsn_pdp_ctx *pdp;
- llist_for_each_entry(pdp, &mm_ctx->pdp_list, list) {
- LOGMMCTXP(LOGL_INFO, mm_ctx, "Changing GTP-U endpoints %s -> %s\n",
- sgsn_gtp_ntoa(&pdp->lib->gsnlu),
- inet_ntop(AF_INET, &sgsn->cfg.gtp_listenaddr.sin_addr, buf, sizeof(buf)));
- sgsn_pdp_upd_gtp_u(pdp,
- &sgsn->cfg.gtp_listenaddr.sin_addr,
- sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
- }
-}
-
-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);
-
- if (ctx->iu.mm_state == state)
- return;
-
- LOGMMCTXP(LOGL_INFO, ctx, "Changing PMM state from %s to %s\n",
- get_value_string(gprs_mm_state_iu_names, ctx->iu.mm_state),
- get_value_string(gprs_mm_state_iu_names, state));
-
- switch (state) {
- case PMM_IDLE:
- /* TODO: start RA Upd timer */
- mmctx_change_gtpu_endpoints_to_sgsn(ctx);
- break;
- case PMM_CONNECTED:
- break;
- case PMM_DETACHED:
- break;
- }
-
- ctx->iu.mm_state = state;
-}
-
/* Our implementation, should be kept in SGSN */
static void mmctx_timer_cb(void *_mm);
@@ -260,7 +215,7 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
switch(ctx->ran_type) {
case MM_CTX_T_UTRAN_Iu:
- mmctx_set_pmm_state(ctx, PMM_DETACHED);
+ osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL);
break;
case MM_CTX_T_GERAN_Gb:
osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL);
@@ -1019,7 +974,7 @@ int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
#ifdef BUILD_IU
case GSM48_MT_GMM_SERVICE_REQ:
ctx->pending_req = 0;
- mmctx_set_pmm_state(ctx, PMM_CONNECTED);
+ osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
rc = gsm48_tx_gmm_service_ack(ctx);
if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
@@ -2014,7 +1969,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->gmm_state = GMM_REGISTERED_NORMAL;
switch(mmctx->ran_type) {
case MM_CTX_T_UTRAN_Iu:
- mmctx_set_pmm_state(mmctx, PMM_CONNECTED);
+ osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
break;
case MM_CTX_T_GERAN_Gb:
/* Unassign the old TLLI */
@@ -2044,7 +1999,7 @@ int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->gmm_state = GMM_REGISTERED_NORMAL;
switch(mmctx->ran_type) {
case MM_CTX_T_UTRAN_Iu:
- mmctx_set_pmm_state(mmctx, PMM_CONNECTED);
+ osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_RA_UPDATE, NULL);
break;
case MM_CTX_T_GERAN_Gb:
/* Unassign the old TLLI */
diff --git a/src/gprs/gprs_mm_state_iu_fsm.c b/src/gprs/gprs_mm_state_iu_fsm.c
new file mode 100644
index 00000000..1ed5f56f
--- /dev/null
+++ b/src/gprs/gprs_mm_state_iu_fsm.c
@@ -0,0 +1,121 @@
+#include <arpa/inet.h>
+
+#include <osmocom/core/tdef.h>
+
+#include <osmocom/sgsn/gprs_mm_state_iu_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_iu_fsm_timeouts[32] = {
+ [ST_PMM_DETACHED] = { },
+ [ST_PMM_CONNECTED] = { },
+ [ST_PMM_IDLE] = { },
+};
+
+#define mm_state_iu_fsm_state_chg(fi, NEXT_STATE) \
+ osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, mm_state_iu_fsm_timeouts, sgsn->cfg.T_defs, -1)
+
+static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx)
+{
+ char buf[INET_ADDRSTRLEN];
+ struct sgsn_pdp_ctx *pdp;
+ llist_for_each_entry(pdp, &mm_ctx->pdp_list, list) {
+ LOGMMCTXP(LOGL_INFO, mm_ctx, "Changing GTP-U endpoints %s -> %s\n",
+ sgsn_gtp_ntoa(&pdp->lib->gsnlu),
+ inet_ntop(AF_INET, &sgsn->cfg.gtp_listenaddr.sin_addr, buf, sizeof(buf)));
+ sgsn_pdp_upd_gtp_u(pdp,
+ &sgsn->cfg.gtp_listenaddr.sin_addr,
+ sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
+ }
+}
+
+static void st_pmm_detached(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch(event) {
+ case E_PMM_PS_ATTACH:
+ mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
+ break;
+ case E_PMM_IMPLICIT_DETACH:
+ break;
+ }
+}
+
+static void st_pmm_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch(event) {
+ case E_PMM_PS_CONN_RELEASE:
+ mm_state_iu_fsm_state_chg(fi, ST_PMM_IDLE);
+ break;
+ case E_PMM_IMPLICIT_DETACH:
+ mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
+ break;
+ case E_PMM_RA_UPDATE:
+ break;
+ }
+}
+
+static void st_pmm_idle_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct sgsn_mm_ctx *ctx = fi->priv;
+
+ mmctx_change_gtpu_endpoints_to_sgsn(ctx);
+}
+
+static void st_pmm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch(event) {
+ case E_PMM_PS_CONN_ESTABLISH:
+ mm_state_iu_fsm_state_chg(fi, ST_PMM_CONNECTED);
+ break;
+ case E_PMM_IMPLICIT_DETACH:
+ mm_state_iu_fsm_state_chg(fi, ST_PMM_DETACHED);
+ break;
+ }
+}
+
+static struct osmo_fsm_state mm_state_iu_fsm_states[] = {
+ [ST_PMM_DETACHED] = {
+ .in_event_mask = X(E_PMM_PS_ATTACH) | X(E_PMM_IMPLICIT_DETACH),
+ .out_state_mask = X(ST_PMM_CONNECTED),
+ .name = "Detached",
+ .action = st_pmm_detached,
+ },
+ [ST_PMM_CONNECTED] = {
+ .in_event_mask = X(E_PMM_PS_CONN_RELEASE) | X(E_PMM_RA_UPDATE) | X(E_PMM_IMPLICIT_DETACH),
+ .out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_IDLE),
+ .name = "Connected",
+ .action = st_pmm_connected,
+ },
+ [ST_PMM_IDLE] = {
+ .in_event_mask = X(E_PMM_IMPLICIT_DETACH) | X(E_PMM_PS_CONN_ESTABLISH),
+ .out_state_mask = X(ST_PMM_DETACHED) | X(ST_PMM_CONNECTED),
+ .name = "Idle",
+ .onenter = st_pmm_idle_on_enter,
+ .action = st_pmm_idle,
+ },
+};
+
+const struct value_string mm_state_iu_fsm_event_names[] = {
+ OSMO_VALUE_STRING(E_PMM_PS_ATTACH),
+ OSMO_VALUE_STRING(E_PMM_PS_CONN_RELEASE),
+ OSMO_VALUE_STRING(E_PMM_PS_CONN_ESTABLISH),
+ OSMO_VALUE_STRING(E_PMM_IMPLICIT_DETACH),
+ OSMO_VALUE_STRING(E_PMM_RA_UPDATE),
+ { 0, NULL }
+};
+
+struct osmo_fsm mm_state_iu_fsm = {
+ .name = "MM_STATE_Iu",
+ .states = mm_state_iu_fsm_states,
+ .num_states = ARRAY_SIZE(mm_state_iu_fsm_states),
+ .event_names = mm_state_iu_fsm_event_names,
+ .log_subsys = DMM,
+};
+
+static __attribute__((constructor)) void mm_state_iu_fsm_init(void)
+{
+ osmo_fsm_register(&mm_state_iu_fsm);
+}
diff --git a/src/gprs/gprs_ranap.c b/src/gprs/gprs_ranap.c
index 836937b6..027b6665 100644
--- a/src/gprs/gprs_ranap.c
+++ b/src/gprs/gprs_ranap.c
@@ -36,6 +36,7 @@
#include <osmocom/sgsn/sgsn.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_attach.h>
+#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
/* Send RAB activation requests for all PDP contexts */
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
@@ -134,12 +135,11 @@ int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type
/* fall thru */
case RANAP_IU_EVENT_LINK_INVALIDATED:
/* Clean up ranap_ue_conn_ctx here */
- if (mm)
+ if (mm) {
LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
- else
+ osmo_fsm_inst_dispatch(mm->iu.mm_state_fsm, E_PMM_PS_CONN_RELEASE, NULL);
+ } else
LOGIUP(ctx, LOGL_INFO, "IU release\n");
- if (mm && mm->iu.mm_state == PMM_CONNECTED)
- mmctx_set_pmm_state(mm, PMM_IDLE);
rc = 0;
break;
case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE:
diff --git a/src/gprs/gprs_sgsn.c b/src/gprs/gprs_sgsn.c
index 82855a6e..23347073 100644
--- a/src/gprs/gprs_sgsn.c
+++ b/src/gprs/gprs_sgsn.c
@@ -43,6 +43,7 @@
#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_mm_state_iu_fsm.h>
#include <osmocom/sgsn/gprs_llc.h>
#include <pdp.h>
@@ -266,6 +267,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli,
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
{
#if BUILD_IU
+ char buf[32];
struct sgsn_mm_ctx *ctx;
struct ranap_ue_conn_ctx *ue_ctx = uectx;
@@ -279,7 +281,9 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
ctx->iu.ue_ctx = ue_ctx;
ctx->iu.ue_ctx->rab_assign_addr_enc = sgsn->cfg.iu.rab_assign_addr_enc;
ctx->iu.new_key = 1;
- ctx->iu.mm_state = PMM_DETACHED;
+ snprintf(buf, sizeof(buf), "%" PRIu32, ue_ctx->conn_id);
+ ctx->iu.mm_state_fsm = osmo_fsm_inst_alloc(&mm_state_iu_fsm, ctx, ctx, LOGL_DEBUG, buf);
+
return ctx;
#else
@@ -353,6 +357,8 @@ void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
gmm_att_req_free(mm);
if (mm->gb.mm_state_fsm)
osmo_fsm_inst_free(mm->gb.mm_state_fsm);
+ if (mm->iu.mm_state_fsm)
+ osmo_fsm_inst_free(mm->iu.mm_state_fsm);
sgsn_mm_ctx_free(mm);
mm = NULL;
diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am
index 8a26d884..47189e55 100644
--- a/tests/sgsn/Makefile.am
+++ b/tests/sgsn/Makefile.am
@@ -51,6 +51,7 @@ sgsn_test_LDADD = \
$(top_builddir)/src/gprs/gprs_gmm_attach.o \
$(top_builddir)/src/gprs/gprs_gmm.o \
$(top_builddir)/src/gprs/gprs_mm_state_gb_fsm.o \
+ $(top_builddir)/src/gprs/gprs_mm_state_iu_fsm.o \
$(top_builddir)/src/gprs/gprs_sgsn.o \
$(top_builddir)/src/gprs/sgsn_vty.o \
$(top_builddir)/src/gprs/sgsn_libgtp.o \