From d181ab54ccf9fb829ec491dfc18ab42e4179ae8f Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sat, 11 Jan 2025 14:32:39 +0900 Subject: [PATCH] [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. --- lib/core/ogs-sockaddr.c | 102 ++++++++++-- lib/core/ogs-sockaddr.h | 17 +- lib/pfcp/context.c | 189 +++++++++++++++++++--- lib/pfcp/context.h | 27 +++- lib/pfcp/handler.c | 22 +-- lib/pfcp/path.c | 99 ++++-------- lib/pfcp/path.h | 4 - lib/pfcp/util.c | 336 ++++++++++++++++++++++++++++++---------- lib/pfcp/util.h | 26 ++-- lib/pfcp/xact.c | 113 +++++--------- lib/sctp/ogs-usrsctp.c | 34 ++-- src/sgwc/context.c | 16 +- src/sgwc/pfcp-path.c | 109 +++++++++++-- src/sgwc/pfcp-sm.c | 44 ++---- src/sgwc/sgwc-sm.c | 16 +- src/sgwu/pfcp-path.c | 109 +++++++++++-- src/sgwu/pfcp-sm.c | 44 ++---- src/sgwu/sgwu-sm.c | 17 +- src/smf/binding.c | 10 +- src/smf/context.c | 17 +- src/smf/gx-handler.c | 9 +- src/smf/npcf-handler.c | 9 +- src/smf/pfcp-path.c | 109 +++++++++++-- src/smf/pfcp-sm.c | 43 ++--- src/smf/smf-sm.c | 16 +- src/upf/pfcp-path.c | 109 +++++++++++-- src/upf/pfcp-sm.c | 44 ++---- src/upf/upf-sm.c | 17 +- 28 files changed, 1111 insertions(+), 596 deletions(-) diff --git a/lib/core/ogs-sockaddr.c b/lib/core/ogs-sockaddr.c index 31df69a69..c54a1f590 100644 --- a/lib/core/ogs-sockaddr.c +++ b/lib/core/ogs-sockaddr.c @@ -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; diff --git a/lib/core/ogs-sockaddr.h b/lib/core/ogs-sockaddr.h index 95e4d0daa..c4550878c 100644 --- a/lib/core/ogs-sockaddr.h +++ b/lib/core/ogs-sockaddr.h @@ -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); diff --git a/lib/pfcp/context.c b/lib/pfcp/context.c index 9981fb2d5..9d5b7544a 100644 --- a/lib/pfcp/context.c +++ b/lib/pfcp/context.c @@ -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) { diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index 289bbd989..219644fcf 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -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); diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index 6228d1361..caee63eb9 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -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; } diff --git a/lib/pfcp/path.c b/lib/pfcp/path.c index 82e3a3467..bbced8614 100644 --- a/lib/pfcp/path.c +++ b/lib/pfcp/path.c @@ -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; } diff --git a/lib/pfcp/path.h b/lib/pfcp/path.h index 379e992eb..f187970b4 100644 --- a/lib/pfcp/path.h +++ b/lib/pfcp/path.h @@ -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); diff --git a/lib/pfcp/util.c b/lib/pfcp/util.c index fd91ca608..d640ba248 100644 --- a/lib/pfcp/util.c +++ b/lib/pfcp/util.c @@ -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; } diff --git a/lib/pfcp/util.h b/lib/pfcp/util.h index 7380efa3d..ef6ae5d9a 100644 --- a/lib/pfcp/util.h +++ b/lib/pfcp/util.h @@ -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 } diff --git a/lib/pfcp/xact.c b/lib/pfcp/xact.c index 30f3f9f12..fbbc2d97c 100644 --- a/lib/pfcp/xact.c +++ b/lib/pfcp/xact.c @@ -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); diff --git a/lib/sctp/ogs-usrsctp.c b/lib/sctp/ogs-usrsctp.c index 323118a19..a587fbcae 100644 --- a/lib/sctp/ogs-usrsctp.c +++ b/lib/sctp/ogs-usrsctp.c @@ -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; } diff --git a/src/sgwc/context.c b/src/sgwc/context.c index 3c19ad7be..758486ef7 100644 --- a/src/sgwc/context.c +++ b/src/sgwc/context.c @@ -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(); diff --git a/src/sgwc/pfcp-path.c b/src/sgwc/pfcp-path.c index b0b12aadd..5712fa98c 100644 --- a/src/sgwc/pfcp-path.c +++ b/src/sgwc/pfcp-path.c @@ -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) diff --git a/src/sgwc/pfcp-sm.c b/src/sgwc/pfcp-sm.c index e0357ae61..bf9ed5aa2 100644 --- a/src/sgwc/pfcp-sm.c +++ b/src/sgwc/pfcp-sm.c @@ -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: diff --git a/src/sgwc/sgwc-sm.c b/src/sgwc/sgwc-sm.c index 1d24945eb..96c7d1272 100644 --- a/src/sgwc/sgwc-sm.c +++ b/src/sgwc/sgwc-sm.c @@ -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; diff --git a/src/sgwu/pfcp-path.c b/src/sgwu/pfcp-path.c index 73def6adb..90093543a 100644 --- a/src/sgwu/pfcp-path.c +++ b/src/sgwu/pfcp-path.c @@ -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) diff --git a/src/sgwu/pfcp-sm.c b/src/sgwu/pfcp-sm.c index 9696cf4a7..130a79912 100644 --- a/src/sgwu/pfcp-sm.c +++ b/src/sgwu/pfcp-sm.c @@ -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: diff --git a/src/sgwu/sgwu-sm.c b/src/sgwu/sgwu-sm.c index 149070771..960430658 100644 --- a/src/sgwu/sgwu-sm.c +++ b/src/sgwu/sgwu-sm.c @@ -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)) { diff --git a/src/smf/binding.c b/src/smf/binding.c index 5ad081a72..d43d63963 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -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(); diff --git a/src/smf/context.c b/src/smf/context.c index 142496bc5..762a9914e 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -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(); diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index e9b6d043e..aba48bd99 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -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(); diff --git a/src/smf/npcf-handler.c b/src/smf/npcf-handler.c index e91c061d0..237c46add 100644 --- a/src/smf/npcf-handler.c +++ b/src/smf/npcf-handler.c @@ -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(); diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index 2739325aa..55976ea1e 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -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) diff --git a/src/smf/pfcp-sm.c b/src/smf/pfcp-sm.c index 86cd34e6c..58ed1c592 100644 --- a/src/smf/pfcp-sm.c +++ b/src/smf/pfcp-sm.c @@ -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 diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c index dab4a8169..4c161de1b 100644 --- a/src/smf/smf-sm.c +++ b/src/smf/smf-sm.c @@ -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; diff --git a/src/upf/pfcp-path.c b/src/upf/pfcp-path.c index ea4591dce..bd5c5d03a 100644 --- a/src/upf/pfcp-path.c +++ b/src/upf/pfcp-path.c @@ -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) diff --git a/src/upf/pfcp-sm.c b/src/upf/pfcp-sm.c index 7a1f74b94..04222172b 100644 --- a/src/upf/pfcp-sm.c +++ b/src/upf/pfcp-sm.c @@ -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: diff --git a/src/upf/upf-sm.c b/src/upf/upf-sm.c index a4e842546..df85d21d7 100644 --- a/src/upf/upf-sm.c +++ b/src/upf/upf-sm.c @@ -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)) {