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