gmm: Initial implementation of READY timer

Change-Id: I451ce08d80fb247c28819de065136e2e4d49f3f5
This commit is contained in:
Pau Espin 2023-05-22 14:33:37 +02:00
parent c6e7a3bd88
commit a2fe6f302a
5 changed files with 90 additions and 4 deletions

View File

@ -10,6 +10,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/endian.h>
#include <osmocom/core/tdef.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/gprs/llc/llc_prim.h>
@ -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,

View File

@ -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),

View File

@ -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". */

View File

@ -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);

View File

@ -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