From 02514bc592923b9c082942d64fcf06db2e4bfd44 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Fri, 30 Aug 2019 16:14:22 +0200 Subject: Introduce FSM mm_state_gb_fsm Implement TS 23.060 6.1.1 Mobility Management States (A/Gb 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: I04004423e993107374d5a3549b8a93ac169251dd --- src/gprs/Makefile.am | 1 + src/gprs/gprs_gb.c | 20 +------ src/gprs/gprs_gmm.c | 93 ++------------------------------- src/gprs/gprs_mm_state_gb_fsm.c | 112 ++++++++++++++++++++++++++++++++++++++++ src/gprs/gprs_sgsn.c | 12 ++--- 5 files changed, 125 insertions(+), 113 deletions(-) create mode 100644 src/gprs/gprs_mm_state_gb_fsm.c (limited to 'src') 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 #include #include #include -/* 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 #include #include +#include #include #include #include @@ -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 + +#include + +#include +#include + +#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 #include #include +#include #include #include @@ -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; -- cgit v1.2.3