[MME] unify EPS Bearer Context Status (BCS) check for both active_flag=0 and 1

Previously, TAU procedure validated EPS Bearer Context Status (BCS)
only when active_flag == 0. When active_flag == 1, the MME skipped BCS
validation and sent TAU ACCEPT directly via InitialContextSetup.

This patch unifies BCS validation so both active_flag paths handle
bearer mismatches consistently. It also selects the correct S1AP
procedure (InitialContextSetup or DownlinkNASTransport) depending on
the UE active state.

Changes:
- emm-sm.c / sgsap-handler.c:
  * Always check EPS_BEARER_CONTEXT_STATUS_TYPE presence.
  * Invoke mme_send_delete_session_or_tau_accept() for both
    active_flag=0 and 1.
  * Send TAU ACCEPT directly only when BCS is not present.

- mme-path.c:
  * Select S1AP procedure in TAU ACCEPT based on active_flag.

- mme-s11-handler.c:
  * After Delete Session Response (OGS_GTP_DELETE_SEND_TAU_ACCEPT),
    send TAU ACCEPT using proper S1AP procedure by active_flag.

This aligns MME TAU behavior with 3GPP TS 24.301 section 5.3.3.0a,
ensuring consistent BCS synchronization regardless of UE activity.
This commit is contained in:
Sukchan Lee
2025-10-22 22:53:32 +09:00
parent b7cd0d6a7c
commit f3f010b36c
4 changed files with 68 additions and 54 deletions

View File

