From fc8c807da29b49d3ccb03f69c81c61e0fa60f7db Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Tue, 23 Nov 2021 14:19:30 +0900 Subject: [PATCH] [SMF] fix the crash during IMS calls (#1238) If PFCP is not deactivated, some eNBs send an GTP error indication. To solve the problem, SMF deactivates the bearer that will be deleted. --- lib/pfcp/context.c | 48 +++++++--- lib/pfcp/xact.h | 3 + src/smf/binding.c | 37 +++++++- src/smf/context.h | 2 +- src/smf/gtp-path.c | 4 +- src/smf/n4-handler.c | 197 +++++++++++++++++++++++++++++++++++------- src/smf/pfcp-path.c | 45 +++++++++- src/smf/pfcp-path.h | 6 +- src/smf/s5c-handler.c | 105 ++++++++++++---------- 9 files changed, 352 insertions(+), 95 deletions(-) diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index d1324d4a7..83529afe6 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -841,18 +841,25 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess) ogs_assert(sess); ogs_pool_alloc(&ogs_pfcp_pdr_pool, &pdr); - ogs_assert(pdr); + if (pdr == NULL) { + ogs_error("pdr_pool() failed"); + return NULL; + } memset(pdr, 0, sizeof *pdr); + ogs_pool_alloc(&sess->pdr_id_pool, &pdr->id_node); + if (pdr->id_node == NULL) { + ogs_error("pdr_id_pool() failed"); + ogs_pool_free(&ogs_pfcp_pdr_pool, pdr); + return NULL; + } + pdr->obj.type = OGS_PFCP_OBJ_PDR_TYPE; pdr->index = ogs_pool_index(&ogs_pfcp_pdr_pool, pdr); ogs_assert(pdr->index > 0 && pdr->index <= ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR); - ogs_pool_alloc(&sess->pdr_id_pool, &pdr->id_node); - ogs_assert(pdr->id_node); - pdr->id = *(pdr->id_node); ogs_assert(pdr->id > 0 && pdr->id <= OGS_MAX_NUM_OF_PDR); @@ -1018,11 +1025,18 @@ ogs_pfcp_far_t *ogs_pfcp_far_add(ogs_pfcp_sess_t *sess) ogs_assert(sess); ogs_pool_alloc(&ogs_pfcp_far_pool, &far); - ogs_assert(far); + if (far == NULL) { + ogs_error("far_pool() failed"); + return NULL; + } memset(far, 0, sizeof *far); ogs_pool_alloc(&sess->far_id_pool, &far->id_node); - ogs_assert(far->id_node); + if (far->id_node == NULL) { + ogs_error("far_id_pool() failed"); + ogs_pool_free(&ogs_pfcp_far_pool, far); + return NULL; + } far->id = *(far->id_node); ogs_assert(far->id > 0 && far->id <= OGS_MAX_NUM_OF_FAR); @@ -1229,11 +1243,18 @@ ogs_pfcp_urr_t *ogs_pfcp_urr_add(ogs_pfcp_sess_t *sess) ogs_assert(sess); ogs_pool_alloc(&ogs_pfcp_urr_pool, &urr); - ogs_assert(urr); + if (urr == NULL) { + ogs_error("urr_pool() failed"); + return NULL; + } memset(urr, 0, sizeof *urr); ogs_pool_alloc(&sess->urr_id_pool, &urr->id_node); - ogs_assert(urr->id_node); + if (urr->id_node == NULL) { + ogs_error("urr_id_pool() failed"); + ogs_pool_free(&ogs_pfcp_urr_pool, urr); + return NULL; + } urr->id = *(urr->id_node); ogs_assert(urr->id > 0 && urr->id <= OGS_MAX_NUM_OF_URR); @@ -1307,11 +1328,18 @@ ogs_pfcp_qer_t *ogs_pfcp_qer_add(ogs_pfcp_sess_t *sess) ogs_assert(sess); ogs_pool_alloc(&ogs_pfcp_qer_pool, &qer); - ogs_assert(qer); + if (qer == NULL) { + ogs_error("qer_pool() failed"); + return NULL; + } memset(qer, 0, sizeof *qer); ogs_pool_alloc(&sess->qer_id_pool, &qer->id_node); - ogs_assert(qer->id_node); + if (qer->id_node == NULL) { + ogs_error("qer_id_pool() failed"); + ogs_pool_free(&ogs_pfcp_qer_pool, qer); + return NULL; + } qer->id = *(qer->id_node); ogs_assert(qer->id > 0 && qer->id <= OGS_MAX_NUM_OF_QER); diff --git a/lib/pfcp/xact.h b/lib/pfcp/xact.h index 9df2f8d4b..c6cfa62db 100644 --- a/lib/pfcp/xact.h +++ b/lib/pfcp/xact.h @@ -66,6 +66,9 @@ typedef struct ogs_pfcp_xact_s { void *assoc_xact; /**< Associated GTP transaction */ ogs_pkbuf_t *gtpbuf; /**< GTP packet buffer */ + uint8_t gtp_pti; /**< GTP Procedure transaction identity */ + uint8_t gtp_cause; /**< GTP Cause Value */ + void *assoc_stream; /**< Associated SBI session */ bool epc; /**< EPC or 5GC */ diff --git a/src/smf/binding.c b/src/smf/binding.c index 03fc64856..0d524297a 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -48,7 +48,9 @@ static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) } ogs_assert(OGS_OK == smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_REMOVE)); + bearer, NULL, OGS_PFCP_MODIFY_REMOVE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); break; case OGS_GTP_UPDATE_BEARER_REQUEST_TYPE: ogs_error("[%s] No Update Bearer Response", smf_ue->imsi_bcd); @@ -143,6 +145,13 @@ void smf_bearer_binding(smf_sess_t *sess) continue; } + if (ogs_list_count(&sess->bearer_list) >= + OGS_MAX_NUM_OF_BEARER) { + ogs_error("Bearer Overflow[%d]", + ogs_list_count(&sess->bearer_list)); + continue; + } + bearer = smf_bearer_add(sess); ogs_assert(bearer); @@ -323,7 +332,9 @@ void smf_bearer_binding(smf_sess_t *sess) ogs_assert(OGS_OK == smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_CREATE)); + bearer, NULL, OGS_PFCP_MODIFY_CREATE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); } else { ogs_gtp_tft_t tft; @@ -368,9 +379,20 @@ void smf_bearer_binding(smf_sess_t *sess) continue; } + /* + * TS23.214 + * 6.3.1.7 Procedures with modification of bearer + * p50 + * 2. ... + * For "PGW/MME initiated bearer deactivation procedure", + * PGW-C shall indicate PGW-U to stop counting and stop + * forwarding downlink packets for the affected bearer(s). + */ ogs_assert(OGS_OK == - smf_gtp_send_delete_bearer_request( - bearer, OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + smf_epc_pfcp_send_bearer_modification_request( + bearer, NULL, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, OGS_GTP_CAUSE_UNDEFINED_VALUE)); } else { ogs_error("Invalid Type[%d]", pcc_rule->type); @@ -445,6 +467,13 @@ void smf_qos_flow_binding(smf_sess_t *sess) continue; } + if (ogs_list_count(&sess->bearer_list) >= + OGS_MAX_NUM_OF_BEARER) { + ogs_error("QosFlow Overflow[%d]", + ogs_list_count(&sess->bearer_list)); + continue; + } + qos_flow = smf_qos_flow_add(sess); ogs_assert(qos_flow); diff --git a/src/smf/context.h b/src/smf/context.h index e7d3e1b4e..e2ddfc843 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -231,7 +231,7 @@ typedef struct smf_sess_s { char *sm_context_ref; /* smContextRef */ uint8_t psi; /* PDU session identity */ - uint8_t pti; /* Procedure transaction identity */ + uint8_t pti; /* 5GS-NAS : Procedure transaction identity */ char *sm_context_status_uri; /* SmContextStatusNotification */ struct { diff --git a/src/smf/gtp-path.c b/src/smf/gtp-path.c index 895da1970..862690a32 100644 --- a/src/smf/gtp-path.c +++ b/src/smf/gtp-path.c @@ -510,7 +510,9 @@ static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) ogs_assert(OGS_OK == smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_REMOVE)); + bearer, NULL, OGS_PFCP_MODIFY_REMOVE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); break; default: ogs_error("GTP Timeout : IMSI[%s] Message-Type[%d]", diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index 45b293ff3..9baca056f 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -19,6 +19,7 @@ #include "context.h" #include "timer.h" +#include "s5c-build.h" #include "pfcp-path.h" #include "gtp-path.h" #include "n4-handler.h" @@ -230,8 +231,14 @@ void smf_5gc_n4_handle_session_modification_response( /* 'stream' could be NULL in smf_qos_flow_binding() */ stream = xact->assoc_stream; - /* If smf_5gc_pfcp_send_qos_flow_modification_request() is called */ - qos_flow = xact->data; + if (flags & OGS_PFCP_MODIFY_SESSION) { + /* If smf_5gc_pfcp_send_session_modification_request() is called */ + + } else { + /* If smf_5gc_pfcp_send_qos_flow_modification_request() is called */ + qos_flow = xact->data; + ogs_assert(qos_flow); + } ogs_pfcp_xact_commit(xact); @@ -411,6 +418,8 @@ void smf_5gc_n4_handle_session_modification_response( } else if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) { smf_n1_n2_message_transfer_param_t param; + ogs_assert(qos_flow); + memset(¶m, 0, sizeof(param)); param.state = SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION; param.n1smbuf = gsm_build_qos_flow_modification_command( @@ -432,6 +441,7 @@ void smf_5gc_n4_handle_session_modification_response( ogs_pkbuf_t *n1smbuf = NULL, *n2smbuf = NULL; ogs_assert(stream); + ogs_assert(qos_flow); n1smbuf = gsm_build_qos_flow_modification_command( qos_flow, sess->pti, @@ -464,6 +474,8 @@ void smf_5gc_n4_handle_session_modification_response( } else if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) { smf_n1_n2_message_transfer_param_t param; + ogs_assert(qos_flow); + memset(¶m, 0, sizeof(param)); param.state = SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION; param.n1smbuf = gsm_build_qos_flow_modification_command( @@ -510,6 +522,8 @@ void smf_5gc_n4_handle_session_modification_response( } if (flags & OGS_PFCP_MODIFY_NETWORK_REQUESTED) { + ogs_assert(qos_flow); + memset(¶m, 0, sizeof(param)); param.state = SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION; param.n1smbuf = gsm_build_qos_flow_modification_command( @@ -528,6 +542,7 @@ void smf_5gc_n4_handle_session_modification_response( ogs_pkbuf_t *n1smbuf = NULL, *n2smbuf = NULL; ogs_assert(stream); + ogs_assert(qos_flow); n1smbuf = gsm_build_qos_flow_modification_command( qos_flow, sess->pti, @@ -612,7 +627,6 @@ void smf_5gc_n4_handle_session_deletion_response( return; } - ogs_assert(sess); if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) { @@ -730,24 +744,27 @@ void smf_epc_n4_handle_session_establishment_response( ogs_assert(far); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { + smf_bearer_t *pdr_bearer = NULL; + if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) ogs_pfcp_far_teid_hash_set(far); - bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); - if (bearer) { + pdr_bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); + if (pdr_bearer) { ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup && pdr->f_teid_len) { - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr); - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr6); + if (pdr_bearer->pgw_s5u_addr) + ogs_freeaddrinfo(pdr_bearer->pgw_s5u_addr); + if (pdr_bearer->pgw_s5u_addr) + ogs_freeaddrinfo(pdr_bearer->pgw_s5u_addr6); ogs_assert(OGS_OK == ogs_pfcp_f_teid_to_sockaddr( &pdr->f_teid, pdr->f_teid_len, - &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6)); - bearer->pgw_s5u_teid = pdr->f_teid.teid; + &pdr_bearer->pgw_s5u_addr, + &pdr_bearer->pgw_s5u_addr6)); + pdr_bearer->pgw_s5u_teid = pdr->f_teid.teid; } } } else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) { @@ -784,23 +801,28 @@ void smf_epc_n4_handle_session_establishment_response( ogs_assert(OGS_OK == smf_gtp_send_create_session_response(sess, gtp_xact)); if (sess->gtp_rat_type == OGS_GTP_RAT_TYPE_WLAN) { + /* + * TS23.214 + * 6.3.1.7 Procedures with modification of bearer + * p50 + * 2. ... + * For "PGW/MME initiated bearer deactivation procedure", + * PGW-C shall indicate PGW-U to stop counting and stop + * forwarding downlink packets for the affected bearer(s). + */ smf_ue_t *smf_ue = NULL; smf_sess_t *eutran_sess = NULL; smf_ue = sess->smf_ue; ogs_assert(smf_ue); - ogs_assert(sess->session.name); eutran_sess = smf_sess_find_by_apn( - smf_ue, sess->session.name, OGS_GTP_RAT_TYPE_EUTRAN); + smf_ue, sess->session.name, OGS_GTP_RAT_TYPE_EUTRAN); if (eutran_sess) { - smf_bearer_t *eutran_linked_bearer = - ogs_list_first(&eutran_sess->bearer_list); - ogs_assert(eutran_linked_bearer); - ogs_assert(OGS_OK == - smf_gtp_send_delete_bearer_request( - eutran_linked_bearer, + smf_epc_pfcp_send_session_modification_request( + eutran_sess, NULL, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, OGS_GTP_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP)); } @@ -816,6 +838,9 @@ void smf_epc_n4_handle_session_modification_response( int i; smf_bearer_t *bearer = NULL; + ogs_gtp_xact_t *gtp_xact = NULL; + uint8_t gtp_pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; + uint8_t gtp_cause = OGS_GTP_CAUSE_UNDEFINED_VALUE; uint64_t flags = 0; uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; @@ -824,11 +849,21 @@ void smf_epc_n4_handle_session_modification_response( ogs_assert(xact); ogs_assert(rsp); - bearer = xact->data; - ogs_assert(bearer); + if (flags & OGS_PFCP_MODIFY_SESSION) { + /* If smf_epc_pfcp_send_session_modification_request() is called */ + + } else { + /* If smf_epc_pfcp_send_bearer_modification_request() is called */ + bearer = xact->data; + ogs_assert(bearer); + } flags = xact->modify_flags; ogs_assert(flags); + gtp_xact = xact->assoc_xact; + gtp_pti = xact->gtp_pti; + gtp_cause = xact->gtp_cause; + ogs_pfcp_xact_commit(xact); if (!sess) { @@ -864,22 +899,28 @@ void smf_epc_n4_handle_session_modification_response( ogs_assert(far); if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { + smf_bearer_t *pdr_bearer = NULL; + if (far->dst_if == OGS_PFCP_INTERFACE_CP_FUNCTION) ogs_pfcp_far_teid_hash_set(far); - ogs_assert(sess->pfcp_node); - if (sess->pfcp_node->up_function_features.ftup && - pdr->f_teid_len) { - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr); - if (bearer->pgw_s5u_addr) - ogs_freeaddrinfo(bearer->pgw_s5u_addr6); + pdr_bearer = smf_bearer_find_by_pdr_id(sess, pdr->id); + if (pdr_bearer) { + ogs_assert(sess->pfcp_node); + if (sess->pfcp_node->up_function_features.ftup && + pdr->f_teid_len) { + if (pdr_bearer->pgw_s5u_addr) + ogs_freeaddrinfo(pdr_bearer->pgw_s5u_addr); + if (pdr_bearer->pgw_s5u_addr) + ogs_freeaddrinfo(pdr_bearer->pgw_s5u_addr6); - ogs_assert(OGS_OK == - ogs_pfcp_f_teid_to_sockaddr( - &pdr->f_teid, pdr->f_teid_len, - &bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6)); - bearer->pgw_s5u_teid = pdr->f_teid.teid; + ogs_assert(OGS_OK == + ogs_pfcp_f_teid_to_sockaddr( + &pdr->f_teid, pdr->f_teid_len, + &pdr_bearer->pgw_s5u_addr, + &pdr_bearer->pgw_s5u_addr6)); + pdr_bearer->pgw_s5u_teid = pdr->f_teid.teid; + } } } else if (pdr->src_if == OGS_PFCP_INTERFACE_CP_FUNCTION) { ogs_assert(OGS_ERROR != ogs_pfcp_setup_pdr_gtpu_node(pdr)); @@ -892,11 +933,101 @@ void smf_epc_n4_handle_session_modification_response( } if (flags & OGS_PFCP_MODIFY_REMOVE) { + ogs_assert(bearer); smf_bearer_remove(bearer); } else if (flags & OGS_PFCP_MODIFY_CREATE) { + ogs_assert(bearer); ogs_assert(OGS_OK == smf_gtp_send_create_bearer_request(bearer)); + } else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) { + /* + * TS23.214 + * 6.3.1.7 Procedures with modification of bearer + * p50 + * 2. ... + * For "PGW/MME initiated bearer deactivation procedure", + * PGW-C shall indicate PGW-U to stop counting and stop + * forwarding downlink packets for the affected bearer(s). + */ + if (gtp_xact) { + /* + * 1. MME sends Bearer Resource Command to SGW/SMF. + * 2. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME + * 3. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF + */ + ogs_gtp_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + int rv; + + ogs_assert(bearer); + + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.teid = sess->sgw_s5c_teid; + h.type = OGS_GTP_DELETE_BEARER_REQUEST_TYPE; + + pkbuf = smf_s5c_build_delete_bearer_request( + h.type, bearer, gtp_pti, gtp_cause); + ogs_expect_or_return(pkbuf); + + rv = ogs_gtp_xact_update_tx(gtp_xact, &h, pkbuf); + ogs_expect_or_return(rv == OGS_OK); + + /* IMPORTANT: + * + * When initiaited by Bearer Resource Command, + * there must be bearer context in the Transaction. + * Otherwise, the bearer context cannot be found + * in GTP response message. + * + * For example, + * 1. MME sends Bearer Resource Command to SGW-C, SMF. + * 2. SMF sends Update/Delete Bearer Request to the SGW-C, MME. + * 3. MME sends Update/Delete Bearer Response to thw SGW-C, SMF. + * + * On number 3 step, if MME sends Response without Bearer Context, + * we need a way to find Bearer context. + * + * To do this, I saved Bearer Context in Transaction Context. + */ + gtp_xact->data = bearer; + + rv = ogs_gtp_xact_commit(gtp_xact); + ogs_expect(rv == OGS_OK); + + } else { + if (flags & OGS_PFCP_MODIFY_SESSION) { + /* + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response to SGW/SMF. + * + * OR + * + * 1. SMF sends Delete Bearer Request(DEFAULT BEARER) to ePDG. + * 2. ePDG sends Delete Bearer Response(DEFAULT BEARER) to SMF. + */ + smf_bearer_t *linked_bearer = + ogs_list_first(&sess->bearer_list); + ogs_assert(linked_bearer); + + ogs_assert(OGS_OK == + smf_gtp_send_delete_bearer_request( + linked_bearer, gtp_pti, gtp_cause)); + } else { + /* + * 1. SMF sends Delete Bearer Request(DEDICATED BEARER) to SGW/MME. + * 2. MME sends Delete Bearer Response(DEDICATED BEARER) to SGW/SMF. + */ + ogs_assert(bearer); + + ogs_assert(OGS_OK == + smf_gtp_send_delete_bearer_request( + bearer, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + gtp_cause)); + } + } + } else if (flags & OGS_PFCP_MODIFY_ACTIVATE) { /* Nothing */ } diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index c55302b22..413e9df47 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -265,6 +265,9 @@ static void sess_epc_timeout(ogs_pfcp_xact_t *xact, void *data) case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE: ogs_warn("No PFCP session establishment response"); break; + case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE: + ogs_error("No PFCP session modification response"); + break; case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE: ogs_error("No PFCP session deletion response"); break; @@ -451,8 +454,44 @@ int smf_epc_pfcp_send_session_establishment_request( return rv; } +int smf_epc_pfcp_send_session_modification_request( + smf_sess_t *sess, void *gtp_xact, + uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(sess); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + + n4buf = smf_n4_build_session_modification_request(h.type, sess, flags); + ogs_expect_or_return_val(n4buf, OGS_ERROR); + + xact = ogs_pfcp_xact_local_create( + sess->pfcp_node, &h, n4buf, sess_epc_timeout, sess); + ogs_expect_or_return_val(xact, OGS_ERROR); + + xact->epc = true; /* EPC PFCP transaction */ + xact->assoc_xact = gtp_xact; + xact->modify_flags = flags | OGS_PFCP_MODIFY_SESSION; + + xact->gtp_pti = gtp_pti; + xact->gtp_cause = gtp_cause; + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + int smf_epc_pfcp_send_bearer_modification_request( - smf_bearer_t *bearer, uint64_t flags) + smf_bearer_t *bearer, void *gtp_xact, + uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause) { int rv; ogs_pkbuf_t *n4buf = NULL; @@ -476,8 +515,12 @@ int smf_epc_pfcp_send_bearer_modification_request( ogs_expect_or_return_val(xact, OGS_ERROR); xact->epc = true; /* EPC PFCP transaction */ + xact->assoc_xact = gtp_xact; xact->modify_flags = flags; + xact->gtp_pti = gtp_pti; + xact->gtp_cause = gtp_cause; + rv = ogs_pfcp_xact_commit(xact); ogs_expect(rv == OGS_OK); diff --git a/src/smf/pfcp-path.h b/src/smf/pfcp-path.h index 538982ecc..ded87f3d3 100644 --- a/src/smf/pfcp-path.h +++ b/src/smf/pfcp-path.h @@ -41,8 +41,12 @@ int smf_5gc_pfcp_send_session_deletion_request( int smf_epc_pfcp_send_session_establishment_request( smf_sess_t *sess, void *gtp_xact); +int smf_epc_pfcp_send_session_modification_request( + smf_sess_t *sess, void *gtp_xact, + uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause); int smf_epc_pfcp_send_bearer_modification_request( - smf_bearer_t *bearer, uint64_t flags); + smf_bearer_t *bearer, void *gtp_xact, + uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause); int smf_epc_pfcp_send_session_deletion_request( smf_sess_t *sess, void *gtp_xact); diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c index 99273c4cf..1354d41a6 100644 --- a/src/smf/s5c-handler.c +++ b/src/smf/s5c-handler.c @@ -448,8 +448,9 @@ void smf_s5c_handle_modify_bearer_request( ogs_expect_or_return(ogs_list_first(&wlan_sess->bearer_list)); ogs_assert(OGS_OK == - smf_gtp_send_delete_bearer_request( - ogs_list_first(&wlan_sess->bearer_list), + smf_epc_pfcp_send_session_modification_request( + wlan_sess, NULL, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, OGS_GTP_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP)); } @@ -468,6 +469,9 @@ void smf_s5c_handle_create_bearer_response( ogs_assert(xact); ogs_assert(rsp); + bearer = xact->data; + ogs_assert(bearer); + ogs_debug("Create Bearer Response"); cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; @@ -509,9 +513,6 @@ void smf_s5c_handle_create_bearer_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } - bearer = xact->data; - ogs_assert(bearer); - if (!sess) { ogs_warn("No Context in TEID"); @@ -547,7 +548,9 @@ void smf_s5c_handle_create_bearer_response( if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { ogs_assert(OGS_OK == smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_REMOVE)); + bearer, NULL, OGS_PFCP_MODIFY_REMOVE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); return; } @@ -583,7 +586,9 @@ void smf_s5c_handle_create_bearer_response( ogs_assert(OGS_OK == smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_ACTIVATE)); + bearer, NULL, OGS_PFCP_MODIFY_ACTIVATE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); } void smf_s5c_handle_update_bearer_response( @@ -601,6 +606,9 @@ void smf_s5c_handle_update_bearer_response( gtp_flags = xact->update_flags; ogs_assert(gtp_flags); + bearer = xact->data; + ogs_assert(bearer); + ogs_debug("Update Bearer Response"); cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; @@ -617,9 +625,6 @@ void smf_s5c_handle_update_bearer_response( cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; } - bearer = xact->data; - ogs_assert(bearer); - if (!sess) { ogs_warn("No Context in TEID"); @@ -674,7 +679,10 @@ void smf_s5c_handle_update_bearer_response( if (pfcp_flags) ogs_assert(OGS_OK == - smf_epc_pfcp_send_bearer_modification_request(bearer, pfcp_flags)); + smf_epc_pfcp_send_bearer_modification_request( + bearer, NULL, pfcp_flags, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); } void smf_s5c_handle_delete_bearer_response( @@ -786,7 +794,9 @@ void smf_s5c_handle_delete_bearer_response( ogs_assert(OGS_OK == smf_epc_pfcp_send_bearer_modification_request( - bearer, OGS_PFCP_MODIFY_REMOVE)); + bearer, NULL, OGS_PFCP_MODIFY_REMOVE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); } } @@ -1134,21 +1144,28 @@ void smf_s5c_handle_bearer_resource_command( return; } - memset(&h, 0, sizeof(ogs_gtp_header_t)); - h.teid = sess->sgw_s5c_teid; - if (tft_delete) { - h.type = OGS_GTP_DELETE_BEARER_REQUEST_TYPE; - pkbuf = smf_s5c_build_delete_bearer_request( - h.type, bearer, cmd->procedure_transaction_id.u8, - OGS_GTP_CAUSE_UNDEFINED_VALUE); - ogs_expect_or_return(pkbuf); - - rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); - ogs_expect_or_return(rv == OGS_OK); + /* + * TS23.214 + * 6.3.1.7 Procedures with modification of bearer + * p50 + * 2. ... + * For "PGW/MME initiated bearer deactivation procedure", + * PGW-C shall indicate PGW-U to stop counting and stop + * forwarding downlink packets for the affected bearer(s). + */ + ogs_assert(OGS_OK == + smf_epc_pfcp_send_bearer_modification_request( + bearer, xact, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, + cmd->procedure_transaction_id.u8, + OGS_GTP_CAUSE_UNDEFINED_VALUE)); } else { + memset(&h, 0, sizeof(ogs_gtp_header_t)); + h.teid = sess->sgw_s5c_teid; h.type = OGS_GTP_UPDATE_BEARER_REQUEST_TYPE; + pkbuf = smf_s5c_build_update_bearer_request( h.type, bearer, cmd->procedure_transaction_id.u8, tft_update ? &tft : NULL, qos_update); @@ -1161,26 +1178,26 @@ void smf_s5c_handle_bearer_resource_command( xact->update_flags |= OGS_GTP_MODIFY_TFT_UPDATE; if (qos_update) xact->update_flags |= OGS_GTP_MODIFY_QOS_UPDATE; + + /* IMPORTANT: + * + * When initiaited by Bearer Resource Command, there must be bearer context + * in the Transaction. Otherwise, the bearer context cannot be found + * in GTP response message. + * + * For example, + * 1. MME sends Bearer Resource Command to SGW-C, SMF. + * 2. SMF sends Update/Delete Bearer Request to the SGW-C, MME. + * 3. MME sends Update/Delete Bearer Response to thw SGW-C, SMF. + * + * On number 3 step, if MME sends Response without Bearer Context, + * we need a way to find Bearer context. + * + * To do this, I saved Bearer Context in Transaction Context. + */ + xact->data = bearer; + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); } - - /* IMPORTANT: - * - * When initiaited by Bearer Resource Command, there must be bearer context - * in the Transaction. Otherwise, the beare context cannot be found - * in GTP response message. - * - * For example, - * 1. MME sends Bearer Resource Command to SGW-C, SMF. - * 2. SMF sends Update/Delete Bearer Request to the SGW-C, MME. - * 3. MME sends Update/Delete Bearer Response to thw SGW-C, SMF. - * - * On number 3 step, if MME sends Response without Bearer Context, - * we need a way to find Bearer context. - * - * To do this, I saved Bearer Context in Transaction Context. - */ - xact->data = bearer; - - rv = ogs_gtp_xact_commit(xact); - ogs_expect(rv == OGS_OK); }