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
This commit is contained in:
parent
a361cab54a
commit
6710670cb1
|
@ -220,6 +220,8 @@ struct ran_msg {
|
||||||
} cipher_mode_reject;
|
} cipher_mode_reject;
|
||||||
struct {
|
struct {
|
||||||
const char *imsi;
|
const char *imsi;
|
||||||
|
bool last_eutran_plmn_present;
|
||||||
|
struct osmo_plmn_id last_eutran_plmn;
|
||||||
} common_id;
|
} common_id;
|
||||||
struct {
|
struct {
|
||||||
enum gsm48_reject_value cause;
|
enum gsm48_reject_value cause;
|
||||||
|
|
|
@ -193,6 +193,8 @@ struct vlr_subscr {
|
||||||
vlr_sgs_lu_mminfo_cb_t mminfo_cb;
|
vlr_sgs_lu_mminfo_cb_t mminfo_cb;
|
||||||
enum sgsap_service_ind paging_serv_ind;
|
enum sgsap_service_ind paging_serv_ind;
|
||||||
struct osmo_timer_list Ts5;
|
struct osmo_timer_list Ts5;
|
||||||
|
bool last_eutran_plmn_present;
|
||||||
|
struct osmo_plmn_id last_eutran_plmn;
|
||||||
} sgs;
|
} sgs;
|
||||||
|
|
||||||
struct osmo_gsm48_classmark classmark;
|
struct osmo_gsm48_classmark classmark;
|
||||||
|
@ -398,6 +400,8 @@ void vlr_subscr_set_imsi(struct vlr_subscr *vsub, const char *imsi);
|
||||||
void vlr_subscr_set_imei(struct vlr_subscr *vsub, const char *imei);
|
void vlr_subscr_set_imei(struct vlr_subscr *vsub, const char *imei);
|
||||||
void vlr_subscr_set_imeisv(struct vlr_subscr *vsub, const char *imeisv);
|
void vlr_subscr_set_imeisv(struct vlr_subscr *vsub, const char *imeisv);
|
||||||
void vlr_subscr_set_msisdn(struct vlr_subscr *vsub, const char *msisdn);
|
void vlr_subscr_set_msisdn(struct vlr_subscr *vsub, const char *msisdn);
|
||||||
|
void vlr_subscr_set_last_used_eutran_plmn_id(struct vlr_subscr *vsub,
|
||||||
|
const struct osmo_plmn_id *last_eutran_plmn);
|
||||||
|
|
||||||
bool vlr_subscr_matches_imsi(struct vlr_subscr *vsub, const char *imsi);
|
bool vlr_subscr_matches_imsi(struct vlr_subscr *vsub, const char *imsi);
|
||||||
bool vlr_subscr_matches_tmsi(struct vlr_subscr *vsub, uint32_t tmsi);
|
bool vlr_subscr_matches_tmsi(struct vlr_subscr *vsub, uint32_t tmsi);
|
||||||
|
|
|
@ -97,7 +97,7 @@ void vlr_sgs_reset(struct vlr_instance *vlr);
|
||||||
int vlr_sgs_loc_update(struct vlr_instance *vlr, struct vlr_sgs_cfg *cfg,
|
int vlr_sgs_loc_update(struct vlr_instance *vlr, struct vlr_sgs_cfg *cfg,
|
||||||
vlr_sgs_lu_response_cb_t response_cb, vlr_sgs_lu_paging_cb_t paging_cb,
|
vlr_sgs_lu_response_cb_t response_cb, vlr_sgs_lu_paging_cb_t paging_cb,
|
||||||
vlr_sgs_lu_mminfo_cb_t mminfo_cb, char *mme_name, enum vlr_lu_type type, const char *imsi,
|
vlr_sgs_lu_mminfo_cb_t mminfo_cb, char *mme_name, enum vlr_lu_type type, const char *imsi,
|
||||||
struct osmo_location_area_id *new_lai);
|
struct osmo_location_area_id *new_lai, struct osmo_plmn_id *last_eutran_plmn);
|
||||||
void vlr_sgs_loc_update_acc_sent(struct vlr_subscr *vsub);
|
void vlr_sgs_loc_update_acc_sent(struct vlr_subscr *vsub);
|
||||||
void vlr_sgs_loc_update_rej_sent(struct vlr_subscr *vsub);
|
void vlr_sgs_loc_update_rej_sent(struct vlr_subscr *vsub);
|
||||||
void vlr_sgs_detach(struct vlr_instance *vlr, const char *imsi, bool eps);
|
void vlr_sgs_detach(struct vlr_instance *vlr, const char *imsi, bool eps);
|
||||||
|
|
|
@ -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)
|
static int msc_vlr_tx_common_id(void *msc_conn_ref)
|
||||||
{
|
{
|
||||||
struct msc_a *msc_a = msc_conn_ref;
|
struct msc_a *msc_a = msc_conn_ref;
|
||||||
|
struct vlr_subscr *vsub = msc_a_vsub(msc_a);
|
||||||
struct ran_msg msg = {
|
struct ran_msg msg = {
|
||||||
.msg_type = RAN_MSG_COMMON_ID,
|
.msg_type = RAN_MSG_COMMON_ID,
|
||||||
.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);
|
return msc_a_ran_down(msc_a, MSC_ROLE_I, &msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
.msg_type = RAN_MSG_COMMON_ID,
|
||||||
.common_id = {
|
.common_id = {
|
||||||
.imsi = vsub->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, to_role, &msg);
|
return msc_a_ran_down(msc_a, to_role, &msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
return ran_a_make_assignment_command(caller_fi, &ran_enc_msg->assignment_command);
|
||||||
|
|
||||||
case RAN_MSG_COMMON_ID:
|
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:
|
case RAN_MSG_CIPHER_MODE_COMMAND:
|
||||||
return ran_a_make_cipher_mode_command(caller_fi, &ran_enc_msg->cipher_mode_command);
|
return ran_a_make_cipher_mode_command(caller_fi, &ran_enc_msg->cipher_mode_command);
|
||||||
|
|
|
@ -608,12 +608,14 @@ static int sgs_rx_loc_upd_req(struct sgs_connection *sgc, struct msgb *msg, cons
|
||||||
char *mme_name;
|
char *mme_name;
|
||||||
struct vlr_sgs_cfg vlr_sgs_cfg;
|
struct vlr_sgs_cfg vlr_sgs_cfg;
|
||||||
struct vlr_subscr *vsub;
|
struct vlr_subscr *vsub;
|
||||||
|
struct osmo_plmn_id last_eutran_plmn_buf, *last_eutran_plmn = NULL;
|
||||||
|
|
||||||
/* Check for lingering connections */
|
/* Check for lingering connections */
|
||||||
vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
|
vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
|
||||||
if (vsub) {
|
if (vsub) {
|
||||||
subscr_conn_toss(vsub);
|
subscr_conn_toss(vsub);
|
||||||
vlr_subscr_put(vsub, __func__);
|
vlr_subscr_put(vsub, __func__);
|
||||||
|
vsub = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine MME-Name */
|
/* 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);
|
return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_MISSING_MAND_IE, msg, SGSAP_IE_LAI);
|
||||||
gsm48_decode_lai2(gsm48_lai, &new_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 */
|
/* Perform actual location update */
|
||||||
memcpy(vlr_sgs_cfg.timer, sgc->sgs->cfg.timer, sizeof(vlr_sgs_cfg.timer));
|
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));
|
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,
|
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) {
|
if (rc != 0) {
|
||||||
resp = gsm29118_create_lu_rej(imsi, SGSAP_SGS_CAUSE_IMSI_UNKNOWN, NULL);
|
resp = gsm29118_create_lu_rej(imsi, SGSAP_SGS_CAUSE_IMSI_UNKNOWN, NULL);
|
||||||
sgs_tx(sgc, resp);
|
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)
|
if (!vsub)
|
||||||
return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_IMSI_UNKNOWN, msg, SGSAP_IE_IMSI);
|
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 */
|
/* Check for lingering connections */
|
||||||
subscr_conn_toss(vsub);
|
subscr_conn_toss(vsub);
|
||||||
|
|
||||||
|
|
|
@ -476,6 +476,23 @@ void vlr_subscr_set_msisdn(struct vlr_subscr *vsub, const char *msisdn)
|
||||||
vsub->imsi, vsub->msisdn);
|
vsub->imsi, vsub->msisdn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vlr_subscr_set_last_used_eutran_plmn_id(struct vlr_subscr *vsub,
|
||||||
|
const struct osmo_plmn_id *last_eutran_plmn)
|
||||||
|
{
|
||||||
|
if (!vsub)
|
||||||
|
return;
|
||||||
|
if (last_eutran_plmn) {
|
||||||
|
vsub->sgs.last_eutran_plmn_present = true;
|
||||||
|
memcpy(&vsub->sgs.last_eutran_plmn, last_eutran_plmn, sizeof(*last_eutran_plmn));
|
||||||
|
} else {
|
||||||
|
vsub->sgs.last_eutran_plmn_present = false;
|
||||||
|
}
|
||||||
|
DEBUGP(DVLR, "set Last E-UTRAN PLMN ID on subscriber: %s\n",
|
||||||
|
vsub->sgs.last_eutran_plmn_present ?
|
||||||
|
osmo_plmn_name(&vsub->sgs.last_eutran_plmn) :
|
||||||
|
"(none)");
|
||||||
|
}
|
||||||
|
|
||||||
bool vlr_subscr_matches_imsi(struct vlr_subscr *vsub, const char *imsi)
|
bool vlr_subscr_matches_imsi(struct vlr_subscr *vsub, const char *imsi)
|
||||||
{
|
{
|
||||||
return vsub && imsi && vsub->imsi[0] && !strcmp(vsub->imsi, imsi);
|
return vsub && imsi && vsub->imsi[0] && !strcmp(vsub->imsi, imsi);
|
||||||
|
|
|
@ -68,11 +68,12 @@ void vlr_sgs_reset(struct vlr_instance *vlr)
|
||||||
* \param[in] type location update type (normal or IMSI attach).
|
* \param[in] type location update type (normal or IMSI attach).
|
||||||
* \param[in] imsi mobile identity (IMSI).
|
* \param[in] imsi mobile identity (IMSI).
|
||||||
* \param[in] new_lai identifier of the new location area.
|
* \param[in] new_lai identifier of the new location area.
|
||||||
|
* \param[in] last_eutran_plnm_id Last E-UTRAN PLMN ID (can be NULL).
|
||||||
* \returns 0 in case of success, -EINVAL in case of error. */
|
* \returns 0 in case of success, -EINVAL in case of error. */
|
||||||
int vlr_sgs_loc_update(struct vlr_instance *vlr, struct vlr_sgs_cfg *cfg,
|
int vlr_sgs_loc_update(struct vlr_instance *vlr, struct vlr_sgs_cfg *cfg,
|
||||||
vlr_sgs_lu_response_cb_t response_cb, vlr_sgs_lu_paging_cb_t paging_cb,
|
vlr_sgs_lu_response_cb_t response_cb, vlr_sgs_lu_paging_cb_t paging_cb,
|
||||||
vlr_sgs_lu_mminfo_cb_t mminfo_cb, char *mme_name, enum vlr_lu_type type, const char *imsi,
|
vlr_sgs_lu_mminfo_cb_t mminfo_cb, char *mme_name, enum vlr_lu_type type, const char *imsi,
|
||||||
struct osmo_location_area_id *new_lai)
|
struct osmo_location_area_id *new_lai, struct osmo_plmn_id *last_eutran_plmn)
|
||||||
{
|
{
|
||||||
struct vlr_subscr *vsub = NULL;
|
struct vlr_subscr *vsub = NULL;
|
||||||
|
|
||||||
|
@ -93,6 +94,7 @@ int vlr_sgs_loc_update(struct vlr_instance *vlr, struct vlr_sgs_cfg *cfg,
|
||||||
vsub->sgs.paging_cb = paging_cb;
|
vsub->sgs.paging_cb = paging_cb;
|
||||||
vsub->sgs.mminfo_cb = mminfo_cb;
|
vsub->sgs.mminfo_cb = mminfo_cb;
|
||||||
vlr_subscr_set_imsi(vsub, imsi);
|
vlr_subscr_set_imsi(vsub, imsi);
|
||||||
|
vlr_subscr_set_last_used_eutran_plmn_id(vsub, last_eutran_plmn);
|
||||||
osmo_strlcpy(vsub->sgs.mme_name, mme_name, sizeof(vsub->sgs.mme_name));
|
osmo_strlcpy(vsub->sgs.mme_name, mme_name, sizeof(vsub->sgs.mme_name));
|
||||||
|
|
||||||
osmo_fsm_inst_dispatch(vsub->sgs_fsm, SGS_UE_E_RX_LU_FROM_MME, NULL);
|
osmo_fsm_inst_dispatch(vsub->sgs_fsm, SGS_UE_E_RX_LU_FROM_MME, NULL);
|
||||||
|
|
Loading…
Reference in New Issue