[PFCP] Refactor PFCP address handling (#3431)

- Replace direct usage of OGS_ADDR/OGS_PORT macros with
  ogs_sockaddr_to_string_static() for consistent IPv4/IPv6 logging.
- Remove redundant stack buffer allocations for address printing.
- Update PFCP node address handling to use addr_list and related
  merges, avoiding obsolete sa_list references.
- Use ogs_pfcp_extract_node_id() and related APIs to safely extract
  PFCP Node ID, improving error handling and reducing stack usage.
This commit is contained in:
Sukchan Lee
2025-01-11 14:32:39 +09:00
parent 8ff1d1b666
commit d181ab54cc
28 changed files with 1111 additions and 596 deletions

View File

@@ -55,6 +55,10 @@
#undef OGS_LOG_DOMAIN
#define OGS_LOG_DOMAIN __ogs_sock_domain
static bool ogs_sockaddr_compare(const ogs_sockaddr_t *a,
const ogs_sockaddr_t *b,
bool compare_port);
/* If you want to use getnameinfo,
* you need to consider DNS query delay (about 10 seconds) */
#if 0
@@ -264,6 +268,60 @@ int ogs_sortaddrinfo(ogs_sockaddr_t **sa_list, int family)
return OGS_OK;
}
/*--------------------------------------------------------------------------
* Merge a single node if not already in "dest" list
*--------------------------------------------------------------------------
*/
void ogs_merge_single_addrinfo(
ogs_sockaddr_t **dest, const ogs_sockaddr_t *item)
{
ogs_sockaddr_t *p;
ogs_sockaddr_t *new_sa;
ogs_assert(dest);
ogs_assert(item);
p = *dest;
while (p) {
if (ogs_sockaddr_is_equal(p, item)) {
/* Already exists */
return;
}
p = p->next;
}
new_sa = (ogs_sockaddr_t *)ogs_malloc(sizeof(*new_sa));
ogs_assert(new_sa);
memcpy(new_sa, item, sizeof(*new_sa));
if (item->hostname) {
new_sa->hostname = ogs_strdup(item->hostname);
ogs_assert(new_sa->hostname);
}
new_sa->next = NULL;
if (!(*dest)) {
*dest = new_sa;
} else {
p = *dest;
while (p->next)
p = p->next;
p->next = new_sa;
}
}
/*--------------------------------------------------------------------------
* Merge an entire src list into dest
*--------------------------------------------------------------------------
*/
void ogs_merge_addrinfo(ogs_sockaddr_t **dest, const ogs_sockaddr_t *src)
{
const ogs_sockaddr_t *cur;
cur = src;
while (cur) {
ogs_merge_single_addrinfo(dest, cur);
cur = cur->next;
}
}
ogs_sockaddr_t *ogs_link_local_addr(const char *dev, const ogs_sockaddr_t *sa)
{
#if defined(HAVE_GETIFADDRS)
@@ -419,13 +477,16 @@ socklen_t ogs_sockaddr_len(const void *sa)
}
}
bool ogs_sockaddr_is_equal(const void *p, const void *q)
/*
* Helper function to compare two addresses.
* If compare_port is true, compare both port and address.
* Otherwise, compare address only.
*/
static bool ogs_sockaddr_compare(const ogs_sockaddr_t *a,
const ogs_sockaddr_t *b,
bool compare_port)
{
const ogs_sockaddr_t *a, *b;
a = p;
ogs_assert(a);
b = q;
ogs_assert(b);
if (a->ogs_sa_family != b->ogs_sa_family)
@@ -433,23 +494,42 @@ bool ogs_sockaddr_is_equal(const void *p, const void *q)
switch (a->ogs_sa_family) {
case AF_INET:
if (a->sin.sin_port != b->sin.sin_port)
if (compare_port && (a->sin.sin_port != b->sin.sin_port))
return false;
if (memcmp(&a->sin.sin_addr, &b->sin.sin_addr, sizeof(struct in_addr)) != 0)
if (memcmp(&a->sin.sin_addr, &b->sin.sin_addr,
sizeof(struct in_addr)) != 0)
return false;
return true;
case AF_INET6:
if (a->sin6.sin6_port != b->sin6.sin6_port)
if (compare_port && (a->sin6.sin6_port != b->sin6.sin6_port))
return false;
if (memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr, sizeof(struct in6_addr)) != 0)
if (memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr,
sizeof(struct in6_addr)) != 0)
return false;
return true;
default:
ogs_error("Unexpected address faimily %u", a->ogs_sa_family);
ogs_error("Unexpected address family %u", a->ogs_sa_family);
ogs_abort();
return false; /* Defensive return */
}
}
/* Compare addresses including port */
bool ogs_sockaddr_is_equal(const void *p, const void *q)
{
const ogs_sockaddr_t *a = (const ogs_sockaddr_t *)p;
const ogs_sockaddr_t *b = (const ogs_sockaddr_t *)q;
return ogs_sockaddr_compare(a, b, true);
}
/* Compare addresses without considering port */
bool ogs_sockaddr_is_equal_addr(const void *p, const void *q)
{
const ogs_sockaddr_t *a = (const ogs_sockaddr_t *)p;
const ogs_sockaddr_t *b = (const ogs_sockaddr_t *)q;
return ogs_sockaddr_compare(a, b, false);
}
static int parse_network(ogs_ipsubnet_t *ipsub, const char *network)
{
/* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */
@@ -669,7 +749,7 @@ char *ogs_ipstrdup(ogs_sockaddr_t *addr)
char *ogs_sockaddr_to_string_static(ogs_sockaddr_t *sa_list)
{
static char dumpstr[OGS_HUGE_LEN];
static char dumpstr[OGS_HUGE_LEN] = { 0, };
char *p, *last;
ogs_sockaddr_t *addr = NULL;

View File

@@ -67,20 +67,8 @@ struct ogs_sockaddr_s {
* If there is a name in the configuration file,
* it is set in the 'hostname' of ogs_sockaddr_t.
* Then, it immediately call getaddrinfo() to fill addr in ogs_sockaddr_t.
*
* When it was always possible to convert DNS to addr, that was no problem.
* However, in some environments, such as Roaming, there are situations
* where it is difficult to always change the DNS to addr.
*
* So, 'fqdn' was created for the purpose of first use in ogs_sbi_client_t.
* 'fqdn' always do not change with addr.
* This value is used as it is in the actual client connection.
*
* Note that 'hostname' is still in use for server or other client
* except for ogs_sbi_client_t.
*/
char *hostname;
char *fqdn;
ogs_sockaddr_t *next;
};
@@ -103,6 +91,10 @@ int ogs_copyaddrinfo(
int ogs_filteraddrinfo(ogs_sockaddr_t **sa_list, int family);
int ogs_sortaddrinfo(ogs_sockaddr_t **sa_list, int family);
void ogs_merge_single_addrinfo(
ogs_sockaddr_t **dest, const ogs_sockaddr_t *item);
void ogs_merge_addrinfo(ogs_sockaddr_t **dest, const ogs_sockaddr_t *src);
ogs_sockaddr_t *ogs_link_local_addr(const char *dev, const ogs_sockaddr_t *sa);
ogs_sockaddr_t *ogs_link_local_addr_by_dev(const char *dev);
ogs_sockaddr_t *ogs_link_local_addr_by_sa(const ogs_sockaddr_t *sa);
@@ -119,6 +111,7 @@ int ogs_inet_pton(int family, const char *src, void *sa);
socklen_t ogs_sockaddr_len(const void *sa);
bool ogs_sockaddr_is_equal(const void *p, const void *q);
bool ogs_sockaddr_is_equal_addr(const void *p, const void *q);
int ogs_ipsubnet(ogs_ipsubnet_t *ipsub,
const char *ipstr, const char *mask_or_numbits);

View File

@@ -868,20 +868,67 @@ int ogs_pfcp_context_parse_config(const char *local, const char *remote)
return OGS_OK;
}
ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *sa_list)
/*--------------------------------------------------------------------------
* check_any_match():
* If any node in "list" or the single "single" matches base, return 1
*--------------------------------------------------------------------------
*/
static bool check_any_match(ogs_sockaddr_t *base,
ogs_sockaddr_t *list,
const ogs_sockaddr_t *single)
{
ogs_pfcp_node_t *node = NULL;
ogs_sockaddr_t *p = NULL;
ogs_assert(sa_list);
while (list) {
p = base;
while (p) {
if (ogs_sockaddr_is_equal_addr(p, list))
return true;
p = p->next;
}
list = list->next;
}
if (single) {
p = base;
while (p) {
if (ogs_sockaddr_is_equal_addr(p, single))
return true;
p = p->next;
}
}
return false;
}
/*--------------------------------------------------------------------------
* ogs_pfcp_node_new():
* Create node with config_addr, copy config_addr into node->addr_list
*--------------------------------------------------------------------------
*/
ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *config_addr)
{
int rv;
ogs_pfcp_node_t *node = NULL;
ogs_pool_alloc(&ogs_pfcp_node_pool, &node);
if (!node) {
ogs_error("No memory: ogs_pool_alloc() failed");
ogs_error("No memory: ogs_pool_alloc() failed [%s]",
ogs_sockaddr_to_string_static(config_addr));
return NULL;
}
memset(node, 0, sizeof(ogs_pfcp_node_t));
node->sa_list = sa_list;
/* Store config_addr, if any */
node->config_addr = config_addr;
/* If config_addr is given, copy it immediately into addr_list */
if (config_addr) {
rv = ogs_copyaddrinfo(&node->addr_list, config_addr);
if (rv != OGS_OK) {
ogs_error("ogs_copyaddrinfo() failed");
ogs_pool_free(&ogs_pfcp_node_pool, node);
return NULL;
}
}
ogs_list_init(&node->local_list);
ogs_list_init(&node->remote_list);
@@ -899,49 +946,125 @@ void ogs_pfcp_node_free(ogs_pfcp_node_t *node)
ogs_pfcp_xact_delete_all(node);
ogs_freeaddrinfo(node->sa_list);
ogs_freeaddrinfo(node->config_addr);
ogs_freeaddrinfo(node->addr_list);
ogs_pool_free(&ogs_pfcp_node_pool, node);
}
ogs_pfcp_node_t *ogs_pfcp_node_add(
ogs_list_t *list, ogs_sockaddr_t *addr)
/*--------------------------------------------------------------------------
* ogs_pfcp_node_add():
* Create a new node (with config_addr=NULL), set node_id/from,
* then merge => finally add to list
*--------------------------------------------------------------------------
*/
ogs_pfcp_node_t *ogs_pfcp_node_add(ogs_list_t *list,
ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from)
{
ogs_pfcp_node_t *node = NULL;
ogs_sockaddr_t *new = NULL;
ogs_assert(list);
ogs_assert(addr);
ogs_assert(node_id && from);
ogs_assert(OGS_OK == ogs_copyaddrinfo(&new, addr));
node = ogs_pfcp_node_new(new);
/* Create node with no config_addr initially */
node = ogs_pfcp_node_new(NULL);
if (!node) {
ogs_error("No memory : ogs_pfcp_node_new() failed");
ogs_freeaddrinfo(new);
ogs_error("No memory: ogs_pfcp_node_add() failed node_id:%s from:%s",
ogs_pfcp_node_id_to_string_static(node_id),
ogs_sockaddr_to_string_static(from));
return NULL;
}
ogs_assert(node);
memcpy(&node->addr, new, sizeof node->addr);
/* Store node_id and from_addr */
memcpy(&node->node_id, node_id, sizeof(node->node_id));
/* Merge them => fill node->addr_list if conditions are met */
if (ogs_pfcp_node_merge(node, node_id, from) != OGS_OK) {
ogs_error("ogs_pfcp_node_merge() failed node_id [%s] from [%s]",
ogs_pfcp_node_id_to_string_static(node_id),
ogs_sockaddr_to_string_static(from));
ogs_pool_free(&ogs_pfcp_node_pool, node);
return NULL;
}
ogs_list_add(list, node);
return node;
}
ogs_pfcp_node_t *ogs_pfcp_node_find(
ogs_list_t *list, ogs_sockaddr_t *addr)
/*--------------------------------------------------------------------------
* ogs_pfcp_node_find():
* Find a node in the list whose "addr_list" matches node_id or from_addr
*--------------------------------------------------------------------------
*/
ogs_pfcp_node_t *ogs_pfcp_node_find(ogs_list_t *list,
ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from)
{
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_node_t *cur;
ogs_sockaddr_t *nid_list = NULL;
int found = 0;
ogs_assert(list);
ogs_assert(addr);
ogs_assert(node_id || from);
ogs_list_for_each(list, node) {
if (ogs_sockaddr_is_equal(&node->addr, addr) == true)
if (node_id)
nid_list = ogs_pfcp_node_id_to_addrinfo(node_id);
ogs_list_for_each(list, cur) {
if (check_any_match(cur->addr_list, nid_list, from)) {
found = 1;
break;
}
}
if (nid_list)
ogs_freeaddrinfo(nid_list);
if (found)
return cur;
return NULL;
}
/*--------------------------------------------------------------------------
* ogs_pfcp_node_merge():
* Merge logic: addr_list + node_id + from_addr
*--------------------------------------------------------------------------
* - If node->addr_list is empty, copy node->config_addr into addr_list first
* - Convert node_id to addresses, then check from_addr
* - If addr_list is empty => merge everything
* - If addr_list not empty => merge only if there's a matching IP
*/
int ogs_pfcp_node_merge(ogs_pfcp_node_t *node,
ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from)
{
ogs_sockaddr_t *nid_list = NULL;
ogs_sockaddr_t single;
ogs_assert(node);
ogs_assert(node_id || from);
/* Convert node_id to a list of addresses */
if (node_id) {
nid_list = ogs_pfcp_node_id_to_addrinfo(node_id);
if (!nid_list) {
ogs_error("ogs_pfcp_node_id_to_addrinfo() failed [%d]",
node_id->type);
return OGS_ERROR;
}
ogs_merge_addrinfo(&node->addr_list, nid_list);
ogs_freeaddrinfo(nid_list);
}
return node;
/* "from" as single item */
if (from) {
memcpy(&single, from, sizeof(single));
single.next = NULL;
ogs_merge_addrinfo(&node->addr_list, &single);
}
return OGS_OK;
}
void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node)
@@ -963,6 +1086,26 @@ void ogs_pfcp_node_remove_all(ogs_list_t *list)
ogs_pfcp_node_remove(list, node);
}
/* Function to compare two node IDs */
int ogs_pfcp_node_id_compare(
const ogs_pfcp_node_id_t *id1, const ogs_pfcp_node_id_t *id2)
{
if (id1->type != id2->type) {
return false; /* Types do not match */
}
switch (id1->type) {
case OGS_PFCP_NODE_ID_IPV4:
return (id1->addr == id2->addr);
case OGS_PFCP_NODE_ID_IPV6:
return (memcmp(id1->addr6, id2->addr6, OGS_IPV6_LEN) == 0);
case OGS_PFCP_NODE_ID_FQDN:
return (strcmp(id1->fqdn, id2->fqdn) == 0);
default:
return false; /* Unknown types do not match */
}
}
ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list,
char *dnn, ogs_pfcp_interface_t source_interface)
{

View File

@@ -84,10 +84,17 @@ typedef struct ogs_pfcp_context_s {
typedef struct ogs_pfcp_node_s {
ogs_lnode_t lnode; /* A node of list_t */
ogs_sockaddr_t *sa_list; /* Socket Address List Candidate */
ogs_sockaddr_t *config_addr; /* Configured addresses */
ogs_pfcp_node_id_t node_id; /* PFCP node ID */
ogs_sock_t *sock; /* Socket Instance */
ogs_sockaddr_t addr; /* Remote Address */
/* List of addresses:: final merged address list */
ogs_sockaddr_t *addr_list;
/*
* Iterator for round-robin sendto operations.
* Points to the current address in the round-robin sequence.
*/
ogs_sockaddr_t *current_addr;
ogs_list_t local_list;
ogs_list_t remote_list;
@@ -399,15 +406,19 @@ void ogs_pfcp_context_final(void);
ogs_pfcp_context_t *ogs_pfcp_self(void);
int ogs_pfcp_context_parse_config(const char *local, const char *remote);
ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *sa_list);
ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *config_addr);
void ogs_pfcp_node_free(ogs_pfcp_node_t *node);
ogs_pfcp_node_t *ogs_pfcp_node_add(
ogs_list_t *list, ogs_sockaddr_t *addr);
ogs_pfcp_node_t *ogs_pfcp_node_find(
ogs_list_t *list, ogs_sockaddr_t *addr);
ogs_pfcp_node_t *ogs_pfcp_node_add(ogs_list_t *list,
ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from);
ogs_pfcp_node_t *ogs_pfcp_node_find(ogs_list_t *list,
ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from);
int ogs_pfcp_node_merge(ogs_pfcp_node_t *node,
ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from);
void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node);
void ogs_pfcp_node_remove_all(ogs_list_t *list);
int ogs_pfcp_node_id_compare(
const ogs_pfcp_node_id_t *id1, const ogs_pfcp_node_id_t *id2);
ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list,
char *dnn, ogs_pfcp_interface_t source_interface);

