1 /*
2 * Copyright (c) 2017 Linaro Limited
3 * Copyright (c) 2018-2019 Foundries.io
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * Uses some original concepts by:
10 * Joakim Eriksson <joakime@sics.se>
11 * Niclas Finne <nfi@sics.se>
12 * Joel Hoglund <joel@sics.se>
13 */
14
15 #define LOG_MODULE_NAME net_lwm2m_engine
16 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
17
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <zephyr/init.h>
29 #include <zephyr/net/http/parser_url.h>
30 #include <zephyr/net/lwm2m.h>
31 #include <zephyr/net/net_ip.h>
32 #include <zephyr/net/socket.h>
33 #include <zephyr/sys/printk.h>
34 #include <zephyr/types.h>
35 #include <zephyr/posix/fcntl.h>
36 #include <zephyr/zvfs/eventfd.h>
37
38 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
39 #include <zephyr/net/tls_credentials.h>
40 #include <mbedtls/ssl_ciphersuites.h>
41 #endif
42 #if defined(CONFIG_DNS_RESOLVER)
43 #include <zephyr/net/dns_resolve.h>
44 #endif
45
46 #include "lwm2m_engine.h"
47 #include "lwm2m_object.h"
48 #include "lwm2m_rw_link_format.h"
49 #include "lwm2m_rw_oma_tlv.h"
50 #include "lwm2m_rw_plain_text.h"
51 #include "lwm2m_util.h"
52 #include "lwm2m_rd_client.h"
53 #if defined(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)
54 #include "lwm2m_rw_senml_json.h"
55 #endif
56 #ifdef CONFIG_LWM2M_RW_JSON_SUPPORT
57 #include "lwm2m_rw_json.h"
58 #endif
59 #ifdef CONFIG_LWM2M_RW_CBOR_SUPPORT
60 #include "lwm2m_rw_cbor.h"
61 #endif
62 #ifdef CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT
63 #include "lwm2m_rw_senml_cbor.h"
64 #endif
65
66 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
67 /* Lowest priority cooperative thread */
68 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
69 #else
70 #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1)
71 #endif
72
73 #define ENGINE_SLEEP_MS 500
74 #define NOTIFY_DELAY_MS 100
75
76 #ifdef CONFIG_LWM2M_VERSION_1_1
77 #define LWM2M_ENGINE_MAX_OBSERVER_PATH CONFIG_LWM2M_ENGINE_MAX_OBSERVER * 3
78 #else
79 #define LWM2M_ENGINE_MAX_OBSERVER_PATH CONFIG_LWM2M_ENGINE_MAX_OBSERVER
80 #endif
81 static struct lwm2m_obj_path_list observe_paths[LWM2M_ENGINE_MAX_OBSERVER_PATH];
82 #define MAX_PERIODIC_SERVICE 10
83
84 static k_tid_t engine_thread_id;
85 static bool suspend_engine_thread;
86 static bool active_engine_thread;
87
88 struct service_node {
89 sys_snode_t node;
90 k_work_handler_t service_work;
91 uint32_t call_period; /* ms */
92 int64_t next_timestamp; /* ms */
93 };
94
95 static struct service_node service_node_data[MAX_PERIODIC_SERVICE];
96 static sys_slist_t engine_service_list;
97
98 static K_KERNEL_STACK_DEFINE(engine_thread_stack, CONFIG_LWM2M_ENGINE_STACK_SIZE);
99 static struct k_thread engine_thread_data;
100
101 static K_MUTEX_DEFINE(engine_lock);
102
103 #define MAX_POLL_FD CONFIG_ZVFS_POLL_MAX
104
105 /* Resources */
106 static struct zsock_pollfd sock_fds[MAX_POLL_FD];
107
108 static struct lwm2m_ctx *sock_ctx[MAX_POLL_FD];
109 static int sock_nfds;
110
111 /* Resource wrappers */
112 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
113 static struct coap_block_context output_block_contexts[NUM_OUTPUT_BLOCK_CONTEXT];
114 #endif
115
116 /* Resource wrappers */
lwm2m_sock_ctx(void)117 struct lwm2m_ctx **lwm2m_sock_ctx(void) { return sock_ctx; }
118
lwm2m_sock_nfds(void)119 int lwm2m_sock_nfds(void) { return sock_nfds; }
120
121 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
lwm2m_output_block_context(void)122 struct coap_block_context *lwm2m_output_block_context(void) { return output_block_contexts; }
123 #endif
124
125 static int lwm2m_socket_update(struct lwm2m_ctx *ctx);
126
127 /* utility functions */
128
lwm2m_engine_wake_up(void)129 void lwm2m_engine_wake_up(void)
130 {
131 if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) {
132 zvfs_eventfd_write(sock_fds[MAX_POLL_FD - 1].fd, 1);
133 }
134 }
135
lwm2m_open_socket(struct lwm2m_ctx * client_ctx)136 int lwm2m_open_socket(struct lwm2m_ctx *client_ctx)
137 {
138 if (client_ctx->sock_fd < 0) {
139 /* open socket */
140
141 if (IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) && client_ctx->use_dtls) {
142 client_ctx->sock_fd = zsock_socket(client_ctx->remote_addr.sa_family,
143 SOCK_DGRAM, IPPROTO_DTLS_1_2);
144 } else {
145 client_ctx->sock_fd =
146 zsock_socket(client_ctx->remote_addr.sa_family, SOCK_DGRAM,
147 IPPROTO_UDP);
148 }
149
150 if (client_ctx->sock_fd < 0) {
151 LOG_ERR("Failed to create socket: %d", errno);
152 return -errno;
153 }
154
155 if (lwm2m_socket_update(client_ctx)) {
156 return lwm2m_socket_add(client_ctx);
157 }
158 }
159
160 return 0;
161 }
162
lwm2m_close_socket(struct lwm2m_ctx * client_ctx)163 int lwm2m_close_socket(struct lwm2m_ctx *client_ctx)
164 {
165 if (client_ctx->sock_fd >= 0) {
166 int ret = zsock_close(client_ctx->sock_fd);
167
168 if (ret) {
169 LOG_ERR("Failed to close socket: %d", errno);
170 ret = -errno;
171 return ret;
172 }
173 }
174
175 client_ctx->sock_fd = -1;
176 client_ctx->connection_suspended = true;
177 #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
178 /* Enable Queue mode buffer store */
179 client_ctx->buffer_client_messages = true;
180 #endif
181 lwm2m_socket_update(client_ctx);
182
183 return 0;
184 }
185
lwm2m_socket_suspend(struct lwm2m_ctx * client_ctx)186 int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx)
187 {
188 int ret = 0;
189
190 if (client_ctx->sock_fd >= 0 && !client_ctx->connection_suspended) {
191 int socket_temp_id = client_ctx->sock_fd;
192
193 /* Prevent closing */
194 client_ctx->sock_fd = -1;
195 /* Just mark as suspended */
196 lwm2m_close_socket(client_ctx);
197 /* store back the socket handle */
198 client_ctx->sock_fd = socket_temp_id;
199
200 if (client_ctx->set_socket_state) {
201 client_ctx->set_socket_state(client_ctx->sock_fd,
202 LWM2M_SOCKET_STATE_NO_DATA);
203 }
204 }
205
206 return ret;
207 }
208
lwm2m_engine_connection_resume(struct lwm2m_ctx * client_ctx)209 int lwm2m_engine_connection_resume(struct lwm2m_ctx *client_ctx)
210 {
211 int ret;
212
213 if (client_ctx->connection_suspended) {
214 if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE) ||
215 IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE)) {
216 LOG_DBG("Resume suspended connection");
217 lwm2m_socket_update(client_ctx);
218 client_ctx->connection_suspended = false;
219 } else {
220 LOG_DBG("Close and resume a new connection");
221 lwm2m_close_socket(client_ctx);
222 ret = lwm2m_open_socket(client_ctx);
223 if (ret) {
224 return ret;
225 }
226 client_ctx->connection_suspended = false;
227 return lwm2m_socket_start(client_ctx);
228 }
229 }
230
231 return 0;
232 }
233
lwm2m_push_queued_buffers(struct lwm2m_ctx * client_ctx)234 int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx)
235 {
236 #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
237 client_ctx->buffer_client_messages = false;
238 lwm2m_client_lock(client_ctx);
239 while (!sys_slist_is_empty(&client_ctx->queued_messages)) {
240 sys_snode_t *msg_node = sys_slist_get(&client_ctx->queued_messages);
241 struct lwm2m_message *msg;
242
243 if (!msg_node) {
244 break;
245 }
246 msg = SYS_SLIST_CONTAINER(msg_node, msg, node);
247 msg->pending->t0 = k_uptime_get();
248 sys_slist_append(&msg->ctx->pending_sends, &msg->node);
249 }
250 lwm2m_client_unlock(client_ctx);
251 #endif
252 return 0;
253 }
254
lwm2m_engine_bootstrap_override(struct lwm2m_ctx * client_ctx,struct lwm2m_obj_path * path)255 bool lwm2m_engine_bootstrap_override(struct lwm2m_ctx *client_ctx, struct lwm2m_obj_path *path)
256 {
257 if (!client_ctx->bootstrap_mode) {
258 /* Bootstrap is not active override is not possible then */
259 return false;
260 }
261
262 if (path->obj_id == LWM2M_OBJECT_SECURITY_ID || path->obj_id == LWM2M_OBJECT_SERVER_ID) {
263 /* Bootstrap server have a access to Security and Server object */
264 return true;
265 }
266
267 return false;
268 }
269
lwm2m_engine_validate_write_access(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst * obj_inst,struct lwm2m_engine_obj_field ** obj_field)270 int lwm2m_engine_validate_write_access(struct lwm2m_message *msg,
271 struct lwm2m_engine_obj_inst *obj_inst,
272 struct lwm2m_engine_obj_field **obj_field)
273 {
274 struct lwm2m_engine_obj_field *o_f;
275
276 o_f = lwm2m_get_engine_obj_field(obj_inst->obj, msg->path.res_id);
277 if (!o_f) {
278 return -ENOENT;
279 }
280
281 *obj_field = o_f;
282
283 if (!LWM2M_HAS_PERM(o_f, LWM2M_PERM_W) &&
284 !lwm2m_engine_bootstrap_override(msg->ctx, &msg->path)) {
285 return -EPERM;
286 }
287
288 if (!obj_inst->resources || obj_inst->resource_count == 0U) {
289 return -EINVAL;
290 }
291
292 return 0;
293 }
294
295 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
bootstrap_delete_allowed(int obj_id,int obj_inst_id)296 static bool bootstrap_delete_allowed(int obj_id, int obj_inst_id)
297 {
298 bool bootstrap_server;
299 int ret;
300
301 if (obj_id == LWM2M_OBJECT_SECURITY_ID) {
302 ret = lwm2m_get_bool(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, obj_inst_id, 1),
303 &bootstrap_server);
304 if (ret < 0) {
305 return false;
306 }
307
308 if (bootstrap_server) {
309 return false;
310 }
311 }
312
313 if (obj_id == LWM2M_OBJECT_DEVICE_ID) {
314 return false;
315 }
316
317 return true;
318 }
319
bootstrap_delete(struct lwm2m_message * msg)320 int bootstrap_delete(struct lwm2m_message *msg)
321 {
322 struct lwm2m_engine_obj_inst *obj_inst, *tmp;
323 int ret = 0;
324 sys_slist_t *engine_obj_inst_list = lwm2m_engine_obj_inst_list();
325
326 if (msg->path.level > 2) {
327 return -EPERM;
328 }
329
330 if (msg->path.level == 2) {
331 if (!bootstrap_delete_allowed(msg->path.obj_id, msg->path.obj_inst_id)) {
332 return -EPERM;
333 }
334
335 return lwm2m_delete_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
336 }
337
338 /* DELETE all instances of a specific object or all object instances if
339 * not specified, excluding the following exceptions (according to the
340 * LwM2M specification v1.0.2, ch 5.2.7.5):
341 * - LwM2M Bootstrap-Server Account (Bootstrap Security object, ID 0)
342 * - Device object (ID 3)
343 */
344 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(engine_obj_inst_list, obj_inst, tmp, node) {
345 if (msg->path.level == 1 && obj_inst->obj->obj_id != msg->path.obj_id) {
346 continue;
347 }
348
349 if (!bootstrap_delete_allowed(obj_inst->obj->obj_id, obj_inst->obj_inst_id)) {
350 continue;
351 }
352
353 ret = lwm2m_delete_obj_inst(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
354 if (ret < 0) {
355 return ret;
356 }
357 }
358
359 return ret;
360 }
361 #endif
362
363 /* returns timestamp when next retransmission is due, or INT64_MAX
364 * if no retransmissions are necessary
365 */
retransmit_request(struct lwm2m_ctx * client_ctx,const int64_t timestamp)366 static int64_t retransmit_request(struct lwm2m_ctx *client_ctx, const int64_t timestamp)
367 {
368 struct lwm2m_message *msg;
369 struct coap_pending *p;
370 int64_t remaining, next = INT64_MAX;
371 int i;
372
373 lwm2m_client_lock(client_ctx);
374
375 for (i = 0, p = client_ctx->pendings; i < ARRAY_SIZE(client_ctx->pendings); i++, p++) {
376 if (!p->timeout) {
377 continue;
378 }
379
380 remaining = p->t0 + p->timeout;
381 if (remaining < timestamp) {
382 msg = find_msg(p, NULL);
383 if (!msg) {
384 LOG_ERR("pending has no valid LwM2M message!");
385 coap_pending_clear(p);
386 continue;
387 }
388 if (!p->retries) {
389 /* pending request has expired */
390 if (msg->message_timeout_cb) {
391 msg->message_timeout_cb(msg);
392 }
393 lwm2m_reset_message(msg, true);
394 continue;
395 }
396 if (msg->acknowledged) {
397 /* No need to retransmit, just keep the timer running to
398 * timeout in case no response arrives.
399 */
400 coap_pending_cycle(p);
401 continue;
402 }
403
404 lwm2m_send_message_async(msg);
405 break;
406 }
407 if (remaining < next) {
408 next = remaining;
409 }
410 }
411
412 lwm2m_client_unlock(client_ctx);
413
414 return next;
415 }
engine_next_service_timestamp(void)416 static int64_t engine_next_service_timestamp(void)
417 {
418 struct service_node *srv;
419 int64_t next = INT64_MAX;
420
421 SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) {
422 if (srv->next_timestamp < next) {
423 next = srv->next_timestamp;
424 }
425 }
426
427 return next;
428 }
429
engine_add_srv(k_work_handler_t service,uint32_t period_ms,int64_t next)430 static int engine_add_srv(k_work_handler_t service, uint32_t period_ms, int64_t next)
431 {
432 int i;
433
434 if (!service) {
435 return -EINVAL;
436 }
437
438 /* First, try if the service is already registered, and modify it*/
439 if (lwm2m_engine_update_service_period(service, period_ms) == 0) {
440 return 0;
441 }
442
443 /* find an unused service index node */
444 for (i = 0; i < MAX_PERIODIC_SERVICE; i++) {
445 if (!service_node_data[i].service_work) {
446 break;
447 }
448 }
449
450 if (i == MAX_PERIODIC_SERVICE) {
451 return -ENOMEM;
452 }
453
454 service_node_data[i].service_work = service;
455 service_node_data[i].call_period = period_ms;
456 service_node_data[i].next_timestamp = next;
457
458 sys_slist_append(&engine_service_list, &service_node_data[i].node);
459
460 lwm2m_engine_wake_up();
461
462 return 0;
463 }
464
lwm2m_engine_add_service(k_work_handler_t service,uint32_t period_ms)465 int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms)
466 {
467 return engine_add_srv(service, period_ms, k_uptime_get() + period_ms);
468 }
469
lwm2m_engine_call_at(k_work_handler_t service,int64_t timestamp)470 int lwm2m_engine_call_at(k_work_handler_t service, int64_t timestamp)
471 {
472 return engine_add_srv(service, 0, timestamp);
473 }
474
lwm2m_engine_call_now(k_work_handler_t service)475 int lwm2m_engine_call_now(k_work_handler_t service)
476 {
477 return engine_add_srv(service, 0, k_uptime_get());
478 }
479
lwm2m_engine_update_service_period(k_work_handler_t service,uint32_t period_ms)480 int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms)
481 {
482 int i = 0;
483
484 for (i = 0; i < MAX_PERIODIC_SERVICE; i++) {
485 if (service_node_data[i].service_work == service) {
486 if (period_ms) {
487 service_node_data[i].call_period = period_ms;
488 service_node_data[i].next_timestamp = k_uptime_get() + period_ms;
489 lwm2m_engine_wake_up();
490 return 0;
491 }
492 sys_slist_find_and_remove(&engine_service_list, &service_node_data[i].node);
493 service_node_data[i].service_work = NULL;
494 return 1;
495 }
496 }
497
498 return -ENOENT;
499 }
500
lwm2m_engine_service(const int64_t timestamp)501 static int64_t lwm2m_engine_service(const int64_t timestamp)
502 {
503 struct service_node *srv, *tmp;
504 bool restart;
505
506 do {
507 restart = false;
508 SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&engine_service_list, srv, tmp, node) {
509 /* service is due */
510 if (timestamp >= srv->next_timestamp) {
511 k_work_handler_t work = srv->service_work;
512
513 if (srv->call_period) {
514 srv->next_timestamp = k_uptime_get() + srv->call_period;
515 } else {
516 sys_slist_find_and_remove(&engine_service_list, &srv->node);
517 srv->service_work = NULL;
518 }
519 if (work) {
520 work(NULL);
521 }
522 /* List might have been modified by the callback */
523 restart = true;
524 break;
525 }
526 }
527 } while (restart);
528
529 /* calculate how long to sleep till the next service */
530 return engine_next_service_timestamp();
531 }
532
533 /* LwM2M Socket Integration */
534
lwm2m_socket_add(struct lwm2m_ctx * ctx)535 int lwm2m_socket_add(struct lwm2m_ctx *ctx)
536 {
537 if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) {
538 /* Last poll-handle is reserved for control socket */
539 if (sock_nfds >= (MAX_POLL_FD - 1)) {
540 return -ENOMEM;
541 }
542 } else {
543 if (sock_nfds >= MAX_POLL_FD) {
544 return -ENOMEM;
545 }
546 }
547
548 sock_ctx[sock_nfds] = ctx;
549 sock_fds[sock_nfds].fd = ctx->sock_fd;
550 sock_fds[sock_nfds].events = ZSOCK_POLLIN;
551 sock_nfds++;
552
553 lwm2m_engine_wake_up();
554
555 return 0;
556 }
557
lwm2m_socket_update(struct lwm2m_ctx * ctx)558 static int lwm2m_socket_update(struct lwm2m_ctx *ctx)
559 {
560 for (int i = 0; i < sock_nfds; i++) {
561 if (sock_ctx[i] != ctx) {
562 continue;
563 }
564 sock_fds[i].fd = ctx->sock_fd;
565 lwm2m_engine_wake_up();
566 return 0;
567 }
568 return -1;
569 }
570
lwm2m_socket_del(struct lwm2m_ctx * ctx)571 void lwm2m_socket_del(struct lwm2m_ctx *ctx)
572 {
573 for (int i = 0; i < sock_nfds; i++) {
574 if (sock_ctx[i] != ctx) {
575 continue;
576 }
577
578 sock_nfds--;
579
580 /* If not last, overwrite the entry with the last one. */
581 if (i < sock_nfds) {
582 sock_ctx[i] = sock_ctx[sock_nfds];
583 sock_fds[i].fd = sock_fds[sock_nfds].fd;
584 sock_fds[i].events = sock_fds[sock_nfds].events;
585 }
586
587 /* Remove the last entry. */
588 sock_ctx[sock_nfds] = NULL;
589 sock_fds[sock_nfds].fd = -1;
590 break;
591 }
592 lwm2m_engine_wake_up();
593 }
594
595 /* Generate notify messages. Return timestamp of next Notify event */
check_notifications(struct lwm2m_ctx * ctx,const int64_t timestamp)596 static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp)
597 {
598 struct observe_node *obs;
599 int rc;
600 int64_t next = INT64_MAX;
601
602 lwm2m_registry_lock();
603 SYS_SLIST_FOR_EACH_CONTAINER(&ctx->observer, obs, node) {
604 if (!obs->event_timestamp) {
605 continue;
606 }
607
608 if (obs->event_timestamp < next) {
609 next = obs->event_timestamp;
610 }
611
612 if (timestamp < obs->event_timestamp) {
613 continue;
614 }
615 /* Check That There is not pending process*/
616 if (obs->active_notify != NULL) {
617 obs->event_timestamp += NOTIFY_DELAY_MS;
618 continue;
619 }
620
621 rc = generate_notify_message(ctx, obs, NULL);
622 if (rc == -ENOMEM) {
623 /* no memory/messages available, retry later */
624 goto cleanup;
625 }
626 obs->event_timestamp =
627 engine_observe_shedule_next_event(obs, ctx->srv_obj_inst, timestamp);
628 obs->last_timestamp = timestamp;
629
630 if (!rc) {
631 /* create at most one notification */
632 goto cleanup;
633 }
634 }
635 cleanup:
636 lwm2m_registry_unlock();
637 return next;
638 }
639
640 /**
641 * @brief Check TX queue states as well as number or pending CoAP transmissions.
642 *
643 * If all queues are empty and there is no packet we are currently transmitting and no
644 * CoAP responses (pendings) we are waiting, inform the application by a callback
645 * that socket is in state LWM2M_SOCKET_STATE_NO_DATA.
646 * Otherwise, before sending a packet, depending on the state of the queues, inform with
647 * one of the ONGOING, ONE_RESPONSE or LAST indicators.
648 *
649 * @param ctx Client context.
650 * @param ongoing_tx Current packet to be transmitted or NULL.
651 */
hint_socket_state(struct lwm2m_ctx * ctx,struct lwm2m_message * ongoing_tx)652 static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoing_tx)
653 {
654 bool empty;
655 size_t pendings;
656 int next_state = -1;
657
658 if (!ctx) {
659 return;
660 }
661
662 lwm2m_client_lock(ctx);
663 #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
664 empty = sys_slist_is_empty(&ctx->pending_sends) &&
665 sys_slist_is_empty(&ctx->queued_messages);
666 #else
667 empty = sys_slist_is_empty(&ctx->pending_sends);
668 #endif
669 pendings = coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings));
670 lwm2m_client_unlock(ctx);
671
672 if (ongoing_tx) {
673 /* Check if more than current TX is in pendings list*/
674 if (pendings > 1) {
675 empty = false;
676 }
677
678 bool ongoing_block_tx = coap_block_has_more(&ongoing_tx->cpkt);
679
680 if (!empty || ongoing_block_tx) {
681 next_state = LWM2M_SOCKET_STATE_ONGOING;
682 } else if (ongoing_tx->type == COAP_TYPE_CON) {
683 next_state = LWM2M_SOCKET_STATE_ONE_RESPONSE;
684 } else {
685 next_state = LWM2M_SOCKET_STATE_LAST;
686 }
687 } else if (empty && pendings == 0) {
688 next_state = LWM2M_SOCKET_STATE_NO_DATA;
689 }
690
691 if (next_state < 0) {
692 return;
693 }
694
695 lwm2m_rd_client_hint_socket_state(ctx, next_state);
696 if (ctx->set_socket_state) {
697 ctx->set_socket_state(ctx->sock_fd, next_state);
698 }
699 }
700
socket_recv_message(struct lwm2m_ctx * client_ctx)701 static int socket_recv_message(struct lwm2m_ctx *client_ctx)
702 {
703 static uint8_t in_buf[NET_IPV6_MTU];
704 socklen_t from_addr_len;
705 ssize_t len;
706 static struct sockaddr from_addr;
707
708 from_addr_len = sizeof(from_addr);
709 len = zsock_recvfrom(client_ctx->sock_fd, in_buf, sizeof(in_buf) - 1, ZSOCK_MSG_DONTWAIT,
710 &from_addr, &from_addr_len);
711
712 if (len < 0) {
713 if (errno == EAGAIN || errno == EWOULDBLOCK) {
714 return -errno;
715 }
716
717 LOG_ERR("Error reading response: %d", errno);
718 if (client_ctx->fault_cb != NULL) {
719 client_ctx->fault_cb(errno);
720 }
721 return -errno;
722 }
723
724 if (len == 0) {
725 LOG_ERR("Zero length recv");
726 return 0;
727 }
728
729 in_buf[len] = 0U;
730 lwm2m_udp_receive(client_ctx, in_buf, len, &from_addr);
731
732 return 0;
733 }
734
socket_send_message(struct lwm2m_ctx * ctx)735 static int socket_send_message(struct lwm2m_ctx *ctx)
736 {
737 int rc;
738 sys_snode_t *msg_node;
739 struct lwm2m_message *msg;
740
741 lwm2m_client_lock(ctx);
742 msg_node = sys_slist_get(&ctx->pending_sends);
743 lwm2m_client_unlock(ctx);
744
745 if (!msg_node) {
746 return 0;
747 }
748
749 msg = SYS_SLIST_CONTAINER(msg_node, msg, node);
750 if (!msg || !msg->ctx) {
751 LOG_ERR("LwM2M message is invalid.");
752 return -EINVAL;
753 }
754
755 if (msg->type == COAP_TYPE_CON) {
756 coap_pending_cycle(msg->pending);
757 }
758
759 hint_socket_state(ctx, msg);
760
761 rc = zsock_send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0);
762
763 if (rc < 0) {
764 LOG_ERR("Failed to send packet, err %d", errno);
765 rc = -errno;
766 } else {
767 engine_update_tx_time();
768 }
769
770 if (msg->type != COAP_TYPE_CON) {
771 if (!lwm2m_outgoing_is_part_of_blockwise(msg)) {
772 lwm2m_reset_message(msg, true);
773 }
774 }
775
776 return rc;
777 }
778
socket_reset_pollfd_events(void)779 static void socket_reset_pollfd_events(void)
780 {
781 for (int i = 0; i < MAX_POLL_FD; ++i) {
782 bool set_pollout = false;
783
784 if (sock_ctx[i] != NULL) {
785 lwm2m_client_lock(sock_ctx[i]);
786 set_pollout = !sys_slist_is_empty(&sock_ctx[i]->pending_sends);
787 lwm2m_client_unlock(sock_ctx[i]);
788 }
789
790 sock_fds[i].events =
791 ZSOCK_POLLIN |
792 (set_pollout ? ZSOCK_POLLOUT : 0);
793 sock_fds[i].revents = 0;
794 }
795 }
796
797 /* LwM2M main work loop */
socket_loop(void * p1,void * p2,void * p3)798 static void socket_loop(void *p1, void *p2, void *p3)
799 {
800 ARG_UNUSED(p1);
801 ARG_UNUSED(p2);
802 ARG_UNUSED(p3);
803
804 int i, rc;
805 int64_t now, next;
806 int64_t timeout, next_tx;
807 bool rd_client_paused;
808
809 while (1) {
810 rd_client_paused = false;
811 /* Check is Thread Suspend Requested */
812 if (suspend_engine_thread) {
813 rc = lwm2m_rd_client_pause();
814 if (rc == 0) {
815 rd_client_paused = true;
816 } else {
817 LOG_ERR("Could not pause RD client");
818 }
819
820 suspend_engine_thread = false;
821 active_engine_thread = false;
822 k_thread_suspend(engine_thread_id);
823 active_engine_thread = true;
824
825 if (rd_client_paused) {
826 rc = lwm2m_rd_client_resume();
827 if (rc < 0) {
828 LOG_ERR("Could not resume RD client");
829 }
830 }
831 }
832
833 now = k_uptime_get();
834 next = lwm2m_engine_service(now);
835
836 for (i = 0; i < sock_nfds; ++i) {
837 struct lwm2m_ctx *ctx = sock_ctx[i];
838 bool is_empty;
839
840 if (ctx == NULL) {
841 continue;
842 }
843
844 lwm2m_client_lock(ctx);
845 is_empty = sys_slist_is_empty(&ctx->pending_sends);
846 lwm2m_client_unlock(ctx);
847
848 if (!is_empty) {
849 continue;
850 }
851
852 next_tx = retransmit_request(ctx, now);
853 if (next_tx < next) {
854 next = next_tx;
855 }
856 if (lwm2m_rd_client_is_registred(ctx)) {
857 next_tx = check_notifications(ctx, now);
858 if (next_tx < next) {
859 next = next_tx;
860 }
861 }
862 }
863
864 socket_reset_pollfd_events();
865
866 timeout = next > now ? next - now : 0;
867 if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) {
868 /* prevent roll-over */
869 timeout = timeout > INT32_MAX ? INT32_MAX : timeout;
870 } else {
871 timeout = timeout > ENGINE_SLEEP_MS ? ENGINE_SLEEP_MS : timeout;
872 }
873
874 rc = zsock_poll(sock_fds, MAX_POLL_FD, timeout);
875 if (rc < 0) {
876 LOG_ERR("Error in poll:%d", errno);
877 errno = 0;
878 k_msleep(ENGINE_SLEEP_MS);
879 continue;
880 }
881
882 for (i = 0; i < MAX_POLL_FD; i++) {
883 short revents = sock_fds[i].revents;
884
885 if (IS_ENABLED(CONFIG_LWM2M_TICKLESS) && (revents & ZSOCK_POLLIN) &&
886 i == (MAX_POLL_FD - 1)) {
887 /* This is the control socket, just read and ignore the data */
888 zvfs_eventfd_t tmp;
889
890 zvfs_eventfd_read(sock_fds[i].fd, &tmp);
891 continue;
892 }
893 if (sock_ctx[i] != NULL && sock_ctx[i]->sock_fd < 0) {
894 continue;
895 }
896
897 if (revents & (ZSOCK_POLLERR | ZSOCK_POLLNVAL | ZSOCK_POLLHUP)) {
898 LOG_ERR("Poll reported a socket error, %02x.", revents);
899 if (sock_ctx[i] != NULL && sock_ctx[i]->fault_cb != NULL) {
900 sock_ctx[i]->fault_cb(EIO);
901 }
902 continue;
903 }
904
905 if (revents & ZSOCK_POLLIN) {
906 while (sock_ctx[i]) {
907 rc = socket_recv_message(sock_ctx[i]);
908 if (rc) {
909 break;
910 }
911 }
912
913 hint_socket_state(sock_ctx[i], NULL);
914 }
915
916 if (revents & ZSOCK_POLLOUT) {
917 rc = socket_send_message(sock_ctx[i]);
918 /* Drop packets that cannot be send, CoAP layer handles retry */
919 /* Other fatal errors should trigger a recovery */
920 if (rc < 0 && rc != -EAGAIN) {
921 LOG_ERR("send() reported a socket error, %d", -rc);
922 if (sock_ctx[i] != NULL && sock_ctx[i]->fault_cb != NULL) {
923 sock_ctx[i]->fault_cb(-rc);
924 }
925 }
926 }
927 }
928 }
929 }
930
931 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
932 #if defined(CONFIG_TLS_CREDENTIALS)
delete_tls_credentials(sec_tag_t tag)933 static void delete_tls_credentials(sec_tag_t tag)
934 {
935 tls_credential_delete(tag, TLS_CREDENTIAL_PSK_ID);
936 tls_credential_delete(tag, TLS_CREDENTIAL_PSK);
937 tls_credential_delete(tag, TLS_CREDENTIAL_PUBLIC_CERTIFICATE);
938 tls_credential_delete(tag, TLS_CREDENTIAL_PRIVATE_KEY);
939 tls_credential_delete(tag, TLS_CREDENTIAL_CA_CERTIFICATE);
940 }
941
is_pem(const void * buf,size_t len)942 static bool is_pem(const void *buf, size_t len)
943 {
944 static const char pem_start[] = "-----BEGIN";
945
946 if (len < sizeof(pem_start)) {
947 return false;
948 }
949 if (strncmp(pem_start, (const char *) buf, sizeof(pem_start) - 1) == 0) {
950 return true;
951 }
952 return false;
953 }
954
load_tls_type(struct lwm2m_ctx * client_ctx,uint16_t res_id,enum tls_credential_type type)955 static int load_tls_type(struct lwm2m_ctx *client_ctx, uint16_t res_id,
956 enum tls_credential_type type)
957 {
958 int ret = 0;
959 void *cred = NULL;
960 uint16_t cred_len;
961 uint16_t max_len;
962
963 ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, res_id), &cred, &max_len,
964 &cred_len, NULL);
965 if (ret < 0) {
966 LOG_ERR("Unable to get resource data for %d/%d/%d", 0, client_ctx->sec_obj_inst,
967 res_id);
968 return ret;
969 }
970
971 if (cred_len == 0) {
972 LOG_ERR("Credential data is empty");
973 return -EINVAL;
974 }
975
976 /* LwM2M registry stores strings without NULL-terminator, so we need to ensure that
977 * string based PEM credentials are terminated properly.
978 */
979 if (is_pem(cred, cred_len)) {
980 if (cred_len >= max_len) {
981 LOG_ERR("No space for string terminator, cannot handle PEM");
982 return -EINVAL;
983 }
984 ((uint8_t *) cred)[cred_len] = 0;
985 cred_len += 1;
986 }
987
988 ret = tls_credential_add(client_ctx->tls_tag, type, cred, cred_len);
989 if (ret < 0) {
990 LOG_ERR("Error setting cred tag %d type %d: Error %d", client_ctx->tls_tag, type,
991 ret);
992 }
993
994 return ret;
995 }
996
lwm2m_load_psk_credentials(struct lwm2m_ctx * ctx)997 static int lwm2m_load_psk_credentials(struct lwm2m_ctx *ctx)
998 {
999 int ret;
1000
1001 delete_tls_credentials(ctx->tls_tag);
1002
1003 ret = load_tls_type(ctx, 3, TLS_CREDENTIAL_PSK_ID);
1004 if (ret < 0) {
1005 return ret;
1006 }
1007
1008 ret = load_tls_type(ctx, 5, TLS_CREDENTIAL_PSK);
1009 return ret;
1010 }
1011
lwm2m_load_x509_credentials(struct lwm2m_ctx * ctx)1012 static int lwm2m_load_x509_credentials(struct lwm2m_ctx *ctx)
1013 {
1014 int ret;
1015
1016 delete_tls_credentials(ctx->tls_tag);
1017
1018 ret = load_tls_type(ctx, 3, TLS_CREDENTIAL_PUBLIC_CERTIFICATE);
1019 if (ret < 0) {
1020 return ret;
1021 }
1022 ret = load_tls_type(ctx, 5, TLS_CREDENTIAL_PRIVATE_KEY);
1023 if (ret < 0) {
1024 return ret;
1025 }
1026
1027 ret = load_tls_type(ctx, 4, TLS_CREDENTIAL_CA_CERTIFICATE);
1028 if (ret < 0) {
1029 return ret;
1030 }
1031 return ret;
1032 }
1033 #else
1034
lwm2m_load_psk_credentials(struct lwm2m_ctx * ctx)1035 int lwm2m_load_psk_credentials(struct lwm2m_ctx *ctx)
1036 {
1037 return -EOPNOTSUPP;
1038 }
1039
lwm2m_load_x509_credentials(struct lwm2m_ctx * ctx)1040 int lwm2m_load_x509_credentials(struct lwm2m_ctx *ctx)
1041 {
1042 return -EOPNOTSUPP;
1043 }
1044 #endif /* CONFIG_TLS_CREDENTIALS*/
1045
lwm2m_load_tls_credentials(struct lwm2m_ctx * ctx)1046 static int lwm2m_load_tls_credentials(struct lwm2m_ctx *ctx)
1047 {
1048 switch (lwm2m_security_mode(ctx)) {
1049 case LWM2M_SECURITY_NOSEC:
1050 if (ctx->use_dtls) {
1051 return -EINVAL;
1052 }
1053 return 0;
1054 case LWM2M_SECURITY_PSK:
1055 return lwm2m_load_psk_credentials(ctx);
1056 case LWM2M_SECURITY_CERT:
1057 return lwm2m_load_x509_credentials(ctx);
1058 default:
1059 return -EOPNOTSUPP;
1060 }
1061 }
1062
1063 static const int cipher_list_psk[] = {
1064 MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8,
1065 };
1066
1067 static const int cipher_list_cert[] = {
1068 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
1069 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
1070 };
1071
1072 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
1073
lwm2m_set_default_sockopt(struct lwm2m_ctx * ctx)1074 int lwm2m_set_default_sockopt(struct lwm2m_ctx *ctx)
1075 {
1076 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
1077 if (ctx->use_dtls) {
1078 int ret;
1079 uint8_t tmp;
1080 sec_tag_t tls_tag_list[] = {
1081 ctx->tls_tag,
1082 };
1083
1084 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_tag_list,
1085 sizeof(tls_tag_list));
1086 if (ret < 0) {
1087 ret = -errno;
1088 LOG_ERR("Failed to set TLS_SEC_TAG_LIST option: %d", ret);
1089 return ret;
1090 }
1091
1092 if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) {
1093 int session_cache = TLS_SESSION_CACHE_ENABLED;
1094
1095 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_SESSION_CACHE,
1096 &session_cache, sizeof(session_cache));
1097 if (ret < 0) {
1098 ret = -errno;
1099 LOG_ERR("Failed to set TLS_SESSION_CACHE option: %d", errno);
1100 return ret;
1101 }
1102 }
1103 if (IS_ENABLED(CONFIG_LWM2M_DTLS_CID)) {
1104 /* Enable CID */
1105 int cid = TLS_DTLS_CID_SUPPORTED;
1106
1107 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_DTLS_CID, &cid,
1108 sizeof(cid));
1109 if (ret) {
1110 ret = -errno;
1111 LOG_ERR("Failed to enable TLS_DTLS_CID: %d", ret);
1112 /* Not fatal, continue. */
1113 }
1114 }
1115
1116 if (ctx->desthostname != NULL && lwm2m_security_mode(ctx) == LWM2M_SECURITY_CERT) {
1117 /** store character at len position */
1118 tmp = ctx->desthostname[ctx->desthostnamelen];
1119
1120 /** change it to '\0' to pass to socket*/
1121 ctx->desthostname[ctx->desthostnamelen] = '\0';
1122
1123 /** mbedtls ignores length */
1124 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_HOSTNAME,
1125 ctx->desthostname, ctx->desthostnamelen);
1126
1127 /** restore character */
1128 ctx->desthostname[ctx->desthostnamelen] = tmp;
1129 if (ret < 0) {
1130 ret = -errno;
1131 LOG_ERR("Failed to set TLS_HOSTNAME option: %d", ret);
1132 return ret;
1133 }
1134
1135 int verify = TLS_PEER_VERIFY_REQUIRED;
1136
1137 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_PEER_VERIFY, &verify,
1138 sizeof(verify));
1139 if (ret) {
1140 LOG_ERR("Failed to set TLS_PEER_VERIFY");
1141 }
1142
1143 } else {
1144 /* By default, Mbed TLS tries to verify peer hostname, disable it */
1145 int verify = TLS_PEER_VERIFY_NONE;
1146
1147 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_PEER_VERIFY, &verify,
1148 sizeof(verify));
1149 if (ret) {
1150 LOG_ERR("Failed to set TLS_PEER_VERIFY");
1151 }
1152 }
1153
1154 switch (lwm2m_security_mode(ctx)) {
1155 case LWM2M_SECURITY_PSK:
1156 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_CIPHERSUITE_LIST,
1157 cipher_list_psk, sizeof(cipher_list_psk));
1158 if (ret) {
1159 LOG_ERR("Failed to set TLS_CIPHERSUITE_LIST");
1160 }
1161 break;
1162 case LWM2M_SECURITY_CERT:
1163 ret = zsock_setsockopt(ctx->sock_fd, SOL_TLS, TLS_CIPHERSUITE_LIST,
1164 cipher_list_cert, sizeof(cipher_list_cert));
1165 if (ret) {
1166 LOG_ERR("Failed to set TLS_CIPHERSUITE_LIST (rc %d, errno %d)", ret,
1167 errno);
1168 }
1169 break;
1170 default:
1171 return -EOPNOTSUPP;
1172 }
1173 }
1174 #else
1175 if (!IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) && ctx->use_dtls) {
1176 return -EOPNOTSUPP;
1177 }
1178 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
1179 return 0;
1180 }
1181
lwm2m_socket_start(struct lwm2m_ctx * client_ctx)1182 int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
1183 {
1184 socklen_t addr_len;
1185 int flags;
1186 int ret;
1187
1188 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
1189 if (client_ctx->use_dtls) {
1190 if (client_ctx->load_credentials) {
1191 ret = client_ctx->load_credentials(client_ctx);
1192 } else {
1193 ret = lwm2m_load_tls_credentials(client_ctx);
1194 }
1195 if (ret < 0) {
1196 return ret;
1197 }
1198 }
1199 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
1200
1201 if (client_ctx->sock_fd < 0) {
1202 ret = lwm2m_open_socket(client_ctx);
1203 if (ret) {
1204 return ret;
1205 }
1206 }
1207
1208 if (client_ctx->set_socketoptions) {
1209 ret = client_ctx->set_socketoptions(client_ctx);
1210 } else {
1211 ret = lwm2m_set_default_sockopt(client_ctx);
1212 }
1213 if (ret) {
1214 goto error;
1215 }
1216
1217 if ((client_ctx->remote_addr).sa_family == AF_INET) {
1218 addr_len = sizeof(struct sockaddr_in);
1219 } else if ((client_ctx->remote_addr).sa_family == AF_INET6) {
1220 addr_len = sizeof(struct sockaddr_in6);
1221 } else {
1222 ret = -EPROTONOSUPPORT;
1223 goto error;
1224 }
1225
1226 if (zsock_connect(client_ctx->sock_fd, &client_ctx->remote_addr, addr_len) < 0) {
1227 ret = -errno;
1228 LOG_ERR("Cannot connect UDP (%d)", ret);
1229 goto error;
1230 }
1231
1232 flags = zsock_fcntl(client_ctx->sock_fd, F_GETFL, 0);
1233 if (flags == -1) {
1234 ret = -errno;
1235 LOG_ERR("zsock_fcntl(F_GETFL) failed (%d)", ret);
1236 goto error;
1237 }
1238 ret = zsock_fcntl(client_ctx->sock_fd, F_SETFL, flags | O_NONBLOCK);
1239 if (ret == -1) {
1240 ret = -errno;
1241 LOG_ERR("zsock_fcntl(F_SETFL) failed (%d)", ret);
1242 goto error;
1243 }
1244
1245 LOG_INF("Connected, sock id %d", client_ctx->sock_fd);
1246 return 0;
1247 error:
1248 lwm2m_socket_close(client_ctx);
1249 return ret;
1250 }
1251
lwm2m_socket_close(struct lwm2m_ctx * client_ctx)1252 int lwm2m_socket_close(struct lwm2m_ctx *client_ctx)
1253 {
1254 int sock_fd = client_ctx->sock_fd;
1255
1256 lwm2m_socket_del(client_ctx);
1257 client_ctx->sock_fd = -1;
1258 if (sock_fd >= 0) {
1259 return zsock_close(sock_fd);
1260 }
1261
1262 return 0;
1263 }
1264
lwm2m_engine_stop(struct lwm2m_ctx * client_ctx)1265 int lwm2m_engine_stop(struct lwm2m_ctx *client_ctx)
1266 {
1267 lwm2m_engine_context_close(client_ctx);
1268
1269 return lwm2m_socket_close(client_ctx);
1270 }
1271
lwm2m_engine_start(struct lwm2m_ctx * client_ctx)1272 int lwm2m_engine_start(struct lwm2m_ctx *client_ctx)
1273 {
1274 char *url;
1275 uint16_t url_len;
1276 uint8_t url_data_flags;
1277 int ret = 0U;
1278
1279 /* get the server URL */
1280 ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, 0), (void **)&url, NULL,
1281 &url_len, &url_data_flags);
1282 if (ret < 0) {
1283 return ret;
1284 }
1285
1286 url[url_len] = '\0';
1287 ret = lwm2m_parse_peerinfo(url, client_ctx, false);
1288 if (ret < 0) {
1289 return ret;
1290 }
1291
1292 return lwm2m_socket_start(client_ctx);
1293 }
1294
lwm2m_engine_pause(void)1295 int lwm2m_engine_pause(void)
1296 {
1297 if (suspend_engine_thread || !active_engine_thread) {
1298 LOG_WRN("Engine thread already suspended");
1299 return 0;
1300 }
1301
1302 suspend_engine_thread = true;
1303 lwm2m_engine_wake_up();
1304
1305 /* Check if pause requested within a engine thread, a callback for example. */
1306 if (engine_thread_id == k_current_get()) {
1307 LOG_DBG("Pause requested");
1308 return 0;
1309 }
1310
1311 while (active_engine_thread) {
1312 k_msleep(10);
1313 }
1314 LOG_INF("LWM2M engine thread paused");
1315 return 0;
1316 }
1317
lwm2m_engine_resume(void)1318 int lwm2m_engine_resume(void)
1319 {
1320 if (suspend_engine_thread || active_engine_thread) {
1321 LOG_WRN("LWM2M engine thread state not ok for resume");
1322 return -EPERM;
1323 }
1324
1325 k_thread_resume(engine_thread_id);
1326 lwm2m_engine_wake_up();
1327
1328 return 0;
1329 }
1330
lwm2m_engine_lock(void)1331 void lwm2m_engine_lock(void)
1332 {
1333 (void)k_mutex_lock(&engine_lock, K_FOREVER);
1334 }
1335
lwm2m_engine_unlock(void)1336 void lwm2m_engine_unlock(void)
1337 {
1338 k_mutex_unlock(&engine_lock);
1339 }
1340
lwm2m_client_lock(struct lwm2m_ctx * ctx)1341 void lwm2m_client_lock(struct lwm2m_ctx *ctx)
1342 {
1343 (void)k_mutex_lock(&ctx->lock, K_FOREVER);
1344 }
1345
lwm2m_client_unlock(struct lwm2m_ctx * ctx)1346 void lwm2m_client_unlock(struct lwm2m_ctx *ctx)
1347 {
1348 k_mutex_unlock(&ctx->lock);
1349 }
1350
lwm2m_engine_init(void)1351 static int lwm2m_engine_init(void)
1352 {
1353 for (int i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) {
1354 sys_slist_append(lwm2m_obs_obj_path_list(), &observe_paths[i].node);
1355 }
1356
1357 /* Reset all socket handles to -1 so unused ones are ignored by zsock_poll() */
1358 for (int i = 0; i < MAX_POLL_FD; ++i) {
1359 sock_fds[i].fd = -1;
1360 }
1361
1362 if (IS_ENABLED(CONFIG_LWM2M_TICKLESS)) {
1363 /* Create eventfd that is used to wake zsock_poll() in the main loop */
1364 int efd = zvfs_eventfd(0, ZVFS_EFD_NONBLOCK);
1365
1366 if (efd == -1) {
1367 int err = errno;
1368
1369 LOG_ERR("Error; eventfd() returned %d", err);
1370 return -err;
1371 }
1372 /* Last poll-handle is reserved for control eventfd */
1373 sock_fds[MAX_POLL_FD - 1].fd = efd;
1374 }
1375
1376 lwm2m_clear_block_contexts();
1377 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
1378 lwm2m_engine_lock();
1379 (void)memset(output_block_contexts, 0, sizeof(output_block_contexts));
1380 lwm2m_engine_unlock();
1381 #endif
1382
1383 STRUCT_SECTION_FOREACH(lwm2m_init_func, init) {
1384 int ret = init->f();
1385
1386 if (ret) {
1387 LOG_ERR("Init function %p returned %d", init, ret);
1388 }
1389 }
1390
1391 /* start sock receive thread */
1392 engine_thread_id = k_thread_create(&engine_thread_data, &engine_thread_stack[0],
1393 K_KERNEL_STACK_SIZEOF(engine_thread_stack), socket_loop,
1394 NULL, NULL, NULL, THREAD_PRIORITY, 0, K_NO_WAIT);
1395 k_thread_name_set(&engine_thread_data, "lwm2m-sock-recv");
1396 LOG_DBG("LWM2M engine socket receive thread started");
1397 active_engine_thread = true;
1398
1399 return 0;
1400 }
1401
1402 SYS_INIT(lwm2m_engine_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
1403