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