View File

@@ -130,14 +130,9 @@ bool ogs_pfcp_cp_handle_association_setup_request(
}
}
if (node->up_function_features.ftup == 0) {
char buf[OGS_ADDRSTRLEN];
ogs_sockaddr_t *addr = node->sa_list;
ogs_assert(addr);
ogs_warn("F-TEID allocation/release not supported with peer [%s]:%d",
OGS_ADDR(addr, buf), OGS_PORT(addr));
}
if (node->up_function_features.ftup == 0)
ogs_warn("F-TEID allocation/release not supported with peer %s",
ogs_sockaddr_to_string_static(node->addr_list));
return true;
}
@@ -182,14 +177,9 @@ bool ogs_pfcp_cp_handle_association_setup_response(
}
}
if (node->up_function_features.ftup == 0) {
char buf[OGS_ADDRSTRLEN];
ogs_sockaddr_t *addr = node->sa_list;
ogs_assert(addr);
ogs_warn("F-TEID allocation/release not supported with peer [%s]:%d",
OGS_ADDR(addr, buf), OGS_PORT(addr));
}
if (node->up_function_features.ftup == 0)
ogs_warn("F-TEID allocation/release not supported with peer %s",
ogs_sockaddr_to_string_static(node->addr_list));
return true;
}

View File

@@ -36,69 +36,6 @@ ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node)
return pfcp;
}
int ogs_pfcp_connect(
ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *node)
{
ogs_sockaddr_t *addr;
char buf[OGS_ADDRSTRLEN];
ogs_assert(ipv4 || ipv6);
ogs_assert(node);
ogs_assert(node->sa_list);
addr = node->sa_list;
while (addr) {
ogs_sock_t *sock = NULL;
if (addr->ogs_sa_family == AF_INET)
sock = ipv4;
else if (addr->ogs_sa_family == AF_INET6)
sock = ipv6;
else
ogs_assert_if_reached();
if (sock) {
ogs_info("ogs_pfcp_connect() [%s]:%d",
OGS_ADDR(addr, buf), OGS_PORT(addr));
node->sock = sock;
memcpy(&node->addr, addr, sizeof node->addr);
break;
}
addr = addr->next;
}
if (addr == NULL) {
ogs_error("ogs_pfcp_connect() [%s]:%d failed",
OGS_ADDR(node->sa_list, buf), OGS_PORT(node->sa_list));
ogs_error("Please check the IP version between SMF and UPF nodes.");
return OGS_ERROR;
}
return OGS_OK;
}
int ogs_pfcp_send(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf)
{
ssize_t sent;
ogs_sock_t *sock = NULL;
ogs_assert(node);
ogs_assert(pkbuf);
sock = node->sock;
ogs_assert(sock);
sent = ogs_send(sock->fd, pkbuf->data, pkbuf->len, 0);
if (sent < 0 || sent != pkbuf->len) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
"ogs_pfcp_send() failed");
return OGS_ERROR;
}
return OGS_OK;
}
int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf)
{
ssize_t sent;
@@ -107,11 +44,34 @@ int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf)
ogs_assert(node);
ogs_assert(pkbuf);
sock = node->sock;
ogs_assert(sock);
addr = &node->addr;
ogs_assert(node->addr_list);
/* Initialize round-robin iterator if needed */
if (node->current_addr == NULL) {
node->current_addr = node->addr_list;
}
addr = node->current_addr;
ogs_assert(addr);
if (addr->ogs_sa_family == AF_INET) {
sock = ogs_pfcp_self()->pfcp_sock;
if (!sock) {
ogs_error("IPv4 socket (pfcp_sock) is not available. "
"Ensure that 'pfcp.server.address: 127.0.0.1' "
"is set in the YAML configuration file.");
return OGS_ERROR;
}
} else if (addr->ogs_sa_family == AF_INET6) {
sock = ogs_pfcp_self()->pfcp_sock6;
if (!sock) {
ogs_error("IPv6 socket (pfcp_sock) is not available. "
"Ensure that 'pfcp.server.address: [::1]' "
"is set in the YAML configuration file.");
return OGS_ERROR;
}
} else
ogs_assert_if_reached();
sent = ogs_sendto(sock->fd, pkbuf->data, pkbuf->len, 0, addr);
if (sent < 0 || sent != pkbuf->len) {
if (ogs_socket_errno != OGS_EAGAIN) {
@@ -125,6 +85,13 @@ int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf)
return OGS_ERROR;
}
/* Move to next address in round-robin sequence */
if (node->current_addr->next)
node->current_addr = node->current_addr->next;
else
/* If end of list reached, wrap around to the start */
node->current_addr = node->addr_list;
return OGS_OK;
}

