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:
parent
e80e655b01
commit
fddeb59911
2 changed files with 23 additions and 1 deletions
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue