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