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",
--
To view, visit
https://gerrit.osmocom.org/c/osmo-msc/+/38490?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-Change-Id: Ie9ffeb140c9d354b3a0f4822e2619f623235add0
Gerrit-Change-Number: 38490
Gerrit-PatchSet: 1
Gerrit-Owner: lynxis lazus <lynxis(a)fe80.eu>