net: lwm2m: Protect send() calls with a mutex

Although LwM2M engine uses cooperative threads, the internal `send()`
implementation might trigger context switch when it calls a kernel
function, therefore resulting in `send()` call being entered from both
the LwM2M thread and the retransmit work.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2020-06-30 12:16:55 +02:00 committed by Carles Cufí
commit fddeb59911
2 changed files with 23 additions and 1 deletions

View file

@ -24,6 +24,7 @@
#define ZEPHYR_INCLUDE_NET_LWM2M_H_
#include <kernel.h>
#include <sys/mutex.h>
#include <net/coap.h>
/**
@ -69,6 +70,7 @@ struct lwm2m_ctx {
struct coap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING];
struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES];
struct k_delayed_work retransmit_work;
struct sys_mutex send_lock;
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
/** TLS tag is set by client as a reference used when the

View file

@ -26,6 +26,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <ctype.h>
#include <errno.h>
#include <init.h>
#include <sys/mutex.h>
#include <sys/printk.h>
#include <net/net_ip.h>
#include <net/http_parser_url.h>
@ -994,6 +995,8 @@ cleanup:
int lwm2m_send_message(struct lwm2m_message *msg)
{
int rc;
if (!msg || !msg->ctx) {
LOG_ERR("LwM2M message is invalid.");
return -EINVAL;
@ -1005,11 +1008,16 @@ int lwm2m_send_message(struct lwm2m_message *msg)
msg->send_attempts++;
if (send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0) < 0) {
sys_mutex_lock(&msg->ctx->send_lock, K_FOREVER);
rc = send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0);
sys_mutex_unlock(&msg->ctx->send_lock);
if (rc < 0) {
if (msg->type == COAP_TYPE_CON) {
coap_pending_clear(msg->pending);
}
LOG_ERR("Failed to send packet, err %d", errno);
return -errno;
}
@ -3769,11 +3777,22 @@ static void retransmit_request(struct k_work *work)
LOG_INF("Resending message: %p", msg);
msg->send_attempts++;
sys_mutex_lock(&client_ctx->send_lock, K_FOREVER);
if (msg->ctx == NULL) {
LOG_INF("Response for %p already handled", msg);
goto next_locked;
}
if (send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0) < 0) {
LOG_ERR("Error sending lwm2m message: %d", -errno);
/* don't error here, retry until timeout */
}
next_locked:
sys_mutex_unlock(&client_ctx->send_lock);
next:
pending = coap_pending_next_to_expire(client_ctx->pendings,
CONFIG_LWM2M_ENGINE_MAX_PENDING);
@ -4055,6 +4074,7 @@ int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx)
void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx)
{
k_delayed_work_init(&client_ctx->retransmit_work, retransmit_request);
sys_mutex_init(&client_ctx->send_lock);
}
/* LwM2M Socket Integration */