diff options
author | Alexander Couzens <lynxis@fe80.eu> | 2019-09-11 03:38:14 +0200 |
---|---|---|
committer | Daniel Willmann <dwillmann@sysmocom.de> | 2020-02-04 10:21:12 +0100 |
commit | 91a8bbd5db47bae83c4b63f58536eeae73738b4a (patch) | |
tree | 28a6e2823993427c8058dc8cd10c7ed0569f8ebf | |
parent | d999e54aa264254a66de425ccf7edcd68f8420f2 (diff) |
gprs_gmm_fsm.c: Implement RAT change between 2g and 3g
Related: OS#2737
Change-Id: I3fc614da6ba137e871ee0fe86ca22b6a4a354dd2
-rw-r--r-- | include/osmocom/sgsn/gprs_gmm_fsm.h | 8 | ||||
-rw-r--r-- | src/sgsn/gprs_gmm.c | 32 | ||||
-rw-r--r-- | src/sgsn/gprs_gmm_fsm.c | 25 |
3 files changed, 63 insertions, 2 deletions
diff --git a/include/osmocom/sgsn/gprs_gmm_fsm.h b/include/osmocom/sgsn/gprs_gmm_fsm.h index fd5b4bff9..f10851e5c 100644 --- a/include/osmocom/sgsn/gprs_gmm_fsm.h +++ b/include/osmocom/sgsn/gprs_gmm_fsm.h @@ -1,6 +1,8 @@ #pragma once #include <osmocom/core/fsm.h> +#include <osmocom/sgsn/gprs_sgsn.h> + /* 3GPP TS 24.008 § 4.1.3.3 GMM mobility management states on the network side */ enum gmm_fsm_states { @@ -23,6 +25,12 @@ enum gmm_fsm_events { E_GMM_SUSPEND, E_GMM_RESUME, E_GMM_CLEANUP, + E_GMM_RAT_CHANGE, +}; + +struct gmm_rat_change_data { + enum sgsn_ran_type new_ran_type; + struct gprs_llc_llme *llme; }; static inline bool gmm_fsm_is_registered(struct osmo_fsm_inst *fi) diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c index c574dac5f..03ff513be 100644 --- a/src/sgsn/gprs_gmm.c +++ b/src/sgsn/gprs_gmm.c @@ -1109,6 +1109,23 @@ static bool mmctx_did_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg) return false; } +/* Notify the FSM of a RAT change */ +static void mmctx_handle_rat_change(struct sgsn_mm_ctx *mmctx, struct msgb *msg, struct gprs_llc_llme *llme) +{ + struct gmm_rat_change_data rat_chg = { + .llme = llme + }; + + rat_chg.new_ran_type = MSG_IU_UE_CTX(msg) ? MM_CTX_T_UTRAN_Iu : MM_CTX_T_GERAN_Gb; + + if (rat_chg.new_ran_type != mmctx->ran_type) + osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RAT_CHANGE, (void *) &rat_chg); + else + LOGMMCTXP(LOGL_ERROR, mmctx, "RAT didn't change or not implemented (ran_type=%u, " + "msg_iu_ue_ctx=%p\n", mmctx->ran_type, MSG_IU_UE_CTX(msg)); + +} + /* 3GPP TS 24.008 § 9.4.1 Attach request */ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, struct gprs_llc_llme *llme) @@ -1234,6 +1251,9 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, goto rejected; } + if (mmctx_did_rat_change(ctx, msg)) + mmctx_handle_rat_change(ctx, msg, llme); + if (ctx->ran_type == MM_CTX_T_GERAN_Gb) { ctx->gb.tlli = msgb_tlli(msg); ctx->gb.llme = llme; @@ -1614,7 +1634,12 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, mmctx->p_tmsi, mmctx->p_tmsi_old, mmctx->gb.tlli, mmctx->gb.tlli_new, osmo_rai_name(&mmctx->ra)); - osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL); + /* A RAT change will trigger the common procedure + * below after handling the RAT change. Protect it + * here from being called twice */ + if (!mmctx_did_rat_change(mmctx, msg)) + osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL); + } } else if (!gprs_ra_id_equals(&mmctx->ra, &old_ra_id) || mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED) @@ -1646,6 +1671,11 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, goto rejected; } + if (mmctx_did_rat_change(mmctx, msg)) { + mmctx_handle_rat_change(mmctx, msg, llme); + osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL); + } + /* Store new BVCI/NSEI in MM context (FIXME: delay until we ack?) */ msgid2mmctx(mmctx, msg); /* Bump the statistics of received signalling msgs for this MM context */ diff --git a/src/sgsn/gprs_gmm_fsm.c b/src/sgsn/gprs_gmm_fsm.c index 94ecb50ef..37ea90408 100644 --- a/src/sgsn/gprs_gmm_fsm.c +++ b/src/sgsn/gprs_gmm_fsm.c @@ -1,6 +1,8 @@ #include <osmocom/core/tdef.h> #include <osmocom/sgsn/gprs_gmm_fsm.h> +#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h> +#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h> #include <osmocom/sgsn/debug.h> #include <osmocom/sgsn/sgsn.h> @@ -149,11 +151,32 @@ const struct value_string gmm_fsm_event_names[] = { /* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */ OSMO_VALUE_STRING(E_GMM_SUSPEND), OSMO_VALUE_STRING(E_GMM_CLEANUP), + OSMO_VALUE_STRING(E_GMM_RAT_CHANGE), { 0, NULL } }; void gmm_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) { + struct sgsn_mm_ctx *mmctx = fi->priv; + struct gmm_rat_change_data *rat_chg = (struct gmm_rat_change_data *)data; + switch (event) { + case E_GMM_RAT_CHANGE: + + switch (fi->state) { + case ST_GMM_COMMON_PROC_INIT: + gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED); + default: + if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) + osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_IMPLICIT_DETACH, NULL); + else if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) { + osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_IMPLICIT_DETACH, NULL); + mmctx->gb.llme = rat_chg->llme; + } + + mmctx->ran_type = rat_chg->new_ran_type; + break; + } + case E_GMM_CLEANUP: switch (fi->state) { case ST_GMM_DEREGISTERED: @@ -175,7 +198,7 @@ struct osmo_fsm gmm_fsm = { .states = gmm_fsm_states, .num_states = ARRAY_SIZE(gmm_fsm_states), .event_names = gmm_fsm_event_names, - .allstate_event_mask = X(E_GMM_CLEANUP), + .allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE), .allstate_action = gmm_fsm_allstate_action, .log_subsys = DMM, .timer_cb = gmm_fsm_timer_cb, |