gmm: Initial implementation of T3312

The RAU procedure triggered by T3312 expiration will be implemented
in a follow-up patch.

Change-Id: If1ca164b7a6c7f7750e2e2f0812d6fde828ed4a4
This commit is contained in:
Pau Espin 2023-05-22 16:39:05 +02:00
parent a2fe6f302a
commit 05b127acbb
3 changed files with 74 additions and 10 deletions

View File

@ -66,7 +66,6 @@ struct gprs_gmm_entity {
char imei[GSM23003_IMEI_NUM_DIGITS + 1];
char imeisv[GSM23003_IMEISV_NUM_DIGITS+1];
uint8_t ra_upd_timer; /* TS 24.008 10.5.7.3 */
uint8_t radio_prio; /* TS 24.008 10.5.7.2 */
struct gprs_ra_id ra; /* TS 24.008 10.5.5.15 (decoded) */
@ -87,6 +86,8 @@ struct gprs_gmm_entity {
/* 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 */
struct osmo_timer_list t3312; /* periodic RAU, in seconds */
unsigned long t3312_assigned_sec; /* value assigned by the network */
};
/* gmm_prim.c: */
@ -116,6 +117,8 @@ 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);
void gprs_gmm_gmme_t3312_start(struct gprs_gmm_entity *gmme);
void gprs_gmm_gmme_t3312_stop(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

@ -79,6 +79,7 @@ static struct osmo_tdef T_defs_gmm[] = {
};
static void t3314_ready_timer_cb(void *data);
static void t3312_periodic_rau_timer_cb(void *data);
static void gprs_gmm_ctx_free(void)
{
@ -176,6 +177,7 @@ struct gprs_gmm_entity *gprs_gmm_gmme_alloc(uint32_t ptmsi, const char *imsi)
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);
osmo_timer_setup(&gmme->t3312, t3312_periodic_rau_timer_cb, gmme);
llist_add(&gmme->list, &g_gmm_ctx->gmme_list);
@ -190,6 +192,8 @@ void gprs_gmm_gmme_free(struct gprs_gmm_entity *gmme)
LOGGMME(gmme, LOGL_DEBUG, "free()\n");
if (osmo_timer_pending(&gmme->t3314))
osmo_timer_del(&gmme->t3314);
if (osmo_timer_pending(&gmme->t3312))
osmo_timer_del(&gmme->t3312);
gprs_gmm_ms_fsm_ctx_release(&gmme->ms_fsm);
llist_del(&gmme->list);
talloc_free(gmme);
@ -295,20 +299,23 @@ void gprs_gmm_gmme_ready_timer_start(struct gprs_gmm_entity *gmme)
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." */
/* "Timer T3312 is stopped and shall be set to its initial value
* for the next start when the READY timer is started.": */
gprs_gmm_gmme_t3312_stop(gmme);
}
/* 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);
/* "In A/Gb mode, the timer T3312 is reset and started with its
* initial value, when the READY timer is stopped or expires."
*/
gprs_gmm_gmme_t3312_start(gmme);
}
bool gprs_gmm_gmme_ready_timer_running(const struct gprs_gmm_entity *gmme)
@ -325,10 +332,54 @@ static void t3314_ready_timer_cb(void *data)
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."
/* "In A/Gb mode, the timer T3312 is reset and started with its
* initial value, when the READY timer is stopped or expires.":
*/
gprs_gmm_gmme_t3312_start(gmme);
}
/* T3312 (Periodic RAU) is started: */
void gprs_gmm_gmme_t3312_start(struct gprs_gmm_entity *gmme)
{
unsigned long t3312_sec;
t3312_sec = osmo_tdef_get(g_gmm_ctx->T_defs, 3312, OSMO_TDEF_S, -1);
if (t3312_sec == 0)
return;
LOGGMME(gmme, LOGL_INFO, "T3312 started\n");
osmo_timer_schedule(&gmme->t3312, t3312_sec, 0);
}
/* T3312 (Periodic RAU) is stopped: */
void gprs_gmm_gmme_t3312_stop(struct gprs_gmm_entity *gmme)
{
if (!osmo_timer_pending(&gmme->t3312))
return;
LOGGMME(gmme, LOGL_INFO, "T3312 stopped\n");
osmo_timer_del(&gmme->t3312);
}
/* T3312 (Periodic RAU) timer expiration: */
static void t3312_periodic_rau_timer_cb(void *data)
{
struct gprs_gmm_entity *gmme = (struct gprs_gmm_entity *)data;
LOGGMME(gmme, LOGL_INFO, "T3312 Periodic RAU timer expired\n");
/* TODO:
* - "Initiation of the Periodic RAU procedure if the MS is not
* attached for emergency bearer services or T3323 started under the
* conditions as specified in subclause 4.7.2.2.
* - Implicit detach from network if the MS is attached for emergency
* bearer services."
* - "If the MS is in a state other than GMM-REGISTERED.NORMAL-SERVICE
* when timer T3312 expires, the periodic routing area updating procedure
* is delayed until the MS returns to GMM-REGISTERED.NORMAL-SERVICE."
* "If timer T3323 expires, the MS shall memorize that it has to initiate a
* routing area updating procedure when it returns to state
* GMM-REGISTERED.NORMAL-SERVICE."
*/
}
int gprs_gmm_submit_gmmreg_attach_cnf(struct gprs_gmm_entity *gmme, bool accepted, uint8_t cause)
@ -595,6 +646,7 @@ static int gprs_gmm_rx_att_ack(struct gprs_gmm_entity *gmme, struct gsm48_hdr *g
struct gsm48_attach_ack *aa;
struct tlv_parsed tp;
int rc;
int periodic_rau_sec;
if (len < sizeof(*gh) + sizeof(*aa)) {
LOGGMME(gmme, LOGL_ERROR, "Rx GMM ATTACH ACCEPT with wrong size %u\n", len);
@ -604,8 +656,11 @@ static int gprs_gmm_rx_att_ack(struct gprs_gmm_entity *gmme, struct gsm48_hdr *g
LOGGMME(gmme, LOGL_INFO, "Rx GMM ATTACH ACCEPT\n");
aa = (struct gsm48_attach_ack *)&gh->data[0];
gmme->ra_upd_timer = aa->ra_upd_timer;
periodic_rau_sec = gprs_gmm_gprs_tmr_to_secs(aa->ra_upd_timer);
gmme->radio_prio = aa->radio_prio;
gmme->t3312_assigned_sec = periodic_rau_sec >= 0 ? periodic_rau_sec : 0;
if (gmme->t3312_assigned_sec == 0)
gprs_gmm_gmme_t3312_stop(gmme);
gsm48_parse_ra(&gmme->ra, (const uint8_t *)&aa->ra_id);
if (len > sizeof(*gh) + sizeof(*aa)) {
@ -632,8 +687,13 @@ static int gprs_gmm_rx_att_ack(struct gprs_gmm_entity *gmme, struct gsm48_hdr *g
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)
if (gmme->t3314_assigned_sec == 0) {
gprs_gmm_gmme_ready_timer_stop(gmme);
/* "If after a READY timer negotiation the READY timer
* value is set to zero, timer T3312 is reset and started
* with its initial value." */
gprs_gmm_gmme_t3312_start(gmme);
}
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
struct osmo_mobile_identity mi;

View File

@ -75,6 +75,7 @@ static void st_gmm_ms_deregistered_on_enter(struct osmo_fsm_inst *fi, uint32_t p
struct gprs_gmm_ms_fsm_ctx *ctx = (struct gprs_gmm_ms_fsm_ctx *)fi->priv;
memset(&ctx->attach, 0, sizeof(ctx->attach));
gprs_gmm_gmme_t3312_stop(ctx->gmme);
}
static void st_gmm_ms_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *data)