1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2018-2019 Foundries.io
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * Uses some original concepts by:
10  *         Joakim Eriksson <joakime@sics.se>
11  *         Niclas Finne <nfi@sics.se>
12  *         Joel Hoglund <joel@sics.se>
13  */
14 
15 #define LOG_MODULE_NAME net_lwm2m_engine
16 #define LOG_LEVEL	CONFIG_LWM2M_LOG_LEVEL
17 
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
20 
21 #include <ctype.h>
22 #include <errno.h>
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <zephyr/init.h>
29 #include <zephyr/net/http/parser_url.h>
30 #include <zephyr/net/lwm2m.h>
31 #include <zephyr/net/net_ip.h>
32 #include <zephyr/net/socket.h>
33 #include <zephyr/sys/printk.h>
34 #include <zephyr/types.h>
35 #ifdef CONFIG_ARCH_POSIX
36 #include <fcntl.h>
37 #else
38 #include <zephyr/posix/fcntl.h>
39 #endif
40 
41 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
42 #include <zephyr/net/tls_credentials.h>
43 #endif
44 #if defined(CONFIG_DNS_RESOLVER)
45 #include <zephyr/net/dns_resolve.h>
46 #endif
47 
48 #include "lwm2m_engine.h"
49 #include "lwm2m_object.h"
50 #include "lwm2m_rw_link_format.h"
51 #include "lwm2m_rw_oma_tlv.h"
52 #include "lwm2m_rw_plain_text.h"
53 #include "lwm2m_util.h"
54 #include "lwm2m_rd_client.h"
55 #if defined(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)
56 #include "lwm2m_rw_senml_json.h"
57 #endif
58 #ifdef CONFIG_LWM2M_RW_JSON_SUPPORT
59 #include "lwm2m_rw_json.h"
60 #endif
61 #ifdef CONFIG_LWM2M_RW_CBOR_SUPPORT
62 #include "lwm2m_rw_cbor.h"
63 #endif
64 #ifdef CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT
65 #include "lwm2m_rw_senml_cbor.h"
66 #endif
67 
68 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
69 /* Lowest priority cooperative thread */
70 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1)
71 #else
72 #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1)
73 #endif
74 
75 #define ENGINE_UPDATE_INTERVAL_MS 500
76 
77 #ifdef CONFIG_LWM2M_VERSION_1_1
78 #define LWM2M_ENGINE_MAX_OBSERVER_PATH CONFIG_LWM2M_ENGINE_MAX_OBSERVER * 3
79 #else
80 #define LWM2M_ENGINE_MAX_OBSERVER_PATH CONFIG_LWM2M_ENGINE_MAX_OBSERVER
81 #endif
82 static struct lwm2m_obj_path_list observe_paths[LWM2M_ENGINE_MAX_OBSERVER_PATH];
83 #define MAX_PERIODIC_SERVICE 10
84 
85 static k_tid_t engine_thread_id;
86 static bool suspend_engine_thread;
87 static bool active_engine_thread;
88 
89 struct service_node {
90 	sys_snode_t node;
91 	k_work_handler_t service_work;
92 	uint32_t min_call_period; /* ms */
93 	uint64_t last_timestamp;  /* ms */
94 };
95 
96 static struct service_node service_node_data[MAX_PERIODIC_SERVICE];
97 static sys_slist_t engine_service_list;
98 
99 static K_KERNEL_STACK_DEFINE(engine_thread_stack, CONFIG_LWM2M_ENGINE_STACK_SIZE);
100 static struct k_thread engine_thread_data;
101 
102 #define MAX_POLL_FD CONFIG_NET_SOCKETS_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_open_socket(struct lwm2m_ctx * client_ctx)128 int lwm2m_open_socket(struct lwm2m_ctx *client_ctx)
129 {
130 	if (client_ctx->sock_fd < 0) {
131 		/* open socket */
132 
133 		if (IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) && client_ctx->use_dtls) {
134 			client_ctx->sock_fd = zsock_socket(client_ctx->remote_addr.sa_family,
135 							   SOCK_DGRAM, IPPROTO_DTLS_1_2);
136 		} else {
137 			client_ctx->sock_fd =
138 				zsock_socket(client_ctx->remote_addr.sa_family, SOCK_DGRAM,
139 					     IPPROTO_UDP);
140 		}
141 
142 		if (client_ctx->sock_fd < 0) {
143 			LOG_ERR("Failed to create socket: %d", errno);
144 			return -errno;
145 		}
146 
147 		if (lwm2m_socket_update(client_ctx)) {
148 			return lwm2m_socket_add(client_ctx);
149 		}
150 	}
151 
152 	return 0;
153 }
154 
lwm2m_close_socket(struct lwm2m_ctx * client_ctx)155 int lwm2m_close_socket(struct lwm2m_ctx *client_ctx)
156 {
157 	int ret = 0;
158 
159 	if (client_ctx->sock_fd >= 0) {
160 		ret = zsock_close(client_ctx->sock_fd);
161 		if (ret) {
162 			LOG_ERR("Failed to close socket: %d", errno);
163 			ret = -errno;
164 			return ret;
165 		}
166 
167 		client_ctx->sock_fd = -1;
168 		client_ctx->connection_suspended = true;
169 #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
170 		/* Enable Queue mode buffer store */
171 		client_ctx->buffer_client_messages = true;
172 #endif
173 		lwm2m_socket_update(client_ctx);
174 	}
175 
176 	return ret;
177 }
178 
179 
lwm2m_socket_suspend(struct lwm2m_ctx * client_ctx)180 int lwm2m_socket_suspend(struct lwm2m_ctx *client_ctx)
181 {
182 	int ret = 0;
183 
184 	if (client_ctx->sock_fd >= 0 && !client_ctx->connection_suspended) {
185 		int socket_temp_id = client_ctx->sock_fd;
186 
187 		client_ctx->sock_fd = -1;
188 		client_ctx->connection_suspended = true;
189 #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
190 		/* Enable Queue mode buffer store */
191 		client_ctx->buffer_client_messages = true;
192 #endif
193 		lwm2m_socket_update(client_ctx);
194 		client_ctx->sock_fd = socket_temp_id;
195 	}
196 
197 	return ret;
198 }
199 
lwm2m_engine_connection_resume(struct lwm2m_ctx * client_ctx)200 int lwm2m_engine_connection_resume(struct lwm2m_ctx *client_ctx)
201 {
202 	int ret;
203 
204 	if (client_ctx->connection_suspended) {
205 		if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE)) {
206 			lwm2m_socket_update(client_ctx);
207 		} else {
208 			lwm2m_close_socket(client_ctx);
209 			client_ctx->connection_suspended = false;
210 			ret = lwm2m_open_socket(client_ctx);
211 			if (ret) {
212 				return ret;
213 			}
214 			LOG_DBG("Resume suspended connection");
215 			return lwm2m_socket_start(client_ctx);
216 		}
217 	}
218 
219 	return 0;
220 }
221 
lwm2m_push_queued_buffers(struct lwm2m_ctx * client_ctx)222 int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx)
223 {
224 #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
225 	client_ctx->buffer_client_messages = false;
226 	while (!sys_slist_is_empty(&client_ctx->queued_messages)) {
227 		sys_snode_t *msg_node = sys_slist_get(&client_ctx->queued_messages);
228 		struct lwm2m_message *msg;
229 
230 		if (!msg_node) {
231 			break;
232 		}
233 		msg = SYS_SLIST_CONTAINER(msg_node, msg, node);
234 		sys_slist_append(&msg->ctx->pending_sends, &msg->node);
235 	}
236 #endif
237 	return 0;
238 }
239 
lwm2m_engine_bootstrap_override(struct lwm2m_ctx * client_ctx,struct lwm2m_obj_path * path)240 bool lwm2m_engine_bootstrap_override(struct lwm2m_ctx *client_ctx, struct lwm2m_obj_path *path)
241 {
242 	if (!client_ctx->bootstrap_mode) {
243 		/* Bootstrap is not active override is not possible then */
244 		return false;
245 	}
246 
247 	if (path->obj_id == LWM2M_OBJECT_SECURITY_ID || path->obj_id == LWM2M_OBJECT_SERVER_ID) {
248 		/* Bootstrap server have a access to Security and Server object */
249 		return true;
250 	}
251 
252 	return false;
253 }
254 
lwm2m_engine_validate_write_access(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst * obj_inst,struct lwm2m_engine_obj_field ** obj_field)255 int lwm2m_engine_validate_write_access(struct lwm2m_message *msg,
256 				       struct lwm2m_engine_obj_inst *obj_inst,
257 				       struct lwm2m_engine_obj_field **obj_field)
258 {
259 	struct lwm2m_engine_obj_field *o_f;
260 
261 	o_f = lwm2m_get_engine_obj_field(obj_inst->obj, msg->path.res_id);
262 	if (!o_f) {
263 		return -ENOENT;
264 	}
265 
266 	*obj_field = o_f;
267 
268 	if (!LWM2M_HAS_PERM(o_f, LWM2M_PERM_W) &&
269 	    !lwm2m_engine_bootstrap_override(msg->ctx, &msg->path)) {
270 		return -EPERM;
271 	}
272 
273 	if (!obj_inst->resources || obj_inst->resource_count == 0U) {
274 		return -EINVAL;
275 	}
276 
277 	return 0;
278 }
279 
280 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
bootstrap_delete_allowed(int obj_id,int obj_inst_id)281 static bool bootstrap_delete_allowed(int obj_id, int obj_inst_id)
282 {
283 	bool bootstrap_server;
284 	int ret;
285 
286 	if (obj_id == LWM2M_OBJECT_SECURITY_ID) {
287 		ret = lwm2m_get_bool(&LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, obj_inst_id, 1),
288 					    &bootstrap_server);
289 		if (ret < 0) {
290 			return false;
291 		}
292 
293 		if (bootstrap_server) {
294 			return false;
295 		}
296 	}
297 
298 	if (obj_id == LWM2M_OBJECT_DEVICE_ID) {
299 		return false;
300 	}
301 
302 	return true;
303 }
304 
bootstrap_delete(struct lwm2m_message * msg)305 int bootstrap_delete(struct lwm2m_message *msg)
306 {
307 	struct lwm2m_engine_obj_inst *obj_inst, *tmp;
308 	int ret = 0;
309 	sys_slist_t *engine_obj_inst_list = lwm2m_engine_obj_inst_list();
310 
311 	if (msg->path.level > 2) {
312 		return -EPERM;
313 	}
314 
315 	if (msg->path.level == 2) {
316 		if (!bootstrap_delete_allowed(msg->path.obj_id, msg->path.obj_inst_id)) {
317 			return -EPERM;
318 		}
319 
320 		return lwm2m_delete_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
321 	}
322 
323 	/* DELETE all instances of a specific object or all object instances if
324 	 * not specified, excluding the following exceptions (according to the
325 	 * LwM2M specification v1.0.2, ch 5.2.7.5):
326 	 * - LwM2M Bootstrap-Server Account (Bootstrap Security object, ID 0)
327 	 * - Device object (ID 3)
328 	 */
329 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(engine_obj_inst_list, obj_inst, tmp, node) {
330 		if (msg->path.level == 1 && obj_inst->obj->obj_id != msg->path.obj_id) {
331 			continue;
332 		}
333 
334 		if (!bootstrap_delete_allowed(obj_inst->obj->obj_id, obj_inst->obj_inst_id)) {
335 			continue;
336 		}
337 
338 		ret = lwm2m_delete_obj_inst(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
339 		if (ret < 0) {
340 			return ret;
341 		}
342 	}
343 
344 	return ret;
345 }
346 #endif
347 /* returns ms until the next retransmission is due, or INT32_MAX
348  * if no retransmissions are necessary
349  */
retransmit_request(struct lwm2m_ctx * client_ctx,const uint32_t timestamp)350 static int32_t retransmit_request(struct lwm2m_ctx *client_ctx, const uint32_t timestamp)
351 {
352 	struct lwm2m_message *msg;
353 	struct coap_pending *p;
354 	int32_t remaining, next_retransmission = INT32_MAX;
355 	int i;
356 
357 	for (i = 0, p = client_ctx->pendings; i < ARRAY_SIZE(client_ctx->pendings); i++, p++) {
358 		if (!p->timeout) {
359 			continue;
360 		}
361 
362 		remaining = p->t0 + p->timeout - timestamp;
363 		if (remaining < 0) {
364 			msg = find_msg(p, NULL);
365 			if (!msg) {
366 				LOG_ERR("pending has no valid LwM2M message!");
367 				coap_pending_clear(p);
368 				continue;
369 			}
370 			if (!p->retries) {
371 				/* pending request has expired */
372 				if (msg->message_timeout_cb) {
373 					msg->message_timeout_cb(msg);
374 				}
375 				lwm2m_reset_message(msg, true);
376 				continue;
377 			}
378 			if (msg->acknowledged) {
379 				/* No need to retransmit, just keep the timer running to
380 				 * timeout in case no response arrives.
381 				 */
382 				coap_pending_cycle(p);
383 				continue;
384 			}
385 
386 			lwm2m_send_message_async(msg);
387 			break;
388 		}
389 		if (remaining < next_retransmission) {
390 			next_retransmission = remaining;
391 		}
392 	}
393 
394 	return next_retransmission;
395 }
engine_next_service_timeout_ms(uint32_t max_timeout,const int64_t timestamp)396 static int32_t engine_next_service_timeout_ms(uint32_t max_timeout, const int64_t timestamp)
397 {
398 	struct service_node *srv;
399 	uint64_t time_left_ms;
400 	uint32_t timeout = max_timeout;
401 
402 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) {
403 		time_left_ms = srv->last_timestamp + srv->min_call_period;
404 
405 		/* service is due */
406 		if (time_left_ms < timestamp) {
407 			return 0;
408 		}
409 
410 		/* service timeout is less than the current timeout */
411 		time_left_ms -= timestamp;
412 		if (time_left_ms < timeout) {
413 			timeout = time_left_ms;
414 		}
415 	}
416 
417 	return timeout;
418 }
419 
lwm2m_engine_add_service(k_work_handler_t service,uint32_t period_ms)420 int lwm2m_engine_add_service(k_work_handler_t service, uint32_t period_ms)
421 {
422 	int i;
423 
424 	if (!service) {
425 		return -EINVAL;
426 	}
427 
428 	/* First, try if the service is already registered, and modify it*/
429 	if (lwm2m_engine_update_service_period(service, period_ms) == 0) {
430 		return 0;
431 	}
432 
433 	/* find an unused service index node */
434 	for (i = 0; i < MAX_PERIODIC_SERVICE; i++) {
435 		if (!service_node_data[i].service_work) {
436 			break;
437 		}
438 	}
439 
440 	if (i == MAX_PERIODIC_SERVICE) {
441 		return -ENOMEM;
442 	}
443 
444 	service_node_data[i].service_work = service;
445 	service_node_data[i].min_call_period = period_ms;
446 	service_node_data[i].last_timestamp = 0U;
447 
448 	sys_slist_append(&engine_service_list, &service_node_data[i].node);
449 
450 	return 0;
451 }
452 
lwm2m_engine_update_service_period(k_work_handler_t service,uint32_t period_ms)453 int lwm2m_engine_update_service_period(k_work_handler_t service, uint32_t period_ms)
454 {
455 	int i = 0;
456 
457 	for (i = 0; i < MAX_PERIODIC_SERVICE; i++) {
458 		if (service_node_data[i].service_work == service) {
459 			service_node_data[i].min_call_period = period_ms;
460 			return 0;
461 		}
462 	}
463 
464 	return -ENOENT;
465 }
466 
lwm2m_engine_service(const int64_t timestamp)467 static int32_t lwm2m_engine_service(const int64_t timestamp)
468 {
469 	struct service_node *srv;
470 	int64_t service_due_timestamp;
471 
472 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) {
473 		service_due_timestamp = srv->last_timestamp + srv->min_call_period;
474 		/* service is due */
475 		if (timestamp >= service_due_timestamp) {
476 			srv->last_timestamp = k_uptime_get();
477 			srv->service_work(NULL);
478 		}
479 	}
480 
481 	/* calculate how long to sleep till the next service */
482 	return engine_next_service_timeout_ms(ENGINE_UPDATE_INTERVAL_MS, timestamp);
483 }
484 
485 /* LwM2M Socket Integration */
486 
lwm2m_socket_add(struct lwm2m_ctx * ctx)487 int lwm2m_socket_add(struct lwm2m_ctx *ctx)
488 {
489 	if (sock_nfds >= MAX_POLL_FD) {
490 		return -ENOMEM;
491 	}
492 
493 	sock_ctx[sock_nfds] = ctx;
494 	sock_fds[sock_nfds].fd = ctx->sock_fd;
495 	sock_fds[sock_nfds].events = ZSOCK_POLLIN;
496 	sock_nfds++;
497 
498 	return 0;
499 }
500 
lwm2m_socket_update(struct lwm2m_ctx * ctx)501 static int lwm2m_socket_update(struct lwm2m_ctx *ctx)
502 {
503 	for (int i = 0; i < sock_nfds; i++) {
504 		if (sock_ctx[i] != ctx) {
505 			continue;
506 		}
507 		sock_fds[i].fd = ctx->sock_fd;
508 		return 0;
509 	}
510 	return -1;
511 }
512 
lwm2m_socket_del(struct lwm2m_ctx * ctx)513 void lwm2m_socket_del(struct lwm2m_ctx *ctx)
514 {
515 	for (int i = 0; i < sock_nfds; i++) {
516 		if (sock_ctx[i] != ctx) {
517 			continue;
518 		}
519 
520 		sock_nfds--;
521 
522 		/* If not last, overwrite the entry with the last one. */
523 		if (i < sock_nfds) {
524 			sock_ctx[i] = sock_ctx[sock_nfds];
525 			sock_fds[i].fd = sock_fds[sock_nfds].fd;
526 			sock_fds[i].events = sock_fds[sock_nfds].events;
527 		}
528 
529 		/* Remove the last entry. */
530 		sock_ctx[sock_nfds] = NULL;
531 		sock_fds[sock_nfds].fd = -1;
532 		break;
533 	}
534 }
535 
check_notifications(struct lwm2m_ctx * ctx,const int64_t timestamp)536 static void check_notifications(struct lwm2m_ctx *ctx, const int64_t timestamp)
537 {
538 	struct observe_node *obs;
539 	int rc;
540 
541 	lwm2m_registry_lock();
542 	SYS_SLIST_FOR_EACH_CONTAINER(&ctx->observer, obs, node) {
543 		if (!obs->event_timestamp || timestamp < obs->event_timestamp) {
544 			continue;
545 		}
546 		/* Check That There is not pending process*/
547 		if (obs->active_tx_operation) {
548 			continue;
549 		}
550 
551 		rc = generate_notify_message(ctx, obs, NULL);
552 		if (rc == -ENOMEM) {
553 			/* no memory/messages available, retry later */
554 			goto cleanup;
555 		}
556 		obs->event_timestamp =
557 			engine_observe_shedule_next_event(obs, ctx->srv_obj_inst, timestamp);
558 		obs->last_timestamp = timestamp;
559 		if (!rc) {
560 			/* create at most one notification */
561 			goto cleanup;
562 		}
563 	}
564 cleanup:
565 	lwm2m_registry_unlock();
566 }
567 
socket_recv_message(struct lwm2m_ctx * client_ctx)568 static int socket_recv_message(struct lwm2m_ctx *client_ctx)
569 {
570 	static uint8_t in_buf[NET_IPV6_MTU];
571 	socklen_t from_addr_len;
572 	ssize_t len;
573 	static struct sockaddr from_addr;
574 
575 	from_addr_len = sizeof(from_addr);
576 	len = zsock_recvfrom(client_ctx->sock_fd, in_buf, sizeof(in_buf) - 1, 0, &from_addr,
577 			     &from_addr_len);
578 
579 	if (len < 0) {
580 		if (errno == EAGAIN || errno == EWOULDBLOCK) {
581 			return -errno;
582 		}
583 
584 		LOG_ERR("Error reading response: %d", errno);
585 		if (client_ctx->fault_cb != NULL) {
586 			client_ctx->fault_cb(errno);
587 		}
588 		return -errno;
589 	}
590 
591 	if (len == 0) {
592 		LOG_ERR("Zero length recv");
593 		return 0;
594 	}
595 
596 	in_buf[len] = 0U;
597 	lwm2m_udp_receive(client_ctx, in_buf, len, &from_addr, handle_request);
598 
599 	return 0;
600 }
601 
socket_send_message(struct lwm2m_ctx * client_ctx)602 static int socket_send_message(struct lwm2m_ctx *client_ctx)
603 {
604 	int rc;
605 	sys_snode_t *msg_node = sys_slist_get(&client_ctx->pending_sends);
606 	struct lwm2m_message *msg;
607 
608 	if (!msg_node) {
609 		return 0;
610 	}
611 
612 	msg = SYS_SLIST_CONTAINER(msg_node, msg, node);
613 	if (!msg || !msg->ctx) {
614 		LOG_ERR("LwM2M message is invalid.");
615 		return -EINVAL;
616 	}
617 
618 	if (msg->type == COAP_TYPE_CON) {
619 		coap_pending_cycle(msg->pending);
620 	}
621 
622 	rc = zsock_send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0);
623 
624 	if (rc < 0) {
625 		LOG_ERR("Failed to send packet, err %d", errno);
626 		rc = -errno;
627 	}
628 
629 	if (msg->type != COAP_TYPE_CON) {
630 		lwm2m_reset_message(msg, true);
631 	}
632 
633 	return rc;
634 }
635 
socket_reset_pollfd_events(void)636 static void socket_reset_pollfd_events(void)
637 {
638 	for (int i = 0; i < sock_nfds; ++i) {
639 		sock_fds[i].events =
640 			ZSOCK_POLLIN |
641 			(sys_slist_is_empty(&sock_ctx[i]->pending_sends) ? 0 : ZSOCK_POLLOUT);
642 		sock_fds[i].revents = 0;
643 	}
644 }
645 
646 /* LwM2M main work loop */
socket_loop(void)647 static void socket_loop(void)
648 {
649 	int i, rc;
650 	int64_t timestamp;
651 	int32_t timeout, next_retransmit;
652 	bool rd_client_paused;
653 
654 	while (1) {
655 		rd_client_paused = false;
656 		/* Check is Thread Suspend Requested */
657 		if (suspend_engine_thread) {
658 			rc = lwm2m_rd_client_pause();
659 			if (rc == 0) {
660 				rd_client_paused = true;
661 			} else {
662 				LOG_ERR("Could not pause RD client");
663 			}
664 
665 			suspend_engine_thread = false;
666 			active_engine_thread = false;
667 			k_thread_suspend(engine_thread_id);
668 			active_engine_thread = true;
669 
670 			if (rd_client_paused) {
671 				rc = lwm2m_rd_client_resume();
672 				if (rc < 0) {
673 					LOG_ERR("Could not resume RD client");
674 				}
675 			}
676 		}
677 
678 		timestamp = k_uptime_get();
679 		timeout = lwm2m_engine_service(timestamp);
680 
681 		/* wait for sockets */
682 		if (sock_nfds < 1) {
683 			k_msleep(timeout);
684 			continue;
685 		}
686 
687 		for (i = 0; i < sock_nfds; ++i) {
688 			if (sock_ctx[i] != NULL &&
689 			    sys_slist_is_empty(&sock_ctx[i]->pending_sends)) {
690 				next_retransmit = retransmit_request(sock_ctx[i], timestamp);
691 				if (next_retransmit < timeout) {
692 					timeout = next_retransmit;
693 				}
694 			}
695 			if (sock_ctx[i] != NULL &&
696 			    sys_slist_is_empty(&sock_ctx[i]->pending_sends) &&
697 			    lwm2m_rd_client_is_registred(sock_ctx[i])) {
698 				check_notifications(sock_ctx[i], timestamp);
699 			}
700 		}
701 
702 		socket_reset_pollfd_events();
703 
704 		/*
705 		 * FIXME: Currently we timeout and restart poll in case fds
706 		 *        were modified.
707 		 */
708 		rc = zsock_poll(sock_fds, sock_nfds, timeout);
709 		if (rc < 0) {
710 			LOG_ERR("Error in poll:%d", errno);
711 			errno = 0;
712 			k_msleep(ENGINE_UPDATE_INTERVAL_MS);
713 			continue;
714 		}
715 
716 		for (i = 0; i < sock_nfds; i++) {
717 
718 			if (sock_ctx[i] != NULL && sock_ctx[i]->sock_fd < 0) {
719 				continue;
720 			}
721 
722 			if ((sock_fds[i].revents & ZSOCK_POLLERR) ||
723 			    (sock_fds[i].revents & ZSOCK_POLLNVAL) ||
724 			    (sock_fds[i].revents & ZSOCK_POLLHUP)) {
725 				LOG_ERR("Poll reported a socket error, %02x.", sock_fds[i].revents);
726 				if (sock_ctx[i] != NULL && sock_ctx[i]->fault_cb != NULL) {
727 					sock_ctx[i]->fault_cb(EIO);
728 				}
729 				continue;
730 			}
731 
732 			if (sock_fds[i].revents & ZSOCK_POLLIN) {
733 				while (sock_ctx[i]) {
734 					rc = socket_recv_message(sock_ctx[i]);
735 					if (rc) {
736 						break;
737 					}
738 				}
739 			}
740 
741 			if (sock_fds[i].revents & ZSOCK_POLLOUT) {
742 				rc = socket_send_message(sock_ctx[i]);
743 				/* Drop packets that cannot be send, CoAP layer handles retry */
744 				/* Other fatal errors should trigger a recovery */
745 				if (rc < 0 && rc != -EAGAIN) {
746 					LOG_ERR("send() reported a socket error, %d", -rc);
747 					if (sock_ctx[i] != NULL && sock_ctx[i]->fault_cb != NULL) {
748 						sock_ctx[i]->fault_cb(-rc);
749 					}
750 				}
751 			}
752 		}
753 	}
754 }
755 
756 #if defined(CONFIG_LWM2M_DTLS_SUPPORT) && defined(CONFIG_TLS_CREDENTIALS)
load_tls_credential(struct lwm2m_ctx * client_ctx,uint16_t res_id,enum tls_credential_type type)757 static int load_tls_credential(struct lwm2m_ctx *client_ctx, uint16_t res_id,
758 			       enum tls_credential_type type)
759 {
760 	int ret = 0;
761 	void *cred = NULL;
762 	uint16_t cred_len;
763 	uint8_t cred_flags;
764 
765 	/* ignore error value */
766 	tls_credential_delete(client_ctx->tls_tag, type);
767 
768 	ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, res_id), &cred, NULL,
769 				&cred_len, &cred_flags);
770 	if (ret < 0) {
771 		LOG_ERR("Unable to get resource data for %d/%d/%d", 0,  client_ctx->sec_obj_inst,
772 			res_id);
773 		return ret;
774 	}
775 
776 	if (cred_len == 0) {
777 		LOG_ERR("Credential data is empty");
778 		return -EINVAL;
779 	}
780 
781 	ret = tls_credential_add(client_ctx->tls_tag, type, cred, cred_len);
782 	if (ret < 0) {
783 		LOG_ERR("Error setting cred tag %d type %d: Error %d", client_ctx->tls_tag, type,
784 			ret);
785 	}
786 
787 	return ret;
788 }
789 #endif /* CONFIG_LWM2M_DTLS_SUPPORT && CONFIG_TLS_CREDENTIALS*/
790 
lwm2m_socket_start(struct lwm2m_ctx * client_ctx)791 int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
792 {
793 	socklen_t addr_len;
794 	int flags;
795 	int ret;
796 
797 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
798 	uint8_t tmp;
799 
800 	if (client_ctx->load_credentials) {
801 		ret = client_ctx->load_credentials(client_ctx);
802 		if (ret < 0) {
803 			return ret;
804 		}
805 	}
806 #if defined(CONFIG_TLS_CREDENTIALS)
807 	else {
808 		ret = load_tls_credential(client_ctx, 3, TLS_CREDENTIAL_PSK_ID);
809 		if (ret < 0) {
810 			return ret;
811 		}
812 
813 		ret = load_tls_credential(client_ctx, 5, TLS_CREDENTIAL_PSK);
814 		if (ret < 0) {
815 			return ret;
816 		}
817 	}
818 #endif /* CONFIG_TLS_CREDENTIALS */
819 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
820 
821 	if (client_ctx->sock_fd < 0) {
822 		ret = lwm2m_open_socket(client_ctx);
823 		if (ret) {
824 			return ret;
825 		}
826 	}
827 
828 	if (client_ctx->set_socketoptions) {
829 		ret = client_ctx->set_socketoptions(client_ctx);
830 		if (ret) {
831 			return ret;
832 		}
833 	}
834 #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
835 	else if (client_ctx->use_dtls) {
836 		sec_tag_t tls_tag_list[] = {
837 			client_ctx->tls_tag,
838 		};
839 
840 		ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, tls_tag_list,
841 				       sizeof(tls_tag_list));
842 		if (ret < 0) {
843 			ret = -errno;
844 			LOG_ERR("Failed to set TLS_SEC_TAG_LIST option: %d", ret);
845 			goto error;
846 		}
847 
848 		if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) {
849 			int session_cache = TLS_SESSION_CACHE_ENABLED;
850 
851 			ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SESSION_CACHE,
852 					       &session_cache, sizeof(session_cache));
853 			if (ret < 0) {
854 				ret = -errno;
855 				LOG_ERR("Failed to set TLS_SESSION_CACHE option: %d", errno);
856 				goto error;
857 			}
858 		}
859 
860 		if (client_ctx->hostname_verify && (client_ctx->desthostname != NULL)) {
861 			/** store character at len position */
862 			tmp = client_ctx->desthostname[client_ctx->desthostnamelen];
863 
864 			/** change it to '\0' to pass to socket*/
865 			client_ctx->desthostname[client_ctx->desthostnamelen] = '\0';
866 
867 			/** mbedtls ignores length */
868 			ret = zsock_setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_HOSTNAME,
869 					       client_ctx->desthostname,
870 					       client_ctx->desthostnamelen);
871 
872 			/** restore character */
873 			client_ctx->desthostname[client_ctx->desthostnamelen] = tmp;
874 			if (ret < 0) {
875 				ret = -errno;
876 				LOG_ERR("Failed to set TLS_HOSTNAME option: %d", ret);
877 				goto error;
878 			}
879 		}
880 	}
881 #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
882 	if ((client_ctx->remote_addr).sa_family == AF_INET) {
883 		addr_len = sizeof(struct sockaddr_in);
884 	} else if ((client_ctx->remote_addr).sa_family == AF_INET6) {
885 		addr_len = sizeof(struct sockaddr_in6);
886 	} else {
887 		ret = -EPROTONOSUPPORT;
888 		goto error;
889 	}
890 
891 	if (zsock_connect(client_ctx->sock_fd, &client_ctx->remote_addr, addr_len) < 0) {
892 		ret = -errno;
893 		LOG_ERR("Cannot connect UDP (%d)", ret);
894 		goto error;
895 	}
896 
897 	flags = zsock_fcntl(client_ctx->sock_fd, F_GETFL, 0);
898 	if (flags == -1) {
899 		ret = -errno;
900 		LOG_ERR("zsock_fcntl(F_GETFL) failed (%d)", ret);
901 		goto error;
902 	}
903 	ret = zsock_fcntl(client_ctx->sock_fd, F_SETFL, flags | O_NONBLOCK);
904 	if (ret == -1) {
905 		ret = -errno;
906 		LOG_ERR("zsock_fcntl(F_SETFL) failed (%d)", ret);
907 		goto error;
908 	}
909 
910 	LOG_INF("Connected, sock id %d", client_ctx->sock_fd);
911 	return 0;
912 error:
913 	lwm2m_socket_close(client_ctx);
914 	return ret;
915 }
916 
lwm2m_socket_close(struct lwm2m_ctx * client_ctx)917 int lwm2m_socket_close(struct lwm2m_ctx *client_ctx)
918 {
919 	int sock_fd = client_ctx->sock_fd;
920 
921 	lwm2m_socket_del(client_ctx);
922 	client_ctx->sock_fd = -1;
923 	if (sock_fd >= 0) {
924 		return zsock_close(sock_fd);
925 	}
926 
927 	return 0;
928 }
929 
lwm2m_engine_stop(struct lwm2m_ctx * client_ctx)930 int lwm2m_engine_stop(struct lwm2m_ctx *client_ctx)
931 {
932 	lwm2m_engine_context_close(client_ctx);
933 
934 	return lwm2m_socket_close(client_ctx);
935 }
936 
lwm2m_engine_start(struct lwm2m_ctx * client_ctx)937 int lwm2m_engine_start(struct lwm2m_ctx *client_ctx)
938 {
939 	char *url;
940 	uint16_t url_len;
941 	uint8_t url_data_flags;
942 	int ret = 0U;
943 
944 	/* get the server URL */
945 	ret = lwm2m_get_res_buf(&LWM2M_OBJ(0, client_ctx->sec_obj_inst, 0), (void **)&url, NULL,
946 				&url_len, &url_data_flags);
947 	if (ret < 0) {
948 		return ret;
949 	}
950 
951 	url[url_len] = '\0';
952 	ret = lwm2m_parse_peerinfo(url, client_ctx, false);
953 	if (ret < 0) {
954 		return ret;
955 	}
956 
957 	return lwm2m_socket_start(client_ctx);
958 }
959 
lwm2m_engine_pause(void)960 int lwm2m_engine_pause(void)
961 {
962 	if (suspend_engine_thread || !active_engine_thread) {
963 		LOG_WRN("Engine thread already suspended");
964 		return 0;
965 	}
966 
967 	suspend_engine_thread = true;
968 
969 	while (active_engine_thread) {
970 		k_msleep(10);
971 	}
972 	LOG_INF("LWM2M engine thread paused");
973 	return 0;
974 }
975 
lwm2m_engine_resume(void)976 int lwm2m_engine_resume(void)
977 {
978 	if (suspend_engine_thread || active_engine_thread) {
979 		LOG_WRN("LWM2M engine thread state not ok for resume");
980 		return -EPERM;
981 	}
982 
983 	k_thread_resume(engine_thread_id);
984 	while (!active_engine_thread) {
985 		k_msleep(10);
986 	}
987 	LOG_INF("LWM2M engine thread resume");
988 	return 0;
989 }
990 
lwm2m_engine_init(void)991 static int lwm2m_engine_init(void)
992 {
993 	int i;
994 
995 	for (i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) {
996 		sys_slist_append(lwm2m_obs_obj_path_list(), &observe_paths[i].node);
997 	}
998 
999 	lwm2m_clear_block_contexts();
1000 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
1001 	(void)memset(output_block_contexts, 0, sizeof(output_block_contexts));
1002 #endif
1003 
1004 	if (IS_ENABLED(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)) {
1005 		/* Init data cache */
1006 		lwm2m_engine_data_cache_init();
1007 	}
1008 
1009 	/* start sock receive thread */
1010 	engine_thread_id = k_thread_create(&engine_thread_data, &engine_thread_stack[0],
1011 			K_KERNEL_STACK_SIZEOF(engine_thread_stack), (k_thread_entry_t)socket_loop,
1012 			NULL, NULL, NULL, THREAD_PRIORITY, 0, K_NO_WAIT);
1013 	k_thread_name_set(&engine_thread_data, "lwm2m-sock-recv");
1014 	LOG_DBG("LWM2M engine socket receive thread started");
1015 	active_engine_thread = true;
1016 
1017 	return 0;
1018 }
1019 
1020 SYS_INIT(lwm2m_engine_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
1021