2020-08-13 00:31:22 +00:00
|
|
|
/*
|
2023-04-09 01:34:19 +00:00
|
|
|
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
|
2020-08-13 00:31:22 +00:00
|
|
|
*
|
|
|
|
* 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 <yaml.h>
|
|
|
|
|
|
|
|
#include "context.h"
|
|
|
|
|
|
|
|
static sgwc_context_t self;
|
|
|
|
|
|
|
|
int __sgwc_log_domain;
|
|
|
|
|
|
|
|
static OGS_POOL(sgwc_bearer_pool, sgwc_bearer_t);
|
|
|
|
static OGS_POOL(sgwc_tunnel_pool, sgwc_tunnel_t);
|
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
static OGS_POOL(sgwc_ue_pool, sgwc_ue_t);
|
|
|
|
static OGS_POOL(sgwc_s11_teid_pool, ogs_pool_id_t);
|
|
|
|
|
|
|
|
static OGS_POOL(sgwc_sess_pool, sgwc_sess_t);
|
|
|
|
static OGS_POOL(sgwc_sxa_seid_pool, ogs_pool_id_t);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
static int context_initialized = 0;
|
|
|
|
|
2020-09-05 03:36:51 +00:00
|
|
|
static int num_of_sgwc_sess = 0;
|
|
|
|
|
|
|
|
static void stats_add_sgwc_session(void);
|
|
|
|
static void stats_remove_sgwc_session(void);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
void sgwc_context_init(void)
|
|
|
|
{
|
|
|
|
ogs_assert(context_initialized == 0);
|
|
|
|
|
|
|
|
memset(&self, 0, sizeof(sgwc_context_t));
|
|
|
|
|
|
|
|
ogs_log_install_domain(&__sgwc_log_domain, "sgwc", ogs_core()->log.level);
|
|
|
|
|
2020-08-26 03:05:01 +00:00
|
|
|
ogs_pool_init(&sgwc_bearer_pool, ogs_app()->pool.bearer);
|
|
|
|
ogs_pool_init(&sgwc_tunnel_pool, ogs_app()->pool.tunnel);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2023-11-19 10:34:51 +00:00
|
|
|
ogs_pool_init(&sgwc_ue_pool, ogs_global_conf()->max.ue);
|
|
|
|
ogs_pool_init(&sgwc_s11_teid_pool, ogs_global_conf()->max.ue);
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_pool_random_id_generate(&sgwc_s11_teid_pool);
|
|
|
|
|
|
|
|
ogs_pool_init(&sgwc_sess_pool, ogs_app()->pool.sess);
|
|
|
|
ogs_pool_init(&sgwc_sxa_seid_pool, ogs_app()->pool.sess);
|
|
|
|
ogs_pool_random_id_generate(&sgwc_sxa_seid_pool);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
self.imsi_ue_hash = ogs_hash_make();
|
2021-06-06 13:35:46 +00:00
|
|
|
ogs_assert(self.imsi_ue_hash);
|
2023-04-09 01:34:19 +00:00
|
|
|
self.sgw_s11_teid_hash = ogs_hash_make();
|
|
|
|
ogs_assert(self.sgw_s11_teid_hash);
|
|
|
|
self.sgwc_sxa_seid_hash = ogs_hash_make();
|
|
|
|
ogs_assert(self.sgwc_sxa_seid_hash);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
ogs_list_init(&self.sgw_ue_list);
|
|
|
|
|
|
|
|
context_initialized = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sgwc_context_final(void)
|
|
|
|
{
|
|
|
|
ogs_assert(context_initialized == 1);
|
|
|
|
|
|
|
|
sgwc_ue_remove_all();
|
|
|
|
|
|
|
|
ogs_assert(self.imsi_ue_hash);
|
|
|
|
ogs_hash_destroy(self.imsi_ue_hash);
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_assert(self.sgw_s11_teid_hash);
|
|
|
|
ogs_hash_destroy(self.sgw_s11_teid_hash);
|
|
|
|
ogs_assert(self.sgwc_sxa_seid_hash);
|
|
|
|
ogs_hash_destroy(self.sgwc_sxa_seid_hash);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
ogs_pool_final(&sgwc_tunnel_pool);
|
|
|
|
ogs_pool_final(&sgwc_bearer_pool);
|
2023-04-09 01:34:19 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_pool_final(&sgwc_ue_pool);
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_pool_final(&sgwc_s11_teid_pool);
|
|
|
|
|
|
|
|
ogs_pool_final(&sgwc_sess_pool);
|
|
|
|
ogs_pool_final(&sgwc_sxa_seid_pool);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
ogs_gtp_node_remove_all(&self.mme_s11_list);
|
|
|
|
ogs_gtp_node_remove_all(&self.pgw_s5c_list);
|
|
|
|
|
|
|
|
context_initialized = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_context_t *sgwc_self(void)
|
|
|
|
{
|
|
|
|
return &self;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sgwc_context_prepare(void)
|
|
|
|
{
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sgwc_context_validation(void)
|
|
|
|
{
|
2021-03-15 01:01:55 +00:00
|
|
|
if (ogs_list_empty(&ogs_gtp_self()->gtpc_list) &&
|
|
|
|
ogs_list_empty(&ogs_gtp_self()->gtpc_list6)) {
|
2020-08-26 03:05:01 +00:00
|
|
|
ogs_error("No sgwc.gtpc in '%s'", ogs_app()->file);
|
2020-08-13 00:31:22 +00:00
|
|
|
return OGS_ERROR;
|
|
|
|
}
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sgwc_context_parse_config(void)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
yaml_document_t *document = NULL;
|
|
|
|
ogs_yaml_iter_t root_iter;
|
|
|
|
|
2020-08-26 03:05:01 +00:00
|
|
|
document = ogs_app()->document;
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(document);
|
|
|
|
|
|
|
|
rv = sgwc_context_prepare();
|
|
|
|
if (rv != OGS_OK) return rv;
|
|
|
|
|
|
|
|
ogs_yaml_iter_init(&root_iter, document);
|
|
|
|
while (ogs_yaml_iter_next(&root_iter)) {
|
|
|
|
const char *root_key = ogs_yaml_iter_key(&root_iter);
|
|
|
|
ogs_assert(root_key);
|
|
|
|
if (!strcmp(root_key, "sgwc")) {
|
|
|
|
ogs_yaml_iter_t sgwc_iter;
|
|
|
|
ogs_yaml_iter_recurse(&root_iter, &sgwc_iter);
|
|
|
|
while (ogs_yaml_iter_next(&sgwc_iter)) {
|
|
|
|
const char *sgwc_key = ogs_yaml_iter_key(&sgwc_iter);
|
|
|
|
ogs_assert(sgwc_key);
|
|
|
|
if (!strcmp(sgwc_key, "gtpc")) {
|
2021-03-15 01:01:55 +00:00
|
|
|
/* handle config in gtp library */
|
2020-08-13 00:31:22 +00:00
|
|
|
} else if (!strcmp(sgwc_key, "pfcp")) {
|
|
|
|
/* handle config in pfcp library */
|
2023-11-19 10:34:51 +00:00
|
|
|
} else if (!strcmp(sgwc_key, "sgwu")) {
|
|
|
|
/* handle config in pfcp library */
|
2020-08-13 00:31:22 +00:00
|
|
|
} else
|
|
|
|
ogs_warn("unknown key `%s`", sgwc_key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = sgwc_context_validation();
|
|
|
|
if (rv != OGS_OK) return rv;
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
2022-04-12 22:07:39 +00:00
|
|
|
sgwc_ue_t *sgwc_ue_add_by_message(ogs_gtp2_message_t *message)
|
2020-08-13 00:31:22 +00:00
|
|
|
{
|
|
|
|
sgwc_ue_t *sgwc_ue = NULL;
|
2022-04-12 22:07:39 +00:00
|
|
|
ogs_gtp2_create_session_request_t *req = &message->create_session_request;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
ogs_assert(message);
|
|
|
|
|
|
|
|
req = &message->create_session_request;
|
|
|
|
if (req->imsi.presence == 0) {
|
|
|
|
ogs_error("No IMSI");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ogs_trace("sgwc_ue_add_by_message() - IMSI ");
|
|
|
|
ogs_log_hexdump(OGS_LOG_TRACE, req->imsi.data, req->imsi.len);
|
|
|
|
|
2022-04-12 22:07:39 +00:00
|
|
|
/*
|
2020-08-13 00:31:22 +00:00
|
|
|
* 7.2.1 in 3GPP TS 29.274 Release 15
|
|
|
|
*
|
|
|
|
* If the new Create Session Request received by the SGW collides with
|
|
|
|
* an existing active PDN connection context (the existing PDN connection
|
|
|
|
* context is identified with the tuple [IMSI, EPS Bearer ID], where IMSI
|
|
|
|
* shall be replaced by TAC and SNR part of ME Identity for emergency
|
|
|
|
* attached UE without UICC or authenticated IMSI), this Create Session
|
|
|
|
* Request shall be treated as a request for a new session. Before creating
|
|
|
|
* the new session, the SGW should delete:
|
|
|
|
*
|
|
|
|
* - the existing PDN connection context locally, if the Create Session
|
|
|
|
* Request is received with the TEID set to zero in the header, or
|
|
|
|
* if it is received with a TEID not set to zero in the header and
|
|
|
|
* it collides with the default bearer of an existing PDN connection
|
|
|
|
* context;
|
|
|
|
* - the existing dedicated bearer context locally, if the Create Session
|
|
|
|
* Request collides with an existing dedicated bearer context and
|
|
|
|
* the message is received with a TEID not set to zero in the header.
|
|
|
|
*/
|
|
|
|
sgwc_ue = sgwc_ue_find_by_imsi(req->imsi.data, req->imsi.len);
|
|
|
|
if (sgwc_ue)
|
|
|
|
sgwc_ue_remove(sgwc_ue);
|
|
|
|
sgwc_ue = sgwc_ue_add(req->imsi.data, req->imsi.len);
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
return sgwc_ue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_ue_t *sgwc_ue_add(uint8_t *imsi, int imsi_len)
|
|
|
|
{
|
|
|
|
sgwc_ue_t *sgwc_ue = NULL;
|
|
|
|
|
|
|
|
ogs_assert(imsi);
|
|
|
|
ogs_assert(imsi_len);
|
|
|
|
|
|
|
|
ogs_pool_alloc(&sgwc_ue_pool, &sgwc_ue);
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
memset(sgwc_ue, 0, sizeof *sgwc_ue);
|
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
/* Set SGW-S11-TEID */
|
|
|
|
ogs_pool_alloc(&sgwc_s11_teid_pool, &sgwc_ue->sgw_s11_teid_node);
|
|
|
|
ogs_assert(sgwc_ue->sgw_s11_teid_node);
|
|
|
|
|
|
|
|
sgwc_ue->sgw_s11_teid = *(sgwc_ue->sgw_s11_teid_node);
|
|
|
|
|
|
|
|
ogs_hash_set(self.sgw_s11_teid_hash,
|
|
|
|
&sgwc_ue->sgw_s11_teid, sizeof(sgwc_ue->sgw_s11_teid), sgwc_ue);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
/* Set IMSI */
|
2024-05-17 11:25:49 +00:00
|
|
|
sgwc_ue->imsi_len = ogs_min(imsi_len, OGS_MAX_IMSI_LEN);
|
2020-08-13 00:31:22 +00:00
|
|
|
memcpy(sgwc_ue->imsi, imsi, sgwc_ue->imsi_len);
|
|
|
|
ogs_buffer_to_bcd(sgwc_ue->imsi, sgwc_ue->imsi_len, sgwc_ue->imsi_bcd);
|
|
|
|
|
|
|
|
ogs_list_init(&sgwc_ue->sess_list);
|
|
|
|
|
|
|
|
ogs_hash_set(self.imsi_ue_hash, sgwc_ue->imsi, sgwc_ue->imsi_len, sgwc_ue);
|
|
|
|
|
|
|
|
ogs_list_add(&self.sgw_ue_list, sgwc_ue);
|
|
|
|
|
2020-09-05 03:36:51 +00:00
|
|
|
ogs_info("[Added] Number of SGWC-UEs is now %d",
|
|
|
|
ogs_list_count(&self.sgw_ue_list));
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
return sgwc_ue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sgwc_ue_remove(sgwc_ue_t *sgwc_ue)
|
|
|
|
{
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
ogs_list_remove(&self.sgw_ue_list, sgwc_ue);
|
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_hash_set(self.sgw_s11_teid_hash,
|
|
|
|
&sgwc_ue->sgw_s11_teid, sizeof(sgwc_ue->sgw_s11_teid), NULL);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_hash_set(self.imsi_ue_hash, sgwc_ue->imsi, sgwc_ue->imsi_len, NULL);
|
|
|
|
|
|
|
|
sgwc_sess_remove_all(sgwc_ue);
|
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_pool_free(&sgwc_s11_teid_pool, sgwc_ue->sgw_s11_teid_node);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_pool_free(&sgwc_ue_pool, sgwc_ue);
|
|
|
|
|
2020-09-05 03:36:51 +00:00
|
|
|
ogs_info("[Removed] Number of SGWC-UEs is now %d",
|
|
|
|
ogs_list_count(&self.sgw_ue_list));
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sgwc_ue_remove_all(void)
|
|
|
|
{
|
|
|
|
sgwc_ue_t *sgwc_ue = NULL, *next = NULL;;
|
|
|
|
|
|
|
|
ogs_list_for_each_safe(&self.sgw_ue_list, next, sgwc_ue)
|
|
|
|
sgwc_ue_remove(sgwc_ue);
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_ue_t *sgwc_ue_find_by_imsi_bcd(char *imsi_bcd)
|
|
|
|
{
|
|
|
|
uint8_t imsi[OGS_MAX_IMSI_LEN];
|
|
|
|
int imsi_len = 0;
|
|
|
|
|
|
|
|
ogs_assert(imsi_bcd);
|
|
|
|
|
|
|
|
ogs_bcd_to_buffer(imsi_bcd, imsi, &imsi_len);
|
|
|
|
|
|
|
|
return sgwc_ue_find_by_imsi(imsi, imsi_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_ue_t *sgwc_ue_find_by_imsi(uint8_t *imsi, int imsi_len)
|
|
|
|
{
|
|
|
|
ogs_assert(imsi && imsi_len);
|
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
return ogs_hash_get(self.imsi_ue_hash, imsi, imsi_len);
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_ue_t *sgwc_ue_find_by_teid(uint32_t teid)
|
|
|
|
{
|
2023-04-09 01:34:19 +00:00
|
|
|
return ogs_hash_get(self.sgw_s11_teid_hash, &teid, sizeof(teid));
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_sess_t *sgwc_sess_add(sgwc_ue_t *sgwc_ue, char *apn)
|
|
|
|
{
|
|
|
|
sgwc_sess_t *sess = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
ogs_pool_alloc(&sgwc_sess_pool, &sess);
|
|
|
|
if (!sess) {
|
2020-08-26 03:05:01 +00:00
|
|
|
ogs_error("Maximum number of session[%lld] reached",
|
|
|
|
(long long)ogs_app()->pool.sess);
|
2020-08-13 00:31:22 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(sess, 0, sizeof *sess);
|
|
|
|
|
2020-09-01 02:41:39 +00:00
|
|
|
ogs_pfcp_pool_init(&sess->pfcp);
|
2020-08-29 14:53:02 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
/* Set TEID & SEID */
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_pool_alloc(&sgwc_sxa_seid_pool, &sess->sgwc_sxa_seid_node);
|
|
|
|
ogs_assert(sess->sgwc_sxa_seid_node);
|
|
|
|
|
|
|
|
sess->sgw_s5c_teid = *(sess->sgwc_sxa_seid_node);
|
|
|
|
sess->sgwc_sxa_seid = *(sess->sgwc_sxa_seid_node);
|
|
|
|
|
|
|
|
ogs_hash_set(self.sgwc_sxa_seid_hash,
|
|
|
|
&sess->sgwc_sxa_seid, sizeof(sess->sgwc_sxa_seid), sess);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2020-12-03 06:16:57 +00:00
|
|
|
/* Create BAR in PFCP Session */
|
|
|
|
ogs_pfcp_bar_new(&sess->pfcp);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
/* Set APN */
|
2021-03-08 12:25:09 +00:00
|
|
|
sess->session.name = ogs_strdup(apn);
|
|
|
|
ogs_assert(sess->session.name);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
sess->sgwc_ue = sgwc_ue;
|
|
|
|
|
|
|
|
ogs_list_add(&sgwc_ue->sess_list, sess);
|
|
|
|
|
2020-09-05 03:36:51 +00:00
|
|
|
stats_add_sgwc_session();
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
return sess;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool compare_ue_info(ogs_pfcp_node_t *node, sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
sgwc_ue_t *sgwc_ue = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ogs_assert(node);
|
|
|
|
ogs_assert(sess);
|
|
|
|
sgwc_ue = sess->sgwc_ue;
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
2021-03-08 12:25:09 +00:00
|
|
|
ogs_assert(sess->session.name);
|
2020-12-03 06:16:57 +00:00
|
|
|
for (i = 0; i < node->num_of_dnn; i++)
|
2021-03-08 12:25:09 +00:00
|
|
|
if (ogs_strcasecmp(node->dnn[i], sess->session.name) == 0) return true;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
for (i = 0; i < node->num_of_e_cell_id; i++)
|
2022-04-14 08:34:55 +00:00
|
|
|
if (sgwc_ue->uli_presence == true &&
|
|
|
|
node->e_cell_id[i] == sgwc_ue->e_cgi.cell_id) return true;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2020-09-09 22:13:58 +00:00
|
|
|
for (i = 0; i < node->num_of_tac; i++)
|
2022-04-14 08:34:55 +00:00
|
|
|
if (sgwc_ue->uli_presence == true &&
|
|
|
|
node->tac[i] == sgwc_ue->e_tai.tac) return true;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ogs_pfcp_node_t *selected_sgwu_node(
|
|
|
|
ogs_pfcp_node_t *current, sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
ogs_pfcp_node_t *next, *node;
|
|
|
|
|
|
|
|
ogs_assert(current);
|
|
|
|
ogs_assert(sess);
|
|
|
|
|
2021-04-24 11:56:14 +00:00
|
|
|
/* continue search from current position */
|
|
|
|
next = ogs_list_next(current);
|
|
|
|
for (node = next; node; node = ogs_list_next(node)) {
|
|
|
|
if (OGS_FSM_CHECK(&node->sm, sgwc_pfcp_state_associated) &&
|
|
|
|
compare_ue_info(node, sess) == true) return node;
|
|
|
|
}
|
|
|
|
/* cyclic search from top to current position */
|
|
|
|
for (node = ogs_list_first(&ogs_pfcp_self()->pfcp_peer_list);
|
|
|
|
node != next; node = ogs_list_next(node)) {
|
|
|
|
if (OGS_FSM_CHECK(&node->sm, sgwc_pfcp_state_associated) &&
|
|
|
|
compare_ue_info(node, sess) == true) return node;
|
|
|
|
}
|
2020-09-09 12:28:19 +00:00
|
|
|
|
2023-11-19 10:34:51 +00:00
|
|
|
if (ogs_global_conf()->parameter.no_pfcp_rr_select == 0) {
|
2020-09-09 12:36:57 +00:00
|
|
|
/* continue search from current position */
|
2020-09-09 12:28:19 +00:00
|
|
|
next = ogs_list_next(current);
|
|
|
|
for (node = next; node; node = ogs_list_next(node)) {
|
2021-04-24 11:56:14 +00:00
|
|
|
if (OGS_FSM_CHECK(&node->sm, sgwc_pfcp_state_associated))
|
|
|
|
return node;
|
2020-09-09 12:28:19 +00:00
|
|
|
}
|
2020-09-09 12:36:57 +00:00
|
|
|
/* cyclic search from top to current position */
|
2021-03-15 01:01:55 +00:00
|
|
|
for (node = ogs_list_first(&ogs_pfcp_self()->pfcp_peer_list);
|
2020-09-09 12:28:19 +00:00
|
|
|
node != next; node = ogs_list_next(node)) {
|
2021-04-24 11:56:14 +00:00
|
|
|
if (OGS_FSM_CHECK(&node->sm, sgwc_pfcp_state_associated))
|
|
|
|
return node;
|
2020-09-09 12:28:19 +00:00
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
2020-09-09 22:13:58 +00:00
|
|
|
ogs_error("No SGWUs are PFCP associated that are suited to RR");
|
2021-03-15 01:01:55 +00:00
|
|
|
return ogs_list_first(&ogs_pfcp_self()->pfcp_peer_list);
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sgwc_sess_select_sgwu(sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
char buf[OGS_ADDRSTRLEN];
|
|
|
|
|
|
|
|
ogs_assert(sess);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When used for the first time, if last node is set,
|
|
|
|
* the search is performed from the first SGW-U in a round-robin manner.
|
|
|
|
*/
|
2021-03-15 01:01:55 +00:00
|
|
|
if (ogs_pfcp_self()->pfcp_node == NULL)
|
|
|
|
ogs_pfcp_self()->pfcp_node =
|
|
|
|
ogs_list_last(&ogs_pfcp_self()->pfcp_peer_list);
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
/* setup GTP session with selected SGW-U */
|
2021-03-15 01:01:55 +00:00
|
|
|
ogs_pfcp_self()->pfcp_node =
|
|
|
|
selected_sgwu_node(ogs_pfcp_self()->pfcp_node, sess);
|
|
|
|
ogs_assert(ogs_pfcp_self()->pfcp_node);
|
|
|
|
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->pfcp_node);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_debug("UE using SGW-U on IP[%s]",
|
2021-03-15 01:01:55 +00:00
|
|
|
OGS_ADDR(&ogs_pfcp_self()->pfcp_node->addr, buf));
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sgwc_sess_remove(sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
sgwc_ue_t *sgwc_ue = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sess);
|
|
|
|
sgwc_ue = sess->sgwc_ue;
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
ogs_list_remove(&sgwc_ue->sess_list, sess);
|
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_hash_set(self.sgwc_sxa_seid_hash, &sess->sgwc_sxa_seid,
|
|
|
|
sizeof(sess->sgwc_sxa_seid), NULL);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
sgwc_bearer_remove_all(sess);
|
|
|
|
|
2020-12-03 06:16:57 +00:00
|
|
|
ogs_assert(sess->pfcp.bar);
|
|
|
|
ogs_pfcp_bar_delete(sess->pfcp.bar);
|
|
|
|
|
2020-09-01 02:41:39 +00:00
|
|
|
ogs_pfcp_pool_final(&sess->pfcp);
|
2020-08-29 14:53:02 +00:00
|
|
|
|
2021-03-08 12:25:09 +00:00
|
|
|
ogs_assert(sess->session.name);
|
|
|
|
ogs_free(sess->session.name);
|
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
ogs_pool_free(&sgwc_sxa_seid_pool, sess->sgwc_sxa_seid_node);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_pool_free(&sgwc_sess_pool, sess);
|
|
|
|
|
2020-09-05 03:36:51 +00:00
|
|
|
stats_remove_sgwc_session();
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sgwc_sess_remove_all(sgwc_ue_t *sgwc_ue)
|
|
|
|
{
|
|
|
|
sgwc_sess_t *sess = NULL, *next_sess = NULL;
|
2022-04-12 22:07:39 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
ogs_list_for_each_safe(&sgwc_ue->sess_list, next_sess, sess)
|
|
|
|
sgwc_sess_remove(sess);
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_sess_t* sgwc_sess_find_by_teid(uint32_t teid)
|
|
|
|
{
|
2023-04-09 01:34:19 +00:00
|
|
|
return sgwc_sess_find_by_seid(teid);
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_sess_t *sgwc_sess_find_by_seid(uint64_t seid)
|
|
|
|
{
|
2023-04-09 01:34:19 +00:00
|
|
|
return ogs_hash_get(self.sgwc_sxa_seid_hash, &seid, sizeof(seid));
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_sess_t* sgwc_sess_find_by_apn(sgwc_ue_t *sgwc_ue, char *apn)
|
|
|
|
{
|
|
|
|
sgwc_sess_t *sess = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
ogs_assert(apn);
|
|
|
|
|
|
|
|
ogs_list_for_each(&sgwc_ue->sess_list, sess) {
|
2021-03-08 12:25:09 +00:00
|
|
|
if (!ogs_strcasecmp(sess->session.name, apn))
|
2020-08-13 00:31:22 +00:00
|
|
|
return sess;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_sess_t *sgwc_sess_find_by_ebi(sgwc_ue_t *sgwc_ue, uint8_t ebi)
|
|
|
|
{
|
|
|
|
sgwc_bearer_t *bearer = NULL;
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
bearer = sgwc_bearer_find_by_ue_ebi(sgwc_ue, ebi);
|
|
|
|
if (bearer)
|
|
|
|
return bearer->sess;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-01-08 20:09:02 +00:00
|
|
|
sgwc_sess_t *sgwc_sess_cycle(sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
return ogs_pool_cycle(&sgwc_sess_pool, sess);
|
|
|
|
}
|
|
|
|
|
2022-04-29 12:28:16 +00:00
|
|
|
int sgwc_sess_pfcp_xact_count(
|
|
|
|
sgwc_ue_t *sgwc_ue, uint8_t pfcp_type, uint64_t modify_flags)
|
|
|
|
{
|
|
|
|
sgwc_sess_t *sess = NULL;
|
|
|
|
int xact_count = 0;
|
|
|
|
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
ogs_list_for_each(&sgwc_ue->sess_list, sess) {
|
|
|
|
ogs_pfcp_node_t *pfcp_node = sess->pfcp_node;
|
|
|
|
ogs_pfcp_xact_t *pfcp_xact = NULL;
|
|
|
|
ogs_assert(pfcp_node);
|
|
|
|
ogs_list_for_each(&pfcp_node->local_list, pfcp_xact) {
|
|
|
|
if (sess != pfcp_xact->data)
|
|
|
|
continue;
|
|
|
|
if (pfcp_type && pfcp_type != pfcp_xact->seq[0].type)
|
|
|
|
continue;
|
|
|
|
if (modify_flags && modify_flags != pfcp_xact->modify_flags)
|
|
|
|
continue;
|
|
|
|
xact_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return xact_count;
|
|
|
|
}
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
sgwc_bearer_t *sgwc_bearer_add(sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
sgwc_bearer_t *bearer = NULL;
|
|
|
|
sgwc_tunnel_t *tunnel = NULL;
|
|
|
|
sgwc_ue_t *sgwc_ue = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sess);
|
|
|
|
sgwc_ue = sess->sgwc_ue;
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
ogs_pool_alloc(&sgwc_bearer_pool, &bearer);
|
|
|
|
ogs_assert(bearer);
|
|
|
|
memset(bearer, 0, sizeof *bearer);
|
|
|
|
|
|
|
|
bearer->sgwc_ue = sgwc_ue;
|
|
|
|
bearer->sess = sess;
|
|
|
|
|
|
|
|
/* Downlink */
|
2022-04-12 22:07:39 +00:00
|
|
|
tunnel = sgwc_tunnel_add(bearer, OGS_GTP2_F_TEID_S5_S8_SGW_GTP_U);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(tunnel);
|
|
|
|
|
|
|
|
/* Uplink */
|
2022-04-12 22:07:39 +00:00
|
|
|
tunnel = sgwc_tunnel_add(bearer, OGS_GTP2_F_TEID_S1_U_SGW_GTP_U);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(tunnel);
|
|
|
|
|
|
|
|
ogs_list_add(&sess->bearer_list, bearer);
|
2022-04-12 22:07:39 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
return bearer;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sgwc_bearer_remove(sgwc_bearer_t *bearer)
|
|
|
|
{
|
|
|
|
ogs_assert(bearer);
|
|
|
|
ogs_assert(bearer->sess);
|
|
|
|
|
|
|
|
ogs_list_remove(&bearer->sess->bearer_list, bearer);
|
|
|
|
|
|
|
|
sgwc_tunnel_remove_all(bearer);
|
|
|
|
|
|
|
|
ogs_pool_free(&sgwc_bearer_pool, bearer);
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sgwc_bearer_remove_all(sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
sgwc_bearer_t *bearer = NULL, *next_bearer = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sess);
|
|
|
|
ogs_list_for_each_safe(&sess->bearer_list, next_bearer, bearer)
|
|
|
|
sgwc_bearer_remove(bearer);
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_bearer_t *sgwc_bearer_find_by_sess_ebi(sgwc_sess_t *sess, uint8_t ebi)
|
|
|
|
{
|
|
|
|
sgwc_bearer_t *bearer = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sess);
|
|
|
|
ogs_list_for_each(&sess->bearer_list, bearer)
|
|
|
|
if (ebi == bearer->ebi) return bearer;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_bearer_t *sgwc_bearer_find_by_ue_ebi(sgwc_ue_t *sgwc_ue, uint8_t ebi)
|
|
|
|
{
|
|
|
|
sgwc_sess_t *sess = NULL;
|
|
|
|
sgwc_bearer_t *bearer = NULL;
|
2022-04-12 22:07:39 +00:00
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
ogs_list_for_each(&sgwc_ue->sess_list, sess) {
|
|
|
|
ogs_list_for_each(&sess->bearer_list, bearer) {
|
|
|
|
if (ebi == bearer->ebi) return bearer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_bearer_t *sgwc_default_bearer_in_sess(sgwc_sess_t *sess)
|
|
|
|
{
|
|
|
|
ogs_assert(sess);
|
|
|
|
return ogs_list_first(&sess->bearer_list);
|
|
|
|
}
|
|
|
|
|
2021-01-08 20:09:02 +00:00
|
|
|
sgwc_bearer_t *sgwc_bearer_cycle(sgwc_bearer_t *bearer)
|
|
|
|
{
|
|
|
|
return ogs_pool_cycle(&sgwc_bearer_pool, bearer);
|
|
|
|
}
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
sgwc_tunnel_t *sgwc_tunnel_add(
|
|
|
|
sgwc_bearer_t *bearer, uint8_t interface_type)
|
|
|
|
{
|
|
|
|
sgwc_sess_t *sess = NULL;
|
|
|
|
sgwc_tunnel_t *tunnel = NULL;
|
|
|
|
|
|
|
|
ogs_pfcp_pdr_t *pdr = NULL;
|
|
|
|
ogs_pfcp_far_t *far = NULL;
|
|
|
|
|
2024-01-08 07:40:25 +00:00
|
|
|
uint8_t src_if = OGS_PFCP_INTERFACE_UNKNOWN;
|
|
|
|
uint8_t dst_if = OGS_PFCP_INTERFACE_UNKNOWN;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
ogs_assert(bearer);
|
|
|
|
sess = bearer->sess;
|
|
|
|
ogs_assert(sess);
|
|
|
|
|
|
|
|
switch (interface_type) {
|
|
|
|
/* Downlink */
|
2022-04-12 22:07:39 +00:00
|
|
|
case OGS_GTP2_F_TEID_S5_S8_SGW_GTP_U:
|
2020-08-13 00:31:22 +00:00
|
|
|
src_if = OGS_PFCP_INTERFACE_CORE;
|
|
|
|
dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Uplink */
|
2022-04-12 22:07:39 +00:00
|
|
|
case OGS_GTP2_F_TEID_S1_U_SGW_GTP_U:
|
2020-08-13 00:31:22 +00:00
|
|
|
src_if = OGS_PFCP_INTERFACE_ACCESS;
|
|
|
|
dst_if = OGS_PFCP_INTERFACE_CORE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Indirect */
|
2022-04-12 22:07:39 +00:00
|
|
|
case OGS_GTP2_F_TEID_SGW_GTP_U_FOR_DL_DATA_FORWARDING:
|
|
|
|
case OGS_GTP2_F_TEID_SGW_GTP_U_FOR_UL_DATA_FORWARDING:
|
2020-08-13 00:31:22 +00:00
|
|
|
src_if = OGS_PFCP_INTERFACE_ACCESS;
|
|
|
|
dst_if = OGS_PFCP_INTERFACE_ACCESS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ogs_fatal("Invalid interface type = %d", interface_type);
|
2023-04-16 02:50:31 +00:00
|
|
|
ogs_assert_if_reached();
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ogs_pool_alloc(&sgwc_tunnel_pool, &tunnel);
|
|
|
|
ogs_assert(tunnel);
|
|
|
|
memset(tunnel, 0, sizeof *tunnel);
|
|
|
|
|
|
|
|
tunnel->interface_type = interface_type;
|
|
|
|
|
2020-08-29 14:53:02 +00:00
|
|
|
pdr = ogs_pfcp_pdr_add(&sess->pfcp);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(pdr);
|
|
|
|
|
2022-06-24 11:30:40 +00:00
|
|
|
ogs_assert(sess->session.name);
|
|
|
|
pdr->apn = ogs_strdup(sess->session.name);
|
|
|
|
ogs_assert(pdr->apn);
|
|
|
|
|
|
|
|
pdr->src_if = src_if;
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2020-08-29 14:53:02 +00:00
|
|
|
far = ogs_pfcp_far_add(&sess->pfcp);
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(far);
|
2020-12-03 06:16:57 +00:00
|
|
|
|
2022-06-24 11:30:40 +00:00
|
|
|
ogs_assert(sess->session.name);
|
|
|
|
far->apn = ogs_strdup(sess->session.name);
|
|
|
|
ogs_assert(far->apn);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
far->dst_if = dst_if;
|
|
|
|
ogs_pfcp_pdr_associate_far(pdr, far);
|
|
|
|
|
2020-12-03 06:16:57 +00:00
|
|
|
far->apply_action =
|
|
|
|
OGS_PFCP_APPLY_ACTION_BUFF| OGS_PFCP_APPLY_ACTION_NOCP;
|
|
|
|
ogs_assert(sess->pfcp.bar);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
ogs_assert(sess->pfcp_node);
|
2020-10-26 02:43:53 +00:00
|
|
|
if (sess->pfcp_node->up_function_features.ftup) {
|
2022-06-24 06:16:54 +00:00
|
|
|
|
|
|
|
/* TS 129 244 V16.5.0 8.2.3
|
|
|
|
*
|
|
|
|
* At least one of the V4 and V6 flags shall be set to "1",
|
|
|
|
* and both may be set to "1" for both scenarios:
|
|
|
|
*
|
|
|
|
* - when the CP function is providing F-TEID, i.e.
|
|
|
|
* both IPv4 address field and IPv6 address field may be present;
|
|
|
|
* or
|
|
|
|
* - when the UP function is requested to allocate the F-TEID,
|
|
|
|
* i.e. when CHOOSE bit is set to "1",
|
|
|
|
* and the IPv4 address and IPv6 address fields are not present.
|
|
|
|
*/
|
|
|
|
|
|
|
|
pdr->f_teid.ipv4 = 1;
|
|
|
|
pdr->f_teid.ipv6 = 1;
|
2020-10-26 02:43:53 +00:00
|
|
|
pdr->f_teid.ch = 1;
|
|
|
|
pdr->f_teid_len = 1;
|
2020-08-13 00:31:22 +00:00
|
|
|
} else {
|
2021-05-30 11:35:30 +00:00
|
|
|
ogs_gtpu_resource_t *resource = NULL;
|
2021-03-15 01:01:55 +00:00
|
|
|
resource = ogs_pfcp_find_gtpu_resource(
|
2020-10-26 02:43:53 +00:00
|
|
|
&sess->pfcp_node->gtpu_resource_list,
|
[GTP-U] Fixed ogs_pfcp_find_gtpu_resource()(#2923)
As mentioned in the sgwu.yaml configuration file, it is possible to configure multiple addresses with different source_interface values for the gtpu interface.
Following the this section, I defined two addresses, one with source_interface set to 0 and another with source_interface set to 1. My expectation was to see different addresses for the two PDRs in the Session Establishment Response message during session establishment. However, both addresses were the same, and it was the address I had set for source_interface = 0.
When I looked into the code, I found the reason for the issue. In the lib/pfcp/context.c file, on line 1185, the function that determines the address is called as follows:
...
} 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) {
...
In the last parameter of this function, a constant value, OGS_PFCP_INTERFACE_ACCESS, is used. This causes every PDR with any source_interface to be considered as "access," and the value 0 is used for its interface.
I replaced the value with pdr->src_if, and the bug was resolved.
2024-01-30 13:37:48 +00:00
|
|
|
sess->session.name, pdr->src_if);
|
2020-10-26 02:43:53 +00:00
|
|
|
if (resource) {
|
2021-03-15 01:01:55 +00:00
|
|
|
ogs_user_plane_ip_resource_info_to_sockaddr(&resource->info,
|
2020-10-26 02:43:53 +00:00
|
|
|
&tunnel->local_addr, &tunnel->local_addr6);
|
|
|
|
if (resource->info.teidri)
|
|
|
|
tunnel->local_teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
|
2023-04-09 01:34:19 +00:00
|
|
|
pdr->teid, resource->info.teidri,
|
2020-10-26 02:43:53 +00:00
|
|
|
resource->info.teid_range);
|
|
|
|
else
|
2023-04-09 01:34:19 +00:00
|
|
|
tunnel->local_teid = pdr->teid;
|
2020-10-26 02:43:53 +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(
|
|
|
|
&tunnel->local_addr, &sess->pfcp_node->addr));
|
2020-10-26 02:43:53 +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(
|
|
|
|
&tunnel->local_addr6, &sess->pfcp_node->addr));
|
2020-10-26 02:43:53 +00:00
|
|
|
else
|
|
|
|
ogs_assert_if_reached();
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2023-04-09 01:34:19 +00:00
|
|
|
tunnel->local_teid = pdr->teid;
|
2020-10-26 02:43:53 +00:00
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
2021-05-30 11:35:30 +00:00
|
|
|
ogs_assert(OGS_OK ==
|
|
|
|
ogs_pfcp_sockaddr_to_f_teid(
|
|
|
|
tunnel->local_addr, tunnel->local_addr6,
|
|
|
|
&pdr->f_teid, &pdr->f_teid_len));
|
2020-10-26 02:43:53 +00:00
|
|
|
pdr->f_teid.teid = tunnel->local_teid;
|
|
|
|
}
|
2020-08-13 00:31:22 +00:00
|
|
|
|
|
|
|
tunnel->pdr = pdr;
|
|
|
|
tunnel->far = far;
|
|
|
|
|
|
|
|
tunnel->bearer = bearer;
|
|
|
|
|
|
|
|
ogs_list_add(&bearer->tunnel_list, tunnel);
|
|
|
|
|
|
|
|
return tunnel;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sgwc_tunnel_remove(sgwc_tunnel_t *tunnel)
|
|
|
|
{
|
|
|
|
ogs_assert(tunnel);
|
|
|
|
ogs_assert(tunnel->bearer);
|
|
|
|
|
|
|
|
ogs_list_remove(&tunnel->bearer->tunnel_list, tunnel);
|
|
|
|
|
2020-08-29 14:53:02 +00:00
|
|
|
ogs_pfcp_pdr_remove(tunnel->pdr);
|
|
|
|
ogs_pfcp_far_remove(tunnel->far);
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
if (tunnel->local_addr)
|
|
|
|
ogs_freeaddrinfo(tunnel->local_addr);
|
|
|
|
if (tunnel->local_addr6)
|
|
|
|
ogs_freeaddrinfo(tunnel->local_addr6);
|
|
|
|
|
|
|
|
ogs_pool_free(&sgwc_tunnel_pool, tunnel);
|
|
|
|
|
|
|
|
return OGS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sgwc_tunnel_remove_all(sgwc_bearer_t *bearer)
|
|
|
|
{
|
|
|
|
sgwc_tunnel_t *tunnel = NULL, *next_tunnel = NULL;
|
|
|
|
|
|
|
|
ogs_assert(bearer);
|
|
|
|
ogs_list_for_each_safe(&bearer->tunnel_list, next_tunnel, tunnel)
|
|
|
|
sgwc_tunnel_remove(tunnel);
|
|
|
|
}
|
|
|
|
|
2020-10-26 02:43:53 +00:00
|
|
|
sgwc_tunnel_t *sgwc_tunnel_find_by_teid(sgwc_ue_t *sgwc_ue, uint32_t teid)
|
2020-08-13 00:31:22 +00:00
|
|
|
{
|
2020-10-26 02:43:53 +00:00
|
|
|
sgwc_sess_t *sess = NULL;
|
|
|
|
sgwc_bearer_t *bearer = NULL;
|
|
|
|
sgwc_tunnel_t *tunnel = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sgwc_ue);
|
|
|
|
|
|
|
|
ogs_list_for_each(&sgwc_ue->sess_list, sess) {
|
|
|
|
ogs_list_for_each(&sess->bearer_list, bearer) {
|
|
|
|
ogs_list_for_each(&bearer->tunnel_list, tunnel) {
|
|
|
|
if (tunnel->local_teid == teid) return tunnel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sgwc_tunnel_t *sgwc_tunnel_find_by_interface_type(
|
|
|
|
sgwc_bearer_t *bearer, uint8_t interface_type)
|
|
|
|
{
|
|
|
|
sgwc_tunnel_t *tunnel = NULL;
|
|
|
|
|
|
|
|
ogs_assert(bearer);
|
|
|
|
|
|
|
|
ogs_list_for_each(&bearer->tunnel_list, tunnel)
|
|
|
|
if (tunnel->interface_type == interface_type) return tunnel;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-26 02:43:53 +00:00
|
|
|
sgwc_tunnel_t *sgwc_tunnel_find_by_pdr_id(
|
|
|
|
sgwc_sess_t *sess, ogs_pfcp_pdr_id_t pdr_id)
|
|
|
|
{
|
|
|
|
sgwc_bearer_t *bearer = NULL;
|
|
|
|
sgwc_tunnel_t *tunnel = NULL;
|
|
|
|
|
|
|
|
ogs_pfcp_pdr_t *pdr = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sess);
|
|
|
|
|
|
|
|
ogs_list_for_each(&sess->bearer_list, bearer) {
|
|
|
|
ogs_list_for_each(&bearer->tunnel_list, tunnel) {
|
|
|
|
pdr = tunnel->pdr;
|
|
|
|
ogs_assert(pdr);
|
|
|
|
|
|
|
|
if (pdr->id == pdr_id) return tunnel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2023-04-16 02:50:31 +00:00
|
|
|
sgwc_tunnel_t *sgwc_tunnel_find_by_far_id(
|
|
|
|
sgwc_sess_t *sess, ogs_pfcp_far_id_t far_id)
|
|
|
|
{
|
|
|
|
sgwc_bearer_t *bearer = NULL;
|
|
|
|
sgwc_tunnel_t *tunnel = NULL;
|
|
|
|
|
|
|
|
ogs_pfcp_far_t *far = NULL;
|
|
|
|
|
|
|
|
ogs_assert(sess);
|
|
|
|
|
|
|
|
ogs_list_for_each(&sess->bearer_list, bearer) {
|
|
|
|
ogs_list_for_each(&bearer->tunnel_list, tunnel) {
|
|
|
|
far = tunnel->far;
|
|
|
|
ogs_assert(far);
|
|
|
|
|
|
|
|
if (far->id == far_id) return tunnel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-08-13 00:31:22 +00:00
|
|
|
sgwc_tunnel_t *sgwc_dl_tunnel_in_bearer(sgwc_bearer_t *bearer)
|
|
|
|
{
|
|
|
|
ogs_assert(bearer);
|
|
|
|
return sgwc_tunnel_find_by_interface_type(bearer,
|
2022-04-12 22:07:39 +00:00
|
|
|
OGS_GTP2_F_TEID_S5_S8_SGW_GTP_U);
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
|
|
|
sgwc_tunnel_t *sgwc_ul_tunnel_in_bearer(sgwc_bearer_t *bearer)
|
|
|
|
{
|
|
|
|
ogs_assert(bearer);
|
|
|
|
return sgwc_tunnel_find_by_interface_type(bearer,
|
2022-04-12 22:07:39 +00:00
|
|
|
OGS_GTP2_F_TEID_S1_U_SGW_GTP_U);
|
2020-08-13 00:31:22 +00:00
|
|
|
}
|
2020-09-05 03:36:51 +00:00
|
|
|
|
|
|
|
static void stats_add_sgwc_session(void)
|
|
|
|
{
|
|
|
|
num_of_sgwc_sess = num_of_sgwc_sess + 1;
|
|
|
|
ogs_info("[Added] Number of SGWC-Sessions is now %d", num_of_sgwc_sess);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stats_remove_sgwc_session(void)
|
|
|
|
{
|
|
|
|
num_of_sgwc_sess = num_of_sgwc_sess - 1;
|
|
|
|
ogs_info("[Removed] Number of SGWC-Sessions is now %d", num_of_sgwc_sess);
|
|
|
|
}
|