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