diff --git a/lib/pfcp/build.c b/lib/pfcp/build.c index a1b3e15fb..56899bd76 100644 --- a/lib/pfcp/build.c +++ b/lib/pfcp/build.c @@ -446,17 +446,15 @@ bool ogs_pfcp_build_created_pdr( ogs_assert(pdr); - if (ogs_pfcp_self()->up_function_features.ftup) { - if (pdr->f_teid_len) { - memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, pdr->f_teid_len); - pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid); + if (pdr->f_teid_len) { + memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, pdr->f_teid_len); + pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid); - message->local_f_teid.presence = 1; - message->local_f_teid.data = &pdrbuf[i].f_teid; - message->local_f_teid.len = pdr->f_teid_len; + message->local_f_teid.presence = 1; + message->local_f_teid.data = &pdrbuf[i].f_teid; + message->local_f_teid.len = pdr->f_teid_len; - pdr_presence = true; - } + pdr_presence = true; } if (pdr_presence == true) { diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index 51b0aaa20..b5df54e82 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -27,19 +27,23 @@ static int context_initialized = 0; static OGS_POOL(ogs_pfcp_node_pool, ogs_pfcp_node_t); static OGS_POOL(ogs_pfcp_sess_pool, ogs_pfcp_sess_t); -static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t); -static OGS_POOL(ogs_pfcp_pdr_teid_pool, ogs_pool_id_t); static OGS_POOL(ogs_pfcp_far_pool, ogs_pfcp_far_t); static OGS_POOL(ogs_pfcp_urr_pool, ogs_pfcp_urr_t); static OGS_POOL(ogs_pfcp_qer_pool, ogs_pfcp_qer_t); static OGS_POOL(ogs_pfcp_bar_pool, ogs_pfcp_bar_t); +static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t); +static OGS_POOL(ogs_pfcp_pdr_teid_pool, ogs_pool_id_t); +static ogs_pool_id_t *pdr_random_to_index; + +static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t); + static OGS_POOL(ogs_pfcp_dev_pool, ogs_pfcp_dev_t); static OGS_POOL(ogs_pfcp_subnet_pool, ogs_pfcp_subnet_t); -static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t); void ogs_pfcp_context_init(void) { + int i; ogs_assert(context_initialized == 0); /* Initialize SMF context */ @@ -53,11 +57,6 @@ void ogs_pfcp_context_init(void) ogs_pool_init(&ogs_pfcp_sess_pool, ogs_app()->pool.sess); - ogs_pool_init(&ogs_pfcp_pdr_pool, - ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR); - ogs_pool_init(&ogs_pfcp_pdr_teid_pool, - ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR); - ogs_pool_random_id_generate(&ogs_pfcp_pdr_teid_pool); ogs_pool_init(&ogs_pfcp_far_pool, ogs_app()->pool.sess * OGS_MAX_NUM_OF_FAR); ogs_pool_init(&ogs_pfcp_urr_pool, @@ -67,6 +66,17 @@ void ogs_pfcp_context_init(void) ogs_pool_init(&ogs_pfcp_bar_pool, ogs_app()->pool.sess * OGS_MAX_NUM_OF_BAR); + ogs_pool_init(&ogs_pfcp_pdr_pool, + ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR); + ogs_pool_init(&ogs_pfcp_pdr_teid_pool, ogs_pfcp_pdr_pool.size); + ogs_pool_random_id_generate(&ogs_pfcp_pdr_teid_pool); + + pdr_random_to_index = ogs_calloc( + sizeof(ogs_pool_id_t), ogs_pfcp_pdr_pool.size); + ogs_assert(pdr_random_to_index); + for (i = 0; i < ogs_pfcp_pdr_pool.size; i++) + pdr_random_to_index[ogs_pfcp_pdr_teid_pool.array[i]] = i; + ogs_pool_init(&ogs_pfcp_rule_pool, ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR * OGS_MAX_NUM_OF_FLOW_IN_PDR); @@ -102,9 +112,11 @@ void ogs_pfcp_context_final(void) ogs_pool_final(&ogs_pfcp_subnet_pool); ogs_pool_final(&ogs_pfcp_rule_pool); - ogs_pool_final(&ogs_pfcp_sess_pool); ogs_pool_final(&ogs_pfcp_pdr_pool); ogs_pool_final(&ogs_pfcp_pdr_teid_pool); + ogs_free(pdr_random_to_index); + + ogs_pool_final(&ogs_pfcp_sess_pool); ogs_pool_final(&ogs_pfcp_far_pool); ogs_pool_final(&ogs_pfcp_urr_pool); ogs_pool_final(&ogs_pfcp_qer_pool); @@ -955,12 +967,88 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( return pdr; } +void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr) +{ + int i = 0; + + ogs_assert(pdr); + ogs_assert(pdr->f_teid.teid > 0 && + pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size); + + /* Find out the Array Index for the restored TEID. */ + i = pdr_random_to_index[pdr->f_teid.teid]; + ogs_assert(i < ogs_pfcp_pdr_teid_pool.size); + + ogs_assert(pdr->teid_node); + /* + * If SWAP has already done this, it will not try this again. + * This situation can occur when multiple PDRs are restored + * with the same TEID. + */ + if (pdr->f_teid.teid == ogs_pfcp_pdr_teid_pool.array[i]) { + ogs_pfcp_pdr_teid_pool.array[i] = *(pdr->teid_node); + *(pdr->teid_node) = pdr->f_teid.teid; + } +} + void ogs_pfcp_object_teid_hash_set( - ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr) + ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr, + bool restoration_indication) { ogs_assert(type); ogs_assert(pdr); + if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) { + + ogs_pfcp_pdr_t *choosed_pdr = NULL; + + if (pdr->f_teid.chid) { + choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( + pdr->sess, pdr->f_teid.choose_id); + if (!choosed_pdr) { + pdr->chid = true; + pdr->choose_id = pdr->f_teid.choose_id; + } + } + + if (choosed_pdr) { + pdr->f_teid_len = choosed_pdr->f_teid_len; + memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); + + } else { + ogs_gtpu_resource_t *resource = NULL; + resource = ogs_pfcp_find_gtpu_resource( + &ogs_gtp_self()->gtpu_resource_list, + pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); + if (resource) { + ogs_assert( + (resource->info.v4 && pdr->f_teid.ipv4) || + (resource->info.v6 && pdr->f_teid.ipv6)); + ogs_assert(OGS_OK == + ogs_pfcp_user_plane_ip_resource_info_to_f_teid( + &resource->info, &pdr->f_teid, &pdr->f_teid_len)); + if (resource->info.teidri) + pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( + pdr->teid, resource->info.teidri, + resource->info.teid_range); + else + pdr->f_teid.teid = pdr->teid; + } else { + ogs_assert( + (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || + (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); + ogs_assert(OGS_OK == + ogs_pfcp_sockaddr_to_f_teid( + pdr->f_teid.ipv4 ? + ogs_gtp_self()->gtpu_addr : NULL, + pdr->f_teid.ipv6 ? + ogs_gtp_self()->gtpu_addr6 : NULL, + &pdr->f_teid, &pdr->f_teid_len)); + pdr->f_teid.teid = pdr->teid; + } + } + } + if (pdr->hash.teid.len) ogs_hash_set(self.object_teid_hash, &pdr->hash.teid.key, pdr->hash.teid.len, NULL); diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index ad317336b..d47fdac9c 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -401,8 +401,11 @@ ogs_pfcp_pdr_t *ogs_pfcp_pdr_find( ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add( ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id); +void ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr); + void ogs_pfcp_object_teid_hash_set( - ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr); + ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr, + bool restoration_indication); ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid); int ogs_pfcp_object_count_by_teid(ogs_pfcp_sess_t *sess, uint32_t teid); diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index 356bd8195..26377faa7 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -320,6 +320,7 @@ bool ogs_pfcp_up_handle_error_indication( ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_create_pdr_t *message, + ogs_pfcp_sereq_flags_t *sereq_flags, uint8_t *cause_value, uint8_t *offending_ie_value) { ogs_pfcp_pdr_t *pdr = NULL; @@ -376,6 +377,18 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, *offending_ie_value = OGS_PFCP_F_TEID_TYPE; return NULL; } + + if (f_teid.ch == 0) { + if (sereq_flags && sereq_flags->restoration_indication == 1) { + f_teid.teid = be32toh(f_teid.teid); + if (ogs_pfcp_object_find_by_teid(f_teid.teid)) { + ogs_error("TEID:%x had already been allocated", f_teid.teid); + *cause_value = OGS_PFCP_CAUSE_INVALID_F_TEID_ALLOCATION_OPTION; + *offending_ie_value = OGS_PFCP_F_TEID_TYPE; + return NULL; + } + } + } } pdr->src_if = message->pdi.source_interface.u8; @@ -398,7 +411,6 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, if (sdf_filter.bid) { oppsite_direction_rule = ogs_pfcp_rule_find_by_sdf_filter_id( sess, sdf_filter.sdf_filter_id); - } if (!oppsite_direction_rule && !sdf_filter.fd) { diff --git a/lib/pfcp/handler.h b/lib/pfcp/handler.h index 9ad357dca..7ae62f30b 100644 --- a/lib/pfcp/handler.h +++ b/lib/pfcp/handler.h @@ -53,6 +53,7 @@ bool ogs_pfcp_up_handle_error_indication( ogs_pfcp_pdr_t *ogs_pfcp_handle_create_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_create_pdr_t *message, + ogs_pfcp_sereq_flags_t *sereq_flags, uint8_t *cause_value, uint8_t *offending_ie_value); ogs_pfcp_pdr_t *ogs_pfcp_handle_created_pdr(ogs_pfcp_sess_t *sess, ogs_pfcp_tlv_created_pdr_t *message, diff --git a/lib/pfcp/message.c b/lib/pfcp/message.c index c8aee5f7e..63fc780cd 100644 --- a/lib/pfcp/message.c +++ b/lib/pfcp/message.c @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by pfcp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2023-03-05 22:26:11.716006 by acetcom + * Created on: 2023-04-09 20:37:00.518388 by acetcom * from 29244-h71-modified.docx ******************************************************************************/ @@ -1546,10 +1546,10 @@ ogs_tlv_desc_t ogs_pfcp_tlv_desc_cp_pfcp_entity_ip_address = ogs_tlv_desc_t ogs_pfcp_tlv_desc_pfcpsereq_flags = { - OGS_TLV_VAR_STR, + OGS_TLV_UINT8, "PFCPSEReq-Flags", OGS_PFCP_PFCPSEREQ_FLAGS_TYPE, - 0, + 1, 0, sizeof(ogs_pfcp_tlv_pfcpsereq_flags_t), { NULL } diff --git a/lib/pfcp/message.h b/lib/pfcp/message.h index 69adde349..e31e26702 100644 --- a/lib/pfcp/message.h +++ b/lib/pfcp/message.h @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by pfcp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2023-03-05 22:26:11.698310 by acetcom + * Created on: 2023-04-09 20:37:00.506639 by acetcom * from 29244-h71-modified.docx ******************************************************************************/ @@ -903,7 +903,7 @@ typedef ogs_tlv_uint32_t ogs_pfcp_tlv_quota_validity_time_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_number_of_reports_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpasrsp_flags_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_cp_pfcp_entity_ip_address_t; -typedef ogs_tlv_octet_t ogs_pfcp_tlv_pfcpsereq_flags_t; +typedef ogs_tlv_uint8_t ogs_pfcp_tlv_pfcpsereq_flags_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_ip_multicast_address_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_source_ip_address_t; typedef ogs_tlv_octet_t ogs_pfcp_tlv_packet_rate_status_t; diff --git a/lib/pfcp/support/pfcp-tlv.py b/lib/pfcp/support/pfcp-tlv.py index d180392f1..bbeac762b 100644 --- a/lib/pfcp/support/pfcp-tlv.py +++ b/lib/pfcp/support/pfcp-tlv.py @@ -519,6 +519,7 @@ type_list["Paging Policy Indicator"]["size"] = 1 # Type 158 type_list["PFCPSRReq-Flags"]["size"] = 1 # Type 161 type_list["PFCPAUReq-Flags"]["size"] = 1 # Type 162 type_list["Quota Validity Time"]["size"] = 4 # Type 181 +type_list["PFCPSEReq-Flags"]["size"] = 1 # Type 186 type_list["Data Status"]["size"] = 1 # Type 260 f = open(outdir + 'message.h', 'w') diff --git a/lib/pfcp/types.h b/lib/pfcp/types.h index 481832409..895a7efd2 100644 --- a/lib/pfcp/types.h +++ b/lib/pfcp/types.h @@ -1651,6 +1651,28 @@ int16_t ogs_pfcp_build_user_id( ogs_tlv_octet_t *octet, ogs_pfcp_user_id_t *user_id, void *data, int data_len); +/* + * 8.2.136 PFCPSEReq-Flags + * + * The following bits within Octet 5 shall indicate: + * - Bit 1 – RESTI (Restoration Indication): if this bit is set to "1", + * it indicates to the UP function that the PFCP session to be established is + * to restore an existing PFCP session. + * - Bit 2 – SUMPC (Stop of Usage Measurement to Pause Charging): + * if this bit is set to "1", it indicates that the UP function shall + * stop the usage measurement for all URRs with the "ASPOC" flag set to "1". + */ +typedef struct ogs_pfcp_sereq_flags_s { + union { + struct { +ED3(uint8_t spare:6;, + uint8_t stop_of_usage_measurement_to_pause_charging:1;, + uint8_t restoration_indication:1;) + }; + uint8_t value; + }; +} __attribute__ ((packed)) ogs_pfcp_sereq_flags_t; + #ifdef __cplusplus } #endif diff --git a/lib/pfcp/xact.h b/lib/pfcp/xact.h index aa0f2bfd2..580b80b46 100644 --- a/lib/pfcp/xact.h +++ b/lib/pfcp/xact.h @@ -78,6 +78,9 @@ typedef struct ogs_pfcp_xact_s { bool epc; /**< EPC or 5GC */ +#define OGS_PFCP_CREATE_RESTORATION_INDICATION ((uint64_t)1<<0) + uint64_t create_flags; + #define OGS_PFCP_MODIFY_SESSION ((uint64_t)1<<0) #define OGS_PFCP_MODIFY_DL_ONLY ((uint64_t)1<<1) #define OGS_PFCP_MODIFY_UL_ONLY ((uint64_t)1<<2) @@ -110,7 +113,6 @@ typedef struct ogs_pfcp_xact_s { #define OGS_PFCP_MODIFY_URR_TIME_QUOTA ((uint64_t)1<<29) #define OGS_PFCP_MODIFY_URR_VOLUME_THRESH ((uint64_t)1<<30) #define OGS_PFCP_MODIFY_URR_TIME_THRESH ((uint64_t)1<<31) - uint64_t modify_flags; #define OGS_PFCP_DELETE_TRIGGER_LOCAL_INITIATED 1 diff --git a/src/sgwc/pfcp-path.c b/src/sgwc/pfcp-path.c index 24d27cb6b..e737a4442 100644 --- a/src/sgwc/pfcp-path.c +++ b/src/sgwc/pfcp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -238,7 +238,8 @@ int sgwc_pfcp_send_bearer_to_modify_list( } int sgwc_pfcp_send_session_establishment_request( - sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf) + sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf, + uint64_t flags) { int rv; ogs_pkbuf_t *sxabuf = NULL; @@ -262,9 +263,40 @@ int sgwc_pfcp_send_session_establishment_request( } } xact->local_seid = sess->sgwc_sxa_seid; + xact->create_flags = flags; memset(&h, 0, sizeof(ogs_pfcp_header_t)); h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; + +/* + * 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header + * + * If a peer's SEID is not available, the SEID field shall still be present + * in the header and its value shall be set to "0" in the following messages: + * + * - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4; + * + * - If a node receives a message for which it has no session, i.e. + * if SEID in the PFCP header is not known, it shall respond + * with "Session context not found" cause in the corresponding + * response message to the sender, the SEID used in the PFCP header + * in the response message shall be then set to "0"; + * + * - If a node receives a request message containing protocol error, + * e.g. Mandatory IE missing, which requires the receiver + * to reject the message as specified in clause 7.6, it shall reject + * the request message. For the response message, the node should look up + * the remote peer's SEID and accordingly set SEID in the PFCP header + * and the message cause code. As an implementation option, + * the node may not look up the remote peer's SEID and + * set the PFCP header SEID to "0" in the response message. + * However in this case, the cause value shall not be set + * to "Session not found". + * + * - When the UP function sends PFCP Session Report Request message + * over N4 towards another SMF or another PFCP entity in the SMF + * as specified in clause 5.22.2 and clause 5.22.3. + */ h.seid = sess->sgwu_sxa_seid; sxabuf = sgwc_sxa_build_session_establishment_request(h.type, sess); diff --git a/src/sgwc/pfcp-path.h b/src/sgwc/pfcp-path.h index 82bbbb0c8..ae3314da2 100644 --- a/src/sgwc/pfcp-path.h +++ b/src/sgwc/pfcp-path.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -33,7 +33,8 @@ int sgwc_pfcp_send_bearer_to_modify_list( sgwc_sess_t *sess, ogs_pfcp_xact_t *xact); int sgwc_pfcp_send_session_establishment_request( - sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf); + sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf, + uint64_t flags); int sgwc_pfcp_send_session_modification_request( sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, diff --git a/src/sgwc/pfcp-sm.c b/src/sgwc/pfcp-sm.c index af099860e..fb9a17736 100644 --- a/src/sgwc/pfcp-sm.c +++ b/src/sgwc/pfcp-sm.c @@ -20,6 +20,7 @@ #include "pfcp-path.h" #include "sxa-handler.h" +static void pfcp_restoration(ogs_pfcp_node_t *node); static void node_timeout(ogs_pfcp_xact_t *xact, void *data); void sgwc_pfcp_state_initial(ogs_fsm_t *s, sgwc_event_t *e) @@ -188,6 +189,7 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e) ogs_pfcp_send_heartbeat_request(node, node_timeout)); if (node->restoration_required == true) { + pfcp_restoration(node); node->restoration_required = false; ogs_error("PFCP restoration"); } @@ -220,11 +222,56 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e) ogs_expect(true == ogs_pfcp_handle_heartbeat_request(node, xact, &message->pfcp_heartbeat_request)); + if (node->restoration_required == true) { + if (node->t_association) { + /* + * node->t_association that the PFCP entity attempts an association. + * + * In this case, even if Remote PFCP entity is restarted, + * PFCP restoration must be performed after PFCP association. + * + * Otherwise, Session related PFCP cannot be initiated + * because the peer PFCP entity is in a de-associated state. + */ + OGS_FSM_TRAN(s, sgwc_pfcp_state_will_associate); + } else { + + /* + * If the peer PFCP entity is performing the association, + * Restoration can be performed immediately. + */ + pfcp_restoration(node); + node->restoration_required = false; + ogs_error("PFCP restoration"); + } + } break; case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE: ogs_expect(true == ogs_pfcp_handle_heartbeat_response(node, xact, &message->pfcp_heartbeat_response)); + if (node->restoration_required == true) { + /* + * node->t_association that the PFCP entity attempts an association. + * + * In this case, even if Remote PFCP entity is restarted, + * PFCP restoration must be performed after PFCP association. + * + * Otherwise, Session related PFCP cannot be initiated + * because the peer PFCP entity is in a de-associated state. + */ + if (node->t_association) { + OGS_FSM_TRAN(s, sgwc_pfcp_state_will_associate); + } else { + /* + * If the peer PFCP entity is performing the association, + * Restoration can be performed immediately. + */ + pfcp_restoration(node); + node->restoration_required = false; + ogs_error("PFCP restoration"); + } + } break; case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE: ogs_warn("PFCP[REQ] has already been associated [%s]:%d", @@ -243,9 +290,24 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e) case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE: if (!message->h.seid_presence) ogs_error("No SEID"); - sgwc_sxa_handle_session_establishment_response( - sess, xact, e->gtp_message, - &message->pfcp_session_establishment_response); + if ((xact->create_flags & + OGS_PFCP_CREATE_RESTORATION_INDICATION)) { + ogs_pfcp_session_establishment_response_t *rsp = NULL; + ogs_pfcp_f_seid_t *up_f_seid = NULL; + + rsp = &message->pfcp_session_establishment_response; + if (rsp->up_f_seid.presence == 0) { + ogs_error("No UP F-SEID"); + break; + } + up_f_seid = rsp->up_f_seid.data; + ogs_assert(up_f_seid); + sess->sgwu_sxa_seid = be64toh(up_f_seid->seid); + } else { + sgwc_sxa_handle_session_establishment_response( + sess, xact, e->gtp_message, + &message->pfcp_session_establishment_response); + } break; case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE: @@ -326,6 +388,29 @@ void sgwc_pfcp_state_exception(ogs_fsm_t *s, sgwc_event_t *e) } } +static void pfcp_restoration(ogs_pfcp_node_t *node) +{ + sgwc_ue_t *sgwc_ue = NULL; + + ogs_list_for_each(&sgwc_self()->sgw_ue_list, sgwc_ue) { + sgwc_sess_t *sess = NULL; + ogs_assert(sgwc_ue); + + ogs_list_for_each(&sgwc_ue->sess_list, sess) { + ogs_assert(sess); + + if (node == sess->pfcp_node) { + ogs_info("UE IMSI[%s] APN[%s]", + sgwc_ue->imsi_bcd, sess->session.name); + ogs_assert(OGS_OK == + sgwc_pfcp_send_session_establishment_request( + sess, NULL, NULL, + OGS_PFCP_CREATE_RESTORATION_INDICATION)); + } + } + } +} + static void node_timeout(ogs_pfcp_xact_t *xact, void *data) { int rv; diff --git a/src/sgwc/s11-handler.c b/src/sgwc/s11-handler.c index e4363659d..f6fe9c319 100644 --- a/src/sgwc/s11-handler.c +++ b/src/sgwc/s11-handler.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -234,6 +234,8 @@ void sgwc_s11_handle_create_session_request( sess = sgwc_sess_add(sgwc_ue, apn); ogs_assert(sess); + ogs_info("UE IMSI[%s] APN[%s]", sgwc_ue->imsi_bcd, sess->session.name); + /* Set User Location Information */ if (req->user_location_information.presence == 1) { decoded = ogs_gtp2_parse_uli(&uli, &req->user_location_information); @@ -376,7 +378,8 @@ void sgwc_s11_handle_create_session_request( sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid); ogs_assert(OGS_OK == - sgwc_pfcp_send_session_establishment_request(sess, s11_xact, gtpbuf)); + sgwc_pfcp_send_session_establishment_request( + sess, s11_xact, gtpbuf, 0)); } void sgwc_s11_handle_modify_bearer_request( diff --git a/src/sgwu/context.c b/src/sgwu/context.c index 27a5dbdb8..87f97ef2f 100644 --- a/src/sgwu/context.c +++ b/src/sgwu/context.c @@ -255,7 +255,10 @@ sgwu_sess_t *sgwu_sess_add_by_message(ogs_pfcp_message_t *message) sess = sgwu_sess_find_by_sgwc_sxa_f_seid(f_seid); if (!sess) { sess = sgwu_sess_add(f_seid); - if (!sess) return NULL; + if (!sess) { + ogs_error("No Session Context"); + return NULL; + } } ogs_assert(sess); diff --git a/src/sgwu/gtp-path.c b/src/sgwu/gtp-path.c index 91c5a6f5b..2aca69da6 100644 --- a/src/sgwu/gtp-path.c +++ b/src/sgwu/gtp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -203,6 +203,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(pdr); break; case OGS_PFCP_OBJ_SESS_TYPE: + /* SGWU does not use SESS TYPE */ + ogs_assert_if_reached(); pfcp_sess = (ogs_pfcp_sess_t *)pfcp_object; ogs_assert(pfcp_sess); diff --git a/src/sgwu/pfcp-path.c b/src/sgwu/pfcp-path.c index 1a63fbacc..f3a08c072 100644 --- a/src/sgwu/pfcp-path.c +++ b/src/sgwu/pfcp-path.c @@ -205,7 +205,6 @@ int sgwu_pfcp_send_session_modification_response( ogs_pfcp_header_t h; ogs_assert(xact); - ogs_assert(created_pdr); memset(&h, 0, sizeof(ogs_pfcp_header_t)); h.type = OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE; diff --git a/src/sgwu/pfcp-sm.c b/src/sgwu/pfcp-sm.c index c28385307..3393eaecf 100644 --- a/src/sgwu/pfcp-sm.c +++ b/src/sgwu/pfcp-sm.c @@ -277,12 +277,9 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e) &message->pfcp_association_setup_response); break; case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE: - if (message->h.seid_presence && message->h.seid == 0) { - ogs_expect(!sess); - sess = sgwu_sess_add_by_message(message); - if (sess) - OGS_SETUP_PFCP_NODE(sess, node); - } + sess = sgwu_sess_add_by_message(message); + if (sess) + OGS_SETUP_PFCP_NODE(sess, node); sgwu_sxa_handle_session_establishment_request( sess, xact, &message->pfcp_session_establishment_request); break; diff --git a/src/sgwu/sxa-handler.c b/src/sgwu/sxa-handler.c index b4d7f795f..7950ef941 100644 --- a/src/sgwu/sxa-handler.c +++ b/src/sgwu/sxa-handler.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -33,6 +33,9 @@ void sgwu_sxa_handle_session_establishment_request( uint8_t offending_ie_value = 0; int i; + ogs_pfcp_sereq_flags_t sereq_flags; + bool restoration_indication = false; + ogs_assert(xact); ogs_assert(req); @@ -48,9 +51,16 @@ void sgwu_sxa_handle_session_establishment_request( return; } + /* PFCPSEReq-Flags */ + memset(&sereq_flags, 0, sizeof(sereq_flags)); + if (req->pfcpsereq_flags.presence == 1) { + sereq_flags.value = req->pfcpsereq_flags.u8; + } + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp, - &req->create_pdr[i], &cause_value, &offending_ie_value); + &req->create_pdr[i], &sereq_flags, + &cause_value, &offending_ie_value); if (created_pdr[i] == NULL) break; } @@ -79,6 +89,18 @@ void sgwu_sxa_handle_session_establishment_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + /* PFCPSEReq-Flags */ + if (sereq_flags.restoration_indication == 1) { + for (i = 0; i < num_of_created_pdr; i++) { + pdr = created_pdr[i]; + ogs_assert(pdr); + + if (pdr->f_teid_len) + ogs_pfcp_pdr_swap_teid(pdr); + } + restoration_indication = true; + } + /* Setup GTP Node */ ogs_list_for_each(&sess->pfcp.far_list, far) { ogs_assert(OGS_ERROR != ogs_pfcp_setup_far_gtpu_node(far)); @@ -86,70 +108,14 @@ void sgwu_sxa_handle_session_establishment_request( ogs_pfcp_far_f_teid_hash_set(far); } - /* Setup TEID Hash */ for (i = 0; i < num_of_created_pdr; i++) { pdr = created_pdr[i]; ogs_assert(pdr); - if (pdr->f_teid_len) { - ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE; - - if (ogs_pfcp_self()->up_function_features.ftup && - pdr->f_teid.ch) { - - ogs_pfcp_pdr_t *choosed_pdr = NULL; - - if (pdr->f_teid.chid) { - type = OGS_PFCP_OBJ_SESS_TYPE; - - choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( - &sess->pfcp, pdr->f_teid.choose_id); - if (!choosed_pdr) { - pdr->chid = true; - pdr->choose_id = pdr->f_teid.choose_id; - } - } - - if (choosed_pdr) { - pdr->f_teid_len = choosed_pdr->f_teid_len; - memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); - - } else { - ogs_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_find_gtpu_resource( - &ogs_gtp_self()->gtpu_resource_list, - pdr->apn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_assert( - (resource->info.v4 && pdr->f_teid.ipv4) || - (resource->info.v6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_user_plane_ip_resource_info_to_f_teid( - &resource->info, &pdr->f_teid, &pdr->f_teid_len)); - if (resource->info.teidri) - pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - pdr->teid, resource->info.teidri, - resource->info.teid_range); - else - pdr->f_teid.teid = pdr->teid; - } else { - ogs_assert( - (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || - (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_sockaddr_to_f_teid( - pdr->f_teid.ipv4 ? - ogs_gtp_self()->gtpu_addr : NULL, - pdr->f_teid.ipv6 ? - ogs_gtp_self()->gtpu_addr6 : NULL, - &pdr->f_teid, &pdr->f_teid_len)); - pdr->f_teid.teid = pdr->teid; - } - } - } - - ogs_pfcp_object_teid_hash_set(type, pdr); - } + /* Setup TEID Hash */ + if (pdr->f_teid_len) + ogs_pfcp_object_teid_hash_set( + OGS_PFCP_OBJ_PDR_TYPE, pdr, restoration_indication); } /* Send Buffered Packet to gNB */ @@ -159,9 +125,15 @@ void sgwu_sxa_handle_session_establishment_request( } } - ogs_assert(OGS_OK == - sgwu_pfcp_send_session_establishment_response( - xact, sess, created_pdr, num_of_created_pdr)); + if (restoration_indication == true || + ogs_pfcp_self()->up_function_features.ftup == 0) + ogs_assert(OGS_OK == + sgwu_pfcp_send_session_establishment_response( + xact, sess, NULL, 0)); + else + ogs_assert(OGS_OK == + sgwu_pfcp_send_session_establishment_response( + xact, sess, created_pdr, num_of_created_pdr)); return; cleanup: @@ -200,7 +172,7 @@ void sgwu_sxa_handle_session_modification_request( for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp, - &req->create_pdr[i], &cause_value, &offending_ie_value); + &req->create_pdr[i], NULL, &cause_value, &offending_ie_value); if (created_pdr[i] == NULL) break; } @@ -301,70 +273,13 @@ void sgwu_sxa_handle_session_modification_request( ogs_pfcp_far_f_teid_hash_set(far); } - /* Setup TEID Hash */ for (i = 0; i < num_of_created_pdr; i++) { pdr = created_pdr[i]; ogs_assert(pdr); - if (pdr->f_teid_len) { - ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_PDR_TYPE; - - if (ogs_pfcp_self()->up_function_features.ftup && - pdr->f_teid.ch) { - - ogs_pfcp_pdr_t *choosed_pdr = NULL; - - if (pdr->f_teid.chid) { - type = OGS_PFCP_OBJ_SESS_TYPE; - - choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( - &sess->pfcp, pdr->f_teid.choose_id); - if (!choosed_pdr) { - pdr->chid = true; - pdr->choose_id = pdr->f_teid.choose_id; - } - } - - if (choosed_pdr) { - pdr->f_teid_len = choosed_pdr->f_teid_len; - memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); - - } else { - ogs_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_find_gtpu_resource( - &ogs_gtp_self()->gtpu_resource_list, - pdr->apn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_assert( - (resource->info.v4 && pdr->f_teid.ipv4) || - (resource->info.v6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_user_plane_ip_resource_info_to_f_teid( - &resource->info, &pdr->f_teid, &pdr->f_teid_len)); - if (resource->info.teidri) - pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - pdr->teid, resource->info.teidri, - resource->info.teid_range); - else - pdr->f_teid.teid = pdr->teid; - } else { - ogs_assert( - (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || - (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_sockaddr_to_f_teid( - pdr->f_teid.ipv4 ? - ogs_gtp_self()->gtpu_addr : NULL, - pdr->f_teid.ipv6 ? - ogs_gtp_self()->gtpu_addr6 : NULL, - &pdr->f_teid, &pdr->f_teid_len)); - pdr->f_teid.teid = pdr->teid; - } - } - } - - ogs_pfcp_object_teid_hash_set(type, pdr); - } + /* Setup TEID Hash */ + if (pdr->f_teid_len) + ogs_pfcp_object_teid_hash_set(OGS_PFCP_OBJ_PDR_TYPE, pdr, false); } /* Send Buffered Packet to gNB */ @@ -374,9 +289,14 @@ void sgwu_sxa_handle_session_modification_request( } } - ogs_assert(OGS_OK == - sgwu_pfcp_send_session_modification_response( - xact, sess, created_pdr, num_of_created_pdr)); + if (ogs_pfcp_self()->up_function_features.ftup == 0) + ogs_assert(OGS_OK == + sgwu_pfcp_send_session_modification_response( + xact, sess, NULL, 0)); + else + ogs_assert(OGS_OK == + sgwu_pfcp_send_session_modification_response( + xact, sess, created_pdr, num_of_created_pdr)); return; cleanup: diff --git a/src/smf/context.c b/src/smf/context.c index eb5cf4fde..6415eb586 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -2142,37 +2142,51 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess) pdr->f_teid.choose_id = OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID; pdr->f_teid_len = 2; } else { - ogs_gtpu_resource_t *resource = NULL; + /* + * CHOOSE_ID is set in INDIRECT so that all PDRs must be set + * to the same TEID. + * + * If sess->handover.upf_dl_teid is set in the PDR of + * the first QoS flow, the PDRs of the remaining QoS flows use + * the same TEID. + */ + if (ogs_list_first(&sess->bearer_list) == qos_flow) { + ogs_gtpu_resource_t *resource = NULL; - if (sess->handover.upf_dl_addr) - ogs_freeaddrinfo(sess->handover.upf_dl_addr); - if (sess->handover.upf_dl_addr6) - ogs_freeaddrinfo(sess->handover.upf_dl_addr6); + if (sess->handover.upf_dl_addr) + ogs_freeaddrinfo(sess->handover.upf_dl_addr); + if (sess->handover.upf_dl_addr6) + ogs_freeaddrinfo(sess->handover.upf_dl_addr6); - resource = ogs_pfcp_find_gtpu_resource( - &sess->pfcp_node->gtpu_resource_list, - sess->session.name, OGS_PFCP_INTERFACE_ACCESS); + resource = ogs_pfcp_find_gtpu_resource( + &sess->pfcp_node->gtpu_resource_list, + sess->session.name, OGS_PFCP_INTERFACE_ACCESS); + + if (resource) { + ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info, + &sess->handover.upf_dl_addr, + &sess->handover.upf_dl_addr6); + if (resource->info.teidri) + sess->handover.upf_dl_teid = + OGS_PFCP_GTPU_INDEX_TO_TEID( + pdr->teid, resource->info.teidri, + resource->info.teid_range); + else + sess->handover.upf_dl_teid = pdr->teid; + } else { + if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) + ogs_assert(OGS_OK == ogs_copyaddrinfo( + &sess->handover.upf_dl_addr, + &sess->pfcp_node->addr)); + else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) + ogs_assert(OGS_OK == ogs_copyaddrinfo( + &sess->handover.upf_dl_addr6, + &sess->pfcp_node->addr)); + else + ogs_assert_if_reached(); - if (resource) { - ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info, - &sess->handover.upf_dl_addr, &sess->handover.upf_dl_addr6); - if (resource->info.teidri) - sess->handover.upf_dl_teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - pdr->teid, resource->info.teidri, - resource->info.teid_range); - else sess->handover.upf_dl_teid = pdr->teid; - } else { - if (sess->pfcp_node->addr.ogs_sa_family == AF_INET) - ogs_assert(OGS_OK == ogs_copyaddrinfo( - &sess->handover.upf_dl_addr, &sess->pfcp_node->addr)); - else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6) - ogs_assert(OGS_OK == ogs_copyaddrinfo( - &sess->handover.upf_dl_addr6, &sess->pfcp_node->addr)); - else - ogs_assert_if_reached(); - - sess->handover.upf_dl_teid = pdr->teid; + } } ogs_assert(OGS_OK == diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index b43bc9414..85e1d2043 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2022 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -452,7 +452,7 @@ test_can_proceed: OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_establishment); ogs_assert(OGS_OK == smf_epc_pfcp_send_session_establishment_request( - sess, e->gtp_xact)); + sess, e->gtp_xact, 0)); } else { /* FIXME: tear down Gx/Gy session * if its sm_data.*init_err == ER_DIAMETER_SUCCESS */ @@ -671,21 +671,28 @@ void smf_gsm_state_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e) send_gtp_create_err_msg(sess, e->gtp_xact, gtp_cause); return; } - switch (gtp_xact->gtp_version) { - case 1: - rv = smf_gtp1_send_create_pdp_context_response(sess, gtp_xact); - break; - case 2: - rv = smf_gtp2_send_create_session_response(sess, gtp_xact); - break; - default: - rv = OGS_ERROR; - break; - } - /* If no CreatePDPCtxResp can be sent, then tear down the session: */ - if (rv != OGS_OK) { - OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion); - return; + + gtp_xact = pfcp_xact->assoc_xact; + if (gtp_xact) { + switch (gtp_xact->gtp_version) { + case 1: + rv = smf_gtp1_send_create_pdp_context_response( + sess, gtp_xact); + break; + case 2: + rv = smf_gtp2_send_create_session_response( + sess, gtp_xact); + break; + default: + rv = OGS_ERROR; + break; + } + /* If no CreatePDPCtxResp can be sent, + * then tear down the session: */ + if (rv != OGS_OK) { + OGS_FSM_TRAN(s, &smf_gsm_state_wait_pfcp_deletion); + return; + } } if (sess->gtp_rat_type == OGS_GTP2_RAT_TYPE_WLAN) { @@ -739,6 +746,9 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) smf_sess_t *sess = NULL; ogs_pkbuf_t *pkbuf = NULL; + ogs_pfcp_xact_t *pfcp_xact = NULL; + ogs_pfcp_message_t *pfcp_message = NULL; + ogs_nas_5gs_message_t *nas_message = NULL; ogs_sbi_stream_t *stream = NULL; @@ -815,6 +825,38 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) } break; + case SMF_EVT_N4_MESSAGE: + pfcp_xact = e->pfcp_xact; + ogs_assert(pfcp_xact); + pfcp_message = e->pfcp_message; + ogs_assert(pfcp_message); + + switch (pfcp_message->h.type) { + case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE: + if ((pfcp_xact->create_flags & + OGS_PFCP_CREATE_RESTORATION_INDICATION)) { + ogs_pfcp_session_establishment_response_t *rsp = NULL; + ogs_pfcp_f_seid_t *up_f_seid = NULL; + + rsp = &pfcp_message->pfcp_session_establishment_response; + if (rsp->up_f_seid.presence == 0) { + ogs_error("No UP F-SEID"); + break; + } + up_f_seid = rsp->up_f_seid.data; + ogs_assert(up_f_seid); + sess->upf_n4_seid = be64toh(up_f_seid->seid); + } else { + ogs_error("cannot handle PFCP Session Establishment Response"); + } + break; + + default: + ogs_error("cannot handle PFCP message type[%d]", + pfcp_message->h.type); + } + break; + case OGS_EVENT_SBI_SERVER: sbi_message = e->h.sbi.message; ogs_assert(sbi_message); diff --git a/src/smf/n4-build.c b/src/smf/n4-build.c index 4ce171cd8..b37003d4e 100644 --- a/src/smf/n4-build.c +++ b/src/smf/n4-build.c @@ -21,7 +21,7 @@ #include "n4-build.h" ogs_pkbuf_t *smf_n4_build_session_establishment_request( - uint8_t type, smf_sess_t *sess) + uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact) { ogs_pfcp_message_t *pfcp_message = NULL; ogs_pfcp_session_establishment_request_t *req = NULL; @@ -46,6 +46,7 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request( ogs_assert(sess); smf_ue = sess->smf_ue; ogs_assert(smf_ue); + ogs_assert(xact); pfcp_message = ogs_calloc(1, sizeof(*pfcp_message)); if (!pfcp_message) { @@ -159,6 +160,16 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request( req->s_nssai.data = &sess->s_nssai; } + /* Restoration Indication */ + if (xact->create_flags & OGS_PFCP_CREATE_RESTORATION_INDICATION) { + ogs_pfcp_sereq_flags_t sereq_flags; + sereq_flags.value = 0; + + sereq_flags.restoration_indication = 1; + req->pfcpsereq_flags.presence = 1; + req->pfcpsereq_flags.u8 = sereq_flags.value; + } + pfcp_message->h.type = type; pkbuf = ogs_pfcp_build_msg(pfcp_message); ogs_expect(pkbuf); diff --git a/src/smf/n4-build.h b/src/smf/n4-build.h index 560a4a0f3..49e9c89df 100644 --- a/src/smf/n4-build.h +++ b/src/smf/n4-build.h @@ -27,7 +27,7 @@ extern "C" { #endif ogs_pkbuf_t *smf_n4_build_session_establishment_request( - uint8_t type, smf_sess_t *sess); + uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact); ogs_pkbuf_t *smf_n4_build_pdr_to_modify_list( uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact); ogs_pkbuf_t *smf_n4_build_qos_flow_to_modify_list( diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index ef3e2b553..3c474db43 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -148,8 +148,6 @@ uint8_t smf_5gc_n4_handle_session_establishment_response( { int i; - ogs_sbi_stream_t *stream = NULL; - uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; uint8_t offending_ie_value = 0; @@ -164,9 +162,6 @@ uint8_t smf_5gc_n4_handle_session_establishment_response( ogs_debug("Session Establishment Response [5gc]"); - stream = xact->assoc_stream; - ogs_assert(stream); - ogs_pfcp_xact_commit(xact); if (rsp->up_f_seid.presence == 0) { @@ -732,7 +727,6 @@ uint8_t smf_epc_n4_handle_session_establishment_response( uint8_t cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; smf_bearer_t *bearer = NULL; - ogs_gtp_xact_t *gtp_xact = NULL; ogs_pfcp_f_seid_t *up_f_seid = NULL; @@ -742,9 +736,6 @@ uint8_t smf_epc_n4_handle_session_establishment_response( ogs_debug("Session Establishment Response [epc]"); - gtp_xact = xact->assoc_xact; - ogs_assert(gtp_xact); - ogs_pfcp_xact_commit(xact); if (rsp->up_f_seid.presence == 0) { diff --git a/src/smf/npcf-handler.c b/src/smf/npcf-handler.c index e902ada25..d126cb3b3 100644 --- a/src/smf/npcf-handler.c +++ b/src/smf/npcf-handler.c @@ -630,7 +630,7 @@ bool smf_npcf_smpolicycontrol_handle_create( up2cp_pdr->precedence = OGS_PFCP_UP2CP_PDR_PRECEDENCE; ogs_assert(OGS_OK == - smf_5gc_pfcp_send_session_establishment_request(sess, stream)); + smf_5gc_pfcp_send_session_establishment_request(sess, 0)); return true; diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index a636f18c3..e146ce2f6 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -362,7 +362,7 @@ int smf_pfcp_send_modify_list( } int smf_5gc_pfcp_send_session_establishment_request( - smf_sess_t *sess, ogs_sbi_stream_t *stream) + smf_sess_t *sess, uint64_t flags) { int rv; ogs_pkbuf_t *n4buf = NULL; @@ -370,7 +370,6 @@ int smf_5gc_pfcp_send_session_establishment_request( ogs_pfcp_xact_t *xact = NULL; ogs_assert(sess); - ogs_assert(stream); xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_5gc_timeout, sess); if (!xact) { @@ -378,14 +377,44 @@ int smf_5gc_pfcp_send_session_establishment_request( return OGS_ERROR; } - xact->assoc_stream = stream; xact->local_seid = sess->smf_n4_seid; + xact->create_flags = flags; memset(&h, 0, sizeof(ogs_pfcp_header_t)); h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; + +/* + * 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header + * + * If a peer's SEID is not available, the SEID field shall still be present + * in the header and its value shall be set to "0" in the following messages: + * + * - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4; + * + * - If a node receives a message for which it has no session, i.e. + * if SEID in the PFCP header is not known, it shall respond + * with "Session context not found" cause in the corresponding + * response message to the sender, the SEID used in the PFCP header + * in the response message shall be then set to "0"; + * + * - If a node receives a request message containing protocol error, + * e.g. Mandatory IE missing, which requires the receiver + * to reject the message as specified in clause 7.6, it shall reject + * the request message. For the response message, the node should look up + * the remote peer's SEID and accordingly set SEID in the PFCP header + * and the message cause code. As an implementation option, + * the node may not look up the remote peer's SEID and + * set the PFCP header SEID to "0" in the response message. + * However in this case, the cause value shall not be set + * to "Session not found". + * + * - When the UP function sends PFCP Session Report Request message + * over N4 towards another SMF or another PFCP entity in the SMF + * as specified in clause 5.22.2 and clause 5.22.3. + */ h.seid = sess->upf_n4_seid; - n4buf = smf_n4_build_session_establishment_request(h.type, sess); + n4buf = smf_n4_build_session_establishment_request(h.type, sess, xact); if (!n4buf) { ogs_error("smf_n4_build_session_establishment_request() failed"); return OGS_ERROR; @@ -506,7 +535,7 @@ int smf_5gc_pfcp_send_session_deletion_request( } int smf_epc_pfcp_send_session_establishment_request( - smf_sess_t *sess, void *gtp_xact) + smf_sess_t *sess, void *gtp_xact, uint64_t flags) { int rv; ogs_pkbuf_t *n4buf = NULL; @@ -524,12 +553,43 @@ int smf_epc_pfcp_send_session_establishment_request( xact->epc = true; /* EPC PFCP transaction */ xact->assoc_xact = gtp_xact; xact->local_seid = sess->smf_n4_seid; + xact->create_flags = flags; memset(&h, 0, sizeof(ogs_pfcp_header_t)); h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; + +/* + * 7.2.2.4.2 Conditions for Sending SEID=0 in PFCP Header + * + * If a peer's SEID is not available, the SEID field shall still be present + * in the header and its value shall be set to "0" in the following messages: + * + * - PFCP Session Establishment Request message on Sxa/Sxb/Sxc/N4; + * + * - If a node receives a message for which it has no session, i.e. + * if SEID in the PFCP header is not known, it shall respond + * with "Session context not found" cause in the corresponding + * response message to the sender, the SEID used in the PFCP header + * in the response message shall be then set to "0"; + * + * - If a node receives a request message containing protocol error, + * e.g. Mandatory IE missing, which requires the receiver + * to reject the message as specified in clause 7.6, it shall reject + * the request message. For the response message, the node should look up + * the remote peer's SEID and accordingly set SEID in the PFCP header + * and the message cause code. As an implementation option, + * the node may not look up the remote peer's SEID and + * set the PFCP header SEID to "0" in the response message. + * However in this case, the cause value shall not be set + * to "Session not found". + * + * - When the UP function sends PFCP Session Report Request message + * over N4 towards another SMF or another PFCP entity in the SMF + * as specified in clause 5.22.2 and clause 5.22.3. + */ h.seid = sess->upf_n4_seid; - n4buf = smf_n4_build_session_establishment_request(h.type, sess); + n4buf = smf_n4_build_session_establishment_request(h.type, sess, xact); if (!n4buf) { ogs_error("smf_n4_build_session_establishment_request() failed"); return OGS_ERROR; diff --git a/src/smf/pfcp-path.h b/src/smf/pfcp-path.h index a7a70180e..d05145f01 100644 --- a/src/smf/pfcp-path.h +++ b/src/smf/pfcp-path.h @@ -36,7 +36,7 @@ int smf_pfcp_send_modify_list( ogs_pfcp_xact_t *xact, ogs_time_t duration); int smf_5gc_pfcp_send_session_establishment_request( - smf_sess_t *sess, ogs_sbi_stream_t *stream); + smf_sess_t *sess, uint64_t flags); int smf_5gc_pfcp_send_all_pdr_modification_request( smf_sess_t *sess, ogs_sbi_stream_t *stream, uint64_t flags, ogs_time_t duration); @@ -47,7 +47,7 @@ int smf_5gc_pfcp_send_session_deletion_request( smf_sess_t *sess, ogs_sbi_stream_t *stream, int trigger); int smf_epc_pfcp_send_session_establishment_request( - smf_sess_t *sess, void *gtp_xact); + smf_sess_t *sess, void *gtp_xact, uint64_t flags); int smf_epc_pfcp_send_all_pdr_modification_request( smf_sess_t *sess, void *gtp_xact, ogs_pkbuf_t *gtpbuf, uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause); diff --git a/src/smf/pfcp-sm.c b/src/smf/pfcp-sm.c index 4dab934be..5b637dd08 100644 --- a/src/smf/pfcp-sm.c +++ b/src/smf/pfcp-sm.c @@ -22,6 +22,7 @@ #include "n4-handler.h" +static void pfcp_restoration(ogs_pfcp_node_t *node); static void reselect_upf(ogs_pfcp_node_t *node); static void node_timeout(ogs_pfcp_xact_t *xact, void *data); @@ -191,7 +192,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) ogs_pfcp_send_heartbeat_request(node, node_timeout)); if (node->restoration_required == true) { - /* PFCP Restoration is being performed after PFCP association */ + pfcp_restoration(node); node->restoration_required = false; ogs_error("PFCP restoration"); } @@ -244,6 +245,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) * If the peer PFCP entity is performing the association, * Restoration can be performed immediately. */ + pfcp_restoration(node); node->restoration_required = false; ogs_error("PFCP restoration"); } @@ -270,6 +272,7 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) * If the peer PFCP entity is performing the association, * Restoration can be performed immediately. */ + pfcp_restoration(node); node->restoration_required = false; ogs_error("PFCP restoration"); } @@ -409,10 +412,52 @@ void smf_pfcp_state_exception(ogs_fsm_t *s, smf_event_t *e) } } +static void pfcp_restoration(ogs_pfcp_node_t *node) +{ + smf_ue_t *smf_ue = NULL; + + char buf1[OGS_ADDRSTRLEN]; + char buf2[OGS_ADDRSTRLEN]; + + ogs_list_for_each(&smf_self()->smf_ue_list, smf_ue) { + smf_sess_t *sess = NULL; + ogs_assert(smf_ue); + + ogs_list_for_each(&smf_ue->sess_list, sess) { + ogs_assert(sess); + + if (node == sess->pfcp_node) { + if (sess->epc) { + ogs_info("UE IMSI[%s] APN[%s] IPv4[%s] IPv6[%s]", + smf_ue->imsi_bcd, sess->session.name, + sess->ipv4 ? + OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? + OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); + ogs_assert(OGS_OK == + smf_epc_pfcp_send_session_establishment_request( + sess, NULL, + OGS_PFCP_CREATE_RESTORATION_INDICATION)); + } else { + ogs_info("UE SUPI[%s] DNN[%s] IPv4[%s] IPv6[%s]", + smf_ue->supi, sess->session.name, + sess->ipv4 ? + OGS_INET_NTOP(&sess->ipv4->addr, buf1) : "", + sess->ipv6 ? + OGS_INET6_NTOP(&sess->ipv6->addr, buf2) : ""); + ogs_assert(OGS_OK == + smf_5gc_pfcp_send_session_establishment_request( + sess, OGS_PFCP_CREATE_RESTORATION_INDICATION)); + } + } + } + } +} + static void reselect_upf(ogs_pfcp_node_t *node) { int r; - smf_ue_t *smf_ue = NULL, *next_ue = NULL;; + smf_ue_t *smf_ue = NULL; ogs_pfcp_node_t *iter = NULL; ogs_assert(node); @@ -434,19 +479,18 @@ static void reselect_upf(ogs_pfcp_node_t *node) return; } - ogs_list_for_each_safe(&smf_self()->smf_ue_list, next_ue, smf_ue) { - smf_sess_t *sess = NULL, *next_sess = NULL;; + ogs_list_for_each(&smf_self()->smf_ue_list, smf_ue) { + smf_sess_t *sess = NULL; ogs_assert(smf_ue); - ogs_list_for_each_safe(&smf_ue->sess_list, next_sess, sess) { + ogs_list_for_each(&smf_ue->sess_list, sess) { ogs_assert(sess); - if (sess->epc) { - ogs_error("[%s:%s] EPC restoration is not implemented", - smf_ue->imsi_bcd, sess->session.name); - } else { - ogs_assert(sess->sm_context_ref); - if (node == sess->pfcp_node) { + if (node == sess->pfcp_node) { + if (sess->epc) { + ogs_error("[%s:%s] EPC restoration is not implemented", + smf_ue->imsi_bcd, sess->session.name); + } else { smf_npcf_smpolicycontrol_param_t param; ogs_info("[%s:%d] SMF-initiated Deletion", @@ -479,18 +523,6 @@ static void node_timeout(ogs_pfcp_xact_t *xact, void *data) switch (type) { case OGS_PFCP_HEARTBEAT_REQUEST_TYPE: ogs_assert(data); - - - /* - * The code below is not secure. - * Session does not differentiate between EPC and 5GC. - * And, it does not check whether there are other PFCP Nodes. - * - * So, UPF redundancy will be implemented later. - * - * We plan to do this again after testing with restoration first - * in case peer PFCP restarts. - */ reselect_upf(data); e = smf_event_new(SMF_EVT_N4_NO_HEARTBEAT); diff --git a/src/upf/context.c b/src/upf/context.c index c6a664073..663c9ae97 100644 --- a/src/upf/context.c +++ b/src/upf/context.c @@ -367,7 +367,10 @@ upf_sess_t *upf_sess_add_by_message(ogs_pfcp_message_t *message) sess = upf_sess_find_by_smf_n4_f_seid(f_seid); if (!sess) { sess = upf_sess_add(f_seid); - if (!sess) return NULL; + if (!sess) { + ogs_error("No Session Context"); + return NULL; + } } ogs_assert(sess); diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c index f6bc70ef4..a40b34b43 100644 --- a/src/upf/gtp-path.c +++ b/src/upf/gtp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -425,6 +425,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) switch(pfcp_object->type) { case OGS_PFCP_OBJ_PDR_TYPE: + /* UPF does not use PDR TYPE */ + ogs_assert_if_reached(); pdr = (ogs_pfcp_pdr_t *)pfcp_object; ogs_assert(pdr); break; diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index b5cd61f4f..c273ef441 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2023 by Sukchan Lee * * This file is part of Open5GS. * @@ -55,6 +55,9 @@ void upf_n4_handle_session_establishment_request( uint8_t offending_ie_value = 0; int i; + ogs_pfcp_sereq_flags_t sereq_flags; + bool restoration_indication = false; + upf_metrics_inst_global_inc(UPF_METR_GLOB_CTR_SM_N4SESSIONESTABREQ); ogs_assert(xact); @@ -74,9 +77,14 @@ void upf_n4_handle_session_establishment_request( return; } + memset(&sereq_flags, 0, sizeof(sereq_flags)); + if (req->pfcpsereq_flags.presence == 1) + sereq_flags.value = req->pfcpsereq_flags.u8; + for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp, - &req->create_pdr[i], &cause_value, &offending_ie_value); + &req->create_pdr[i], &sereq_flags, + &cause_value, &offending_ie_value); if (created_pdr[i] == NULL) break; } @@ -116,6 +124,18 @@ void upf_n4_handle_session_establishment_request( if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) goto cleanup; + /* PFCPSEReq-Flags */ + if (sereq_flags.restoration_indication == 1) { + for (i = 0; i < num_of_created_pdr; i++) { + pdr = created_pdr[i]; + ogs_assert(pdr); + + if (pdr->f_teid_len) + ogs_pfcp_pdr_swap_teid(pdr); + } + restoration_indication = true; + } + /* Setup GTP Node */ ogs_list_for_each(&sess->pfcp.far_list, far) { ogs_assert(OGS_ERROR != ogs_pfcp_setup_far_gtpu_node(far)); @@ -155,65 +175,9 @@ void upf_n4_handle_session_establishment_request( } /* Setup UPF-N3-TEID & QFI Hash */ - if (pdr->f_teid_len) { - ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE; - - if (ogs_pfcp_self()->up_function_features.ftup && - pdr->f_teid.ch) { - - ogs_pfcp_pdr_t *choosed_pdr = NULL; - - if (pdr->f_teid.chid) { - choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( - &sess->pfcp, pdr->f_teid.choose_id); - if (!choosed_pdr) { - pdr->chid = true; - pdr->choose_id = pdr->f_teid.choose_id; - } - } else { - type = OGS_PFCP_OBJ_PDR_TYPE; - } - - if (choosed_pdr) { - pdr->f_teid_len = choosed_pdr->f_teid_len; - memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); - - } else { - ogs_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_find_gtpu_resource( - &ogs_gtp_self()->gtpu_resource_list, - pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_assert( - (resource->info.v4 && pdr->f_teid.ipv4) || - (resource->info.v6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_user_plane_ip_resource_info_to_f_teid( - &resource->info, &pdr->f_teid, &pdr->f_teid_len)); - if (resource->info.teidri) - pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - pdr->teid, resource->info.teidri, - resource->info.teid_range); - else - pdr->f_teid.teid = pdr->teid; - } else { - ogs_assert( - (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || - (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_sockaddr_to_f_teid( - pdr->f_teid.ipv4 ? - ogs_gtp_self()->gtpu_addr : NULL, - pdr->f_teid.ipv6 ? - ogs_gtp_self()->gtpu_addr6 : NULL, - &pdr->f_teid, &pdr->f_teid_len)); - pdr->f_teid.teid = pdr->teid; - } - } - } - - ogs_pfcp_object_teid_hash_set(type, pdr); - } + if (pdr->f_teid_len) + ogs_pfcp_object_teid_hash_set( + OGS_PFCP_OBJ_SESS_TYPE, pdr, restoration_indication); } /* Send Buffered Packet to gNB/SGW */ @@ -223,9 +187,16 @@ void upf_n4_handle_session_establishment_request( } } - ogs_assert(OGS_OK == - upf_pfcp_send_session_establishment_response( - xact, sess, created_pdr, num_of_created_pdr)); + if (restoration_indication == true || + ogs_pfcp_self()->up_function_features.ftup == 0) + ogs_assert(OGS_OK == + upf_pfcp_send_session_establishment_response( + xact, sess, NULL, 0)); + else + ogs_assert(OGS_OK == + upf_pfcp_send_session_establishment_response( + xact, sess, created_pdr, num_of_created_pdr)); + return; cleanup: @@ -266,7 +237,7 @@ void upf_n4_handle_session_modification_request( for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) { created_pdr[i] = ogs_pfcp_handle_create_pdr(&sess->pfcp, - &req->create_pdr[i], &cause_value, &offending_ie_value); + &req->create_pdr[i], NULL, &cause_value, &offending_ie_value); if (created_pdr[i] == NULL) break; } @@ -399,70 +370,13 @@ void upf_n4_handle_session_modification_request( ogs_pfcp_far_f_teid_hash_set(far); } - /* Setup UPF-N3-TEID & QFI Hash */ for (i = 0; i < num_of_created_pdr; i++) { pdr = created_pdr[i]; ogs_assert(pdr); - if (pdr->f_teid_len) { - ogs_pfcp_object_type_e type = OGS_PFCP_OBJ_SESS_TYPE; - - if (ogs_pfcp_self()->up_function_features.ftup && - pdr->f_teid.ch) { - - ogs_pfcp_pdr_t *choosed_pdr = NULL; - - if (pdr->f_teid.chid) { - choosed_pdr = ogs_pfcp_pdr_find_by_choose_id( - &sess->pfcp, pdr->f_teid.choose_id); - if (!choosed_pdr) { - pdr->chid = true; - pdr->choose_id = pdr->f_teid.choose_id; - } - } else { - type = OGS_PFCP_OBJ_PDR_TYPE; - } - - if (choosed_pdr) { - pdr->f_teid_len = choosed_pdr->f_teid_len; - memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len); - - } else { - ogs_gtpu_resource_t *resource = NULL; - resource = ogs_pfcp_find_gtpu_resource( - &ogs_gtp_self()->gtpu_resource_list, - pdr->dnn, OGS_PFCP_INTERFACE_ACCESS); - if (resource) { - ogs_assert( - (resource->info.v4 && pdr->f_teid.ipv4) || - (resource->info.v6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_user_plane_ip_resource_info_to_f_teid( - &resource->info, &pdr->f_teid, &pdr->f_teid_len)); - if (resource->info.teidri) - pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID( - pdr->teid, resource->info.teidri, - resource->info.teid_range); - else - pdr->f_teid.teid = pdr->teid; - } else { - ogs_assert( - (ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) || - (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6)); - ogs_assert(OGS_OK == - ogs_pfcp_sockaddr_to_f_teid( - pdr->f_teid.ipv4 ? - ogs_gtp_self()->gtpu_addr : NULL, - pdr->f_teid.ipv6 ? - ogs_gtp_self()->gtpu_addr6 : NULL, - &pdr->f_teid, &pdr->f_teid_len)); - pdr->f_teid.teid = pdr->teid; - } - } - } - - ogs_pfcp_object_teid_hash_set(type, pdr); - } + /* Setup UPF-N3-TEID & QFI Hash */ + if (pdr->f_teid_len) + ogs_pfcp_object_teid_hash_set(OGS_PFCP_OBJ_SESS_TYPE, pdr, false); } /* Send Buffered Packet to gNB/SGW */ @@ -472,9 +386,14 @@ void upf_n4_handle_session_modification_request( } } - ogs_assert(OGS_OK == - upf_pfcp_send_session_modification_response( - xact, sess, created_pdr, num_of_created_pdr)); + if (ogs_pfcp_self()->up_function_features.ftup == 0) + ogs_assert(OGS_OK == + upf_pfcp_send_session_modification_response( + xact, sess, NULL, 0)); + else + ogs_assert(OGS_OK == + upf_pfcp_send_session_modification_response( + xact, sess, created_pdr, num_of_created_pdr)); return; cleanup: diff --git a/src/upf/pfcp-path.c b/src/upf/pfcp-path.c index 4e64d6b74..16c9c0544 100644 --- a/src/upf/pfcp-path.c +++ b/src/upf/pfcp-path.c @@ -208,7 +208,6 @@ int upf_pfcp_send_session_modification_response( ogs_pfcp_header_t h; ogs_assert(xact); - ogs_assert(created_pdr); memset(&h, 0, sizeof(ogs_pfcp_header_t)); h.type = OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE; diff --git a/src/upf/pfcp-sm.c b/src/upf/pfcp-sm.c index 787ac2dca..980bcb60d 100644 --- a/src/upf/pfcp-sm.c +++ b/src/upf/pfcp-sm.c @@ -281,12 +281,9 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e) &message->pfcp_association_setup_response); break; case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE: - if (message->h.seid_presence && message->h.seid == 0) { - ogs_expect(!sess); - sess = upf_sess_add_by_message(message); - if (sess) - OGS_SETUP_PFCP_NODE(sess, node); - } + sess = upf_sess_add_by_message(message); + if (sess) + OGS_SETUP_PFCP_NODE(sess, node); upf_n4_handle_session_establishment_request( sess, xact, &message->pfcp_session_establishment_request); break;