diff --git a/lib/pfcp/path.c b/lib/pfcp/path.c index bbced8614..118d1622d 100644 --- a/lib/pfcp/path.c +++ b/lib/pfcp/path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -36,6 +36,91 @@ ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node) return pfcp; } +/* Minimum PFCP header length (e.g., 12 bytes) */ +#define MIN_PFCP_HEADER_LENGTH 12 + +/* + * ogs_pfcp_recvfrom + * + * Receives a PFCP message from the socket 'fd'. It allocates a pkbuf, + * receives the message, trims the pkbuf, and verifies the header. + * If any error occurs (e.g., too short message, unsupported version, or + * incomplete message), the function frees the pkbuf and returns NULL. + * + * The sender's address is stored in 'from'. + * + * Returns a pointer to ogs_pkbuf_t on success, or NULL on failure. + */ +ogs_pkbuf_t *ogs_pfcp_recvfrom(ogs_socket_t fd, ogs_sockaddr_t *from) +{ + ogs_pkbuf_t *pkbuf; + ssize_t size; + ogs_pfcp_header_t *h; + uint16_t pfcp_body_length; + size_t expected_total_length; + + ogs_assert(fd != INVALID_SOCKET); + ogs_assert(from); + + /* Allocate buffer for maximum SDU length */ + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + if (pkbuf == NULL) { + ogs_error("ogs_pkbuf_alloc() failed"); + return NULL; + } + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); + + size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, from); + if (size <= 0) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "ogs_recvfrom() failed"); + ogs_pkbuf_free(pkbuf); + return NULL; + } + ogs_pkbuf_trim(pkbuf, size); + + /* Check that the data is at least as long as the header */ + if (size < MIN_PFCP_HEADER_LENGTH) { + ogs_error("Received PFCP message too short: %ld bytes (min %d)", + size, MIN_PFCP_HEADER_LENGTH); + ogs_pkbuf_free(pkbuf); + return NULL; + } + + h = (ogs_pfcp_header_t *)pkbuf->data; + + /* Verify PFCP version */ + if (h->version != OGS_PFCP_VERSION) { + ogs_pfcp_header_t rsp; + memset(&rsp, 0, sizeof(rsp)); + ogs_error("Not supported version[%d]", h->version); + rsp.flags = (OGS_PFCP_VERSION << 5); + rsp.type = OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE; + rsp.length = htobe16(4); + rsp.sqn_only = h->sqn_only; + if (ogs_sendto(fd, &rsp, 8, 0, from) < 0) { + ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, + "ogs_sendto() failed"); + } + ogs_pkbuf_free(pkbuf); + return NULL; + } + + /* Check total PFCP message length. + Assume the header's length field indicates the body length, + excluding the first 4 bytes. */ + pfcp_body_length = be16toh(h->length); + expected_total_length = pfcp_body_length + 4; + if ((size_t)size < expected_total_length) { + ogs_error("Incomplete PFCP message: expected %zu bytes, " + "received %ld bytes", expected_total_length, size); + ogs_pkbuf_free(pkbuf); + return NULL; + } + + return pkbuf; +} + int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf) { ssize_t sent; diff --git a/lib/pfcp/path.h b/lib/pfcp/path.h index f187970b4..c715b6d4f 100644 --- a/lib/pfcp/path.h +++ b/lib/pfcp/path.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -58,6 +58,8 @@ typedef struct ogs_pfcp_xact_s ogs_pfcp_xact_t; ogs_sock_t *ogs_pfcp_server(ogs_socknode_t *node); int ogs_pfcp_sendto(ogs_pfcp_node_t *node, ogs_pkbuf_t *pkbuf); +ogs_pkbuf_t *ogs_pfcp_recvfrom(ogs_socket_t fd, ogs_sockaddr_t *from); + ogs_pkbuf_t *ogs_pfcp_handle_echo_req(ogs_pkbuf_t *pkt); int ogs_pfcp_send_heartbeat_request(ogs_pfcp_node_t *node, diff --git a/src/sgwc/pfcp-path.c b/src/sgwc/pfcp-path.c index 5712fa98c..1483e99a1 100644 --- a/src/sgwc/pfcp-path.c +++ b/src/sgwc/pfcp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2023 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -56,50 +56,20 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data) { int rv; - ssize_t size; sgwc_event_t *e = NULL; 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); - ogs_assert(pkbuf); - ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); - - size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from); - if (size <= 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_recvfrom() failed"); - ogs_pkbuf_free(pkbuf); - return; - } - - ogs_pkbuf_trim(pkbuf, size); - - h = (ogs_pfcp_header_t *)pkbuf->data; - if (h->version != OGS_PFCP_VERSION) { - ogs_pfcp_header_t rsp; - - ogs_error("Not supported version[%d]", h->version); - - memset(&rsp, 0, sizeof rsp); - rsp.flags = (OGS_PFCP_VERSION << 5); - rsp.type = OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE; - rsp.length = htobe16(4); - rsp.sqn_only = h->sqn_only; - if (ogs_sendto(fd, &rsp, 8, 0, &from) < 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_sendto() failed"); - } - ogs_pkbuf_free(pkbuf); - + pkbuf = ogs_pfcp_recvfrom(fd, &from); + if (!pkbuf) { + ogs_error("ogs_pfcp_recvfrom() failed"); return; } diff --git a/src/sgwu/pfcp-path.c b/src/sgwu/pfcp-path.c index 90093543a..3cdd32053 100644 --- a/src/sgwu/pfcp-path.c +++ b/src/sgwu/pfcp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -56,50 +56,20 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data) { int rv; - ssize_t size; sgwu_event_t *e = NULL; 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); - ogs_assert(pkbuf); - ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); - - size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from); - if (size <= 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_recvfrom() failed"); - ogs_pkbuf_free(pkbuf); - return; - } - - ogs_pkbuf_trim(pkbuf, size); - - h = (ogs_pfcp_header_t *)pkbuf->data; - if (h->version != OGS_PFCP_VERSION) { - ogs_pfcp_header_t rsp; - - ogs_error("Not supported version[%d]", h->version); - - memset(&rsp, 0, sizeof rsp); - rsp.flags = (OGS_PFCP_VERSION << 5); - rsp.type = OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE; - rsp.length = htobe16(4); - rsp.sqn_only = h->sqn_only; - if (ogs_sendto(fd, &rsp, 8, 0, &from) < 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_sendto() failed"); - } - ogs_pkbuf_free(pkbuf); - + pkbuf = ogs_pfcp_recvfrom(fd, &from); + if (!pkbuf) { + ogs_error("ogs_pfcp_recvfrom() failed"); return; } diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index 55976ea1e..b560cfa02 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2023 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -96,50 +96,20 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data) { int rv; - ssize_t size; smf_event_t *e = NULL; 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); - ogs_assert(pkbuf); - ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); - - size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from); - if (size <= 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_recvfrom() failed"); - ogs_pkbuf_free(pkbuf); - return; - } - - ogs_pkbuf_trim(pkbuf, size); - - h = (ogs_pfcp_header_t *)pkbuf->data; - if (h->version != OGS_PFCP_VERSION) { - ogs_pfcp_header_t rsp; - - ogs_error("Not supported version[%d]", h->version); - - memset(&rsp, 0, sizeof rsp); - rsp.flags = (OGS_PFCP_VERSION << 5); - rsp.type = OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE; - rsp.length = htobe16(4); - rsp.sqn_only = h->sqn_only; - if (ogs_sendto(fd, &rsp, 8, 0, &from) < 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_sendto() failed"); - } - ogs_pkbuf_free(pkbuf); - + pkbuf = ogs_pfcp_recvfrom(fd, &from); + if (!pkbuf) { + ogs_error("ogs_pfcp_recvfrom() failed"); return; } diff --git a/src/upf/pfcp-path.c b/src/upf/pfcp-path.c index bd5c5d03a..ad3c3577a 100644 --- a/src/upf/pfcp-path.c +++ b/src/upf/pfcp-path.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 by Sukchan Lee + * Copyright (C) 2019-2025 by Sukchan Lee * * This file is part of Open5GS. * @@ -59,50 +59,20 @@ static void pfcp_recv_cb(short when, ogs_socket_t fd, void *data) { int rv; - ssize_t size; upf_event_t *e = NULL; 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); - ogs_assert(pkbuf); - ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN); - - size = ogs_recvfrom(fd, pkbuf->data, pkbuf->len, 0, &from); - if (size <= 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_recvfrom() failed"); - ogs_pkbuf_free(pkbuf); - return; - } - - ogs_pkbuf_trim(pkbuf, size); - - h = (ogs_pfcp_header_t *)pkbuf->data; - if (h->version != OGS_PFCP_VERSION) { - ogs_pfcp_header_t rsp; - - ogs_error("Not supported version[%d]", h->version); - - memset(&rsp, 0, sizeof rsp); - rsp.flags = (OGS_PFCP_VERSION << 5); - rsp.type = OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE; - rsp.length = htobe16(4); - rsp.sqn_only = h->sqn_only; - if (ogs_sendto(fd, &rsp, 8, 0, &from) < 0) { - ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno, - "ogs_sendto() failed"); - } - ogs_pkbuf_free(pkbuf); - + pkbuf = ogs_pfcp_recvfrom(fd, &from); + if (!pkbuf) { + ogs_error("ogs_pfcp_recvfrom() failed"); return; }