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 #include "lwm2m_obj_server.h"
66 
67 #define LWM2M_RD_CLIENT_URI "rd"
68 #define CLIENT_EP_LEN		CONFIG_LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH
69 #define CLIENT_BINDING_LEN sizeof("UQ")
70 #define CLIENT_QUEUE_LEN sizeof("Q")
71 #define DELAY_BEFORE_CLOSING	(1 * MSEC_PER_SEC)
72 #define DELAY_FOR_ACK		100U
73 #define EXCHANGE_LIFETIME	247U
74 #define MINIMUM_PERIOD		15
75 #define DISABLE_TIMEOUT		(K_SECONDS(CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES * EXCHANGE_LIFETIME))
76 
77 static void sm_handle_registration_update_failure(void);
78 static int sm_send_registration_msg(void);
79 static bool sm_is_suspended(void);
80 static void lwm2m_rd_client_service(struct k_work *work);
81 static int64_t calc_next_event(void);
82 static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms);
83 static void set_sm_state(uint8_t sm_state);
84 /** Try to fallback to bootstrap. Return true if we did. */
85 static bool fallback_to_bootstrap(void);
86 
87 /* The states for the RD client state machine */
88 /*
89  * When node is unregistered it ends up in UNREGISTERED
90  * and this is going to be there until use X or Y kicks it
91  * back into INIT again
92  */
93 enum sm_engine_state {
94 	ENGINE_IDLE,
95 	ENGINE_INIT,
96 	ENGINE_DO_BOOTSTRAP_REG,
97 	ENGINE_BOOTSTRAP_REG_SENT,
98 	ENGINE_BOOTSTRAP_REG_DONE,
99 	ENGINE_BOOTSTRAP_TRANS_DONE,
100 	ENGINE_DO_REGISTRATION,
101 	ENGINE_SEND_REGISTRATION,
102 	ENGINE_REGISTRATION_SENT,
103 	ENGINE_REGISTRATION_DONE,
104 	ENGINE_REGISTRATION_DONE_RX_OFF,
105 	ENGINE_UPDATE_REGISTRATION,
106 	ENGINE_UPDATE_SENT,
107 	ENGINE_SERVER_DISABLED,
108 	ENGINE_SUSPENDED,
109 	ENGINE_DEREGISTER,
110 	ENGINE_DEREGISTER_SENT,
111 	ENGINE_DEREGISTERED,
112 	ENGINE_NETWORK_ERROR,
113 };
114 
115 struct lwm2m_rd_client_info {
116 	struct k_mutex mutex;
117 	struct lwm2m_message rd_message;
118 	struct lwm2m_ctx *ctx;
119 	uint32_t lifetime;
120 	uint8_t engine_state;
121 	uint8_t retries;
122 	uint8_t retry_delay;
123 
124 	int64_t last_update;
125 	int64_t last_tx;
126 	int64_t next_event;
127 	int64_t last_state_change;
128 
129 	char ep_name[CLIENT_EP_LEN];
130 	char server_ep[CLIENT_EP_LEN];
131 
132 	bool use_bootstrap  : 1;
133 	bool trigger_update : 1;
134 	bool update_objects : 1;
135 	bool close_socket   : 1;
136 	bool server_disabled: 1;
137 } client;
138 
139 /* Allocate some data for queries and updates. Make sure it's large enough to
140  * hold the largest query string, which in most cases will be the endpoint
141  * string. In other case, 32 bytes are enough to encode any other query string
142  * documented in the LwM2M specification.
143  */
144 static char query_buffer[MAX(32, sizeof("ep=") + CLIENT_EP_LEN)];
145 static enum sm_engine_state suspended_client_state;
146 
rd_get_message(void)147 static struct lwm2m_message *rd_get_message(void)
148 {
149 	if (client.rd_message.ctx) {
150 		/* Free old message */
151 		lwm2m_reset_message(&client.rd_message, true);
152 	}
153 
154 	client.rd_message.ctx = client.ctx;
155 	return &client.rd_message;
156 
157 }
158 
rd_client_message_free(void)159 static void rd_client_message_free(void)
160 {
161 	lwm2m_reset_message(lwm2m_get_ongoing_rd_msg(), true);
162 }
163 
164 
lwm2m_get_ongoing_rd_msg(void)165 struct lwm2m_message *lwm2m_get_ongoing_rd_msg(void)
166 {
167 	if (!client.ctx || !client.rd_message.ctx) {
168 		return NULL;
169 	}
170 	return &client.rd_message;
171 }
172 
engine_update_tx_time(void)173 void engine_update_tx_time(void)
174 {
175 	client.last_tx = k_uptime_get();
176 }
177 
next_event_at(int64_t timestamp)178 static void next_event_at(int64_t timestamp)
179 {
180 	client.next_event = timestamp;
181 	(void)lwm2m_engine_call_at(lwm2m_rd_client_service, timestamp);
182 }
183 
set_sm_state_delayed(uint8_t sm_state,int64_t delay_ms)184 static void set_sm_state_delayed(uint8_t sm_state, int64_t delay_ms)
185 {
186 	k_mutex_lock(&client.mutex, K_FOREVER);
187 	enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE;
188 
189 	/* Determine if a callback to the app is needed */
190 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
191 	if (sm_state == ENGINE_BOOTSTRAP_REG_DONE) {
192 		event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE;
193 	} else if (client.engine_state == ENGINE_BOOTSTRAP_TRANS_DONE &&
194 		   sm_state == ENGINE_DO_REGISTRATION) {
195 		event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE;
196 	} else
197 #endif
198 	if (client.engine_state == ENGINE_UPDATE_SENT &&
199 	    (sm_state == ENGINE_REGISTRATION_DONE ||
200 	     sm_state == ENGINE_REGISTRATION_DONE_RX_OFF)) {
201 		lwm2m_push_queued_buffers(client.ctx);
202 		event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE;
203 	} else if (sm_state == ENGINE_REGISTRATION_DONE) {
204 		lwm2m_push_queued_buffers(client.ctx);
205 		event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE;
206 	} else if (sm_state == ENGINE_REGISTRATION_DONE_RX_OFF) {
207 		event = LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF;
208 	} else if (sm_state == ENGINE_DEREGISTERED && !client.server_disabled) {
209 		event = LWM2M_RD_CLIENT_EVENT_DISCONNECT;
210 	} else if (sm_state == ENGINE_UPDATE_REGISTRATION) {
211 		event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE;
212 	} else if (sm_state == ENGINE_DEREGISTER) {
213 		if (client.server_disabled) {
214 			event = LWM2M_RD_CLIENT_EVENT_SERVER_DISABLED;
215 		} else {
216 			event = LWM2M_RD_CLIENT_EVENT_DEREGISTER;
217 		}
218 	}
219 
220 	if (sm_is_suspended()) {
221 		/* Just change the state where we are going to resume next */
222 		suspended_client_state = sm_state;
223 	} else {
224 		client.engine_state = sm_state;
225 	}
226 
227 	if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.ctx->event_cb) {
228 		client.ctx->event_cb(client.ctx, event);
229 	}
230 
231 	/* Suspend socket after Event callback */
232 	if (event == LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF) {
233 		if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUSPEND_SOCKET_AT_IDLE) ||
234 		    IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE)) {
235 			lwm2m_socket_suspend(client.ctx);
236 		} else if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_CLOSE_SOCKET_AT_IDLE)) {
237 			lwm2m_close_socket(client.ctx);
238 		}
239 	}
240 	client.last_state_change = k_uptime_get();
241 	next_event_at(k_uptime_get() + delay_ms);
242 	k_mutex_unlock(&client.mutex);
243 }
244 
set_sm_state(uint8_t sm_state)245 static void set_sm_state(uint8_t sm_state)
246 {
247 	set_sm_state_delayed(sm_state, 0);
248 }
249 
sm_is_bootstrap(void)250 static bool sm_is_bootstrap(void)
251 {
252 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
253 	k_mutex_lock(&client.mutex, K_FOREVER);
254 	bool is_bootstrap = (client.engine_state >= ENGINE_DO_BOOTSTRAP_REG &&
255 		client.engine_state <= ENGINE_BOOTSTRAP_TRANS_DONE);
256 	k_mutex_unlock(&client.mutex);
257 	return is_bootstrap;
258 #else
259 	return false;
260 #endif
261 }
262 
sm_is_registered(void)263 static bool sm_is_registered(void)
264 {
265 	k_mutex_lock(&client.mutex, K_FOREVER);
266 	bool registered = (client.engine_state >= ENGINE_REGISTRATION_DONE &&
267 			   client.engine_state <= ENGINE_DEREGISTER_SENT);
268 
269 	k_mutex_unlock(&client.mutex);
270 	return registered;
271 }
272 
sm_is_suspended(void)273 static bool sm_is_suspended(void)
274 {
275 	k_mutex_lock(&client.mutex, K_FOREVER);
276 	bool suspended = (client.engine_state == ENGINE_SUSPENDED);
277 
278 	k_mutex_unlock(&client.mutex);
279 	return suspended;
280 }
281 
282 
get_sm_state(void)283 static uint8_t get_sm_state(void)
284 {
285 	k_mutex_lock(&client.mutex, K_FOREVER);
286 	uint8_t state = client.engine_state;
287 
288 	k_mutex_unlock(&client.mutex);
289 	return state;
290 }
291 
292 /** Handle state transition when we have lost the connection. */
sm_handle_timeout_state(enum sm_engine_state sm_state)293 static void sm_handle_timeout_state(enum sm_engine_state sm_state)
294 {
295 	k_mutex_lock(&client.mutex, K_FOREVER);
296 	enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE;
297 
298 	switch (client.engine_state) {
299 	case ENGINE_DO_BOOTSTRAP_REG:
300 	case ENGINE_BOOTSTRAP_REG_SENT:
301 	case ENGINE_BOOTSTRAP_REG_DONE:
302 	case ENGINE_BOOTSTRAP_TRANS_DONE:
303 		/* Don't send BOOTSTRAP_REG_FAILURE event, that is only emitted from
304 		 * do_network_error() once we are out of retries.
305 		 */
306 		break;
307 
308 	case ENGINE_SEND_REGISTRATION:
309 	case ENGINE_REGISTRATION_SENT:
310 	case ENGINE_REGISTRATION_DONE:
311 	case ENGINE_REGISTRATION_DONE_RX_OFF:
312 	case ENGINE_UPDATE_REGISTRATION:
313 	case ENGINE_UPDATE_SENT:
314 		event = LWM2M_RD_CLIENT_EVENT_REG_TIMEOUT;
315 		break;
316 
317 	case ENGINE_DEREGISTER:
318 	case ENGINE_DEREGISTER_SENT:
319 		event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE;
320 		break;
321 	default:
322 		/* No default events for socket errors */
323 		break;
324 	}
325 
326 	set_sm_state(sm_state);
327 
328 	if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.ctx->event_cb) {
329 		client.ctx->event_cb(client.ctx, event);
330 	}
331 	k_mutex_unlock(&client.mutex);
332 }
333 
334 /** Handle state transition where server have rejected the connection. */
sm_handle_failure_state(enum sm_engine_state sm_state)335 static void sm_handle_failure_state(enum sm_engine_state sm_state)
336 {
337 	k_mutex_lock(&client.mutex, K_FOREVER);
338 	enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE;
339 
340 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
341 	if (client.engine_state == ENGINE_BOOTSTRAP_REG_SENT) {
342 		event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE;
343 	} else
344 #endif
345 	if (client.engine_state == ENGINE_REGISTRATION_SENT) {
346 		event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE;
347 	} else if (client.engine_state == ENGINE_UPDATE_SENT) {
348 		sm_handle_registration_update_failure();
349 		k_mutex_unlock(&client.mutex);
350 		return;
351 	} else if (client.engine_state == ENGINE_DEREGISTER_SENT) {
352 		event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE;
353 	}
354 
355 	lwm2m_engine_stop(client.ctx);
356 	set_sm_state(sm_state);
357 
358 	if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.ctx->event_cb) {
359 		client.ctx->event_cb(client.ctx, event);
360 	}
361 	k_mutex_unlock(&client.mutex);
362 }
363 
364 /* force state machine restart */
socket_fault_cb(int error)365 static void socket_fault_cb(int error)
366 {
367 	LOG_ERR("RD Client socket error: %d", error);
368 	lwm2m_socket_close(client.ctx);
369 
370 	if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) && sm_is_bootstrap()) {
371 		client.ctx->sec_obj_inst = -1;
372 		/* force full registration */
373 		client.last_update = 0;
374 
375 		if (get_sm_state() == ENGINE_BOOTSTRAP_TRANS_DONE) {
376 			/* Ignore the error, some servers close the connection immediately
377 			 * after receiving Ack to Bootstrap-Finish command.
378 			 */
379 			return;
380 		}
381 	}
382 
383 	/* Network error state causes engine to re-register,
384 	 * so only trigger that state if we are not stopping the
385 	 * engine.
386 	 * Also when engine is going to be disabled, for a while, we might get spurious
387 	 * socket errors when closing, so ignore them.
388 	 */
389 	if (client.engine_state > ENGINE_IDLE &&
390 		client.engine_state < ENGINE_SERVER_DISABLED) {
391 		sm_handle_timeout_state(ENGINE_NETWORK_ERROR);
392 	} else if (client.engine_state != ENGINE_SUSPENDED &&
393 		   !client.server_disabled) {
394 		sm_handle_timeout_state(ENGINE_IDLE);
395 	}
396 }
397 
398 /* force re-update with remote peer */
engine_trigger_update(bool update_objects)399 void engine_trigger_update(bool update_objects)
400 {
401 	k_mutex_lock(&client.mutex, K_FOREVER);
402 	if (client.engine_state < ENGINE_REGISTRATION_SENT ||
403 	    client.engine_state > ENGINE_UPDATE_SENT) {
404 		k_mutex_unlock(&client.mutex);
405 		return;
406 	}
407 
408 	client.trigger_update = true;
409 	/* short delay for Ack, then trigger an update */
410 	next_event_at(k_uptime_get() + DELAY_FOR_ACK);
411 
412 	if (update_objects) {
413 		client.update_objects = true;
414 	}
415 	k_mutex_unlock(&client.mutex);
416 }
417 
code2str(uint8_t code)418 static inline const char *code2str(uint8_t code)
419 {
420 	switch (code) {
421 	case COAP_RESPONSE_CODE_BAD_REQUEST:
422 		return "Bad Request";
423 	case COAP_RESPONSE_CODE_FORBIDDEN:
424 		return "Forbidden";
425 	case COAP_RESPONSE_CODE_NOT_FOUND:
426 		return "Not Found";
427 	case COAP_RESPONSE_CODE_PRECONDITION_FAILED:
428 		return "Precondition Failed";
429 	default:
430 		break;
431 	}
432 
433 	return "Unknown";
434 }
435 
436 /* state machine reply callbacks */
437 
438 #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)439 static int do_bootstrap_reply_cb(const struct coap_packet *response,
440 				 struct coap_reply *reply,
441 				 const struct sockaddr *from)
442 {
443 	uint8_t code;
444 
445 	code = coap_header_get_code(response);
446 	LOG_DBG("Bootstrap callback (code:%u.%u)",
447 		COAP_RESPONSE_CODE_CLASS(code),
448 		COAP_RESPONSE_CODE_DETAIL(code));
449 
450 	if (code == COAP_RESPONSE_CODE_CHANGED) {
451 		LOG_INF("Bootstrap registration done!");
452 		set_sm_state(ENGINE_BOOTSTRAP_REG_DONE);
453 		return 0;
454 	}
455 
456 	LOG_ERR("Failed with code %u.%u (%s). Not Retrying.",
457 		COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
458 		code2str(code));
459 
460 	sm_handle_failure_state(ENGINE_IDLE);
461 
462 	return 0;
463 }
464 
do_bootstrap_reg_timeout_cb(struct lwm2m_message * msg)465 static void do_bootstrap_reg_timeout_cb(struct lwm2m_message *msg)
466 {
467 	LOG_WRN("Bootstrap Timeout");
468 	sm_handle_timeout_state(ENGINE_NETWORK_ERROR);
469 }
470 #endif
471 
engine_trigger_bootstrap(void)472 int engine_trigger_bootstrap(void)
473 {
474 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
475 	k_mutex_lock(&client.mutex, K_FOREVER);
476 
477 	if (client.use_bootstrap) {
478 		/* Bootstrap is not possible to trig */
479 		LOG_WRN("Bootstrap process ongoing");
480 		k_mutex_unlock(&client.mutex);
481 		return -EPERM;
482 	}
483 	LOG_INF("Server Initiated Bootstrap");
484 	/* Free ongoing possible message */
485 	rd_client_message_free();
486 	client.use_bootstrap = true;
487 	client.trigger_update = false;
488 	set_sm_state_delayed(ENGINE_INIT, DELAY_BEFORE_CLOSING);
489 	k_mutex_unlock(&client.mutex);
490 	return 0;
491 #else
492 	return -EPERM;
493 #endif
494 }
do_registration_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)495 static int do_registration_reply_cb(const struct coap_packet *response,
496 				    struct coap_reply *reply,
497 				    const struct sockaddr *from)
498 {
499 	struct coap_option options[2];
500 	uint8_t code;
501 	int ret = -EINVAL;
502 
503 	code = coap_header_get_code(response);
504 	LOG_DBG("Registration callback (code:%u.%u)",
505 		COAP_RESPONSE_CODE_CLASS(code),
506 		COAP_RESPONSE_CODE_DETAIL(code));
507 
508 	/* check state and possibly set registration to done */
509 	if (code == COAP_RESPONSE_CODE_CREATED) {
510 		ret = coap_find_options(response, COAP_OPTION_LOCATION_PATH,
511 					options, 2);
512 		if (ret < 2) {
513 			LOG_ERR("Unexpected endpoint data returned. ret = %d", ret);
514 			ret = -EINVAL;
515 			goto fail;
516 		}
517 
518 		/* option[0] should be "rd" */
519 
520 		if (options[1].len + 1 > sizeof(client.server_ep)) {
521 			LOG_ERR("Unexpected length of query: "
522 				    "%u (expected %zu)\n",
523 				    options[1].len,
524 				    sizeof(client.server_ep));
525 			ret = -EINVAL;
526 			goto fail;
527 		}
528 
529 		/* remember the last reg time */
530 		client.last_update = k_uptime_get();
531 		client.server_disabled = false;
532 		client.retries = 0;
533 
534 		memcpy(client.server_ep, options[1].value,
535 		       options[1].len);
536 		client.server_ep[options[1].len] = '\0';
537 		set_sm_state(ENGINE_REGISTRATION_DONE);
538 		LOG_INF("Registration Done (EP='%s')",
539 			client.server_ep);
540 
541 		return 0;
542 	}
543 
544 	LOG_ERR("Failed with code %u.%u (%s).",
545 		COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
546 		code2str(code));
547 fail:
548 	lwm2m_server_disable(client.ctx->srv_obj_inst, DISABLE_TIMEOUT);
549 	sm_handle_failure_state(ENGINE_NETWORK_ERROR);
550 
551 	return ret;
552 }
553 
do_registration_timeout_cb(struct lwm2m_message * msg)554 static void do_registration_timeout_cb(struct lwm2m_message *msg)
555 {
556 	LOG_WRN("Registration Timeout");
557 
558 	sm_handle_timeout_state(ENGINE_NETWORK_ERROR);
559 }
560 
do_update_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)561 static int do_update_reply_cb(const struct coap_packet *response,
562 			      struct coap_reply *reply,
563 			      const struct sockaddr *from)
564 {
565 	uint8_t code;
566 
567 	code = coap_header_get_code(response);
568 	LOG_INF("Update callback (code:%u.%u)",
569 		COAP_RESPONSE_CODE_CLASS(code),
570 		COAP_RESPONSE_CODE_DETAIL(code));
571 
572 	/* If NOT_FOUND just continue on */
573 	if ((code == COAP_RESPONSE_CODE_CHANGED) ||
574 	    (code == COAP_RESPONSE_CODE_CREATED)) {
575 		/* remember the last reg time */
576 		client.last_update = k_uptime_get();
577 		client.server_disabled = false;
578 		client.retries = 0;
579 		set_sm_state(ENGINE_REGISTRATION_DONE);
580 		LOG_INF("Update Done");
581 		return 0;
582 	}
583 
584 	LOG_ERR("Failed with code %u.%u (%s). Retrying registration.",
585 		COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
586 		code2str(code));
587 
588 	sm_handle_failure_state(ENGINE_DO_REGISTRATION);
589 
590 	return 0;
591 }
592 
do_update_timeout_cb(struct lwm2m_message * msg)593 static void do_update_timeout_cb(struct lwm2m_message *msg)
594 {
595 	LOG_WRN("Registration Update Timeout");
596 
597 	if (client.ctx->sock_fd > -1) {
598 		client.close_socket = true;
599 	}
600 	/* Re-do registration */
601 	sm_handle_timeout_state(ENGINE_DO_REGISTRATION);
602 }
603 
do_deregister_reply_cb(const struct coap_packet * response,struct coap_reply * reply,const struct sockaddr * from)604 static int do_deregister_reply_cb(const struct coap_packet *response,
605 				  struct coap_reply *reply,
606 				  const struct sockaddr *from)
607 {
608 	uint8_t code;
609 
610 	code = coap_header_get_code(response);
611 	LOG_DBG("Deregister callback (code:%u.%u)",
612 		COAP_RESPONSE_CODE_CLASS(code),
613 		COAP_RESPONSE_CODE_DETAIL(code));
614 
615 	if (code == COAP_RESPONSE_CODE_DELETED) {
616 		LOG_INF("Deregistration success");
617 		set_sm_state(ENGINE_DEREGISTERED);
618 		return 0;
619 	}
620 
621 	LOG_ERR("Failed with code %u.%u (%s). Not Retrying",
622 		COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code),
623 		code2str(code));
624 
625 	sm_handle_failure_state(ENGINE_DEREGISTERED);
626 
627 	return 0;
628 }
629 
do_deregister_timeout_cb(struct lwm2m_message * msg)630 static void do_deregister_timeout_cb(struct lwm2m_message *msg)
631 {
632 	LOG_WRN("De-Registration Timeout");
633 
634 	sm_handle_timeout_state(ENGINE_DEREGISTERED);
635 }
636 
is_bootsrap_server(int sec_obj_inst)637 static bool is_bootsrap_server(int sec_obj_inst)
638 {
639 	bool bootstrap;
640 	int ret;
641 
642 	ret = lwm2m_get_bool(&LWM2M_OBJ(0, sec_obj_inst, 1), &bootstrap);
643 	if (ret < 0) {
644 		LOG_WRN("Failed to check bootstrap, err %d", ret);
645 		return false;
646 	}
647 	return bootstrap;
648 }
649 
sm_update_lifetime(int srv_obj_inst,uint32_t * lifetime)650 static bool sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime)
651 {
652 	uint32_t new_lifetime;
653 
654 	if (lwm2m_get_u32(&LWM2M_OBJ(1, srv_obj_inst, 1), &new_lifetime) < 0) {
655 		new_lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME;
656 		LOG_INF("Using default lifetime: %u", new_lifetime);
657 	}
658 
659 	if (new_lifetime < CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME) {
660 		new_lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME;
661 		lwm2m_set_u32(&LWM2M_OBJ(1, srv_obj_inst, 1), new_lifetime);
662 		LOG_INF("Overwrite a server lifetime with default");
663 	}
664 
665 	if (new_lifetime != *lifetime) {
666 		*lifetime = new_lifetime;
667 		return true;
668 	}
669 
670 	return false;
671 }
672 
673 /**
674  * @brief Find the next security instance for bootstrapping.
675  *
676  * Search for the next security instance that has the bootstrap flag set and
677  * is not the same as current security instance.
678  *
679  * @param sec_obj_inst current security instance or -1.
680  * @return zero on success, negative on error.
681  */
sm_next_bootstrap_inst(int * sec_obj_inst)682 static int sm_next_bootstrap_inst(int *sec_obj_inst)
683 {
684 	int i, obj_inst_id = -1;
685 
686 	if (*sec_obj_inst >= 0 && !is_bootsrap_server(*sec_obj_inst)) {
687 		*sec_obj_inst = -1;
688 	}
689 
690 	/* Iterate over all instances to find the correct one. */
691 	for (i = 0; i < CONFIG_LWM2M_SECURITY_INSTANCE_COUNT; i++) {
692 		obj_inst_id = lwm2m_security_index_to_inst_id(i);
693 		if (obj_inst_id < 0) {
694 			continue;
695 		}
696 		if (obj_inst_id == *sec_obj_inst) {
697 			continue;
698 		}
699 
700 		if (is_bootsrap_server(obj_inst_id)) {
701 			*sec_obj_inst = obj_inst_id;
702 			return 0;
703 		}
704 	}
705 
706 	LOG_WRN("No Bootstrap servers found.");
707 
708 	return -ENOENT;
709 }
710 
711 /* state machine step functions */
712 
sm_do_init(void)713 static int sm_do_init(void)
714 {
715 	lwm2m_engine_stop(client.ctx);
716 	client.trigger_update = false;
717 	client.lifetime = 0U;
718 	client.last_update = 0U;
719 	client.close_socket = false;
720 
721 	/* Do bootstrap or registration */
722 	if (client.use_bootstrap && IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) {
723 		set_sm_state(ENGINE_DO_BOOTSTRAP_REG);
724 	} else {
725 		set_sm_state(ENGINE_DO_REGISTRATION);
726 	}
727 	return 0;
728 }
729 
730 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
sm_send_bootstrap_registration(void)731 static int sm_send_bootstrap_registration(void)
732 {
733 	struct lwm2m_message *msg;
734 	int ret;
735 
736 	msg = rd_get_message();
737 	if (!msg) {
738 		LOG_ERR("Unable to get a lwm2m message!");
739 		return -ENOMEM;
740 	}
741 
742 	msg->type = COAP_TYPE_CON;
743 	msg->code = COAP_METHOD_POST;
744 	msg->mid = coap_next_id();
745 	msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
746 	msg->reply_cb = do_bootstrap_reply_cb;
747 	msg->message_timeout_cb = do_bootstrap_reg_timeout_cb;
748 
749 	ret = lwm2m_init_message(msg);
750 	if (ret) {
751 		goto cleanup;
752 	}
753 
754 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
755 					"bs", strlen("bs"));
756 	if (ret < 0) {
757 		goto cleanup;
758 	}
759 
760 	snprintk(query_buffer, sizeof(query_buffer) - 1, "ep=%s",
761 		 client.ep_name);
762 
763 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY,
764 					query_buffer, strlen(query_buffer));
765 	if (ret < 0) {
766 		goto cleanup;
767 	}
768 
769 	if (IS_ENABLED(CONFIG_LWM2M_VERSION_1_1)) {
770 		int pct = LWM2M_FORMAT_OMA_TLV;
771 
772 		if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_CBOR_SUPPORT)) {
773 			pct = LWM2M_FORMAT_APP_SENML_CBOR;
774 		} else if (IS_ENABLED(CONFIG_LWM2M_RW_SENML_JSON_SUPPORT)) {
775 			pct = LWM2M_FORMAT_APP_SEML_JSON;
776 		}
777 
778 		snprintk(query_buffer, sizeof(query_buffer) - 1, "pct=%d", pct);
779 
780 		coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY,
781 				  query_buffer, strlen(query_buffer));
782 	}
783 
784 	/* log the bootstrap attempt */
785 	LOG_DBG("Register ID with bootstrap server as '%s'",
786 		query_buffer);
787 
788 	ret = lwm2m_send_message_async(msg);
789 	if (ret < 0) {
790 		LOG_ERR("Failed to send bootstrap message (err: %d)", ret);
791 		goto cleanup;
792 	}
793 
794 	return 0;
795 
796 cleanup:
797 	lwm2m_reset_message(msg, true);
798 	return ret;
799 }
800 
sm_do_bootstrap_reg(void)801 static void sm_do_bootstrap_reg(void)
802 {
803 	int ret;
804 
805 	/* clear out existing connection data */
806 	if (client.ctx->sock_fd > -1) {
807 		lwm2m_engine_stop(client.ctx);
808 	}
809 
810 	client.ctx->bootstrap_mode = true;
811 	ret = sm_next_bootstrap_inst(&client.ctx->sec_obj_inst);
812 	if (ret < 0) {
813 		set_sm_state(ENGINE_NETWORK_ERROR);
814 		return;
815 	}
816 
817 	LOG_INF("Bootstrap started with endpoint '%s' using security object %d",
818 		client.ep_name, client.ctx->sec_obj_inst);
819 
820 	ret = lwm2m_engine_start(client.ctx);
821 	if (ret < 0) {
822 		LOG_ERR("Cannot init LWM2M engine (%d)", ret);
823 		set_sm_state(ENGINE_NETWORK_ERROR);
824 		return;
825 	}
826 
827 	ret = sm_send_bootstrap_registration();
828 	if (!ret) {
829 		set_sm_state(ENGINE_BOOTSTRAP_REG_SENT);
830 	} else {
831 		LOG_ERR("Bootstrap registration err: %d", ret);
832 		set_sm_state(ENGINE_NETWORK_ERROR);
833 	}
834 
835 	return;
836 }
837 
engine_bootstrap_finish(void)838 void engine_bootstrap_finish(void)
839 {
840 	LOG_INF("Bootstrap data transfer done!");
841 	/* Transition only if the client is bootstrapping, otherwise retransmissions of bootstrap
842 	 * finish may restart an already registered client.
843 	 * Delay the state transition, so engine have some time to send ACK before we close the
844 	 * socket.
845 	 */
846 	if (get_sm_state() == ENGINE_BOOTSTRAP_REG_DONE) {
847 		set_sm_state_delayed(ENGINE_BOOTSTRAP_TRANS_DONE, DELAY_BEFORE_CLOSING);
848 	}
849 }
850 
sm_bootstrap_trans_done(void)851 static int sm_bootstrap_trans_done(void)
852 {
853 	/* close down context resources */
854 	lwm2m_engine_stop(client.ctx);
855 
856 	/* reset security object instance */
857 	client.ctx->sec_obj_inst = -1;
858 	client.use_bootstrap = false;
859 
860 	/* reset server timestamps */
861 	lwm2m_server_reset_timestamps();
862 
863 	set_sm_state(ENGINE_DO_REGISTRATION);
864 
865 	return 0;
866 }
867 #endif
868 
sm_send_registration(bool send_obj_support_data,coap_reply_t reply_cb,lwm2m_message_timeout_cb_t timeout_cb)869 static int sm_send_registration(bool send_obj_support_data,
870 				coap_reply_t reply_cb,
871 				lwm2m_message_timeout_cb_t timeout_cb)
872 {
873 	struct lwm2m_message *msg;
874 	int ret;
875 	char binding[CLIENT_BINDING_LEN];
876 	char queue[CLIENT_QUEUE_LEN];
877 
878 	msg = rd_get_message();
879 	if (!msg) {
880 		LOG_ERR("Unable to get a lwm2m message!");
881 		return -ENOMEM;
882 	}
883 
884 	msg->type = COAP_TYPE_CON;
885 	msg->code = COAP_METHOD_POST;
886 	msg->mid = coap_next_id();
887 	msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
888 	msg->reply_cb = reply_cb;
889 	msg->message_timeout_cb = timeout_cb;
890 
891 	ret = lwm2m_init_message(msg);
892 	if (ret) {
893 		goto cleanup;
894 	}
895 
896 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
897 					LWM2M_RD_CLIENT_URI,
898 					strlen(LWM2M_RD_CLIENT_URI));
899 	if (ret < 0) {
900 		goto cleanup;
901 	}
902 
903 	if (sm_is_registered()) {
904 		ret = coap_packet_append_option(
905 			&msg->cpkt, COAP_OPTION_URI_PATH,
906 			client.server_ep, strlen(client.server_ep));
907 		if (ret < 0) {
908 			goto cleanup;
909 		}
910 	}
911 
912 	if (send_obj_support_data) {
913 		ret = coap_append_option_int(
914 			&msg->cpkt, COAP_OPTION_CONTENT_FORMAT,
915 			LWM2M_FORMAT_APP_LINK_FORMAT);
916 		if (ret < 0) {
917 			goto cleanup;
918 		}
919 	}
920 
921 	if (!sm_is_registered()) {
922 		snprintk(query_buffer, sizeof(query_buffer) - 1,
923 			"lwm2m=%s", LWM2M_PROTOCOL_VERSION_STRING);
924 		ret = coap_packet_append_option(
925 			&msg->cpkt, COAP_OPTION_URI_QUERY,
926 			query_buffer, strlen(query_buffer));
927 		if (ret < 0) {
928 			goto cleanup;
929 		}
930 
931 		snprintk(query_buffer, sizeof(query_buffer) - 1,
932 			 "ep=%s", client.ep_name);
933 		ret = coap_packet_append_option(
934 			&msg->cpkt, COAP_OPTION_URI_QUERY,
935 			query_buffer, strlen(query_buffer));
936 		if (ret < 0) {
937 			goto cleanup;
938 		}
939 	}
940 
941 	/* Send lifetime only if changed or on initial registration.*/
942 	if (sm_update_lifetime(client.ctx->srv_obj_inst, &client.lifetime) ||
943 	    !sm_is_registered()) {
944 		snprintk(query_buffer, sizeof(query_buffer) - 1,
945 			 "lt=%d", client.lifetime);
946 		ret = coap_packet_append_option(
947 			&msg->cpkt, COAP_OPTION_URI_QUERY,
948 			query_buffer, strlen(query_buffer));
949 		if (ret < 0) {
950 			goto cleanup;
951 		}
952 	}
953 
954 	lwm2m_engine_get_binding(binding);
955 	lwm2m_engine_get_queue_mode(queue);
956 	/* UDP is a default binding, no need to add option if UDP without queue is used. */
957 	if ((!sm_is_registered() && (strcmp(binding, "U") != 0 || strcmp(queue, "Q") == 0))) {
958 		snprintk(query_buffer, sizeof(query_buffer) - 1,
959 			 "b=%s", binding);
960 
961 		ret = coap_packet_append_option(
962 			&msg->cpkt, COAP_OPTION_URI_QUERY,
963 			query_buffer, strlen(query_buffer));
964 		if (ret < 0) {
965 			goto cleanup;
966 		}
967 
968 #if CONFIG_LWM2M_VERSION_1_1
969 		/* In LwM2M 1.1, queue mode is a separate parameter */
970 		uint16_t len = strlen(queue);
971 
972 		if (len) {
973 			ret = coap_packet_append_option(
974 				&msg->cpkt, COAP_OPTION_URI_QUERY,
975 				queue, len);
976 			if (ret < 0) {
977 				goto cleanup;
978 			}
979 		}
980 #endif
981 	}
982 
983 	if (send_obj_support_data) {
984 		ret = coap_packet_append_payload_marker(&msg->cpkt);
985 		if (ret < 0) {
986 			goto cleanup;
987 		}
988 
989 		msg->out.out_cpkt = &msg->cpkt;
990 		msg->out.writer = &link_format_writer;
991 
992 		ret = do_register_op_link_format(msg);
993 		if (ret < 0) {
994 			goto cleanup;
995 		}
996 	}
997 
998 	ret = lwm2m_send_message_async(msg);
999 	if (ret < 0) {
1000 		goto cleanup;
1001 	}
1002 
1003 	/* log the registration attempt */
1004 	LOG_DBG("registration sent [%s]",
1005 		lwm2m_sprint_ip_addr(&client.ctx->remote_addr));
1006 
1007 	return 0;
1008 
1009 cleanup:
1010 	LOG_ERR("error %d when sending registration message", ret);
1011 	lwm2m_reset_message(msg, true);
1012 	return ret;
1013 }
1014 
sm_handle_registration_update_failure(void)1015 static void sm_handle_registration_update_failure(void)
1016 {
1017 	k_mutex_lock(&client.mutex, K_FOREVER);
1018 	LOG_WRN("Registration Update fail -> trigger full registration");
1019 	lwm2m_engine_context_close(client.ctx);
1020 	set_sm_state(ENGINE_SEND_REGISTRATION);
1021 	k_mutex_unlock(&client.mutex);
1022 }
1023 
sm_send_registration_msg(void)1024 static int sm_send_registration_msg(void)
1025 {
1026 	int ret;
1027 
1028 	ret = sm_send_registration(true,
1029 				   do_registration_reply_cb,
1030 				   do_registration_timeout_cb);
1031 	if (!ret) {
1032 		set_sm_state(ENGINE_REGISTRATION_SENT);
1033 	} else {
1034 		LOG_ERR("Registration err: %d", ret);
1035 		set_sm_state(ENGINE_NETWORK_ERROR);
1036 	}
1037 
1038 	return ret;
1039 }
1040 
sm_do_registration(void)1041 static void sm_do_registration(void)
1042 {
1043 	uint16_t ssid;
1044 	int ret = 0;
1045 
1046 	if (client.ctx->connection_suspended) {
1047 		if (lwm2m_engine_connection_resume(client.ctx)) {
1048 			lwm2m_engine_context_close(client.ctx);
1049 			/* perform full registration */
1050 			set_sm_state(ENGINE_DO_REGISTRATION);
1051 			return;
1052 		}
1053 
1054 	} else {
1055 		bool select_srv = true;
1056 		uint16_t srv = (uint16_t) client.ctx->srv_obj_inst;
1057 
1058 		client.last_update = 0;
1059 		client.ctx->bootstrap_mode = false;
1060 
1061 		/* clear out existing connection data */
1062 		if (client.ctx->sock_fd > -1) {
1063 			if (client.close_socket) {
1064 				/* Clear old socket connection */
1065 				client.close_socket = false;
1066 				lwm2m_engine_stop(client.ctx);
1067 			} else {
1068 				lwm2m_engine_context_close(client.ctx);
1069 				/* Keep current connection, retry registration with same server */
1070 				select_srv = false;
1071 			}
1072 		}
1073 
1074 		if (select_srv) {
1075 			/* Select next one from the list, or fail */
1076 			if (!lwm2m_server_select(&srv)) {
1077 				LOG_ERR("Unable to find a valid server instance.");
1078 				goto bootstrap_or_retry;
1079 			}
1080 
1081 			client.ctx->srv_obj_inst = srv;
1082 			sm_update_lifetime(srv, &client.lifetime);
1083 
1084 			ret = lwm2m_get_u16(&LWM2M_OBJ(1, client.ctx->srv_obj_inst, 0), &ssid);
1085 			if (ret < 0) {
1086 				LOG_ERR("Failed to read SSID");
1087 				lwm2m_server_disable(srv, K_FOREVER);
1088 				goto bootstrap_or_retry;
1089 			}
1090 
1091 			ret = lwm2m_security_short_id_to_inst(ssid);
1092 			if (ret < 0) {
1093 				LOG_ERR("Unable to find a valid security instance.");
1094 				lwm2m_server_disable(srv, K_FOREVER);
1095 				goto bootstrap_or_retry;
1096 			}
1097 			client.ctx->sec_obj_inst = (uint16_t) ret;
1098 		}
1099 
1100 		LOG_INF("RD Client started with endpoint '%s' with client lifetime %d using server "
1101 			"object %d",
1102 			client.ep_name, client.lifetime, client.ctx->srv_obj_inst);
1103 
1104 		ret = lwm2m_engine_start(client.ctx);
1105 		if (ret < 0) {
1106 			LOG_ERR("Cannot init LWM2M engine (%d)", ret);
1107 			goto retry;
1108 		}
1109 	}
1110 
1111 	sm_send_registration_msg();
1112 	return;
1113 
1114 bootstrap_or_retry:
1115 	if (!client.server_disabled && fallback_to_bootstrap()) {
1116 		lwm2m_engine_stop(client.ctx);
1117 		return;
1118 	}
1119 retry:
1120 	lwm2m_engine_stop(client.ctx);
1121 	set_sm_state(ENGINE_NETWORK_ERROR);
1122 }
1123 
next_update(void)1124 static int64_t next_update(void)
1125 {
1126 	int64_t next;
1127 	int64_t period = CONFIG_LWM2M_UPDATE_PERIOD;
1128 	int64_t early = CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY;
1129 
1130 	if (period == 0) {
1131 		period = client.lifetime;
1132 	}
1133 	if (early > client.lifetime) {
1134 		early = client.lifetime;
1135 	}
1136 
1137 	next = MIN(period, client.lifetime - early);
1138 	next = MAX(next, MINIMUM_PERIOD);
1139 
1140 	return client.last_update + next * MSEC_PER_SEC;
1141 }
1142 
next_rx_off(void)1143 static int64_t next_rx_off(void)
1144 {
1145 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1146 		return client.last_tx + CONFIG_LWM2M_QUEUE_MODE_UPTIME * MSEC_PER_SEC;
1147 	} else {
1148 		return next_update();
1149 	}
1150 }
1151 
1152 /** Return timestamp to next even whether it is RX_OFF or update event */
calc_next_event(void)1153 static int64_t calc_next_event(void)
1154 {
1155 	return Z_MIN(next_update(), next_rx_off());
1156 }
1157 
sm_registration_done(void)1158 static void sm_registration_done(void)
1159 {
1160 	k_mutex_lock(&client.mutex, K_FOREVER);
1161 
1162 	int64_t now = k_uptime_get();
1163 
1164 	if (sm_is_registered() &&
1165 	    (client.trigger_update ||
1166 	     now >= next_update())) {
1167 		set_sm_state_delayed(ENGINE_UPDATE_REGISTRATION, DELAY_FOR_ACK);
1168 	} else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) &&
1169 	    (client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) &&
1170 	    (now >= next_rx_off())) {
1171 		set_sm_state(ENGINE_REGISTRATION_DONE_RX_OFF);
1172 		next_event_at(next_update());
1173 	} else {
1174 		next_event_at(calc_next_event());
1175 	}
1176 	k_mutex_unlock(&client.mutex);
1177 }
1178 
update_registration(void)1179 static int update_registration(void)
1180 {
1181 	int ret;
1182 	bool update_objects;
1183 
1184 	update_objects = client.update_objects;
1185 	client.trigger_update = false;
1186 	client.update_objects = false;
1187 
1188 	ret = lwm2m_engine_connection_resume(client.ctx);
1189 	if (ret) {
1190 		return ret;
1191 	}
1192 
1193 	ret = sm_send_registration(update_objects,
1194 				   do_update_reply_cb,
1195 				   do_update_timeout_cb);
1196 	if (ret) {
1197 		LOG_ERR("Registration update err: %d", ret);
1198 		return ret;
1199 	}
1200 
1201 	return 0;
1202 }
1203 
sm_update_registration(void)1204 static int sm_update_registration(void)
1205 {
1206 	int ret;
1207 
1208 	ret = update_registration();
1209 	if (ret) {
1210 		LOG_ERR("Failed to update registration. Falling back to full registration");
1211 
1212 		lwm2m_engine_stop(client.ctx);
1213 		/* perform full registration */
1214 		set_sm_state(ENGINE_DO_REGISTRATION);
1215 		return ret;
1216 	}
1217 
1218 	set_sm_state(ENGINE_UPDATE_SENT);
1219 
1220 	return 0;
1221 }
1222 
sm_do_deregister(void)1223 static int sm_do_deregister(void)
1224 {
1225 	struct lwm2m_message *msg;
1226 	int ret;
1227 
1228 	if (lwm2m_engine_connection_resume(client.ctx)) {
1229 		lwm2m_engine_context_close(client.ctx);
1230 		/* Connection failed, enter directly to deregistered state */
1231 		set_sm_state(ENGINE_DEREGISTERED);
1232 		return 0;
1233 	}
1234 
1235 	msg = rd_get_message();
1236 	if (!msg) {
1237 		LOG_ERR("Unable to get a lwm2m message!");
1238 		ret = -ENOMEM;
1239 		goto close_ctx;
1240 	}
1241 
1242 	msg->type = COAP_TYPE_CON;
1243 	msg->code = COAP_METHOD_DELETE;
1244 	msg->mid = coap_next_id();
1245 	msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
1246 	msg->reply_cb = do_deregister_reply_cb;
1247 	msg->message_timeout_cb = do_deregister_timeout_cb;
1248 
1249 	ret = lwm2m_init_message(msg);
1250 	if (ret) {
1251 		goto cleanup;
1252 	}
1253 
1254 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
1255 					LWM2M_RD_CLIENT_URI,
1256 					strlen(LWM2M_RD_CLIENT_URI));
1257 	if (ret < 0) {
1258 		LOG_ERR("Failed to encode URI path option (err:%d).", ret);
1259 		goto cleanup;
1260 	}
1261 
1262 	/* include server endpoint in URI PATH */
1263 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
1264 					client.server_ep,
1265 					strlen(client.server_ep));
1266 	if (ret < 0) {
1267 		LOG_ERR("Failed to encode URI path option (err:%d).", ret);
1268 		goto cleanup;
1269 	}
1270 
1271 	LOG_INF("Deregister from '%s'", client.server_ep);
1272 
1273 	ret = lwm2m_send_message_async(msg);
1274 	if (ret < 0) {
1275 		LOG_ERR("Failed to send deregistration message (err:%d).", ret);
1276 		goto cleanup;
1277 	}
1278 
1279 	set_sm_state(ENGINE_DEREGISTER_SENT);
1280 	return 0;
1281 
1282 cleanup:
1283 	lwm2m_reset_message(msg, true);
1284 close_ctx:
1285 	lwm2m_engine_stop(client.ctx);
1286 	set_sm_state(ENGINE_DEREGISTERED);
1287 	return ret;
1288 }
1289 
fallback_to_bootstrap(void)1290 static bool fallback_to_bootstrap(void)
1291 {
1292 	if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) {
1293 		bool fallback = true;
1294 
1295 		(void)lwm2m_get_bool(&LWM2M_OBJ(LWM2M_OBJECT_SERVER_ID, client.ctx->srv_obj_inst,
1296 						SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID),
1297 				     &fallback);
1298 		if (fallback) {
1299 			client.use_bootstrap = true;
1300 			set_sm_state(ENGINE_INIT);
1301 			return true;
1302 		}
1303 	}
1304 	return false;
1305 }
1306 
sm_do_network_error(void)1307 static void sm_do_network_error(void)
1308 {
1309 	int err;
1310 
1311 	LOG_ERR("sm_do_network_error, retries %d", client.retries);
1312 
1313 	lwm2m_socket_close(client.ctx);
1314 
1315 	if (client.retry_delay) {
1316 		next_event_at(k_uptime_get() + client.retry_delay * MSEC_PER_SEC);
1317 		client.retry_delay = 0;
1318 		return;
1319 	}
1320 	client.retry_delay = 1 << client.retries;
1321 	client.retries++;
1322 
1323 	/* Stop retrying and try fallback */
1324 	if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) {
1325 		LOG_ERR("Network error, max retries reached (%d)", client.retries);
1326 
1327 		/* Disable current server for a period so lwm2m_server_select() does not pick it */
1328 		if (client.ctx->srv_obj_inst > -1) {
1329 			lwm2m_server_disable(client.ctx->srv_obj_inst, DISABLE_TIMEOUT);
1330 		}
1331 
1332 		/* Are we in bootstrap? Try if we can fallback to some other BS server */
1333 		if (client.ctx->bootstrap_mode &&
1334 		    IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) {
1335 			LOG_DBG("In bootstrap, try fallback srv");
1336 			/* Do we have any other bootstrap server to back off to? */
1337 			if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) {
1338 				/* No, we are out of options, stop engine */
1339 				goto stop_engine;
1340 			}
1341 			set_sm_state(ENGINE_INIT);
1342 			return;
1343 		}
1344 
1345 		/* Try if there are other server to fall back to,
1346 		 * Only allow fallback to higher priority server (lower value, or lower id)
1347 		 * if we have successfully registered before.
1348 		 * This should block us from looping the same list again.
1349 		 * Instead we should fallback to bootstrap.
1350 		 */
1351 		uint16_t srv;
1352 
1353 		if (lwm2m_server_select(&srv)) {
1354 			uint8_t p1, p2;
1355 
1356 			p1 = lwm2m_server_get_prio(client.ctx->srv_obj_inst);
1357 			p2 = lwm2m_server_get_prio(srv);
1358 			if (p1 < p2 || client.last_update != 0) {
1359 				set_sm_state(ENGINE_INIT);
1360 				return;
1361 			}
1362 		}
1363 
1364 		/* If we have been disabled by some server, don't fall back to bootstrap */
1365 		if (client.server_disabled) {
1366 			set_sm_state(ENGINE_SERVER_DISABLED);
1367 			return;
1368 		}
1369 
1370 		if (fallback_to_bootstrap()) {
1371 			return;
1372 		}
1373 		goto stop_engine;
1374 	}
1375 
1376 	/* Retry bootstrap */
1377 	if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) {
1378 		if (client.ctx->bootstrap_mode) {
1379 			lwm2m_engine_context_close(client.ctx);
1380 			/* If we don't have fallback BS server, retry with current one */
1381 			if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) {
1382 				client.ctx->sec_obj_inst = -1;
1383 			}
1384 			set_sm_state(ENGINE_DO_BOOTSTRAP_REG);
1385 			return;
1386 		}
1387 	}
1388 
1389 	if (!client.last_update ||
1390 	    (k_uptime_get() - client.last_update) / MSEC_PER_SEC > client.lifetime) {
1391 		/* do full registration as there is no active registration or lifetime exceeded */
1392 		/* Keep the same server until out of retry */
1393 		set_sm_state(ENGINE_DO_REGISTRATION);
1394 		return;
1395 	}
1396 
1397 	/* Try if we can recover the DTLS session and try Update.
1398 	 * This might fallback into full registration on sm_handle_registration_update_failure().
1399 	 */
1400 	err = lwm2m_socket_start(client.ctx);
1401 	if (err) {
1402 		LOG_ERR("Failed to start socket %d", err);
1403 		/*
1404 		 * keep this state until lifetime/retry count exceeds. Renew
1405 		 * sm state to set retry_delay etc ...
1406 		 */
1407 		set_sm_state(ENGINE_NETWORK_ERROR);
1408 		return;
1409 	}
1410 	set_sm_state(ENGINE_UPDATE_REGISTRATION);
1411 	return;
1412 
1413 stop_engine:
1414 
1415 	/* We are out of options, stop engine */
1416 	if (client.ctx->event_cb) {
1417 		if (client.ctx->bootstrap_mode) {
1418 			client.ctx->event_cb(client.ctx,
1419 					     LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE);
1420 		} else {
1421 			client.ctx->event_cb(client.ctx, LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR);
1422 		}
1423 	}
1424 	set_sm_state(ENGINE_IDLE);
1425 }
1426 
lwm2m_rd_client_service(struct k_work * work)1427 static void lwm2m_rd_client_service(struct k_work *work)
1428 {
1429 	k_mutex_lock(&client.mutex, K_FOREVER);
1430 
1431 	int64_t timeout = 0;
1432 
1433 	if (client.ctx) {
1434 		LOG_DBG("State: %d", get_sm_state());
1435 		client.next_event = INT64_MAX;
1436 		switch (get_sm_state()) {
1437 		case ENGINE_IDLE:
1438 			if (client.ctx->sock_fd > -1) {
1439 				lwm2m_engine_stop(client.ctx);
1440 			}
1441 			rd_client_message_free();
1442 			break;
1443 
1444 		case ENGINE_INIT:
1445 			sm_do_init();
1446 			break;
1447 
1448 		case ENGINE_SUSPENDED:
1449 			break;
1450 
1451 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
1452 		case ENGINE_DO_BOOTSTRAP_REG:
1453 			sm_do_bootstrap_reg();
1454 			break;
1455 
1456 		case ENGINE_BOOTSTRAP_REG_SENT:
1457 			/* wait for bootstrap registration done */
1458 			timeout = EXCHANGE_LIFETIME;
1459 			break;
1460 
1461 		case ENGINE_BOOTSTRAP_REG_DONE:
1462 			/* wait for transfer done */
1463 			timeout = EXCHANGE_LIFETIME;
1464 			break;
1465 
1466 		case ENGINE_BOOTSTRAP_TRANS_DONE:
1467 			sm_bootstrap_trans_done();
1468 			break;
1469 #endif
1470 
1471 		case ENGINE_DO_REGISTRATION:
1472 			sm_do_registration();
1473 			break;
1474 
1475 		case ENGINE_SEND_REGISTRATION:
1476 			sm_send_registration_msg();
1477 			break;
1478 
1479 		case ENGINE_REGISTRATION_SENT:
1480 			/* wait registration to be done or timeout */
1481 			timeout = EXCHANGE_LIFETIME;
1482 			break;
1483 
1484 		case ENGINE_REGISTRATION_DONE:
1485 		case ENGINE_REGISTRATION_DONE_RX_OFF:
1486 			sm_registration_done();
1487 			break;
1488 
1489 		case ENGINE_UPDATE_REGISTRATION:
1490 			sm_update_registration();
1491 			break;
1492 
1493 		case ENGINE_UPDATE_SENT:
1494 			/* wait update to be done or abort */
1495 			timeout = EXCHANGE_LIFETIME;
1496 			break;
1497 
1498 		case ENGINE_SERVER_DISABLED:
1499 			if (lwm2m_server_select(NULL)) {
1500 				set_sm_state(ENGINE_INIT);
1501 			} else {
1502 				/* wait for server to be enabled. */
1503 				/*
1504 				 * TODO: Once engine is converted to use timepoint_t
1505 				 * this should calculate the next event from the previous server.
1506 				 */
1507 				next_event_at(k_uptime_get() + SEC_PER_MIN * MSEC_PER_SEC);
1508 			}
1509 			break;
1510 
1511 		case ENGINE_DEREGISTER:
1512 			sm_do_deregister();
1513 			break;
1514 
1515 		case ENGINE_DEREGISTER_SENT:
1516 			/* wait for deregister to be done or reset */
1517 			timeout = EXCHANGE_LIFETIME;
1518 			break;
1519 
1520 		case ENGINE_DEREGISTERED:
1521 			lwm2m_engine_stop(client.ctx);
1522 			if (client.server_disabled) {
1523 				set_sm_state(ENGINE_SERVER_DISABLED);
1524 			} else {
1525 				set_sm_state(ENGINE_IDLE);
1526 			}
1527 			break;
1528 
1529 		case ENGINE_NETWORK_ERROR:
1530 			sm_do_network_error();
1531 			break;
1532 
1533 		default:
1534 			LOG_ERR("Unhandled state: %d", get_sm_state());
1535 
1536 		}
1537 
1538 		if (timeout) {
1539 			int64_t end = client.last_state_change + timeout * MSEC_PER_SEC;
1540 
1541 			if (end < k_uptime_get()) {
1542 				LOG_DBG("State machine have timed out");
1543 				sm_handle_timeout_state(ENGINE_INIT);
1544 			} else if (client.next_event > end) {
1545 				next_event_at(end);
1546 			}
1547 		}
1548 	}
1549 
1550 	k_mutex_unlock(&client.mutex);
1551 }
1552 
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)1553 int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name,
1554 			   uint32_t flags, lwm2m_ctx_event_cb_t event_cb,
1555 			   lwm2m_observe_cb_t observe_cb)
1556 {
1557 	k_mutex_lock(&client.mutex, K_FOREVER);
1558 
1559 	if (!IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) &&
1560 	    (flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP)) {
1561 		LOG_ERR("Bootstrap support is disabled. Please enable "
1562 			"CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP.");
1563 
1564 		k_mutex_unlock(&client.mutex);
1565 		return -ENOTSUP;
1566 	}
1567 
1568 	/* Check client idle state or socket is still active */
1569 
1570 	if (client.ctx && (client.engine_state != ENGINE_IDLE || client.ctx->sock_fd != -1)) {
1571 		LOG_WRN("Client is already running. state %d ", client.engine_state);
1572 		k_mutex_unlock(&client.mutex);
1573 		return -EINPROGRESS;
1574 	}
1575 
1576 	/* Init Context */
1577 	lwm2m_server_reset_timestamps();
1578 	lwm2m_engine_context_init(client_ctx);
1579 
1580 	client.ctx = client_ctx;
1581 	client.ctx->sock_fd = -1;
1582 	client.ctx->fault_cb = socket_fault_cb;
1583 	client.ctx->observe_cb = observe_cb;
1584 	client.ctx->event_cb = event_cb;
1585 	client.use_bootstrap = flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP;
1586 	client.ctx->srv_obj_inst = -1;
1587 	client.ctx->sec_obj_inst = -1;
1588 	client.retries = 0;
1589 
1590 	strncpy(client.ep_name, ep_name, CLIENT_EP_LEN - 1);
1591 	client.ep_name[CLIENT_EP_LEN - 1] = '\0';
1592 	LOG_INF("Start LWM2M Client: %s", client.ep_name);
1593 
1594 	set_sm_state(ENGINE_INIT);
1595 
1596 	k_mutex_unlock(&client.mutex);
1597 
1598 	return 0;
1599 }
1600 
lwm2m_rd_client_stop(struct lwm2m_ctx * client_ctx,lwm2m_ctx_event_cb_t event_cb,bool deregister)1601 int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx,
1602 			   lwm2m_ctx_event_cb_t event_cb, bool deregister)
1603 {
1604 	k_mutex_lock(&client.mutex, K_FOREVER);
1605 
1606 	if (client.ctx != client_ctx) {
1607 		k_mutex_unlock(&client.mutex);
1608 		LOG_WRN("Cannot stop. Wrong context");
1609 		return -EPERM;
1610 	}
1611 
1612 	client.ctx->event_cb = event_cb;
1613 	rd_client_message_free();
1614 
1615 	if (sm_is_registered() && deregister && !client.server_disabled) {
1616 		set_sm_state(ENGINE_DEREGISTER);
1617 	} else {
1618 		client.server_disabled = false;
1619 		set_sm_state(ENGINE_DEREGISTERED);
1620 	}
1621 
1622 	LOG_INF("Stop LWM2M Client: %s", client.ep_name);
1623 
1624 	k_mutex_unlock(&client.mutex);
1625 
1626 
1627 	return 0;
1628 }
1629 
lwm2m_rd_client_pause(void)1630 int lwm2m_rd_client_pause(void)
1631 {
1632 	enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED;
1633 	LOG_DBG("lwm2m_rd_client_pause()");
1634 
1635 	k_mutex_lock(&client.mutex, K_FOREVER);
1636 
1637 	if (!client.ctx) {
1638 		k_mutex_unlock(&client.mutex);
1639 		LOG_ERR("Cannot pause. No context");
1640 		return -EPERM;
1641 	} else if (sm_is_suspended()) {
1642 		k_mutex_unlock(&client.mutex);
1643 		LOG_ERR("LwM2M client already suspended");
1644 		return 0;
1645 	}
1646 
1647 	LOG_INF("Suspend client");
1648 	if (client.ctx->event_cb) {
1649 		client.ctx->event_cb(client.ctx, event);
1650 	}
1651 
1652 	/* Suspend or close the socket */
1653 	if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_CLOSE_SOCKET_AT_IDLE)) {
1654 		lwm2m_close_socket(client.ctx);
1655 	} else {
1656 		lwm2m_socket_suspend(client.ctx);
1657 	}
1658 
1659 	suspended_client_state = get_sm_state();
1660 	set_sm_state(ENGINE_SUSPENDED);
1661 
1662 	k_mutex_unlock(&client.mutex);
1663 
1664 	return 0;
1665 }
1666 
lwm2m_rd_client_resume(void)1667 int lwm2m_rd_client_resume(void)
1668 {
1669 	k_mutex_lock(&client.mutex, K_FOREVER);
1670 
1671 	if (!client.ctx || !lwm2m_rd_client_is_suspended(client.ctx)) {
1672 		k_mutex_unlock(&client.mutex);
1673 		LOG_WRN("Cannot resume, state is not suspended");
1674 		return -EPERM;
1675 	}
1676 
1677 	LOG_INF("Resume Client state");
1678 
1679 	if (suspended_client_state == ENGINE_UPDATE_SENT) {
1680 		/* Set back to Registration done and trigger an update */
1681 		suspended_client_state = ENGINE_REGISTRATION_DONE;
1682 	}
1683 	/* Clear Possible pending RD Client message */
1684 	rd_client_message_free();
1685 
1686 	client.engine_state = suspended_client_state;
1687 
1688 	/* Do we need to resume the bootstrap? */
1689 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
1690 	if (sm_is_bootstrap()) {
1691 		client.engine_state = ENGINE_DO_BOOTSTRAP_REG;
1692 	}
1693 #endif
1694 	/* Or do we resume into registration state */
1695 	if (client.engine_state >= ENGINE_DO_REGISTRATION &&
1696 		client.engine_state <= ENGINE_SERVER_DISABLED) {
1697 		if (!client.last_update ||
1698 			(client.lifetime <= (k_uptime_get() - client.last_update) / MSEC_PER_SEC)) {
1699 			/* No lifetime left, register again */
1700 			client.engine_state = ENGINE_DO_REGISTRATION;
1701 		} else {
1702 			/* Resume similarly like from QUEUE mode */
1703 			client.engine_state = ENGINE_REGISTRATION_DONE_RX_OFF;
1704 			lwm2m_rd_client_connection_resume(client.ctx);
1705 		}
1706 	}
1707 
1708 	next_event_at(0);
1709 	k_mutex_unlock(&client.mutex);
1710 
1711 	return 0;
1712 }
1713 
lwm2m_rd_client_server_disabled(uint16_t inst_id)1714 int lwm2m_rd_client_server_disabled(uint16_t inst_id)
1715 {
1716 	if (client.ctx->srv_obj_inst != inst_id) {
1717 		return -EPERM;
1718 	}
1719 
1720 	k_mutex_lock(&client.mutex, K_FOREVER);
1721 
1722 	client.server_disabled = true;
1723 
1724 	if (sm_is_registered()) {
1725 		LOG_INF("Server disabled, deregister");
1726 		set_sm_state_delayed(ENGINE_DEREGISTER, DELAY_BEFORE_CLOSING);
1727 	} else {
1728 		LOG_INF("Server disabled");
1729 		set_sm_state(ENGINE_DEREGISTERED);
1730 	}
1731 
1732 	k_mutex_unlock(&client.mutex);
1733 
1734 	return 0;
1735 }
1736 
lwm2m_rd_client_update(void)1737 void lwm2m_rd_client_update(void)
1738 {
1739 	engine_trigger_update(false);
1740 }
1741 
lwm2m_rd_client_ctx(void)1742 struct lwm2m_ctx *lwm2m_rd_client_ctx(void)
1743 {
1744 	return client.ctx;
1745 }
1746 
lwm2m_rd_client_set_ctx(struct lwm2m_ctx * ctx)1747 void lwm2m_rd_client_set_ctx(struct lwm2m_ctx *ctx)
1748 {
1749 	client.ctx = ctx;
1750 }
1751 
lwm2m_rd_client_connection_resume(struct lwm2m_ctx * client_ctx)1752 int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx)
1753 {
1754 	if (client.ctx != client_ctx) {
1755 		return -EPERM;
1756 	}
1757 
1758 	if (client.engine_state == ENGINE_REGISTRATION_DONE_RX_OFF) {
1759 		/*
1760 		 * Switch state to triggering a proper registration message
1761 		 * If the socket stays open (Connection ID or no-sec), or we have TLS session cache,
1762 		 * we can trigger the update, otherwise fall back to full registration.
1763 		 */
1764 		if ((IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUSPEND_SOCKET_AT_IDLE) &&
1765 		     IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) ||
1766 		    (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE) ||
1767 		     IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE)) ||
1768 		    !IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT)) {
1769 			client.engine_state = ENGINE_REGISTRATION_DONE;
1770 			if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_NO_MSG_BUFFERING)) {
1771 				/* Force online for a short period */
1772 				engine_update_tx_time();
1773 			} else {
1774 				client.trigger_update = true;
1775 			}
1776 		} else {
1777 			client.engine_state = ENGINE_DO_REGISTRATION;
1778 		}
1779 		next_event_at(0);
1780 	}
1781 
1782 	return 0;
1783 }
1784 
lwm2m_rd_client_timeout(struct lwm2m_ctx * client_ctx)1785 int lwm2m_rd_client_timeout(struct lwm2m_ctx *client_ctx)
1786 {
1787 	if (client.ctx != client_ctx) {
1788 		return -EPERM;
1789 	}
1790 
1791 	if (!sm_is_registered()) {
1792 		return 0;
1793 	}
1794 	k_mutex_lock(&client.mutex, K_FOREVER);
1795 	LOG_WRN("Confirmable Timeout -> Re-connect and register");
1796 	set_sm_state(ENGINE_DO_REGISTRATION);
1797 	next_event_at(0);
1798 	k_mutex_unlock(&client.mutex);
1799 	return 0;
1800 }
1801 
lwm2m_rd_client_is_registred(struct lwm2m_ctx * client_ctx)1802 bool lwm2m_rd_client_is_registred(struct lwm2m_ctx *client_ctx)
1803 {
1804 	if (client.ctx != client_ctx || !sm_is_registered()) {
1805 		return false;
1806 	}
1807 
1808 	return true;
1809 }
lwm2m_rd_client_is_suspended(struct lwm2m_ctx * client_ctx)1810 bool lwm2m_rd_client_is_suspended(struct lwm2m_ctx *client_ctx)
1811 {
1812 	if (client.ctx != client_ctx || !sm_is_suspended()) {
1813 		return false;
1814 	}
1815 
1816 	return true;
1817 }
1818 
1819 
lwm2m_rd_client_init(void)1820 int lwm2m_rd_client_init(void)
1821 {
1822 	client.ctx = NULL;
1823 	client.rd_message.ctx = NULL;
1824 	client.engine_state = ENGINE_IDLE;
1825 	k_mutex_init(&client.mutex);
1826 
1827 	return 0;
1828 }
1829 
sys_lwm2m_rd_client_init(void)1830 static int sys_lwm2m_rd_client_init(void)
1831 {
1832 	return lwm2m_rd_client_init();
1833 }
1834 
1835 LWM2M_ENGINE_INIT(sys_lwm2m_rd_client_init);
1836