View File

@@ -56,10 +56,6 @@ extern "C" {
typedef struct ogs_pfcp_xact_s ogs_pfcp_xact_t;
ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node);
int ogs_pfcp_connect(
ogs_sock_t *ipv4, ogs_sock_t *ipv6, ogs_pfcp_node_t *node);
int ogs_pfcp_send(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf);
int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf);
ogs_pkbuf_t *ogs_pfcp_handle_echo_req(ogs_pkbuf_t *pkt);

View File

@@ -19,116 +19,180 @@
#include "ogs-pfcp.h"
/**
* Extracts the `node_id` from a PFCP message.
*
* @param node_id Pointer to store the extracted node_id.
* @param msg Pointer to the parsed PFCP message.
* @return ogs_pfcp_status_e Status of the operation.
/*
* Requirements of Node ID:
* NONE : Node ID must not be present
* OPTIONAL : Node ID may or may not be present
* MANDATORY : Node ID must be present
*/
ogs_pfcp_status_e ogs_pfcp_get_node_id(
ogs_pfcp_node_id_t *node_id, ogs_pfcp_message_t *message)
#define OGS_PFCP_NODE_ID_NONE 0
#define OGS_PFCP_NODE_ID_OPTIONAL 1
#define OGS_PFCP_NODE_ID_MANDATORY 2
/*
* This function extracts the PFCP Node ID from the given PFCP message.
* It determines the Node ID field location and requirement based on
* the message type. Then it validates presence and copies data into
* 'node_id'. If Node ID is not consistent with the requirement, an
* error status is returned.
*/
ogs_pfcp_status_e
ogs_pfcp_extract_node_id(ogs_pfcp_message_t *message,
ogs_pfcp_node_id_t *node_id)
{
/* For C89 compliance, all variables are declared upfront. */
ogs_pfcp_tlv_node_id_t *tlv_node_id = NULL;
int requirement = OGS_PFCP_NODE_ID_NONE;
ogs_pfcp_status_e status = OGS_PFCP_STATUS_SUCCESS;
ogs_assert(node_id);
/* Validate input pointers */
ogs_assert(message);
ogs_assert(node_id);
/* Initialize the output structure */
memset(node_id, 0, sizeof(*node_id));
/* Determine the location of node_id TLV and requirement */
switch (message->h.type) {
/* Message Types with node_id */
case OGS_PFCP_PFD_MANAGEMENT_REQUEST_TYPE:
tlv_node_id = &message->pfcp_pfd_management_request.node_id;
break;
case OGS_PFCP_PFD_MANAGEMENT_REQUEST_TYPE:
tlv_node_id = &message->pfcp_pfd_management_request.node_id;
requirement = OGS_PFCP_NODE_ID_OPTIONAL;
break;
case OGS_PFCP_PFD_MANAGEMENT_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_pfd_management_response.node_id;
break;
case OGS_PFCP_PFD_MANAGEMENT_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_pfd_management_response.node_id;
requirement = OGS_PFCP_NODE_ID_OPTIONAL;
break;
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
tlv_node_id = &message->pfcp_association_setup_request.node_id;
break;
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
tlv_node_id = &message->pfcp_association_setup_request.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_association_setup_response.node_id;
break;
case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_association_setup_response.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_ASSOCIATION_UPDATE_REQUEST_TYPE:
tlv_node_id = &message->pfcp_association_update_request.node_id;
break;
case OGS_PFCP_ASSOCIATION_UPDATE_REQUEST_TYPE:
tlv_node_id = &message->pfcp_association_update_request.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_ASSOCIATION_UPDATE_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_association_update_response.node_id;
break;
case OGS_PFCP_ASSOCIATION_UPDATE_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_association_update_response.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_ASSOCIATION_RELEASE_REQUEST_TYPE:
tlv_node_id = &message->pfcp_association_release_request.node_id;
break;
case OGS_PFCP_ASSOCIATION_RELEASE_REQUEST_TYPE:
tlv_node_id = &message->pfcp_association_release_request.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_ASSOCIATION_RELEASE_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_association_release_response.node_id;
break;
case OGS_PFCP_ASSOCIATION_RELEASE_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_association_release_response.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_NODE_REPORT_REQUEST_TYPE:
tlv_node_id = &message->pfcp_node_report_request.node_id;
break;
case OGS_PFCP_NODE_REPORT_REQUEST_TYPE:
tlv_node_id = &message->pfcp_node_report_request.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_NODE_REPORT_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_node_report_response.node_id;
break;
case OGS_PFCP_NODE_REPORT_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_node_report_response.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_SESSION_SET_DELETION_REQUEST_TYPE:
tlv_node_id = &message->pfcp_session_set_deletion_request.node_id;
break;
case OGS_PFCP_SESSION_SET_DELETION_REQUEST_TYPE:
tlv_node_id = &message->pfcp_session_set_deletion_request.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_SESSION_SET_DELETION_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_session_set_deletion_response.node_id;
break;
case OGS_PFCP_SESSION_SET_DELETION_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_session_set_deletion_response.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_SESSION_SET_MODIFICATION_REQUEST_TYPE:
tlv_node_id =
&message->pfcp_session_set_modification_request.node_id;
break;
case OGS_PFCP_SESSION_SET_MODIFICATION_REQUEST_TYPE:
tlv_node_id = &message->pfcp_session_set_modification_request.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_SESSION_SET_MODIFICATION_RESPONSE_TYPE:
tlv_node_id =
&message->pfcp_session_set_modification_response.node_id;
break;
case OGS_PFCP_SESSION_SET_MODIFICATION_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_session_set_modification_response.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE:
tlv_node_id = &message->pfcp_session_establishment_request.node_id;
break;
case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE:
tlv_node_id = &message->pfcp_session_establishment_request.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_session_establishment_response.node_id;
break;
case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
tlv_node_id = &message->pfcp_session_establishment_response.node_id;
requirement = OGS_PFCP_NODE_ID_MANDATORY;
break;
case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE:
tlv_node_id = &message->pfcp_session_modification_request.node_id;
break;
case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE:
tlv_node_id = &message->pfcp_session_modification_request.node_id;
requirement = OGS_PFCP_NODE_ID_OPTIONAL;
break;
/* Add other message types with node_id here as needed */
/* Add other message types with node_id here as needed */
/* Message Types without node_id */
case OGS_PFCP_HEARTBEAT_REQUEST_TYPE:
case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE:
case OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE:
case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE:
case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE:
case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE:
case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE:
case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE:
break;
case OGS_PFCP_HEARTBEAT_REQUEST_TYPE:
case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE:
case OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE:
case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE:
case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE:
case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE:
case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE:
case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE:
/* Node ID must not be present for these messages */
requirement = OGS_PFCP_NODE_ID_NONE;
break;
default:
ogs_error("Unknown message type %d", message->h.type);
return OGS_PFCP_ERROR_UNKNOWN_MESSAGE;
default:
/* Unknown message type */
ogs_error("Unknown message type %d", message->h.type);
return OGS_PFCP_ERROR_UNKNOWN_MESSAGE;
}
if (!tlv_node_id)
return OGS_PFCP_ERROR_NODE_ID_NOT_FOUND;
/* Check requirement vs. tlv_node_id existence */
switch (requirement) {
case OGS_PFCP_NODE_ID_MANDATORY:
/* Must have tlv_node_id. presence must be 1. */
ogs_assert(tlv_node_id);
if (!tlv_node_id->presence) {
status = OGS_PFCP_ERROR_NODE_ID_NOT_PRESENT;
goto done;
}
break;
if (!tlv_node_id->presence)
return OGS_PFCP_ERROR_NODE_ID_NOT_PRESENT;
case OGS_PFCP_NODE_ID_OPTIONAL:
/*
* Must have tlv_node_id. presence=1 => real Node ID
* presence=0 => no Node ID
*/
ogs_assert(tlv_node_id);
if (!tlv_node_id->presence) {
status = OGS_PFCP_STATUS_NODE_ID_OPTIONAL_ABSENT;
goto done;
}
break;
case OGS_PFCP_NODE_ID_NONE:
/* Must be NULL => no Node ID field */
ogs_assert(tlv_node_id == NULL);
status = OGS_PFCP_STATUS_NODE_ID_NONE;
goto done;
default:
status = OGS_PFCP_ERROR_UNKNOWN_MESSAGE;
goto done;
}
memcpy(node_id, tlv_node_id->data, tlv_node_id->len);
@@ -140,5 +204,113 @@ ogs_pfcp_status_e ogs_pfcp_get_node_id(
return OGS_PFCP_ERROR_SEMANTIC_INCORRECT_MESSAGE;
}
return OGS_PFCP_STATUS_SUCCESS;
/* Node ID is valid */
status = OGS_PFCP_STATUS_SUCCESS;
done:
return status;
}
ogs_sockaddr_t *ogs_pfcp_node_id_to_addrinfo(const ogs_pfcp_node_id_t *node_id)
{
ogs_sockaddr_t *p;
int ret;
uint16_t port = ogs_pfcp_self()->pfcp_port;
char fqdn[OGS_MAX_FQDN_LEN+1];
ogs_assert(node_id);
switch (node_id->type) {
/*------------------------------------------------
* 1) IPv4
*-----------------------------------------------*/
case OGS_PFCP_NODE_ID_IPV4:
p = (ogs_sockaddr_t *)ogs_calloc(1, sizeof(*p));
if (!p) {
ogs_error("ogs_calloc() failed");
return NULL;
}
p->sa.sa_family = AF_INET;
p->sin.sin_port = htobe16(port);
p->sin.sin_addr.s_addr = node_id->addr;
p->next = NULL;
return p;
/*------------------------------------------------
* 2) IPv6
*-----------------------------------------------*/
case OGS_PFCP_NODE_ID_IPV6:
p = (ogs_sockaddr_t *)ogs_calloc(1, sizeof(*p));
if (!p) {
ogs_error("ogs_calloc() failed");
return NULL;
}
p->sa.sa_family = AF_INET6;
p->sin6.sin6_port = htobe16(port);
/* Copy 16 bytes of IPv6 address */
memcpy(&p->sin6.sin6_addr, node_id->addr6, 16);
p->next = NULL;
return OGS_OK;
/*------------------------------------------------
* 3) FQDN
*-----------------------------------------------*/
case OGS_PFCP_NODE_ID_FQDN:
/* If the FQDN is not empty, we attempt DNS resolution.
* ogs_addaddrinfo() is a placeholder for your actual
* DNS -> ogs_sockaddr_t function (often wraps getaddrinfo).
*/
/* Port=0 or set as needed, family=AF_UNSPEC, flags=0. */
if (ogs_fqdn_parse(fqdn, node_id->fqdn, strlen(node_id->fqdn)) <= 0) {
ogs_error("ogs_fqdn_parse() error [%s]", node_id->fqdn);
return NULL;
}
ret = ogs_getaddrinfo(&p, AF_UNSPEC, fqdn, port, 0);
if (ret != 0) {
/* DNS resolution failed => *out remains NULL */
ogs_error("ogs_addaddrinfo() failed");
return NULL;
}
/* If FQDN is empty, just return with no addresses. */
return p;
/*------------------------------------------------
* 4) Unsupported type or default
*-----------------------------------------------*/
default:
/* Optionally handle an error or just return success
* with no addresses.
*/
ogs_error("Unknown type [%d]", node_id->type);
return NULL;
}
}
/* Utility function to convert node_id to string for logging */
const char *ogs_pfcp_node_id_to_string_static(
const ogs_pfcp_node_id_t *node_id)
{
static char buffer[OGS_MAX_FQDN_LEN+1] = { 0, };
if (node_id) {
switch (node_id->type) {
case OGS_PFCP_NODE_ID_IPV4:
inet_ntop(AF_INET, &node_id->addr, buffer, sizeof(buffer));
break;
case OGS_PFCP_NODE_ID_IPV6:
inet_ntop(AF_INET6, node_id->addr6, buffer, sizeof(buffer));
break;
case OGS_PFCP_NODE_ID_FQDN:
if (ogs_fqdn_parse(buffer,
node_id->fqdn,
strlen(node_id->fqdn)) <= 0)
snprintf(buffer, sizeof(buffer), "%s", node_id->fqdn);
break;
default:
snprintf(buffer, sizeof(buffer), "Unknown");
break;
}
}
return buffer;
}

