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