lynxis lazus has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-msc/+/38490?usp=email )
Change subject: vlr: add PS support ......................................................................
vlr: add PS support
Add vlr_ra_update() similar to vlr_lu_update(). Implement resending of GMM PDUs. While CS has a reliable connection between the MS and MSC, the MS and SGSN doesn't have such connection. The PDU is resend N times before the LU fsm is failing.
Change-Id: Ie9ffeb140c9d354b3a0f4822e2619f623235add0 --- M src/libvlr/vlr.c M src/libvlr/vlr_lu_fsm.c 2 files changed, 214 insertions(+), 2 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/90/38490/1
diff --git a/src/libvlr/vlr.c b/src/libvlr/vlr.c index c7d17f8..b8650c7 100644 --- a/src/libvlr/vlr.c +++ b/src/libvlr/vlr.c @@ -1480,6 +1480,16 @@ } }
+/* SGSN->VLR: Subscriber has provided ATTACH/RAU Complete */ +int vlr_subscr_rx_rau_complete(struct vlr_subscr *vsub) +{ + if (!vsub->lu_fsm) + return -EINVAL; + + return osmo_fsm_inst_dispatch(vsub->lu_fsm, + VLR_ULA_E_NEW_TMSI_ACK, NULL); +} + bool vlr_subscr_expire(struct vlr_subscr *vsub) { if (vsub->lu_complete) { diff --git a/src/libvlr/vlr_lu_fsm.c b/src/libvlr/vlr_lu_fsm.c index fca8347..fa0b83b 100644 --- a/src/libvlr/vlr_lu_fsm.c +++ b/src/libvlr/vlr_lu_fsm.c @@ -354,6 +354,7 @@ uint8_t cause; bool assign_tmsi; enum vlr_lu_type lu_type; + int N; /*! counter of timeouts */ };
static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi); @@ -407,6 +408,7 @@ OSMO_ASSERT(vlr);
OSMO_ASSERT(event == LU_COMPL_VLR_E_START); + lcvp->N = 0;
/* TODO: National Roaming restrictions? */ /* TODO: Roaming restriction due to unsupported feature in subscriber @@ -564,6 +566,42 @@ vlr_lu_compl_fsm_success(fi); }
+static void vlr_lu_compl_fsm_reset_n(struct osmo_fsm_inst *fi, uint32_t prev_state) +{ + struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi); + lcvp->N = 0; +} + +static int lu_compl_vlr_timeout(struct osmo_fsm_inst *fi) { + struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi); + struct vlr_instance *vlr = lcvp->vsub->vlr; + struct vlr_subscr *vsub = lcvp->vsub; + + /* on cs: terminate the FSM */ + if (vlr_is_cs(lcvp->vsub->vlr)) + return 1; + + /* PS: we have to resend the complete message 5x times, before failing */ + if (++lcvp->N >= 5) + return 1; + + LOGPFSML(fi, LOGL_ERROR, "LU Compl timeout %i / %i \n", fi->T, lcvp->N); + + switch (fi->state) { + case LU_COMPL_VLR_S_WAIT_IMEI: + case LU_COMPL_VLR_S_WAIT_IMEI_TMSI: + vlr->ops.tx_id_req(lcvp->msc_conn_ref, GSM_MI_TYPE_IMEI); + break; + case LU_COMPL_VLR_S_WAIT_TMSI_CNF: + vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, vsub->tmsi_new, lcvp->lu_type); + break; + } + + osmo_timer_schedule(&fi->timer, vlr_timer_secs(vlr, fi->T, fi->T), 0); + + return 0; +} + static const struct osmo_fsm_state lu_compl_vlr_states[] = { [LU_COMPL_VLR_S_INIT] = { .in_event_mask = S(LU_COMPL_VLR_E_START), @@ -579,6 +617,7 @@ S(LU_COMPL_VLR_S_WAIT_TMSI_CNF) | S(LU_COMPL_VLR_S_DONE), .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_SUB_PRES), + .onenter = vlr_lu_compl_fsm_reset_n, .action = lu_compl_vlr_wait_subscr_pres, }, [LU_COMPL_VLR_S_WAIT_IMEI] = { @@ -586,6 +625,7 @@ S(LU_COMPL_VLR_E_IMEI_CHECK_NACK), .out_state_mask = S(LU_COMPL_VLR_S_DONE), .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI), + .onenter = vlr_lu_compl_fsm_reset_n, .action = lu_compl_vlr_wait_imei, }, [LU_COMPL_VLR_S_WAIT_IMEI_TMSI] = { @@ -594,12 +634,14 @@ .out_state_mask = S(LU_COMPL_VLR_S_DONE) | S(LU_COMPL_VLR_S_WAIT_TMSI_CNF), .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI_TMSI), + .onenter = vlr_lu_compl_fsm_reset_n, .action = lu_compl_vlr_wait_imei, }, [LU_COMPL_VLR_S_WAIT_TMSI_CNF] = { .in_event_mask = S(LU_COMPL_VLR_E_NEW_TMSI_ACK), .out_state_mask = S(LU_COMPL_VLR_S_DONE), .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_TMSI_CNF), + .onenter = vlr_lu_compl_fsm_reset_n, .action = lu_compl_vlr_wait_tmsi, }, [LU_COMPL_VLR_S_DONE] = { @@ -616,6 +658,7 @@ .allstate_action = NULL, .log_subsys = DLGLOBAL, .event_names = lu_compl_vlr_event_names, + .timer_cb = lu_compl_vlr_timeout, };
static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi) @@ -711,6 +754,8 @@ uint32_t tmsi; struct osmo_location_area_id old_lai; struct osmo_location_area_id new_lai; + struct osmo_routing_area_id old_rai; + struct osmo_routing_area_id new_rai; bool authentication_required; /* is_ciphering_to_be_attempted: true when any A5/n > 0 are enabled. Ciphering is allowed, always attempt to get Auth Info from * the HLR. */ @@ -722,6 +767,9 @@ bool is_r99; bool is_utran; bool assign_tmsi; + + /*! count times timer T timed out */ + int N; };
@@ -1386,6 +1434,12 @@ } }
+static void lu_fsm_reset_n(struct osmo_fsm_inst *fi, uint32_t prev_state) +{ + struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi); + lfp->N = 0; +} + static const struct osmo_fsm_state vlr_lu_fsm_states[] = { [VLR_ULA_S_IDLE] = { .in_event_mask = S(VLR_ULA_E_UPDATE_LA), @@ -1450,6 +1504,7 @@ S(VLR_ULA_S_WAIT_HLR_UPD) | S(VLR_ULA_S_DONE), .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMSI), + .onenter = lu_fsm_reset_n, .action = lu_fsm_wait_imsi, }, [VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY] = { @@ -1511,6 +1566,54 @@ vsub->lu_fsm = NULL; }
+static void fsm_lu_preterm(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause) +{ + struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi); + uint8_t gsm48_cause; + + if (vlr_is_cs(lfp->vlr)) + return; + + if (cause != OSMO_FSM_TERM_TIMEOUT) + return; + + switch (fi->state) { + case VLR_ULA_S_WAIT_IMSI: + gsm48_cause = GSM48_REJECT_MS_IDENTITY_NOT_DERVIVABLE; + break; + case VLR_ULA_S_WAIT_AUTH: + default: + gsm48_cause = GSM48_REJECT_NETWORK_FAILURE; + } + + lfp->vlr->ops.tx_lu_rej(lfp->msc_conn_ref, gsm48_cause, lfp->lu_type); +} + +int fsm_lu_timer_cb(struct osmo_fsm_inst *fi) +{ + struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi); + struct vlr_instance *vlr = lfp->vlr; + + /* only PS requires resending, CS termiante FSM */ + if (vlr_is_cs(vlr)) + return 1; + + /* PS: we have to resend the complete message 5x times, before failing */ + if (++lfp->N >= 5) + return 1; + + switch (fi->state) { + case VLR_ULA_S_WAIT_IMSI: + vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMSI); + break; + } + + osmo_timer_schedule(&fi->timer, vlr_timer_secs(vlr, fi->T, fi->T), 0); + + return 0; +} + + static struct osmo_fsm vlr_lu_fsm = { .name = "vlr_lu_fsm", .states = vlr_lu_fsm_states, @@ -1520,6 +1623,8 @@ .log_subsys = DLGLOBAL, .event_names = fsm_lu_event_names, .cleanup = fsm_lu_cleanup, + .pre_term = fsm_lu_preterm, + .timer_cb = fsm_lu_timer_cb, };
static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi) @@ -1528,8 +1633,8 @@ return (struct lu_fsm_priv*)fi->priv; }
-struct osmo_fsm_inst * -vlr_loc_update(struct osmo_fsm_inst *parent, +static struct osmo_fsm_inst * +_vlr_loc_update(struct osmo_fsm_inst *parent, uint32_t parent_event_success, uint32_t parent_event_failure, void *parent_event_data, @@ -1579,6 +1684,103 @@ } fi->priv = lfp;
+ return fi; +} + +struct osmo_fsm_inst * +vlr_loc_update(struct osmo_fsm_inst *parent, + uint32_t parent_event_success, + uint32_t parent_event_failure, + void *parent_event_data, + struct vlr_instance *vlr, void *msc_conn_ref, + enum vlr_lu_type type, uint32_t tmsi, const char *imsi, + const struct osmo_location_area_id *old_lai, + const struct osmo_location_area_id *new_lai, + bool authentication_required, + bool is_ciphering_to_be_attempted, + bool is_ciphering_required, + uint8_t key_seq, + bool is_r99, bool is_utran, + bool assign_tmsi) +{ + struct osmo_fsm_inst *fi = _vlr_loc_update( + parent, + parent_event_success, + parent_event_failure, + parent_event_data, + vlr, msc_conn_ref, + type, tmsi, imsi, + old_lai, + new_lai, + authentication_required, + is_ciphering_to_be_attempted, + is_ciphering_required, + key_seq, + is_r99, is_utran, + assign_tmsi); + + if (!fi) + return NULL; + + LOGPFSM(fi, "rev=%s net=%s%s%s\n", + is_r99 ? "R99" : "GSM", + is_utran ? "UTRAN" : "GERAN", + (authentication_required || is_ciphering_to_be_attempted) ? + " Auth" : " (no Auth)", + (authentication_required || is_ciphering_to_be_attempted) ? + (is_ciphering_to_be_attempted ? "+Ciph" : " (no Ciph)") + : ""); + + if (is_utran && !authentication_required) + LOGPFSML(fi, LOGL_ERROR, + "Authentication off on UTRAN network. Good luck.\n"); + + osmo_fsm_inst_dispatch(fi, VLR_ULA_E_UPDATE_LA, NULL); + + return fi; +} + + +struct osmo_fsm_inst * +vlr_ra_update(struct osmo_fsm_inst *parent, + uint32_t parent_event_success, + uint32_t parent_event_failure, + void *parent_event_data, + struct vlr_instance *vlr, void *msc_conn_ref, + enum vlr_lu_type type, uint32_t tmsi, const char *imsi, + const struct osmo_routing_area_id *old_rai, + const struct osmo_routing_area_id *new_rai, + bool authentication_required, + bool is_ciphering_to_be_attempted, + bool is_ciphering_required, + uint8_t key_seq, + bool is_r99, bool is_utran, + bool assign_tmsi) +{ + struct lu_fsm_priv *lfp; + struct osmo_fsm_inst *fi = _vlr_loc_update( + parent, + parent_event_success, + parent_event_failure, + parent_event_data, + vlr, msc_conn_ref, + type, tmsi, imsi, + &old_rai->lac, + &new_rai->lac, + authentication_required, + is_ciphering_to_be_attempted, + is_ciphering_required, + key_seq, + is_r99, is_utran, + assign_tmsi); + + if (!fi) + return NULL; + + lfp = fi->priv; + lfp->old_rai = *old_rai; + lfp->new_rai = *new_rai; + LOGPFSM(fi, "rev=%s net=%s%s%s\n", is_r99 ? "R99" : "GSM", is_utran ? "UTRAN" : "GERAN",