From a2fe6f302ac6a88c2a816f6dea5dd6a25813b76d Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Mon, 22 May 2023 14:33:37 +0200 Subject: [PATCH] gmm: Initial implementation of READY timer Change-Id: I451ce08d80fb247c28819de065136e2e4d49f3f5 --- include/osmocom/gprs/gmm/gmm_private.h | 7 +++ src/gmm/gmm.c | 63 ++++++++++++++++++++++++++ src/gmm/gmm_pdu.c | 5 ++ src/gmm/gmm_prim.c | 15 +++++- tests/gmm/gmm_prim_test.ok | 4 +- 5 files changed, 90 insertions(+), 4 deletions(-) diff --git a/include/osmocom/gprs/gmm/gmm_private.h b/include/osmocom/gprs/gmm/gmm_private.h index 339753b..0ae4df4 100644 --- a/include/osmocom/gprs/gmm/gmm_private.h +++ b/include/osmocom/gprs/gmm/gmm_private.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,9 @@ struct gprs_gmm_entity { unsigned long t3302; unsigned long t3346; + /* READY timer, TS 24.008 4.7.2.1.1 */ + struct osmo_timer_list t3314; + unsigned long t3314_assigned_sec; /* value assigned by the network */ }; /* gmm_prim.c: */ @@ -109,6 +113,9 @@ struct gprs_gmm_entity *gprs_gmm_find_gmme_by_imsi(const char *imsi); struct gprs_gmm_entity *gprs_gmm_find_gmme_by_tlli(uint32_t tlli); struct gprs_gmm_entity *gprs_gmm_find_gmme_by_sess_id(uint32_t id); uint32_t gprs_gmm_alloc_rand_tlli(void); +void gprs_gmm_gmme_ready_timer_start(struct gprs_gmm_entity *gmme); +void gprs_gmm_gmme_ready_timer_stop(struct gprs_gmm_entity *gmme); +bool gprs_gmm_gmme_ready_timer_running(const struct gprs_gmm_entity *gmme); int gprs_gmm_rx(struct gprs_gmm_entity *gmme, struct gsm48_hdr *gh, unsigned int len); int gprs_gmm_tx_att_req(struct gprs_gmm_entity *gmme, enum osmo_gprs_gmm_attach_type attach_type, diff --git a/src/gmm/gmm.c b/src/gmm/gmm.c index aef3571..5a3b0c0 100644 --- a/src/gmm/gmm.c +++ b/src/gmm/gmm.c @@ -78,6 +78,8 @@ static struct osmo_tdef T_defs_gmm[] = { { 0 } /* empty item at the end */ }; +static void t3314_ready_timer_cb(void *data); + static void gprs_gmm_ctx_free(void) { struct gprs_gmm_entity *gmme; @@ -173,6 +175,8 @@ struct gprs_gmm_entity *gprs_gmm_gmme_alloc(uint32_t ptmsi, const char *imsi) gmme->t3302 = osmo_tdef_get(g_gmm_ctx->T_defs, 3302, OSMO_TDEF_S, -1); gmme->t3346 = osmo_tdef_get(g_gmm_ctx->T_defs, 3346, OSMO_TDEF_S, -1); + osmo_timer_setup(&gmme->t3314, t3314_ready_timer_cb, gmme); + llist_add(&gmme->list, &g_gmm_ctx->gmme_list); return gmme; @@ -184,6 +188,8 @@ void gprs_gmm_gmme_free(struct gprs_gmm_entity *gmme) return; LOGGMME(gmme, LOGL_DEBUG, "free()\n"); + if (osmo_timer_pending(&gmme->t3314)) + osmo_timer_del(&gmme->t3314); gprs_gmm_ms_fsm_ctx_release(&gmme->ms_fsm); llist_del(&gmme->list); talloc_free(gmme); @@ -280,6 +286,51 @@ failed: return GPRS_GMM_TLLI_UNASSIGNED; } +/* TS 24.008 4.7.2.1.1 READY timer behaviour (A/Gb mode only) */ +/* Ready timer is started: */ +void gprs_gmm_gmme_ready_timer_start(struct gprs_gmm_entity *gmme) +{ + if (gmme->t3314_assigned_sec == 0) + return; + LOGGMME(gmme, LOGL_INFO, "READY timer started\n"); + osmo_timer_schedule(&gmme->t3314, gmme->t3314_assigned_sec, 0); + + /* TODO: "Timer T3312 is stopped and shall be set to its initial value + * for the next start when the READY timer is started." */ +} + +/* Ready timer is stopped: */ +void gprs_gmm_gmme_ready_timer_stop(struct gprs_gmm_entity *gmme) +{ + /* TODO: "In A/Gb mode, the timer T3312 is reset and started with its + * initial value, when the READY timer is stopped or expires." + */ + if (!osmo_timer_pending(&gmme->t3314)) + return; + LOGGMME(gmme, LOGL_INFO, "READY timer stopped\n"); + osmo_timer_del(&gmme->t3314); +} + +bool gprs_gmm_gmme_ready_timer_running(const struct gprs_gmm_entity *gmme) +{ + return osmo_timer_pending(&gmme->t3314); +} + +/* READY timer expiration: */ +static void t3314_ready_timer_cb(void *data) +{ + /* "When the READY timer has expired the MS shall perform the routing + * area updating procedure when a routing area border is crossed" + */ + struct gprs_gmm_entity *gmme = (struct gprs_gmm_entity *)data; + LOGGMME(gmme, LOGL_INFO, "READY timer expired\n"); + + /* TODO: "In A/Gb mode, the timer T3312 is reset and started with its + *initial value, when the READY timer is stopped or expires." + */ + +} + int gprs_gmm_submit_gmmreg_attach_cnf(struct gprs_gmm_entity *gmme, bool accepted, uint8_t cause) { struct osmo_gprs_gmm_prim *gmm_prim_tx; @@ -572,6 +623,18 @@ static int gprs_gmm_rx_att_ack(struct gprs_gmm_entity *gmme, struct gsm48_hdr *g gmme->ptmsi_sig = GSM_RESERVED_TMSI; } + /* 10.5.7.3 Negotiated READY timer value */ + if (TLVP_PRESENT(&tp, GSM48_IE_GMM_TIMER_READY)) { + int secs = gprs_gmm_gprs_tmr_to_secs(*TLVP_VAL(&tp, GSM48_IE_GMM_TIMER_READY)); + gmme->t3314_assigned_sec = secs >= 0 ? secs : 0; + } else { + /* Apply the requested value: */ + gmme->t3314_assigned_sec = osmo_tdef_get(g_gmm_ctx->T_defs, 3314, OSMO_TDEF_S, -1); + } + /* "If the negotiated READY timer value is set to zero, the READY timer shall be stopped immediately": */ + if (gmme->t3314_assigned_sec == 0) + gprs_gmm_gmme_ready_timer_stop(gmme); + if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) { struct osmo_mobile_identity mi; if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI), diff --git a/src/gmm/gmm_pdu.c b/src/gmm/gmm_pdu.c index 28fd30f..c6c8118 100644 --- a/src/gmm/gmm_pdu.c +++ b/src/gmm/gmm_pdu.c @@ -181,6 +181,7 @@ int gprs_gmm_build_attach_req(struct gprs_gmm_entity *gmme, uint8_t *l; int rc; struct gsm48_ra_id *raid_enc; + unsigned long t3314_sec; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -236,6 +237,10 @@ int gprs_gmm_build_attach_req(struct gprs_gmm_entity *gmme, msgb_tv_fixed_put(msg, GSM48_IE_GMM_PTMSI_SIG, sizeof(ptmsi_sig), ptmsi_sig); } + /* 10.5.7.3 Requested READY timer value */ + t3314_sec = osmo_tdef_get(g_gmm_ctx->T_defs, 3314, OSMO_TDEF_S, -1); + msgb_tv_put(msg, GSM48_IE_GMM_TIMER_READY, gprs_gmm_secs_to_gprs_tmr_floor(t3314_sec)); + /* 9.4.1.13 P-TMSI type: The MS shall include this IE if the * type of identity in the Mobile identity IE is set to * "TMSI/P-TMSI/M-TMSI". */ diff --git a/src/gmm/gmm_prim.c b/src/gmm/gmm_prim.c index 7ca6535..34c9fe9 100644 --- a/src/gmm/gmm_prim.c +++ b/src/gmm/gmm_prim.c @@ -603,6 +603,18 @@ int gprs_gmm_prim_call_down_cb(struct osmo_gprs_gmm_prim *gmm_prim) return rc; } +static int gprs_gmm_prim_handle_gmmrr_llc_transmitted_ind(struct osmo_gprs_gmm_prim *gmm_prim) +{ + struct gprs_gmm_entity *gmme = gprs_gmm_find_gmme_by_tlli(gmm_prim->gmmrr.tlli); + if (!gmme) { + LOGGMM(LOGL_NOTICE, "Rx %s: Unknown TLLI 0x%08x\n", + osmo_gprs_gmm_prim_name(gmm_prim), gmm_prim->gmmrr.tlli); + return -ENOENT; + } + gprs_gmm_gmme_ready_timer_start(gmme); + return 0; +} + static int gprs_gmm_prim_handle_gmmrr(struct osmo_gprs_gmm_prim *gmm_prim) { int rc = 0; @@ -612,8 +624,7 @@ static int gprs_gmm_prim_handle_gmmrr(struct osmo_gprs_gmm_prim *gmm_prim) rc = 1; break; case OSMO_PRIM(OSMO_GPRS_GMM_GMMRR_LLC_TRANSMITTED, PRIM_OP_INDICATION): - rc = gprs_gmm_prim_handle_unsupported(gmm_prim); - rc = 1; + rc = gprs_gmm_prim_handle_gmmrr_llc_transmitted_ind(gmm_prim); break; default: rc = gprs_gmm_prim_handle_unsupported(gmm_prim); diff --git a/tests/gmm/gmm_prim_test.ok b/tests/gmm/gmm_prim_test.ok index cfebbfa..068876b 100644 --- a/tests/gmm/gmm_prim_test.ok +++ b/tests/gmm/gmm_prim_test.ok @@ -1,5 +1,5 @@ ==== test_gmm_prim_ms_gmmreg() [start] ==== -test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM l3=[08 01 04 97 07 00 00 01 0a 00 05 f4 00 00 12 34 00 f0 00 00 00 00 00 19 55 66 77 e1 ] +test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM l3=[08 01 04 97 07 00 00 01 0a 00 05 f4 00 00 12 34 00 f0 00 00 00 00 00 19 55 66 77 17 16 e1 ] test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM l3=[08 16 08 42 32 24 43 32 24 43 f2 ] test_gmm_prim_up_cb(): Rx GMMREG-SIM_AUTH.indication ac_ref_nr=2 key_seq=0 rand=e2 a6 f3 f8 bb 9e a7 01 e0 ce 4f 33 64 a9 91 75 test_gmm_prim_llc_down_cb(): Rx LLGMM-ASSIGN.request old_TLLI=0xffffffff new_TLLI=0x80001234 @@ -13,7 +13,7 @@ test_gmm_prim_llc_down_cb(): Rx LLGMM-ASSIGN.request old_TLLI=0xea711b41 new_TLL test_gmm_prim_up_cb(): Rx GMMREG-DETACH.confirm detach_type='GPRS detach' ==== test_gmm_prim_ms_gmmreg() [end] ==== ==== test_gmm_prim_ms_gmmsm() [start] ==== -test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM l3=[08 01 04 97 07 00 00 01 0a 00 05 f4 00 00 12 34 00 f0 00 00 00 00 00 19 55 66 77 e1 ] +test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM l3=[08 01 04 97 07 00 00 01 0a 00 05 f4 00 00 12 34 00 f0 00 00 00 00 00 19 55 66 77 17 16 e1 ] test_gmm_prim_llc_down_cb(): Rx LL-UNITDATA.request TLLI=0x80001234 SAPI=GMM l3=[08 16 08 42 32 24 43 32 24 43 f2 ] test_gmm_prim_up_cb(): Rx GMMREG-SIM_AUTH.indication ac_ref_nr=2 key_seq=0 rand=e2 a6 f3 f8 bb 9e a7 01 e0 ce 4f 33 64 a9 91 75 test_gmm_prim_llc_down_cb(): Rx LLGMM-ASSIGN.request old_TLLI=0xffffffff new_TLLI=0x80001234