vlr: Add support for CS and PS timers

To prepare for PS support, add related PS timers
and try to keep the code simple to support both domains.
Use osmo_tdef_fsm_inst_state_chg() where possible because
this way we can have a t_def pointer which we set at the start.

Change-Id: I364973b8d9e277ec5963343c0a83061e81a5baba
This commit is contained in:
Alexander Couzens
2024-10-21 17:56:19 +02:00
parent e2931c27ce
commit 177184ee2e
10 changed files with 131 additions and 43 deletions

View File

@@ -421,7 +421,10 @@ bool vlr_subscr_matches_tmsi(struct vlr_subscr *vsub, uint32_t tmsi);
bool vlr_subscr_matches_msisdn(struct vlr_subscr *vsub, const char *msisdn);
bool vlr_subscr_matches_imei(struct vlr_subscr *vsub, const char *imei);
unsigned long vlr_timer_secs(struct vlr_instance *vlr, int timer);
unsigned long vlr_timer_secs(struct vlr_instance *vlr, int cs_timer, int ps_timer);
/* vlr_tdefs is pointing to msc_tdefs_vlr or sgsn_tdefs_vlr depending on the domain*/
extern struct osmo_tdef *vlr_tdefs;
int vlr_subscr_changed(struct vlr_subscr *vsub);
int vlr_subscr_purge(struct vlr_subscr *vsub) __attribute__((warn_unused_result));

View File

