diff options
Diffstat (limited to 'src/gprs/gprs_gmm.c')
-rw-r--r-- | src/gprs/gprs_gmm.c | 87 |
1 files changed, 87 insertions, 0 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); |