View File

@@ -29,26 +29,30 @@ extern "C" {
#endif
typedef enum {
/* Operation was successful */
/* Success with actual Node ID */
OGS_PFCP_STATUS_SUCCESS = 0,
/* The message type is unknown */
OGS_PFCP_ERROR_UNKNOWN_MESSAGE,
/* Success with no Node ID (NONE type) */
OGS_PFCP_STATUS_NODE_ID_NONE,
/* The message is semantically incorrect */
/* Success with OPTIONAL node_id_tlv, but presence=0 */
OGS_PFCP_STATUS_NODE_ID_OPTIONAL_ABSENT,
/* Error codes */
OGS_PFCP_ERROR_SEMANTIC_INCORRECT_MESSAGE,
/* The node ID is not present in the message */
OGS_PFCP_ERROR_NODE_ID_NOT_PRESENT,
/* The node ID was not found in the expected location */
OGS_PFCP_ERROR_NODE_ID_NOT_FOUND,
OGS_PFCP_ERROR_UNKNOWN_MESSAGE
/* Add additional error codes as needed */
} ogs_pfcp_status_e;
ogs_pfcp_status_e ogs_pfcp_get_node_id(
ogs_pfcp_node_id_t *node_id, ogs_pfcp_message_t *message);
ogs_pfcp_status_e
ogs_pfcp_extract_node_id(ogs_pfcp_message_t *message,
ogs_pfcp_node_id_t *node_id);
ogs_sockaddr_t *ogs_pfcp_node_id_to_addrinfo(const ogs_pfcp_node_id_t *node_id);
const char *ogs_pfcp_node_id_to_string_static(
const ogs_pfcp_node_id_t *node_id);
#ifdef __cplusplus
}

View File

