Skip to content

Commit

Permalink
net: lwm2m: Make CoAP pendings/replies arrays access thread safe
Browse files Browse the repository at this point in the history
Make sure LwM2M context mutex is locked whenever accessing CoAP
pendings/replies arrays.

Signed-off-by: Robert Lubos <[email protected]>
  • Loading branch information
rlubos committed Oct 15, 2024
1 parent b05daa1 commit 4e58586
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 16 deletions.
4 changes: 4 additions & 0 deletions subsys/net/lib/lwm2m/lwm2m_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ static int64_t retransmit_request(struct lwm2m_ctx *client_ctx, const int64_t ti
int64_t remaining, next = INT64_MAX;
int i;

lwm2m_client_lock(client_ctx);

for (i = 0, p = client_ctx->pendings; i < ARRAY_SIZE(client_ctx->pendings); i++, p++) {
if (!p->timeout) {
continue;
Expand Down Expand Up @@ -406,6 +408,8 @@ static int64_t retransmit_request(struct lwm2m_ctx *client_ctx, const int64_t ti
}
}

lwm2m_client_unlock(client_ctx);

return next;
}
static int64_t engine_next_service_timestamp(void)
Expand Down
55 changes: 39 additions & 16 deletions subsys/net/lib/lwm2m/lwm2m_message_handling.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ void lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx)
struct observe_node *obs;
size_t i;

lwm2m_client_lock(client_ctx);

/* Remove observes for this context */
while (!sys_slist_is_empty(&client_ctx->observer)) {
obs_node = sys_slist_get_not_empty(&client_ctx->observer);
Expand All @@ -466,11 +468,11 @@ void lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx)
coap_pendings_clear(client_ctx->pendings, ARRAY_SIZE(client_ctx->pendings));
coap_replies_clear(client_ctx->replies, ARRAY_SIZE(client_ctx->replies));


client_ctx->connection_suspended = false;
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
client_ctx->buffer_client_messages = true;
#endif
lwm2m_client_unlock(client_ctx);
}

void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx)
Expand Down Expand Up @@ -663,20 +665,22 @@ int lwm2m_init_message(struct lwm2m_message *msg)
return 0;
}

lwm2m_client_lock(msg->ctx);

msg->pending = coap_pending_next_unused(msg->ctx->pendings, ARRAY_SIZE(msg->ctx->pendings));
if (!msg->pending) {
LOG_ERR("Unable to find a free pending to track "
"retransmissions.");
r = -ENOMEM;
goto cleanup;
goto cleanup_unlock;
}

r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr, NULL);
if (r < 0) {
LOG_ERR("Unable to initialize a pending "
"retransmission (err:%d).",
r);
goto cleanup;
goto cleanup_unlock;
}

if (msg->reply_cb) {
Expand All @@ -685,16 +689,20 @@ int lwm2m_init_message(struct lwm2m_message *msg)
if (!msg->reply) {
LOG_ERR("No resources for waiting for replies.");
r = -ENOMEM;
goto cleanup;
goto cleanup_unlock;
}

coap_reply_clear(msg->reply);
coap_reply_init(msg->reply, &msg->cpkt);
msg->reply->reply = msg->reply_cb;
}

lwm2m_client_unlock(msg->ctx);

return 0;

cleanup_unlock:
lwm2m_client_unlock(msg->ctx);
cleanup:
lwm2m_reset_message(msg, true);

Expand Down Expand Up @@ -2645,11 +2653,14 @@ static int lwm2m_response_promote_to_con(struct lwm2m_message *msg)
coap_pending_clear(msg->pending);
}

lwm2m_client_lock(msg->ctx);

/* Add the packet to the pending list. */
msg->pending = coap_pending_next_unused(msg->ctx->pendings, ARRAY_SIZE(msg->ctx->pendings));
if (!msg->pending) {
LOG_ERR("Unable to find a free pending to track "
"retransmissions.");
lwm2m_client_unlock(msg->ctx);
return -ENOMEM;
}

