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_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
5 files changed, 138 insertions, 55 deletions
diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am
index 94861e297..05d5b4c3c 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 81f42737e..edb7eea1e 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 000000000..1ed5f56f1
--- /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 836937b6e..027b6665a 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 82855a6eb..23347073b 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;