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 <pieter.degendt@basalte.be>
This commit is contained in:
Pieter De Gendt 2025-01-09 17:05:30 +01:00 committed by Benjamin Cabé
commit 81b87ac35b
2 changed files with 51 additions and 4 deletions

View file

@ -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

View file

@ -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];