lynxis lazus has submitted this change. ( 
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, 220 insertions(+), 2 deletions(-)

Approvals:
  fixeria: Looks good to me, but someone else must approve
  daniel: Looks good to me, approved
  Jenkins Builder: Verified




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 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: merged
Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-Change-Id: Ie9ffeb140c9d354b3a0f4822e2619f623235add0
Gerrit-Change-Number: 38490
Gerrit-PatchSet: 14
Gerrit-Owner: lynxis lazus <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <[email protected]>
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: lynxis lazus <[email protected]>
Gerrit-Reviewer: neels <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>

Reply via email to