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