From dd16b7821c97bd218ab247207492791a0283f037 Mon Sep 17 00:00:00 2001 From: Pieter De Gendt Date: Thu, 9 Jan 2025 17:05:30 +0100 Subject: [PATCH] net: lib: coap: Handle truncated messages in CoAP server If the CoAP server receives a message that doesn't fit into the receive buffer, we should stop processing the message and respond to the client with 4.13 "Request Entity too large". Signed-off-by: Pieter De Gendt --- subsys/net/lib/coap/Kconfig | 8 ++++++ subsys/net/lib/coap/coap_server.c | 47 ++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/subsys/net/lib/coap/Kconfig b/subsys/net/lib/coap/Kconfig index 443514a686152d..a4a75108cdccae 100644 --- a/subsys/net/lib/coap/Kconfig +++ b/subsys/net/lib/coap/Kconfig @@ -247,6 +247,14 @@ config COAP_SERVER_PENDING_ALLOCATOR_STATIC_BLOCKS help The number of data blocks to reserve for pending messages to retransmit. +config COAP_SERVER_TRUNCATE_MSGS + bool "Handle truncated messages" + default y + help + Include ZSOCK_MSG_TRUNC in flags passed to zsock_recvfrom() to + receive network stack notifications about block truncation. + Otherwise it happens silently. + config COAP_SERVER_SHELL bool "CoAP service shell commands" depends on SHELL diff --git a/subsys/net/lib/coap/coap_server.c b/subsys/net/lib/coap/coap_server.c index 8b7fc0168c3ad9..0234268901ddb7 100644 --- a/subsys/net/lib/coap/coap_server.c +++ b/subsys/net/lib/coap/coap_server.c @@ -135,10 +135,13 @@ static int coap_server_process(int sock_fd) uint8_t type; ssize_t received; int ret; + int flags = ZSOCK_MSG_DONTWAIT; - received = zsock_recvfrom(sock_fd, buf, sizeof(buf), ZSOCK_MSG_DONTWAIT, &client_addr, - &client_addr_len); - __ASSERT_NO_MSG(received <= sizeof(buf)); + if (IS_ENABLED(CONFIG_COAP_SERVER_TRUNCATE_MSGS)) { + flags |= ZSOCK_MSG_TRUNC; + } + + received = zsock_recvfrom(sock_fd, buf, sizeof(buf), flags, &client_addr, &client_addr_len); if (received < 0) { if (errno == EWOULDBLOCK) { @@ -149,7 +152,7 @@ static int coap_server_process(int sock_fd) return -errno; } - ret = coap_packet_parse(&request, buf, received, options, opt_num); + ret = coap_packet_parse(&request, buf, MIN(received, sizeof(buf)), options, opt_num); if (ret < 0) { LOG_ERR("Failed To parse coap message (%d)", ret); return ret; @@ -170,6 +173,42 @@ static int coap_server_process(int sock_fd) type = coap_header_get_type(&request); + if (received > sizeof(buf)) { + /* The message was truncated and can't be processed further */ + struct coap_packet response; + uint8_t token[COAP_TOKEN_MAX_LEN]; + uint8_t tkl = coap_header_get_token(&request, token); + uint16_t id = coap_header_get_id(&request); + + if (type == COAP_TYPE_CON) { + type = COAP_TYPE_ACK; + } else { + type = COAP_TYPE_NON_CON; + } + + ret = coap_packet_init(&response, buf, sizeof(buf), COAP_VERSION_1, type, tkl, + token, COAP_RESPONSE_CODE_REQUEST_TOO_LARGE, id); + if (ret < 0) { + LOG_ERR("Failed to init response (%d)", ret); + goto unlock; + } + + ret = coap_append_option_int(&response, COAP_OPTION_SIZE1, + CONFIG_COAP_SERVER_MESSAGE_SIZE); + if (ret < 0) { + LOG_ERR("Failed to add SIZE1 option (%d)", ret); + goto unlock; + } + + ret = coap_service_send(service, &response, &client_addr, client_addr_len, NULL); + if (ret < 0) { + LOG_ERR("Failed to reply \"Request Entity Too Large\" (%d)", ret); + goto unlock; + } + + goto unlock; + } + pending = coap_pending_received(&request, service->data->pending, MAX_PENDINGS); if (pending) { uint8_t token[COAP_TOKEN_MAX_LEN];