aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmsc
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2021-04-27 18:20:15 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2021-04-29 14:22:33 +0200
commit6710670cb14a6bafb8c708e0ec673428a36a92bd (patch)
treec051f42f5347044223fe85ac4cd0a6282db69c0e /src/libmsc
parenta361cab54a6404572c76ac36e127fc3e3e4ceaab (diff)
Fill Last Used E-UTRAN PLMN Id when in CSFB
Since recently, osmo-bsc behaves strictly as per specs, meaning it will only send the "Cell selection indicator after release of all TCH and SDCCH IE" in RR Channel Release iff: * "Last Used E-UTRAN PLMN Id" was received in the CommonID sent MSC->BSC * "Last Used E-UTRAN PLMN Id" was received insider "old BSS to new BSS Information" in the HandoverRequest sent MSC->BSC. On the other hand, CSFB_Indicator from ClearCommand MSC->BSC is nw ignored and not taken into account. Hence, let's update osmo-msc to also behave correctly by sending the Last Used E-UTRAN PLMN ID at CommonID tx time to avoid regressions in CSFB support when running against newer osmo-bsc. Let's keep sending the CSFB Indicator in ClearCommand as we used too, in order to keep compatibility with older BSCs (as per spec). Related: SYS#5337 Change-Id: Ic5f175b179973d0a50d94f00e15f5a3e332605fc
Diffstat (limited to 'src/libmsc')
-rw-r--r--src/libmsc/gsm_04_08.c9
-rw-r--r--src/libmsc/msc_a.c5
-rw-r--r--src/libmsc/ran_msg_a.c6
-rw-r--r--src/libmsc/sgs_iface.c42
4 files changed, 59 insertions, 3 deletions
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index 63790598d..58ef074f4 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -1368,12 +1368,19 @@ int msc_vlr_tx_cm_serv_acc(void *msc_conn_ref, enum osmo_cm_service_type cm_serv
static int msc_vlr_tx_common_id(void *msc_conn_ref)
{
struct msc_a *msc_a = msc_conn_ref;
+ struct vlr_subscr *vsub = msc_a_vsub(msc_a);
struct ran_msg msg = {
.msg_type = RAN_MSG_COMMON_ID,
.common_id = {
- .imsi = msc_a_vsub(msc_a)->imsi,
+ .imsi = vsub->imsi,
+ .last_eutran_plmn_present = vsub->sgs.last_eutran_plmn_present,
},
};
+ if (vsub->sgs.last_eutran_plmn_present) {
+ memcpy(&msg.common_id.last_eutran_plmn, &vsub->sgs.last_eutran_plmn,
+ sizeof(vsub->sgs.last_eutran_plmn));
+ }
+
return msc_a_ran_down(msc_a, MSC_ROLE_I, &msg);
}
diff --git a/src/libmsc/msc_a.c b/src/libmsc/msc_a.c
index 0645c5434..daa5bc7f1 100644
--- a/src/libmsc/msc_a.c
+++ b/src/libmsc/msc_a.c
@@ -1648,8 +1648,13 @@ int msc_tx_common_id(struct msc_a *msc_a, enum msc_role to_role)
.msg_type = RAN_MSG_COMMON_ID,
.common_id = {
.imsi = vsub->imsi,
+ .last_eutran_plmn_present = vsub->sgs.last_eutran_plmn_present,
},
};
+ if (vsub->sgs.last_eutran_plmn_present) {
+ memcpy(&msg.common_id.last_eutran_plmn, &vsub->sgs.last_eutran_plmn,
+ sizeof(vsub->sgs.last_eutran_plmn));
+ }
return msc_a_ran_down(msc_a, to_role, &msg);
}
diff --git a/src/libmsc/ran_msg_a.c b/src/libmsc/ran_msg_a.c
index 2890076d0..4cce2899e 100644
--- a/src/libmsc/ran_msg_a.c
+++ b/src/libmsc/ran_msg_a.c
@@ -1218,7 +1218,11 @@ static struct msgb *_ran_a_encode(struct osmo_fsm_inst *caller_fi, const struct
return ran_a_make_assignment_command(caller_fi, &ran_enc_msg->assignment_command);
case RAN_MSG_COMMON_ID:
- return gsm0808_create_common_id(ran_enc_msg->common_id.imsi, NULL, NULL);
+ return gsm0808_create_common_id(ran_enc_msg->common_id.imsi, NULL,
+ ran_enc_msg->common_id.last_eutran_plmn_present ?
+ &ran_enc_msg->common_id.last_eutran_plmn :
+ NULL
+ );
case RAN_MSG_CIPHER_MODE_COMMAND:
return ran_a_make_cipher_mode_command(caller_fi, &ran_enc_msg->cipher_mode_command);
diff --git a/src/libmsc/sgs_iface.c b/src/libmsc/sgs_iface.c
index d13449d29..04302ae4d 100644
--- a/src/libmsc/sgs_iface.c
+++ b/src/libmsc/sgs_iface.c
@@ -608,12 +608,14 @@ static int sgs_rx_loc_upd_req(struct sgs_connection *sgc, struct msgb *msg, cons
char *mme_name;
struct vlr_sgs_cfg vlr_sgs_cfg;
struct vlr_subscr *vsub;
+ struct osmo_plmn_id last_eutran_plmn_buf, *last_eutran_plmn = NULL;
/* Check for lingering connections */
vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
if (vsub) {
subscr_conn_toss(vsub);
vlr_subscr_put(vsub, __func__);
+ vsub = NULL;
}
/* Determine MME-Name */
@@ -639,11 +641,29 @@ static int sgs_rx_loc_upd_req(struct sgs_connection *sgc, struct msgb *msg, cons
return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_MISSING_MAND_IE, msg, SGSAP_IE_LAI);
gsm48_decode_lai2(gsm48_lai, &new_lai);
+ /* 3GPP TS 23.272 sec 4.3.3 (CSFB):
+ * "During the SGs location update procedure, obtaining the last used LTE PLMN ID via TAI"
+ */
+ if (TLVP_PRES_LEN(tp, SGSAP_IE_TAI, 3)) {
+ last_eutran_plmn = &last_eutran_plmn_buf;
+ osmo_plmn_from_bcd(TLVP_VAL(tp, SGSAP_IE_TAI), last_eutran_plmn);
+ /* TODO: we could also gather the TAC from here, but we don't need it yet */
+ } else if (TLVP_PRES_LEN(tp, SGSAP_IE_EUTRAN_CGI, 3)) {
+ /* Since TAI is optional, let's try harder getting Last Used
+ * E-UTRAN PLMN ID by fetching it from E-UTRAN CGI */
+ last_eutran_plmn = &last_eutran_plmn_buf;
+ osmo_plmn_from_bcd(TLVP_VAL(tp, SGSAP_IE_EUTRAN_CGI), last_eutran_plmn);
+ /* TODO: we could also gather the ECI from here, but we don't need it yet */
+ } else {
+ LOGSGC(sgc, LOGL_INFO, "Receiving SGsAP-LOCATION-UPDATE-REQUEST without TAI nor "
+ "E-CGI IEs, fast fallback GERAN->EUTRAN won't be possible!\n");
+ }
+
/* Perform actual location update */
memcpy(vlr_sgs_cfg.timer, sgc->sgs->cfg.timer, sizeof(vlr_sgs_cfg.timer));
memcpy(vlr_sgs_cfg.counter, sgc->sgs->cfg.counter, sizeof(vlr_sgs_cfg.counter));
rc = vlr_sgs_loc_update(gsm_network->vlr, &vlr_sgs_cfg, sgs_tx_loc_upd_resp_cb, sgs_iface_tx_paging,
- sgs_tx_mm_info_cb, mme_name, type, imsi, &new_lai);
+ sgs_tx_mm_info_cb, mme_name, type, imsi, &new_lai, last_eutran_plmn);
if (rc != 0) {
resp = gsm29118_create_lu_rej(imsi, SGSAP_SGS_CAUSE_IMSI_UNKNOWN, NULL);
sgs_tx(sgc, resp);
@@ -905,6 +925,26 @@ static int sgs_rx_csfb_ind(struct sgs_connection *sgc, struct msgb *msg, const s
if (!vsub)
return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_IMSI_UNKNOWN, msg, SGSAP_IE_IMSI);
+ /* 3GPP TS 23.272 sec 4.3.3 (CSFB):
+ * "During the SGs location update procedure, obtaining the last used LTE PLMN ID via TAI"
+ */
+ vsub->sgs.last_eutran_plmn_present = TLVP_PRES_LEN(tp, SGSAP_IE_EUTRAN_CGI, 3);
+ if (TLVP_PRES_LEN(tp, SGSAP_IE_TAI, 3)) {
+ vsub->sgs.last_eutran_plmn_present = true;
+ osmo_plmn_from_bcd(TLVP_VAL(tp, SGSAP_IE_TAI), &vsub->sgs.last_eutran_plmn);
+ /* TODO: we could also gather the TAC from here, but we don't need it yet */
+ } else if (TLVP_PRES_LEN(tp, SGSAP_IE_EUTRAN_CGI, 3)) {
+ /* Since TAI is optional, let's try harder getting Last Used
+ * E-UTRAN PLMN ID by fetching it from E-UTRAN CGI */
+ vsub->sgs.last_eutran_plmn_present = true;
+ osmo_plmn_from_bcd(TLVP_VAL(tp, SGSAP_IE_EUTRAN_CGI), &vsub->sgs.last_eutran_plmn);
+ /* TODO: we could also gather the ECI from here, but we don't need it yet */
+ } else if (!vsub->sgs.last_eutran_plmn_present) {
+ LOGSGC(sgc, LOGL_INFO, "Receiving SGsAP-MO-CSFB-INDICATION without TAI nor "
+ "E-CGI IEs, and they are not known from previous SGsAP-LOCATION-UPDATE-REQUEST. "
+ "Fast fallback GERAN->EUTRAN won't be possible!\n");
+ }
+
/* Check for lingering connections */
subscr_conn_toss(vsub);