open5gs/src/upf/n4-handler.c

742 lines
22 KiB
C
Raw Normal View History

2020-04-26 19:36:05 +00:00
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "context.h"
#include "pfcp-path.h"
#include "gtp-path.h"
2020-04-26 19:36:05 +00:00
#include "n4-handler.h"
void upf_n4_handle_association_setup_request(
ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact,
ogs_pfcp_association_setup_request_t *req)
{
ogs_assert(xact);
upf_pfcp_send_association_setup_response(
xact, OGS_PFCP_CAUSE_REQUEST_ACCEPTED);
}
void upf_n4_handle_association_setup_response(
ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact,
ogs_pfcp_association_setup_response_t *rsp)
{
ogs_assert(xact);
ogs_pfcp_xact_commit(xact);
}
void upf_n4_handle_heartbeat_request(
ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact,
ogs_pfcp_heartbeat_request_t *req)
{
ogs_assert(xact);
ogs_pfcp_send_heartbeat_response(xact);
}
void upf_n4_handle_heartbeat_response(
ogs_pfcp_node_t *node, ogs_pfcp_xact_t *xact,
ogs_pfcp_heartbeat_response_t *rsp)
{
ogs_assert(xact);
ogs_pfcp_xact_commit(xact);
2020-07-27 01:02:40 +00:00
ogs_timer_start(node->t_no_heartbeat,
ogs_config()->time.message.pfcp.no_heartbeat_duration);
2020-04-26 19:36:05 +00:00
}
2020-07-20 01:42:58 +00:00
static void setup_gtp_node(ogs_pfcp_far_t *far,
ogs_pfcp_tlv_outer_header_creation_t *outer_header_creation)
{
int rv;
ogs_ip_t ip;
ogs_gtp_node_t *gnode = NULL;
ogs_assert(far);
ogs_assert(outer_header_creation);
ogs_assert(outer_header_creation->presence);
memcpy(&far->outer_header_creation,
outer_header_creation->data, outer_header_creation->len);
far->outer_header_creation.teid = be32toh(far->outer_header_creation.teid);
rv = ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip);
ogs_assert(rv == OGS_OK);
gnode = ogs_gtp_node_find_by_ip(&upf_self()->gnb_n3_list, &ip);
if (!gnode) {
gnode = ogs_gtp_node_add_by_ip(
&upf_self()->gnb_n3_list, &ip, upf_self()->gtpu_port,
ogs_config()->parameter.no_ipv4,
ogs_config()->parameter.no_ipv6,
ogs_config()->parameter.prefer_ipv4);
ogs_assert(gnode);
rv = ogs_gtp_connect(
upf_self()->gtpu_sock, upf_self()->gtpu_sock6, gnode);
ogs_assert(rv == OGS_OK);
}
OGS_SETUP_GTP_NODE(far, gnode);
}
2020-04-26 19:36:05 +00:00
static ogs_pfcp_pdr_t *handle_create_pdr(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_create_pdr_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_pdr_t *pdr = NULL;
ogs_pfcp_far_t *far = NULL;
ogs_pfcp_qer_t *qer = NULL;
int i, len;
int rv;
ogs_assert(sess);
ogs_assert(message);
if (message->presence == 0)
return NULL;
if (message->pdr_id.presence == 0) {
ogs_warn("No PDR-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_PDR_ID_TYPE;
return NULL;
}
if (message->precedence.presence == 0) {
ogs_warn("No Presence in PDR");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_PRECEDENCE_TYPE;
return NULL;
}
pdr = ogs_pfcp_pdr_find_or_add(sess, message->pdr_id.u16);
ogs_assert(pdr);
ogs_pfcp_pdr_reorder_by_precedence(pdr, message->precedence.u32);
if (message->pdi.presence == 0) {
ogs_warn("No PDI in PDR");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_PDI_TYPE;
return NULL;
}
if (message->pdi.source_interface.presence == 0) {
ogs_warn("No Source Interface in PDI");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_SOURCE_INTERFACE_TYPE;
return NULL;
}
pdr->precedence = message->precedence.u32;
pdr->src_if = message->pdi.source_interface.u8;
for (i = 0; i < OGS_MAX_NUM_OF_RULE; i++) {
ogs_pfcp_sdf_filter_t sdf_filter_in_message;
if (message->pdi.sdf_filter[i].presence == 0)
break;
len = ogs_pfcp_parse_sdf_filter(
&sdf_filter_in_message, &message->pdi.sdf_filter[i]);
ogs_assert(message->pdi.sdf_filter[i].len == len);
if (sdf_filter_in_message.fd) {
upf_sdf_filter_t *sdf_filter = NULL;
char *flow_description = NULL;
flow_description = ogs_malloc(
sdf_filter_in_message.flow_description_len+1);
ogs_cpystrn(flow_description,
sdf_filter_in_message.flow_description,
sdf_filter_in_message.flow_description_len+1);
sdf_filter = upf_sdf_filter_add(pdr);
ogs_assert(sdf_filter);
rv = ogs_ipfw_compile_rule(&sdf_filter->rule, flow_description);
ogs_assert(rv == OGS_OK);
sdf_filter->pdr = pdr;
ogs_free(flow_description);
}
}
/* APN(Network Instance) and UE IP Address
* has already been processed in upf_sess_add() */
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
/* Nothing */
} else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
if (message->pdi.local_f_teid.presence == 0) {
ogs_warn("No F-TEID in PDI");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_F_TEID_TYPE;
return NULL;
}
if (message->outer_header_removal.presence == 0) {
ogs_warn("No Outer Header Removal in PDI");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_OUTER_HEADER_REMOVAL_TYPE;
return NULL;
}
2020-07-20 01:42:58 +00:00
pdr->f_teid_len = message->pdi.local_f_teid.len;
memcpy(&pdr->f_teid, message->pdi.local_f_teid.data, pdr->f_teid_len);
2020-04-26 19:36:05 +00:00
pdr->f_teid.teid = be32toh(pdr->f_teid.teid);
2020-07-20 01:42:58 +00:00
2020-04-26 19:36:05 +00:00
memcpy(&pdr->outer_header_removal,
message->outer_header_removal.data,
message->outer_header_removal.len);
} else {
ogs_error("Invalid Source Interface[%d] in PDR", pdr->src_if);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
*offending_ie_value = OGS_PFCP_SOURCE_INTERFACE_TYPE;
return NULL;
}
if (message->far_id.presence) {
far = ogs_pfcp_far_find_or_add(sess, message->far_id.u32);
ogs_assert(far);
ogs_pfcp_pdr_associate_far(pdr, far);
}
if (message->qer_id.presence) {
qer = ogs_pfcp_qer_find_or_add(sess, message->qer_id.u32);
ogs_assert(qer);
ogs_pfcp_pdr_associate_qer(pdr, qer);
}
return pdr;
}
static bool handle_remove_pdr(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_remove_pdr_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_pdr_t *pdr = NULL;
ogs_assert(sess);
ogs_assert(message);
if (message->presence == 0)
return false;
if (message->pdr_id.presence == 0) {
ogs_warn("No PDR-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_PDR_ID_TYPE;
return false;
}
pdr = ogs_pfcp_pdr_find(sess, message->pdr_id.u16);
if (!pdr) {
ogs_error("Unknown PDR-ID[%d]", message->pdr_id.u16);
*cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
return false;
}
ogs_pfcp_pdr_remove(pdr);
return true;
}
static ogs_pfcp_far_t *handle_create_far(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_create_far_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_far_t *far = NULL;
ogs_assert(message);
ogs_assert(sess);
if (message->presence == 0)
return NULL;
if (message->far_id.presence == 0) {
ogs_warn("No FAR-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
far = ogs_pfcp_far_find(sess, message->far_id.u32);
if (!far) {
ogs_error("Cannot find FAR-ID[%d] in PDR", message->far_id.u32);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
if (message->apply_action.presence == 0) {
ogs_warn("No Apply Action");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_APPLY_ACTION_TYPE;
return NULL;
}
if (message->forwarding_parameters.
destination_interface.presence == 0) {
2020-06-17 05:22:28 +00:00
return far;
2020-04-26 19:36:05 +00:00
}
far->apply_action = message->apply_action.u8;
far->dst_if = message->forwarding_parameters.destination_interface.u8;
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
2020-06-17 05:22:28 +00:00
if (message->forwarding_parameters.outer_header_creation.presence) {
2020-07-20 01:42:58 +00:00
setup_gtp_node(far,
&message->forwarding_parameters.outer_header_creation);
2020-04-26 19:36:05 +00:00
}
2020-06-22 03:07:14 +00:00
2020-06-17 05:22:28 +00:00
} else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */
2020-04-26 19:36:05 +00:00
2020-06-17 05:22:28 +00:00
/* Nothing */
} else {
ogs_error("Invalid Destination Interface[%d] in FAR", far->dst_if);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
*offending_ie_value = OGS_PFCP_DESTINATION_INTERFACE_TYPE;
return NULL;
}
return far;
}
static ogs_pfcp_far_t *handle_update_far(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_update_far_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_far_t *far = NULL;
ogs_assert(message);
ogs_assert(sess);
if (message->presence == 0)
return NULL;
if (message->far_id.presence == 0) {
ogs_warn("No FAR-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
far = ogs_pfcp_far_find(sess, message->far_id.u32);
if (!far) {
ogs_error("Cannot find FAR-ID[%d] in PDR", message->far_id.u32);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
if (message->apply_action.presence)
far->apply_action = message->apply_action.u8;
if (message->update_forwarding_parameters.
destination_interface.presence == 0)
far->dst_if = message->update_forwarding_parameters.
destination_interface.u8;
if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { /* Downlink */
if (message->update_forwarding_parameters.
outer_header_creation.presence) {
2020-07-20 01:42:58 +00:00
setup_gtp_node(far,
&message->update_forwarding_parameters.outer_header_creation);
2020-04-26 19:36:05 +00:00
}
2020-06-22 03:07:14 +00:00
2020-04-26 19:36:05 +00:00
} else if (far->dst_if == OGS_PFCP_INTERFACE_CORE) { /* Uplink */
/* Nothing */
} else {
ogs_error("Invalid Destination Interface[%d] in FAR", far->dst_if);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
*offending_ie_value = OGS_PFCP_DESTINATION_INTERFACE_TYPE;
return NULL;
}
return far;
}
static bool handle_remove_far(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_remove_far_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_far_t *far = NULL;
ogs_assert(sess);
ogs_assert(message);
if (message->presence == 0)
return false;
if (message->far_id.presence == 0) {
ogs_warn("No FAR-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return false;
}
far = ogs_pfcp_far_find(sess, message->far_id.u32);
if (!far) {
ogs_error("Unknown FAR-ID[%d]", message->far_id.u32);
*cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
return false;
}
ogs_pfcp_far_remove(far);
return true;
}
static ogs_pfcp_qer_t *handle_create_qer(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_create_qer_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_qer_t *qer = NULL;
ogs_assert(message);
ogs_assert(sess);
if (message->presence == 0)
return NULL;
if (message->qer_id.presence == 0) {
ogs_warn("No QER-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
qer = ogs_pfcp_qer_find(sess, message->qer_id.u32);
if (!qer) {
ogs_error("Cannot find QER-ID[%d] in PDR", message->qer_id.u32);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
if (message->gate_status.presence == 0) {
ogs_warn("No Gate Status");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_APPLY_ACTION_TYPE;
return NULL;
}
qer->gate_status.value = message->gate_status.u8;
if (message->maximum_bitrate.presence)
ogs_pfcp_parse_bitrate(&qer->mbr, &message->maximum_bitrate);
if (message->guaranteed_bitrate.presence)
ogs_pfcp_parse_bitrate(&qer->gbr, &message->guaranteed_bitrate);
2020-07-18 03:29:45 +00:00
if (message->qos_flow_identifier.presence)
qer->qfi = message->qos_flow_identifier.u8;
2020-04-26 19:36:05 +00:00
return qer;
}
static ogs_pfcp_qer_t *handle_update_qer(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_update_qer_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_qer_t *qer = NULL;
ogs_assert(message);
ogs_assert(sess);
if (message->presence == 0)
return NULL;
if (message->qer_id.presence == 0) {
ogs_warn("No QER-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
qer = ogs_pfcp_qer_find(sess, message->qer_id.u32);
if (!qer) {
ogs_error("Cannot find QER-ID[%d] in PDR", message->qer_id.u32);
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
*offending_ie_value = OGS_PFCP_FAR_ID_TYPE;
return NULL;
}
if (message->maximum_bitrate.presence)
ogs_pfcp_parse_bitrate(&qer->mbr, &message->maximum_bitrate);
if (message->guaranteed_bitrate.presence)
ogs_pfcp_parse_bitrate(&qer->gbr, &message->guaranteed_bitrate);
return qer;
}
static bool handle_remove_qer(ogs_pfcp_sess_t *sess,
ogs_pfcp_tlv_remove_qer_t *message,
uint8_t *cause_value, uint8_t *offending_ie_value)
{
ogs_pfcp_qer_t *qer = NULL;
ogs_assert(sess);
ogs_assert(message);
if (message->presence == 0)
return false;
if (message->qer_id.presence == 0) {
ogs_warn("No QER-ID");
*cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING;
*offending_ie_value = OGS_PFCP_QER_ID_TYPE;
return false;
}
qer = ogs_pfcp_qer_find(sess, message->qer_id.u32);
if (!qer) {
ogs_error("Unknown QER-ID[%d]", message->qer_id.u32);
*cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
return false;
}
ogs_pfcp_qer_remove(qer);
return true;
}
void upf_n4_handle_session_establishment_request(
upf_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_establishment_request_t *req)
{
2020-07-20 01:42:58 +00:00
ogs_pfcp_pdr_t *pdr = NULL;
2020-04-26 19:36:05 +00:00
ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR];
int num_of_created_pdr = 0;
uint8_t cause_value = 0;
uint8_t offending_ie_value = 0;
int i;
ogs_assert(xact);
ogs_assert(req);
2020-07-09 05:38:09 +00:00
ogs_debug("Session Establishment Request");
2020-04-26 19:36:05 +00:00
cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
if (!sess) {
ogs_warn("No Context");
ogs_pfcp_send_error_message(xact, 0,
OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE,
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
return;
}
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
created_pdr[i] = handle_create_pdr(&sess->pfcp,
&req->create_pdr[i], &cause_value, &offending_ie_value);
if (created_pdr[i] == NULL)
break;
}
num_of_created_pdr = i;
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_FAR; i++) {
if (handle_create_far(&sess->pfcp, &req->create_far[i],
&cause_value, &offending_ie_value) == NULL)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_QER; i++) {
if (handle_create_qer(&sess->pfcp, &req->create_qer[i],
&cause_value, &offending_ie_value) == NULL)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
2020-07-20 01:42:58 +00:00
/* Setup UPF-N3-TEID & QFI Hash */
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
if (pdr->f_teid_len)
ogs_pfcp_pdr_hash_set(pdr);
}
}
/* Send Buffered Packet to gNB/SGW */
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
upf_gtp_send_buffered_packet(pdr);
}
}
2020-04-26 19:36:05 +00:00
upf_pfcp_send_session_establishment_response(
xact, sess, created_pdr, num_of_created_pdr);
return;
cleanup:
ogs_pfcp_sess_clear(&sess->pfcp);
ogs_pfcp_send_error_message(xact, sess ? sess->smf_n4_seid : 0,
OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE,
cause_value, offending_ie_value);
}
void upf_n4_handle_session_modification_request(
upf_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_modification_request_t *req)
{
2020-07-20 01:42:58 +00:00
ogs_pfcp_pdr_t *pdr = NULL;
2020-04-26 19:36:05 +00:00
ogs_pfcp_pdr_t *created_pdr[OGS_MAX_NUM_OF_PDR];
int num_of_created_pdr = 0;
uint8_t cause_value = 0;
uint8_t offending_ie_value = 0;
int i;
ogs_assert(xact);
ogs_assert(req);
2020-07-09 05:38:09 +00:00
ogs_debug("Session Modification Request");
2020-04-26 19:36:05 +00:00
cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
if (!sess) {
ogs_warn("No Context");
ogs_pfcp_send_error_message(xact, 0,
OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE,
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
return;
}
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
created_pdr[i] = handle_create_pdr(&sess->pfcp,
&req->create_pdr[i], &cause_value, &offending_ie_value);
if (created_pdr[i] == NULL)
break;
}
num_of_created_pdr = i;
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
if (handle_remove_pdr(&sess->pfcp, &req->remove_pdr[i],
&cause_value, &offending_ie_value) == false)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_FAR; i++) {
if (handle_create_far(&sess->pfcp, &req->create_far[i],
&cause_value, &offending_ie_value) == NULL)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
2020-06-17 05:22:28 +00:00
for (i = 0; i < OGS_MAX_NUM_OF_FAR; i++) {
if (handle_update_far(&sess->pfcp, &req->update_far[i],
&cause_value, &offending_ie_value) == NULL)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_FAR; i++) {
2020-04-26 19:36:05 +00:00
if (handle_remove_far(&sess->pfcp, &req->remove_far[i],
&cause_value, &offending_ie_value) == false)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_QER; i++) {
if (handle_create_qer(&sess->pfcp, &req->create_qer[i],
&cause_value, &offending_ie_value) == NULL)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_QER; i++) {
if (handle_update_qer(&sess->pfcp, &req->update_qer[i],
&cause_value, &offending_ie_value) == NULL)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
2020-06-17 05:22:28 +00:00
for (i = 0; i < OGS_MAX_NUM_OF_QER; i++) {
2020-04-26 19:36:05 +00:00
if (handle_remove_qer(&sess->pfcp, &req->remove_qer[i],
&cause_value, &offending_ie_value) == false)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
2020-07-20 01:42:58 +00:00
/* Setup UPF-N3-TEID & QFI Hash */
for (i = 0; i < num_of_created_pdr; i++) {
pdr = created_pdr[i];
ogs_assert(pdr);
if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS) { /* Uplink */
if (pdr->f_teid_len)
ogs_pfcp_pdr_hash_set(pdr);
}
}
/* Send Buffered Packet to gNB/SGW */
ogs_list_for_each(&sess->pfcp.pdr_list, pdr) {
if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { /* Downlink */
upf_gtp_send_buffered_packet(pdr);
}
}
2020-04-26 19:36:05 +00:00
upf_pfcp_send_session_modification_response(
xact, sess, created_pdr, num_of_created_pdr);
return;
cleanup:
ogs_pfcp_sess_clear(&sess->pfcp);
ogs_pfcp_send_error_message(xact, sess ? sess->smf_n4_seid : 0,
OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE,
cause_value, offending_ie_value);
}
void upf_n4_handle_session_deletion_request(
upf_sess_t *sess, ogs_pfcp_xact_t *xact,
ogs_pfcp_session_deletion_request_t *req)
{
ogs_assert(xact);
ogs_assert(req);
2020-07-09 05:38:09 +00:00
ogs_debug("Session Deletion Request");
2020-04-26 19:36:05 +00:00
if (!sess) {
ogs_warn("No Context");
ogs_pfcp_send_error_message(xact, 0,
2020-07-04 03:14:48 +00:00
OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE,
2020-04-26 19:36:05 +00:00
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
return;
}
ogs_assert(sess);
upf_pfcp_send_session_deletion_response(xact, sess);
upf_sess_remove(sess);
}