@@ -729,24 +729,27 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh); ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1; mme_ue->nhcc = 1;
ogs_info("[%s] TAU accept(active_flag=1)", ogs_info("[%s] KDF update(active_flag=1)",
mme_ue->imsi_bcd);
r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else if (!(mme_ue->tracking_area_update_request_presencemask &
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_TYPE)) {
ogs_info("[%s] TAU accept(NO Bearer Context Status)",
mme_ue->imsi_bcd); mme_ue->imsi_bcd);
}
/* check BCS regardless of active_flag */
if (mme_ue->tracking_area_update_request_presencemask &
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_TYPE) {
ogs_info("[%s] TAU accept(active_flag=%d, BCS check)",
mme_ue->imsi_bcd,
mme_ue->nas_eps.update.active_flag);
mme_send_delete_session_or_tau_accept(enb_ue, mme_ue);
} else {
ogs_info("[%s] TAU accept(active_flag=%d, No BCS)",
mme_ue->imsi_bcd,
mme_ue->nas_eps.update.active_flag);
r = nas_eps_send_tau_accept(mme_ue, r = nas_eps_send_tau_accept(mme_ue,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport); S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK); ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR); ogs_assert(r != OGS_ERROR);
} else {
ogs_info("[%s] TAU accept(WITH Bearer Context Status)",
mme_ue->imsi_bcd);
mme_send_delete_session_or_tau_accept(enb_ue, mme_ue);
} }
} else if (e->s1ap_code == } else if (e->s1ap_code ==
S1AP_ProcedureCode_id_uplinkNASTransport) { S1AP_ProcedureCode_id_uplinkNASTransport) {

View File

@@ -329,7 +329,7 @@ cleanup:
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* Function: mme_send_delete_session_or_tau_accept * Function: mme_send_delete_session_or_tau_accept
* ---------------------------------------------------------------------- * ----------------------------------------------------------------------
* - If active_flag == 0, check UE's EPS Bearer Context Status (BCS) * - Check UE's EPS Bearer Context Status (BCS) regardless of active_flag
* against MME's sessions before sending TAU ACCEPT. * against MME's sessions before sending TAU ACCEPT.
* - If UE does not report the default bearer EBI, delete that session. * - If UE does not report the default bearer EBI, delete that session.
* - Otherwise, send TAU ACCEPT immediately. * - Otherwise, send TAU ACCEPT immediately.
@@ -383,11 +383,21 @@ void mme_send_delete_session_or_tau_accept(enb_ue_t *enb_ue, mme_ue_t *mme_ue)
} }
if (deleted > 0) { if (deleted > 0) {
ogs_warn("[%s] Deleted %d session(s) due to BCS mismatch", ogs_warn("[%s] Deleted %d session(s) due to BCS mismatch, "
mme_ue->imsi_bcd, deleted); "active_flag=%d",
mme_ue->imsi_bcd, deleted,
mme_ue->nas_eps.update.active_flag);
} else { } else {
ogs_info("[%s] TAU accept(BCS match)", mme_ue->imsi_bcd); /*
* Choose S1AP procedure based on active_flag:
* - active_flag==1 : InitialContextSetup
* - active_flag==0 : DownlinkNASTransport
*/
ogs_info("[%s] Send TAU accept(BCS match, active_flag=%d)",
mme_ue->imsi_bcd, mme_ue->nas_eps.update.active_flag);
r = nas_eps_send_tau_accept(mme_ue, r = nas_eps_send_tau_accept(mme_ue,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport); S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK); ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR); ogs_assert(r != OGS_ERROR);

View File

@@ -886,8 +886,11 @@ void mme_s11_handle_delete_session_response(
GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION_BY_TAU, GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION_BY_TAU,
ogs_info("[%s] TAU accept(BCS mismatch)", mme_ue->imsi_bcd); ogs_info("[%s] Send TAU accept(BCS match, active_flag=%d)",
mme_ue->imsi_bcd, mme_ue->nas_eps.update.active_flag);
r = nas_eps_send_tau_accept(mme_ue, r = nas_eps_send_tau_accept(mme_ue,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport); S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK); ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR); ogs_assert(r != OGS_ERROR);

View File

@@ -150,25 +150,26 @@ void sgsap_handle_location_update_accept(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh); ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1; mme_ue->nhcc = 1;
ogs_info("[%s] LU accept + TAU accept(active_flag==1)", ogs_info("[%s] KDF update(active_flag=1)", mme_ue->imsi_bcd);
mme_ue->imsi_bcd); }
r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup); /* check BCS regardless of active_flag */
ogs_expect(r == OGS_OK); if (mme_ue->tracking_area_update_request_presencemask &
ogs_assert(r != OGS_ERROR); OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_TYPE) {
} else if (!(mme_ue->tracking_area_update_request_presencemask & ogs_info("[%s] LU accept + TAU accept(active_flag=%d, BCS)",
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_TYPE)) { mme_ue->imsi_bcd,
ogs_info("[%s] LU accept + TAU accept(NO Bearer Context Status)", mme_ue->nas_eps.update.active_flag);
mme_ue->imsi_bcd); mme_send_delete_session_or_tau_accept(enb_ue, mme_ue);
} else {
ogs_info("[%s] LU accept + TAU accept(active_flag=%d, No BCS)",
mme_ue->imsi_bcd,
mme_ue->nas_eps.update.active_flag);
r = nas_eps_send_tau_accept(mme_ue, r = nas_eps_send_tau_accept(mme_ue,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport); S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK); ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR); ogs_assert(r != OGS_ERROR);
} else {
ogs_info("[%s] LU accept + TAU accept"
"(WITH Bearer Context Status)",
mme_ue->imsi_bcd);
mme_send_delete_session_or_tau_accept(enb_ue, mme_ue);
} }
} else if (mme_ue->tracking_area_update_request_type == } else if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_UPLINK_NAS_TRANPORT) { MME_TAU_TYPE_UPLINK_NAS_TRANPORT) {
@@ -359,31 +360,30 @@ void sgsap_handle_location_update_reject(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh); ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1; mme_ue->nhcc = 1;
ogs_fatal("[%s] LU reject + TAU accept(active_flag==1)", ogs_info("[%s] KDF update(active_flag=1)", mme_ue->imsi_bcd);
mme_ue->imsi_bcd); }
r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup); /* check BCS regardless of active_flag */
ogs_expect(r == OGS_OK); if (mme_ue->tracking_area_update_request_presencemask &
ogs_assert(r != OGS_ERROR); OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_TYPE) {
} else if (!(mme_ue->tracking_area_update_request_presencemask & ogs_info("[%s] LU reject + TAU accept(active_flag=%d, BCS)",
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_TYPE)) { mme_ue->imsi_bcd,
ogs_fatal("[%s] LU reject + TAU accept" mme_ue->nas_eps.update.active_flag);
"(NO Bearer Context Status)", mme_send_delete_session_or_tau_accept(enb_ue, mme_ue);
mme_ue->imsi_bcd); } else {
ogs_info("[%s] LU reject + TAU accept(active_flag=%d, No BCS)",
mme_ue->imsi_bcd,
mme_ue->nas_eps.update.active_flag);
r = nas_eps_send_tau_accept(mme_ue, r = nas_eps_send_tau_accept(mme_ue,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport); S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK); ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR); ogs_assert(r != OGS_ERROR);
} else {
ogs_fatal("[%s] LU reject + TAU accept"
"(WITH Bearer Context Status)",
mme_ue->imsi_bcd);
mme_send_delete_session_or_tau_accept(enb_ue, mme_ue);
} }
} else if (mme_ue->tracking_area_update_request_type == } else if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_UPLINK_NAS_TRANPORT) { MME_TAU_TYPE_UPLINK_NAS_TRANPORT) {
ogs_debug(" Uplink NAS Transport"); ogs_info("[%s] LU reject + TAU accept(UplinkNASTransport)",
ogs_fatal("[%s] LU reject + TAU accept(UplinkNASTransport)",
mme_ue->imsi_bcd); mme_ue->imsi_bcd);
r = nas_eps_send_tau_accept(mme_ue, r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_downlinkNASTransport); S1AP_ProcedureCode_id_downlinkNASTransport);
@@ -391,9 +391,8 @@ void sgsap_handle_location_update_reject(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)
ogs_assert(r != OGS_ERROR); ogs_assert(r != OGS_ERROR);
} else if (mme_ue->tracking_area_update_request_type == } else if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_UNPROTECTED_INTEGRITY) { MME_TAU_TYPE_UNPROTECTED_INTEGRITY) {
ogs_fatal("[%s] LU reject + TAU accept(Unprotected Integrity)", ogs_info("[%s] LU reject + TAU accept(Unprotected Integrity)",
mme_ue->imsi_bcd); mme_ue->imsi_bcd);
ogs_debug(" Unprotected Integrity");
r = nas_eps_send_tau_accept(mme_ue, r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup); S1AP_ProcedureCode_id_InitialContextSetup);
ogs_expect(r == OGS_OK); ogs_expect(r == OGS_OK);
@@ -414,7 +413,6 @@ void sgsap_handle_location_update_reject(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)
*/ */
if (!mme_ue->nas_eps.update.active_flag && if (!mme_ue->nas_eps.update.active_flag &&
!MME_NEXT_P_TMSI_IS_AVAILABLE(mme_ue)) { !MME_NEXT_P_TMSI_IS_AVAILABLE(mme_ue)) {
ogs_fatal("NEXT = %d", MME_NEXT_P_TMSI_IS_AVAILABLE(mme_ue));
enb_ue->relcause.group = S1AP_Cause_PR_nas; enb_ue->relcause.group = S1AP_Cause_PR_nas;
enb_ue->relcause.cause = S1AP_CauseNas_normal_release; enb_ue->relcause.cause = S1AP_CauseNas_normal_release;
mme_send_release_access_bearer_or_ue_context_release(enb_ue); mme_send_release_access_bearer_or_ue_context_release(enb_ue);