diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2021-04-27 18:20:15 +0200 |
---|---|---|
committer | Pau Espin Pedrol <pespin@sysmocom.de> | 2021-04-29 14:22:33 +0200 |
commit | 6710670cb14a6bafb8c708e0ec673428a36a92bd (patch) | |
tree | c051f42f5347044223fe85ac4cd0a6282db69c0e /src/libmsc | |
parent | a361cab54a6404572c76ac36e127fc3e3e4ceaab (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.c | 9 | ||||
-rw-r--r-- | src/libmsc/msc_a.c | 5 | ||||
-rw-r--r-- | src/libmsc/ran_msg_a.c | 6 | ||||
-rw-r--r-- | src/libmsc/sgs_iface.c | 42 |
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); |