[MME] unify TAU procedure handling and BCS check across all S1AP cases(#4112, #4113, #4117)

This patch consolidates the TAU handling logic for both
initialUEMessage and uplinkNASTransport cases, ensuring that the
EPS Bearer Context Status (BCS) check is always performed regardless
of active_flag or S1AP procedure type.

Key changes:
- Removed duplicated TAU handling code paths in emm-sm.c.
- Commonized KDF derivation and BCS validation under a single block.
- Introduced mme_ue->tracking_area_update_accept_proc to store
  the selected S1AP procedure for TAU ACCEPT transmission.
- When e->s1ap_code == initialUEMessage and active_flag == 1,
  TAU ACCEPT is sent via InitialContextSetup; otherwise via
  DownlinkNASTransport.
- Applied the stored proc consistently across all handlers:
  mme-path.c, mme-s11-handler.c, mme-s6a-handler.c, and sgsap-handler.c.
- Added fallback to DownlinkNASTransport if proc is not set.
- Cleared tracking_area_update_accept_proc after use to avoid reuse.

This ensures consistent TAU behavior for both initialUEMessage and
uplinkNASTransport flows, unified BCS mismatch handling
This commit is contained in:
Sukchan Lee 2025-10-25 21:31:45 +09:00
parent 7803c39be6
commit ef140ce0d2
7 changed files with 110 additions and 185 deletions

View file

@ -170,7 +170,7 @@ int ogs_asn_BIT_STRING_to_ip(BIT_STRING_t *bit_string, ogs_ip_t *ip)
} else if (bit_string->size == OGS_IPV6_LEN) {
ip->ipv6 = 1;
memcpy(&ip->addr6, bit_string->buf, OGS_IPV6_LEN);
ogs_debug(" IPv6[%s]", OGS_INET_NTOP(&ip->addr6, buf));
ogs_debug(" IPv6[%s]", OGS_INET6_NTOP(&ip->addr6, buf));
} else {
ogs_error("ogs_asn_BIT_STRING_to_ip(size=%d) failed", bit_string->size);
return OGS_ERROR;
@ -204,7 +204,7 @@ int ogs_asn_ip_to_BIT_STRING(ogs_ip_t *ip, BIT_STRING_t *bit_string)
bit_string->size = OGS_IPV6_LEN;
bit_string->buf = CALLOC(bit_string->size, sizeof(uint8_t));
memcpy(bit_string->buf, &ip->addr6, OGS_IPV6_LEN);
ogs_debug(" IPv6[%s]", OGS_INET_NTOP(&ip->addr6, buf));
ogs_debug(" IPv6[%s]", OGS_INET6_NTOP(&ip->addr6, buf));
} else {
ogs_error("No IPv4 or IPv6");
return OGS_ERROR;

View file

@ -682,6 +682,14 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
message->emm.tracking_area_update_request.
eps_bearer_context_status.value;
/* Determine S1AP procedure and store it for reuse */
mme_ue->tracking_area_update_accept_proc =
S1AP_ProcedureCode_id_downlinkNASTransport;
if (e->s1ap_code == S1AP_ProcedureCode_id_initialUEMessage &&
mme_ue->nas_eps.update.active_flag)
mme_ue->tracking_area_update_accept_proc =
S1AP_ProcedureCode_id_InitialContextSetup;
/* Update CSMAP from Tracking area update request */
mme_ue->csmap = mme_csmap_find_by_tai(&mme_ue->tai);
if (mme_ue->csmap &&
@ -692,76 +700,48 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e,
mme_ue->nas_eps.update.value ==
OGS_NAS_EPS_UPDATE_TYPE_COMBINED_TA_LA_UPDATING_WITH_IMSI_ATTACH)) {
if (e->s1ap_code == S1AP_ProcedureCode_id_initialUEMessage)
mme_ue->tracking_area_update_request_type =
MME_TAU_TYPE_INITIAL_UE_MESSAGE;
else if (e->s1ap_code ==
S1AP_ProcedureCode_id_uplinkNASTransport)
mme_ue->tracking_area_update_request_type =
MME_TAU_TYPE_UPLINK_NAS_TRANPORT;
else {
ogs_error("Invalid Procedure Code[%d]", (int)e->s1ap_code);
break;
}
ogs_assert(OGS_OK ==
sgsap_send_location_update_request(mme_ue));
} else {
if (e->s1ap_code == S1AP_ProcedureCode_id_initialUEMessage) {
ogs_debug(" Initial UE Message");
if (mme_ue->nas_eps.update.active_flag) {
if (mme_ue->nas_eps.update.active_flag) {
/*
* TS33.401
* 7 Security procedures between UE and EPS access network elements
* 7.2 Handling of user-related keys in E-UTRAN
* 7.2.7 Key handling for the TAU procedure when registered in E-UTRAN
*
* If the "active flag" is set in the TAU request message or
* the MME chooses to establish radio bearers when there is pending downlink
* UP data or pending downlink signalling, radio bearers will be established
* as part of the TAU procedure and a KeNB derivation is necessary.
*/
ogs_kdf_kenb(mme_ue->kasme, mme_ue->ul_count.i32,
mme_ue->kenb);
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1;
/*
* TS33.401
* 7 Security procedures between UE and EPS access network elements
* 7.2 Handling of user-related keys in E-UTRAN
* 7.2.7 Key handling for the TAU procedure when registered in E-UTRAN
*
* If the "active flag" is set in the TAU request message or
* the MME chooses to establish radio bearers when there is pending downlink
* UP data or pending downlink signalling, radio bearers will be established
* as part of the TAU procedure and a KeNB derivation is necessary.
*/
ogs_kdf_kenb(mme_ue->kasme, mme_ue->ul_count.i32,
mme_ue->kenb);
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1;
ogs_info("[%s] KDF update(active_flag=1)",
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,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}
} else if (e->s1ap_code ==
S1AP_ProcedureCode_id_uplinkNASTransport) {
ogs_info("[%s] TAU accept(UplinkNASTransport)",
ogs_info("[%s] KDF update(active_flag=1)",
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,
S1AP_ProcedureCode_id_downlinkNASTransport);
mme_ue->tracking_area_update_accept_proc);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else {
ogs_error("Invalid Procedure Code[%d]", (int)e->s1ap_code);
break;
}
/*

View file

@ -431,12 +431,10 @@ struct mme_ue_s {
ogs_nas_detach_type_t detach;
} nas_eps;
#define MME_TAU_TYPE_INITIAL_UE_MESSAGE 1
#define MME_TAU_TYPE_UPLINK_NAS_TRANPORT 2
#define MME_TAU_TYPE_UNPROTECTED_INTEGRITY 3
uint8_t tracking_area_update_request_type;
uint64_t tracking_area_update_request_presencemask;
uint16_t tracking_area_update_request_ebcs_value;
S1AP_ProcedureCode_t tracking_area_update_accept_proc;
/* 1. MME initiated detach request to the UE.
* (nas_eps.type = MME_EPS_TYPE_DETACH_REQUEST_TO_UE)

View file

@ -396,9 +396,7 @@ void mme_send_delete_session_or_tau_accept(enb_ue_t *enb_ue, mme_ue_t *mme_ue)
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,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport);
mme_ue->tracking_area_update_accept_proc);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}

View file

@ -889,9 +889,7 @@ void mme_s11_handle_delete_session_response(
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,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport);
mme_ue->tracking_area_update_accept_proc);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);

View file

@ -127,6 +127,10 @@ uint8_t mme_s6a_handle_ula(
return OGS_NAS_EMM_CAUSE_NO_EPS_BEARER_CONTEXT_ACTIVATED;
}
/* Determine S1AP procedure and store it for reuse */
mme_ue->tracking_area_update_accept_proc =
S1AP_ProcedureCode_id_InitialContextSetup;
/* Update CSMAP from Tracking area update request */
mme_ue->csmap = mme_csmap_find_by_tai(&mme_ue->tai);
if (mme_ue->csmap &&
@ -137,14 +141,12 @@ uint8_t mme_s6a_handle_ula(
mme_ue->nas_eps.update.value ==
OGS_NAS_EPS_UPDATE_TYPE_COMBINED_TA_LA_UPDATING_WITH_IMSI_ATTACH)) {
mme_ue->tracking_area_update_request_type =
MME_TAU_TYPE_UNPROTECTED_INTEGRITY;
ogs_assert(OGS_OK == sgsap_send_location_update_request(mme_ue));
} else {
ogs_info("[%s] TAU accept(Diameter ULA)", mme_ue->imsi_bcd);
r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup);
mme_ue->tracking_area_update_accept_proc);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}

View file

@ -129,67 +129,42 @@ void sgsap_handle_location_update_accept(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST) {
if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_INITIAL_UE_MESSAGE) {
ogs_debug(" Iniital UE Message");
if (mme_ue->nas_eps.update.active_flag) {
if (mme_ue->nas_eps.update.active_flag) {
/*
* TS33.401
* 7 Security procedures between UE and EPS access network elements
* 7.2 Handling of user-related keys in E-UTRAN
* 7.2.7 Key handling for the TAU procedure when registered in E-UTRAN
*
* If the "active flag" is set in the TAU request message or
* the MME chooses to establish radio bearers when there is pending downlink
* UP data or pending downlink signalling, radio bearers will be established
* as part of the TAU procedure and a KeNB derivation is necessary.
*/
ogs_kdf_kenb(mme_ue->kasme, mme_ue->ul_count.i32,
mme_ue->kenb);
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1;
/*
* TS33.401
* 7 Security procedures between UE and EPS access network elements
* 7.2 Handling of user-related keys in E-UTRAN
* 7.2.7 Key handling for the TAU procedure when registered in E-UTRAN
*
* If the "active flag" is set in the TAU request message or
* the MME chooses to establish radio bearers when there is pending downlink
* UP data or pending downlink signalling, radio bearers will be established
* as part of the TAU procedure and a KeNB derivation is necessary.
*/
ogs_kdf_kenb(mme_ue->kasme, mme_ue->ul_count.i32,
mme_ue->kenb);
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1;
ogs_info("[%s] KDF update(active_flag=1)", mme_ue->imsi_bcd);
}
ogs_info("[%s] KDF update(active_flag=1)", 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] LU accept + TAU accept(active_flag=%d, BCS)",
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] 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,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}
} else if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_UPLINK_NAS_TRANPORT) {
ogs_info("[%s] LU accept + accept(UplinkNASTransport)",
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] LU accept + TAU accept(active_flag=%d, BCS)",
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] 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,
S1AP_ProcedureCode_id_downlinkNASTransport);
mme_ue->tracking_area_update_accept_proc);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_UNPROTECTED_INTEGRITY) {
ogs_info("[%s] LU accept + TAU accept(Unprotected Integrity)",
mme_ue->imsi_bcd);
r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup);
ogs_expect(r == OGS_OK);
} else {
ogs_error("Invalid TAU Type[%d]",
mme_ue->tracking_area_update_request_type);
return;
}
/*
@ -339,67 +314,41 @@ void sgsap_handle_location_update_reject(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST) {
if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_INITIAL_UE_MESSAGE) {
ogs_debug(" Iniital UE Message");
if (mme_ue->nas_eps.update.active_flag) {
if (mme_ue->nas_eps.update.active_flag) {
/*
* TS33.401
* 7 Security procedures between UE and EPS access network elements
* 7.2 Handling of user-related keys in E-UTRAN
* 7.2.7 Key handling for the TAU procedure when registered in E-UTRAN
*
* If the "active flag" is set in the TAU request message or
* the MME chooses to establish radio bearers when there is pending downlink
* UP data or pending downlink signalling, radio bearers will be established
* as part of the TAU procedure and a KeNB derivation is necessary.
*/
ogs_kdf_kenb(mme_ue->kasme, mme_ue->ul_count.i32,
mme_ue->kenb);
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1;
/*
* TS33.401
* 7 Security procedures between UE and EPS access network elements
* 7.2 Handling of user-related keys in E-UTRAN
* 7.2.7 Key handling for the TAU procedure when registered in E-UTRAN
*
* If the "active flag" is set in the TAU request message or
* the MME chooses to establish radio bearers when there is pending downlink
* UP data or pending downlink signalling, radio bearers will be established
* as part of the TAU procedure and a KeNB derivation is necessary.
*/
ogs_kdf_kenb(mme_ue->kasme, mme_ue->ul_count.i32,
mme_ue->kenb);
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->kenb, mme_ue->nh);
mme_ue->nhcc = 1;
ogs_info("[%s] KDF update(active_flag=1)", mme_ue->imsi_bcd);
}
ogs_info("[%s] KDF update(active_flag=1)", 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] LU reject + TAU accept(active_flag=%d, BCS)",
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] 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,
mme_ue->nas_eps.update.active_flag ?
S1AP_ProcedureCode_id_InitialContextSetup :
S1AP_ProcedureCode_id_downlinkNASTransport);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
}
} else if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_UPLINK_NAS_TRANPORT) {
ogs_info("[%s] LU reject + TAU accept(UplinkNASTransport)",
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] LU reject + TAU accept(active_flag=%d, BCS)",
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] 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,
S1AP_ProcedureCode_id_downlinkNASTransport);
mme_ue->tracking_area_update_accept_proc);
ogs_expect(r == OGS_OK);
ogs_assert(r != OGS_ERROR);
} else if (mme_ue->tracking_area_update_request_type ==
MME_TAU_TYPE_UNPROTECTED_INTEGRITY) {
ogs_info("[%s] LU reject + TAU accept(Unprotected Integrity)",
mme_ue->imsi_bcd);
r = nas_eps_send_tau_accept(mme_ue,
S1AP_ProcedureCode_id_InitialContextSetup);
ogs_expect(r == OGS_OK);
} else {
ogs_error("Invalid TAU Type[%d]",
mme_ue->tracking_area_update_request_type);
return;
}
/*