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