From faa1a8c0160ecab0ddd9f3bd43fa347b0837f379 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 11 Oct 2024 17:15:04 +0200 Subject: [PATCH 1/4] net: lwm2m: Make LwM2M message allocation thread safe The LwM2M message allocation was not thread safe, i. e. the message was acquired by setting the ctx pointer, and it was freed by clearing the entire message structure. If preemptive threads were enabled, and memset() clearing the message content was preempted, the message structure being currently zeroed migh've been allocated and initialized by some other thread. If the thread releasing the message resumed work, it would continue clearing the freshly allocated and initialized message structure. In order to prevent this, introduce a new global mutex for the lwm2m engine global variables. The mutex is used when LwM2M message is allocated/deallocated. This will prevent reallocating the message during the release process. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 12 ++++++++++++ subsys/net/lib/lwm2m/lwm2m_engine.h | 10 ++++++++++ subsys/net/lib/lwm2m/lwm2m_message_handling.c | 12 ++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index be61fc46bdbd0c..383612d7e42c41 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -96,6 +96,8 @@ static sys_slist_t engine_service_list; static K_KERNEL_STACK_DEFINE(engine_thread_stack, CONFIG_LWM2M_ENGINE_STACK_SIZE); static struct k_thread engine_thread_data; +static K_MUTEX_DEFINE(engine_lock); + #define MAX_POLL_FD CONFIG_ZVFS_POLL_MAX /* Resources */ @@ -1285,6 +1287,16 @@ int lwm2m_engine_resume(void) return 0; } +void lwm2m_engine_lock(void) +{ + (void)k_mutex_lock(&engine_lock, K_FOREVER); +} + +void lwm2m_engine_unlock(void) +{ + k_mutex_unlock(&engine_lock); +} + static int lwm2m_engine_init(void) { for (int i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) { diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 58f3e1a128acf3..3581a3ddfbfa58 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -375,4 +375,14 @@ int lwm2m_sock_nfds(void); */ void lwm2m_engine_wake_up(void); +/** + * @brief Locks the access to shared LwM2M engine variables. + */ +void lwm2m_engine_lock(void); + +/** + * @brief Unlocks the access to shared LwM2M engine variables. + */ +void lwm2m_engine_unlock(void); + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index ac765aa0fc6716..1c8381bfe591d9 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -519,16 +519,22 @@ struct lwm2m_message *find_msg(struct coap_pending *pending, struct coap_reply * struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx) { + struct lwm2m_message *msg = NULL; size_t i; + lwm2m_engine_lock(); + for (i = 0; i < CONFIG_LWM2M_ENGINE_MAX_MESSAGES; i++) { if (!messages[i].ctx) { messages[i].ctx = client_ctx; - return &messages[i]; + msg = &messages[i]; + break; } } - return NULL; + lwm2m_engine_unlock(); + + return msg; } void lm2m_message_clear_allocations(struct lwm2m_message *msg) @@ -561,11 +567,13 @@ void lwm2m_reset_message(struct lwm2m_message *msg, bool release) } if (release) { + lwm2m_engine_lock(); #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) release_output_block_ctx(&msg->out.block_ctx); release_body_encode_buffer(&msg->body_encode_buffer.data); #endif (void)memset(msg, 0, sizeof(*msg)); + lwm2m_engine_unlock(); } else { msg->message_timeout_cb = NULL; (void)memset(&msg->cpkt, 0, sizeof(msg->cpkt)); From a124f04c0ed2f015d5341c5434e469548ce40b10 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 15 Oct 2024 15:58:07 +0200 Subject: [PATCH 2/4] net: lwm2m: Make CoAP block contetx allocation thread safe Use global engine mutex to protect allocation/deallocation of the CoAP block contexts. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 2 ++ subsys/net/lib/lwm2m/lwm2m_message_handling.c | 26 ++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 383612d7e42c41..90f215e79564bf 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1338,7 +1338,9 @@ static int lwm2m_engine_init(void) lwm2m_clear_block_contexts(); #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) + lwm2m_engine_lock(); (void)memset(output_block_contexts, 0, sizeof(output_block_contexts)); + lwm2m_engine_unlock(); #endif STRUCT_SECTION_FOREACH(lwm2m_init_func, init) { diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 1c8381bfe591d9..810679e66b043d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -117,7 +117,9 @@ enum coap_block_size lwm2m_default_block_size(void) void lwm2m_clear_block_contexts(void) { + lwm2m_engine_lock(); (void)memset(block1_contexts, 0, sizeof(block1_contexts)); + lwm2m_engine_unlock(); } static int init_block_ctx(const struct lwm2m_obj_path *path, struct lwm2m_block_context **ctx) @@ -130,6 +132,8 @@ static int init_block_ctx(const struct lwm2m_obj_path *path, struct lwm2m_block_ return -EFAULT; } + lwm2m_engine_lock(); + *ctx = NULL; timestamp = k_uptime_get(); for (i = 0; i < NUM_BLOCK1_CONTEXT; i++) { @@ -149,6 +153,7 @@ static int init_block_ctx(const struct lwm2m_obj_path *path, struct lwm2m_block_ } if (*ctx == NULL) { + lwm2m_engine_unlock(); LOG_ERR("Cannot find free block context"); return -ENOMEM; } @@ -160,6 +165,8 @@ static int init_block_ctx(const struct lwm2m_obj_path *path, struct lwm2m_block_ (*ctx)->last_block = false; memset(&(*ctx)->opaque, 0, sizeof((*ctx)->opaque)); + lwm2m_engine_unlock(); + return 0; } @@ -174,6 +181,8 @@ static int get_block_ctx(const struct lwm2m_obj_path *path, struct lwm2m_block_c *ctx = NULL; + lwm2m_engine_lock(); + for (i = 0; i < NUM_BLOCK1_CONTEXT; i++) { if (lwm2m_obj_path_equal(path, &block1_contexts[i].path)) { *ctx = &block1_contexts[i]; @@ -183,6 +192,8 @@ static int get_block_ctx(const struct lwm2m_obj_path *path, struct lwm2m_block_c } } + lwm2m_engine_unlock(); + if (*ctx == NULL) { return -ENOENT; } @@ -196,24 +207,31 @@ static void free_block_ctx(struct lwm2m_block_context *ctx) return; } + lwm2m_engine_lock(); memset(&ctx->path, 0, sizeof(struct lwm2m_obj_path)); + lwm2m_engine_unlock(); } #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER) STATIC int request_output_block_ctx(struct coap_block_context **ctx) { - *ctx = NULL; + int ret = -ENOMEM; int i; + *ctx = NULL; + + lwm2m_engine_lock(); for (i = 0; i < NUM_OUTPUT_BLOCK_CONTEXT; i++) { if (lwm2m_output_block_context()[i].block_size == 0) { *ctx = &lwm2m_output_block_context()[i]; (*ctx)->block_size = OUTPUT_CONTEXT_IN_USE_MARK; - return 0; + ret = 0; + break; } } + lwm2m_engine_unlock(); - return -ENOMEM; + return ret; } STATIC void release_output_block_ctx(struct coap_block_context **ctx) @@ -224,12 +242,14 @@ STATIC void release_output_block_ctx(struct coap_block_context **ctx) return; } + lwm2m_engine_lock(); for (i = 0; i < NUM_OUTPUT_BLOCK_CONTEXT; i++) { if (&lwm2m_output_block_context()[i] == *ctx) { lwm2m_output_block_context()[i].block_size = 0; *ctx = NULL; } } + lwm2m_engine_unlock(); } From b05daa15a174c2810a95a77a5b5e80dd57a1c271 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 14 Oct 2024 17:52:53 +0200 Subject: [PATCH 3/4] net: lwm2m: Make LwM2M context lists access thread safe System lists are not thread safe, therefore all accesses should be protected with a mutex. Introduce a LwM2M context specific mutex, and use it whenever lists defined per-context are acessed. Signed-off-by: Robert Lubos --- include/zephyr/net/lwm2m.h | 1 + subsys/net/lib/lwm2m/lwm2m_engine.c | 52 +++++++++++++++---- subsys/net/lib/lwm2m/lwm2m_engine.h | 14 +++++ subsys/net/lib/lwm2m/lwm2m_message_handling.c | 10 ++++ 4 files changed, 68 insertions(+), 9 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 8a2cbf557d0d48..9c4590a276790b 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -217,6 +217,7 @@ struct lwm2m_ctx { sys_slist_t queued_messages; #endif sys_slist_t observer; + struct k_mutex lock; /** @endcond */ /** A pointer to currently processed request, for internal LwM2M engine diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 90f215e79564bf..af4c996f57515a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -234,6 +234,7 @@ int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx) { #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) client_ctx->buffer_client_messages = false; + lwm2m_client_lock(client_ctx); while (!sys_slist_is_empty(&client_ctx->queued_messages)) { sys_snode_t *msg_node = sys_slist_get(&client_ctx->queued_messages); struct lwm2m_message *msg; @@ -245,6 +246,7 @@ int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx) msg->pending->t0 = k_uptime_get(); sys_slist_append(&msg->ctx->pending_sends, &msg->node); } + lwm2m_client_unlock(client_ctx); #endif return 0; } @@ -643,17 +645,22 @@ static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestam */ static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoing_tx) { + bool empty; + size_t pendings; + if (!ctx || !ctx->set_socket_state) { return; } + lwm2m_client_lock(ctx); #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - bool empty = sys_slist_is_empty(&ctx->pending_sends) && - sys_slist_is_empty(&ctx->queued_messages); + empty = sys_slist_is_empty(&ctx->pending_sends) && + sys_slist_is_empty(&ctx->queued_messages); #else - bool empty = sys_slist_is_empty(&ctx->pending_sends); + empty = sys_slist_is_empty(&ctx->pending_sends); #endif - size_t pendings = coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)); + pendings = coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)); + lwm2m_client_unlock(ctx); if (ongoing_tx) { /* Check if more than current TX is in pendings list*/ @@ -712,9 +719,13 @@ static int socket_recv_message(struct lwm2m_ctx *client_ctx) static int socket_send_message(struct lwm2m_ctx *ctx) { int rc; - sys_snode_t *msg_node = sys_slist_get(&ctx->pending_sends); + sys_snode_t *msg_node; struct lwm2m_message *msg; + lwm2m_client_lock(ctx); + msg_node = sys_slist_get(&ctx->pending_sends); + lwm2m_client_unlock(ctx); + if (!msg_node) { return 0; } @@ -752,11 +763,17 @@ static int socket_send_message(struct lwm2m_ctx *ctx) static void socket_reset_pollfd_events(void) { for (int i = 0; i < MAX_POLL_FD; ++i) { + bool set_pollout = false; + + if (sock_ctx[i] != NULL) { + lwm2m_client_lock(sock_ctx[i]); + set_pollout = !sys_slist_is_empty(&sock_ctx[i]->pending_sends); + lwm2m_client_unlock(sock_ctx[i]); + } + sock_fds[i].events = ZSOCK_POLLIN | - (!sock_ctx[i] || sys_slist_is_empty(&sock_ctx[i]->pending_sends) - ? 0 - : ZSOCK_POLLOUT); + (set_pollout ? ZSOCK_POLLOUT : 0); sock_fds[i].revents = 0; } } @@ -802,13 +819,20 @@ static void socket_loop(void *p1, void *p2, void *p3) for (i = 0; i < sock_nfds; ++i) { struct lwm2m_ctx *ctx = sock_ctx[i]; + bool is_empty; if (ctx == NULL) { continue; } - if (!sys_slist_is_empty(&ctx->pending_sends)) { + + lwm2m_client_lock(ctx); + is_empty = sys_slist_is_empty(&ctx->pending_sends); + lwm2m_client_unlock(ctx); + + if (!is_empty) { continue; } + next_tx = retransmit_request(ctx, now); if (next_tx < next) { next = next_tx; @@ -1297,6 +1321,16 @@ void lwm2m_engine_unlock(void) k_mutex_unlock(&engine_lock); } +void lwm2m_client_lock(struct lwm2m_ctx *ctx) +{ + (void)k_mutex_lock(&ctx->lock, K_FOREVER); +} + +void lwm2m_client_unlock(struct lwm2m_ctx *ctx) +{ + k_mutex_unlock(&ctx->lock); +} + static int lwm2m_engine_init(void) { for (int i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) { diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 3581a3ddfbfa58..3cf855e05800da 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -385,4 +385,18 @@ void lwm2m_engine_lock(void); */ void lwm2m_engine_unlock(void); +/** + * @brief Locks the client. + * + * @param[in] client_ctx LwM2M context + */ +void lwm2m_client_lock(struct lwm2m_ctx *ctx); + +/** + * @brief Unlocks the client previously locked by lwm2m_client_lock(). + * + * @param[in] client_ctx LwM2M context + */ +void lwm2m_client_unlock(struct lwm2m_ctx *ctx); + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 810679e66b043d..2ef01cd96cdcab 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -482,6 +482,7 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) client_ctx->buffer_client_messages = true; sys_slist_init(&client_ctx->queued_messages); #endif + k_mutex_init(&client_ctx->lock); } /* utility functions */ @@ -580,10 +581,12 @@ void lwm2m_reset_message(struct lwm2m_message *msg, bool release) lm2m_message_clear_allocations(msg); if (msg->ctx) { + lwm2m_client_lock(msg->ctx); sys_slist_find_and_remove(&msg->ctx->pending_sends, &msg->node); #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) sys_slist_find_and_remove(&msg->ctx->queued_messages, &msg->node); #endif + lwm2m_client_unlock(msg->ctx); } if (release) { @@ -720,7 +723,10 @@ int lwm2m_send_message_async(struct lwm2m_message *msg) return ret; } } + + lwm2m_client_lock(msg->ctx); sys_slist_append(&msg->ctx->pending_sends, &msg->node); + lwm2m_client_unlock(msg->ctx); if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { engine_update_tx_time(); @@ -741,14 +747,18 @@ int lwm2m_information_interface_send(struct lwm2m_message *msg) } if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_NO_MSG_BUFFERING)) { + lwm2m_client_lock(msg->ctx); sys_slist_append(&msg->ctx->pending_sends, &msg->node); + lwm2m_client_unlock(msg->ctx); lwm2m_engine_wake_up(); lwm2m_engine_connection_resume(msg->ctx); return 0; } if (msg->ctx->buffer_client_messages) { + lwm2m_client_lock(msg->ctx); sys_slist_append(&msg->ctx->queued_messages, &msg->node); + lwm2m_client_unlock(msg->ctx); lwm2m_engine_wake_up(); return 0; } From 4e58586be330d7d0a9797424b73a789f67111c2e Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Tue, 15 Oct 2024 15:41:57 +0200 Subject: [PATCH 4/4] net: lwm2m: Make CoAP pendings/replies arrays access thread safe Make sure LwM2M context mutex is locked whenever accessing CoAP pendings/replies arrays. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 4 ++ subsys/net/lib/lwm2m/lwm2m_message_handling.c | 55 +++++++++++++------ 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index af4c996f57515a..f5a845b9a8f9b3 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -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; @@ -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) diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index 2ef01cd96cdcab..8d2369e46f2935 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -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); @@ -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) @@ -663,12 +665,14 @@ 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); @@ -676,7 +680,7 @@ int lwm2m_init_message(struct lwm2m_message *msg) LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", r); - goto cleanup; + goto cleanup_unlock; } if (msg->reply_cb) { @@ -685,7 +689,7 @@ 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); @@ -693,8 +697,12 @@ int lwm2m_init_message(struct lwm2m_message *msg) 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); @@ -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; } @@ -2660,6 +2671,8 @@ static int lwm2m_response_promote_to_con(struct lwm2m_message *msg) ret); } + lwm2m_client_unlock(msg->ctx); + return ret; } @@ -2738,6 +2751,9 @@ 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) { @@ -2745,7 +2761,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ if (msg == NULL) { LOG_DBG("Orphaned pending %p.", pending); coap_pending_clear(pending); - return; + goto client_unlock; } msg->acknowledged = true; @@ -2753,7 +2769,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, uint8_t *buf, uint16_t buf_ 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 @@ -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; } } @@ -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); @@ -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 @@ -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 */ @@ -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(); @@ -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)