1 /*
2 * Copyright (c) 2017 Linaro Limited
3 * Copyright (c) 2017-2019 Foundries.io
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * Copyright (c) 2015, Yanzi Networks AB.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the copyright holder nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35 * OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Original authors:
40 * Joakim Eriksson <joakime@sics.se>
41 * Niclas Finne <nfi@sics.se>
42 * Joel Hoglund <joel@sics.se>
43 */
44
45 #define LOG_MODULE_NAME net_lwm2m_rd_client
46 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
47
48 #include <zephyr/logging/log.h>
49 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
50
51 #include <zephyr/types.h>
52 #include <stddef.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <errno.h>
56 #include <zephyr/init.h>
57 #include <zephyr/sys/printk.h>
58 #include <zephyr/net/socket.h>
59
60 #include "lwm2m_object.h"
61 #include "lwm2m_engine.h"
62 #include "lwm2m_rd_client.h"
63 #include "lwm2m_rw_link_format.h"
64 #include "lwm2m_util.h"
65
66 #define LWM2M_RD_CLIENT_URI "rd"
67
68 #define SECONDS_TO_UPDATE_EARLY CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY
69 #define STATE_MACHINE_UPDATE_INTERVAL_MS 500
70
71 #define CLIENT_EP_LEN CONFIG_LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH
72
73 #define CLIENT_BINDING_LEN sizeof("UQ")
74 #define CLIENT_QUEUE_LEN sizeof("Q")
75
76 static void sm_handle_registration_update_failure(void);
77 static int sm_send_registration_msg(void);
78 static bool sm_is_suspended(void);
79
80 /* The states for the RD client state machine */
81 /*
82 * When node is unregistered it ends up in UNREGISTERED
83 * and this is going to be there until use X or Y kicks it
84 * back into INIT again
85 */
86 enum sm_engine_state {
87 ENGINE_IDLE,
88 ENGINE_INIT,
89 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
90 ENGINE_DO_BOOTSTRAP_REG,
91 ENGINE_BOOTSTRAP_REG_SENT,
92 ENGINE_BOOTSTRAP_REG_DONE,
93 ENGINE_BOOTSTRAP_TRANS_DONE,
94 #endif
95 ENGINE_DO_REGISTRATION,
96 ENGINE_SEND_REGISTRATION,
97 ENGINE_REGISTRATION_SENT,
98 ENGINE_REGISTRATION_DONE,
99 ENGINE_REGISTRATION_DONE_RX_OFF,
100 ENGINE_UPDATE_REGISTRATION,
101 ENGINE_UPDATE_SENT,
102 ENGINE_SUSPENDED,
103 ENGINE_DEREGISTER,
104 ENGINE_DEREGISTER_SENT,
105 ENGINE_DEREGISTERED,
106 ENGINE_NETWORK_ERROR,
107 };
108
109 struct lwm2m_rd_client_info {
110 struct k_mutex mutex;
111 struct lwm2m_message rd_message;
112 struct lwm2m_ctx *ctx;
113 uint32_t lifetime;
114 uint8_t engine_state;
115 uint8_t retries;
116 uint8_t retry_delay;
117
118 int64_t last_update;
119 int64_t last_tx;
120
121 char ep_name[CLIENT_EP_LEN];
122 char server_ep[CLIENT_EP_LEN];
123
124 bool use_bootstrap : 1;
125
126 bool trigger_update : 1;
127 bool update_objects : 1;
128 bool close_socket : 1;
129 } client;
130
131 /* Allocate some data for queries and updates. Make sure it's large enough to
132 * hold the largest query string, which in most cases will be the endpoint
133 * string. In other case, 32 bytes are enough to encode any other query string
134 * documented in the LwM2M specification.
135 */
136 static char query_buffer[MAX(32, sizeof("ep=") + CLIENT_EP_LEN)];
137 static enum sm_engine_state suspended_client_state;
138
rd_get_message(void)139 static struct lwm2m_message *rd_get_message(void)
140 {
141 if (client.rd_message.ctx) {
142 /* Free old message */
143 lwm2m_reset_message(&client.rd_message, true);
144 }
145
146 client.rd_message.ctx = client.ctx;
147 return &client.rd_message;
148
149 }
150
rd_client_message_free(void)151 static void rd_client_message_free(void)
152 {
153 lwm2m_reset_message(lwm2m_get_ongoing_rd_msg(), true);
154 }
155
156
lwm2m_get_ongoing_rd_msg(void)157 struct lwm2m_message *lwm2m_get_ongoing_rd_msg(void)
158 {
159 if (!client.ctx || !client.rd_message.ctx) {
160 return NULL;
161 }
162 return &client.rd_message;
163 }
164
engine_update_tx_time(void)165 void engine_update_tx_time(void)
166 {
167 client.last_tx = k_uptime_get();
168 }
169
set_sm_state(uint8_t sm_state)170 static void set_sm_state(uint8_t sm_state)
171 {
172 k_mutex_lock(&client.mutex, K_FOREVER);
173 enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE;
174
175 /* Determine if a callback to the app is needed */
176 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
177 if (sm_state == ENGINE_BOOTSTRAP_REG_DONE) {
178 event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE;
179 } else if (client.engine_state == ENGINE_BOOTSTRAP_TRANS_DONE &&
180 sm_state == ENGINE_DO_REGISTRATION) {
181 event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE;
182 } else
183 #endif
184 if (client.engine_state == ENGINE_UPDATE_SENT &&
185 (sm_state == ENGINE_REGISTRATION_DONE ||
186 sm_state == ENGINE_REGISTRATION_DONE_RX_OFF)) {
187 lwm2m_push_queued_buffers(client.ctx);
188 event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE;
189 } else if (sm_state == ENGINE_REGISTRATION_DONE) {
190 lwm2m_push_queued_buffers(client.ctx);
191 event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE;
192 } else if (sm_state == ENGINE_REGISTRATION_DONE_RX_OFF) {
193 event = LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF;
194 } else if ((sm_state == ENGINE_INIT ||
195 sm_state == ENGINE_DEREGISTERED) &&
196 (client.engine_state >= ENGINE_DO_REGISTRATION &&
197 client.engine_state <= ENGINE_DEREGISTER_SENT)) {
198 event = LWM2M_RD_CLIENT_EVENT_DISCONNECT;
199 } else if (sm_state == ENGINE_NETWORK_ERROR) {
200 lwm2m_socket_close(client.ctx);
201 client.retry_delay = 1 << client.retries;
202 client.retries++;
203 if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) {
204 client.retries = 0;
205 event = LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR;
206 }
207 } else if (sm_state == ENGINE_UPDATE_REGISTRATION) {
208 event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE;
209 }
210
211 if (sm_is_suspended()) {
212 /* Just change the state where we are going to resume next */
213 suspended_client_state = sm_state;
214 } else {
215 client.engine_state = sm_state;
216 }
217
218 if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.ctx->event_cb) {
219 client.ctx->event_cb(client.ctx, event);
220 }
221
222 /* Suspend socket after Event callback */
223 if (event == LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF) {
224 if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUSPEND_SOCKET_AT_IDLE) ||
225 IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE)) {
226 lwm2m_socket_suspend(client.ctx);
227 } else if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_CLOSE_SOCKET_AT_IDLE)) {
228 lwm2m_close_socket(client.ctx);
229 }
230 }
231 k_mutex_unlock(&client.mutex);
232 }
233
sm_is_bootstrap(void)234 static bool sm_is_bootstrap(void)
235 {
236 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
237 k_mutex_lock(&client.mutex, K_FOREVER);
238 bool is_bootstrap = (client.engine_state >= ENGINE_DO_BOOTSTRAP_REG &&
239 client.engine_state <= ENGINE_BOOTSTRAP_TRANS_DONE);
240 k_mutex_unlock(&client.mutex);
241 return is_bootstrap;
242 #else
243 return false;
244 #endif
245 }
246
sm_is_registered(void)247 static bool sm_is_registered(void)
248 {
249 k_mutex_lock(&client.mutex, K_FOREVER);
250 bool registered = (client.engine_state >= ENGINE_REGISTRATION_DONE &&
251 client.engine_state <= ENGINE_DEREGISTER_SENT);
252
253 k_mutex_unlock(&client.mutex);
254 return registered;
255 }
256
sm_is_suspended(void)257 static bool sm_is_suspended(void)
258 {
259 k_mutex_lock(&client.mutex, K_FOREVER);
260 bool suspended = (client.engine_state == ENGINE_SUSPENDED);
261
262 k_mutex_unlock(&client.mutex);
263 return suspended;
264 }
265
266
get_sm_state(void)267 static uint8_t get_sm_state(void)
268 {
269 k_mutex_lock(&client.mutex, K_FOREVER);
270 uint8_t state = client.engine_state;
271
272 k_mutex_unlock(&client.mutex);
273 return state;
274 }
275
sm_handle_timeout_state(struct lwm2m_message * msg,enum sm_engine_state sm_state)276 static void sm_handle_timeout_state(struct lwm2m_message *msg,
277 enum sm_engine_state sm_state)
278 {
279 k_mutex_lock(&client.mutex, K_FOREVER);
280 enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE;
281
282 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
283 if (client.engine_state == ENGINE_BOOTSTRAP_REG_SENT) {
284 event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE;
285 } else
286 #endif
287 {
288 if (client.engine_state == ENGINE_REGISTRATION_SENT) {
289 event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT;
290 } else if (client.engine_state == ENGINE_UPDATE_SENT) {
291 event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT;
292 } else if (client.engine_state == ENGINE_DEREGISTER_SENT) {
293 event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE;
294 } else {
295 /* TODO: unknown timeout state */
296 }
297 }
298
299 set_sm_state(sm_state);
300
301 if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.ctx->event_cb) {
302 client.ctx->event_cb(client.ctx, event);
303 }
304 k_mutex_unlock(&client.mutex);
305 }
306
sm_handle_failure_state(enum sm_engine_state sm_state)307 static void sm_handle_failure_state(enum sm_engine_state sm_state)
308 {
309 k_mutex_lock(&client.mutex, K_FOREVER);
310 enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE;
311
312 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
313 if (client.engine_state == ENGINE_BOOTSTRAP_REG_SENT) {
314 event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE;
315 } else
316 #endif
317 if (client.engine_state == ENGINE_REGISTRATION_SENT) {
318 event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE;
319 } else if (client.engine_state == ENGINE_UPDATE_SENT) {
320 sm_handle_registration_update_failure();
321 k_mutex_unlock(&client.mutex);
322 return;
323 } else if (client.engine_state == ENGINE_DEREGISTER_SENT) {
324 event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE;
325 }
326
327 lwm2m_engine_stop(client.ctx);
328 set_sm_state(sm_state);
329
330 if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.ctx->event_cb) {
331 client.ctx->event_cb(client.ctx, event);
332 }
333 k_mutex_unlock(&client.mutex);
334 }
335
336 /* force state machine restart */
socket_fault_cb(int error)337 static void socket_fault_cb(int error)
338 {
339 LOG_ERR("RD Client socket error: %d", error);
340
341 if (sm_is_bootstrap()) {
342 client.ctx->sec_obj_inst = -1;
343 /* force full registration */
344 client.last_update = 0;
345 }
346
347 lwm2m_socket_close(client.ctx);
348
349 /* Network error state causes engine to re-register,
350 * so only trigger that state if we are not stopping the
351 * engine.
352 */
353 if (client.engine_state > ENGINE_IDLE &&
354 client.engine_state < ENGINE_SUSPENDED) {
355 set_sm_state(ENGINE_NETWORK_ERROR);
356 } else if (client.engine_state != ENGINE_SUSPENDED) {
357 sm_handle_failure_state(ENGINE_IDLE);
358 }
359 }
360
361 /* force re-update with remote peer */
engine_trigger_update(bool update_objects)362 void engine_trigger_update(bool update_objects)
363 {
364 k_mutex_lock(&client.mutex, K_FOREVER);
365 if (client.engine_state < ENGINE_REGISTRATION_SENT ||
366 client.engine_state > ENGINE_UPDATE_SENT) {
367 k_mutex_unlock(&client.mutex);
368 return;
369 }
370
371 client.trigger_update = true;
372
373 if (update_objects) {
374 client.update_objects = true;
375 }
376 k_mutex_unlock(&client.mutex);
377 }
378
code2str(uint8_t code)379 static inline const char *code2str(uint8_t code)
380 {
381 switch (code) {
382 case COAP_RESPONSE_CODE_BAD_REQUEST:
383 return "Bad Request";
384 case COAP_RESPONSE_CODE_FORBIDDEN:
385 return "Forbidden";
386 case COAP_RESPONSE_CODE_NOT_FOUND:
387 return "Not Found";
388 case COAP_RESPONSE_CODE_PRECONDITION_FAILED:
389 return "Precondition Failed";
390 default:
391 break;
392 }
393
394 return "Unknown";
395 }
396
397 /* state machine reply callbacks */
398
399 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
do_bootstrap_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)400 static int do_bootstrap_reply_cb(const struct coap_packet *response,
401 struct coap_reply *reply,
402 const struct sockaddr *from)
403 {
404 uint8_t code;
405
406 code = coap_header_get_code(response);
407 LOG_DBG("Bootstrap callback (code:%u.%u)",
408 COAP_RESPONSE_CODE_CLASS(code),
409 COAP_RESPONSE_CODE_DETAIL(code));
410
411 if (code == COAP_RESPONSE_CODE_CHANGED) {
412 LOG_INF("Bootstrap registration done!");
413 set_sm_state(ENGINE_BOOTSTRAP_REG_DONE);
414 return 0;
415 }
416
417 LOG_ERR("Failed with code %u.%u (%s). Not Retrying.",
418 COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
419 code2str(code));
420
421 sm_handle_failure_state(ENGINE_IDLE);
422
423 return 0;
424 }
425
do_bootstrap_reg_timeout_cb(struct lwm2m_message * msg)426 static void do_bootstrap_reg_timeout_cb(struct lwm2m_message *msg)
427 {
428 LOG_WRN("Bootstrap Timeout");
429
430 /* TODO:
431 * Look for the "next" BOOTSTRAP server entry in our security info
432 */
433
434 /* Restart from scratch */
435 sm_handle_timeout_state(msg, ENGINE_INIT);
436 }
437 #endif
438
engine_trigger_bootstrap(void)439 int engine_trigger_bootstrap(void)
440 {
441 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
442 k_mutex_lock(&client.mutex, K_FOREVER);
443
444 if (client.use_bootstrap) {
445 /* Bootstrap is not possible to trig */
446 LOG_WRN("Bootstrap process ongoing");
447 k_mutex_unlock(&client.mutex);
448 return -EPERM;
449 }
450 LOG_INF("Server Initiated Bootstrap");
451 /* Free ongoing possible message */
452 rd_client_message_free();
453 client.use_bootstrap = true;
454 client.trigger_update = false;
455 client.engine_state = ENGINE_INIT;
456 k_mutex_unlock(&client.mutex);
457 return 0;
458 #else
459 return -EPERM;
460 #endif
461 }
do_registration_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)462 static int do_registration_reply_cb(const struct coap_packet *response,
463 struct coap_reply *reply,
464 const struct sockaddr *from)
465 {
466 struct coap_option options[2];
467 uint8_t code;
468 int ret = -EINVAL;
469
470 code = coap_header_get_code(response);
471 LOG_DBG("Registration callback (code:%u.%u)",
472 COAP_RESPONSE_CODE_CLASS(code),
473 COAP_RESPONSE_CODE_DETAIL(code));
474
475 /* check state and possibly set registration to done */
476 if (code == COAP_RESPONSE_CODE_CREATED) {
477 ret = coap_find_options(response, COAP_OPTION_LOCATION_PATH,
478 options, 2);
479 if (ret < 2) {
480 LOG_ERR("Unexpected endpoint data returned. ret = %d", ret);
481 ret = -EINVAL;
482 goto fail;
483 }
484
485 /* option[0] should be "rd" */
486
487 if (options[1].len + 1 > sizeof(client.server_ep)) {
488 LOG_ERR("Unexpected length of query: "
489 "%u (expected %zu)\n",
490 options[1].len,
491 sizeof(client.server_ep));
492 ret = -EINVAL;
493 goto fail;
494 }
495
496 /* remember the last reg time */
497 client.last_update = k_uptime_get();
498
499 memcpy(client.server_ep, options[1].value,
500 options[1].len);
501 client.server_ep[options[1].len] = '\0';
502 set_sm_state(ENGINE_REGISTRATION_DONE);
503 LOG_INF("Registration Done (EP='%s')",
504 client.server_ep);
505
506 return 0;
507 } else if (code == COAP_RESPONSE_CODE_CONTINUE) {
508 #if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
509 return 0;
510 #else
511 LOG_ERR("Response code CONTINUE not supported");
512 #endif
513 }
514
515 LOG_ERR("Failed with code %u.%u (%s). Not Retrying.",
516 COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
517 code2str(code));
518 fail:
519 sm_handle_failure_state(ENGINE_IDLE);
520
521 return ret;
522 }
523
do_registration_timeout_cb(struct lwm2m_message * msg)524 static void do_registration_timeout_cb(struct lwm2m_message *msg)
525 {
526 LOG_WRN("Registration Timeout");
527
528 /* Restart from scratch */
529 sm_handle_timeout_state(msg, ENGINE_INIT);
530 }
531
do_update_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)532 static int do_update_reply_cb(const struct coap_packet *response,
533 struct coap_reply *reply,
534 const struct sockaddr *from)
535 {
536 uint8_t code;
537
538 code = coap_header_get_code(response);
539 LOG_INF("Update callback (code:%u.%u)",
540 COAP_RESPONSE_CODE_CLASS(code),
541 COAP_RESPONSE_CODE_DETAIL(code));
542
543 /* If NOT_FOUND just continue on */
544 if ((code == COAP_RESPONSE_CODE_CHANGED) ||
545 (code == COAP_RESPONSE_CODE_CREATED)) {
546 /* remember the last reg time */
547 client.last_update = k_uptime_get();
548 set_sm_state(ENGINE_REGISTRATION_DONE);
549 LOG_INF("Update Done");
550 return 0;
551 }
552
553 LOG_ERR("Failed with code %u.%u (%s). Retrying registration.",
554 COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
555 code2str(code));
556
557 sm_handle_failure_state(ENGINE_DO_REGISTRATION);
558
559 return 0;
560 }
561
do_update_timeout_cb(struct lwm2m_message * msg)562 static void do_update_timeout_cb(struct lwm2m_message *msg)
563 {
564 LOG_WRN("Registration Update Timeout");
565
566 if (client.ctx->sock_fd > -1) {
567 client.close_socket = true;
568 }
569 /* Re-do registration */
570 sm_handle_timeout_state(msg, ENGINE_DO_REGISTRATION);
571 }
572
do_deregister_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)573 static int do_deregister_reply_cb(const struct coap_packet *response,
574 struct coap_reply *reply,
575 const struct sockaddr *from)
576 {
577 uint8_t code;
578
579 code = coap_header_get_code(response);
580 LOG_DBG("Deregister callback (code:%u.%u)",
581 COAP_RESPONSE_CODE_CLASS(code),
582 COAP_RESPONSE_CODE_DETAIL(code));
583
584 if (code == COAP_RESPONSE_CODE_DELETED) {
585 LOG_INF("Deregistration success");
586 set_sm_state(ENGINE_DEREGISTERED);
587 return 0;
588 }
589
590 LOG_ERR("Failed with code %u.%u (%s). Not Retrying",
591 COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
592 code2str(code));
593
594 sm_handle_failure_state(ENGINE_IDLE);
595
596 return 0;
597 }
598
do_deregister_timeout_cb(struct lwm2m_message * msg)599 static void do_deregister_timeout_cb(struct lwm2m_message *msg)
600 {
601 LOG_WRN("De-Registration Timeout");
602
603 sm_handle_timeout_state(msg, ENGINE_IDLE);
604 }
605
sm_bootstrap_verify(bool bootstrap_server,int sec_obj_inst)606 static bool sm_bootstrap_verify(bool bootstrap_server, int sec_obj_inst)
607 {
608 bool bootstrap;
609 int ret;
610
611 ret = lwm2m_get_bool(&LWM2M_OBJ(0, sec_obj_inst, 1), &bootstrap);
612 if (ret < 0) {
613 LOG_WRN("Failed to check bootstrap, err %d", ret);
614 return false;
615 }
616
617 if (bootstrap == bootstrap_server) {
618 return true;
619 } else {
620 return false;
621 }
622 }
623
sm_update_lifetime(int srv_obj_inst,uint32_t * lifetime)624 static bool sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime)
625 {
626 uint32_t new_lifetime;
627
628 if (lwm2m_get_u32(&LWM2M_OBJ(1, srv_obj_inst, 1), &new_lifetime) < 0) {
629 new_lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME;
630 LOG_INF("Using default lifetime: %u", new_lifetime);
631 }
632
633 if (new_lifetime < CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME) {
634 new_lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME;
635 lwm2m_set_u32(&LWM2M_OBJ(1, srv_obj_inst, 1), new_lifetime);
636 LOG_INF("Overwrite a server lifetime with default");
637 }
638
639 if (new_lifetime != *lifetime) {
640 *lifetime = new_lifetime;
641 return true;
642 }
643
644 return false;
645 }
646
sm_select_server_inst(int sec_obj_inst,int * srv_obj_inst,uint32_t * lifetime)647 static int sm_select_server_inst(int sec_obj_inst, int *srv_obj_inst,
648 uint32_t *lifetime)
649 {
650 uint16_t server_id;
651 int ret, obj_inst_id;
652
653 ret = lwm2m_get_u16(&LWM2M_OBJ(0, sec_obj_inst, 10), &server_id);
654 if (ret < 0) {
655 LOG_WRN("Failed to obtain Short Server ID, err %d", ret);
656 return -EINVAL;
657 }
658
659 obj_inst_id = lwm2m_server_short_id_to_inst(server_id);
660 if (obj_inst_id < 0) {
661 LOG_WRN("Failed to obtain Server Object instance, err %d",
662 obj_inst_id);
663 return -EINVAL;
664 }
665
666 sm_update_lifetime(obj_inst_id, lifetime);
667 *srv_obj_inst = obj_inst_id;
668
669 return 0;
670 }
671
sm_select_security_inst(bool bootstrap_server,int * sec_obj_inst)672 static int sm_select_security_inst(bool bootstrap_server, int *sec_obj_inst)
673 {
674 int i, obj_inst_id = -1;
675
676 /* lookup existing index */
677 i = lwm2m_security_inst_id_to_index(*sec_obj_inst);
678 if (i >= 0 && sm_bootstrap_verify(bootstrap_server, *sec_obj_inst)) {
679 return 0;
680 }
681
682 *sec_obj_inst = -1;
683
684 /* Iterate over all instances to find the correct one. */
685 for (i = 0; i < CONFIG_LWM2M_SECURITY_INSTANCE_COUNT; i++) {
686 obj_inst_id = lwm2m_security_index_to_inst_id(i);
687 if (obj_inst_id < 0) {
688 LOG_WRN("Failed to get inst id for %d", i);
689 continue;
690 }
691
692 if (sm_bootstrap_verify(bootstrap_server, obj_inst_id)) {
693 *sec_obj_inst = obj_inst_id;
694 return 0;
695 }
696 }
697
698 LOG_WRN("sec_obj_inst: No matching servers found.");
699
700 return -ENOENT;
701 }
702
703 /* state machine step functions */
704
sm_do_init(void)705 static int sm_do_init(void)
706 {
707 lwm2m_engine_stop(client.ctx);
708 client.ctx->sec_obj_inst = -1;
709 client.ctx->srv_obj_inst = -1;
710 client.trigger_update = false;
711 client.lifetime = 0U;
712 client.retries = 0U;
713 client.last_update = 0U;
714 client.close_socket = false;
715
716 /* Do bootstrap or registration */
717 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
718 if (client.use_bootstrap) {
719 set_sm_state(ENGINE_DO_BOOTSTRAP_REG);
720 } else {
721 set_sm_state(ENGINE_DO_REGISTRATION);
722 }
723 #else
724 set_sm_state(ENGINE_DO_REGISTRATION);
725 #endif
726 return 0;
727 }
728
729 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
sm_send_bootstrap_registration(void)730 static int sm_send_bootstrap_registration(void)
731 {
732 struct lwm2m_message *msg;
733 int ret;
734
735 msg = rd_get_message();
736 if (!msg) {
737 LOG_ERR("Unable to get a lwm2m message!");
738 return -ENOMEM;
739 }
740
741 msg->type = COAP_TYPE_CON;
742 msg->code = COAP_METHOD_POST;
743 msg->mid = coap_next_id();
744 msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
745 msg->reply_cb = do_bootstrap_reply_cb;
746 msg->message_timeout_cb = do_bootstrap_reg_timeout_cb;
747
748 ret = lwm2m_init_message(msg);
749 if (ret) {
750 goto cleanup;
751 }
752
753 /* TODO: handle return error */
754 coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
755 "bs", strlen("bs"));
756
757 snprintk(query_buffer, sizeof(query_buffer) - 1, "ep=%s",
758 client.ep_name);
759 /* TODO: handle return error */
760 coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY,
761 query_buffer, strlen(query_buffer));
762
763
764 if (IS_ENABLED(CONFIG_LWM2M_VERSION_1_1)) {
765 int pct = LWM2M_FORMAT_OMA_TLV;
766
767 if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT)) {
768 pct = LWM2M_FORMAT_APP_SENML_CBOR;
769 } else if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)) {
770 pct = LWM2M_FORMAT_APP_SEML_JSON;
771 }
772
773 snprintk(query_buffer, sizeof(query_buffer) - 1, "pct=%d", pct);
774
775 coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY,
776 query_buffer, strlen(query_buffer));
777 }
778
779 /* log the bootstrap attempt */
780 LOG_DBG("Register ID with bootstrap server as '%s'",
781 query_buffer);
782
783 lwm2m_send_message_async(msg);
784
785 return 0;
786
787 cleanup:
788 lwm2m_reset_message(msg, true);
789 return ret;
790 }
791
sm_do_bootstrap_reg(void)792 static int sm_do_bootstrap_reg(void)
793 {
794 int ret;
795
796 /* clear out existing connection data */
797 if (client.ctx->sock_fd > -1) {
798 lwm2m_engine_stop(client.ctx);
799 }
800
801 client.ctx->bootstrap_mode = true;
802 ret = sm_select_security_inst(client.ctx->bootstrap_mode,
803 &client.ctx->sec_obj_inst);
804 if (ret < 0) {
805 /* no bootstrap server found, let's move to registration */
806 LOG_WRN("Bootstrap server not found! Try normal registration.");
807 set_sm_state(ENGINE_DO_REGISTRATION);
808 return ret;
809 }
810
811 LOG_INF("Bootstrap started with endpoint '%s' with client lifetime %d",
812 client.ep_name, client.lifetime);
813
814 ret = lwm2m_engine_start(client.ctx);
815 if (ret < 0) {
816 LOG_ERR("Cannot init LWM2M engine (%d)", ret);
817 set_sm_state(ENGINE_NETWORK_ERROR);
818 return ret;
819 }
820
821 ret = sm_send_bootstrap_registration();
822 if (!ret) {
823 set_sm_state(ENGINE_BOOTSTRAP_REG_SENT);
824 } else {
825 LOG_ERR("Bootstrap registration err: %d", ret);
826 set_sm_state(ENGINE_NETWORK_ERROR);
827 }
828
829 return ret;
830 }
831
engine_bootstrap_finish(void)832 void engine_bootstrap_finish(void)
833 {
834 LOG_INF("Bootstrap data transfer done!");
835 set_sm_state(ENGINE_BOOTSTRAP_TRANS_DONE);
836 }
837
sm_bootstrap_trans_done(void)838 static int sm_bootstrap_trans_done(void)
839 {
840 /* close down context resources */
841 lwm2m_engine_stop(client.ctx);
842
843 /* reset security object instance */
844 client.ctx->sec_obj_inst = -1;
845 client.use_bootstrap = false;
846
847 set_sm_state(ENGINE_DO_REGISTRATION);
848
849 return 0;
850 }
851 #endif
852
sm_send_registration(bool send_obj_support_data,coap_reply_t reply_cb,lwm2m_message_timeout_cb_t timeout_cb)853 static int sm_send_registration(bool send_obj_support_data,
854 coap_reply_t reply_cb,
855 lwm2m_message_timeout_cb_t timeout_cb)
856 {
857 struct lwm2m_message *msg;
858 int ret;
859 char binding[CLIENT_BINDING_LEN];
860 char queue[CLIENT_QUEUE_LEN];
861
862 msg = rd_get_message();
863 if (!msg) {
864 LOG_ERR("Unable to get a lwm2m message!");
865 return -ENOMEM;
866 }
867
868 msg->type = COAP_TYPE_CON;
869 msg->code = COAP_METHOD_POST;
870 msg->mid = coap_next_id();
871 msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
872 msg->reply_cb = reply_cb;
873 msg->message_timeout_cb = timeout_cb;
874
875 ret = lwm2m_init_message(msg);
876 if (ret) {
877 goto cleanup;
878 }
879
880 ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
881 LWM2M_RD_CLIENT_URI,
882 strlen(LWM2M_RD_CLIENT_URI));
883 if (ret < 0) {
884 goto cleanup;
885 }
886
887 if (sm_is_registered()) {
888 ret = coap_packet_append_option(
889 &msg->cpkt, COAP_OPTION_URI_PATH,
890 client.server_ep, strlen(client.server_ep));
891 if (ret < 0) {
892 goto cleanup;
893 }
894 }
895
896 if (send_obj_support_data) {
897 ret = coap_append_option_int(
898 &msg->cpkt, COAP_OPTION_CONTENT_FORMAT,
899 LWM2M_FORMAT_APP_LINK_FORMAT);
900 if (ret < 0) {
901 goto cleanup;
902 }
903 }
904
905 if (!sm_is_registered()) {
906 snprintk(query_buffer, sizeof(query_buffer) - 1,
907 "lwm2m=%s", LWM2M_PROTOCOL_VERSION_STRING);
908 ret = coap_packet_append_option(
909 &msg->cpkt, COAP_OPTION_URI_QUERY,
910 query_buffer, strlen(query_buffer));
911 if (ret < 0) {
912 goto cleanup;
913 }
914
915 snprintk(query_buffer, sizeof(query_buffer) - 1,
916 "ep=%s", client.ep_name);
917 ret = coap_packet_append_option(
918 &msg->cpkt, COAP_OPTION_URI_QUERY,
919 query_buffer, strlen(query_buffer));
920 if (ret < 0) {
921 goto cleanup;
922 }
923 }
924
925 /* Send lifetime only if changed or on initial registration.*/
926 if (sm_update_lifetime(client.ctx->srv_obj_inst, &client.lifetime) ||
927 !sm_is_registered()) {
928 snprintk(query_buffer, sizeof(query_buffer) - 1,
929 "lt=%d", client.lifetime);
930 ret = coap_packet_append_option(
931 &msg->cpkt, COAP_OPTION_URI_QUERY,
932 query_buffer, strlen(query_buffer));
933 if (ret < 0) {
934 goto cleanup;
935 }
936 }
937
938 lwm2m_engine_get_binding(binding);
939 lwm2m_engine_get_queue_mode(queue);
940 /* UDP is a default binding, no need to add option if UDP without queue is used. */
941 if ((!sm_is_registered() && (strcmp(binding, "U") != 0 || strcmp(queue, "Q") == 0))) {
942 snprintk(query_buffer, sizeof(query_buffer) - 1,
943 "b=%s", binding);
944
945 ret = coap_packet_append_option(
946 &msg->cpkt, COAP_OPTION_URI_QUERY,
947 query_buffer, strlen(query_buffer));
948 if (ret < 0) {
949 goto cleanup;
950 }
951
952 #if CONFIG_LWM2M_VERSION_1_1
953 /* In LwM2M 1.1, queue mode is a separate parameter */
954 uint16_t len = strlen(queue);
955
956 if (len) {
957 ret = coap_packet_append_option(
958 &msg->cpkt, COAP_OPTION_URI_QUERY,
959 queue, len);
960 if (ret < 0) {
961 goto cleanup;
962 }
963 }
964 #endif
965 }
966
967 if (send_obj_support_data) {
968 ret = coap_packet_append_payload_marker(&msg->cpkt);
969 if (ret < 0) {
970 goto cleanup;
971 }
972
973 msg->out.out_cpkt = &msg->cpkt;
974 msg->out.writer = &link_format_writer;
975
976 ret = do_register_op_link_format(msg);
977 if (ret < 0) {
978 goto cleanup;
979 }
980 }
981
982 lwm2m_send_message_async(msg);
983
984 /* log the registration attempt */
985 LOG_DBG("registration sent [%s]",
986 lwm2m_sprint_ip_addr(&client.ctx->remote_addr));
987
988 return 0;
989
990 cleanup:
991 LOG_ERR("error %d when sending registration message", ret);
992 lwm2m_reset_message(msg, true);
993 return ret;
994 }
995
sm_handle_registration_update_failure(void)996 static void sm_handle_registration_update_failure(void)
997 {
998 k_mutex_lock(&client.mutex, K_FOREVER);
999 LOG_WRN("Registration Update fail -> trigger full registration");
1000 client.engine_state = ENGINE_SEND_REGISTRATION;
1001 lwm2m_engine_context_close(client.ctx);
1002 k_mutex_unlock(&client.mutex);
1003 }
1004
sm_send_registration_msg(void)1005 static int sm_send_registration_msg(void)
1006 {
1007 int ret;
1008
1009 ret = sm_send_registration(true,
1010 do_registration_reply_cb,
1011 do_registration_timeout_cb);
1012 if (!ret) {
1013 set_sm_state(ENGINE_REGISTRATION_SENT);
1014 } else {
1015 LOG_ERR("Registration err: %d", ret);
1016 set_sm_state(ENGINE_NETWORK_ERROR);
1017 }
1018
1019 return ret;
1020 }
1021
sm_do_registration(void)1022 static int sm_do_registration(void)
1023 {
1024 int ret = 0;
1025
1026 if (client.ctx->connection_suspended) {
1027 if (lwm2m_engine_connection_resume(client.ctx)) {
1028 lwm2m_engine_context_close(client.ctx);
1029 /* perform full registration */
1030 set_sm_state(ENGINE_DO_REGISTRATION);
1031 return 0;
1032 }
1033
1034 } else {
1035 /* clear out existing connection data */
1036 if (client.ctx->sock_fd > -1) {
1037 if (client.close_socket) {
1038 /* Clear old socket connection */
1039 client.close_socket = false;
1040 lwm2m_engine_stop(client.ctx);
1041 } else {
1042 lwm2m_engine_context_close(client.ctx);
1043 }
1044 }
1045
1046 client.last_update = 0;
1047
1048 client.ctx->bootstrap_mode = false;
1049 ret = sm_select_security_inst(client.ctx->bootstrap_mode,
1050 &client.ctx->sec_obj_inst);
1051 if (ret < 0) {
1052 LOG_ERR("Unable to find a valid security instance.");
1053 set_sm_state(ENGINE_INIT);
1054 return -EINVAL;
1055 }
1056
1057 ret = sm_select_server_inst(client.ctx->sec_obj_inst,
1058 &client.ctx->srv_obj_inst,
1059 &client.lifetime);
1060 if (ret < 0) {
1061 LOG_ERR("Unable to find a valid server instance.");
1062 set_sm_state(ENGINE_INIT);
1063 return -EINVAL;
1064 }
1065
1066 LOG_INF("RD Client started with endpoint '%s' with client lifetime %d",
1067 client.ep_name, client.lifetime);
1068
1069 ret = lwm2m_engine_start(client.ctx);
1070 if (ret < 0) {
1071 LOG_ERR("Cannot init LWM2M engine (%d)", ret);
1072 set_sm_state(ENGINE_NETWORK_ERROR);
1073 return ret;
1074 }
1075 }
1076
1077 ret = sm_send_registration_msg();
1078
1079 return ret;
1080 }
1081
sm_registration_done(void)1082 static int sm_registration_done(void)
1083 {
1084 k_mutex_lock(&client.mutex, K_FOREVER);
1085 int ret = 0;
1086
1087 /*
1088 * check for lifetime seconds - SECONDS_TO_UPDATE_EARLY
1089 * so that we can update early and avoid lifetime timeout
1090 */
1091 if (sm_is_registered() &&
1092 (client.trigger_update ||
1093 ((client.lifetime - SECONDS_TO_UPDATE_EARLY) <=
1094 (k_uptime_get() - client.last_update) / 1000))) {
1095 set_sm_state(ENGINE_UPDATE_REGISTRATION);
1096 } else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) &&
1097 (client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) &&
1098 (((k_uptime_get() - client.last_tx) / 1000) >=
1099 CONFIG_LWM2M_QUEUE_MODE_UPTIME)) {
1100 set_sm_state(ENGINE_REGISTRATION_DONE_RX_OFF);
1101 }
1102 k_mutex_unlock(&client.mutex);
1103 return ret;
1104 }
1105
update_registration(void)1106 static int update_registration(void)
1107 {
1108 int ret;
1109 bool update_objects;
1110
1111 update_objects = client.update_objects;
1112 client.trigger_update = false;
1113 client.update_objects = false;
1114
1115 ret = lwm2m_engine_connection_resume(client.ctx);
1116 if (ret) {
1117 return ret;
1118 }
1119
1120 ret = sm_send_registration(update_objects,
1121 do_update_reply_cb,
1122 do_update_timeout_cb);
1123 if (ret) {
1124 LOG_ERR("Registration update err: %d", ret);
1125 return ret;
1126 }
1127
1128 return 0;
1129 }
1130
sm_update_registration(void)1131 static int sm_update_registration(void)
1132 {
1133 int ret;
1134
1135 ret = update_registration();
1136 if (ret) {
1137 LOG_ERR("Failed to update registration. Falling back to full registration");
1138
1139 lwm2m_engine_stop(client.ctx);
1140 /* perform full registration */
1141 set_sm_state(ENGINE_DO_REGISTRATION);
1142 return ret;
1143 }
1144
1145 set_sm_state(ENGINE_UPDATE_SENT);
1146
1147 return 0;
1148 }
1149
sm_do_deregister(void)1150 static int sm_do_deregister(void)
1151 {
1152 struct lwm2m_message *msg;
1153 int ret;
1154
1155 if (lwm2m_engine_connection_resume(client.ctx)) {
1156 lwm2m_engine_context_close(client.ctx);
1157 /* Connection failed, enter directly to deregistered state */
1158 set_sm_state(ENGINE_DEREGISTERED);
1159 return 0;
1160 }
1161
1162 msg = rd_get_message();
1163 if (!msg) {
1164 LOG_ERR("Unable to get a lwm2m message!");
1165 ret = -ENOMEM;
1166 goto close_ctx;
1167 }
1168
1169 msg->type = COAP_TYPE_CON;
1170 msg->code = COAP_METHOD_DELETE;
1171 msg->mid = coap_next_id();
1172 msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
1173 msg->reply_cb = do_deregister_reply_cb;
1174 msg->message_timeout_cb = do_deregister_timeout_cb;
1175
1176 ret = lwm2m_init_message(msg);
1177 if (ret) {
1178 goto cleanup;
1179 }
1180
1181 ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
1182 LWM2M_RD_CLIENT_URI,
1183 strlen(LWM2M_RD_CLIENT_URI));
1184 if (ret < 0) {
1185 LOG_ERR("Failed to encode URI path option (err:%d).", ret);
1186 goto cleanup;
1187 }
1188
1189 /* include server endpoint in URI PATH */
1190 ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
1191 client.server_ep,
1192 strlen(client.server_ep));
1193 if (ret < 0) {
1194 LOG_ERR("Failed to encode URI path option (err:%d).", ret);
1195 goto cleanup;
1196 }
1197
1198 LOG_INF("Deregister from '%s'", client.server_ep);
1199
1200 lwm2m_send_message_async(msg);
1201
1202 set_sm_state(ENGINE_DEREGISTER_SENT);
1203 return 0;
1204
1205 cleanup:
1206 lwm2m_reset_message(msg, true);
1207 close_ctx:
1208 lwm2m_engine_stop(client.ctx);
1209 set_sm_state(ENGINE_DEREGISTERED);
1210 return ret;
1211 }
1212
sm_do_network_error(void)1213 static void sm_do_network_error(void)
1214 {
1215 int err;
1216
1217 if (--client.retry_delay > 0) {
1218 return;
1219 }
1220
1221 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
1222 if (client.ctx->bootstrap_mode) {
1223 lwm2m_engine_context_close(client.ctx);
1224 set_sm_state(ENGINE_DO_BOOTSTRAP_REG);
1225 return;
1226 }
1227 #endif
1228
1229 if (!client.last_update || (k_uptime_get() - client.last_update) / 1000 > client.lifetime) {
1230 /* do full registration as there is no active registration or lifetime exceeded */
1231 lwm2m_engine_context_close(client.ctx);
1232 set_sm_state(ENGINE_DO_REGISTRATION);
1233 return;
1234 }
1235
1236 err = lwm2m_socket_start(client.ctx);
1237 if (err) {
1238 LOG_ERR("Failed to start socket %d", err);
1239 /*
1240 * keep this state until lifetime/retry count exceeds. Renew
1241 * sm state to set retry_delay etc ...
1242 */
1243 set_sm_state(ENGINE_NETWORK_ERROR);
1244 return;
1245 }
1246
1247 set_sm_state(ENGINE_UPDATE_REGISTRATION);
1248 }
1249
lwm2m_rd_client_service(struct k_work * work)1250 static void lwm2m_rd_client_service(struct k_work *work)
1251 {
1252 k_mutex_lock(&client.mutex, K_FOREVER);
1253
1254 if (client.ctx) {
1255 switch (get_sm_state()) {
1256 case ENGINE_IDLE:
1257 if (client.ctx->sock_fd > -1) {
1258 lwm2m_engine_stop(client.ctx);
1259 }
1260 rd_client_message_free();
1261 break;
1262
1263 case ENGINE_INIT:
1264 sm_do_init();
1265 break;
1266
1267 case ENGINE_SUSPENDED:
1268 break;
1269
1270 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
1271 case ENGINE_DO_BOOTSTRAP_REG:
1272 sm_do_bootstrap_reg();
1273 break;
1274
1275 case ENGINE_BOOTSTRAP_REG_SENT:
1276 /* wait for bootstrap registration done */
1277 break;
1278
1279 case ENGINE_BOOTSTRAP_REG_DONE:
1280 /* wait for transfer done */
1281 break;
1282
1283 case ENGINE_BOOTSTRAP_TRANS_DONE:
1284 sm_bootstrap_trans_done();
1285 break;
1286 #endif
1287
1288 case ENGINE_DO_REGISTRATION:
1289 sm_do_registration();
1290 break;
1291
1292 case ENGINE_SEND_REGISTRATION:
1293 sm_send_registration_msg();
1294 break;
1295
1296 case ENGINE_REGISTRATION_SENT:
1297 /* wait registration to be done or timeout */
1298 break;
1299
1300 case ENGINE_REGISTRATION_DONE:
1301 case ENGINE_REGISTRATION_DONE_RX_OFF:
1302 sm_registration_done();
1303 break;
1304
1305 case ENGINE_UPDATE_REGISTRATION:
1306 sm_update_registration();
1307 break;
1308
1309 case ENGINE_UPDATE_SENT:
1310 /* wait update to be done or abort */
1311 break;
1312
1313 case ENGINE_DEREGISTER:
1314 sm_do_deregister();
1315 break;
1316
1317 case ENGINE_DEREGISTER_SENT:
1318 /* wait for deregister to be done or reset */
1319 break;
1320
1321 case ENGINE_DEREGISTERED:
1322 lwm2m_engine_stop(client.ctx);
1323 set_sm_state(ENGINE_IDLE);
1324 break;
1325
1326 case ENGINE_NETWORK_ERROR:
1327 sm_do_network_error();
1328 break;
1329
1330 default:
1331 LOG_ERR("Unhandled state: %d", get_sm_state());
1332
1333 }
1334 }
1335
1336 k_mutex_unlock(&client.mutex);
1337 }
1338
lwm2m_rd_client_start(struct lwm2m_ctx * client_ctx,const char * ep_name,uint32_t flags,lwm2m_ctx_event_cb_t event_cb,lwm2m_observe_cb_t observe_cb)1339 int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name,
1340 uint32_t flags, lwm2m_ctx_event_cb_t event_cb,
1341 lwm2m_observe_cb_t observe_cb)
1342 {
1343 k_mutex_lock(&client.mutex, K_FOREVER);
1344
1345 if (!IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) &&
1346 (flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP)) {
1347 LOG_ERR("Bootstrap support is disabled. Please enable "
1348 "CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP.");
1349
1350 k_mutex_unlock(&client.mutex);
1351 return -ENOTSUP;
1352 }
1353
1354 /* Check client idle state or socket is still active */
1355
1356 if (client.ctx && (client.engine_state != ENGINE_IDLE || client.ctx->sock_fd != -1)) {
1357 LOG_WRN("Client is already running. state %d ", client.engine_state);
1358 k_mutex_unlock(&client.mutex);
1359 return -EINPROGRESS;
1360 }
1361
1362 /* Init Context */
1363 lwm2m_engine_context_init(client_ctx);
1364
1365 client.ctx = client_ctx;
1366 client.ctx->sock_fd = -1;
1367 client.ctx->fault_cb = socket_fault_cb;
1368 client.ctx->observe_cb = observe_cb;
1369 client.ctx->event_cb = event_cb;
1370 client.use_bootstrap = flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP;
1371
1372 set_sm_state(ENGINE_INIT);
1373 strncpy(client.ep_name, ep_name, CLIENT_EP_LEN - 1);
1374 client.ep_name[CLIENT_EP_LEN - 1] = '\0';
1375 LOG_INF("Start LWM2M Client: %s", client.ep_name);
1376
1377 k_mutex_unlock(&client.mutex);
1378 return 0;
1379 }
1380
lwm2m_rd_client_stop(struct lwm2m_ctx * client_ctx,lwm2m_ctx_event_cb_t event_cb,bool deregister)1381 int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx,
1382 lwm2m_ctx_event_cb_t event_cb, bool deregister)
1383 {
1384 k_mutex_lock(&client.mutex, K_FOREVER);
1385
1386 if (client.ctx != client_ctx) {
1387 k_mutex_unlock(&client.mutex);
1388 LOG_WRN("Cannot stop. Wrong context");
1389 return -EPERM;
1390 }
1391
1392 client.ctx->event_cb = event_cb;
1393 rd_client_message_free();
1394
1395 if (sm_is_registered() && deregister) {
1396 set_sm_state(ENGINE_DEREGISTER);
1397 } else {
1398 set_sm_state(ENGINE_DEREGISTERED);
1399 }
1400
1401 LOG_INF("Stop LWM2M Client: %s", client.ep_name);
1402
1403 k_mutex_unlock(&client.mutex);
1404
1405 return 0;
1406 }
1407
lwm2m_rd_client_pause(void)1408 int lwm2m_rd_client_pause(void)
1409 {
1410 enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED;
1411
1412 k_mutex_lock(&client.mutex, K_FOREVER);
1413
1414 if (!client.ctx) {
1415 k_mutex_unlock(&client.mutex);
1416 LOG_ERR("Cannot pause. No context");
1417 return -EPERM;
1418 } else if (client.engine_state == ENGINE_SUSPENDED) {
1419 k_mutex_unlock(&client.mutex);
1420 LOG_ERR("LwM2M client already suspended");
1421 return 0;
1422 }
1423
1424 LOG_INF("Suspend client");
1425 if (!client.ctx->connection_suspended && client.ctx->event_cb) {
1426 client.ctx->event_cb(client.ctx, event);
1427 }
1428
1429 suspended_client_state = get_sm_state();
1430 client.engine_state = ENGINE_SUSPENDED;
1431
1432 k_mutex_unlock(&client.mutex);
1433
1434 return 0;
1435 }
1436
lwm2m_rd_client_resume(void)1437 int lwm2m_rd_client_resume(void)
1438 {
1439 int ret;
1440
1441 k_mutex_lock(&client.mutex, K_FOREVER);
1442
1443 if (!client.ctx) {
1444 k_mutex_unlock(&client.mutex);
1445 LOG_WRN("Cannot resume. No context");
1446 return -EPERM;
1447 }
1448
1449 if (client.engine_state != ENGINE_SUSPENDED) {
1450 k_mutex_unlock(&client.mutex);
1451 LOG_WRN("Cannot resume state is not Suspended");
1452 return -EPERM;
1453 }
1454
1455 LOG_INF("Resume Client state");
1456 lwm2m_close_socket(client.ctx);
1457 if (suspended_client_state == ENGINE_UPDATE_SENT) {
1458 /* Set back to Registration done for enable trigger Update */
1459 suspended_client_state = ENGINE_REGISTRATION_DONE;
1460 }
1461 /* Clear Possible pending RD Client message */
1462 rd_client_message_free();
1463
1464 client.engine_state = suspended_client_state;
1465
1466 if (!client.last_update ||
1467 (client.lifetime <= (k_uptime_get() - client.last_update) / 1000)) {
1468 client.engine_state = ENGINE_DO_REGISTRATION;
1469 } else {
1470 lwm2m_rd_client_connection_resume(client.ctx);
1471 client.trigger_update = true;
1472 }
1473
1474 ret = lwm2m_open_socket(client.ctx);
1475 if (ret) {
1476 LOG_ERR("Socket Open Fail");
1477 client.engine_state = ENGINE_INIT;
1478 }
1479
1480 k_mutex_unlock(&client.mutex);
1481
1482 return 0;
1483 }
1484
lwm2m_rd_client_update(void)1485 void lwm2m_rd_client_update(void)
1486 {
1487 engine_trigger_update(false);
1488 }
1489
lwm2m_rd_client_ctx(void)1490 struct lwm2m_ctx *lwm2m_rd_client_ctx(void)
1491 {
1492 return client.ctx;
1493 }
1494
lwm2m_rd_client_connection_resume(struct lwm2m_ctx * client_ctx)1495 int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx)
1496 {
1497 if (client.ctx != client_ctx) {
1498 return -EPERM;
1499 }
1500
1501 if (client.engine_state == ENGINE_REGISTRATION_DONE_RX_OFF) {
1502 #ifdef CONFIG_LWM2M_DTLS_SUPPORT
1503 /*
1504 * Switch state for triggering a proper registration message
1505 * if CONFIG_LWM2M_TLS_SESSION_CACHING is false we force full
1506 * registration after Fully DTLS handshake
1507 */
1508 if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) {
1509 client.engine_state = ENGINE_REGISTRATION_DONE;
1510 client.trigger_update = true;
1511 } else {
1512 client.engine_state = ENGINE_DO_REGISTRATION;
1513 }
1514 #else
1515 client.engine_state = ENGINE_REGISTRATION_DONE;
1516 client.trigger_update = true;
1517 #endif
1518 }
1519
1520 return 0;
1521 }
1522
lwm2m_rd_client_timeout(struct lwm2m_ctx * client_ctx)1523 int lwm2m_rd_client_timeout(struct lwm2m_ctx *client_ctx)
1524 {
1525 if (client.ctx != client_ctx) {
1526 return -EPERM;
1527 }
1528
1529 if (!sm_is_registered()) {
1530 return 0;
1531 }
1532 k_mutex_lock(&client.mutex, K_FOREVER);
1533 LOG_WRN("Confirmable Timeout -> Re-connect and register");
1534 client.engine_state = ENGINE_DO_REGISTRATION;
1535 k_mutex_unlock(&client.mutex);
1536 return 0;
1537 }
1538
lwm2m_rd_client_is_registred(struct lwm2m_ctx * client_ctx)1539 bool lwm2m_rd_client_is_registred(struct lwm2m_ctx *client_ctx)
1540 {
1541 if (client.ctx != client_ctx || !sm_is_registered()) {
1542 return false;
1543 }
1544
1545 return true;
1546 }
lwm2m_rd_client_is_suspended(struct lwm2m_ctx * client_ctx)1547 bool lwm2m_rd_client_is_suspended(struct lwm2m_ctx *client_ctx)
1548 {
1549 if (client.ctx != client_ctx || !sm_is_suspended()) {
1550 return false;
1551 }
1552
1553 return true;
1554 }
1555
1556
lwm2m_rd_client_init(void)1557 int lwm2m_rd_client_init(void)
1558 {
1559 client.ctx = NULL;
1560 client.rd_message.ctx = NULL;
1561 client.engine_state = ENGINE_IDLE;
1562 k_mutex_init(&client.mutex);
1563
1564 return lwm2m_engine_add_service(lwm2m_rd_client_service,
1565 STATE_MACHINE_UPDATE_INTERVAL_MS);
1566
1567 }
1568
sys_lwm2m_rd_client_init(void)1569 static int sys_lwm2m_rd_client_init(void)
1570 {
1571 return lwm2m_rd_client_init();
1572 }
1573
1574
1575 SYS_INIT(sys_lwm2m_rd_client_init, APPLICATION,
1576 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
1577