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