diff options
-rw-r--r-- | include/osmocom/sgsn/gprs_sgsn.h | 4 | ||||
-rw-r--r-- | src/gprs/gprs_gmm.c | 87 | ||||
-rw-r--r-- | src/gprs/gprs_sgsn.c | 5 | ||||
-rw-r--r-- | src/gprs/sgsn_vty.c | 2 | ||||
-rw-r--r-- | tests/test_nodes.vty | 2 |
5 files changed, 98 insertions, 2 deletions
diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h index 9753ea211..336155c9b 100644 --- a/include/osmocom/sgsn/gprs_sgsn.h +++ b/include/osmocom/sgsn/gprs_sgsn.h @@ -156,6 +156,10 @@ struct sgsn_mm_ctx { struct gprs_llc_llme *llme; uint32_t tlli; uint32_t tlli_new; + + /* timer for mm state. state=READY: T3314 (aka TS 23.060 "READY timer") */ + struct osmo_timer_list state_timer; + unsigned int state_T; /* Txxxx number but only used for pmm_states */ } gb; struct { int new_key; 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)" }, diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty index 630094fda..2ef926af1 100644 --- a/tests/test_nodes.vty +++ b/tests/test_nodes.vty @@ -2,7 +2,7 @@ OsmoSGSN> enable OsmoSGSN# show timer T3312 = 600 s Periodic RA Update timer (s) (default: 600 s) T3313 = 30 s Waiting for paging response timer (s) (default: 30 s) -T3314 = 44 s Force to STANDBY on expiry timer (s) (default: 44 s) +T3314 = 44 s READY timer. Force to STANDBY on expiry timer (s) (default: 44 s) T3316 = 44 s AA-Ready timer (s) (default: 44 s) T3322 = 6 s Detach request -> accept timer (s) (default: 6 s) T3350 = 6 s Waiting for ATT/RAU/TMSI_COMPL timer (s) (default: 6 s) |