1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2018-2019 Foundries.io
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * Uses some original concepts by:
10  *         Joakim Eriksson <joakime@sics.se>
11  *         Niclas Finne <nfi@sics.se>
12  *         Joel Hoglund <joel@sics.se>
13  */
14 
15 #define LOG_MODULE_NAME net_lwm2m_registry
16 #define LOG_LEVEL	CONFIG_LWM2M_LOG_LEVEL
17 
18 #include <zephyr/logging/log.h>
19 #include <zephyr/sys/ring_buffer.h>
20 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
21 
22 #include "lwm2m_engine.h"
23 #include "lwm2m_object.h"
24 #include "lwm2m_obj_access_control.h"
25 #include "lwm2m_util.h"
26 #include "lwm2m_rd_client.h"
27 
28 #include <ctype.h>
29 #include <errno.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 
36 #include <zephyr/types.h>
37 
38 #define BINDING_OPT_MAX_LEN 3 /* "UQ" */
39 #define QUEUE_OPT_MAX_LEN   2 /* "Q" */
40 
41 /* Thread safety */
42 static K_MUTEX_DEFINE(registry_lock);
43 
lwm2m_registry_lock(void)44 void lwm2m_registry_lock(void)
45 {
46 	(void)k_mutex_lock(&registry_lock, K_FOREVER);
47 }
48 
lwm2m_registry_unlock(void)49 void lwm2m_registry_unlock(void)
50 {
51 	(void)k_mutex_unlock(&registry_lock);
52 }
53 
54 /* Default core object version */
55 struct default_obj_version {
56 	uint16_t obj_id;
57 	uint8_t version_major;
58 	uint8_t version_minor;
59 };
60 
61 /* Based on Appendix E of the respective LwM2M specification. */
62 static const struct default_obj_version default_obj_versions[] = {
63 #if defined(CONFIG_LWM2M_VERSION_1_0)
64 	{ LWM2M_OBJECT_SECURITY_ID, 1, 0 },
65 	{ LWM2M_OBJECT_SERVER_ID, 1, 0 },
66 	{ LWM2M_OBJECT_ACCESS_CONTROL_ID, 1, 0 },
67 	{ LWM2M_OBJECT_DEVICE_ID, 1, 0 },
68 	{ LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID, 1, 0 },
69 	{ LWM2M_OBJECT_FIRMWARE_ID, 1, 0 },
70 	{ LWM2M_OBJECT_LOCATION_ID, 1, 0 },
71 	{ LWM2M_OBJECT_CONNECTIVITY_STATISTICS_ID, 1, 0 },
72 #elif defined(CONFIG_LWM2M_VERSION_1_1)
73 	{ LWM2M_OBJECT_SECURITY_ID, 1, 1 },
74 	{ LWM2M_OBJECT_SERVER_ID, 1, 1 },
75 	{ LWM2M_OBJECT_ACCESS_CONTROL_ID, 1, 0 },
76 	{ LWM2M_OBJECT_DEVICE_ID, 1, 1 },
77 	{ LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID, 1, 2 },
78 	{ LWM2M_OBJECT_FIRMWARE_ID, 1, 0 },
79 	{ LWM2M_OBJECT_LOCATION_ID, 1, 0 },
80 	{ LWM2M_OBJECT_CONNECTIVITY_STATISTICS_ID, 1, 0 },
81 	/* OSCORE object not implemented yet, but include it for completeness */
82 	{ LWM2M_OBJECT_OSCORE_ID, 1, 0 },
83 #else
84 #error "Default core object versions not defined for LwM2M version"
85 #endif
86 };
87 
88 /* Resources */
89 static sys_slist_t engine_obj_list;
90 static sys_slist_t engine_obj_inst_list;
91 
92 /* Resource wrappers */
lwm2m_engine_obj_list(void)93 sys_slist_t *lwm2m_engine_obj_list(void) { return &engine_obj_list; }
94 
lwm2m_engine_obj_inst_list(void)95 sys_slist_t *lwm2m_engine_obj_inst_list(void) { return &engine_obj_inst_list; }
96 
97 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
98 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
99 				     const struct lwm2m_obj_path *path, const void *value,
100 				     uint16_t len);
101 #endif
102 /* Engine object */
103 
lwm2m_register_obj(struct lwm2m_engine_obj * obj)104 void lwm2m_register_obj(struct lwm2m_engine_obj *obj)
105 {
106 	k_mutex_lock(&registry_lock, K_FOREVER);
107 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
108 	/* If bootstrap, then bootstrap server should create the ac obj instances */
109 #if !IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
110 	int server_obj_inst_id = lwm2m_server_short_id_to_inst(CONFIG_LWM2M_SERVER_DEFAULT_SSID);
111 
112 	access_control_add_obj(obj->obj_id, server_obj_inst_id);
113 #endif /* CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP */
114 #endif /* CONFIG_LWM2M_ACCESS_CONTROL_ENABLE */
115 	sys_slist_append(&engine_obj_list, &obj->node);
116 	k_mutex_unlock(&registry_lock);
117 }
118 
lwm2m_unregister_obj(struct lwm2m_engine_obj * obj)119 void lwm2m_unregister_obj(struct lwm2m_engine_obj *obj)
120 {
121 	k_mutex_lock(&registry_lock, K_FOREVER);
122 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
123 	access_control_remove_obj(obj->obj_id);
124 #endif
125 	engine_remove_observer_by_id(obj->obj_id, -1);
126 	sys_slist_find_and_remove(&engine_obj_list, &obj->node);
127 	k_mutex_unlock(&registry_lock);
128 }
129 
get_engine_obj(int obj_id)130 struct lwm2m_engine_obj *get_engine_obj(int obj_id)
131 {
132 	struct lwm2m_engine_obj *obj;
133 
134 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) {
135 		if (obj->obj_id == obj_id) {
136 			return obj;
137 		}
138 	}
139 
140 	return NULL;
141 }
142 
lwm2m_get_engine_obj_field(struct lwm2m_engine_obj * obj,int res_id)143 struct lwm2m_engine_obj_field *lwm2m_get_engine_obj_field(struct lwm2m_engine_obj *obj, int res_id)
144 {
145 	int i;
146 
147 	if (obj && obj->fields && obj->field_count > 0) {
148 		for (i = 0; i < obj->field_count; i++) {
149 			if (obj->fields[i].res_id == res_id) {
150 				return &obj->fields[i];
151 			}
152 		}
153 	}
154 
155 	return NULL;
156 }
157 
lwm2m_engine_get_obj(const struct lwm2m_obj_path * path)158 struct lwm2m_engine_obj *lwm2m_engine_get_obj(const struct lwm2m_obj_path *path)
159 {
160 	if (path->level < LWM2M_PATH_LEVEL_OBJECT) {
161 		return NULL;
162 	}
163 
164 	return get_engine_obj(path->obj_id);
165 }
166 /* Engine object instance */
167 
engine_register_obj_inst(struct lwm2m_engine_obj_inst * obj_inst)168 static void engine_register_obj_inst(struct lwm2m_engine_obj_inst *obj_inst)
169 {
170 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
171 	/* If bootstrap, then bootstrap server should create the ac obj instances */
172 #if !IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
173 	int server_obj_inst_id = lwm2m_server_short_id_to_inst(CONFIG_LWM2M_SERVER_DEFAULT_SSID);
174 
175 	access_control_add(obj_inst->obj->obj_id, obj_inst->obj_inst_id, server_obj_inst_id);
176 #endif /* CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP */
177 #endif /* CONFIG_LWM2M_ACCESS_CONTROL_ENABLE */
178 	sys_slist_append(&engine_obj_inst_list, &obj_inst->node);
179 }
180 
engine_unregister_obj_inst(struct lwm2m_engine_obj_inst * obj_inst)181 static void engine_unregister_obj_inst(struct lwm2m_engine_obj_inst *obj_inst)
182 {
183 #if defined(CONFIG_LWM2M_ACCESS_CONTROL_ENABLE)
184 	access_control_remove(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
185 #endif
186 	engine_remove_observer_by_id(obj_inst->obj->obj_id, obj_inst->obj_inst_id);
187 	sys_slist_find_and_remove(&engine_obj_inst_list, &obj_inst->node);
188 }
189 
get_engine_obj_inst(int obj_id,int obj_inst_id)190 struct lwm2m_engine_obj_inst *get_engine_obj_inst(int obj_id, int obj_inst_id)
191 {
192 	struct lwm2m_engine_obj_inst *obj_inst;
193 
194 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) {
195 		if (obj_inst->obj->obj_id == obj_id && obj_inst->obj_inst_id == obj_inst_id) {
196 			return obj_inst;
197 		}
198 	}
199 
200 	return NULL;
201 }
202 
next_engine_obj_inst(int obj_id,int obj_inst_id)203 struct lwm2m_engine_obj_inst *next_engine_obj_inst(int obj_id, int obj_inst_id)
204 {
205 	struct lwm2m_engine_obj_inst *obj_inst, *next = NULL;
206 
207 	SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) {
208 		if (obj_inst->obj->obj_id == obj_id && obj_inst->obj_inst_id > obj_inst_id &&
209 		    (!next || next->obj_inst_id > obj_inst->obj_inst_id)) {
210 			next = obj_inst;
211 		}
212 	}
213 
214 	return next;
215 }
216 
lwm2m_create_obj_inst(uint16_t obj_id,uint16_t obj_inst_id,struct lwm2m_engine_obj_inst ** obj_inst)217 int lwm2m_create_obj_inst(uint16_t obj_id, uint16_t obj_inst_id,
218 			  struct lwm2m_engine_obj_inst **obj_inst)
219 {
220 	k_mutex_lock(&registry_lock, K_FOREVER);
221 	struct lwm2m_engine_obj *obj;
222 	int ret;
223 
224 	*obj_inst = NULL;
225 	obj = get_engine_obj(obj_id);
226 	if (!obj) {
227 		LOG_ERR("unable to find obj: %u", obj_id);
228 		k_mutex_unlock(&registry_lock);
229 		return -ENOENT;
230 	}
231 
232 	if (!obj->create_cb) {
233 		LOG_ERR("obj %u has no create_cb", obj_id);
234 		k_mutex_unlock(&registry_lock);
235 		return -EINVAL;
236 	}
237 
238 	if (obj->instance_count + 1 > obj->max_instance_count) {
239 		LOG_ERR("no more instances available for obj %u", obj_id);
240 		k_mutex_unlock(&registry_lock);
241 		return -ENOMEM;
242 	}
243 
244 	*obj_inst = obj->create_cb(obj_inst_id);
245 	if (!*obj_inst) {
246 		LOG_ERR("unable to create obj %u instance %u", obj_id, obj_inst_id);
247 		/*
248 		 * Already checked for instance count total.
249 		 * This can only be an error if the object instance exists.
250 		 */
251 		k_mutex_unlock(&registry_lock);
252 		return -EEXIST;
253 	}
254 
255 	obj->instance_count++;
256 	(*obj_inst)->obj = obj;
257 	(*obj_inst)->obj_inst_id = obj_inst_id;
258 	engine_register_obj_inst(*obj_inst);
259 
260 	if (obj->user_create_cb) {
261 		ret = obj->user_create_cb(obj_inst_id);
262 		if (ret < 0) {
263 			LOG_ERR("Error in user obj create %u/%u: %d", obj_id, obj_inst_id, ret);
264 			k_mutex_unlock(&registry_lock);
265 			lwm2m_delete_obj_inst(obj_id, obj_inst_id);
266 			return ret;
267 		}
268 	}
269 	k_mutex_unlock(&registry_lock);
270 	return 0;
271 }
272 
lwm2m_delete_obj_inst(uint16_t obj_id,uint16_t obj_inst_id)273 int lwm2m_delete_obj_inst(uint16_t obj_id, uint16_t obj_inst_id)
274 {
275 	k_mutex_lock(&registry_lock, K_FOREVER);
276 	int i, ret = 0;
277 	struct lwm2m_engine_obj *obj;
278 	struct lwm2m_engine_obj_inst *obj_inst;
279 
280 	obj = get_engine_obj(obj_id);
281 	if (!obj) {
282 		k_mutex_unlock(&registry_lock);
283 		return -ENOENT;
284 	}
285 
286 	obj_inst = get_engine_obj_inst(obj_id, obj_inst_id);
287 	if (!obj_inst) {
288 		k_mutex_unlock(&registry_lock);
289 		return -ENOENT;
290 	}
291 
292 	if (obj->user_delete_cb) {
293 		ret = obj->user_delete_cb(obj_inst_id);
294 		if (ret < 0) {
295 			LOG_ERR("Error in user obj delete %u/%u: %d", obj_id, obj_inst_id, ret);
296 			/* don't return error */
297 		}
298 	}
299 
300 	engine_unregister_obj_inst(obj_inst);
301 	obj->instance_count--;
302 
303 	if (obj->delete_cb) {
304 		ret = obj->delete_cb(obj_inst_id);
305 	}
306 
307 	/* reset obj_inst and res_inst data structure */
308 	for (i = 0; i < obj_inst->resource_count; i++) {
309 		clear_attrs(&obj_inst->resources[i]);
310 		(void)memset(obj_inst->resources + i, 0, sizeof(struct lwm2m_engine_res));
311 	}
312 
313 	clear_attrs(obj_inst);
314 	(void)memset(obj_inst, 0, sizeof(struct lwm2m_engine_obj_inst));
315 	k_mutex_unlock(&registry_lock);
316 	return ret;
317 }
318 
lwm2m_create_object_inst(const struct lwm2m_obj_path * path)319 int lwm2m_create_object_inst(const struct lwm2m_obj_path *path)
320 {
321 	struct lwm2m_engine_obj_inst *obj_inst;
322 	int ret = 0;
323 
324 	if (path->level != LWM2M_PATH_LEVEL_OBJECT_INST) {
325 		LOG_ERR("path must have 2 parts");
326 		return -EINVAL;
327 	}
328 
329 	ret = lwm2m_create_obj_inst(path->obj_id, path->obj_inst_id, &obj_inst);
330 	if (ret < 0) {
331 		return ret;
332 	}
333 
334 	engine_trigger_update(true);
335 
336 	return 0;
337 }
338 
lwm2m_engine_create_obj_inst(const char * pathstr)339 int lwm2m_engine_create_obj_inst(const char *pathstr)
340 {
341 	struct lwm2m_obj_path path;
342 	int ret = 0;
343 
344 	LOG_DBG("path:%s", pathstr);
345 
346 	/* translate path -> path_obj */
347 	ret = lwm2m_string_to_path(pathstr, &path, '/');
348 	if (ret < 0) {
349 		return ret;
350 	}
351 
352 	return lwm2m_create_object_inst(&path);
353 }
354 
lwm2m_delete_object_inst(const struct lwm2m_obj_path * path)355 int lwm2m_delete_object_inst(const struct lwm2m_obj_path *path)
356 {
357 	int ret = 0;
358 
359 	if (path->level != LWM2M_PATH_LEVEL_OBJECT_INST) {
360 		LOG_ERR("path must have 2 parts");
361 		return -EINVAL;
362 	}
363 
364 	ret = lwm2m_delete_obj_inst(path->obj_id, path->obj_inst_id);
365 	if (ret < 0) {
366 		return ret;
367 	}
368 
369 	engine_trigger_update(true);
370 
371 	return 0;
372 }
373 
lwm2m_engine_delete_obj_inst(const char * pathstr)374 int lwm2m_engine_delete_obj_inst(const char *pathstr)
375 {
376 	struct lwm2m_obj_path path;
377 	int ret = 0;
378 
379 	LOG_DBG("path: %s", pathstr);
380 
381 	/* translate path -> path_obj */
382 	ret = lwm2m_string_to_path(pathstr, &path, '/');
383 	if (ret < 0) {
384 		return ret;
385 	}
386 
387 	return lwm2m_delete_object_inst(&path);
388 }
389 
lwm2m_engine_get_obj_inst(const struct lwm2m_obj_path * path)390 struct lwm2m_engine_obj_inst *lwm2m_engine_get_obj_inst(const struct lwm2m_obj_path *path)
391 {
392 	if (path->level < LWM2M_PATH_LEVEL_OBJECT_INST) {
393 		return NULL;
394 	}
395 
396 	return get_engine_obj_inst(path->obj_id, path->obj_inst_id);
397 }
398 
path_to_objs(const struct lwm2m_obj_path * path,struct lwm2m_engine_obj_inst ** obj_inst,struct lwm2m_engine_obj_field ** obj_field,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)399 int path_to_objs(const struct lwm2m_obj_path *path, struct lwm2m_engine_obj_inst **obj_inst,
400 		 struct lwm2m_engine_obj_field **obj_field, struct lwm2m_engine_res **res,
401 		 struct lwm2m_engine_res_inst **res_inst)
402 {
403 	struct lwm2m_engine_obj_inst *oi;
404 	struct lwm2m_engine_obj_field *of;
405 	struct lwm2m_engine_res *r = NULL;
406 	struct lwm2m_engine_res_inst *ri = NULL;
407 	int i;
408 
409 	if (!path) {
410 		return -EINVAL;
411 	}
412 
413 	oi = get_engine_obj_inst(path->obj_id, path->obj_inst_id);
414 	if (!oi) {
415 		LOG_ERR("obj instance %d/%d not found", path->obj_id, path->obj_inst_id);
416 		return -ENOENT;
417 	}
418 
419 	if (!oi->resources || oi->resource_count == 0U) {
420 		LOG_ERR("obj instance has no resources");
421 		return -EINVAL;
422 	}
423 
424 	of = lwm2m_get_engine_obj_field(oi->obj, path->res_id);
425 	if (!of) {
426 		LOG_ERR("obj field %d not found", path->res_id);
427 		return -ENOENT;
428 	}
429 
430 	for (i = 0; i < oi->resource_count; i++) {
431 		if (oi->resources[i].res_id == path->res_id) {
432 			r = &oi->resources[i];
433 			break;
434 		}
435 	}
436 
437 	if (!r) {
438 		if (LWM2M_HAS_PERM(of, BIT(LWM2M_FLAG_OPTIONAL))) {
439 			LOG_DBG("resource %d not found", path->res_id);
440 		} else {
441 			LOG_ERR("resource %d not found", path->res_id);
442 		}
443 
444 		return -ENOENT;
445 	}
446 
447 	for (i = 0; i < r->res_inst_count; i++) {
448 		if (r->res_instances[i].res_inst_id == path->res_inst_id) {
449 			ri = &r->res_instances[i];
450 			break;
451 		}
452 	}
453 
454 	/* specifically don't complain about missing resource instance */
455 
456 	if (obj_inst) {
457 		*obj_inst = oi;
458 	}
459 
460 	if (obj_field) {
461 		*obj_field = of;
462 	}
463 
464 	if (res) {
465 		*res = r;
466 	}
467 
468 	if (ri && res_inst) {
469 		*res_inst = ri;
470 	}
471 
472 	return 0;
473 }
474 
is_string(const struct lwm2m_obj_path * path)475 static bool is_string(const struct lwm2m_obj_path *path)
476 {
477 	struct lwm2m_engine_obj_field *obj_field;
478 	int ret;
479 
480 	ret = path_to_objs(path, NULL, &obj_field, NULL, NULL);
481 	if (ret < 0 || !obj_field) {
482 		return false;
483 	}
484 	if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
485 		return true;
486 	}
487 	return false;
488 }
489 
490 /* User data setter functions */
491 
lwm2m_set_res_buf(const struct lwm2m_obj_path * path,void * buffer_ptr,uint16_t buffer_len,uint16_t data_len,uint8_t data_flags)492 int lwm2m_set_res_buf(const struct lwm2m_obj_path *path, void *buffer_ptr, uint16_t buffer_len,
493 		      uint16_t data_len, uint8_t data_flags)
494 {
495 	int ret;
496 	struct lwm2m_engine_res_inst *res_inst = NULL;
497 
498 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
499 		LOG_ERR("path must have at least 3 parts");
500 		return -EINVAL;
501 	}
502 
503 	k_mutex_lock(&registry_lock, K_FOREVER);
504 	/* look up resource obj */
505 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
506 	if (ret < 0) {
507 		k_mutex_unlock(&registry_lock);
508 		return ret;
509 	}
510 
511 	if (!res_inst) {
512 		LOG_ERR("res instance %d not found", path->res_inst_id);
513 		k_mutex_unlock(&registry_lock);
514 		return -ENOENT;
515 	}
516 
517 	/* assign data elements */
518 	res_inst->data_ptr = buffer_ptr;
519 	res_inst->data_len = data_len;
520 	res_inst->max_data_len = buffer_len;
521 	res_inst->data_flags = data_flags;
522 
523 	k_mutex_unlock(&registry_lock);
524 	return ret;
525 }
526 
lwm2m_engine_set_res_buf(const char * pathstr,void * buffer_ptr,uint16_t buffer_len,uint16_t data_len,uint8_t data_flags)527 int lwm2m_engine_set_res_buf(const char *pathstr, void *buffer_ptr, uint16_t buffer_len,
528 			     uint16_t data_len, uint8_t data_flags)
529 {
530 	struct lwm2m_obj_path path;
531 	int ret = 0;
532 
533 	/* translate path -> path_obj */
534 	ret = lwm2m_string_to_path(pathstr, &path, '/');
535 	if (ret < 0) {
536 		return ret;
537 	}
538 
539 	return lwm2m_set_res_buf(&path, buffer_ptr, buffer_len, data_len, data_flags);
540 }
541 
lwm2m_engine_set_res_data(const char * pathstr,void * data_ptr,uint16_t data_len,uint8_t data_flags)542 int lwm2m_engine_set_res_data(const char *pathstr, void *data_ptr, uint16_t data_len,
543 			      uint8_t data_flags)
544 {
545 	struct lwm2m_obj_path path;
546 	int ret = 0;
547 
548 	/* translate path -> path_obj */
549 	ret = lwm2m_string_to_path(pathstr, &path, '/');
550 	if (ret < 0) {
551 		return ret;
552 	}
553 
554 	return lwm2m_set_res_buf(&path, data_ptr, data_len, data_len, data_flags);
555 }
556 
lwm2m_validate_time_resource_lenghts(uint16_t resource_length,uint16_t buf_length)557 static bool lwm2m_validate_time_resource_lenghts(uint16_t resource_length, uint16_t buf_length)
558 {
559 	if (resource_length != sizeof(time_t) && resource_length != sizeof(uint32_t)) {
560 		return false;
561 	}
562 
563 	if (buf_length != sizeof(time_t) && buf_length != sizeof(uint32_t)) {
564 		return false;
565 	}
566 
567 	return true;
568 }
569 
lwm2m_check_buf_sizes(uint8_t data_type,uint16_t resource_length,uint16_t buf_length)570 static int lwm2m_check_buf_sizes(uint8_t data_type, uint16_t resource_length, uint16_t buf_length)
571 {
572 	switch (data_type) {
573 	case LWM2M_RES_TYPE_OPAQUE:
574 	case LWM2M_RES_TYPE_STRING:
575 		if (resource_length > buf_length) {
576 			return -ENOMEM;
577 		}
578 		break;
579 	case LWM2M_RES_TYPE_U32:
580 	case LWM2M_RES_TYPE_U8:
581 	case LWM2M_RES_TYPE_S64:
582 	case LWM2M_RES_TYPE_S32:
583 	case LWM2M_RES_TYPE_S16:
584 	case LWM2M_RES_TYPE_S8:
585 	case LWM2M_RES_TYPE_BOOL:
586 	case LWM2M_RES_TYPE_FLOAT:
587 	case LWM2M_RES_TYPE_OBJLNK:
588 		if (resource_length != buf_length) {
589 			return -EINVAL;
590 		}
591 		break;
592 	default:
593 		return 0;
594 	}
595 	return 0;
596 }
597 
lwm2m_engine_set(const struct lwm2m_obj_path * path,const void * value,uint16_t len)598 static int lwm2m_engine_set(const struct lwm2m_obj_path *path, const void *value, uint16_t len)
599 {
600 	struct lwm2m_engine_obj_inst *obj_inst;
601 	struct lwm2m_engine_obj_field *obj_field;
602 	struct lwm2m_engine_res *res = NULL;
603 	struct lwm2m_engine_res_inst *res_inst = NULL;
604 	void *data_ptr = NULL;
605 	size_t max_data_len = 0;
606 	int ret = 0;
607 	bool changed = false;
608 
609 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
610 		LOG_ERR("path must have at least 3 parts");
611 		return -EINVAL;
612 	}
613 
614 	LOG_DBG("path:%u/%u/%u, buf:%p, len:%d", path->obj_id, path->obj_inst_id,
615 		path->res_id, value, len);
616 
617 	k_mutex_lock(&registry_lock, K_FOREVER);
618 	/* look up resource obj */
619 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
620 	if (ret < 0) {
621 		k_mutex_unlock(&registry_lock);
622 		return ret;
623 	}
624 
625 	if (!res_inst) {
626 		LOG_ERR("res instance %d not found", path->res_inst_id);
627 		k_mutex_unlock(&registry_lock);
628 		return -ENOENT;
629 	}
630 
631 	if (LWM2M_HAS_RES_FLAG(res_inst, LWM2M_RES_DATA_FLAG_RO)) {
632 		LOG_ERR("res instance data pointer is read-only "
633 			"[%u/%u/%u/%u:lvl%u]", path->obj_id, path->obj_inst_id, path->res_id,
634 			path->res_inst_id, path->level);
635 		k_mutex_unlock(&registry_lock);
636 		return -EACCES;
637 	}
638 
639 	/* setup initial data elements */
640 	data_ptr = res_inst->data_ptr;
641 	max_data_len = res_inst->max_data_len;
642 
643 	/* allow user to override data elements via callback */
644 	if (res->pre_write_cb) {
645 		data_ptr = res->pre_write_cb(obj_inst->obj_inst_id, res->res_id,
646 					     res_inst->res_inst_id, &max_data_len);
647 	}
648 
649 	if (!data_ptr) {
650 		LOG_ERR("res instance data pointer is NULL [%u/%u/%u/%u:%u]", path->obj_id,
651 			path->obj_inst_id, path->res_id, path->res_inst_id, path->level);
652 		k_mutex_unlock(&registry_lock);
653 		return -EINVAL;
654 	}
655 
656 	ret = lwm2m_check_buf_sizes(obj_field->data_type, len, max_data_len);
657 	if (ret) {
658 		LOG_ERR("Incorrect buffer length %u for res data length %zu", len,
659 			max_data_len);
660 		k_mutex_unlock(&registry_lock);
661 		return ret;
662 	}
663 
664 	if (memcmp(data_ptr, value, len) != 0 || res_inst->data_len != len) {
665 		changed = true;
666 	}
667 
668 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
669 	if (res->validate_cb) {
670 		ret = res->validate_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
671 				       (uint8_t *)value, len, false, 0);
672 		if (ret < 0) {
673 			k_mutex_unlock(&registry_lock);
674 			return -EINVAL;
675 		}
676 	}
677 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
678 
679 	switch (obj_field->data_type) {
680 
681 	case LWM2M_RES_TYPE_OPAQUE:
682 		if (len) {
683 			memcpy((uint8_t *)data_ptr, value, len);
684 		}
685 		break;
686 
687 	case LWM2M_RES_TYPE_STRING:
688 		if (len) {
689 			strncpy(data_ptr, value, len - 1);
690 			((char *)data_ptr)[len - 1] = '\0';
691 		} else {
692 			((char *)data_ptr)[0] = '\0';
693 		}
694 		break;
695 
696 	case LWM2M_RES_TYPE_U32:
697 		*((uint32_t *)data_ptr) = *(uint32_t *)value;
698 		break;
699 
700 	case LWM2M_RES_TYPE_U16:
701 		*((uint16_t *)data_ptr) = *(uint16_t *)value;
702 		break;
703 
704 	case LWM2M_RES_TYPE_U8:
705 		*((uint8_t *)data_ptr) = *(uint8_t *)value;
706 		break;
707 
708 	case LWM2M_RES_TYPE_TIME:
709 		if (!lwm2m_validate_time_resource_lenghts(max_data_len, len)) {
710 			LOG_ERR("Time Set: buffer length %u  max data len %zu not supported", len,
711 				max_data_len);
712 			return -EINVAL;
713 		}
714 
715 		if (max_data_len == sizeof(time_t)) {
716 			if (len == sizeof(time_t)) {
717 				*((time_t *)data_ptr) = *(time_t *)value;
718 			} else {
719 				*((time_t *)data_ptr) = (time_t) *((uint32_t *)value);
720 			}
721 		} else {
722 			LOG_WRN("Converting time to 32bit may cause integer overflow on resource "
723 				"[%u/%u/%u/%u:%u]", path->obj_id, path->obj_inst_id, path->res_id,
724 				path->res_inst_id, path->level);
725 			if (len == sizeof(uint32_t)) {
726 				*((uint32_t *)data_ptr) = *(uint32_t *)value;
727 			} else {
728 				*((uint32_t *)data_ptr) = (uint32_t) *((time_t *)value);
729 			}
730 		}
731 
732 		break;
733 
734 	case LWM2M_RES_TYPE_S64:
735 		*((int64_t *)data_ptr) = *(int64_t *)value;
736 		break;
737 
738 	case LWM2M_RES_TYPE_S32:
739 		*((int32_t *)data_ptr) = *(int32_t *)value;
740 		break;
741 
742 	case LWM2M_RES_TYPE_S16:
743 		*((int16_t *)data_ptr) = *(int16_t *)value;
744 		break;
745 
746 	case LWM2M_RES_TYPE_S8:
747 		*((int8_t *)data_ptr) = *(int8_t *)value;
748 		break;
749 
750 	case LWM2M_RES_TYPE_BOOL:
751 		*((bool *)data_ptr) = *(bool *)value;
752 		break;
753 
754 	case LWM2M_RES_TYPE_FLOAT:
755 		*(double *)data_ptr = *(double *)value;
756 		break;
757 
758 	case LWM2M_RES_TYPE_OBJLNK:
759 		*((struct lwm2m_objlnk *)data_ptr) = *(struct lwm2m_objlnk *)value;
760 		break;
761 
762 	default:
763 		LOG_ERR("unknown obj data_type %d", obj_field->data_type);
764 		k_mutex_unlock(&registry_lock);
765 		return -EINVAL;
766 	}
767 
768 	res_inst->data_len = len;
769 
770 	/* Cache Data Write */
771 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
772 	lwm2m_engine_cache_write(obj_field, path, value, len);
773 #endif
774 
775 	if (res->post_write_cb) {
776 		ret = res->post_write_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
777 					 data_ptr, len, false, 0);
778 	}
779 
780 	if (changed && LWM2M_HAS_PERM(obj_field, LWM2M_PERM_R)) {
781 		lwm2m_notify_observer_path(path);
782 	}
783 	k_mutex_unlock(&registry_lock);
784 	return ret;
785 }
786 
lwm2m_set_opaque(const struct lwm2m_obj_path * path,const char * data_ptr,uint16_t data_len)787 int lwm2m_set_opaque(const struct lwm2m_obj_path *path, const char *data_ptr, uint16_t data_len)
788 {
789 	return lwm2m_engine_set(path, data_ptr, data_len);
790 }
791 
lwm2m_engine_set_opaque(const char * pathstr,const char * data_ptr,uint16_t data_len)792 int lwm2m_engine_set_opaque(const char *pathstr, const char *data_ptr, uint16_t data_len)
793 {
794 	struct lwm2m_obj_path path;
795 	int ret = 0;
796 
797 	ret = lwm2m_string_to_path(pathstr, &path, '/');
798 	if (ret < 0) {
799 		return ret;
800 	}
801 	return lwm2m_set_opaque(&path, data_ptr, data_len);
802 }
803 
lwm2m_set_string(const struct lwm2m_obj_path * path,const char * data_ptr)804 int lwm2m_set_string(const struct lwm2m_obj_path *path, const char *data_ptr)
805 {
806 	uint16_t len = strlen(data_ptr);
807 
808 	/* String resources contain terminator as well, opaque resources don't */
809 	if (is_string(path)) {
810 		len += 1;
811 	}
812 
813 	return lwm2m_engine_set(path, data_ptr, len);
814 }
815 
lwm2m_engine_set_string(const char * pathstr,const char * data_ptr)816 int lwm2m_engine_set_string(const char *pathstr, const char *data_ptr)
817 {
818 	struct lwm2m_obj_path path;
819 	int ret = 0;
820 
821 	ret = lwm2m_string_to_path(pathstr, &path, '/');
822 	if (ret < 0) {
823 		return ret;
824 	}
825 	return lwm2m_set_string(&path, data_ptr);
826 }
827 
lwm2m_set_u8(const struct lwm2m_obj_path * path,uint8_t value)828 int lwm2m_set_u8(const struct lwm2m_obj_path *path, uint8_t value)
829 {
830 	return lwm2m_engine_set(path, &value, 1);
831 }
832 
lwm2m_engine_set_u8(const char * pathstr,uint8_t value)833 int lwm2m_engine_set_u8(const char *pathstr, uint8_t value)
834 {
835 	struct lwm2m_obj_path path;
836 	int ret = 0;
837 
838 	ret = lwm2m_string_to_path(pathstr, &path, '/');
839 	if (ret < 0) {
840 		return ret;
841 	}
842 	return lwm2m_set_u8(&path, value);
843 }
844 
lwm2m_set_u16(const struct lwm2m_obj_path * path,uint16_t value)845 int lwm2m_set_u16(const struct lwm2m_obj_path *path, uint16_t value)
846 {
847 	return lwm2m_engine_set(path, &value, 2);
848 }
849 
lwm2m_engine_set_u16(const char * pathstr,uint16_t value)850 int lwm2m_engine_set_u16(const char *pathstr, uint16_t value)
851 {
852 	struct lwm2m_obj_path path;
853 	int ret = 0;
854 
855 	ret = lwm2m_string_to_path(pathstr, &path, '/');
856 	if (ret < 0) {
857 		return ret;
858 	}
859 	return lwm2m_set_u16(&path, value);
860 }
861 
lwm2m_set_u32(const struct lwm2m_obj_path * path,uint32_t value)862 int lwm2m_set_u32(const struct lwm2m_obj_path *path, uint32_t value)
863 {
864 	return lwm2m_engine_set(path, &value, 4);
865 }
866 
lwm2m_engine_set_u32(const char * pathstr,uint32_t value)867 int lwm2m_engine_set_u32(const char *pathstr, uint32_t value)
868 {
869 	struct lwm2m_obj_path path;
870 	int ret = 0;
871 
872 	ret = lwm2m_string_to_path(pathstr, &path, '/');
873 	if (ret < 0) {
874 		return ret;
875 	}
876 	return lwm2m_set_u32(&path, value);
877 }
878 
lwm2m_set_u64(const struct lwm2m_obj_path * path,uint64_t value)879 int lwm2m_set_u64(const struct lwm2m_obj_path *path, uint64_t value)
880 {
881 	return lwm2m_engine_set(path, &value, 8);
882 }
883 
lwm2m_engine_set_u64(const char * pathstr,uint64_t value)884 int lwm2m_engine_set_u64(const char *pathstr, uint64_t value)
885 {
886 	struct lwm2m_obj_path path;
887 	int ret = 0;
888 
889 	ret = lwm2m_string_to_path(pathstr, &path, '/');
890 	if (ret < 0) {
891 		return ret;
892 	}
893 	return lwm2m_set_s64(&path, (int64_t) value);
894 }
895 
lwm2m_set_s8(const struct lwm2m_obj_path * path,int8_t value)896 int lwm2m_set_s8(const struct lwm2m_obj_path *path, int8_t value)
897 {
898 	return lwm2m_engine_set(path, &value, 1);
899 }
900 
lwm2m_engine_set_s8(const char * pathstr,int8_t value)901 int lwm2m_engine_set_s8(const char *pathstr, int8_t value)
902 {
903 	struct lwm2m_obj_path path;
904 	int ret = 0;
905 
906 	ret = lwm2m_string_to_path(pathstr, &path, '/');
907 	if (ret < 0) {
908 		return ret;
909 	}
910 	return lwm2m_set_s8(&path, value);
911 }
912 
lwm2m_set_s16(const struct lwm2m_obj_path * path,int16_t value)913 int lwm2m_set_s16(const struct lwm2m_obj_path *path, int16_t value)
914 {
915 	return lwm2m_engine_set(path, &value, 2);
916 
917 }
918 
lwm2m_engine_set_s16(const char * pathstr,int16_t value)919 int lwm2m_engine_set_s16(const char *pathstr, int16_t value)
920 {
921 	struct lwm2m_obj_path path;
922 	int ret = 0;
923 
924 	ret = lwm2m_string_to_path(pathstr, &path, '/');
925 	if (ret < 0) {
926 		return ret;
927 	}
928 	return lwm2m_set_s16(&path, value);
929 }
930 
lwm2m_set_s32(const struct lwm2m_obj_path * path,int32_t value)931 int lwm2m_set_s32(const struct lwm2m_obj_path *path, int32_t value)
932 {
933 	return lwm2m_engine_set(path, &value, 4);
934 }
935 
lwm2m_engine_set_s32(const char * pathstr,int32_t value)936 int lwm2m_engine_set_s32(const char *pathstr, int32_t value)
937 {
938 	struct lwm2m_obj_path path;
939 	int ret = 0;
940 
941 	ret = lwm2m_string_to_path(pathstr, &path, '/');
942 	if (ret < 0) {
943 		return ret;
944 	}
945 	return lwm2m_set_s32(&path, value);
946 }
947 
lwm2m_set_s64(const struct lwm2m_obj_path * path,int64_t value)948 int lwm2m_set_s64(const struct lwm2m_obj_path *path, int64_t value)
949 {
950 	return lwm2m_engine_set(path, &value, 8);
951 }
952 
lwm2m_engine_set_s64(const char * pathstr,int64_t value)953 int lwm2m_engine_set_s64(const char *pathstr, int64_t value)
954 {
955 	struct lwm2m_obj_path path;
956 	int ret = 0;
957 
958 	ret = lwm2m_string_to_path(pathstr, &path, '/');
959 	if (ret < 0) {
960 		return ret;
961 	}
962 	return lwm2m_set_s64(&path, value);
963 }
964 
lwm2m_set_bool(const struct lwm2m_obj_path * path,bool value)965 int lwm2m_set_bool(const struct lwm2m_obj_path *path, bool value)
966 {
967 	uint8_t temp = (value != 0 ? 1 : 0);
968 
969 	return lwm2m_engine_set(path, &temp, 1);
970 }
971 
lwm2m_engine_set_bool(const char * pathstr,bool value)972 int lwm2m_engine_set_bool(const char *pathstr, bool value)
973 {
974 	struct lwm2m_obj_path path;
975 	int ret = 0;
976 
977 	ret = lwm2m_string_to_path(pathstr, &path, '/');
978 	if (ret < 0) {
979 		return ret;
980 	}
981 	return lwm2m_set_bool(&path, value);
982 }
983 
lwm2m_set_f64(const struct lwm2m_obj_path * path,const double value)984 int lwm2m_set_f64(const struct lwm2m_obj_path *path, const double value)
985 {
986 	return lwm2m_engine_set(path, &value, sizeof(double));
987 }
988 
lwm2m_engine_set_float(const char * pathstr,const double * value)989 int lwm2m_engine_set_float(const char *pathstr, const double *value)
990 {
991 	struct lwm2m_obj_path path;
992 	int ret = 0;
993 
994 	ret = lwm2m_string_to_path(pathstr, &path, '/');
995 	if (ret < 0) {
996 		return ret;
997 	}
998 	return lwm2m_set_f64(&path, *value);
999 }
1000 
lwm2m_set_objlnk(const struct lwm2m_obj_path * path,const struct lwm2m_objlnk * value)1001 int lwm2m_set_objlnk(const struct lwm2m_obj_path *path, const struct lwm2m_objlnk *value)
1002 {
1003 	return lwm2m_engine_set(path, value, sizeof(struct lwm2m_objlnk));
1004 }
1005 
lwm2m_engine_set_objlnk(const char * pathstr,const struct lwm2m_objlnk * value)1006 int lwm2m_engine_set_objlnk(const char *pathstr, const struct lwm2m_objlnk *value)
1007 {
1008 	struct lwm2m_obj_path path;
1009 	int ret = 0;
1010 
1011 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1012 	if (ret < 0) {
1013 		return ret;
1014 	}
1015 	return lwm2m_set_objlnk(&path, value);
1016 }
1017 
lwm2m_set_time(const struct lwm2m_obj_path * path,time_t value)1018 int lwm2m_set_time(const struct lwm2m_obj_path *path, time_t value)
1019 {
1020 	return lwm2m_engine_set(path, &value, sizeof(time_t));
1021 }
1022 
lwm2m_engine_set_time(const char * pathstr,time_t value)1023 int lwm2m_engine_set_time(const char *pathstr, time_t value)
1024 {
1025 	struct lwm2m_obj_path path;
1026 	int ret = 0;
1027 
1028 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1029 	if (ret < 0) {
1030 		return ret;
1031 	}
1032 	return lwm2m_set_time(&path, value);
1033 }
1034 
lwm2m_set_res_data_len(const struct lwm2m_obj_path * path,uint16_t data_len)1035 int lwm2m_set_res_data_len(const struct lwm2m_obj_path *path, uint16_t data_len)
1036 {
1037 	int ret;
1038 	void *buffer_ptr;
1039 	uint16_t buffer_len;
1040 	uint16_t old_len;
1041 	uint8_t data_flags;
1042 
1043 	ret = lwm2m_get_res_buf(path, &buffer_ptr, &buffer_len, &old_len, &data_flags);
1044 	if (ret) {
1045 		return ret;
1046 	}
1047 	return lwm2m_set_res_buf(path, buffer_ptr, buffer_len, data_len, data_flags);
1048 }
1049 
lwm2m_engine_set_res_data_len(const char * pathstr,uint16_t data_len)1050 int lwm2m_engine_set_res_data_len(const char *pathstr, uint16_t data_len)
1051 {
1052 	struct lwm2m_obj_path path;
1053 	int ret = 0;
1054 
1055 	/* translate path -> path_obj */
1056 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1057 	if (ret < 0) {
1058 		return ret;
1059 	}
1060 
1061 	return lwm2m_set_res_data_len(&path, data_len);
1062 }
1063 /* User data getter functions */
1064 
lwm2m_get_res_buf(const struct lwm2m_obj_path * path,void ** buffer_ptr,uint16_t * buffer_len,uint16_t * data_len,uint8_t * data_flags)1065 int lwm2m_get_res_buf(const struct lwm2m_obj_path *path, void **buffer_ptr, uint16_t *buffer_len,
1066 		      uint16_t *data_len, uint8_t *data_flags)
1067 {
1068 	int ret;
1069 	struct lwm2m_engine_res_inst *res_inst = NULL;
1070 
1071 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1072 		LOG_ERR("path must have at least 3 parts");
1073 		return -EINVAL;
1074 	}
1075 
1076 	k_mutex_lock(&registry_lock, K_FOREVER);
1077 	/* look up resource obj */
1078 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1079 	if (ret < 0) {
1080 		k_mutex_unlock(&registry_lock);
1081 		return ret;
1082 	}
1083 
1084 	if (!res_inst) {
1085 		LOG_ERR("res instance %d not found", path->res_inst_id);
1086 		k_mutex_unlock(&registry_lock);
1087 		return -ENOENT;
1088 	}
1089 
1090 	if (buffer_ptr) {
1091 		*buffer_ptr = res_inst->data_ptr;
1092 	}
1093 	if (buffer_len) {
1094 		*buffer_len = res_inst->max_data_len;
1095 	}
1096 	if (data_len) {
1097 		*data_len = res_inst->data_len;
1098 	}
1099 	if (data_flags) {
1100 		*data_flags = res_inst->data_flags;
1101 	}
1102 
1103 	k_mutex_unlock(&registry_lock);
1104 	return 0;
1105 }
1106 
lwm2m_engine_get_res_buf(const char * pathstr,void ** buffer_ptr,uint16_t * buffer_len,uint16_t * data_len,uint8_t * data_flags)1107 int lwm2m_engine_get_res_buf(const char *pathstr, void **buffer_ptr, uint16_t *buffer_len,
1108 			     uint16_t *data_len, uint8_t *data_flags)
1109 {
1110 	struct lwm2m_obj_path path;
1111 	int ret = 0;
1112 
1113 	/* translate path -> path_obj */
1114 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1115 	if (ret < 0) {
1116 		return ret;
1117 	}
1118 
1119 	return lwm2m_get_res_buf(&path, buffer_ptr, buffer_len, data_len, data_flags);
1120 }
1121 
lwm2m_engine_get_res_data(const char * pathstr,void ** data_ptr,uint16_t * data_len,uint8_t * data_flags)1122 int lwm2m_engine_get_res_data(const char *pathstr, void **data_ptr, uint16_t *data_len,
1123 			      uint8_t *data_flags)
1124 {
1125 	struct lwm2m_obj_path path;
1126 	int ret = 0;
1127 
1128 	/* translate path -> path_obj */
1129 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1130 	if (ret < 0) {
1131 		return ret;
1132 	}
1133 
1134 	return lwm2m_get_res_buf(&path, data_ptr, NULL, data_len, data_flags);
1135 }
1136 
lwm2m_engine_get(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1137 static int lwm2m_engine_get(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1138 {
1139 	int ret = 0;
1140 	struct lwm2m_engine_obj_inst *obj_inst;
1141 	struct lwm2m_engine_obj_field *obj_field;
1142 	struct lwm2m_engine_res *res = NULL;
1143 	struct lwm2m_engine_res_inst *res_inst = NULL;
1144 	void *data_ptr = NULL;
1145 	size_t data_len = 0;
1146 
1147 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1148 		LOG_ERR("path must have at least 3 parts");
1149 		return -EINVAL;
1150 	}
1151 	LOG_DBG("path:%u/%u/%u/%u, level %u, buf:%p, buflen:%d", path->obj_id, path->obj_inst_id,
1152 		path->res_id, path->res_inst_id, path->level, buf, buflen);
1153 
1154 	k_mutex_lock(&registry_lock, K_FOREVER);
1155 	/* look up resource obj */
1156 	ret = path_to_objs(path, &obj_inst, &obj_field, &res, &res_inst);
1157 	if (ret < 0) {
1158 		k_mutex_unlock(&registry_lock);
1159 		return ret;
1160 	}
1161 
1162 	if (!res_inst) {
1163 		LOG_ERR("res instance %d not found", path->res_inst_id);
1164 		k_mutex_unlock(&registry_lock);
1165 		return -ENOENT;
1166 	}
1167 
1168 	/* setup initial data elements */
1169 	data_ptr = res_inst->data_ptr;
1170 	data_len = res_inst->data_len;
1171 
1172 	/* allow user to override data elements via callback */
1173 	if (res->read_cb) {
1174 		data_ptr = res->read_cb(obj_inst->obj_inst_id, res->res_id, res_inst->res_inst_id,
1175 					&data_len);
1176 	}
1177 
1178 	if (data_ptr && data_len > 0) {
1179 		ret = lwm2m_check_buf_sizes(obj_field->data_type, data_len, buflen);
1180 		if (ret) {
1181 			LOG_ERR("Incorrect resource data length %zu. Buffer length %u", data_len,
1182 				buflen);
1183 			k_mutex_unlock(&registry_lock);
1184 			return ret;
1185 		}
1186 
1187 		switch (obj_field->data_type) {
1188 
1189 		case LWM2M_RES_TYPE_OPAQUE:
1190 			memcpy(buf, data_ptr, data_len);
1191 			break;
1192 
1193 		case LWM2M_RES_TYPE_STRING:
1194 			strncpy(buf, data_ptr, data_len - 1);
1195 			((char *)buf)[data_len - 1] = '\0';
1196 			break;
1197 
1198 		case LWM2M_RES_TYPE_U32:
1199 			*(uint32_t *)buf = *(uint32_t *)data_ptr;
1200 			break;
1201 		case LWM2M_RES_TYPE_TIME:
1202 			if (!lwm2m_validate_time_resource_lenghts(data_len, buflen)) {
1203 				LOG_ERR("Time get buffer length %u  data len %zu not supported",
1204 					buflen, data_len);
1205 				return -EINVAL;
1206 			}
1207 
1208 			if (data_len == sizeof(time_t)) {
1209 				if (buflen == sizeof(time_t)) {
1210 					*((time_t *)buf) = *(time_t *)data_ptr;
1211 				} else {
1212 					/* In this case get operation may not got correct value */
1213 					LOG_WRN("Converting time to 32bit may cause integer "
1214 						"overflow");
1215 					*((uint32_t *)buf) = (uint32_t) *((time_t *)data_ptr);
1216 				}
1217 			} else {
1218 				LOG_WRN("Converting time to 32bit may cause integer overflow");
1219 				if (buflen == sizeof(uint32_t)) {
1220 					*((uint32_t *)buf) = *(uint32_t *)data_ptr;
1221 				} else {
1222 					*((time_t *)buf) = (time_t) *((uint32_t *)data_ptr);
1223 				}
1224 			}
1225 			break;
1226 
1227 		case LWM2M_RES_TYPE_U16:
1228 			*(uint16_t *)buf = *(uint16_t *)data_ptr;
1229 			break;
1230 
1231 		case LWM2M_RES_TYPE_U8:
1232 			*(uint8_t *)buf = *(uint8_t *)data_ptr;
1233 			break;
1234 
1235 		case LWM2M_RES_TYPE_S64:
1236 			*(int64_t *)buf = *(int64_t *)data_ptr;
1237 			break;
1238 
1239 		case LWM2M_RES_TYPE_S32:
1240 			*(int32_t *)buf = *(int32_t *)data_ptr;
1241 			break;
1242 
1243 		case LWM2M_RES_TYPE_S16:
1244 			*(int16_t *)buf = *(int16_t *)data_ptr;
1245 			break;
1246 
1247 		case LWM2M_RES_TYPE_S8:
1248 			*(int8_t *)buf = *(int8_t *)data_ptr;
1249 			break;
1250 
1251 		case LWM2M_RES_TYPE_BOOL:
1252 			*(bool *)buf = *(bool *)data_ptr;
1253 			break;
1254 
1255 		case LWM2M_RES_TYPE_FLOAT:
1256 			*(double *)buf = *(double *)data_ptr;
1257 			break;
1258 
1259 		case LWM2M_RES_TYPE_OBJLNK:
1260 			*(struct lwm2m_objlnk *)buf = *(struct lwm2m_objlnk *)data_ptr;
1261 			break;
1262 
1263 		default:
1264 			LOG_ERR("unknown obj data_type %d", obj_field->data_type);
1265 			k_mutex_unlock(&registry_lock);
1266 			return -EINVAL;
1267 		}
1268 	} else if (obj_field->data_type == LWM2M_RES_TYPE_STRING) {
1269 		/* Ensure empty string when there is no data */
1270 		((char *)buf)[0] = '\0';
1271 	}
1272 	k_mutex_unlock(&registry_lock);
1273 	return 0;
1274 }
1275 
lwm2m_get_opaque(const struct lwm2m_obj_path * path,void * buf,uint16_t buflen)1276 int lwm2m_get_opaque(const struct lwm2m_obj_path *path, void *buf, uint16_t buflen)
1277 {
1278 	return lwm2m_engine_get(path, buf, buflen);
1279 }
1280 
lwm2m_engine_get_opaque(const char * pathstr,void * buf,uint16_t buflen)1281 int lwm2m_engine_get_opaque(const char *pathstr, void *buf, uint16_t buflen)
1282 {
1283 	struct lwm2m_obj_path path;
1284 	int ret = 0;
1285 
1286 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1287 	if (ret < 0) {
1288 		return ret;
1289 	}
1290 	return lwm2m_get_opaque(&path, buf, buflen);
1291 }
1292 
lwm2m_get_string(const struct lwm2m_obj_path * path,void * str,uint16_t buflen)1293 int lwm2m_get_string(const struct lwm2m_obj_path *path, void *str, uint16_t buflen)
1294 {
1295 	/* Ensure termination, in case resource is not a string type */
1296 	if (!is_string(path)) {
1297 		memset(str, 0, buflen);
1298 		buflen -= 1; /* Last terminator cannot be overwritten */
1299 	}
1300 
1301 	return lwm2m_engine_get(path, str, buflen);
1302 }
1303 
lwm2m_engine_get_string(const char * pathstr,void * str,uint16_t buflen)1304 int lwm2m_engine_get_string(const char *pathstr, void *str, uint16_t buflen)
1305 {
1306 	struct lwm2m_obj_path path;
1307 	int ret = 0;
1308 
1309 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1310 	if (ret < 0) {
1311 		return ret;
1312 	}
1313 	return lwm2m_get_string(&path, str, buflen);
1314 }
1315 
lwm2m_get_u8(const struct lwm2m_obj_path * path,uint8_t * value)1316 int lwm2m_get_u8(const struct lwm2m_obj_path *path, uint8_t *value)
1317 {
1318 	return lwm2m_engine_get(path, value, 1);
1319 }
1320 
lwm2m_engine_get_u8(const char * pathstr,uint8_t * value)1321 int lwm2m_engine_get_u8(const char *pathstr, uint8_t *value)
1322 {
1323 	struct lwm2m_obj_path path;
1324 	int ret = 0;
1325 
1326 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1327 	if (ret < 0) {
1328 		return ret;
1329 	}
1330 	return lwm2m_get_u8(&path, value);
1331 }
1332 
lwm2m_get_u16(const struct lwm2m_obj_path * path,uint16_t * value)1333 int lwm2m_get_u16(const struct lwm2m_obj_path *path, uint16_t *value)
1334 {
1335 	return lwm2m_engine_get(path, value, 2);
1336 }
1337 
lwm2m_engine_get_u16(const char * pathstr,uint16_t * value)1338 int lwm2m_engine_get_u16(const char *pathstr, uint16_t *value)
1339 {
1340 	struct lwm2m_obj_path path;
1341 	int ret = 0;
1342 
1343 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1344 	if (ret < 0) {
1345 		return ret;
1346 	}
1347 	return lwm2m_get_u16(&path, value);
1348 }
1349 
lwm2m_get_u32(const struct lwm2m_obj_path * path,uint32_t * value)1350 int lwm2m_get_u32(const struct lwm2m_obj_path *path, uint32_t *value)
1351 {
1352 	return lwm2m_engine_get(path, value, 4);
1353 }
1354 
lwm2m_engine_get_u32(const char * pathstr,uint32_t * value)1355 int lwm2m_engine_get_u32(const char *pathstr, uint32_t *value)
1356 {
1357 	struct lwm2m_obj_path path;
1358 	int ret = 0;
1359 
1360 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1361 	if (ret < 0) {
1362 		return ret;
1363 	}
1364 	return lwm2m_get_u32(&path, value);
1365 }
1366 
lwm2m_get_u64(const struct lwm2m_obj_path * path,uint64_t * value)1367 int lwm2m_get_u64(const struct lwm2m_obj_path *path, uint64_t *value)
1368 {
1369 	return lwm2m_engine_get(path, value, 8);
1370 }
1371 
lwm2m_engine_get_u64(const char * pathstr,uint64_t * value)1372 int lwm2m_engine_get_u64(const char *pathstr, uint64_t *value)
1373 {
1374 	struct lwm2m_obj_path path;
1375 	int ret = 0;
1376 
1377 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1378 	if (ret < 0) {
1379 		return ret;
1380 	}
1381 	return lwm2m_get_s64(&path, (int64_t *) value);
1382 }
1383 
lwm2m_get_s8(const struct lwm2m_obj_path * path,int8_t * value)1384 int lwm2m_get_s8(const struct lwm2m_obj_path *path, int8_t *value)
1385 {
1386 	return lwm2m_engine_get(path, value, 1);
1387 }
1388 
lwm2m_engine_get_s8(const char * pathstr,int8_t * value)1389 int lwm2m_engine_get_s8(const char *pathstr, int8_t *value)
1390 {
1391 	struct lwm2m_obj_path path;
1392 	int ret = 0;
1393 
1394 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1395 	if (ret < 0) {
1396 		return ret;
1397 	}
1398 	return lwm2m_get_s8(&path, value);
1399 }
1400 
lwm2m_get_s16(const struct lwm2m_obj_path * path,int16_t * value)1401 int lwm2m_get_s16(const struct lwm2m_obj_path *path, int16_t *value)
1402 {
1403 	return lwm2m_engine_get(path, value, 2);
1404 }
1405 
lwm2m_engine_get_s16(const char * pathstr,int16_t * value)1406 int lwm2m_engine_get_s16(const char *pathstr, int16_t *value)
1407 {
1408 	struct lwm2m_obj_path path;
1409 	int ret = 0;
1410 
1411 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1412 	if (ret < 0) {
1413 		return ret;
1414 	}
1415 	return lwm2m_get_s16(&path, value);
1416 }
1417 
lwm2m_get_s32(const struct lwm2m_obj_path * path,int32_t * value)1418 int lwm2m_get_s32(const struct lwm2m_obj_path *path, int32_t *value)
1419 {
1420 	return lwm2m_engine_get(path, value, 4);
1421 }
1422 
lwm2m_engine_get_s32(const char * pathstr,int32_t * value)1423 int lwm2m_engine_get_s32(const char *pathstr, int32_t *value)
1424 {
1425 	struct lwm2m_obj_path path;
1426 	int ret = 0;
1427 
1428 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1429 	if (ret < 0) {
1430 		return ret;
1431 	}
1432 	return lwm2m_get_s32(&path, value);
1433 }
1434 
lwm2m_get_s64(const struct lwm2m_obj_path * path,int64_t * value)1435 int lwm2m_get_s64(const struct lwm2m_obj_path *path, int64_t *value)
1436 {
1437 	return lwm2m_engine_get(path, value, 8);
1438 }
1439 
lwm2m_engine_get_s64(const char * pathstr,int64_t * value)1440 int lwm2m_engine_get_s64(const char *pathstr, int64_t *value)
1441 {
1442 	struct lwm2m_obj_path path;
1443 	int ret = 0;
1444 
1445 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1446 	if (ret < 0) {
1447 		return ret;
1448 	}
1449 	return lwm2m_get_s64(&path, value);
1450 }
1451 
lwm2m_get_bool(const struct lwm2m_obj_path * path,bool * value)1452 int lwm2m_get_bool(const struct lwm2m_obj_path *path, bool *value)
1453 {
1454 	int ret = 0;
1455 	int8_t temp = 0;
1456 
1457 	ret = lwm2m_get_s8(path, &temp);
1458 	if (!ret) {
1459 		*value = temp != 0;
1460 	}
1461 
1462 	return ret;
1463 }
1464 
lwm2m_engine_get_bool(const char * pathstr,bool * value)1465 int lwm2m_engine_get_bool(const char *pathstr, bool *value)
1466 {
1467 	struct lwm2m_obj_path path;
1468 	int ret = 0;
1469 
1470 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1471 	if (ret < 0) {
1472 		return ret;
1473 	}
1474 	return lwm2m_get_bool(&path, value);
1475 }
1476 
lwm2m_get_f64(const struct lwm2m_obj_path * path,double * value)1477 int lwm2m_get_f64(const struct lwm2m_obj_path *path, double *value)
1478 {
1479 	return lwm2m_engine_get(path, value, sizeof(double));
1480 }
1481 
lwm2m_engine_get_float(const char * pathstr,double * buf)1482 int lwm2m_engine_get_float(const char *pathstr, double *buf)
1483 {
1484 	struct lwm2m_obj_path path;
1485 	int ret = 0;
1486 
1487 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1488 	if (ret < 0) {
1489 		return ret;
1490 	}
1491 	return lwm2m_get_f64(&path, buf);
1492 }
1493 
lwm2m_get_objlnk(const struct lwm2m_obj_path * path,struct lwm2m_objlnk * buf)1494 int lwm2m_get_objlnk(const struct lwm2m_obj_path *path, struct lwm2m_objlnk *buf)
1495 {
1496 	return lwm2m_engine_get(path, buf, sizeof(struct lwm2m_objlnk));
1497 }
1498 
lwm2m_engine_get_objlnk(const char * pathstr,struct lwm2m_objlnk * buf)1499 int lwm2m_engine_get_objlnk(const char *pathstr, struct lwm2m_objlnk *buf)
1500 {
1501 	struct lwm2m_obj_path path;
1502 	int ret = 0;
1503 
1504 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1505 	if (ret < 0) {
1506 		return ret;
1507 	}
1508 	return lwm2m_get_objlnk(&path, buf);
1509 }
1510 
lwm2m_get_time(const struct lwm2m_obj_path * path,time_t * buf)1511 int lwm2m_get_time(const struct lwm2m_obj_path *path, time_t *buf)
1512 {
1513 	return lwm2m_engine_get(path, buf, sizeof(time_t));
1514 }
1515 
lwm2m_engine_get_time(const char * pathstr,time_t * buf)1516 int lwm2m_engine_get_time(const char *pathstr, time_t *buf)
1517 {
1518 	struct lwm2m_obj_path path;
1519 	int ret = 0;
1520 
1521 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1522 	if (ret < 0) {
1523 		return ret;
1524 	}
1525 	return lwm2m_get_time(&path, buf);
1526 }
1527 
lwm2m_get_resource(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res)1528 int lwm2m_get_resource(const struct lwm2m_obj_path *path, struct lwm2m_engine_res **res)
1529 {
1530 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1531 		LOG_ERR("path must have 3 parts");
1532 		return -EINVAL;
1533 	}
1534 
1535 	return path_to_objs(path, NULL, NULL, res, NULL);
1536 }
1537 
lwm2m_engine_get_resource(const char * pathstr,struct lwm2m_engine_res ** res)1538 int lwm2m_engine_get_resource(const char *pathstr, struct lwm2m_engine_res **res)
1539 {
1540 	int ret;
1541 	struct lwm2m_obj_path path;
1542 
1543 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1544 	if (ret < 0) {
1545 		return ret;
1546 	}
1547 
1548 	return lwm2m_get_resource(&path, res);
1549 }
1550 
lwm2m_engine_get_opaque_more(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)1551 size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen,
1552 				    struct lwm2m_opaque_context *opaque, bool *last_block)
1553 {
1554 	uint32_t in_len = opaque->remaining;
1555 	uint16_t remaining = in->in_cpkt->max_len - in->offset;
1556 
1557 	if (in_len > buflen) {
1558 		in_len = buflen;
1559 	}
1560 
1561 	if (in_len > remaining) {
1562 		in_len = remaining;
1563 	}
1564 
1565 	opaque->remaining -= in_len;
1566 	remaining -= in_len;
1567 	if (opaque->remaining == 0U || remaining == 0) {
1568 		*last_block = true;
1569 	}
1570 
1571 	if (buf_read(buf, in_len, CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) {
1572 		*last_block = true;
1573 		return 0;
1574 	}
1575 
1576 	return (size_t)in_len;
1577 }
1578 
lwm2m_engine_get_queue_mode(char * queue)1579 void lwm2m_engine_get_queue_mode(char *queue)
1580 {
1581 	if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1582 		strncpy(queue, "Q", QUEUE_OPT_MAX_LEN);
1583 	} else {
1584 		strncpy(queue, "", QUEUE_OPT_MAX_LEN);
1585 	}
1586 }
1587 
lwm2m_engine_get_binding(char * binding)1588 void lwm2m_engine_get_binding(char *binding)
1589 {
1590 	/* Defaults to UDP. */
1591 	strncpy(binding, "U", BINDING_OPT_MAX_LEN);
1592 #if CONFIG_LWM2M_VERSION_1_0
1593 	/* In LwM2M 1.0 binding and queue mode are in same parameter */
1594 	char queue[QUEUE_OPT_MAX_LEN];
1595 
1596 	lwm2m_engine_get_queue_mode(queue);
1597 	strncat(binding, queue, QUEUE_OPT_MAX_LEN);
1598 #endif
1599 }
1600 /* Engine resource instance */
1601 
lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res * res,struct lwm2m_engine_res_inst ** res_inst,uint8_t resource_instance_id)1602 static int lwm2m_engine_allocate_resource_instance(struct lwm2m_engine_res *res,
1603 						   struct lwm2m_engine_res_inst **res_inst,
1604 						   uint8_t resource_instance_id)
1605 {
1606 	int i;
1607 
1608 	if (!res->res_instances || res->res_inst_count == 0) {
1609 		return -ENOMEM;
1610 	}
1611 
1612 	for (i = 0; i < res->res_inst_count; i++) {
1613 		if (res->res_instances[i].res_inst_id == RES_INSTANCE_NOT_CREATED) {
1614 			break;
1615 		}
1616 	}
1617 
1618 	if (i >= res->res_inst_count) {
1619 		return -ENOMEM;
1620 	}
1621 
1622 	res->res_instances[i].res_inst_id = resource_instance_id;
1623 	*res_inst = &res->res_instances[i];
1624 	return 0;
1625 }
1626 
lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path * path,struct lwm2m_engine_res ** res,struct lwm2m_engine_res_inst ** res_inst)1627 int lwm2m_engine_get_create_res_inst(const struct lwm2m_obj_path *path,
1628 				     struct lwm2m_engine_res **res,
1629 				     struct lwm2m_engine_res_inst **res_inst)
1630 {
1631 	int ret;
1632 	struct lwm2m_engine_res *r = NULL;
1633 	struct lwm2m_engine_res_inst *r_i = NULL;
1634 
1635 	ret = path_to_objs(path, NULL, NULL, &r, &r_i);
1636 	if (ret < 0) {
1637 		return ret;
1638 	}
1639 
1640 	if (!r) {
1641 		return -ENOENT;
1642 	}
1643 	/* Store resource pointer */
1644 	*res = r;
1645 
1646 	if (!r_i) {
1647 		if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1648 			return -EINVAL;
1649 		}
1650 
1651 		ret = lwm2m_engine_allocate_resource_instance(r, &r_i, path->res_inst_id);
1652 		if (ret < 0) {
1653 			return ret;
1654 		}
1655 	}
1656 
1657 	/* Store resource instance pointer */
1658 	*res_inst = r_i;
1659 	return 0;
1660 }
1661 
lwm2m_create_res_inst(const struct lwm2m_obj_path * path)1662 int lwm2m_create_res_inst(const struct lwm2m_obj_path *path)
1663 {
1664 	int ret;
1665 	struct lwm2m_engine_res *res = NULL;
1666 	struct lwm2m_engine_res_inst *res_inst = NULL;
1667 
1668 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1669 		LOG_ERR("path must have 4 parts");
1670 		return -EINVAL;
1671 	}
1672 	k_mutex_lock(&registry_lock, K_FOREVER);
1673 	ret = path_to_objs(path, NULL, NULL, &res, &res_inst);
1674 	if (ret < 0) {
1675 		k_mutex_unlock(&registry_lock);
1676 		return ret;
1677 	}
1678 
1679 	if (!res) {
1680 		LOG_ERR("resource %u not found", path->res_id);
1681 		k_mutex_unlock(&registry_lock);
1682 		return -ENOENT;
1683 	}
1684 
1685 	if (res_inst && res_inst->res_inst_id != RES_INSTANCE_NOT_CREATED) {
1686 		LOG_ERR("res instance %u already exists", path->res_inst_id);
1687 		k_mutex_unlock(&registry_lock);
1688 		return -EINVAL;
1689 	}
1690 	k_mutex_unlock(&registry_lock);
1691 	return lwm2m_engine_allocate_resource_instance(res, &res_inst, path->res_inst_id);
1692 }
1693 
lwm2m_engine_create_res_inst(const char * pathstr)1694 int lwm2m_engine_create_res_inst(const char *pathstr)
1695 {
1696 	int ret;
1697 	struct lwm2m_obj_path path;
1698 
1699 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1700 	if (ret < 0) {
1701 		return ret;
1702 	}
1703 
1704 	return lwm2m_create_res_inst(&path);
1705 }
1706 
lwm2m_delete_res_inst(const struct lwm2m_obj_path * path)1707 int lwm2m_delete_res_inst(const struct lwm2m_obj_path *path)
1708 {
1709 	int ret;
1710 	struct lwm2m_engine_res_inst *res_inst = NULL;
1711 
1712 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE_INST) {
1713 		LOG_ERR("path must have 4 parts");
1714 		return -EINVAL;
1715 	}
1716 	k_mutex_lock(&registry_lock, K_FOREVER);
1717 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1718 	if (ret < 0) {
1719 		k_mutex_unlock(&registry_lock);
1720 		return ret;
1721 	}
1722 
1723 	if (!res_inst) {
1724 		LOG_ERR("res instance %u not found", path->res_inst_id);
1725 		k_mutex_unlock(&registry_lock);
1726 		return -ENOENT;
1727 	}
1728 
1729 	res_inst->data_ptr = NULL;
1730 	res_inst->max_data_len = 0U;
1731 	res_inst->data_len = 0U;
1732 	res_inst->res_inst_id = RES_INSTANCE_NOT_CREATED;
1733 	k_mutex_unlock(&registry_lock);
1734 	return 0;
1735 }
1736 
lwm2m_engine_delete_res_inst(const char * pathstr)1737 int lwm2m_engine_delete_res_inst(const char *pathstr)
1738 {
1739 	int ret;
1740 	struct lwm2m_obj_path path;
1741 
1742 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1743 	if (ret < 0) {
1744 		return ret;
1745 	}
1746 
1747 	return lwm2m_delete_res_inst(&path);
1748 }
1749 /* Register callbacks */
1750 
lwm2m_register_read_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1751 int lwm2m_register_read_callback(const struct lwm2m_obj_path *path, lwm2m_engine_get_data_cb_t cb)
1752 {
1753 	int ret;
1754 	struct lwm2m_engine_res *res = NULL;
1755 
1756 	ret = lwm2m_get_resource(path, &res);
1757 	if (ret < 0) {
1758 		return ret;
1759 	}
1760 
1761 	res->read_cb = cb;
1762 	return 0;
1763 }
1764 
lwm2m_engine_register_read_callback(const char * pathstr,lwm2m_engine_get_data_cb_t cb)1765 int lwm2m_engine_register_read_callback(const char *pathstr, lwm2m_engine_get_data_cb_t cb)
1766 {
1767 	int ret;
1768 	struct lwm2m_obj_path path;
1769 
1770 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1771 	if (ret < 0) {
1772 		return ret;
1773 	}
1774 
1775 	return lwm2m_register_read_callback(&path, cb);
1776 }
1777 
lwm2m_register_pre_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_get_data_cb_t cb)1778 int lwm2m_register_pre_write_callback(const struct lwm2m_obj_path *path,
1779 				      lwm2m_engine_get_data_cb_t cb)
1780 {
1781 	int ret;
1782 	struct lwm2m_engine_res *res = NULL;
1783 
1784 	ret = lwm2m_get_resource(path, &res);
1785 	if (ret < 0) {
1786 		return ret;
1787 	}
1788 
1789 	res->pre_write_cb = cb;
1790 	return 0;
1791 }
1792 
lwm2m_engine_register_pre_write_callback(const char * pathstr,lwm2m_engine_get_data_cb_t cb)1793 int lwm2m_engine_register_pre_write_callback(const char *pathstr, lwm2m_engine_get_data_cb_t cb)
1794 {
1795 	int ret;
1796 	struct lwm2m_obj_path path;
1797 
1798 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1799 	if (ret < 0) {
1800 		return ret;
1801 	}
1802 
1803 	return lwm2m_register_pre_write_callback(&path, cb);
1804 }
1805 
lwm2m_register_validate_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1806 int lwm2m_register_validate_callback(const struct lwm2m_obj_path *path,
1807 				     lwm2m_engine_set_data_cb_t cb)
1808 {
1809 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1810 	int ret;
1811 	struct lwm2m_engine_res *res = NULL;
1812 
1813 	ret = lwm2m_get_resource(path, &res);
1814 	if (ret < 0) {
1815 		return ret;
1816 	}
1817 
1818 	res->validate_cb = cb;
1819 	return 0;
1820 #else
1821 	ARG_UNUSED(path);
1822 	ARG_UNUSED(cb);
1823 
1824 	LOG_ERR("Validation disabled. Set "
1825 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1826 		"enable validation support.");
1827 	return -ENOTSUP;
1828 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1829 }
1830 
lwm2m_engine_register_validate_callback(const char * pathstr,lwm2m_engine_set_data_cb_t cb)1831 int lwm2m_engine_register_validate_callback(const char *pathstr, lwm2m_engine_set_data_cb_t cb)
1832 {
1833 #if CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0
1834 	int ret;
1835 	struct lwm2m_obj_path path;
1836 
1837 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1838 	if (ret < 0) {
1839 		return ret;
1840 	}
1841 
1842 	return lwm2m_register_validate_callback(&path, cb);
1843 #else
1844 	ARG_UNUSED(pathstr);
1845 	ARG_UNUSED(cb);
1846 
1847 	LOG_ERR("Validation disabled. Set "
1848 		"CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 to "
1849 		"enable validation support.");
1850 	return -ENOTSUP;
1851 #endif /* CONFIG_LWM2M_ENGINE_VALIDATION_BUFFER_SIZE > 0 */
1852 }
1853 
lwm2m_register_post_write_callback(const struct lwm2m_obj_path * path,lwm2m_engine_set_data_cb_t cb)1854 int lwm2m_register_post_write_callback(const struct lwm2m_obj_path *path,
1855 				       lwm2m_engine_set_data_cb_t cb)
1856 {
1857 	int ret;
1858 	struct lwm2m_engine_res *res = NULL;
1859 
1860 	ret = lwm2m_get_resource(path, &res);
1861 	if (ret < 0) {
1862 		return ret;
1863 	}
1864 
1865 	res->post_write_cb = cb;
1866 	return 0;
1867 }
1868 
lwm2m_engine_register_post_write_callback(const char * pathstr,lwm2m_engine_set_data_cb_t cb)1869 int lwm2m_engine_register_post_write_callback(const char *pathstr, lwm2m_engine_set_data_cb_t cb)
1870 {
1871 	int ret;
1872 	struct lwm2m_obj_path path;
1873 
1874 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1875 	if (ret < 0) {
1876 		return ret;
1877 	}
1878 
1879 	return lwm2m_register_post_write_callback(&path, cb);
1880 }
1881 
lwm2m_register_exec_callback(const struct lwm2m_obj_path * path,lwm2m_engine_execute_cb_t cb)1882 int lwm2m_register_exec_callback(const struct lwm2m_obj_path *path, lwm2m_engine_execute_cb_t cb)
1883 {
1884 	int ret;
1885 	struct lwm2m_engine_res *res = NULL;
1886 
1887 	ret = lwm2m_get_resource(path, &res);
1888 	if (ret < 0) {
1889 		return ret;
1890 	}
1891 
1892 	res->execute_cb = cb;
1893 	return 0;
1894 }
1895 
lwm2m_engine_register_exec_callback(const char * pathstr,lwm2m_engine_execute_cb_t cb)1896 int lwm2m_engine_register_exec_callback(const char *pathstr, lwm2m_engine_execute_cb_t cb)
1897 {
1898 	int ret;
1899 	struct lwm2m_obj_path path;
1900 
1901 	ret = lwm2m_string_to_path(pathstr, &path, '/');
1902 	if (ret < 0) {
1903 		return ret;
1904 	}
1905 
1906 	return lwm2m_register_exec_callback(&path, cb);
1907 }
1908 
lwm2m_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1909 int lwm2m_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1910 {
1911 	struct lwm2m_engine_obj *obj = NULL;
1912 
1913 	obj = get_engine_obj(obj_id);
1914 	if (!obj) {
1915 		LOG_ERR("unable to find obj: %u", obj_id);
1916 		return -ENOENT;
1917 	}
1918 
1919 	obj->user_create_cb = cb;
1920 	return 0;
1921 }
1922 
lwm2m_engine_register_create_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1923 int lwm2m_engine_register_create_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1924 {
1925 	return lwm2m_register_create_callback(obj_id, cb);
1926 }
1927 
lwm2m_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1928 int lwm2m_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1929 {
1930 	struct lwm2m_engine_obj *obj = NULL;
1931 
1932 	obj = get_engine_obj(obj_id);
1933 	if (!obj) {
1934 		LOG_ERR("unable to find obj: %u", obj_id);
1935 		return -ENOENT;
1936 	}
1937 
1938 	obj->user_delete_cb = cb;
1939 	return 0;
1940 }
1941 
lwm2m_engine_register_delete_callback(uint16_t obj_id,lwm2m_engine_user_cb_t cb)1942 int lwm2m_engine_register_delete_callback(uint16_t obj_id, lwm2m_engine_user_cb_t cb)
1943 {
1944 	return lwm2m_register_delete_callback(obj_id, cb);
1945 }
1946 /* Generic data handlers */
1947 
lwm2m_get_or_create_engine_obj(struct lwm2m_message * msg,struct lwm2m_engine_obj_inst ** obj_inst,uint8_t * created)1948 int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg,
1949 				   struct lwm2m_engine_obj_inst **obj_inst, uint8_t *created)
1950 {
1951 	int ret = 0;
1952 
1953 	if (created) {
1954 		*created = 0U;
1955 	}
1956 
1957 	*obj_inst = get_engine_obj_inst(msg->path.obj_id, msg->path.obj_inst_id);
1958 	if (!*obj_inst) {
1959 		ret = lwm2m_create_obj_inst(msg->path.obj_id, msg->path.obj_inst_id, obj_inst);
1960 		if (ret < 0) {
1961 			return ret;
1962 		}
1963 
1964 		/* set created flag to one */
1965 		if (created) {
1966 			*created = 1U;
1967 		}
1968 
1969 		if (!msg->ctx->bootstrap_mode) {
1970 			engine_trigger_update(true);
1971 		}
1972 	}
1973 
1974 	return ret;
1975 }
1976 
lwm2m_engine_get_res(const struct lwm2m_obj_path * path)1977 struct lwm2m_engine_res *lwm2m_engine_get_res(const struct lwm2m_obj_path *path)
1978 {
1979 	struct lwm2m_engine_res *res = NULL;
1980 	int ret;
1981 
1982 	if (path->level < LWM2M_PATH_LEVEL_RESOURCE) {
1983 		return NULL;
1984 	}
1985 
1986 	ret = path_to_objs(path, NULL, NULL, &res, NULL);
1987 	if (ret < 0) {
1988 		return NULL;
1989 	}
1990 
1991 	return res;
1992 }
1993 
lwm2m_engine_get_res_inst(const struct lwm2m_obj_path * path)1994 struct lwm2m_engine_res_inst *lwm2m_engine_get_res_inst(const struct lwm2m_obj_path *path)
1995 {
1996 	struct lwm2m_engine_res_inst *res_inst = NULL;
1997 	int ret;
1998 
1999 	if (path->level != LWM2M_PATH_LEVEL_RESOURCE_INST) {
2000 		return NULL;
2001 	}
2002 
2003 	ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
2004 	if (ret < 0) {
2005 		return NULL;
2006 	}
2007 
2008 	return res_inst;
2009 }
2010 
lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj * obj)2011 bool lwm2m_engine_shall_report_obj_version(const struct lwm2m_engine_obj *obj)
2012 {
2013 	/* For non-core objects, report version other than 1.0 */
2014 	if (!obj->is_core) {
2015 		return obj->version_major != 1 || obj->version_minor != 0;
2016 	}
2017 
2018 	/* For core objects, report version based on default version array. */
2019 	for (size_t i = 0; i < ARRAY_SIZE(default_obj_versions); i++) {
2020 		if (obj->obj_id != default_obj_versions[i].obj_id) {
2021 			continue;
2022 		}
2023 
2024 		return obj->version_major != default_obj_versions[i].version_major ||
2025 		       obj->version_minor != default_obj_versions[i].version_minor;
2026 	}
2027 
2028 	return true;
2029 }
2030 
2031 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2032 static sys_slist_t lwm2m_timed_cache_list;
2033 static struct lwm2m_time_series_resource lwm2m_cache_entries[CONFIG_LWM2M_MAX_CACHED_RESOURCES];
2034 
2035 static struct lwm2m_time_series_resource *
lwm2m_cache_entry_allocate(const struct lwm2m_obj_path * path)2036 lwm2m_cache_entry_allocate(const struct lwm2m_obj_path *path)
2037 {
2038 	int i;
2039 	struct lwm2m_time_series_resource *entry;
2040 
2041 	entry = lwm2m_cache_entry_get_by_object(path);
2042 	if (entry) {
2043 		return entry;
2044 	}
2045 
2046 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
2047 		if (lwm2m_cache_entries[i].path.level == 0) {
2048 			lwm2m_cache_entries[i].path = *path;
2049 			sys_slist_append(&lwm2m_timed_cache_list, &lwm2m_cache_entries[i].node);
2050 			return &lwm2m_cache_entries[i];
2051 		}
2052 	}
2053 
2054 	return NULL;
2055 }
2056 
lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field * obj_field,const struct lwm2m_obj_path * path,const void * value,uint16_t len)2057 static void lwm2m_engine_cache_write(const struct lwm2m_engine_obj_field *obj_field,
2058 				     const struct lwm2m_obj_path *path, const void *value,
2059 				     uint16_t len)
2060 {
2061 	struct lwm2m_time_series_resource *cache_entry;
2062 	struct lwm2m_time_series_elem elements;
2063 
2064 	cache_entry = lwm2m_cache_entry_get_by_object(path);
2065 	if (!cache_entry) {
2066 		return;
2067 	}
2068 
2069 	elements.t = time(NULL);
2070 
2071 	if (elements.t  <= 0) {
2072 		LOG_WRN("Time() not available");
2073 		return;
2074 	}
2075 
2076 	switch (obj_field->data_type) {
2077 	case LWM2M_RES_TYPE_U32:
2078 		elements.u32 = *(uint32_t *)value;
2079 		break;
2080 
2081 	case LWM2M_RES_TYPE_U16:
2082 		elements.u16 = *(uint16_t *)value;
2083 		break;
2084 
2085 	case LWM2M_RES_TYPE_U8:
2086 		elements.u8 = *(uint8_t *)value;
2087 		break;
2088 
2089 	case LWM2M_RES_TYPE_S64:
2090 		elements.i64 = *(int64_t *)value;
2091 		break;
2092 
2093 	case LWM2M_RES_TYPE_TIME:
2094 		if (len == sizeof(time_t)) {
2095 			elements.time = *(time_t *)value;
2096 		} else if (len == sizeof(uint32_t)) {
2097 			elements.time = (time_t) *((uint32_t *)value);
2098 		} else {
2099 			LOG_ERR("Not supporting size %d bytes for time", len);
2100 			return;
2101 		}
2102 		break;
2103 
2104 	case LWM2M_RES_TYPE_S32:
2105 		elements.i32 = *(int32_t *)value;
2106 		break;
2107 
2108 	case LWM2M_RES_TYPE_S16:
2109 		elements.i16 = *(int16_t *)value;
2110 		break;
2111 
2112 	case LWM2M_RES_TYPE_S8:
2113 		elements.i8 = *(int8_t *)value;
2114 		break;
2115 
2116 	case LWM2M_RES_TYPE_BOOL:
2117 		elements.b = *(bool *)value;
2118 		break;
2119 
2120 	default:
2121 		elements.f = *(double *)value;
2122 		break;
2123 	}
2124 
2125 	if (!lwm2m_cache_write(cache_entry, &elements)) {
2126 		LOG_WRN("Data cache full");
2127 	}
2128 }
2129 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2130 
2131 struct lwm2m_time_series_resource *
lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path * obj_path)2132 lwm2m_cache_entry_get_by_object(const struct lwm2m_obj_path *obj_path)
2133 {
2134 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2135 	struct lwm2m_time_series_resource *entry;
2136 
2137 	if (obj_path->level < LWM2M_PATH_LEVEL_RESOURCE) {
2138 		LOG_ERR("Path level wrong for cache %u", obj_path->level);
2139 		return NULL;
2140 	}
2141 
2142 	if (sys_slist_is_empty(&lwm2m_timed_cache_list)) {
2143 		return NULL;
2144 	}
2145 
2146 	SYS_SLIST_FOR_EACH_CONTAINER(&lwm2m_timed_cache_list, entry, node) {
2147 		if (lwm2m_obj_path_equal(&entry->path, obj_path)) {
2148 			return entry;
2149 		}
2150 	}
2151 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2152 	return NULL;
2153 
2154 }
2155 
lwm2m_enable_cache(const struct lwm2m_obj_path * path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)2156 int lwm2m_enable_cache(const struct lwm2m_obj_path *path, struct lwm2m_time_series_elem *data_cache,
2157 		       size_t cache_len)
2158 {
2159 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2160 	struct lwm2m_engine_obj_inst *obj_inst;
2161 	struct lwm2m_engine_obj_field *obj_field;
2162 	struct lwm2m_engine_res_inst *res_inst = NULL;
2163 	struct lwm2m_time_series_resource *cache_entry;
2164 	int ret = 0;
2165 	size_t cache_entry_size = sizeof(struct lwm2m_time_series_elem);
2166 
2167 	/* look up resource obj */
2168 	ret = path_to_objs(path, &obj_inst, &obj_field, NULL, &res_inst);
2169 	if (ret < 0) {
2170 		return ret;
2171 	}
2172 
2173 	if (!res_inst) {
2174 		LOG_ERR("res instance %d not found", path->res_inst_id);
2175 		return -ENOENT;
2176 	}
2177 
2178 	switch (obj_field->data_type) {
2179 	case LWM2M_RES_TYPE_U32:
2180 	case LWM2M_RES_TYPE_TIME:
2181 	case LWM2M_RES_TYPE_U16:
2182 	case LWM2M_RES_TYPE_U8:
2183 	case LWM2M_RES_TYPE_S64:
2184 	case LWM2M_RES_TYPE_S32:
2185 	case LWM2M_RES_TYPE_S16:
2186 	case LWM2M_RES_TYPE_S8:
2187 	case LWM2M_RES_TYPE_BOOL:
2188 	case LWM2M_RES_TYPE_FLOAT:
2189 		/* Support only fixed width resource types */
2190 		cache_entry = lwm2m_cache_entry_allocate(path);
2191 		break;
2192 	default:
2193 		cache_entry = NULL;
2194 		break;
2195 	}
2196 
2197 	if (!cache_entry) {
2198 		return -ENODATA;
2199 	}
2200 
2201 	ring_buf_init(&cache_entry->rb, cache_entry_size * cache_len, (uint8_t *)data_cache);
2202 
2203 	return 0;
2204 #else
2205 	LOG_ERR("LwM2M resource cache is only supported for "
2206 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
2207 	return -ENOTSUP;
2208 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2209 }
2210 
lwm2m_engine_enable_cache(const char * resource_path,struct lwm2m_time_series_elem * data_cache,size_t cache_len)2211 int lwm2m_engine_enable_cache(const char *resource_path, struct lwm2m_time_series_elem *data_cache,
2212 			    size_t cache_len)
2213 {
2214 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2215 	struct lwm2m_obj_path path;
2216 	int ret;
2217 
2218 	/* translate path -> path_obj */
2219 	ret = lwm2m_string_to_path(resource_path, &path, '/');
2220 	if (ret < 0) {
2221 		return ret;
2222 	}
2223 
2224 	if (path.level < LWM2M_PATH_LEVEL_RESOURCE) {
2225 		LOG_ERR("path must have at least 3 parts");
2226 		return -EINVAL;
2227 	}
2228 
2229 	return lwm2m_enable_cache(&path, data_cache, cache_len);
2230 #else
2231 	LOG_ERR("LwM2M resource cache is only supported for "
2232 		"CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT");
2233 	return -ENOTSUP;
2234 #endif /* CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT */
2235 }
2236 
2237 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
lwm2m_engine_data_cache_init(void)2238 static int lwm2m_engine_data_cache_init(void)
2239 {
2240 	int i;
2241 
2242 	sys_slist_init(&lwm2m_timed_cache_list);
2243 
2244 	for (i = 0; i < ARRAY_SIZE(lwm2m_cache_entries); i++) {
2245 		lwm2m_cache_entries[i].path.level = LWM2M_PATH_LEVEL_NONE;
2246 	}
2247 	return 0;
2248 }
2249 LWM2M_ENGINE_INIT(lwm2m_engine_data_cache_init);
2250 #endif
2251 
lwm2m_cache_write(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)2252 bool lwm2m_cache_write(struct lwm2m_time_series_resource *cache_entry,
2253 		       struct lwm2m_time_series_elem *buf)
2254 {
2255 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2256 	uint32_t length;
2257 	uint8_t *buf_ptr;
2258 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
2259 
2260 	if (ring_buf_space_get(&cache_entry->rb) < element_size) {
2261 		/* No space  */
2262 		if (IS_ENABLED(CONFIG_LWM2M_CACHE_DROP_LATEST)) {
2263 			return false;
2264 		}
2265 		/* Free entry */
2266 		length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
2267 		ring_buf_get_finish(&cache_entry->rb, length);
2268 	}
2269 
2270 	length = ring_buf_put_claim(&cache_entry->rb, &buf_ptr, element_size);
2271 
2272 	if (length != element_size) {
2273 		ring_buf_put_finish(&cache_entry->rb, 0);
2274 		LOG_ERR("Allocation failed %u", length);
2275 		return false;
2276 	}
2277 
2278 	ring_buf_put_finish(&cache_entry->rb, length);
2279 	/* Store data */
2280 	memcpy(buf_ptr, buf, element_size);
2281 	return true;
2282 #else
2283 	return NULL;
2284 #endif
2285 }
2286 
lwm2m_cache_read(struct lwm2m_time_series_resource * cache_entry,struct lwm2m_time_series_elem * buf)2287 bool lwm2m_cache_read(struct lwm2m_time_series_resource *cache_entry,
2288 		      struct lwm2m_time_series_elem *buf)
2289 {
2290 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2291 	uint32_t length;
2292 	uint8_t *buf_ptr;
2293 	uint32_t element_size = sizeof(struct lwm2m_time_series_elem);
2294 
2295 	if (ring_buf_is_empty(&cache_entry->rb)) {
2296 		return false;
2297 	}
2298 
2299 	length = ring_buf_get_claim(&cache_entry->rb, &buf_ptr, element_size);
2300 
2301 	if (length != element_size) {
2302 		LOG_ERR("Cache read fail %u", length);
2303 		ring_buf_get_finish(&cache_entry->rb, 0);
2304 		return false;
2305 	}
2306 
2307 	/* Read Data */
2308 	memcpy(buf, buf_ptr, element_size);
2309 	ring_buf_get_finish(&cache_entry->rb, length);
2310 	return true;
2311 
2312 #else
2313 	return NULL;
2314 #endif
2315 }
2316 
lwm2m_cache_size(const struct lwm2m_time_series_resource * cache_entry)2317 size_t lwm2m_cache_size(const struct lwm2m_time_series_resource *cache_entry)
2318 {
2319 #if defined(CONFIG_LWM2M_RESOURCE_DATA_CACHE_SUPPORT)
2320 	uint32_t bytes_available;
2321 
2322 	/* ring_buf_is_empty() takes non-const pointer but still does not modify */
2323 	if (ring_buf_is_empty((struct ring_buf *) &cache_entry->rb)) {
2324 		return 0;
2325 	}
2326 
2327 	/* ring_buf_size_get() takes non-const pointer but still does not modify */
2328 	bytes_available = ring_buf_size_get((struct ring_buf *) &cache_entry->rb);
2329 
2330 	return (bytes_available / sizeof(struct lwm2m_time_series_elem));
2331 #else
2332 	return 0;
2333 #endif
2334 }
2335