@@ -1048,9 +1048,9 @@ static void vty_dump_one_subscr(struct vty *vty, struct vlr_subscr *vsub,
VTY_NEWLINE);
}
if (!vlr_timer_secs(vsub->vlr, 3212)) {
MSC_VTY_DUMP(vty, offset, "Expires: never (T3212 is disabled)%s",
VTY_NEWLINE);
if (!vlr_timer_secs(vsub->vlr, 3212, 3312)) {
MSC_VTY_DUMP(vty, offset, "Expires: never (%s is disabled)%s",
vlr_is_cs(vsub->vlr) ? "T3212" : "T3312", VTY_NEWLINE);
} else if (vsub->expire_lu == VLR_SUBSCRIBER_NO_EXPIRATION) {
MSC_VTY_DUMP(vty, offset, "Expires: never%s",
VTY_NEWLINE);

View File

@@ -200,14 +200,28 @@ struct osmo_tdef msc_tdefs_vlr[] = {
{ /* terminator */ }
};
/* 3GPP TS 24.008, table 11.2 Mobility management timers (network-side) */
struct osmo_tdef sgsn_tdefs_vlr[] = {
{ .T = 3312, .default_val = 60, .unit = OSMO_TDEF_M, .desc = "Subscriber expiration timeout" },
{ .T = 3350, .default_val = 6, .desc = "Attach/RAU Complete Reallocation procedure" },
{ .T = 3360, .default_val = 6, .desc = "Authentication procedure" },
{ .T = 3370, .default_val = 6, .desc = "Identification procedure" },
{ /* terminator */ }
};
struct osmo_tdef *vlr_tdefs;
/* This is just a wrapper around the osmo_tdef API.
* TODO: we should start using osmo_tdef_fsm_inst_state_chg() */
unsigned long vlr_timer_secs(struct vlr_instance *vlr, int timer)
unsigned long vlr_timer_secs(struct vlr_instance *vlr, int cs_timer, int ps_timer)
{
/* NOTE: since we usually do not need more than one instance of the VLR,
* and since libosmocore's osmo_tdef API does not (yet) support dynamic
* configuration, we always use the global instance of msc_tdefs_vlr. */
return osmo_tdef_get(msc_tdefs_vlr, timer, OSMO_TDEF_S, 0);
if (vlr_is_cs(vlr))
return osmo_tdef_get(vlr_tdefs, cs_timer, OSMO_TDEF_S, 0);
else
return osmo_tdef_get(vlr_tdefs, ps_timer, OSMO_TDEF_S, 0);
}
/* return static buffer with printable name of VLR subscriber */
@@ -731,7 +745,7 @@ void vlr_subscr_enable_expire_lu(struct vlr_subscr *vsub)
/* Mark the subscriber as inactive if it stopped to do periodical location updates. */
if (osmo_clock_gettime(CLOCK_MONOTONIC, &now) == 0) {
vsub->expire_lu = now.tv_sec + vlr_timer_secs(vsub->vlr, 3212);
vsub->expire_lu = now.tv_sec + vlr_timer_secs(vsub->vlr, 3212, 3312);
} else {
LOGVSUBP(LOGL_ERROR, vsub,
"Could not enable Location Update expiry: unable to read current time\n");
@@ -748,7 +762,7 @@ void vlr_subscr_expire_lu(void *data)
/* Periodic location update might be disabled from the VTY,
* so we shall not expire subscribers until explicit IMSI Detach. */
if (!vlr_timer_secs(vlr, 3212))
if (!vlr_timer_secs(vlr, 3212, 3312))
goto done;
if (llist_empty(&vlr->subscribers))
@@ -1550,16 +1564,23 @@ struct vlr_instance *vlr_alloc(void *ctx, const struct vlr_ops *ops, bool is_ps)
/* reset shared timer definitions */
osmo_tdefs_reset(msc_tdefs_vlr);
osmo_tdefs_reset(sgsn_tdefs_vlr);
/* osmo_auth_fsm.c */
vlr_auth_fsm_init();
vlr_auth_fsm_init(is_ps);
/* osmo_lu_fsm.c */
vlr_lu_fsm_init();
vlr_lu_fsm_init(is_ps);
/* vlr_access_request_fsm.c */
vlr_parq_fsm_init();
vlr_parq_fsm_init(is_ps);
/* vlr_sgs_fsm.c */
vlr_sgs_fsm_init();
if (is_ps)
vlr_tdefs = sgsn_tdefs_vlr;
else
vlr_tdefs = msc_tdefs_vlr;
return vlr;
err_statg:

View File

@@ -20,6 +20,7 @@
*/
#include <osmocom/core/fsm.h>
#include <osmocom/core/tdef.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/vlr/vlr.h>
@@ -50,6 +51,18 @@ static const struct value_string proc_arq_vlr_event_names[] = {
{ 0, NULL }
};
struct osmo_tdef_state_timeout msc_parq_tdef_states[32] = {
[PR_ARQ_S_WAIT_CHECK_IMEI] = { .T = 3270 },
[PR_ARQ_S_WAIT_OBTAIN_IMSI] = { .T = 3270 },
};
struct osmo_tdef_state_timeout sgsn_parq_tdef_states[32] = {
[PR_ARQ_S_WAIT_CHECK_IMEI] = { .T = 3370 },
[PR_ARQ_S_WAIT_OBTAIN_IMSI] = { .T = 3370 },
};
struct osmo_tdef_state_timeout *parq_fsm_state_tdef;
struct proc_arq_priv {
struct vlr_instance *vlr;
struct vlr_subscr *vsub;
@@ -201,8 +214,7 @@ static void _proc_arq_vlr_post_trace(struct osmo_fsm_inst *fi)
if (0 /* IMEI check required */) {
/* Chck_IMEI_VLR */
vlr->ops.tx_id_req(par->msc_conn_ref, GSM_MI_TYPE_IMEI);
osmo_fsm_inst_state_chg(fi, PR_ARQ_S_WAIT_CHECK_IMEI,
vlr_timer_secs(vlr, 3270), 3270);
osmo_tdef_fsm_inst_state_chg(fi, PR_ARQ_S_WAIT_CHECK_IMEI, parq_fsm_state_tdef, vlr_tdefs, -1);
} else
_proc_arq_vlr_post_imei(fi);
}
@@ -404,8 +416,7 @@ static void proc_arq_vlr_fn_init(struct osmo_fsm_inst *fi,
/* TMSI was included, are we permitted to use it? */
if (vlr->cfg.parq_retrieve_imsi) {
/* Obtain_IMSI_VLR */
osmo_fsm_inst_state_chg(fi, PR_ARQ_S_WAIT_OBTAIN_IMSI,
vlr_timer_secs(vlr, 3270), 3270);
osmo_tdef_fsm_inst_state_chg(fi, PR_ARQ_S_WAIT_OBTAIN_IMSI, parq_fsm_state_tdef, vlr_tdefs, -1);
return;
} else {
/* Set User Error: Unidentified Subscriber */
@@ -803,8 +814,13 @@ static struct osmo_fsm upd_loc_child_vlr_fsm = {
};
#endif
void vlr_parq_fsm_init(void)
void vlr_parq_fsm_init(bool is_ps)
{
if (is_ps)
parq_fsm_state_tdef = sgsn_parq_tdef_states;
else
parq_fsm_state_tdef = msc_parq_tdef_states;
//OSMO_ASSERT(osmo_fsm_register(&upd_loc_child_vlr_fsm) == 0);
OSMO_ASSERT(osmo_fsm_register(&proc_arq_vlr_fsm) == 0);
}

View File

@@ -16,5 +16,5 @@ enum proc_arq_vlr_state {
PR_ARQ_S_DONE,
};
void vlr_parq_fsm_init(void);
void vlr_parq_fsm_init(bool is_ps);
void vlr_parq_fsm_set_log_subsys(int log_level);

View File

@@ -21,6 +21,7 @@
#include <osmocom/core/fsm.h>
#include <osmocom/core/tdef.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsup.h>
#include <osmocom/vlr/vlr.h>
@@ -41,6 +42,20 @@ static const struct value_string fsm_auth_event_names[] = {
{ 0, NULL }
};
struct osmo_tdef_state_timeout msc_auth_tdef_states[32] = {
[VLR_SUB_AS_WAIT_RESP] = { .T = 3260 },
[VLR_SUB_AS_WAIT_RESP_RESYNC] = { .T = 3260 },
[VLR_SUB_AS_WAIT_ID_IMSI] = { .T = 3270 },
};
struct osmo_tdef_state_timeout sgsn_auth_tdef_states[32] = {
[VLR_SUB_AS_WAIT_RESP] = { .T = 3360 },
[VLR_SUB_AS_WAIT_RESP_RESYNC] = { .T = 3360 },
[VLR_SUB_AS_WAIT_ID_IMSI] = { .T = 3370 },
};
struct osmo_tdef_state_timeout *auth_fsm_state_tdef;
/* private state of the auth_fsm_instance */
struct auth_fsm_priv {
struct vlr_subscr *vsub;
@@ -344,8 +359,7 @@ static void auth_fsm_needs_auth(struct osmo_fsm_inst *fi, uint32_t event, void *
GSM_29002_TIMER_M, 0);
} else {
/* go straight ahead with sending auth request */
osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
vlr_timer_secs(vsub->vlr, 3260), 3260);
osmo_tdef_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP, auth_fsm_state_tdef, vlr_tdefs, -1);
_vlr_subscr_authenticate(fi);
}
}
@@ -398,8 +412,8 @@ static void auth_fsm_wait_ai(struct osmo_fsm_inst *fi, uint32_t event,
return;
pass:
osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
vlr_timer_secs(vsub->vlr, 3260), 3260);
osmo_tdef_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP, auth_fsm_state_tdef, vlr_tdefs, -1);
_vlr_subscr_authenticate(fi);
}
@@ -421,9 +435,7 @@ static void auth_fsm_wait_auth_resp(struct osmo_fsm_inst *fi, uint32_t event,
if (!afp->by_imsi) {
vlr->ops.tx_id_req(vsub->msc_conn_ref,
GSM_MI_TYPE_IMSI);
osmo_fsm_inst_state_chg(fi,
VLR_SUB_AS_WAIT_ID_IMSI,
vlr_timer_secs(vlr, 3270), 3270);
osmo_tdef_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_ID_IMSI, auth_fsm_state_tdef, vlr_tdefs, -1);
} else {
auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_ILLEGAL_MS);
}
@@ -465,8 +477,7 @@ static void auth_fsm_wait_ai_resync(struct osmo_fsm_inst *fi,
switch (event) {
case VLR_AUTH_E_HLR_SAI_ACK:
vlr_subscr_update_tuples(vsub, gsup);
osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC,
vlr_timer_secs(vsub->vlr, 3260), 3260);
osmo_tdef_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC, auth_fsm_state_tdef, vlr_tdefs, -1);
_vlr_subscr_authenticate(fi);
break;
case VLR_AUTH_E_HLR_SAI_NACK:
@@ -497,9 +508,7 @@ static void auth_fsm_wait_auth_resp_resync(struct osmo_fsm_inst *fi,
if (!afp->by_imsi) {
vlr->ops.tx_id_req(vsub->msc_conn_ref,
GSM_MI_TYPE_IMSI);
osmo_fsm_inst_state_chg(fi,
VLR_SUB_AS_WAIT_ID_IMSI,
vlr_timer_secs(vlr, 3270), 3270);
osmo_tdef_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_ID_IMSI, auth_fsm_state_tdef, vlr_tdefs, -1);
} else {
/* Result = Aborted */
auth_fsm_term(fi, AUTH_FSM_FAILURE, GSM48_REJECT_SYNCH_FAILURE);
@@ -614,8 +623,13 @@ static struct osmo_fsm vlr_auth_fsm = {
.cleanup = auth_fsm_cleanup,
};
void vlr_auth_fsm_init(void)
void vlr_auth_fsm_init(bool is_ps)
{
if (is_ps)
auth_fsm_state_tdef = sgsn_auth_tdef_states;
else
auth_fsm_state_tdef = msc_auth_tdef_states;
OSMO_ASSERT(osmo_fsm_register(&vlr_auth_fsm) == 0);
}

View File

@@ -37,6 +37,6 @@ struct osmo_fsm_inst *auth_fsm_start(struct vlr_subscr *vsub,
bool is_r99,
bool is_utran);
void vlr_auth_fsm_init(void);
void vlr_auth_fsm_init(bool is_ps);
void vlr_auth_fsm_set_log_subsys(int log_level);
bool auth_try_reuse_tuple(struct vlr_subscr *vsub, uint8_t key_seq);

View File

@@ -20,6 +20,7 @@
*/
#include <osmocom/core/fsm.h>
#include <osmocom/core/tdef.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/vlr/vlr.h>
@@ -328,6 +329,20 @@ static const struct value_string lu_compl_vlr_event_names[] = {
{ 0, NULL }
};
struct osmo_tdef_state_timeout msc_lu_compl_tdef_states[32] = {
[LU_COMPL_VLR_S_WAIT_IMEI] = { .T = 3270 },
[LU_COMPL_VLR_S_WAIT_IMEI_TMSI] = { .T = 3270 },
[LU_COMPL_VLR_S_WAIT_TMSI_CNF] = { .T = 3250 },
};
struct osmo_tdef_state_timeout sgsn_lu_compl_tdef_states[32] = {
[LU_COMPL_VLR_S_WAIT_IMEI] = { .T = 3370 },
[LU_COMPL_VLR_S_WAIT_IMEI_TMSI] = { .T = 3370 },
[LU_COMPL_VLR_S_WAIT_TMSI_CNF] = { .T = 3350 },
};
struct osmo_tdef_state_timeout *lu_compl_fsm_state_tdef;
struct lu_compl_vlr_priv {
struct vlr_subscr *vsub;
void *msc_conn_ref;
@@ -431,8 +446,7 @@ static void lu_compl_vlr_new_tmsi(struct osmo_fsm_inst *fi)
return;
}
osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_TMSI_CNF,
vlr_timer_secs(vlr, 3250), 3250);
osmo_tdef_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_TMSI_CNF, lu_compl_fsm_state_tdef, vlr_tdefs, -1);
vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, vsub->tmsi_new, lcvp->lu_type);
}
@@ -455,11 +469,11 @@ static void lu_compl_vlr_wait_subscr_pres(struct osmo_fsm_inst *fi,
/* If imeisv_early is enabled: IMEI already retrieved and checked (vlr_loc_upd_node1_pre), don't do it again. */
if (vlr->cfg.check_imei_rqd && !vlr->cfg.retrieve_imeisv_early) {
/* Check IMEI VLR */
osmo_fsm_inst_state_chg(fi,
osmo_tdef_fsm_inst_state_chg(fi,
lcvp->assign_tmsi ?
LU_COMPL_VLR_S_WAIT_IMEI_TMSI
: LU_COMPL_VLR_S_WAIT_IMEI,
vlr_timer_secs(vlr, 3270), 3270);
lu_compl_fsm_state_tdef, vlr_tdefs, -1);
vlr->ops.tx_id_req(lcvp->msc_conn_ref, GSM_MI_TYPE_IMEI);
return;
}
@@ -665,6 +679,20 @@ static const struct value_string fsm_lu_event_names[] = {
{ 0, NULL }
};
struct osmo_tdef_state_timeout msc_lu_tdef_states[32] = {
[VLR_ULA_S_WAIT_IMEISV] = { .T = 3270 },
[VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY] = { .T = 3270 },
[VLR_ULA_S_WAIT_IMSI] = { .T = 3270 },
};
struct osmo_tdef_state_timeout sgsn_lu_tdef_states[32] = {
[VLR_ULA_S_WAIT_IMEISV] = { .T = 3370 },
[VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY] = { .T = 3370 },
[VLR_ULA_S_WAIT_IMSI] = { .T = 3370 },
};
struct osmo_tdef_state_timeout *lu_fsm_state_tdef;
struct lu_fsm_priv {
struct vlr_instance *vlr;
struct vlr_subscr *vsub;
@@ -942,7 +970,7 @@ static void vlr_loc_upd_node1_pre(struct osmo_fsm_inst *fi)
LOGPFSM(fi, "%s()\n", __func__);
if (vlr->cfg.check_imei_rqd && vlr->cfg.retrieve_imeisv_early) {
osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY, vlr_timer_secs(lfp->vlr, 3270), 3270);
osmo_tdef_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY, lu_fsm_state_tdef, vlr_tdefs, -1);
vlr_subscr_tx_req_check_imei(lfp->vsub);
} else {
vlr_loc_upd_node1(fi);
@@ -977,8 +1005,7 @@ static void vlr_loc_upd_want_imsi(struct osmo_fsm_inst *fi)
OSMO_ASSERT(lfp->vsub);
/* Obtain_IMSI_VLR */
osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMSI,
vlr_timer_secs(vlr, 3270), 3270);
osmo_tdef_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMSI, lu_fsm_state_tdef, vlr_tdefs, -1);
vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMSI);
/* will continue at vlr_loc_upd_node1_pre() once IMSI arrives */
}
@@ -1114,8 +1141,7 @@ static void lu_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event,
_start_lu_main(fi);
} else {
vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMEISV);
osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMEISV,
vlr_timer_secs(vlr, 3270), 3270);
osmo_tdef_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMEISV, lu_fsm_state_tdef, vlr_tdefs, -1);
}
}
@@ -1587,8 +1613,16 @@ void vlr_loc_update_cancel(struct osmo_fsm_inst *fi,
lu_fsm_failure(fi, gsm48_cause);
}
void vlr_lu_fsm_init(void)
void vlr_lu_fsm_init(bool is_ps)
{
if (is_ps) {
lu_fsm_state_tdef = sgsn_lu_tdef_states;
lu_compl_fsm_state_tdef = sgsn_lu_compl_tdef_states;
} else {
lu_fsm_state_tdef = msc_lu_tdef_states;
lu_compl_fsm_state_tdef = msc_lu_compl_tdef_states;
}
OSMO_ASSERT(osmo_fsm_register(&vlr_lu_fsm) == 0);
OSMO_ASSERT(osmo_fsm_register(&upd_hlr_vlr_fsm) == 0);
OSMO_ASSERT(osmo_fsm_register(&sub_pres_vlr_fsm) == 0);

View File

@@ -16,5 +16,5 @@ enum vlr_lu_state {
VLR_ULA_S_DONE
};
void vlr_lu_fsm_init(void);
void vlr_lu_fsm_init(bool is_ps);
void vlr_lu_fsm_set_log_subsys(int log_subsys);

View File

@@ -941,7 +941,7 @@ static void test_no_authen_subscr_expire()
vlr_subscr_put(vsub, __func__);
/* Let T3212 (periodic Location update timer) expire */
fake_time_passes(vlr_timer_secs(net->vlr, 3212) + 60 * 4, 0);
fake_time_passes(vlr_timer_secs(net->vlr, 3212, 3312) + 60 * 4, 0);
/* The subscriber should now be gone. */
vsub = vlr_subscr_find_by_imsi(net->vlr, imsi, __func__);