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(®istry_lock, K_FOREVER);
47 }
48
lwm2m_registry_unlock(void)49 void lwm2m_registry_unlock(void)
50 {
51 (void)k_mutex_unlock(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_lock);
265 lwm2m_delete_obj_inst(obj_id, obj_inst_id);
266 return ret;
267 }
268 }
269 k_mutex_unlock(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_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(®istry_lock, K_FOREVER);
1673 ret = path_to_objs(path, NULL, NULL, &res, &res_inst);
1674 if (ret < 0) {
1675 k_mutex_unlock(®istry_lock);
1676 return ret;
1677 }
1678
1679 if (!res) {
1680 LOG_ERR("resource %u not found", path->res_id);
1681 k_mutex_unlock(®istry_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(®istry_lock);
1688 return -EINVAL;
1689 }
1690 k_mutex_unlock(®istry_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(®istry_lock, K_FOREVER);
1717 ret = path_to_objs(path, NULL, NULL, NULL, &res_inst);
1718 if (ret < 0) {
1719 k_mutex_unlock(®istry_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(®istry_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(®istry_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