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 	lwm2m_send_message_async(msg);
789 
790 	return 0;
791 
792 cleanup:
793 	lwm2m_reset_message(msg, true);
794 	return ret;
795 }
796 
sm_do_bootstrap_reg(void)797 static void sm_do_bootstrap_reg(void)
798 {
799 	int ret;
800 
801 	/* clear out existing connection data */
802 	if (client.ctx->sock_fd > -1) {
803 		lwm2m_engine_stop(client.ctx);
804 	}
805 
806 	client.ctx->bootstrap_mode = true;
807 	ret = sm_next_bootstrap_inst(&client.ctx->sec_obj_inst);
808 	if (ret < 0) {
809 		set_sm_state(ENGINE_NETWORK_ERROR);
810 		return;
811 	}
812 
813 	LOG_INF("Bootstrap started with endpoint '%s' using security object %d",
814 		client.ep_name, client.ctx->sec_obj_inst);
815 
816 	ret = lwm2m_engine_start(client.ctx);
817 	if (ret < 0) {
818 		LOG_ERR("Cannot init LWM2M engine (%d)", ret);
819 		set_sm_state(ENGINE_NETWORK_ERROR);
820 		return;
821 	}
822 
823 	ret = sm_send_bootstrap_registration();
824 	if (!ret) {
825 		set_sm_state(ENGINE_BOOTSTRAP_REG_SENT);
826 	} else {
827 		LOG_ERR("Bootstrap registration err: %d", ret);
828 		set_sm_state(ENGINE_NETWORK_ERROR);
829 	}
830 
831 	return;
832 }
833 
engine_bootstrap_finish(void)834 void engine_bootstrap_finish(void)
835 {
836 	LOG_INF("Bootstrap data transfer done!");
837 	/* Delay the state transition, so engine have some time to send ACK
838 	 * before we close the socket
839 	 */
840 	set_sm_state_delayed(ENGINE_BOOTSTRAP_TRANS_DONE, DELAY_BEFORE_CLOSING);
841 }
842 
sm_bootstrap_trans_done(void)843 static int sm_bootstrap_trans_done(void)
844 {
845 	/* close down context resources */
846 	lwm2m_engine_stop(client.ctx);
847 
848 	/* reset security object instance */
849 	client.ctx->sec_obj_inst = -1;
850 	client.use_bootstrap = false;
851 
852 	/* reset server timestamps */
853 	lwm2m_server_reset_timestamps();
854 
855 	set_sm_state(ENGINE_DO_REGISTRATION);
856 
857 	return 0;
858 }
859 #endif
860 
sm_send_registration(bool send_obj_support_data,coap_reply_t reply_cb,lwm2m_message_timeout_cb_t timeout_cb)861 static int sm_send_registration(bool send_obj_support_data,
862 				coap_reply_t reply_cb,
863 				lwm2m_message_timeout_cb_t timeout_cb)
864 {
865 	struct lwm2m_message *msg;
866 	int ret;
867 	char binding[CLIENT_BINDING_LEN];
868 	char queue[CLIENT_QUEUE_LEN];
869 
870 	msg = rd_get_message();
871 	if (!msg) {
872 		LOG_ERR("Unable to get a lwm2m message!");
873 		return -ENOMEM;
874 	}
875 
876 	msg->type = COAP_TYPE_CON;
877 	msg->code = COAP_METHOD_POST;
878 	msg->mid = coap_next_id();
879 	msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
880 	msg->reply_cb = reply_cb;
881 	msg->message_timeout_cb = timeout_cb;
882 
883 	ret = lwm2m_init_message(msg);
884 	if (ret) {
885 		goto cleanup;
886 	}
887 
888 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
889 					LWM2M_RD_CLIENT_URI,
890 					strlen(LWM2M_RD_CLIENT_URI));
891 	if (ret < 0) {
892 		goto cleanup;
893 	}
894 
895 	if (sm_is_registered()) {
896 		ret = coap_packet_append_option(
897 			&msg->cpkt, COAP_OPTION_URI_PATH,
898 			client.server_ep, strlen(client.server_ep));
899 		if (ret < 0) {
900 			goto cleanup;
901 		}
902 	}
903 
904 	if (send_obj_support_data) {
905 		ret = coap_append_option_int(
906 			&msg->cpkt, COAP_OPTION_CONTENT_FORMAT,
907 			LWM2M_FORMAT_APP_LINK_FORMAT);
908 		if (ret < 0) {
909 			goto cleanup;
910 		}
911 	}
912 
913 	if (!sm_is_registered()) {
914 		snprintk(query_buffer, sizeof(query_buffer) - 1,
915 			"lwm2m=%s", LWM2M_PROTOCOL_VERSION_STRING);
916 		ret = coap_packet_append_option(
917 			&msg->cpkt, COAP_OPTION_URI_QUERY,
918 			query_buffer, strlen(query_buffer));
919 		if (ret < 0) {
920 			goto cleanup;
921 		}
922 
923 		snprintk(query_buffer, sizeof(query_buffer) - 1,
924 			 "ep=%s", client.ep_name);
925 		ret = coap_packet_append_option(
926 			&msg->cpkt, COAP_OPTION_URI_QUERY,
927 			query_buffer, strlen(query_buffer));
928 		if (ret < 0) {
929 			goto cleanup;
930 		}
931 	}
932 
933 	/* Send lifetime only if changed or on initial registration.*/
934 	if (sm_update_lifetime(client.ctx->srv_obj_inst, &client.lifetime) ||
935 	    !sm_is_registered()) {
936 		snprintk(query_buffer, sizeof(query_buffer) - 1,
937 			 "lt=%d", client.lifetime);
938 		ret = coap_packet_append_option(
939 			&msg->cpkt, COAP_OPTION_URI_QUERY,
940 			query_buffer, strlen(query_buffer));
941 		if (ret < 0) {
942 			goto cleanup;
943 		}
944 	}
945 
946 	lwm2m_engine_get_binding(binding);
947 	lwm2m_engine_get_queue_mode(queue);
948 	/* UDP is a default binding, no need to add option if UDP without queue is used. */
949 	if ((!sm_is_registered() && (strcmp(binding, "U") != 0 || strcmp(queue, "Q") == 0))) {
950 		snprintk(query_buffer, sizeof(query_buffer) - 1,
951 			 "b=%s", binding);
952 
953 		ret = coap_packet_append_option(
954 			&msg->cpkt, COAP_OPTION_URI_QUERY,
955 			query_buffer, strlen(query_buffer));
956 		if (ret < 0) {
957 			goto cleanup;
958 		}
959 
960 #if CONFIG_LWM2M_VERSION_1_1
961 		/* In LwM2M 1.1, queue mode is a separate parameter */
962 		uint16_t len = strlen(queue);
963 
964 		if (len) {
965 			ret = coap_packet_append_option(
966 				&msg->cpkt, COAP_OPTION_URI_QUERY,
967 				queue, len);
968 			if (ret < 0) {
969 				goto cleanup;
970 			}
971 		}
972 #endif
973 	}
974 
975 	if (send_obj_support_data) {
976 		ret = coap_packet_append_payload_marker(&msg->cpkt);
977 		if (ret < 0) {
978 			goto cleanup;
979 		}
980 
981 		msg->out.out_cpkt = &msg->cpkt;
982 		msg->out.writer = &link_format_writer;
983 
984 		ret = do_register_op_link_format(msg);
985 		if (ret < 0) {
986 			goto cleanup;
987 		}
988 	}
989 
990 	lwm2m_send_message_async(msg);
991 
992 	/* log the registration attempt */
993 	LOG_DBG("registration sent [%s]",
994 		lwm2m_sprint_ip_addr(&client.ctx->remote_addr));
995 
996 	return 0;
997 
998 cleanup:
999 	LOG_ERR("error %d when sending registration message", ret);
1000 	lwm2m_reset_message(msg, true);
1001 	return ret;
1002 }
1003 
sm_handle_registration_update_failure(void)1004 static void sm_handle_registration_update_failure(void)
1005 {
1006 	k_mutex_lock(&client.mutex, K_FOREVER);
1007 	LOG_WRN("Registration Update fail -> trigger full registration");
1008 	lwm2m_engine_context_close(client.ctx);
1009 	set_sm_state(ENGINE_SEND_REGISTRATION);
1010 	k_mutex_unlock(&client.mutex);
1011 }
1012 
sm_send_registration_msg(void)1013 static int sm_send_registration_msg(void)
1014 {
1015 	int ret;
1016 
1017 	ret = sm_send_registration(true,
1018 				   do_registration_reply_cb,
1019 				   do_registration_timeout_cb);
1020 	if (!ret) {
1021 		set_sm_state(ENGINE_REGISTRATION_SENT);
1022 	} else {
1023 		LOG_ERR("Registration err: %d", ret);
1024 		set_sm_state(ENGINE_NETWORK_ERROR);
1025 	}
1026 
1027 	return ret;
1028 }
1029 
sm_do_registration(void)1030 static void sm_do_registration(void)
1031 {
1032 	uint16_t ssid;
1033 	int ret = 0;
1034 
1035 	if (client.ctx->connection_suspended) {
1036 		if (lwm2m_engine_connection_resume(client.ctx)) {
1037 			lwm2m_engine_context_close(client.ctx);
1038 			/* perform full registration */
1039 			set_sm_state(ENGINE_DO_REGISTRATION);
1040 			return;
1041 		}
1042 
1043 	} else {
1044 		bool select_srv = true;
1045 		uint16_t srv = (uint16_t) client.ctx->srv_obj_inst;
1046 
1047 		client.last_update = 0;
1048 		client.ctx->bootstrap_mode = false;
1049 
1050 		/* clear out existing connection data */
1051 		if (client.ctx->sock_fd > -1) {
1052 			if (client.close_socket) {
1053 				/* Clear old socket connection */
1054 				client.close_socket = false;
1055 				lwm2m_engine_stop(client.ctx);
1056 			} else {
1057 				lwm2m_engine_context_close(client.ctx);
1058 				/* Keep current connection, retry registration with same server */
1059 				select_srv = false;
1060 			}
1061 		}
1062 
1063 		if (select_srv) {
1064 			/* Select next one from the list, or fail */
1065 			if (!lwm2m_server_select(&srv)) {
1066 				LOG_ERR("Unable to find a valid server instance.");
1067 				goto bootstrap_or_retry;
1068 			}
1069 
1070 			client.ctx->srv_obj_inst = srv;
1071 			sm_update_lifetime(srv, &client.lifetime);
1072 
1073 			ret = lwm2m_get_u16(&LWM2M_OBJ(1, client.ctx->srv_obj_inst, 0), &ssid);
1074 			if (ret < 0) {
1075 				LOG_ERR("Failed to read SSID");
1076 				lwm2m_server_disable(srv, K_FOREVER);
1077 				goto bootstrap_or_retry;
1078 			}
1079 
1080 			ret = lwm2m_security_short_id_to_inst(ssid);
1081 			if (ret < 0) {
1082 				LOG_ERR("Unable to find a valid security instance.");
1083 				lwm2m_server_disable(srv, K_FOREVER);
1084 				goto bootstrap_or_retry;
1085 			}
1086 			client.ctx->sec_obj_inst = (uint16_t) ret;
1087 		}
1088 
1089 		LOG_INF("RD Client started with endpoint '%s' with client lifetime %d using server "
1090 			"object %d",
1091 			client.ep_name, client.lifetime, client.ctx->srv_obj_inst);
1092 
1093 		ret = lwm2m_engine_start(client.ctx);
1094 		if (ret < 0) {
1095 			LOG_ERR("Cannot init LWM2M engine (%d)", ret);
1096 			goto retry;
1097 		}
1098 	}
1099 
1100 	sm_send_registration_msg();
1101 	return;
1102 
1103 bootstrap_or_retry:
1104 	if (!client.server_disabled && fallback_to_bootstrap()) {
1105 		lwm2m_engine_stop(client.ctx);
1106 		return;
1107 	}
1108 retry:
1109 	lwm2m_engine_stop(client.ctx);
1110 	set_sm_state(ENGINE_NETWORK_ERROR);
1111 }
1112 
next_update(void)1113 static int64_t next_update(void)
1114 {
1115 	int64_t next;
1116 	int64_t period = CONFIG_LWM2M_UPDATE_PERIOD;
1117 	int64_t early = CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY;
1118 
1119 	if (period == 0) {
1120 		period = client.lifetime;
1121 	}
1122 	if (early > client.lifetime) {
1123 		early = client.lifetime;
1124 	}
1125 
1126 	next = MIN(period, client.lifetime - early);
1127 	next = MAX(next, MINIMUM_PERIOD);
1128 
1129 	return client.last_update + next * MSEC_PER_SEC;
1130 }
1131 
next_rx_off(void)1132 static int64_t next_rx_off(void)
1133 {
1134 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1135 		return client.last_tx + CONFIG_LWM2M_QUEUE_MODE_UPTIME * MSEC_PER_SEC;
1136 	} else {
1137 		return next_update();
1138 	}
1139 }
1140 
1141 /** Return timestamp to next even whether it is RX_OFF or update event */
calc_next_event(void)1142 static int64_t calc_next_event(void)
1143 {
1144 	return Z_MIN(next_update(), next_rx_off());
1145 }
1146 
sm_registration_done(void)1147 static void sm_registration_done(void)
1148 {
1149 	k_mutex_lock(&client.mutex, K_FOREVER);
1150 
1151 	int64_t now = k_uptime_get();
1152 
1153 	if (sm_is_registered() &&
1154 	    (client.trigger_update ||
1155 	     now >= next_update())) {
1156 		set_sm_state_delayed(ENGINE_UPDATE_REGISTRATION, DELAY_FOR_ACK);
1157 	} else if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED) &&
1158 	    (client.engine_state != ENGINE_REGISTRATION_DONE_RX_OFF) &&
1159 	    (now >= next_rx_off())) {
1160 		set_sm_state(ENGINE_REGISTRATION_DONE_RX_OFF);
1161 		next_event_at(next_update());
1162 	} else {
1163 		next_event_at(calc_next_event());
1164 	}
1165 	k_mutex_unlock(&client.mutex);
1166 }
1167 
update_registration(void)1168 static int update_registration(void)
1169 {
1170 	int ret;
1171 	bool update_objects;
1172 
1173 	update_objects = client.update_objects;
1174 	client.trigger_update = false;
1175 	client.update_objects = false;
1176 
1177 	ret = lwm2m_engine_connection_resume(client.ctx);
1178 	if (ret) {
1179 		return ret;
1180 	}
1181 
1182 	ret = sm_send_registration(update_objects,
1183 				   do_update_reply_cb,
1184 				   do_update_timeout_cb);
1185 	if (ret) {
1186 		LOG_ERR("Registration update err: %d", ret);
1187 		return ret;
1188 	}
1189 
1190 	return 0;
1191 }
1192 
sm_update_registration(void)1193 static int sm_update_registration(void)
1194 {
1195 	int ret;
1196 
1197 	ret = update_registration();
1198 	if (ret) {
1199 		LOG_ERR("Failed to update registration. Falling back to full registration");
1200 
1201 		lwm2m_engine_stop(client.ctx);
1202 		/* perform full registration */
1203 		set_sm_state(ENGINE_DO_REGISTRATION);
1204 		return ret;
1205 	}
1206 
1207 	set_sm_state(ENGINE_UPDATE_SENT);
1208 
1209 	return 0;
1210 }
1211 
sm_do_deregister(void)1212 static int sm_do_deregister(void)
1213 {
1214 	struct lwm2m_message *msg;
1215 	int ret;
1216 
1217 	if (lwm2m_engine_connection_resume(client.ctx)) {
1218 		lwm2m_engine_context_close(client.ctx);
1219 		/* Connection failed, enter directly to deregistered state */
1220 		set_sm_state(ENGINE_DEREGISTERED);
1221 		return 0;
1222 	}
1223 
1224 	msg = rd_get_message();
1225 	if (!msg) {
1226 		LOG_ERR("Unable to get a lwm2m message!");
1227 		ret = -ENOMEM;
1228 		goto close_ctx;
1229 	}
1230 
1231 	msg->type = COAP_TYPE_CON;
1232 	msg->code = COAP_METHOD_DELETE;
1233 	msg->mid = coap_next_id();
1234 	msg->tkl = LWM2M_MSG_TOKEN_GENERATE_NEW;
1235 	msg->reply_cb = do_deregister_reply_cb;
1236 	msg->message_timeout_cb = do_deregister_timeout_cb;
1237 
1238 	ret = lwm2m_init_message(msg);
1239 	if (ret) {
1240 		goto cleanup;
1241 	}
1242 
1243 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
1244 					LWM2M_RD_CLIENT_URI,
1245 					strlen(LWM2M_RD_CLIENT_URI));
1246 	if (ret < 0) {
1247 		LOG_ERR("Failed to encode URI path option (err:%d).", ret);
1248 		goto cleanup;
1249 	}
1250 
1251 	/* include server endpoint in URI PATH */
1252 	ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
1253 					client.server_ep,
1254 					strlen(client.server_ep));
1255 	if (ret < 0) {
1256 		LOG_ERR("Failed to encode URI path option (err:%d).", ret);
1257 		goto cleanup;
1258 	}
1259 
1260 	LOG_INF("Deregister from '%s'", client.server_ep);
1261 
1262 	lwm2m_send_message_async(msg);
1263 
1264 	set_sm_state(ENGINE_DEREGISTER_SENT);
1265 	return 0;
1266 
1267 cleanup:
1268 	lwm2m_reset_message(msg, true);
1269 close_ctx:
1270 	lwm2m_engine_stop(client.ctx);
1271 	set_sm_state(ENGINE_DEREGISTERED);
1272 	return ret;
1273 }
1274 
fallback_to_bootstrap(void)1275 static bool fallback_to_bootstrap(void)
1276 {
1277 	if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) {
1278 		bool fallback = true;
1279 
1280 		(void)lwm2m_get_bool(&LWM2M_OBJ(LWM2M_OBJECT_SERVER_ID, client.ctx->srv_obj_inst,
1281 						SERVER_BOOTSTRAP_ON_REGISTRATION_FAILURE_ID),
1282 				     &fallback);
1283 		if (fallback) {
1284 			client.use_bootstrap = true;
1285 			set_sm_state(ENGINE_INIT);
1286 			return true;
1287 		}
1288 	}
1289 	return false;
1290 }
1291 
sm_do_network_error(void)1292 static void sm_do_network_error(void)
1293 {
1294 	int err;
1295 
1296 	LOG_ERR("sm_do_network_error, retries %d", client.retries);
1297 
1298 	lwm2m_socket_close(client.ctx);
1299 
1300 	if (client.retry_delay) {
1301 		next_event_at(k_uptime_get() + client.retry_delay * MSEC_PER_SEC);
1302 		client.retry_delay = 0;
1303 		return;
1304 	}
1305 	client.retry_delay = 1 << client.retries;
1306 	client.retries++;
1307 
1308 	/* Stop retrying and try fallback */
1309 	if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) {
1310 		LOG_ERR("Network error, max retries reached (%d)", client.retries);
1311 
1312 		/* Disable current server for a period so lwm2m_server_select() does not pick it */
1313 		if (client.ctx->srv_obj_inst > -1) {
1314 			lwm2m_server_disable(client.ctx->srv_obj_inst, DISABLE_TIMEOUT);
1315 		}
1316 
1317 		/* Are we in bootstrap? Try if we can fallback to some other BS server */
1318 		if (client.ctx->bootstrap_mode &&
1319 		    IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) {
1320 			LOG_DBG("In bootstrap, try fallback srv");
1321 			/* Do we have any other bootstrap server to back off to? */
1322 			if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) {
1323 				/* No, we are out of options, stop engine */
1324 				goto stop_engine;
1325 			}
1326 			set_sm_state(ENGINE_INIT);
1327 			return;
1328 		}
1329 
1330 		/* Try if there are other server to fall back to,
1331 		 * Only allow fallback to higher priority server (lower value, or lower id)
1332 		 * if we have successfully registered before.
1333 		 * This should block us from looping the same list again.
1334 		 * Instead we should fallback to bootstrap.
1335 		 */
1336 		uint16_t srv;
1337 
1338 		if (lwm2m_server_select(&srv)) {
1339 			uint8_t p1, p2;
1340 
1341 			p1 = lwm2m_server_get_prio(client.ctx->srv_obj_inst);
1342 			p2 = lwm2m_server_get_prio(srv);
1343 			if (p1 < p2 || client.last_update != 0) {
1344 				set_sm_state(ENGINE_INIT);
1345 				return;
1346 			}
1347 		}
1348 
1349 		/* If we have been disabled by some server, don't fall back to bootstrap */
1350 		if (client.server_disabled) {
1351 			set_sm_state(ENGINE_SERVER_DISABLED);
1352 			return;
1353 		}
1354 
1355 		if (fallback_to_bootstrap()) {
1356 			return;
1357 		}
1358 		goto stop_engine;
1359 	}
1360 
1361 	/* Retry bootstrap */
1362 	if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)) {
1363 		if (client.ctx->bootstrap_mode) {
1364 			lwm2m_engine_context_close(client.ctx);
1365 			/* If we don't have fallback BS server, retry with current one */
1366 			if (sm_next_bootstrap_inst(&client.ctx->sec_obj_inst) < 0) {
1367 				client.ctx->sec_obj_inst = -1;
1368 			}
1369 			set_sm_state(ENGINE_DO_BOOTSTRAP_REG);
1370 			return;
1371 		}
1372 	}
1373 
1374 	if (!client.last_update ||
1375 	    (k_uptime_get() - client.last_update) / MSEC_PER_SEC > client.lifetime) {
1376 		/* do full registration as there is no active registration or lifetime exceeded */
1377 		/* Keep the same server until out of retry */
1378 		set_sm_state(ENGINE_DO_REGISTRATION);
1379 		return;
1380 	}
1381 
1382 	/* Try if we can recover the DTLS session and try Update.
1383 	 * This might fallback into full registration on sm_handle_registration_update_failure().
1384 	 */
1385 	err = lwm2m_socket_start(client.ctx);
1386 	if (err) {
1387 		LOG_ERR("Failed to start socket %d", err);
1388 		/*
1389 		 * keep this state until lifetime/retry count exceeds. Renew
1390 		 * sm state to set retry_delay etc ...
1391 		 */
1392 		set_sm_state(ENGINE_NETWORK_ERROR);
1393 		return;
1394 	}
1395 	set_sm_state(ENGINE_UPDATE_REGISTRATION);
1396 	return;
1397 
1398 stop_engine:
1399 
1400 	/* We are out of options, stop engine */
1401 	if (client.ctx->event_cb) {
1402 		if (client.ctx->bootstrap_mode) {
1403 			client.ctx->event_cb(client.ctx,
1404 					     LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE);
1405 		} else {
1406 			client.ctx->event_cb(client.ctx, LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR);
1407 		}
1408 	}
1409 	set_sm_state(ENGINE_IDLE);
1410 }
1411 
lwm2m_rd_client_service(struct k_work * work)1412 static void lwm2m_rd_client_service(struct k_work *work)
1413 {
1414 	k_mutex_lock(&client.mutex, K_FOREVER);
1415 
1416 	int64_t timeout = 0;
1417 
1418 	if (client.ctx) {
1419 		LOG_DBG("State: %d", get_sm_state());
1420 		client.next_event = INT64_MAX;
1421 		switch (get_sm_state()) {
1422 		case ENGINE_IDLE:
1423 			if (client.ctx->sock_fd > -1) {
1424 				lwm2m_engine_stop(client.ctx);
1425 			}
1426 			rd_client_message_free();
1427 			break;
1428 
1429 		case ENGINE_INIT:
1430 			sm_do_init();
1431 			break;
1432 
1433 		case ENGINE_SUSPENDED:
1434 			break;
1435 
1436 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
1437 		case ENGINE_DO_BOOTSTRAP_REG:
1438 			sm_do_bootstrap_reg();
1439 			break;
1440 
1441 		case ENGINE_BOOTSTRAP_REG_SENT:
1442 			/* wait for bootstrap registration done */
1443 			timeout = EXCHANGE_LIFETIME;
1444 			break;
1445 
1446 		case ENGINE_BOOTSTRAP_REG_DONE:
1447 			/* wait for transfer done */
1448 			timeout = EXCHANGE_LIFETIME;
1449 			break;
1450 
1451 		case ENGINE_BOOTSTRAP_TRANS_DONE:
1452 			sm_bootstrap_trans_done();
1453 			break;
1454 #endif
1455 
1456 		case ENGINE_DO_REGISTRATION:
1457 			sm_do_registration();
1458 			break;
1459 
1460 		case ENGINE_SEND_REGISTRATION:
1461 			sm_send_registration_msg();
1462 			break;
1463 
1464 		case ENGINE_REGISTRATION_SENT:
1465 			/* wait registration to be done or timeout */
1466 			timeout = EXCHANGE_LIFETIME;
1467 			break;
1468 
1469 		case ENGINE_REGISTRATION_DONE:
1470 		case ENGINE_REGISTRATION_DONE_RX_OFF:
1471 			sm_registration_done();
1472 			break;
1473 
1474 		case ENGINE_UPDATE_REGISTRATION:
1475 			sm_update_registration();
1476 			break;
1477 
1478 		case ENGINE_UPDATE_SENT:
1479 			/* wait update to be done or abort */
1480 			timeout = EXCHANGE_LIFETIME;
1481 			break;
1482 
1483 		case ENGINE_SERVER_DISABLED:
1484 			if (lwm2m_server_select(NULL)) {
1485 				set_sm_state(ENGINE_INIT);
1486 			} else {
1487 				/* wait for server to be enabled. */
1488 				/*
1489 				 * TODO: Once engine is converted to use timepoint_t
1490 				 * this should calculate the next event from the previous server.
1491 				 */
1492 				next_event_at(k_uptime_get() + SEC_PER_MIN * MSEC_PER_SEC);
1493 			}
1494 			break;
1495 
1496 		case ENGINE_DEREGISTER:
1497 			sm_do_deregister();
1498 			break;
1499 
1500 		case ENGINE_DEREGISTER_SENT:
1501 			/* wait for deregister to be done or reset */
1502 			timeout = EXCHANGE_LIFETIME;
1503 			break;
1504 
1505 		case ENGINE_DEREGISTERED:
1506 			lwm2m_engine_stop(client.ctx);
1507 			if (client.server_disabled) {
1508 				set_sm_state(ENGINE_SERVER_DISABLED);
1509 			} else {
1510 				set_sm_state(ENGINE_IDLE);
1511 			}
1512 			break;
1513 
1514 		case ENGINE_NETWORK_ERROR:
1515 			sm_do_network_error();
1516 			break;
1517 
1518 		default:
1519 			LOG_ERR("Unhandled state: %d", get_sm_state());
1520 
1521 		}
1522 
1523 		if (timeout) {
1524 			int64_t end = client.last_state_change + timeout * MSEC_PER_SEC;
1525 
1526 			if (end < k_uptime_get()) {
1527 				LOG_DBG("State machine have timed out");
1528 				sm_handle_timeout_state(ENGINE_INIT);
1529 			} else if (client.next_event > end) {
1530 				next_event_at(end);
1531 			}
1532 		}
1533 	}
1534 
1535 	k_mutex_unlock(&client.mutex);
1536 }
1537 
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)1538 int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name,
1539 			   uint32_t flags, lwm2m_ctx_event_cb_t event_cb,
1540 			   lwm2m_observe_cb_t observe_cb)
1541 {
1542 	k_mutex_lock(&client.mutex, K_FOREVER);
1543 
1544 	if (!IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) &&
1545 	    (flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP)) {
1546 		LOG_ERR("Bootstrap support is disabled. Please enable "
1547 			"CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP.");
1548 
1549 		k_mutex_unlock(&client.mutex);
1550 		return -ENOTSUP;
1551 	}
1552 
1553 	/* Check client idle state or socket is still active */
1554 
1555 	if (client.ctx && (client.engine_state != ENGINE_IDLE || client.ctx->sock_fd != -1)) {
1556 		LOG_WRN("Client is already running. state %d ", client.engine_state);
1557 		k_mutex_unlock(&client.mutex);
1558 		return -EINPROGRESS;
1559 	}
1560 
1561 	/* Init Context */
1562 	lwm2m_server_reset_timestamps();
1563 	lwm2m_engine_context_init(client_ctx);
1564 
1565 	client.ctx = client_ctx;
1566 	client.ctx->sock_fd = -1;
1567 	client.ctx->fault_cb = socket_fault_cb;
1568 	client.ctx->observe_cb = observe_cb;
1569 	client.ctx->event_cb = event_cb;
1570 	client.use_bootstrap = flags & LWM2M_RD_CLIENT_FLAG_BOOTSTRAP;
1571 	client.ctx->srv_obj_inst = -1;
1572 	client.ctx->sec_obj_inst = -1;
1573 	client.retries = 0;
1574 
1575 	strncpy(client.ep_name, ep_name, CLIENT_EP_LEN - 1);
1576 	client.ep_name[CLIENT_EP_LEN - 1] = '\0';
1577 	LOG_INF("Start LWM2M Client: %s", client.ep_name);
1578 
1579 	set_sm_state(ENGINE_INIT);
1580 
1581 	k_mutex_unlock(&client.mutex);
1582 
1583 	return 0;
1584 }
1585 
lwm2m_rd_client_stop(struct lwm2m_ctx * client_ctx,lwm2m_ctx_event_cb_t event_cb,bool deregister)1586 int lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx,
1587 			   lwm2m_ctx_event_cb_t event_cb, bool deregister)
1588 {
1589 	k_mutex_lock(&client.mutex, K_FOREVER);
1590 
1591 	if (client.ctx != client_ctx) {
1592 		k_mutex_unlock(&client.mutex);
1593 		LOG_WRN("Cannot stop. Wrong context");
1594 		return -EPERM;
1595 	}
1596 
1597 	client.ctx->event_cb = event_cb;
1598 	rd_client_message_free();
1599 
1600 	if (sm_is_registered() && deregister && !client.server_disabled) {
1601 		set_sm_state(ENGINE_DEREGISTER);
1602 	} else {
1603 		client.server_disabled = false;
1604 		set_sm_state(ENGINE_DEREGISTERED);
1605 	}
1606 
1607 	LOG_INF("Stop LWM2M Client: %s", client.ep_name);
1608 
1609 	k_mutex_unlock(&client.mutex);
1610 
1611 
1612 	return 0;
1613 }
1614 
lwm2m_rd_client_pause(void)1615 int lwm2m_rd_client_pause(void)
1616 {
1617 	enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_ENGINE_SUSPENDED;
1618 	LOG_DBG("lwm2m_rd_client_pause()");
1619 
1620 	k_mutex_lock(&client.mutex, K_FOREVER);
1621 
1622 	if (!client.ctx) {
1623 		k_mutex_unlock(&client.mutex);
1624 		LOG_ERR("Cannot pause. No context");
1625 		return -EPERM;
1626 	} else if (sm_is_suspended()) {
1627 		k_mutex_unlock(&client.mutex);
1628 		LOG_ERR("LwM2M client already suspended");
1629 		return 0;
1630 	}
1631 
1632 	LOG_INF("Suspend client");
1633 	if (client.ctx->event_cb) {
1634 		client.ctx->event_cb(client.ctx, event);
1635 	}
1636 
1637 	/* Suspend or close the socket */
1638 	if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_CLOSE_SOCKET_AT_IDLE)) {
1639 		lwm2m_close_socket(client.ctx);
1640 	} else {
1641 		lwm2m_socket_suspend(client.ctx);
1642 	}
1643 
1644 	suspended_client_state = get_sm_state();
1645 	set_sm_state(ENGINE_SUSPENDED);
1646 
1647 	k_mutex_unlock(&client.mutex);
1648 
1649 	return 0;
1650 }
1651 
lwm2m_rd_client_resume(void)1652 int lwm2m_rd_client_resume(void)
1653 {
1654 	k_mutex_lock(&client.mutex, K_FOREVER);
1655 
1656 	if (!client.ctx || !lwm2m_rd_client_is_suspended(client.ctx)) {
1657 		k_mutex_unlock(&client.mutex);
1658 		LOG_WRN("Cannot resume, state is not suspended");
1659 		return -EPERM;
1660 	}
1661 
1662 	LOG_INF("Resume Client state");
1663 
1664 	if (suspended_client_state == ENGINE_UPDATE_SENT) {
1665 		/* Set back to Registration done and trigger an update */
1666 		suspended_client_state = ENGINE_REGISTRATION_DONE;
1667 	}
1668 	/* Clear Possible pending RD Client message */
1669 	rd_client_message_free();
1670 
1671 	client.engine_state = suspended_client_state;
1672 
1673 	/* Do we need to resume the bootstrap? */
1674 #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
1675 	if (sm_is_bootstrap()) {
1676 		client.engine_state = ENGINE_DO_BOOTSTRAP_REG;
1677 	}
1678 #endif
1679 	/* Or do we resume into registration state */
1680 	if (client.engine_state >= ENGINE_DO_REGISTRATION &&
1681 		client.engine_state <= ENGINE_SERVER_DISABLED) {
1682 		if (!client.last_update ||
1683 			(client.lifetime <= (k_uptime_get() - client.last_update) / MSEC_PER_SEC)) {
1684 			/* No lifetime left, register again */
1685 			client.engine_state = ENGINE_DO_REGISTRATION;
1686 		} else {
1687 			/* Resume similarly like from QUEUE mode */
1688 			client.engine_state = ENGINE_REGISTRATION_DONE_RX_OFF;
1689 			lwm2m_rd_client_connection_resume(client.ctx);
1690 		}
1691 	}
1692 
1693 	next_event_at(0);
1694 	k_mutex_unlock(&client.mutex);
1695 
1696 	return 0;
1697 }
1698 
lwm2m_rd_client_server_disabled(uint16_t inst_id)1699 int lwm2m_rd_client_server_disabled(uint16_t inst_id)
1700 {
1701 	if (client.ctx->srv_obj_inst != inst_id) {
1702 		return -EPERM;
1703 	}
1704 
1705 	k_mutex_lock(&client.mutex, K_FOREVER);
1706 
1707 	client.server_disabled = true;
1708 
1709 	if (sm_is_registered()) {
1710 		LOG_INF("Server disabled, deregister");
1711 		set_sm_state_delayed(ENGINE_DEREGISTER, DELAY_BEFORE_CLOSING);
1712 	} else {
1713 		LOG_INF("Server disabled");
1714 		set_sm_state(ENGINE_DEREGISTERED);
1715 	}
1716 
1717 	k_mutex_unlock(&client.mutex);
1718 
1719 	return 0;
1720 }
1721 
lwm2m_rd_client_update(void)1722 void lwm2m_rd_client_update(void)
1723 {
1724 	engine_trigger_update(false);
1725 }
1726 
lwm2m_rd_client_ctx(void)1727 struct lwm2m_ctx *lwm2m_rd_client_ctx(void)
1728 {
1729 	return client.ctx;
1730 }
1731 
lwm2m_rd_client_set_ctx(struct lwm2m_ctx * ctx)1732 void lwm2m_rd_client_set_ctx(struct lwm2m_ctx *ctx)
1733 {
1734 	client.ctx = ctx;
1735 }
1736 
lwm2m_rd_client_connection_resume(struct lwm2m_ctx * client_ctx)1737 int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx)
1738 {
1739 	if (client.ctx != client_ctx) {
1740 		return -EPERM;
1741 	}
1742 
1743 	if (client.engine_state == ENGINE_REGISTRATION_DONE_RX_OFF) {
1744 		/*
1745 		 * Switch state to triggering a proper registration message
1746 		 * If the socket stays open (Connection ID or no-sec), or we have TLS session cache,
1747 		 * we can trigger the update, otherwise fall back to full registration.
1748 		 */
1749 		if ((IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUSPEND_SOCKET_AT_IDLE) &&
1750 		     IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) ||
1751 		    (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_STOP_POLLING_AT_IDLE) ||
1752 		     IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_LISTEN_AT_IDLE)) ||
1753 		    !IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT)) {
1754 			client.engine_state = ENGINE_REGISTRATION_DONE;
1755 			if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_NO_MSG_BUFFERING)) {
1756 				/* Force online for a short period */
1757 				engine_update_tx_time();
1758 			} else {
1759 				client.trigger_update = true;
1760 			}
1761 		} else {
1762 			client.engine_state = ENGINE_DO_REGISTRATION;
1763 		}
1764 		next_event_at(0);
1765 	}
1766 
1767 	return 0;
1768 }
1769 
lwm2m_rd_client_timeout(struct lwm2m_ctx * client_ctx)1770 int lwm2m_rd_client_timeout(struct lwm2m_ctx *client_ctx)
1771 {
1772 	if (client.ctx != client_ctx) {
1773 		return -EPERM;
1774 	}
1775 
1776 	if (!sm_is_registered()) {
1777 		return 0;
1778 	}
1779 	k_mutex_lock(&client.mutex, K_FOREVER);
1780 	LOG_WRN("Confirmable Timeout -> Re-connect and register");
1781 	set_sm_state(ENGINE_DO_REGISTRATION);
1782 	next_event_at(0);
1783 	k_mutex_unlock(&client.mutex);
1784 	return 0;
1785 }
1786 
lwm2m_rd_client_is_registred(struct lwm2m_ctx * client_ctx)1787 bool lwm2m_rd_client_is_registred(struct lwm2m_ctx *client_ctx)
1788 {
1789 	if (client.ctx != client_ctx || !sm_is_registered()) {
1790 		return false;
1791 	}
1792 
1793 	return true;
1794 }
lwm2m_rd_client_is_suspended(struct lwm2m_ctx * client_ctx)1795 bool lwm2m_rd_client_is_suspended(struct lwm2m_ctx *client_ctx)
1796 {
1797 	if (client.ctx != client_ctx || !sm_is_suspended()) {
1798 		return false;
1799 	}
1800 
1801 	return true;
1802 }
1803 
1804 
lwm2m_rd_client_init(void)1805 int lwm2m_rd_client_init(void)
1806 {
1807 	client.ctx = NULL;
1808 	client.rd_message.ctx = NULL;
1809 	client.engine_state = ENGINE_IDLE;
1810 	k_mutex_init(&client.mutex);
1811 
1812 	return 0;
1813 }
1814 
sys_lwm2m_rd_client_init(void)1815 static int sys_lwm2m_rd_client_init(void)
1816 {
1817 	return lwm2m_rd_client_init();
1818 }
1819 
1820 LWM2M_ENGINE_INIT(sys_lwm2m_rd_client_init);
1821