open5gs/src/smf/binding.c

672 lines
24 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/>.
*/
2021-01-01 02:07:08 +00:00
#include "binding.h"
2020-04-26 19:36:05 +00:00
#include "s5c-build.h"
#include "pfcp-path.h"
2021-06-21 13:36:38 +00:00
#include "gtp-path.h"
2020-04-26 19:36:05 +00:00
#include "ipfw/ipfw2.h"
static void gtp_bearer_timeout(ogs_gtp_xact_t *xact, void *data)
2020-04-26 19:36:05 +00:00
{
2020-11-07 22:27:12 +00:00
smf_bearer_t *bearer = data;
smf_sess_t *sess = NULL;
smf_ue_t *smf_ue = NULL;
2020-04-26 19:36:05 +00:00
uint8_t type = 0;
2020-11-07 22:27:12 +00:00
ogs_assert(bearer);
sess = bearer->sess;
2020-04-26 19:36:05 +00:00
ogs_assert(sess);
2020-11-07 22:27:12 +00:00
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
2020-04-26 19:36:05 +00:00
type = xact->seq[0].type;
2020-11-07 22:27:12 +00:00
switch (type) {
case OGS_GTP2_CREATE_BEARER_REQUEST_TYPE:
2020-11-07 22:27:12 +00:00
ogs_error("[%s] No Create Bearer Response", smf_ue->imsi_bcd);
if (!smf_bearer_cycle(bearer)) {
ogs_warn("[%s] Bearer has already been removed", smf_ue->imsi_bcd);
break;
}
ogs_assert(OGS_OK ==
smf_epc_pfcp_send_bearer_modification_request(
bearer, NULL, OGS_PFCP_MODIFY_REMOVE,
OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED,
OGS_GTP2_CAUSE_UNDEFINED_VALUE));
2020-11-07 22:27:12 +00:00
break;
case OGS_GTP2_UPDATE_BEARER_REQUEST_TYPE:
2020-11-07 22:27:12 +00:00
ogs_error("[%s] No Update Bearer Response", smf_ue->imsi_bcd);
break;
default:
ogs_error("GTP Timeout : IMSI[%s] Message-Type[%d]",
smf_ue->imsi_bcd, type);
break;
}
2020-04-26 19:36:05 +00:00
}
/*
* Issue #338
*
* <DOWNLINK>
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
*
* <UPLINK>
* RULE : Source <UE_IP> <UE_PORT> Destination <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
* TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
*/
2020-04-26 19:36:05 +00:00
static void encode_traffic_flow_template(
ogs_gtp2_tft_t *tft, smf_bearer_t *bearer, uint8_t tft_operation_code)
2020-04-26 19:36:05 +00:00
{
2021-01-01 02:07:08 +00:00
int i;
2020-04-26 19:36:05 +00:00
smf_pf_t *pf = NULL;
ogs_assert(tft);
ogs_assert(bearer);
2020-04-26 19:36:05 +00:00
memset(tft, 0, sizeof(*tft));
tft->code = tft_operation_code;
2020-04-26 19:36:05 +00:00
i = 0;
if (tft_operation_code != OGS_GTP2_TFT_CODE_DELETE_EXISTING_TFT &&
tft_operation_code != OGS_GTP2_TFT_CODE_NO_TFT_OPERATION) {
ogs_list_for_each_entry(&bearer->pf_to_add_list, pf, to_add_node) {
ogs_assert(i < OGS_MAX_NUM_OF_FLOW_IN_GTP);
tft->pf[i].identifier = pf->identifier - 1;
/* Deletion of packet filters
* from existing requires only the identifier */
if (tft_operation_code !=
OGS_GTP2_TFT_CODE_DELETE_PACKET_FILTERS_FROM_EXISTING) {
tft->pf[i].direction = pf->direction;
tft->pf[i].precedence = pf->precedence - 1;
2020-04-26 19:36:05 +00:00
ogs_pf_content_from_ipfw_rule(
pf->direction, &tft->pf[i].content, &pf->ipfw_rule,
ogs_app()->
parameter.no_ipv4v6_local_addr_in_packet_filter);
}
2020-04-26 19:36:05 +00:00
i++;
}
2020-04-26 19:36:05 +00:00
}
tft->num_of_packet_filter = i;
}
void smf_bearer_binding(smf_sess_t *sess)
{
int rv;
int i, j;
ogs_assert(sess);
2021-11-14 12:07:56 +00:00
for (i = 0; i < sess->policy.num_of_pcc_rule; i++) {
2020-04-26 19:36:05 +00:00
ogs_gtp_xact_t *xact = NULL;
ogs_gtp2_header_t h;
2020-04-26 19:36:05 +00:00
ogs_pkbuf_t *pkbuf = NULL;
smf_bearer_t *bearer = NULL;
2021-11-14 12:07:56 +00:00
ogs_pcc_rule_t *pcc_rule = &sess->policy.pcc_rule[i];
2020-04-26 19:36:05 +00:00
ogs_assert(pcc_rule);
if (pcc_rule->name == NULL) {
ogs_error("No PCC Rule Name");
continue;
}
if (pcc_rule->type == OGS_PCC_RULE_TYPE_INSTALL) {
2021-11-14 12:07:56 +00:00
bool bearer_created = false;
bool qos_presence = false;
2020-04-26 19:36:05 +00:00
bearer = smf_bearer_find_by_pcc_rule_name(sess, pcc_rule->name);
2020-04-26 19:36:05 +00:00
if (!bearer) {
2021-11-14 12:07:56 +00:00
ogs_pfcp_pdr_t *dl_pdr = NULL, *ul_pdr = NULL;
2020-04-26 19:36:05 +00:00
if (pcc_rule->num_of_flow == 0) {
/* TFT is mandatory in
* activate dedicated EPS bearer context request */
ogs_error("No flow in PCC Rule");
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;
}
2020-04-26 19:36:05 +00:00
bearer = smf_bearer_add(sess);
ogs_assert(bearer);
2021-03-15 01:01:55 +00:00
dl_pdr = bearer->dl_pdr;
ogs_assert(dl_pdr);
ul_pdr = bearer->ul_pdr;
ogs_assert(ul_pdr);
2020-04-26 19:36:05 +00:00
/* Precedence is set to the order in which it was created */
2021-03-15 01:01:55 +00:00
dl_pdr->precedence = dl_pdr->id;
ul_pdr->precedence = ul_pdr->id;
ogs_assert(sess->pfcp_node);
if (sess->pfcp_node->up_function_features.ftup) {
ul_pdr->f_teid.ch = 1;
ul_pdr->f_teid_len = 1;
} else {
2021-05-30 11:35:30 +00:00
ogs_gtpu_resource_t *resource = NULL;
resource = ogs_pfcp_find_gtpu_resource(
2021-03-15 01:01:55 +00:00
&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,
&bearer->pgw_s5u_addr, &bearer->pgw_s5u_addr6);
if (resource->info.teidri)
bearer->pgw_s5u_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
ul_pdr->index, resource->info.teidri,
2021-03-15 01:01:55 +00:00
resource->info.teid_range);
else
bearer->pgw_s5u_teid = ul_pdr->index;
2021-03-15 01:01:55 +00:00
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
2021-06-06 13:35:46 +00:00
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(&bearer->pgw_s5u_addr,
&sess->pfcp_node->addr));
2021-03-15 01:01:55 +00:00
else if (sess->pfcp_node->addr.ogs_sa_family ==
AF_INET6)
2021-06-06 13:35:46 +00:00
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(&bearer->pgw_s5u_addr6,
&sess->pfcp_node->addr));
2021-03-15 01:01:55 +00:00
else
ogs_assert_if_reached();
bearer->pgw_s5u_teid = ul_pdr->index;
2021-03-15 01:01:55 +00:00
}
2021-05-30 11:35:30 +00:00
ogs_assert(OGS_OK ==
ogs_pfcp_sockaddr_to_f_teid(
bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6,
&ul_pdr->f_teid, &ul_pdr->f_teid_len));
2021-03-15 01:01:55 +00:00
ul_pdr->f_teid.teid = bearer->pgw_s5u_teid;
}
2020-04-26 19:36:05 +00:00
2021-01-01 02:07:08 +00:00
bearer->pcc_rule.name = ogs_strdup(pcc_rule->name);
ogs_assert(bearer->pcc_rule.name);
2020-04-26 19:36:05 +00:00
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(ogs_qos_t));
2021-11-14 12:07:56 +00:00
bearer_created = true;
2020-08-13 00:31:22 +00:00
2020-04-26 19:36:05 +00:00
} else {
2021-01-01 02:07:08 +00:00
ogs_assert(strcmp(bearer->pcc_rule.name, pcc_rule->name) == 0);
2020-04-26 19:36:05 +00:00
if ((pcc_rule->qos.mbr.downlink &&
bearer->qos.mbr.downlink != pcc_rule->qos.mbr.downlink) ||
(pcc_rule->qos.mbr.uplink &&
bearer->qos.mbr.uplink != pcc_rule->qos.mbr.uplink) ||
(pcc_rule->qos.gbr.downlink &&
bearer->qos.gbr.downlink != pcc_rule->qos.gbr.downlink) ||
(pcc_rule->qos.gbr.uplink &&
bearer->qos.gbr.uplink != pcc_rule->qos.gbr.uplink)) {
/* Update QoS parameter */
memcpy(&bearer->qos, &pcc_rule->qos, sizeof(ogs_qos_t));
/* Update Bearer Request encodes updated QoS parameter */
2021-11-14 12:07:56 +00:00
qos_presence = true;
2020-04-26 19:36:05 +00:00
}
}
/*
* We only use the method of adding a flow to an existing tft.
*
* EPC: OGS_GTP2_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT
* 5GC: OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_ADD_PACKET_FILTERS
*/
ogs_list_init(&bearer->pf_to_add_list);
2020-04-26 19:36:05 +00:00
for (j = 0; j < pcc_rule->num_of_flow; j++) {
smf_pf_t *pf = NULL;
2021-11-14 12:07:56 +00:00
ogs_flow_t *flow = &pcc_rule->flow[j];
2020-04-26 19:36:05 +00:00
ogs_expect_or_return(flow);
ogs_expect_or_return(flow->description);
2021-11-14 12:07:56 +00:00
/*
* To add a flow to an existing tft.
* duplicated flows are not added
*/
if (smf_pf_find_by_flow(
bearer, flow->direction, flow->description) != NULL) {
continue;
}
2021-11-14 12:07:56 +00:00
/*
* To add a flow to an existing tft.
*
* Only new flows are added to the PF list.
* Then, in the PF list, there are all flows
* from the beginning to the present.
*/
2021-01-01 02:07:08 +00:00
pf = smf_pf_add(bearer);
if (!pf) {
ogs_error("Overflow: PacketFilter in Bearer");
break;
}
2020-04-26 19:36:05 +00:00
pf->direction = flow->direction;
2020-08-13 00:31:22 +00:00
pf->flow_description = ogs_strdup(flow->description);
2021-06-06 13:35:46 +00:00
ogs_assert(pf->flow_description);
2020-08-13 00:31:22 +00:00
rv = ogs_ipfw_compile_rule(
&pf->ipfw_rule, pf->flow_description);
/*
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
*
* <UPLINK>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* -->
* RULE : Source <UE_IP> <UE_PORT> Destination <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
*/
if (flow->direction == OGS_FLOW_UPLINK_ONLY)
ogs_ipfw_rule_swap(&pf->ipfw_rule);
2020-08-13 00:31:22 +00:00
if (rv != OGS_OK) {
ogs_error("Invalid Flow-Description[%s]",
pf->flow_description);
smf_pf_remove(pf);
break;
}
2021-11-14 12:07:56 +00:00
/*
* To add a flow to an existing tft.
*
* 'pf_to_add_list' now has the added flow.
*/
ogs_list_add(&bearer->pf_to_add_list, &pf->to_add_node);
2020-04-26 19:36:05 +00:00
}
2021-11-14 12:07:56 +00:00
if (bearer_created == false &&
qos_presence == false &&
ogs_list_count(&bearer->pf_to_add_list) == 0) {
ogs_warn("No need to send 'Update Bearer Request'");
ogs_warn("bearer_created:%d, qos_presence:%d, rule_count:%d",
2021-11-14 12:07:56 +00:00
bearer_created, qos_presence,
ogs_list_count(&bearer->pf_to_add_list));
continue;
}
2021-11-14 12:07:56 +00:00
if (bearer_created == true) {
2021-11-14 12:07:56 +00:00
smf_bearer_tft_update(bearer);
smf_bearer_qos_update(bearer);
2020-04-26 19:36:05 +00:00
ogs_assert(OGS_OK ==
smf_epc_pfcp_send_bearer_modification_request(
bearer, NULL, OGS_PFCP_MODIFY_CREATE,
OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED,
OGS_GTP2_CAUSE_UNDEFINED_VALUE));
} else {
ogs_gtp2_tft_t tft;
2020-04-26 19:36:05 +00:00
memset(&tft, 0, sizeof tft);
2021-11-14 12:07:56 +00:00
if (ogs_list_count(&bearer->pf_to_add_list) > 0) {
encode_traffic_flow_template(
&tft, bearer,
OGS_GTP2_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT);
}
memset(&h, 0, sizeof(ogs_gtp2_header_t));
h.type = OGS_GTP2_UPDATE_BEARER_REQUEST_TYPE;
2020-04-26 19:36:05 +00:00
h.teid = sess->sgw_s5c_teid;
pkbuf = smf_s5c_build_update_bearer_request(
h.type, bearer,
OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED,
2021-11-14 12:07:56 +00:00
(ogs_list_count(&bearer->pf_to_add_list) > 0) ?
&tft : NULL, qos_presence);
2020-04-26 19:36:05 +00:00
ogs_expect_or_return(pkbuf);
2020-08-13 00:31:22 +00:00
xact = ogs_gtp_xact_local_create(
sess->gnode, &h, pkbuf, gtp_bearer_timeout, bearer);
2020-08-13 00:31:22 +00:00
ogs_expect_or_return(xact);
2021-11-14 12:07:56 +00:00
if (ogs_list_count(&bearer->pf_to_add_list) > 0)
2020-08-13 00:31:22 +00:00
xact->update_flags |= OGS_GTP_MODIFY_TFT_UPDATE;
2021-11-14 12:07:56 +00:00
if (qos_presence == true)
2020-08-13 00:31:22 +00:00
xact->update_flags |= OGS_GTP_MODIFY_QOS_UPDATE;
2020-04-26 19:36:05 +00:00
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
}
2020-08-13 00:31:22 +00:00
2020-04-26 19:36:05 +00:00
} else if (pcc_rule->type == OGS_PCC_RULE_TYPE_REMOVE) {
2021-01-01 02:07:08 +00:00
bearer = smf_bearer_find_by_pcc_rule_name(sess, pcc_rule->name);
2020-04-26 19:36:05 +00:00
if (!bearer) {
ogs_warn("No need to send 'Delete Bearer Request'");
ogs_warn(" - Bearer[Name:%s] has already been removed.",
pcc_rule->name);
continue;
2020-04-26 19:36:05 +00:00
}
/*
* 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).
*/
2021-06-21 13:36:38 +00:00
ogs_assert(OGS_OK ==
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_GTP2_CAUSE_UNDEFINED_VALUE));
2020-04-26 19:36:05 +00:00
} else {
ogs_error("Invalid Type[%d]", pcc_rule->type);
}
}
}
int smf_gtp2_send_create_bearer_request(smf_bearer_t *bearer)
{
int rv;
smf_sess_t *sess = NULL;
ogs_gtp_xact_t *xact = NULL;
ogs_gtp2_header_t h;
ogs_pkbuf_t *pkbuf = NULL;
ogs_gtp2_tft_t tft;
ogs_assert(bearer);
sess = bearer->sess;
ogs_assert(sess);
h.type = OGS_GTP2_CREATE_BEARER_REQUEST_TYPE;
h.teid = sess->sgw_s5c_teid;
memset(&tft, 0, sizeof tft);
encode_traffic_flow_template(
&tft, bearer, OGS_GTP2_TFT_CODE_CREATE_NEW_TFT);
pkbuf = smf_s5c_build_create_bearer_request(h.type, bearer, &tft);
2021-06-06 13:35:46 +00:00
ogs_expect_or_return_val(pkbuf, OGS_ERROR);
2020-11-07 22:27:12 +00:00
xact = ogs_gtp_xact_local_create(
sess->gnode, &h, pkbuf, gtp_bearer_timeout, bearer);
2021-06-06 13:35:46 +00:00
ogs_expect_or_return_val(xact, OGS_ERROR);
rv = ogs_gtp_xact_commit(xact);
ogs_expect(rv == OGS_OK);
2021-06-06 13:35:46 +00:00
return rv;
}
2021-01-01 02:07:08 +00:00
2021-11-14 12:07:56 +00:00
void smf_qos_flow_binding(smf_sess_t *sess)
2021-01-01 02:07:08 +00:00
{
int rv;
int i, j;
uint64_t pfcp_flags, check;
2021-01-01 02:07:08 +00:00
ogs_assert(sess);
pfcp_flags = OGS_PFCP_MODIFY_NETWORK_REQUESTED;
ogs_list_init(&sess->qos_flow_to_modify_list);
2021-11-14 12:07:56 +00:00
for (i = 0; i < sess->policy.num_of_pcc_rule; i++) {
2021-01-01 02:07:08 +00:00
smf_bearer_t *qos_flow = NULL;
2021-11-14 12:07:56 +00:00
ogs_pcc_rule_t *pcc_rule = &sess->policy.pcc_rule[i];
2021-01-01 02:07:08 +00:00
ogs_assert(pcc_rule);
if (pcc_rule->id == NULL) {
ogs_error("No PCC Rule Id");
continue;
}
if (pcc_rule->type == OGS_PCC_RULE_TYPE_INSTALL) {
2021-11-14 12:07:56 +00:00
smf_pf_t *pf = NULL;
2021-01-01 02:07:08 +00:00
ogs_pfcp_pdr_t *dl_pdr = NULL, *ul_pdr = NULL;
2021-11-14 12:07:56 +00:00
bool qos_flow_created = false;
bool qos_presence = false;
qos_flow = smf_qos_flow_find_by_pcc_rule_id(sess, pcc_rule->id);
2021-01-01 02:07:08 +00:00
if (!qos_flow) {
if (pcc_rule->num_of_flow == 0) {
/* TFT is mandatory in
* activate dedicated EPS bearer context request */
ogs_error("No flow in PCC Rule");
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;
}
2021-01-01 02:07:08 +00:00
qos_flow = smf_qos_flow_add(sess);
ogs_assert(qos_flow);
dl_pdr = qos_flow->dl_pdr;
ogs_assert(dl_pdr);
ul_pdr = qos_flow->ul_pdr;
ogs_assert(ul_pdr);
/* Precedence is derived from PCC Rule Precedence */
dl_pdr->precedence = pcc_rule->precedence;
ul_pdr->precedence = pcc_rule->precedence;
/* Set UPF-N3 TEID & ADDR to the UL PDR */
ogs_assert(sess->pfcp_node);
if (sess->pfcp_node->up_function_features.ftup) {
ul_pdr->f_teid.ch = 1;
ul_pdr->f_teid.chid = 1;
ul_pdr->f_teid.choose_id = OGS_PFCP_DEFAULT_CHOOSE_ID;
ul_pdr->f_teid_len = 2;
} else {
2021-05-30 11:35:30 +00:00
ogs_assert(OGS_OK ==
ogs_pfcp_sockaddr_to_f_teid(
2021-01-01 02:07:08 +00:00
sess->upf_n3_addr, sess->upf_n3_addr6,
2021-05-30 11:35:30 +00:00
&ul_pdr->f_teid, &ul_pdr->f_teid_len));
2021-01-01 02:07:08 +00:00
ul_pdr->f_teid.teid = sess->upf_n3_teid;
}
qos_flow->pcc_rule.id = ogs_strdup(pcc_rule->id);
ogs_assert(qos_flow->pcc_rule.id);
memcpy(&qos_flow->qos, &pcc_rule->qos, sizeof(ogs_qos_t));
2021-11-14 12:07:56 +00:00
qos_flow_created = true;
2021-01-01 02:07:08 +00:00
} else {
ogs_assert(strcmp(qos_flow->pcc_rule.id, pcc_rule->id) == 0);
if ((pcc_rule->qos.mbr.downlink &&
qos_flow->qos.mbr.downlink != pcc_rule->qos.mbr.downlink) ||
(pcc_rule->qos.mbr.uplink &&
qos_flow->qos.mbr.uplink != pcc_rule->qos.mbr.uplink) ||
(pcc_rule->qos.gbr.downlink &&
qos_flow->qos.gbr.downlink != pcc_rule->qos.gbr.downlink) ||
(pcc_rule->qos.gbr.uplink &&
qos_flow->qos.gbr.uplink != pcc_rule->qos.gbr.uplink)) {
/* Update QoS parameter */
memcpy(&qos_flow->qos, &pcc_rule->qos, sizeof(ogs_qos_t));
/* Update Bearer Request encodes updated QoS parameter */
2021-11-14 12:07:56 +00:00
qos_presence = true;
2021-01-01 02:07:08 +00:00
}
}
/*
* We only use the method of adding a flow to an existing tft.
*
* EPC: OGS_GTP2_TFT_CODE_ADD_PACKET_FILTERS_TO_EXISTING_TFT
* 5GC: OGS_NAS_QOS_CODE_MODIFY_EXISTING_QOS_RULE_AND_ADD_PACKET_FILTERS
*/
ogs_list_init(&qos_flow->pf_to_add_list);
2021-01-01 02:07:08 +00:00
for (j = 0; j < pcc_rule->num_of_flow; j++) {
ogs_flow_t *flow = &pcc_rule->flow[j];
ogs_expect_or_return(flow);
ogs_expect_or_return(flow->description);
2021-11-14 12:07:56 +00:00
/*
* To add a flow to an existing tft.
* duplicated flows are not added
*/
if (smf_pf_find_by_flow(
qos_flow, flow->direction, flow->description) != NULL) {
continue;
}
2021-11-14 12:07:56 +00:00
/*
* To add a flow to an existing tft.
*
* Only new flows are added to the PF list.
* Then, in the PF list, there are all flows
* from the beginning to the present.
*/
2021-01-01 02:07:08 +00:00
pf = smf_pf_add(qos_flow);
2021-11-14 12:07:56 +00:00
if (!pf) {
ogs_error("Overflow: PacketFilter in Bearer");
break;
}
2021-01-01 02:07:08 +00:00
pf->direction = flow->direction;
pf->flow_description = ogs_strdup(flow->description);
2021-06-06 13:35:46 +00:00
ogs_assert(pf->flow_description);
2021-01-01 02:07:08 +00:00
rv = ogs_ipfw_compile_rule(
&pf->ipfw_rule, pf->flow_description);
/*
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* -->
* RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
*
* <UPLINK>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* -->
* RULE : Source <UE_IP> <UE_PORT> Destination <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
*/
if (flow->direction == OGS_FLOW_UPLINK_ONLY)
ogs_ipfw_rule_swap(&pf->ipfw_rule);
if (rv != OGS_OK) {
ogs_error("Invalid Flow-Description[%s]",
pf->flow_description);
smf_pf_remove(pf);
break;
}
2021-11-14 12:07:56 +00:00
/*
* To add a flow to an existing tft.
*
* 'pf_to_add_list' now has the added flow.
*/
ogs_list_add(&qos_flow->pf_to_add_list, &pf->to_add_node);
2021-01-01 02:07:08 +00:00
}
2021-11-14 12:07:56 +00:00
if (qos_flow_created == false &&
qos_presence == false &&
ogs_list_count(&qos_flow->pf_to_add_list) == 0) {
ogs_warn("No need to send 'Session Modification Request'");
ogs_warn("qos_flow_created:%d, qos_presence:%d, rule_count:%d",
2021-11-14 12:07:56 +00:00
qos_flow_created, qos_presence,
ogs_list_count(&qos_flow->pf_to_add_list));
continue;
}
2021-01-01 02:07:08 +00:00
2021-11-14 12:07:56 +00:00
if (qos_flow_created == true) {
smf_bearer_tft_update(qos_flow);
smf_bearer_qos_update(qos_flow);
2021-01-01 02:07:08 +00:00
pfcp_flags |= OGS_PFCP_MODIFY_CREATE;
2021-01-01 02:07:08 +00:00
ogs_list_add(&sess->qos_flow_to_modify_list,
&qos_flow->to_modify_node);
2021-01-01 02:07:08 +00:00
} else {
2021-11-14 12:07:56 +00:00
pfcp_flags |= OGS_PFCP_MODIFY_NETWORK_REQUESTED;
2021-01-01 02:07:08 +00:00
2021-11-14 12:07:56 +00:00
if (ogs_list_count(&qos_flow->pf_to_add_list) > 0) {
pfcp_flags |= OGS_PFCP_MODIFY_TFT_ADD;
smf_bearer_tft_update(qos_flow);
}
if (qos_presence == true) {
pfcp_flags |= OGS_PFCP_MODIFY_QOS_MODIFY;
smf_bearer_qos_update(qos_flow);
}
2021-01-01 02:07:08 +00:00
ogs_list_add(&sess->qos_flow_to_modify_list,
&qos_flow->to_modify_node);
2021-01-01 02:07:08 +00:00
}
} else if (pcc_rule->type == OGS_PCC_RULE_TYPE_REMOVE) {
2021-11-14 12:07:56 +00:00
qos_flow = smf_qos_flow_find_by_pcc_rule_id(sess, pcc_rule->id);
2021-01-01 02:07:08 +00:00
if (!qos_flow) {
2021-11-14 12:07:56 +00:00
ogs_warn("No need to send 'Session Modification Request'");
ogs_warn(" - QosFlow[Id:%s] has already been removed.",
pcc_rule->id);
2021-01-01 02:07:08 +00:00
continue;
}
pfcp_flags |= OGS_PFCP_MODIFY_REMOVE;
ogs_list_add(&sess->qos_flow_to_modify_list,
&qos_flow->to_modify_node);
2021-01-01 02:07:08 +00:00
} else {
ogs_error("Invalid Type[%d]", pcc_rule->type);
ogs_assert_if_reached();
}
}
check = pfcp_flags & (OGS_PFCP_MODIFY_CREATE|OGS_PFCP_MODIFY_REMOVE);
if (check != 0 &&
check != OGS_PFCP_MODIFY_CREATE && check != OGS_PFCP_MODIFY_REMOVE) {
ogs_fatal("Invalid flags[%ld]", pfcp_flags);
ogs_assert_if_reached();
}
if (ogs_list_count(&sess->qos_flow_to_modify_list)) {
ogs_assert(OGS_OK ==
smf_5gc_pfcp_send_session_modification_request(
sess, NULL, pfcp_flags, 0));
}
2021-01-01 02:07:08 +00:00
}