Expand All @@ -2660,6 +2671,8 @@ static int lwm2m_response_promote_to_con(struct lwm2m_message *msg)
ret);
}

lwm2m_client_unlock(msg->ctx);

return ret;
}

Expand Down Expand Up @@ -2738,22 +2751,25 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
}

has_block2 = coap_get_option_int(&response, COAP_OPTION_BLOCK2) > 0 ? true : false;

lwm2m_client_lock(client_ctx);

pending = coap_pending_received(&response, client_ctx->pendings,
ARRAY_SIZE(client_ctx->pendings));
if (pending && coap_header_get_type(&response) == COAP_TYPE_ACK) {
msg = find_msg(pending, NULL);
if (msg == NULL) {
LOG_DBG("Orphaned pending %p.", pending);
coap_pending_clear(pending);
return;
goto client_unlock;
}

msg->acknowledged = true;

if (msg->reply == NULL) {
/* No response expected, release the message. */
lwm2m_reset_message(msg, true);
return;
goto client_unlock;
}

/* If the original message was a request and an empty
Expand All @@ -2762,7 +2778,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
if ((msg->code >= COAP_METHOD_GET) && (msg->code <= COAP_METHOD_DELETE) &&
(coap_header_get_code(&response) == COAP_CODE_EMPTY)) {
LOG_DBG("Empty ACK, expect separate response.");
return;
goto client_unlock;
}
}

Expand All @@ -2784,7 +2800,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
r = coap_get_block1_option(&response, &more_blocks, &block_num);
if (r < 0) {
LOG_ERR("Missing block1 option in response with continue");
return;
goto client_unlock;
}

enum coap_block_size block_size = coap_bytes_to_block_size(r);
Expand All @@ -2796,36 +2812,36 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
if (!more_blocks) {
lwm2m_reset_message(msg, true);
LOG_ERR("Missing more flag in response with continue");
return;
goto client_unlock;
}

last_block_num = msg->out.block_ctx->current /
coap_block_size_to_bytes(block_size);
if (last_block_num > block_num) {
LOG_INF("Block already sent: ignore");
return;
goto client_unlock;
} else if (last_block_num < block_num) {
LOG_WRN("Requested block out of order");
return;
goto client_unlock;
}

r = build_msg_block_for_send(msg, block_num + 1, block_size);
if (r < 0) {
lwm2m_reset_message(msg, true);
LOG_ERR("Unable to build next block of lwm2m message!");
return;
goto client_unlock;
}

r = lwm2m_send_message_async(msg);
if (r < 0) {
lwm2m_reset_message(msg, true);
LOG_ERR("Unable to send next block of lwm2m message!");
return;
goto client_unlock;
}

/* skip release as message was reused for new block */
LOG_DBG("Block # %d sent", block_num + 1);
return;
goto client_unlock;
}
#endif

Expand All @@ -2834,7 +2850,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
/* reset reply->user_data for next time */
reply->user_data = (void *)COAP_REPLY_STATUS_NONE;
LOG_DBG("reply %p NOT removed", reply);
return;
goto client_unlock;
}

/* free up msg resources */
Expand All @@ -2843,9 +2859,11 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
}

LOG_DBG("reply %p handled and removed", reply);
return;
goto client_unlock;
}

lwm2m_client_unlock(client_ctx);

if (coap_header_get_type(&response) == COAP_TYPE_CON) {
if (has_block2 && IS_ENABLED(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)) {
msg = find_ongoing_block2_tx();
Expand Down Expand Up @@ -2895,6 +2913,11 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_
} else {
LOG_DBG("No handler for response");
}

return;

client_unlock:
lwm2m_client_unlock(client_ctx);
}

static void notify_message_timeout_cb(struct lwm2m_message *msg)
Expand Down

0 comments on commit 4e58586

Please sign in to comment.