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