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