lynxis lazus submitted this change.

View Change

Approvals: fixeria: Looks good to me, but someone else must approve daniel: Looks good to me, approved Jenkins Builder: Verified
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, 220 insertions(+), 2 deletions(-)

diff --git a/src/libvlr/vlr.c b/src/libvlr/vlr.c
index 21f9fc6..919def3 100644
--- a/src/libvlr/vlr.c
+++ b/src/libvlr/vlr.c
@@ -1487,6 +1487,15 @@
}
}

+/* 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 ec459a1..4bed335 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,47 @@
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(vlr))
+ return 1;
+
+ /* PS: we have to resend the complete message 5x times, before failing */
+ lcvp->N++;
+ if (lcvp->N >= 5)
+ return 1;
+
+ LOGPFSML(fi, LOGL_ERROR, "LU Compl timeout T%d / N%d\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;
+ default:
+ OSMO_ASSERT(0);
+ 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),
@@ -586,6 +629,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 +638,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 +662,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 +758,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 +771,9 @@
bool is_r99;
bool is_utran;
bool assign_tmsi;
+
+ /*! count times timer T timed out */
+ int N;
};


@@ -1383,6 +1435,12 @@
}
}

+static void lu_fsm_wait_imsi_onenter(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),
@@ -1447,6 +1505,7 @@
S(VLR_ULA_S_WAIT_HLR_UPD) |
S(VLR_ULA_S_DONE),
.name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMSI),
+ .onenter = lu_fsm_wait_imsi_onenter,
.action = lu_fsm_wait_imsi,
},
[VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY] = {
@@ -1508,6 +1567,59 @@
vsub->lu_fsm = NULL;
}

+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;
+ struct vlr_subscr *vsub = lfp->vsub;
+
+ /* only PS requires resending, CS terminate FSM */
+ if (vlr_is_cs(vlr))
+ return 1;
+
+ /* PS: we have to resend the complete message 5x times, before failing */
+ if (++lfp->N >= 5) {
+ /* LU reject and terminate FSM */
+ uint8_t gsm48_cause;
+
+ switch (fi->state) {
+ case VLR_ULA_S_WAIT_IMSI:
+ case VLR_ULA_S_WAIT_CIPH:
+ gsm48_cause = GSM48_REJECT_MS_IDENTITY_NOT_DERVIVABLE;
+ break;
+ case VLR_ULA_S_WAIT_AUTH: /* HLR/GSUP timeout */
+ default:
+ gsm48_cause = GSM48_REJECT_NETWORK_FAILURE;
+ break;
+ }
+
+ lfp->vlr->ops.tx_lu_rej(lfp->msc_conn_ref, gsm48_cause, lfp->lu_type);
+ /* 1 will terminate the fsm */
+ return 1;
+ }
+
+ switch (fi->state) {
+ case VLR_ULA_S_WAIT_CIPH:
+ if (vlr_set_ciph_mode(vsub->vlr, fi, lfp->msc_conn_ref,
+ vsub->sec_ctx,
+ vsub->vlr->cfg.retrieve_imeisv_ciphered)) {
+ LOGPFSML(fi, LOGL_ERROR,
+ "Failed to re-send Ciphering Mode Command\n");
+ lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
+ return 0;
+ }
+ break;
+ 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,
@@ -1517,6 +1629,7 @@
.log_subsys = DLGLOBAL,
.event_names = fsm_lu_event_names,
.cleanup = fsm_lu_cleanup,
+ .timer_cb = fsm_lu_timer_cb,
};

static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi)
@@ -1525,8 +1638,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,
@@ -1575,6 +1688,102 @@
}
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 change 38490. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-Change-Id: Ie9ffeb140c9d354b3a0f4822e2619f623235add0
Gerrit-Change-Number: 38490
Gerrit-PatchSet: 14
Gerrit-Owner: lynxis lazus <lynxis@fe80.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann@sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu>
Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>