aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs
diff options
context:
space:
mode:
authorAlexander Couzens <lynxis@fe80.eu>2017-02-03 22:16:05 +0100
committerPau Espin Pedrol <pespin@sysmocom.de>2019-08-20 17:48:47 +0200
commit39cbecd273b16d72dd7b4aa8b307e5d4bc643474 (patch)
treec9329192f33f3833f73d2664d909ad5c1750565b /src/gprs
parent5ed3f67f96ce29a1afcd9db89b45752c1d69ac8c (diff)
gprs/gprs_gmm: implement T3314. Timeout to reset MM state READY->STANDBY
When a MS MM state is READY its exact location is known (PCU). On Gb, T3314 (aka TS 23.060 "READY timer") sets the MM state from READY to STANDBY, where only the RA is known. Introduce a second set of timer variables, because state timer can run while another packet state timer is timing out. Related: OS#1941 Change-Id: I4ce23ebe50d141076c20c9c56990b7103cd25e55
Diffstat (limited to 'src/gprs')
-rw-r--r--src/gprs/gprs_gmm.c87
-rw-r--r--src/gprs/gprs_sgsn.c5
-rw-r--r--src/gprs/sgsn_vty.c2
3 files changed, 93 insertions, 1 deletions
diff --git a/src/gprs/gprs_gmm.c b/src/gprs/gprs_gmm.c
index db8defcc6..f7aff7311 100644
--- a/src/gprs/gprs_gmm.c
+++ b/src/gprs/gprs_gmm.c
@@ -137,6 +137,57 @@ static void mmctx_change_gtpu_endpoints_to_sgsn(struct sgsn_mm_ctx *mm_ctx)
}
}
+static void mmctx_set_mm_state(struct sgsn_mm_ctx *ctx, enum gprs_pmm_state state);
+static void mmctx_state_timer_cb(void *_mm)
+{
+ struct sgsn_mm_ctx *mm = _mm;
+
+ switch (mm->gb.state_T) {
+ case 3314:
+ switch (mm->pmm_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_pmm_state_names, mm->pmm_state));
+ break;
+ }
+ break;
+ default:
+ LOGMMCTXP(LOGL_ERROR, mm, "state timer expired in unknown mode %u\n",
+ mm->gb.state_T);
+ break;
+ }
+}
+
+static 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;
+}
+
static void mmctx_set_pmm_state(struct sgsn_mm_ctx *ctx, enum gprs_pmm_state state)
{
OSMO_ASSERT(ctx->ran_type == MM_CTX_T_UTRAN_Iu);
@@ -173,6 +224,24 @@ static void mmctx_set_mm_state(struct sgsn_mm_ctx *ctx, enum gprs_pmm_state stat
get_value_string(gprs_pmm_state_names, ctx->pmm_state),
get_value_string(gprs_pmm_state_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->pmm_state == MM_READY)
+ mmctx_state_timer_stop(ctx, 3314);
+ break;
+ case MM_STANDBY:
+ if (ctx->pmm_state == MM_READY)
+ mmctx_state_timer_stop(ctx, 3314);
+ break;
+ default:
+ /* when changing to state != MM_READY */
+ break;
+ }
+
ctx->pmm_state = state;
}
@@ -2968,6 +3037,21 @@ int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
return rc;
}
+/* Update the MM context state */
+static void gsm0408_gprs_notify_pdu_gb(struct sgsn_mm_ctx *mmctx)
+{
+ switch (mmctx->pmm_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)
@@ -2988,6 +3072,9 @@ int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
/* 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_sgsn.c b/src/gprs/gprs_sgsn.c
index eb04846eb..9f02d5420 100644
--- a/src/gprs/gprs_sgsn.c
+++ b/src/gprs/gprs_sgsn.c
@@ -341,6 +341,11 @@ 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);
diff --git a/src/gprs/sgsn_vty.c b/src/gprs/sgsn_vty.c
index ae26cbeae..66986911c 100644
--- a/src/gprs/sgsn_vty.c
+++ b/src/gprs/sgsn_vty.c
@@ -94,7 +94,7 @@ const struct value_string sgsn_auth_pol_strs[] = {
static struct osmo_tdef sgsn_T_defs[] = {
{ .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
{ .T=3313, .default_val=GSM0408_T3313_SECS, .desc="Waiting for paging response timer (s)" },
- { .T=3314, .default_val=GSM0408_T3314_SECS, .desc="Force to STANDBY on expiry timer (s)" },
+ { .T=3314, .default_val=GSM0408_T3314_SECS, .desc="READY timer. Force to STANDBY on expiry timer (s)" },
{ .T=3316, .default_val=GSM0408_T3316_SECS, .desc="AA-Ready timer (s)" },
{ .T=3322, .default_val=GSM0408_T3322_SECS, .desc="Detach request -> accept timer (s)" },
{ .T=3350, .default_val=GSM0408_T3350_SECS, .desc="Waiting for ATT/RAU/TMSI_COMPL timer (s)" },