@@ -70,7 +70,6 @@ void ogs_pfcp_xact_final(void)
ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *node,
void (*cb)(ogs_pfcp_xact_t *xact, void *data), void *data)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_xact_t *xact = NULL;
ogs_assert(node);
@@ -109,11 +108,10 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *node,
ogs_list_init(&xact->pdr_to_create_list);
ogs_debug("[%d] %s Create peer [%s]:%d",
ogs_debug("[%d] %s Create peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_sockaddr_to_string_static(node->addr_list));
return xact;
}
@@ -121,7 +119,6 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *node,
static ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create(
ogs_pfcp_node_t *node, uint32_t sqn)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_xact_t *xact = NULL;
ogs_assert(node);
@@ -156,11 +153,10 @@ static ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create(
ogs_list_add(xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
&xact->node->local_list : &xact->node->remote_list, xact);
ogs_debug("[%d] %s Create peer [%s]:%d",
ogs_debug("[%d] %s Create peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_sockaddr_to_string_static(node->addr_list));
return xact;
}
@@ -183,7 +179,6 @@ ogs_pfcp_xact_t *ogs_pfcp_xact_find_by_id(ogs_pool_id_t id)
int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact,
ogs_pfcp_header_t *hdesc, ogs_pkbuf_t *pkbuf)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_xact_stage_t stage;
ogs_pfcp_header_t *h = NULL;
int pfcp_hlen = 0;
@@ -193,12 +188,11 @@ int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact,
ogs_assert(hdesc);
ogs_assert(pkbuf);
ogs_debug("[%d] %s UPD TX-%d peer [%s]:%d",
ogs_debug("[%d] %s UPD TX-%d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
hdesc->type,
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
stage = ogs_pfcp_xact_get_stage(hdesc->type, xact->xid);
if (xact->org == OGS_PFCP_LOCAL_ORIGINATOR) {
@@ -290,15 +284,13 @@ int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact,
static int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_xact_stage_t stage;
ogs_debug("[%d] %s UPD RX-%d peer [%s]:%d",
ogs_debug("[%d] %s UPD RX-%d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
type,
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
stage = ogs_pfcp_xact_get_stage(type, xact->xid);
if (xact->org == OGS_PFCP_LOCAL_ORIGINATOR) {
@@ -325,25 +317,23 @@ static int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type)
pfcp.t1_holding_duration);
ogs_warn("[%d] %s Request Duplicated. Retransmit!"
" for step %d type %d peer [%s]:%d",
" for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE",
xact->step, type,
OGS_ADDR(&xact->node->addr,
buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(
xact->node->addr_list));
ogs_expect(OGS_OK == ogs_pfcp_sendto(xact->node, pkbuf));
} else {
ogs_warn("[%d] %s Request Duplicated. Discard!"
" for step %d type %d peer [%s]:%d",
" for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE",
xact->step, type,
OGS_ADDR(&xact->node->addr,
buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(
xact->node->addr_list));
}
return OGS_RETRY;
@@ -391,25 +381,23 @@ static int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type)
pfcp.t1_holding_duration);
ogs_warn("[%d] %s Request Duplicated. Retransmit!"
" for step %d type %d peer [%s]:%d",
" for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE",
xact->step, type,
OGS_ADDR(&xact->node->addr,
buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(
xact->node->addr_list));
ogs_expect(OGS_OK == ogs_pfcp_sendto(xact->node, pkbuf));
} else {
ogs_warn("[%d] %s Request Duplicated. Discard!"
" for step %d type %d peer [%s]:%d",
" for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
"LOCAL " : "REMOTE",
xact->step, type,
OGS_ADDR(&xact->node->addr,
buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(
xact->node->addr_list));
}
return OGS_RETRY;
@@ -462,8 +450,6 @@ static int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type)
int ogs_pfcp_xact_commit(ogs_pfcp_xact_t *xact)
{
char buf[OGS_ADDRSTRLEN];
uint8_t type;
ogs_pkbuf_t *pkbuf = NULL;
ogs_pfcp_xact_stage_t stage;
@@ -471,11 +457,10 @@ int ogs_pfcp_xact_commit(ogs_pfcp_xact_t *xact)
ogs_assert(xact);
ogs_assert(xact->node);
ogs_debug("[%d] %s Commit peer [%s]:%d",
ogs_debug("[%d] %s Commit peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
type = xact->seq[xact->step-1].type;
stage = ogs_pfcp_xact_get_stage(type, xact->xid);
@@ -581,7 +566,6 @@ void ogs_pfcp_xact_delayed_commit(ogs_pfcp_xact_t *xact, ogs_time_t duration)
static void response_timeout(void *data)
{
char buf[OGS_ADDRSTRLEN];
ogs_pool_id_t xact_id = OGS_INVALID_POOL_ID;
ogs_pfcp_xact_t *xact = NULL;
@@ -597,12 +581,11 @@ static void response_timeout(void *data)
ogs_assert(xact->node);
ogs_debug("[%d] %s Response Timeout "
"for step %d type %d peer [%s]:%d",
"for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->step, xact->seq[xact->step-1].type,
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
if (--xact->response_rcount > 0) {
ogs_pkbuf_t *pkbuf = NULL;
@@ -617,12 +600,11 @@ static void response_timeout(void *data)
ogs_expect(OGS_OK == ogs_pfcp_sendto(xact->node, pkbuf));
} else {
ogs_warn("[%d] %s No Reponse. Give up! "
"for step %d type %d peer [%s]:%d",
"for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->step, xact->seq[xact->step-1].type,
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
if (xact->cb)
xact->cb(xact, xact->data);
@@ -633,7 +615,6 @@ static void response_timeout(void *data)
static void holding_timeout(void *data)
{
char buf[OGS_ADDRSTRLEN];
ogs_pool_id_t xact_id = OGS_INVALID_POOL_ID;
ogs_pfcp_xact_t *xact = NULL;
@@ -649,12 +630,11 @@ static void holding_timeout(void *data)
ogs_assert(xact->node);
ogs_debug("[%d] %s Holding Timeout "
"for step %d type %d peer [%s]:%d",
"for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->step, xact->seq[xact->step-1].type,
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
if (--xact->holding_rcount > 0) {
if (xact->tm_holding)
@@ -662,19 +642,17 @@ static void holding_timeout(void *data)
ogs_local_conf()->time.message.pfcp.t1_holding_duration);
} else {
ogs_debug("[%d] %s Delete Transaction "
"for step %d type %d peer [%s]:%d",
"for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->step, xact->seq[xact->step-1].type,
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
ogs_pfcp_xact_delete(xact);
}
}
static void delayed_commit_timeout(void *data)
{
char buf[OGS_ADDRSTRLEN];
ogs_pool_id_t xact_id = OGS_INVALID_POOL_ID;
ogs_pfcp_xact_t *xact = NULL;
@@ -690,12 +668,11 @@ static void delayed_commit_timeout(void *data)
ogs_assert(xact->node);
ogs_debug("[%d] %s Delayed Send Timeout "
"for step %d type %d peer [%s]:%d",
"for step %d type %d peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
xact->step, xact->seq[xact->step-1].type,
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
ogs_pfcp_xact_commit(xact);
}
@@ -704,7 +681,6 @@ int ogs_pfcp_xact_receive(
ogs_pfcp_node_t *node, ogs_pfcp_header_t *h, ogs_pfcp_xact_t **xact)
{
int rv;
char buf[OGS_ADDRSTRLEN];
uint8_t type;
uint32_t sqn, xid;
@@ -731,35 +707,33 @@ int ogs_pfcp_xact_receive(
list = &node->local_list;
break;
default:
ogs_error("[%d] Unexpected type %u from PFCP peer [%s]:%d",
xid, type, OGS_ADDR(&node->addr, buf), OGS_PORT(&node->addr));
ogs_error("[%d] Unexpected type %u from PFCP peer %s",
xid, type, ogs_sockaddr_to_string_static(node->addr_list));
return OGS_ERROR;
}
ogs_assert(list);
ogs_list_for_each(list, new) {
if (new->xid == xid) {
ogs_debug("[%d] %s Find peer [%s]:%d",
ogs_debug("[%d] %s Find peer %s",
new->xid,
new->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_sockaddr_to_string_static(node->addr_list));
break;
}
}
if (!new) {
ogs_debug("[%d] Cannot find new type %u from PFCP peer [%s]:%d",
xid, type, OGS_ADDR(&node->addr, buf), OGS_PORT(&node->addr));
ogs_debug("[%d] Cannot find new type %u from PFCP peer %s",
xid, type, ogs_sockaddr_to_string_static(node->addr_list));
new = ogs_pfcp_xact_remote_create(node, sqn);
}
ogs_assert(new);
ogs_debug("[%d] %s Receive peer [%s]:%d",
ogs_debug("[%d] %s Receive peer %s",
new->xid,
new->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_sockaddr_to_string_static(node->addr_list));
rv = ogs_pfcp_xact_update_rx(new, type);
if (rv == OGS_ERROR) {
@@ -811,16 +785,13 @@ static ogs_pfcp_xact_stage_t ogs_pfcp_xact_get_stage(uint8_t type, uint32_t xid)
int ogs_pfcp_xact_delete(ogs_pfcp_xact_t *xact)
{
char buf[OGS_ADDRSTRLEN];
ogs_assert(xact);
ogs_assert(xact->node);
ogs_debug("[%d] %s Delete peer [%s]:%d",
ogs_debug("[%d] %s Delete peer %s",
xact->xid,
xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
OGS_ADDR(&xact->node->addr, buf),
OGS_PORT(&xact->node->addr));
ogs_sockaddr_to_string_static(xact->node->addr_list));
if (xact->seq[0].pkbuf)
ogs_pkbuf_free(xact->seq[0].pkbuf);

View File

@@ -93,7 +93,6 @@ ogs_sock_t *ogs_sctp_server(
int type, ogs_sockaddr_t *sa_list, ogs_sockopt_t *socket_option)
{
int rv;
char *sa_list_str = NULL;
char buf[OGS_ADDRSTRLEN];
ogs_sock_t *new = NULL;
@@ -143,10 +142,8 @@ ogs_sock_t *ogs_sctp_server(
}
if (addr == NULL) {
sa_list_str = ogs_sockaddr_strdup(sa_list);
ogs_error("sctp_server %s failed", sa_list_str);
ogs_free(sa_list_str);
ogs_error("sctp_server %s failed",
ogs_sockaddr_to_string_static(sa_list));
return NULL;
}
@@ -164,7 +161,6 @@ ogs_sock_t *ogs_sctp_client(
ogs_sockopt_t *socket_option)
{
int rv;
char *sa_list_str = NULL;
char buf[OGS_ADDRSTRLEN];
ogs_sock_t *new = NULL;
@@ -214,10 +210,8 @@ ogs_sock_t *ogs_sctp_client(
}
if (addr == NULL) {
sa_list_str = ogs_sockaddr_strdup(sa_list);
ogs_error("sctp_client %s failed", sa_list_str);
ogs_free(sa_list_str);
ogs_error("sctp_client %s failed",
ogs_sockaddr_to_string_static(sa_list));
return NULL;
}
@@ -227,7 +221,6 @@ ogs_sock_t *ogs_sctp_client(
int ogs_sctp_bind(ogs_sock_t *sock, ogs_sockaddr_t *sa_list)
{
struct socket *socket = (struct socket *)sock;
char *sa_list_str = NULL;
socklen_t addrlen;
ogs_assert(socket);
@@ -237,16 +230,13 @@ int ogs_sctp_bind(ogs_sock_t *sock, ogs_sockaddr_t *sa_list)
ogs_assert(addrlen);
if (usrsctp_bind(socket, &sa_list->sa, addrlen) != 0) {
sa_list_str = ogs_sockaddr_strdup(sa_list);
ogs_error("sctp_bind() %s failed", sa_list_str);
ogs_free(sa_list_str);
ogs_error("sctp_bind() %s failed",
ogs_sockaddr_to_string_static(sa_list));
return OGS_ERROR;
}
sa_list_str = ogs_sockaddr_strdup(sa_list);
ogs_debug("sctp_bind() %s", sa_list_str);
ogs_free(sa_list_str);
ogs_debug("sctp_bind() %s", ogs_sockaddr_to_string_static(sa_list));
return OGS_OK;
}
@@ -254,7 +244,6 @@ int ogs_sctp_bind(ogs_sock_t *sock, ogs_sockaddr_t *sa_list)
int ogs_sctp_connect(ogs_sock_t *sock, ogs_sockaddr_t *sa_list)
{
struct socket *socket = (struct socket *)sock;
char *sa_list_str = NULL;
socklen_t addrlen;
ogs_assert(socket);
@@ -264,16 +253,11 @@ int ogs_sctp_connect(ogs_sock_t *sock, ogs_sockaddr_t *sa_list)
ogs_assert(addrlen);
if (usrsctp_connect(socket, &sa_list->sa, addrlen) != 0) {
sa_list_str = ogs_sockaddr_strdup(sa_list);
ogs_error("sctp_connect() %s", sa_list_str);
ogs_free(sa_list_str);
ogs_error("sctp_connect() %s", ogs_sockaddr_to_string_static(sa_list));
return OGS_ERROR;
}
sa_list_str = ogs_sockaddr_strdup(sa_list);
ogs_debug("sctp_connect() %s", sa_list_str);
ogs_free(sa_list_str);
ogs_debug("sctp_connect() %s", ogs_sockaddr_to_string_static(sa_list));
return OGS_OK;
}

View File

@@ -408,8 +408,6 @@ static ogs_pfcp_node_t *selected_sgwu_node(
void sgwc_sess_select_sgwu(sgwc_sess_t *sess)
{
char buf[OGS_ADDRSTRLEN];
ogs_assert(sess);
/*
@@ -425,8 +423,9 @@ void sgwc_sess_select_sgwu(sgwc_sess_t *sess)
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);
ogs_debug("UE using SGW-U on IP[%s]",
OGS_ADDR(&ogs_pfcp_self()->pfcp_node->addr, buf));
ogs_debug("UE using SGW-U on IP %s",
ogs_sockaddr_to_string_static(
ogs_pfcp_self()->pfcp_node->addr_list));
}
int sgwc_sess_remove(sgwc_sess_t *sess)
@@ -761,14 +760,15 @@ sgwc_tunnel_t *sgwc_tunnel_add(
else
tunnel->local_teid = pdr->teid;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_assert(sess->pfcp_node->addr_list);
if (sess->pfcp_node->addr_list->ogs_sa_family == AF_INET)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(
&tunnel->local_addr, &sess->pfcp_node->addr));
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
&tunnel->local_addr, sess->pfcp_node->addr_list));
else if (sess->pfcp_node->addr_list->ogs_sa_family == AF_INET6)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(
&tunnel->local_addr6, &sess->pfcp_node->addr));
&tunnel->local_addr6, sess->pfcp_node->addr_list));
else
ogs_assert_if_reached();

View File

@@ -61,8 +61,12 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_pfcp_header_t *h = NULL;
ogs_pfcp_status_e pfcp_status;;
ogs_pfcp_node_id_t node_id;
ogs_assert(fd != INVALID_SOCKET);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
@@ -102,28 +106,105 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = sgwc_event_new(SGWC_EVT_SXA_MESSAGE);
ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
ogs_pkbuf_free(e->pkbuf);
sgwc_event_free(e);
return;
}
node->sock = data;
pfcp_node_fsm_init(node, false);
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((message = ogs_pfcp_parse_msg(pkbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(pkbuf);
sgwc_event_free(e);
return;
}
pfcp_status = ogs_pfcp_extract_node_id(message, &node_id);
switch (pfcp_status) {
case OGS_PFCP_STATUS_SUCCESS:
case OGS_PFCP_STATUS_NODE_ID_NONE:
case OGS_PFCP_STATUS_NODE_ID_OPTIONAL_ABSENT:
ogs_debug("ogs_pfcp_extract_node_id() "
"type [%d] pfcp_status [%d] node_id [%s] from %s",
message->h.type, pfcp_status,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
break;
case OGS_PFCP_ERROR_SEMANTIC_INCORRECT_MESSAGE:
case OGS_PFCP_ERROR_NODE_ID_NOT_PRESENT:
case OGS_PFCP_ERROR_NODE_ID_NOT_FOUND:
case OGS_PFCP_ERROR_UNKNOWN_MESSAGE:
ogs_error("ogs_pfcp_extract_node_id() failed "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
default:
ogs_error("Unexpected pfcp_status "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL, &from);
if (!node) {
if (message->h.type == OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE ||
message->h.type == OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE) {
ogs_assert(pfcp_status == OGS_PFCP_STATUS_SUCCESS);
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list,
&node_id, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
goto cleanup;
}
ogs_debug("Added PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
pfcp_node_fsm_init(node, false);
} else {
ogs_error("Cannot find PFCP-Node: type [%d] node_id %s from %s",
message->h.type,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
} else {
ogs_debug("Found PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_expect(OGS_OK == ogs_pfcp_node_merge(
node,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL,
&from));
ogs_debug("Merged PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
}
e->pfcp_node = node;
e->pkbuf = pkbuf;
e->pfcp_message = message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_pkbuf_free(e->pkbuf);
sgwc_event_free(e);
goto cleanup;
}
return;
cleanup:
ogs_pkbuf_free(pkbuf);
ogs_pfcp_message_free(message);
sgwc_event_free(e);
}
int sgwc_pfcp_open(void)

View File

@@ -25,7 +25,6 @@ static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
void sgwc_pfcp_state_initial(ogs_fsm_t *s, sgwc_event_t *e)
{
int rv;
ogs_pfcp_node_t *node = NULL;
ogs_assert(s);
@@ -36,10 +35,6 @@ void sgwc_pfcp_state_initial(ogs_fsm_t *s, sgwc_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
rv = ogs_pfcp_connect(
ogs_pfcp_self()->pfcp_sock, ogs_pfcp_self()->pfcp_sock6, node);
ogs_assert(rv == OGS_OK);
node->t_no_heartbeat = ogs_timer_add(ogs_app()->timer_mgr,
sgwc_timer_pfcp_no_heartbeat, node);
ogs_assert(node->t_no_heartbeat);
@@ -63,14 +58,10 @@ void sgwc_pfcp_state_final(ogs_fsm_t *s, sgwc_event_t *e)
void sgwc_pfcp_state_will_associate(ogs_fsm_t *s, sgwc_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(s);
ogs_assert(e);
@@ -78,8 +69,6 @@ void sgwc_pfcp_state_will_associate(ogs_fsm_t *s, sgwc_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
addr = node->sa_list;
ogs_assert(addr);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
@@ -103,8 +92,8 @@ void sgwc_pfcp_state_will_associate(ogs_fsm_t *s, sgwc_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
ogs_warn("Retry association with peer [%s]:%d failed",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("Retry association with peer failed %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_assert(node->t_association);
ogs_timer_start(node->t_association,
@@ -159,13 +148,10 @@ void sgwc_pfcp_state_will_associate(ogs_fsm_t *s, sgwc_event_t *e)
void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
sgwc_sess_t *sess = NULL;
ogs_assert(s);
@@ -175,14 +161,11 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
addr = node->sa_list;
ogs_assert(addr);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
ogs_info("PFCP associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_start(node->t_no_heartbeat,
ogs_local_conf()->time.message.pfcp.no_heartbeat_duration);
ogs_assert(OGS_OK ==
@@ -195,9 +178,8 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
}
break;
case OGS_FSM_EXIT_SIG:
ogs_info("PFCP de-associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP de-associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_stop(node->t_no_heartbeat);
break;
case SGWC_EVT_SXA_MESSAGE:
@@ -274,16 +256,14 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
}
break;
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
ogs_warn("PFCP[REQ] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[REQ] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_cp_handle_association_setup_request(node, xact,
&message->pfcp_association_setup_request);
break;
case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
ogs_warn("PFCP[RSP] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[RSP] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_cp_handle_association_setup_response(node, xact,
&message->pfcp_association_setup_response);
break;
@@ -359,8 +339,8 @@ void sgwc_pfcp_state_associated(ogs_fsm_t *s, sgwc_event_t *e)
}
break;
case SGWC_EVT_SXA_NO_HEARTBEAT:
ogs_warn("No Heartbeat from SGW-U [%s]:%d",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("No Heartbeat from SGW-U %s",
ogs_sockaddr_to_string_static(node->addr_list));
OGS_FSM_TRAN(s, sgwc_pfcp_state_will_associate);
break;
default:

View File

@@ -89,23 +89,12 @@ void sgwc_state_operational(ogs_fsm_t *s, sgwc_event_t *e)
ogs_assert(e);
recvbuf = e->pkbuf;
ogs_assert(recvbuf);
pfcp_message = e->pfcp_message;
ogs_assert(pfcp_message);
pfcp_node = e->pfcp_node;
ogs_assert(pfcp_node);
ogs_assert(OGS_FSM_STATE(&pfcp_node->sm));
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((pfcp_message = ogs_pfcp_parse_msg(recvbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(recvbuf);
break;
}
rv = ogs_pfcp_xact_receive(pfcp_node, &pfcp_message->h, &pfcp_xact);
if (rv != OGS_OK) {
ogs_pkbuf_free(recvbuf);
@@ -113,7 +102,6 @@ void sgwc_state_operational(ogs_fsm_t *s, sgwc_event_t *e)
break;
}
e->pfcp_message = pfcp_message;
e->pfcp_xact_id = pfcp_xact ? pfcp_xact->id : OGS_INVALID_POOL_ID;
e->gtp_message = NULL;

View File

@@ -61,8 +61,12 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_pfcp_header_t *h = NULL;
ogs_pfcp_status_e pfcp_status;;
ogs_pfcp_node_id_t node_id;
ogs_assert(fd != INVALID_SOCKET);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
@@ -102,28 +106,105 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = sgwu_event_new(SGWU_EVT_SXA_MESSAGE);
ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
ogs_pkbuf_free(e->pkbuf);
sgwu_event_free(e);
return;
}
node->sock = data;
pfcp_node_fsm_init(node, false);
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((message = ogs_pfcp_parse_msg(pkbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(pkbuf);
sgwu_event_free(e);
return;
}
pfcp_status = ogs_pfcp_extract_node_id(message, &node_id);
switch (pfcp_status) {
case OGS_PFCP_STATUS_SUCCESS:
case OGS_PFCP_STATUS_NODE_ID_NONE:
case OGS_PFCP_STATUS_NODE_ID_OPTIONAL_ABSENT:
ogs_debug("ogs_pfcp_extract_node_id() "
"type [%d] pfcp_status [%d] node_id [%s] from %s",
message->h.type, pfcp_status,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
break;
case OGS_PFCP_ERROR_SEMANTIC_INCORRECT_MESSAGE:
case OGS_PFCP_ERROR_NODE_ID_NOT_PRESENT:
case OGS_PFCP_ERROR_NODE_ID_NOT_FOUND:
case OGS_PFCP_ERROR_UNKNOWN_MESSAGE:
ogs_error("ogs_pfcp_extract_node_id() failed "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
default:
ogs_error("Unexpected pfcp_status "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL, &from);
if (!node) {
if (message->h.type == OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE ||
message->h.type == OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE) {
ogs_assert(pfcp_status == OGS_PFCP_STATUS_SUCCESS);
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list,
&node_id, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
goto cleanup;
}
ogs_debug("Added PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
pfcp_node_fsm_init(node, false);
} else {
ogs_error("Cannot find PFCP-Node: type [%d] node_id %s from %s",
message->h.type,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
} else {
ogs_debug("Found PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_expect(OGS_OK == ogs_pfcp_node_merge(
node,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL,
&from));
ogs_debug("Merged PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
}
e->pfcp_node = node;
e->pkbuf = pkbuf;
e->pfcp_message = message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_pkbuf_free(e->pkbuf);
sgwu_event_free(e);
goto cleanup;
}
return;
cleanup:
ogs_pkbuf_free(pkbuf);
ogs_pfcp_message_free(message);
sgwu_event_free(e);
}
int sgwu_pfcp_open(void)

View File

@@ -25,7 +25,6 @@ static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
void sgwu_pfcp_state_initial(ogs_fsm_t *s, sgwu_event_t *e)
{
int rv;
ogs_pfcp_node_t *node = NULL;
ogs_assert(s);
@@ -36,10 +35,6 @@ void sgwu_pfcp_state_initial(ogs_fsm_t *s, sgwu_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
rv = ogs_pfcp_connect(
ogs_pfcp_self()->pfcp_sock, ogs_pfcp_self()->pfcp_sock6, node);
ogs_assert(rv == OGS_OK);
node->t_no_heartbeat = ogs_timer_add(ogs_app()->timer_mgr,
sgwu_timer_no_heartbeat, node);
ogs_assert(node->t_no_heartbeat);
@@ -63,12 +58,9 @@ void sgwu_pfcp_state_final(ogs_fsm_t *s, sgwu_event_t *e)
void sgwu_pfcp_state_will_associate(ogs_fsm_t *s, sgwu_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(s);
ogs_assert(e);
@@ -96,11 +88,8 @@ void sgwu_pfcp_state_will_associate(ogs_fsm_t *s, sgwu_event_t *e)
case SGWU_EVT_SXA_TIMER:
switch(e->timer_id) {
case SGWU_TIMER_ASSOCIATION:
addr = node->sa_list;
ogs_assert(addr);
ogs_warn("Retry association with peer [%s]:%d failed",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("Retry association with peer failed %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_assert(node->t_association);
ogs_timer_start(node->t_association,
@@ -155,13 +144,10 @@ void sgwu_pfcp_state_will_associate(ogs_fsm_t *s, sgwu_event_t *e)
void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
sgwu_sess_t *sess = NULL;
ogs_assert(s);
@@ -171,14 +157,11 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
addr = node->sa_list;
ogs_assert(addr);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
ogs_info("PFCP associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_start(node->t_no_heartbeat,
ogs_local_conf()->time.message.pfcp.no_heartbeat_duration);
ogs_assert(OGS_OK ==
@@ -191,9 +174,8 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e)
}
break;
case OGS_FSM_EXIT_SIG:
ogs_info("PFCP de-associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP de-associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_stop(node->t_no_heartbeat);
break;
case SGWU_EVT_SXA_MESSAGE:
@@ -263,16 +245,14 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e)
}
break;
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
ogs_warn("PFCP[REQ] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[REQ] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_up_handle_association_setup_request(node, xact,
&message->pfcp_association_setup_request);
break;
case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
ogs_warn("PFCP[RSP] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[RSP] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_up_handle_association_setup_response(node, xact,
&message->pfcp_association_setup_response);
break;
@@ -318,8 +298,8 @@ void sgwu_pfcp_state_associated(ogs_fsm_t *s, sgwu_event_t *e)
}
break;
case SGWU_EVT_SXA_NO_HEARTBEAT:
ogs_warn("No Heartbeat from SGW-C [%s]:%d",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("No Heartbeat from SGW-C %s",
ogs_sockaddr_to_string_static(node->addr_list));
OGS_FSM_TRAN(s, sgwu_pfcp_state_will_associate);
break;
default:

View File

@@ -58,21 +58,11 @@ void sgwu_state_operational(ogs_fsm_t *s, sgwu_event_t *e)
ogs_assert(e);
recvbuf = e->pkbuf;
ogs_assert(recvbuf);
pfcp_message = e->pfcp_message;
ogs_assert(pfcp_message);
node = e->pfcp_node;
ogs_assert(node);
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((pfcp_message = ogs_pfcp_parse_msg(recvbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(recvbuf);
break;
}
ogs_assert(OGS_FSM_STATE(&node->sm));
rv = ogs_pfcp_xact_receive(node, &pfcp_message->h, &xact);
if (rv != OGS_OK) {
@@ -81,7 +71,6 @@ void sgwu_state_operational(ogs_fsm_t *s, sgwu_event_t *e)
break;
}
e->pfcp_message = pfcp_message;
e->pfcp_xact_id = xact ? xact->id : OGS_INVALID_POOL_ID;
ogs_fsm_dispatch(&node->sm, e);
if (OGS_FSM_CHECK(&node->sm, sgwu_pfcp_state_exception)) {

View File

@@ -206,15 +206,17 @@ void smf_bearer_binding(smf_sess_t *sess)
else
bearer->pgw_s5u_teid = ul_pdr->teid;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_assert(sess->pfcp_node->addr_list);
if (sess->pfcp_node->addr_list->ogs_sa_family ==
AF_INET)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(&bearer->pgw_s5u_addr,
&sess->pfcp_node->addr));
else if (sess->pfcp_node->addr.ogs_sa_family ==
sess->pfcp_node->addr_list));
else if (sess->pfcp_node->addr_list->ogs_sa_family ==
AF_INET6)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(&bearer->pgw_s5u_addr6,
&sess->pfcp_node->addr));
sess->pfcp_node->addr_list));
else
ogs_assert_if_reached();

View File

@@ -1184,8 +1184,6 @@ static ogs_pfcp_node_t *selected_upf_node(
void smf_sess_select_upf(smf_sess_t *sess)
{
char buf[OGS_ADDRSTRLEN];
ogs_assert(sess);
/*
@@ -1201,8 +1199,9 @@ void smf_sess_select_upf(smf_sess_t *sess)
selected_upf_node(ogs_pfcp_self()->pfcp_node, sess);
ogs_assert(ogs_pfcp_self()->pfcp_node);
OGS_SETUP_PFCP_NODE(sess, ogs_pfcp_self()->pfcp_node);
ogs_debug("UE using UPF on IP[%s]",
OGS_ADDR(&ogs_pfcp_self()->pfcp_node->addr, buf));
ogs_debug("UE using UPF on IP %s",
ogs_sockaddr_to_string_static(
ogs_pfcp_self()->pfcp_node->addr_list));
}
smf_sess_t *smf_sess_add_by_apn(smf_ue_t *smf_ue, char *apn, uint8_t rat_type)
@@ -2186,14 +2185,16 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess)
else
sess->handover.upf_dl_teid = pdr->teid;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_assert(sess->pfcp_node->addr_list);
if (sess->pfcp_node->addr_list->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)
sess->pfcp_node->addr_list));
else if (sess->pfcp_node->addr_list->ogs_sa_family ==
AF_INET6)
ogs_assert(OGS_OK == ogs_copyaddrinfo(
&sess->handover.upf_dl_addr6,
&sess->pfcp_node->addr));
sess->pfcp_node->addr_list));
else
ogs_assert_if_reached();

View File

@@ -210,14 +210,15 @@ uint32_t smf_gx_handle_cca_initial_request(
else
bearer->pgw_s5u_teid = ul_pdr->teid;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_assert(sess->pfcp_node->addr_list);
if (sess->pfcp_node->addr_list->ogs_sa_family == AF_INET)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(
&bearer->pgw_s5u_addr, &sess->pfcp_node->addr));
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
&bearer->pgw_s5u_addr, sess->pfcp_node->addr_list));
else if (sess->pfcp_node->addr_list->ogs_sa_family == AF_INET6)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(
&bearer->pgw_s5u_addr6, &sess->pfcp_node->addr));
&bearer->pgw_s5u_addr6, sess->pfcp_node->addr_list));
else
ogs_assert_if_reached();

View File

@@ -645,14 +645,15 @@ bool smf_npcf_smpolicycontrol_handle_create(
else
sess->upf_n3_teid = ul_pdr->teid;
} else {
if (sess->pfcp_node->addr.ogs_sa_family == AF_INET)
ogs_assert(sess->pfcp_node->addr_list);
if (sess->pfcp_node->addr_list->ogs_sa_family == AF_INET)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(
&sess->upf_n3_addr, &sess->pfcp_node->addr));
else if (sess->pfcp_node->addr.ogs_sa_family == AF_INET6)
&sess->upf_n3_addr, sess->pfcp_node->addr_list));
else if (sess->pfcp_node->addr_list->ogs_sa_family == AF_INET6)
ogs_assert(OGS_OK ==
ogs_copyaddrinfo(
&sess->upf_n3_addr6, &sess->pfcp_node->addr));
&sess->upf_n3_addr6, sess->pfcp_node->addr_list));
else
ogs_assert_if_reached();

View File

@@ -101,8 +101,12 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_pfcp_header_t *h = NULL;
ogs_pfcp_status_e pfcp_status;;
ogs_pfcp_node_id_t node_id;
ogs_assert(fd != INVALID_SOCKET);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
@@ -142,28 +146,105 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = smf_event_new(SMF_EVT_N4_MESSAGE);
ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
ogs_pkbuf_free(e->pkbuf);
ogs_event_free(e);
return;
}
node->sock = data;
pfcp_node_fsm_init(node, false);
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((message = ogs_pfcp_parse_msg(pkbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(pkbuf);
ogs_event_free(e);
return;
}
pfcp_status = ogs_pfcp_extract_node_id(message, &node_id);
switch (pfcp_status) {
case OGS_PFCP_STATUS_SUCCESS:
case OGS_PFCP_STATUS_NODE_ID_NONE:
case OGS_PFCP_STATUS_NODE_ID_OPTIONAL_ABSENT:
ogs_debug("ogs_pfcp_extract_node_id() "
"type [%d] pfcp_status [%d] node_id [%s] from %s",
message->h.type, pfcp_status,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
break;
case OGS_PFCP_ERROR_SEMANTIC_INCORRECT_MESSAGE:
case OGS_PFCP_ERROR_NODE_ID_NOT_PRESENT:
case OGS_PFCP_ERROR_NODE_ID_NOT_FOUND:
case OGS_PFCP_ERROR_UNKNOWN_MESSAGE:
ogs_error("ogs_pfcp_extract_node_id() failed "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
default:
ogs_error("Unexpected pfcp_status "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL, &from);
if (!node) {
if (message->h.type == OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE ||
message->h.type == OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE) {
ogs_assert(pfcp_status == OGS_PFCP_STATUS_SUCCESS);
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list,
&node_id, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
goto cleanup;
}
ogs_debug("Added PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
pfcp_node_fsm_init(node, false);
} else {
ogs_error("Cannot find PFCP-Node: type [%d] node_id %s from %s",
message->h.type,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
} else {
ogs_debug("Found PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_expect(OGS_OK == ogs_pfcp_node_merge(
node,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL,
&from));
ogs_debug("Merged PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
}
e->pfcp_node = node;
e->pkbuf = pkbuf;
e->pfcp_message = message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_pkbuf_free(e->pkbuf);
ogs_event_free(e);
goto cleanup;
}
return;
cleanup:
ogs_pkbuf_free(pkbuf);
ogs_pfcp_message_free(message);
ogs_event_free(e);
}
int smf_pfcp_open(void)

View File

@@ -28,7 +28,6 @@ static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
void smf_pfcp_state_initial(ogs_fsm_t *s, smf_event_t *e)
{
int rv;
ogs_pfcp_node_t *node = NULL;
ogs_assert(s);
@@ -39,10 +38,6 @@ void smf_pfcp_state_initial(ogs_fsm_t *s, smf_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
rv = ogs_pfcp_connect(
ogs_pfcp_self()->pfcp_sock, ogs_pfcp_self()->pfcp_sock6, node);
ogs_assert(rv == OGS_OK);
node->t_no_heartbeat = ogs_timer_add(ogs_app()->timer_mgr,
smf_timer_pfcp_no_heartbeat, node);
ogs_assert(node->t_no_heartbeat);
@@ -66,13 +61,10 @@ void smf_pfcp_state_final(ogs_fsm_t *s, smf_event_t *e)
void smf_pfcp_state_will_associate(ogs_fsm_t *s, smf_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
smf_sess_t *sess;
ogs_assert(s);
@@ -82,8 +74,6 @@ void smf_pfcp_state_will_associate(ogs_fsm_t *s, smf_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
addr = node->sa_list;
ogs_assert(addr);
switch (e->h.id) {
case OGS_FSM_ENTRY_SIG:
@@ -107,8 +97,8 @@ void smf_pfcp_state_will_associate(ogs_fsm_t *s, smf_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
ogs_warn("Retry association with peer [%s]:%d failed",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("Retry association with peer failed %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_assert(node->t_association);
ogs_timer_start(node->t_association,
@@ -179,13 +169,10 @@ void smf_pfcp_state_will_associate(ogs_fsm_t *s, smf_event_t *e)
void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
smf_sess_t *sess = NULL;
ogs_assert(s);
@@ -195,14 +182,11 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
addr = node->sa_list;
ogs_assert(addr);
switch (e->h.id) {
case OGS_FSM_ENTRY_SIG:
ogs_info("PFCP associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_start(node->t_no_heartbeat,
ogs_local_conf()->time.message.pfcp.no_heartbeat_duration);
ogs_assert(OGS_OK ==
@@ -215,9 +199,8 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
}
break;
case OGS_FSM_EXIT_SIG:
ogs_info("PFCP de-associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP de-associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_stop(node->t_no_heartbeat);
break;
case SMF_EVT_N4_MESSAGE:
@@ -296,16 +279,14 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
}
break;
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
ogs_warn("PFCP[REQ] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[REQ] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_cp_handle_association_setup_request(node, xact,
&message->pfcp_association_setup_request);
break;
case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
ogs_warn("PFCP[RSP] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[RSP] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_cp_handle_association_setup_response(node, xact,
&message->pfcp_association_setup_response);
break;
@@ -421,8 +402,8 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
}
break;
case SMF_EVT_N4_NO_HEARTBEAT:
ogs_warn("No Heartbeat from UPF [%s]:%d",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("No Heartbeat from UPF %s",
ogs_sockaddr_to_string_static(node->addr_list));
/*
* reselect_upf() should not be executed on node_timeout

View File

@@ -405,23 +405,12 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
ogs_assert(e);
recvbuf = e->pkbuf;
ogs_assert(recvbuf);
pfcp_message = e->pfcp_message;
ogs_assert(pfcp_message);
pfcp_node = e->pfcp_node;
ogs_assert(pfcp_node);
ogs_assert(OGS_FSM_STATE(&pfcp_node->sm));
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((pfcp_message = ogs_pfcp_parse_msg(recvbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(recvbuf);
break;
}
rv = ogs_pfcp_xact_receive(pfcp_node, &pfcp_message->h, &pfcp_xact);
if (rv != OGS_OK) {
ogs_pkbuf_free(recvbuf);
@@ -429,7 +418,6 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e)
break;
}
e->pfcp_message = pfcp_message;
e->pfcp_xact_id = pfcp_xact ? pfcp_xact->id : OGS_INVALID_POOL_ID;
e->gtp2_message = NULL;

View File

@@ -64,8 +64,12 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
ogs_pkbuf_t *pkbuf = NULL;
ogs_sockaddr_t from;
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_pfcp_header_t *h = NULL;
ogs_pfcp_status_e pfcp_status;;
ogs_pfcp_node_id_t node_id;
ogs_assert(fd != INVALID_SOCKET);
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
@@ -105,28 +109,105 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data)
e = upf_event_new(UPF_EVT_N4_MESSAGE);
ogs_assert(e);
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
ogs_pkbuf_free(e->pkbuf);
upf_event_free(e);
return;
}
node->sock = data;
pfcp_node_fsm_init(node, false);
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((message = ogs_pfcp_parse_msg(pkbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(pkbuf);
upf_event_free(e);
return;
}
pfcp_status = ogs_pfcp_extract_node_id(message, &node_id);
switch (pfcp_status) {
case OGS_PFCP_STATUS_SUCCESS:
case OGS_PFCP_STATUS_NODE_ID_NONE:
case OGS_PFCP_STATUS_NODE_ID_OPTIONAL_ABSENT:
ogs_debug("ogs_pfcp_extract_node_id() "
"type [%d] pfcp_status [%d] node_id [%s] from %s",
message->h.type, pfcp_status,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
break;
case OGS_PFCP_ERROR_SEMANTIC_INCORRECT_MESSAGE:
case OGS_PFCP_ERROR_NODE_ID_NOT_PRESENT:
case OGS_PFCP_ERROR_NODE_ID_NOT_FOUND:
case OGS_PFCP_ERROR_UNKNOWN_MESSAGE:
ogs_error("ogs_pfcp_extract_node_id() failed "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
default:
ogs_error("Unexpected pfcp_status "
"type [%d] pfcp_status [%d] from %s",
message->h.type, pfcp_status,
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
node = ogs_pfcp_node_find(&ogs_pfcp_self()->pfcp_peer_list,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL, &from);
if (!node) {
if (message->h.type == OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE ||
message->h.type == OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE) {
ogs_assert(pfcp_status == OGS_PFCP_STATUS_SUCCESS);
node = ogs_pfcp_node_add(&ogs_pfcp_self()->pfcp_peer_list,
&node_id, &from);
if (!node) {
ogs_error("No memory: ogs_pfcp_node_add() failed");
goto cleanup;
}
ogs_debug("Added PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
pfcp_node_fsm_init(node, false);
} else {
ogs_error("Cannot find PFCP-Node: type [%d] node_id %s from %s",
message->h.type,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ?
ogs_pfcp_node_id_to_string_static(&node_id) :
"NULL",
ogs_sockaddr_to_string_static(&from));
goto cleanup;
}
} else {
ogs_debug("Found PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_expect(OGS_OK == ogs_pfcp_node_merge(
node,
pfcp_status == OGS_PFCP_STATUS_SUCCESS ? &node_id : NULL,
&from));
ogs_debug("Merged PFCP-Node: addr_list %s",
ogs_sockaddr_to_string_static(node->addr_list));
}
e->pfcp_node = node;
e->pkbuf = pkbuf;
e->pfcp_message = message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_pkbuf_free(e->pkbuf);
upf_event_free(e);
goto cleanup;
}
return;
cleanup:
ogs_pkbuf_free(pkbuf);
ogs_pfcp_message_free(message);
upf_event_free(e);
}
int upf_pfcp_open(void)

View File

@@ -30,7 +30,6 @@ static void node_timeout(ogs_pfcp_xact_t *xact, void *data);
void upf_pfcp_state_initial(ogs_fsm_t *s, upf_event_t *e)
{
int rv;
ogs_pfcp_node_t *node = NULL;
ogs_assert(s);
@@ -41,10 +40,6 @@ void upf_pfcp_state_initial(ogs_fsm_t *s, upf_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
rv = ogs_pfcp_connect(
ogs_pfcp_self()->pfcp_sock, ogs_pfcp_self()->pfcp_sock6, node);
ogs_assert(rv == OGS_OK);
node->t_no_heartbeat = ogs_timer_add(ogs_app()->timer_mgr,
upf_timer_no_heartbeat, node);
ogs_assert(node->t_no_heartbeat);
@@ -68,12 +63,9 @@ void upf_pfcp_state_final(ogs_fsm_t *s, upf_event_t *e)
void upf_pfcp_state_will_associate(ogs_fsm_t *s, upf_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
ogs_assert(s);
ogs_assert(e);
@@ -101,11 +93,8 @@ void upf_pfcp_state_will_associate(ogs_fsm_t *s, upf_event_t *e)
case UPF_EVT_N4_TIMER:
switch(e->timer_id) {
case UPF_TIMER_ASSOCIATION:
addr = node->sa_list;
ogs_assert(addr);
ogs_warn("Retry association with peer [%s]:%d failed",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("Retry association with peer failed %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_assert(node->t_association);
ogs_timer_start(node->t_association,
@@ -160,13 +149,10 @@ void upf_pfcp_state_will_associate(ogs_fsm_t *s, upf_event_t *e)
void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e)
{
char buf[OGS_ADDRSTRLEN];
ogs_pfcp_node_t *node = NULL;
ogs_pfcp_xact_t *xact = NULL;
ogs_pfcp_message_t *message = NULL;
ogs_sockaddr_t *addr = NULL;
upf_sess_t *sess = NULL;
ogs_assert(s);
@@ -176,14 +162,11 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e)
node = e->pfcp_node;
ogs_assert(node);
addr = node->sa_list;
ogs_assert(addr);
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
ogs_info("PFCP associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_start(node->t_no_heartbeat,
ogs_local_conf()->time.message.pfcp.no_heartbeat_duration);
ogs_assert(OGS_OK ==
@@ -196,9 +179,8 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e)
}
break;
case OGS_FSM_EXIT_SIG:
ogs_info("PFCP de-associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_info("PFCP de-associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_timer_stop(node->t_no_heartbeat);
break;
case UPF_EVT_N4_MESSAGE:
@@ -267,16 +249,14 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e)
}
break;
case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
ogs_warn("PFCP[REQ] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[REQ] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_up_handle_association_setup_request(node, xact,
&message->pfcp_association_setup_request);
break;
case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
ogs_warn("PFCP[RSP] has already been associated [%s]:%d",
OGS_ADDR(&node->addr, buf),
OGS_PORT(&node->addr));
ogs_warn("PFCP[RSP] has already been associated %s",
ogs_sockaddr_to_string_static(node->addr_list));
ogs_pfcp_up_handle_association_setup_response(node, xact,
&message->pfcp_association_setup_response);
break;
@@ -322,8 +302,8 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e)
}
break;
case UPF_EVT_N4_NO_HEARTBEAT:
ogs_warn("No Heartbeat from SMF [%s]:%d",
OGS_ADDR(addr, buf), OGS_PORT(addr));
ogs_warn("No Heartbeat from SMF %s",
ogs_sockaddr_to_string_static(node->addr_list));
OGS_FSM_TRAN(s, upf_pfcp_state_will_associate);
break;
default:

View File

@@ -63,21 +63,11 @@ void upf_state_operational(ogs_fsm_t *s, upf_event_t *e)
ogs_assert(e);
recvbuf = e->pkbuf;
ogs_assert(recvbuf);
pfcp_message = e->pfcp_message;
ogs_assert(pfcp_message);
node = e->pfcp_node;
ogs_assert(node);
/*
* Issue #1911
*
* Because ogs_pfcp_message_t is over 80kb in size,
* it can cause stack overflow.
* To avoid this, the pfcp_message structure uses heap memory.
*/
if ((pfcp_message = ogs_pfcp_parse_msg(recvbuf)) == NULL) {
ogs_error("ogs_pfcp_parse_msg() failed");
ogs_pkbuf_free(recvbuf);
break;
}
ogs_assert(OGS_FSM_STATE(&node->sm));
rv = ogs_pfcp_xact_receive(node, &pfcp_message->h, &xact);
if (rv != OGS_OK) {
@@ -86,7 +76,6 @@ void upf_state_operational(ogs_fsm_t *s, upf_event_t *e)
break;
}
e->pfcp_message = pfcp_message;
e->pfcp_xact_id = xact ? xact->id : OGS_INVALID_POOL_ID;
ogs_fsm_dispatch(&node->sm, e);
if (OGS_FSM_CHECK(&node->sm, upf_pfcp_state_exception)) {