1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define LOG_MODULE_NAME net_lwm2m_senml_json
8 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
9
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
12
13 #include <stdio.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <inttypes.h>
17 #include <ctype.h>
18 #include <zephyr/sys/base64.h>
19 #include <zephyr/sys/slist.h>
20 #include <zephyr/data/json.h>
21
22 #include "lwm2m_object.h"
23 #include "lwm2m_rw_senml_json.h"
24 #include "lwm2m_engine.h"
25 #include "lwm2m_util.h"
26
27 #define BASE64_OUTPUT_MIN_LENGTH 4
28 #define BASE64_MODULO_LENGTH(x) (x % BASE64_OUTPUT_MIN_LENGTH)
29 #define BASE64_BYTES_TO_MODULO(x) (BASE64_OUTPUT_MIN_LENGTH - x)
30
31 struct senml_string_bn_payload {
32 const char *base_name;
33 const char *name;
34 const char *val_string;
35 };
36
37 struct senml_string_payload {
38 const char *name;
39 const char *val_string;
40 };
41
42 struct senml_opaque_payload {
43 const char *name;
44 struct json_obj_token val_opaque;
45 };
46
47 struct senml_opaque_bn_payload {
48 const char *base_name;
49 const char *name;
50 struct json_obj_token val_opaque;
51 };
52
53 struct senml_boolean_payload {
54 const char *name;
55 bool val_bool;
56 };
57
58 struct senml_boolean_t_payload {
59 const char *name;
60 bool val_bool;
61 struct json_obj_token time;
62 };
63
64 struct senml_boolean_bn_payload {
65 const char *base_name;
66 const char *name;
67 bool val_bool;
68 };
69
70 struct senml_boolean_bn_t_payload {
71 const char *base_name;
72 const char *name;
73 bool val_bool;
74 struct json_obj_token base_time;
75 };
76
77 struct senml_float_payload {
78 const char *name;
79 struct json_obj_token val_float;
80 };
81
82 struct senml_float_t_payload {
83 const char *name;
84 struct json_obj_token val_float;
85 struct json_obj_token time;
86 };
87
88 struct senml_float_bn_payload {
89 const char *base_name;
90 const char *name;
91 struct json_obj_token val_float;
92 };
93
94 struct senml_float_bn_t_payload {
95 const char *base_name;
96 const char *name;
97 struct json_obj_token val_float;
98 struct json_obj_token base_time;
99 };
100
101 struct senml_json_object {
102 union {
103 struct senml_float_payload float_obj;
104 struct senml_float_t_payload float_t_obj;
105 struct senml_float_bn_payload float_bn_obj;
106 struct senml_float_bn_t_payload float_bn_t_obj;
107 struct senml_boolean_payload boolean_obj;
108 struct senml_boolean_t_payload boolean_t_obj;
109 struct senml_boolean_bn_payload boolean_bn_obj;
110 struct senml_boolean_bn_t_payload boolean_bn_t_obj;
111 struct senml_opaque_payload opaque_obj;
112 struct senml_opaque_bn_payload opaque_bn_obj;
113 struct senml_string_payload string_obj;
114 struct senml_string_bn_payload string_bn_obj;
115 } obj;
116 };
117
118 struct json_out_formatter_data {
119 uint8_t writer_flags;
120 struct lwm2m_obj_path base_name;
121 bool add_base_name_to_start;
122 bool historical_data;
123 char bn_string[sizeof("/65535/65535/") + 1];
124 char name_string[sizeof("/65535/65535/") + 1];
125 char timestamp_buffer[42];
126 int timestamp_length;
127 time_t base_time;
128 struct senml_json_object json;
129 struct lwm2m_output_context *out;
130 };
131
132 /* Decode payload structure */
133 struct senml_context {
134 const char *base_name;
135 const char *name;
136 char *val_object_link;
137 const char *val_string;
138 struct json_obj_token val_opaque;
139 struct json_obj_token val_float;
140 bool val_bool;
141 };
142
143 /* Decode description structure for parsing LwM2m SenML-JSON object*/
144 static const struct json_obj_descr senml_descr[] = {
145 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_context, "bn",
146 base_name, JSON_TOK_STRING),
147 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_context, "n",
148 name, JSON_TOK_STRING),
149 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_context, "v",
150 val_float, JSON_TOK_FLOAT),
151 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_context, "vb",
152 val_bool, JSON_TOK_TRUE),
153 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_context, "vlo",
154 val_object_link, JSON_TOK_STRING),
155 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_context, "vd",
156 val_opaque, JSON_TOK_OPAQUE),
157 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_context, "vs",
158 val_string, JSON_TOK_STRING),
159 };
160
161 #define JSON_BN_TYPE 1
162 #define JSON_N_TYPE 2
163 #define JSON_V_TYPE 4
164 #define JSON_VB_TYPE 8
165 #define JSON_VLO_TYPE 16
166 #define JSON_VD_TYPE 32
167 #define JSON_VS_TYPE 64
168
169 #define JSON_NAME_MASK (JSON_BN_TYPE + JSON_N_TYPE)
170 #define JSON_VALUE_MASK (JSON_V_TYPE + JSON_VB_TYPE + JSON_VLO_TYPE + JSON_VD_TYPE + JSON_VS_TYPE)
171
172 #define JSON_BIT_CHECK(mask, x) (mask & x)
173
174 static const struct json_obj_descr senml_float_bn_descr[] = {
175 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_bn_payload, "bn",
176 base_name, JSON_TOK_STRING),
177 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_bn_payload, "n",
178 name, JSON_TOK_STRING),
179 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_bn_payload, "v",
180 val_float, JSON_TOK_FLOAT),
181 };
182
183 static const struct json_obj_descr senml_float_bn_t_descr[] = {
184 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_bn_t_payload, "bn",
185 base_name, JSON_TOK_STRING),
186 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_bn_t_payload, "bt",
187 base_time, JSON_TOK_FLOAT),
188 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_bn_t_payload, "n",
189 name, JSON_TOK_STRING),
190 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_bn_t_payload, "v",
191 val_float, JSON_TOK_FLOAT),
192 };
193
194 static const struct json_obj_descr senml_float_descr[] = {
195 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_payload, "n",
196 name, JSON_TOK_STRING),
197 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_payload, "v",
198 val_float, JSON_TOK_FLOAT),
199 };
200
201 static const struct json_obj_descr senml_float_t_descr[] = {
202 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_t_payload, "n",
203 name, JSON_TOK_STRING),
204 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_t_payload, "v",
205 val_float, JSON_TOK_FLOAT),
206 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_float_t_payload, "t",
207 time, JSON_TOK_FLOAT),
208 };
209
210 static const struct json_obj_descr senml_boolean_bn_descr[] = {
211 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_bn_payload, "bn",
212 base_name, JSON_TOK_STRING),
213 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_bn_payload, "n",
214 name, JSON_TOK_STRING),
215 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_bn_payload, "vb",
216 val_bool, JSON_TOK_TRUE),
217 };
218
219 static const struct json_obj_descr senml_boolean_bn_t_descr[] = {
220 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_bn_t_payload, "bn",
221 base_name, JSON_TOK_STRING),
222 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_bn_t_payload, "bt",
223 base_time, JSON_TOK_FLOAT),
224 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_bn_t_payload, "n",
225 name, JSON_TOK_STRING),
226 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_bn_t_payload, "vb",
227 val_bool, JSON_TOK_TRUE),
228 };
229
230 static const struct json_obj_descr senml_boolean_descr[] = {
231 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_payload, "n",
232 name, JSON_TOK_STRING),
233 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_payload, "vb",
234 val_bool, JSON_TOK_TRUE),
235 };
236
237 static const struct json_obj_descr senml_boolean_t_descr[] = {
238 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_t_payload, "n",
239 name, JSON_TOK_STRING),
240 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_t_payload, "vb",
241 val_bool, JSON_TOK_TRUE),
242 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_boolean_t_payload, "t",
243 time, JSON_TOK_FLOAT),
244 };
245
246 static const struct json_obj_descr senml_obj_lnk_bn_descr[] = {
247 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_bn_payload, "bn",
248 base_name, JSON_TOK_STRING),
249 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_bn_payload, "n",
250 name, JSON_TOK_STRING),
251 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_bn_payload, "vlo",
252 val_string, JSON_TOK_STRING),
253 };
254
255 static const struct json_obj_descr senml_obj_lnk_descr[] = {
256 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_payload, "n",
257 name, JSON_TOK_STRING),
258 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_payload, "vlo",
259 val_string, JSON_TOK_STRING),
260 };
261
262 static const struct json_obj_descr senml_opaque_bn_descr[] = {
263 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_opaque_bn_payload, "bn",
264 base_name, JSON_TOK_STRING),
265 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_opaque_bn_payload, "n",
266 name, JSON_TOK_STRING),
267 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_opaque_bn_payload, "vd",
268 val_opaque, JSON_TOK_OPAQUE),
269 };
270
271 static const struct json_obj_descr senml_opaque_descr[] = {
272 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_opaque_payload, "n",
273 name, JSON_TOK_STRING),
274 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_opaque_payload, "vd",
275 val_opaque, JSON_TOK_OPAQUE),
276 };
277
278 static const struct json_obj_descr senml_string_bn_descr[] = {
279 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_bn_payload, "bn",
280 base_name, JSON_TOK_STRING),
281 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_bn_payload, "n",
282 name, JSON_TOK_STRING),
283 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_bn_payload, "vs",
284 val_string, JSON_TOK_STRING),
285 };
286
287 static const struct json_obj_descr senml_string_descr[] = {
288 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_payload, "n",
289 name, JSON_TOK_STRING),
290 JSON_OBJ_DESCR_PRIM_NAMED(struct senml_string_payload, "vs",
291 val_string, JSON_TOK_STRING),
292 };
293
294 struct json_in_formatter_data {
295 int object_bit_field;
296 struct senml_context senml_object;
297 };
298
299 /* some temporary buffer space for format conversions */
300 static char pt_buffer[42];
301
init_object_name_parameters(struct json_out_formatter_data * fd,struct lwm2m_obj_path * path)302 static int init_object_name_parameters(struct json_out_formatter_data *fd,
303 struct lwm2m_obj_path *path)
304 {
305 int ret;
306
307 if (fd->add_base_name_to_start) {
308 /* Init Base name string */
309 ret = snprintk(fd->bn_string, sizeof(fd->bn_string), "/%u/%u/", path->obj_id,
310 path->obj_inst_id);
311 if (ret < 0) {
312 return ret;
313 }
314 }
315
316 /* Init Name string */
317 if (fd->writer_flags & WRITER_RESOURCE_INSTANCE) {
318 ret = snprintk(fd->name_string, sizeof(fd->name_string), "%u/%u", path->res_id,
319 path->res_inst_id);
320 } else {
321 ret = snprintk(fd->name_string, sizeof(fd->name_string), "%u", path->res_id);
322 }
323
324 if (ret < 0) {
325 return ret;
326 }
327
328 return 0;
329 }
330
put_begin(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)331 static int put_begin(struct lwm2m_output_context *out, struct lwm2m_obj_path *path)
332 {
333 int res;
334 struct json_out_formatter_data *fd;
335
336 fd = engine_get_out_user_data(out);
337 if (!fd) {
338 return -EINVAL;
339 }
340
341 res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), "[", 1);
342 if (res < 0) {
343 return res;
344 }
345
346 /* Init base level state for skip first object instance compare */
347 fd->base_name.level = LWM2M_PATH_LEVEL_NONE;
348 return 1;
349 }
350
put_end(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)351 static int put_end(struct lwm2m_output_context *out, struct lwm2m_obj_path *path)
352 {
353 struct json_out_formatter_data *fd;
354 int res;
355
356 fd = engine_get_out_user_data(out);
357 if (!fd) {
358 return -EINVAL;
359 }
360
361 res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), "]", 1);
362 if (res < 0) {
363 return res;
364 }
365
366 return 1;
367 }
368
put_begin_oi(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)369 static int put_begin_oi(struct lwm2m_output_context *out, struct lwm2m_obj_path *path)
370 {
371 struct json_out_formatter_data *fd;
372 bool update_base_name = false;
373
374 fd = engine_get_out_user_data(out);
375 if (!fd) {
376 return -EINVAL;
377 }
378
379 if (fd->base_name.level == LWM2M_PATH_LEVEL_NONE) {
380 update_base_name = true;
381
382 } else if (fd->base_name.obj_id != path->obj_id ||
383 fd->base_name.obj_inst_id != path->obj_inst_id) {
384 update_base_name = true;
385 }
386
387 if (update_base_name) {
388 fd->base_name.level = LWM2M_PATH_LEVEL_OBJECT_INST;
389 fd->base_name.obj_id = path->obj_id;
390 fd->base_name.obj_inst_id = path->obj_inst_id;
391 }
392
393 fd->add_base_name_to_start = update_base_name;
394
395 return 0;
396 }
397
put_begin_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)398 static int put_begin_ri(struct lwm2m_output_context *out, struct lwm2m_obj_path *path)
399 {
400 struct json_out_formatter_data *fd;
401
402 fd = engine_get_out_user_data(out);
403 if (!fd) {
404 return -EINVAL;
405 }
406
407 fd->writer_flags |= WRITER_RESOURCE_INSTANCE;
408 return 0;
409 }
410
put_end_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)411 static int put_end_ri(struct lwm2m_output_context *out, struct lwm2m_obj_path *path)
412 {
413 struct json_out_formatter_data *fd;
414
415 fd = engine_get_out_user_data(out);
416 if (!fd) {
417 return -EINVAL;
418 }
419
420 fd->writer_flags &= ~WRITER_RESOURCE_INSTANCE;
421 return 0;
422 }
423
put_end_r(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)424 static int put_end_r(struct lwm2m_output_context *out, struct lwm2m_obj_path *path)
425 {
426 struct json_out_formatter_data *fd;
427
428 fd = engine_get_out_user_data(out);
429 if (!fd) {
430 return -EINVAL;
431 }
432
433 /* Clear Historical Data */
434 fd->historical_data = false;
435 fd->base_time = 0;
436 return 0;
437 }
438
number_to_string(char * buf,size_t buf_len,const char * format,...)439 static int number_to_string(char *buf, size_t buf_len, const char *format, ...)
440 {
441 va_list vargs;
442 int n;
443
444 va_start(vargs, format);
445 n = vsnprintk(buf, buf_len, format, vargs);
446 va_end(vargs);
447 if (n < 0 || n >= buf_len) {
448 return -EINVAL;
449 }
450
451 return n;
452 }
453
454
float_to_string(double * value)455 static int float_to_string(double *value)
456 {
457 int len;
458
459 len = lwm2m_ftoa(value, pt_buffer, sizeof(pt_buffer), 15);
460 if (len < 0 || len >= sizeof(pt_buffer)) {
461 LOG_ERR("Failed to encode float value");
462 return -EINVAL;
463 }
464
465 return len;
466 }
467
objlnk_to_string(struct lwm2m_objlnk * value)468 static int objlnk_to_string(struct lwm2m_objlnk *value)
469 {
470 return snprintk(pt_buffer, sizeof(pt_buffer), "%u:%u", value->obj_id, value->obj_inst);
471 }
472
json_add_separator(struct lwm2m_output_context * out,struct json_out_formatter_data * fd)473 static int json_add_separator(struct lwm2m_output_context *out, struct json_out_formatter_data *fd)
474 {
475 int len = 0;
476
477 if (fd->writer_flags & WRITER_OUTPUT_VALUE) {
478 /* Add separator */
479 char separator = ',';
480
481 len = buf_append(CPKT_BUF_WRITE(out->out_cpkt), &separator, sizeof(separator));
482 if (len < 0) {
483 return -ENOMEM;
484 }
485 }
486
487 return len;
488 }
489
json_postprefix(struct json_out_formatter_data * fd)490 static void json_postprefix(struct json_out_formatter_data *fd)
491 {
492 fd->writer_flags |= WRITER_OUTPUT_VALUE;
493 fd->add_base_name_to_start = false;
494 }
495
json_float_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,int float_string_length)496 static int json_float_object_write(struct lwm2m_output_context *out,
497 struct json_out_formatter_data *fd, int float_string_length)
498 {
499 int res, len;
500 ssize_t o_len;
501 const struct json_obj_descr *descr;
502 size_t descr_len;
503 void *obj_payload;
504
505 len = json_add_separator(out, fd);
506 if (len < 0) {
507 return len;
508 }
509
510 if (fd->add_base_name_to_start) {
511 if (fd->historical_data) {
512 descr = senml_float_bn_t_descr;
513 descr_len = ARRAY_SIZE(senml_float_bn_t_descr);
514 obj_payload = &fd->json.obj.float_bn_t_obj;
515 fd->json.obj.float_bn_t_obj.base_name = fd->bn_string;
516 fd->json.obj.float_bn_t_obj.name = fd->name_string;
517 fd->json.obj.float_bn_t_obj.val_float.start = pt_buffer;
518 fd->json.obj.float_bn_t_obj.val_float.length = float_string_length;
519 fd->json.obj.float_bn_t_obj.base_time.start = fd->timestamp_buffer;
520 fd->json.obj.float_bn_t_obj.base_time.length = fd->timestamp_length;
521 } else {
522 descr = senml_float_bn_descr;
523 descr_len = ARRAY_SIZE(senml_float_bn_descr);
524 obj_payload = &fd->json.obj.float_bn_obj;
525 fd->json.obj.float_bn_obj.base_name = fd->bn_string;
526 fd->json.obj.float_bn_obj.name = fd->name_string;
527 fd->json.obj.float_bn_obj.val_float.start = pt_buffer;
528 fd->json.obj.float_bn_obj.val_float.length = float_string_length;
529 }
530
531 } else {
532 if (fd->historical_data) {
533 descr = senml_float_t_descr;
534 descr_len = ARRAY_SIZE(senml_float_t_descr);
535 obj_payload = &fd->json.obj.float_t_obj;
536 fd->json.obj.float_t_obj.name = fd->name_string;
537 fd->json.obj.float_t_obj.val_float.start = pt_buffer;
538 fd->json.obj.float_t_obj.val_float.length = float_string_length;
539 fd->json.obj.float_t_obj.time.start = fd->timestamp_buffer;
540 fd->json.obj.float_t_obj.time.length = fd->timestamp_length;
541 } else {
542 descr = senml_float_descr;
543 descr_len = ARRAY_SIZE(senml_float_descr);
544 obj_payload = &fd->json.obj.float_obj;
545 fd->json.obj.float_obj.name = fd->name_string;
546 fd->json.obj.float_obj.val_float.start = pt_buffer;
547 fd->json.obj.float_obj.val_float.length = float_string_length;
548 }
549 }
550
551 /* Calculate length */
552 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
553 if (o_len < 0) {
554 return -EINVAL;
555 }
556
557 /* Encode */
558 res = json_obj_encode_buf(descr, descr_len, obj_payload,
559 CPKT_BUF_W_REGION(out->out_cpkt));
560 if (res < 0) {
561 return -ENOMEM;
562 }
563
564 len += o_len;
565 out->out_cpkt->offset += len;
566 json_postprefix(fd);
567 return len;
568 }
569
json_string_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,char * buf)570 static int json_string_object_write(struct lwm2m_output_context *out,
571 struct json_out_formatter_data *fd, char *buf)
572 {
573 int res, len;
574 ssize_t o_len;
575 const struct json_obj_descr *descr;
576 size_t descr_len;
577 void *obj_payload;
578
579 len = json_add_separator(out, fd);
580 if (len < 0) {
581 return len;
582 }
583
584 if (fd->add_base_name_to_start) {
585 descr = senml_string_bn_descr;
586 descr_len = ARRAY_SIZE(senml_string_bn_descr);
587 obj_payload = &fd->json.obj.string_bn_obj;
588 fd->json.obj.string_bn_obj.base_name = fd->bn_string;
589 fd->json.obj.string_bn_obj.name = fd->name_string;
590 fd->json.obj.string_bn_obj.val_string = buf;
591
592 } else {
593 descr = senml_string_descr;
594 descr_len = ARRAY_SIZE(senml_string_descr);
595 obj_payload = &fd->json.obj.string_obj;
596 fd->json.obj.string_obj.name = fd->name_string;
597 fd->json.obj.string_obj.val_string = buf;
598 }
599
600 /* Calculate length */
601 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
602 if (o_len < 0) {
603 return -EINVAL;
604 }
605
606 /* Encode */
607 res = json_obj_encode_buf(descr, descr_len, obj_payload,
608 CPKT_BUF_W_REGION(out->out_cpkt));
609 if (res < 0) {
610 return -ENOMEM;
611 }
612
613 len += o_len;
614 out->out_cpkt->offset += len;
615 json_postprefix(fd);
616 return len;
617 }
618
json_boolean_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,bool value)619 static int json_boolean_object_write(struct lwm2m_output_context *out,
620 struct json_out_formatter_data *fd, bool value)
621 {
622 int res, len;
623 ssize_t o_len;
624 const struct json_obj_descr *descr;
625 size_t descr_len;
626 void *obj_payload;
627
628 len = json_add_separator(out, fd);
629 if (len < 0) {
630 return len;
631 }
632
633 if (fd->add_base_name_to_start) {
634 if (fd->historical_data) {
635 descr = senml_boolean_bn_t_descr;
636 descr_len = ARRAY_SIZE(senml_boolean_bn_t_descr);
637 obj_payload = &fd->json.obj.boolean_bn_t_obj;
638 fd->json.obj.boolean_bn_t_obj.base_name = fd->bn_string;
639 fd->json.obj.boolean_bn_t_obj.name = fd->name_string;
640 fd->json.obj.boolean_bn_t_obj.base_time.start = fd->timestamp_buffer;
641 fd->json.obj.boolean_bn_t_obj.base_time.length = fd->timestamp_length;
642 fd->json.obj.boolean_bn_t_obj.val_bool = value;
643 } else {
644 descr = senml_boolean_bn_descr;
645 descr_len = ARRAY_SIZE(senml_boolean_bn_descr);
646 obj_payload = &fd->json.obj.boolean_bn_obj;
647 fd->json.obj.boolean_bn_obj.base_name = fd->bn_string;
648 fd->json.obj.boolean_bn_obj.name = fd->name_string;
649 fd->json.obj.boolean_bn_obj.val_bool = value;
650 }
651
652 } else {
653 if (fd->historical_data) {
654 descr = senml_boolean_t_descr;
655 descr_len = ARRAY_SIZE(senml_boolean_t_descr);
656 obj_payload = &fd->json.obj.boolean_t_obj;
657 fd->json.obj.boolean_t_obj.name = fd->name_string;
658 fd->json.obj.boolean_t_obj.time.start = fd->timestamp_buffer;
659 fd->json.obj.boolean_t_obj.time.length = fd->timestamp_length;
660 fd->json.obj.boolean_t_obj.val_bool = value;
661 } else {
662 descr = senml_boolean_descr;
663 descr_len = ARRAY_SIZE(senml_boolean_descr);
664 obj_payload = &fd->json.obj.boolean_obj;
665 fd->json.obj.boolean_obj.name = fd->name_string;
666 fd->json.obj.boolean_obj.val_bool = value;
667 }
668 }
669
670 /* Calculate length */
671 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
672 if (o_len < 0) {
673 return -EINVAL;
674 }
675
676 /* Encode */
677 res = json_obj_encode_buf(descr, descr_len, obj_payload,
678 CPKT_BUF_W_REGION(out->out_cpkt));
679 if (res < 0) {
680 return -ENOMEM;
681 }
682
683 len += o_len;
684 out->out_cpkt->offset += len;
685 json_postprefix(fd);
686 return len;
687 }
688
json_objlnk_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd)689 static int json_objlnk_object_write(struct lwm2m_output_context *out,
690 struct json_out_formatter_data *fd)
691 {
692 int res, len;
693 ssize_t o_len;
694 const struct json_obj_descr *descr;
695 size_t descr_len;
696 void *obj_payload;
697
698 len = json_add_separator(out, fd);
699 if (len < 0) {
700 return len;
701 }
702
703 if (fd->add_base_name_to_start) {
704 descr = senml_obj_lnk_bn_descr;
705 descr_len = ARRAY_SIZE(senml_obj_lnk_bn_descr);
706 obj_payload = &fd->json.obj.string_bn_obj;
707 fd->json.obj.string_bn_obj.base_name = fd->bn_string;
708 fd->json.obj.string_bn_obj.name = fd->name_string;
709 fd->json.obj.string_bn_obj.val_string = pt_buffer;
710
711 } else {
712 descr = senml_obj_lnk_descr;
713 descr_len = ARRAY_SIZE(senml_obj_lnk_descr);
714 obj_payload = &fd->json.obj.string_obj;
715 fd->json.obj.string_obj.name = fd->name_string;
716 fd->json.obj.string_obj.val_string = pt_buffer;
717 }
718
719 /* Calculate length */
720 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
721 if (o_len < 0) {
722 return -EINVAL;
723 }
724
725 /* Encode */
726 res = json_obj_encode_buf(descr, descr_len, obj_payload,
727 CPKT_BUF_W_REGION(out->out_cpkt));
728 if (res < 0) {
729 return -ENOMEM;
730 }
731
732 len += o_len;
733 out->out_cpkt->offset += len;
734 json_postprefix(fd);
735 return len;
736 }
737
put_s32(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int32_t value)738 static int put_s32(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int32_t value)
739 {
740 struct json_out_formatter_data *fd;
741 int len = 0;
742
743 fd = engine_get_out_user_data(out);
744
745 if (!out->out_cpkt || !fd) {
746 return -EINVAL;
747 }
748
749 if (init_object_name_parameters(fd, path)) {
750 return -EINVAL;
751 }
752
753 len = number_to_string(pt_buffer, sizeof(pt_buffer), "%d", value);
754 if (len < 0) {
755 return len;
756 }
757
758 return json_float_object_write(out, fd, len);
759 }
760
put_s16(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int16_t value)761 static int put_s16(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int16_t value)
762 {
763 return put_s32(out, path, (int32_t)value);
764 }
765
put_s8(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int8_t value)766 static int put_s8(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int8_t value)
767 {
768 return put_s32(out, path, (int32_t)value);
769 }
770
put_s64(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int64_t value)771 static int put_s64(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int64_t value)
772 {
773 struct json_out_formatter_data *fd;
774 int len;
775
776 fd = engine_get_out_user_data(out);
777
778 if (!out->out_cpkt || !fd) {
779 return -EINVAL;
780 }
781
782 if (init_object_name_parameters(fd, path)) {
783 return -EINVAL;
784 }
785
786 len = number_to_string(pt_buffer, sizeof(pt_buffer), "%lld", value);
787 if (len < 0) {
788 return len;
789 }
790
791 return json_float_object_write(out, fd, len);
792 }
793
put_time(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,time_t value)794 static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, time_t value)
795 {
796 return put_s64(out, path, (int64_t)value);
797 }
798
put_string(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,char * buf,size_t buflen)799 static int put_string(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, char *buf,
800 size_t buflen)
801 {
802 struct json_out_formatter_data *fd;
803
804 fd = engine_get_out_user_data(out);
805
806 if (!out->out_cpkt || !fd) {
807 return -EINVAL;
808 }
809
810 if (init_object_name_parameters(fd, path)) {
811 return -EINVAL;
812 }
813
814 return json_string_object_write(out, fd, buf);
815
816 }
817
put_float(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,double * value)818 static int put_float(struct lwm2m_output_context *out, struct lwm2m_obj_path *path,
819 double *value)
820 {
821 struct json_out_formatter_data *fd;
822 int len;
823
824 fd = engine_get_out_user_data(out);
825
826 if (!out->out_cpkt || !fd) {
827 return -EINVAL;
828 }
829
830 if (init_object_name_parameters(fd, path)) {
831 return -EINVAL;
832 }
833
834 len = float_to_string(value);
835 if (len < 0) {
836 return len;
837 }
838
839 return json_float_object_write(out, fd, len);
840 }
841
put_bool(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,bool value)842 static int put_bool(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, bool value)
843 {
844 struct json_out_formatter_data *fd;
845
846 fd = engine_get_out_user_data(out);
847
848 if (!out->out_cpkt || !fd) {
849 return -EINVAL;
850 }
851
852 if (init_object_name_parameters(fd, path)) {
853 return -EINVAL;
854 }
855
856 return json_boolean_object_write(out, fd, value);
857 }
858
859 #define SEN_BASE64_SIZE_T_MAX ((size_t) -1)
860
861 /*
862 * Encode a buffer into base64 format
863 */
base64_encoded_length(size_t slen)864 static size_t base64_encoded_length(size_t slen)
865 {
866 size_t n;
867
868 if (slen == 0) {
869 return 0;
870 }
871
872 n = slen / 3 + (slen % 3 != 0);
873
874 if (n > (SEN_BASE64_SIZE_T_MAX - 1) / 4) {
875 return -ENOMEM;
876 }
877
878 n *= 4;
879 return n;
880 }
881
json_base64_encode_data(struct json_out_formatter_data * fd,const char * buf)882 static bool json_base64_encode_data(struct json_out_formatter_data *fd, const char *buf)
883 {
884 if (fd->add_base_name_to_start) {
885 if (fd->json.obj.opaque_bn_obj.val_opaque.start == buf) {
886 return true;
887 }
888 } else if (fd->json.obj.opaque_obj.val_opaque.start == buf) {
889 return true;
890 }
891 return false;
892 }
893
json_append_bytes_base64(const char * bytes,size_t len,void * data)894 static int json_append_bytes_base64(const char *bytes, size_t len, void *data)
895 {
896 struct json_out_formatter_data *fd = data;
897 struct lwm2m_output_context *out;
898 size_t temp_length = 0;
899
900 out = fd->out;
901
902 if (json_base64_encode_data(fd, bytes)) {
903 if (base64_encode(CPKT_BUF_W_PTR(out->out_cpkt), CPKT_BUF_W_SIZE(out->out_cpkt),
904 &temp_length, bytes, len)) {
905 /* No space available for base64 data */
906 return -ENOMEM;
907 }
908 /* Update Data offset */
909 out->out_cpkt->offset += temp_length;
910 } else {
911 if (buf_append(CPKT_BUF_WRITE(fd->out->out_cpkt), bytes, len) < 0) {
912 return -ENOMEM;
913 }
914 }
915
916 return 0;
917 }
918
put_opaque(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,char * buf,size_t buflen)919 static int put_opaque(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, char *buf,
920 size_t buflen)
921 {
922 struct json_out_formatter_data *fd;
923 int res, len;
924 ssize_t o_len, encoded_length;
925 const struct json_obj_descr *descr;
926 size_t descr_len;
927 void *obj_payload;
928
929 fd = engine_get_out_user_data(out);
930
931 if (!out->out_cpkt || !fd) {
932 return -EINVAL;
933 }
934
935 if (init_object_name_parameters(fd, path)) {
936 return -EINVAL;
937 }
938
939 encoded_length = base64_encoded_length(buflen);
940 if (encoded_length < 0) {
941 return -ENOMEM;
942 }
943
944 len = json_add_separator(out, fd);
945 if (len < 0) {
946 return len;
947 }
948
949 if (fd->add_base_name_to_start) {
950 descr = senml_opaque_bn_descr;
951 descr_len = ARRAY_SIZE(senml_opaque_bn_descr);
952 obj_payload = &fd->json.obj.opaque_bn_obj;
953 fd->json.obj.opaque_bn_obj.base_name = fd->bn_string;
954 fd->json.obj.opaque_bn_obj.name = fd->name_string;
955 fd->json.obj.opaque_bn_obj.val_opaque.start = buf;
956 fd->json.obj.opaque_bn_obj.val_opaque.length = encoded_length;
957 } else {
958 descr = senml_opaque_descr;
959 descr_len = ARRAY_SIZE(senml_opaque_descr);
960 obj_payload = &fd->json.obj.opaque_obj;
961 fd->json.obj.opaque_obj.name = fd->name_string;
962 fd->json.obj.opaque_obj.val_opaque.start = buf;
963 fd->json.obj.opaque_obj.val_opaque.length = encoded_length;
964 }
965 /* Store Out context pointer for data write */
966 fd->out = out;
967
968 /* Calculate length */
969 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
970 if (o_len < 0) {
971 return -EINVAL;
972 }
973
974 /* Put Original payload length back */
975 if (fd->add_base_name_to_start) {
976 fd->json.obj.opaque_bn_obj.val_opaque.length = buflen;
977 } else {
978 fd->json.obj.opaque_obj.val_opaque.length = buflen;
979 }
980
981 /* Encode */
982 res = json_obj_encode(descr, descr_len, obj_payload, json_append_bytes_base64, fd);
983 if (res < 0) {
984 return -ENOMEM;
985 }
986
987 json_postprefix(fd);
988 len += o_len;
989 return len;
990
991 }
992
put_objlnk(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,struct lwm2m_objlnk * value)993 static int put_objlnk(struct lwm2m_output_context *out, struct lwm2m_obj_path *path,
994 struct lwm2m_objlnk *value)
995 {
996 struct json_out_formatter_data *fd;
997
998 fd = engine_get_out_user_data(out);
999
1000 if (!out->out_cpkt || !fd) {
1001 return -EINVAL;
1002 }
1003
1004 if (init_object_name_parameters(fd, path)) {
1005 return -EINVAL;
1006 }
1007
1008 if (objlnk_to_string(value) < 0) {
1009 return -EINVAL;
1010 }
1011
1012 return json_objlnk_object_write(out, fd);
1013 }
1014
read_int(struct lwm2m_input_context * in,int64_t * value,bool accept_sign)1015 static int read_int(struct lwm2m_input_context *in, int64_t *value, bool accept_sign)
1016 {
1017 struct json_in_formatter_data *fd;
1018 const uint8_t *buf;
1019 size_t i = 0;
1020 bool neg = false;
1021 char c;
1022
1023 /* initialize values to 0 */
1024 *value = 0;
1025
1026 fd = engine_get_in_user_data(in);
1027 if (!fd || !JSON_BIT_CHECK(fd->object_bit_field, JSON_V_TYPE)) {
1028 return -EINVAL;
1029 }
1030
1031 size_t value_length = fd->senml_object.val_float.length;
1032
1033 if (value_length == 0) {
1034 return -ENODATA;
1035 }
1036
1037 buf = fd->senml_object.val_float.start;
1038 while (*(buf + i) && i < value_length) {
1039 c = *(buf + i);
1040 if (c == '-' && accept_sign && i == 0) {
1041 neg = true;
1042 } else if (isdigit(c) != 0) {
1043 *value = *value * 10 + (c - '0');
1044 } else {
1045 /* anything else stop reading */
1046 break;
1047 }
1048 i++;
1049 }
1050
1051 if (neg) {
1052 *value = -*value;
1053 }
1054
1055 return i;
1056 }
1057
get_s64(struct lwm2m_input_context * in,int64_t * value)1058 static int get_s64(struct lwm2m_input_context *in, int64_t *value)
1059 {
1060 return read_int(in, value, true);
1061 }
1062
get_time(struct lwm2m_input_context * in,time_t * value)1063 static int get_time(struct lwm2m_input_context *in, time_t *value)
1064 {
1065 int64_t temp64;
1066 int ret;
1067
1068 ret = read_int(in, &temp64, true);
1069 *value = (time_t)temp64;
1070
1071 return ret;
1072 }
1073
get_s32(struct lwm2m_input_context * in,int32_t * value)1074 static int get_s32(struct lwm2m_input_context *in, int32_t *value)
1075 {
1076 int64_t tmp = 0;
1077 int len = 0;
1078
1079 len = read_int(in, &tmp, true);
1080 if (len > 0) {
1081 *value = (int32_t)tmp;
1082 }
1083
1084 return len;
1085 }
1086
get_string(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen)1087 static int get_string(struct lwm2m_input_context *in, uint8_t *buf, size_t buflen)
1088 {
1089 struct json_in_formatter_data *fd;
1090 size_t string_length;
1091
1092 fd = engine_get_in_user_data(in);
1093 if (!fd || !JSON_BIT_CHECK(fd->object_bit_field, JSON_VS_TYPE)) {
1094 return -EINVAL;
1095 }
1096
1097 string_length = strlen(fd->senml_object.val_string);
1098
1099 if (string_length > buflen) {
1100 LOG_WRN("Buffer too small to accommodate string, truncating");
1101 string_length = buflen - 1;
1102 }
1103 memcpy(buf, fd->senml_object.val_string, string_length);
1104
1105 /* add NULL */
1106 buf[string_length] = '\0';
1107
1108 return string_length;
1109 }
1110
get_float(struct lwm2m_input_context * in,double * value)1111 static int get_float(struct lwm2m_input_context *in, double *value)
1112 {
1113 struct json_in_formatter_data *fd;
1114
1115 int i = 0, len = 0;
1116 bool has_dot = false;
1117 uint8_t tmp, buf[24];
1118 const uint8_t *json_buf;
1119
1120 fd = engine_get_in_user_data(in);
1121 if (!fd || !JSON_BIT_CHECK(fd->object_bit_field, JSON_V_TYPE)) {
1122 return -EINVAL;
1123 }
1124
1125 size_t value_length = fd->senml_object.val_float.length;
1126
1127 if (value_length == 0) {
1128 return -ENODATA;
1129 }
1130
1131 json_buf = fd->senml_object.val_float.start;
1132 while (*(json_buf + len) && len < value_length) {
1133 tmp = *(json_buf + len);
1134
1135 if ((tmp == '-' && i == 0) || (tmp == '.' && !has_dot) || isdigit(tmp) != 0) {
1136 len++;
1137
1138 /* Copy only if it fits into provided buffer - we won't
1139 * get better precision anyway.
1140 */
1141 if (i < sizeof(buf) - 1) {
1142 buf[i++] = tmp;
1143 }
1144
1145 if (tmp == '.') {
1146 has_dot = true;
1147 }
1148 } else {
1149 break;
1150 }
1151 }
1152
1153 buf[i] = '\0';
1154
1155 if (lwm2m_atof(buf, value) != 0) {
1156 LOG_ERR("Failed to parse float value");
1157 }
1158
1159 return len;
1160 }
1161
get_bool(struct lwm2m_input_context * in,bool * value)1162 static int get_bool(struct lwm2m_input_context *in, bool *value)
1163 {
1164 struct json_in_formatter_data *fd;
1165
1166 fd = engine_get_in_user_data(in);
1167 if (!fd || !JSON_BIT_CHECK(fd->object_bit_field, JSON_VB_TYPE)) {
1168 return -EINVAL;
1169 }
1170
1171 *value = fd->senml_object.val_bool;
1172
1173 return 1;
1174 }
1175
base64_url_safe_decode(uint8_t * data_buf,size_t buf_len)1176 static void base64_url_safe_decode(uint8_t *data_buf, size_t buf_len)
1177 {
1178 uint8_t *ptr = data_buf;
1179
1180 for (size_t i = 0; i < buf_len; i++) {
1181 if (*ptr == '-') {
1182 /* replace '-' with "+" */
1183 *ptr = '+';
1184 } else if (*ptr == '_') {
1185 /* replace '_' with "/" */
1186 *ptr = '/';
1187 }
1188 ptr++;
1189 }
1190 }
1191
store_padded_modulo(uint16_t * padded_length,uint8_t * padded_buf,uint8_t * data_tail,uint16_t data_length)1192 static int store_padded_modulo(uint16_t *padded_length, uint8_t *padded_buf, uint8_t *data_tail,
1193 uint16_t data_length)
1194 {
1195 uint16_t padded_len = BASE64_MODULO_LENGTH(data_length);
1196
1197 if (data_length < padded_len) {
1198 return -ENODATA;
1199 }
1200 *padded_length = padded_len;
1201
1202 if (padded_len) {
1203 uint8_t *tail_ptr;
1204
1205 tail_ptr = data_tail - padded_len;
1206 memcpy(padded_buf, tail_ptr, padded_len);
1207 for (size_t i = padded_len; i < BASE64_OUTPUT_MIN_LENGTH; i++) {
1208 padded_buf[i] = '=';
1209 }
1210 }
1211 return 0;
1212 }
1213
get_opaque(struct lwm2m_input_context * in,uint8_t * value,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)1214 static int get_opaque(struct lwm2m_input_context *in, uint8_t *value, size_t buflen,
1215 struct lwm2m_opaque_context *opaque, bool *last_block)
1216 {
1217 struct json_in_formatter_data *fd;
1218 struct json_obj_token *val_opaque;
1219 uint8_t *data_ptr;
1220 int in_len, ret;
1221 uint16_t padded_length = 0;
1222 uint8_t padded_buf[BASE64_OUTPUT_MIN_LENGTH];
1223 size_t buffer_base64_length;
1224
1225 fd = engine_get_in_user_data(in);
1226 if (!fd || !JSON_BIT_CHECK(fd->object_bit_field, JSON_VD_TYPE)) {
1227 return -EINVAL;
1228 }
1229 val_opaque = &fd->senml_object.val_opaque;
1230
1231 data_ptr = val_opaque->start;
1232
1233 /* Decode from url safe to normal */
1234 base64_url_safe_decode(data_ptr, val_opaque->length);
1235
1236 if (opaque->remaining == 0) {
1237 size_t original_size = val_opaque->length;
1238 size_t base64_length;
1239
1240 ret = store_padded_modulo(&padded_length, padded_buf, data_ptr + original_size,
1241 original_size);
1242 if (ret) {
1243 return ret;
1244 }
1245
1246 if (base64_decode(data_ptr, val_opaque->length, &base64_length, data_ptr,
1247 val_opaque->length) < 0) {
1248 return -ENODATA;
1249 }
1250
1251 val_opaque->length = base64_length;
1252 if (padded_length) {
1253 if (base64_decode(padded_buf, BASE64_OUTPUT_MIN_LENGTH,
1254 &buffer_base64_length, padded_buf,
1255 BASE64_OUTPUT_MIN_LENGTH) < 0) {
1256 return -ENODATA;
1257 }
1258 /* Add padded tail */
1259 memcpy(data_ptr + val_opaque->length, padded_buf, buffer_base64_length);
1260 val_opaque->length += buffer_base64_length;
1261 }
1262 opaque->len = val_opaque->length;
1263 opaque->remaining = val_opaque->length;
1264 }
1265
1266 in_len = opaque->remaining;
1267
1268 if (in_len > buflen) {
1269 in_len = buflen;
1270 }
1271
1272 if (in_len > val_opaque->length) {
1273 in_len = val_opaque->length;
1274 }
1275
1276 opaque->remaining -= in_len;
1277 if (opaque->remaining == 0U) {
1278 *last_block = true;
1279 }
1280 /* Copy data to buffer */
1281 memcpy(value, data_ptr, in_len);
1282
1283 return in_len;
1284 }
1285
get_objlnk(struct lwm2m_input_context * in,struct lwm2m_objlnk * value)1286 static int get_objlnk(struct lwm2m_input_context *in, struct lwm2m_objlnk *value)
1287 {
1288 int64_t tmp;
1289 int len, total_len;
1290 struct json_in_formatter_data *fd;
1291 char *demiliter_pos;
1292
1293 fd = engine_get_in_user_data(in);
1294 if (!fd || !JSON_BIT_CHECK(fd->object_bit_field, JSON_VLO_TYPE)) {
1295 return -EINVAL;
1296 }
1297
1298 demiliter_pos = strchr(fd->senml_object.val_object_link, ':');
1299 if (!demiliter_pos) {
1300 return -ENODATA;
1301 }
1302
1303 fd->object_bit_field |= JSON_V_TYPE;
1304 fd->senml_object.val_float.start = fd->senml_object.val_object_link;
1305 fd->senml_object.val_float.length = strlen(fd->senml_object.val_object_link);
1306
1307 /* Set String end for first item */
1308 *demiliter_pos = '\0';
1309
1310 len = read_int(in, &tmp, false);
1311 if (len <= 0) {
1312 return -ENODATA;
1313 }
1314
1315 total_len = len;
1316 value->obj_id = (uint16_t)tmp;
1317
1318 len++; /* +1 for ':' delimiter. */
1319 demiliter_pos++;
1320 fd->senml_object.val_float.start = demiliter_pos;
1321 fd->senml_object.val_float.length = strlen(demiliter_pos);
1322
1323 len = read_int(in, &tmp, false);
1324 if (len <= 0) {
1325 return -ENODATA;
1326 }
1327
1328 total_len += len;
1329 value->obj_inst = (uint16_t)tmp;
1330
1331 return total_len;
1332 }
1333
put_data_timestamp(struct lwm2m_output_context * out,time_t value)1334 static int put_data_timestamp(struct lwm2m_output_context *out, time_t value)
1335 {
1336 struct json_out_formatter_data *fd;
1337 int len;
1338
1339 fd = engine_get_out_user_data(out);
1340
1341 if (!out->out_cpkt || !fd) {
1342 LOG_ERR("Timestamp fail");
1343 return -EINVAL;
1344 }
1345
1346 len = number_to_string(fd->timestamp_buffer, sizeof(fd->timestamp_buffer), "%lld",
1347 value - fd->base_time);
1348
1349 if (len < 0) {
1350 return len;
1351 }
1352
1353 if (fd->base_time == 0) {
1354 /* Store base time */
1355 fd->base_time = value;
1356 }
1357
1358 fd->timestamp_length = len;
1359 fd->historical_data = true;
1360
1361 return 0;
1362 }
1363
1364 const struct lwm2m_writer senml_json_writer = {
1365 .put_begin = put_begin,
1366 .put_end = put_end,
1367 .put_begin_oi = put_begin_oi,
1368 .put_begin_ri = put_begin_ri,
1369 .put_end_ri = put_end_ri,
1370 .put_end_r = put_end_r,
1371 .put_s8 = put_s8,
1372 .put_s16 = put_s16,
1373 .put_s32 = put_s32,
1374 .put_s64 = put_s64,
1375 .put_string = put_string,
1376 .put_time = put_time,
1377 .put_float = put_float,
1378 .put_bool = put_bool,
1379 .put_opaque = put_opaque,
1380 .put_objlnk = put_objlnk,
1381 .put_data_timestamp = put_data_timestamp,
1382 };
1383
1384 const struct lwm2m_reader senml_json_reader = {
1385 .get_s32 = get_s32,
1386 .get_s64 = get_s64,
1387 .get_string = get_string,
1388 .get_time = get_time,
1389 .get_float = get_float,
1390 .get_bool = get_bool,
1391 .get_opaque = get_opaque,
1392 .get_objlnk = get_objlnk,
1393 };
1394
do_read_op_senml_json(struct lwm2m_message * msg)1395 int do_read_op_senml_json(struct lwm2m_message *msg)
1396 {
1397 struct lwm2m_obj_path_list temp;
1398 sys_slist_t lwm2m_path_list;
1399 int ret;
1400 struct json_out_formatter_data fd;
1401
1402 (void)memset(&fd, 0, sizeof(fd));
1403 engine_set_out_user_data(&msg->out, &fd);
1404 /* Init list */
1405 sys_slist_init(&lwm2m_path_list);
1406 /* Init message here ready for response */
1407 temp.path = msg->path;
1408 /* Add one entry to list */
1409 sys_slist_append(&lwm2m_path_list, &temp.node);
1410
1411 ret = lwm2m_perform_read_op(msg, LWM2M_FORMAT_APP_SEML_JSON);
1412 engine_clear_out_user_data(&msg->out);
1413
1414 return ret;
1415 }
1416
lwm2m_senml_write_operation(struct lwm2m_message * msg,struct json_in_formatter_data * fd)1417 static int lwm2m_senml_write_operation(struct lwm2m_message *msg, struct json_in_formatter_data *fd)
1418 {
1419 struct lwm2m_engine_obj_field *obj_field = NULL;
1420 struct lwm2m_engine_obj_inst *obj_inst = NULL;
1421 struct lwm2m_engine_res *res = NULL;
1422 struct lwm2m_engine_res_inst *res_inst = NULL;
1423 uint8_t created;
1424 int ret = 0;
1425
1426 /* handle resource value */
1427 /* reset values */
1428 created = 0U;
1429
1430 /* if valid, use the return value as level */
1431 ret = lwm2m_get_or_create_engine_obj(msg, &obj_inst, &created);
1432 if (ret < 0) {
1433 return ret;
1434 }
1435
1436 ret = lwm2m_engine_validate_write_access(msg, obj_inst, &obj_field);
1437 if (ret < 0) {
1438 return ret;
1439 }
1440
1441 ret = lwm2m_engine_get_create_res_inst(&msg->path, &res, &res_inst);
1442 if (ret < 0) {
1443 /* if OPTIONAL and BOOTSTRAP-WRITE or CREATE use ENOTSUP */
1444 if ((msg->ctx->bootstrap_mode ||
1445 msg->operation == LWM2M_OP_CREATE) &&
1446 LWM2M_HAS_PERM(obj_field, BIT(LWM2M_FLAG_OPTIONAL))) {
1447 ret = -ENOTSUP;
1448 return ret;
1449 }
1450
1451 ret = -ENOENT;
1452 return ret;
1453 }
1454
1455 /* Write the resource value */
1456 ret = lwm2m_write_handler(obj_inst, res, res_inst, obj_field, msg);
1457 if (ret == -EACCES || ret == -ENOENT) {
1458 /* if read-only or non-existent data buffer move on */
1459 ret = 0;
1460 }
1461
1462 return ret;
1463 }
1464
do_write_op_senml_json(struct lwm2m_message * msg)1465 int do_write_op_senml_json(struct lwm2m_message *msg)
1466 {
1467 struct json_in_formatter_data fd;
1468 struct json_obj json_object;
1469 struct lwm2m_obj_path resource_path;
1470 int ret = 0;
1471 uint8_t full_name[MAX_RESOURCE_LEN + 1] = {0};
1472 const char *base_name_ptr = NULL;
1473 char *data_ptr;
1474 uint16_t in_len;
1475
1476 (void)memset(&fd, 0, sizeof(fd));
1477 engine_set_in_user_data(&msg->in, &fd);
1478
1479 if (msg->in.block_ctx) {
1480 LOG_ERR("Json library not support Coap Block");
1481 ret = -EOPNOTSUPP;
1482 goto end_of_operation;
1483 }
1484
1485 data_ptr = (char *)coap_packet_get_payload(msg->in.in_cpkt, &in_len);
1486
1487 /* When No blockwise do Normal Init */
1488 if (json_arr_separate_object_parse_init(&json_object, data_ptr, in_len)) {
1489 ret = -EINVAL;
1490 goto end_of_operation;
1491 }
1492
1493 while (1) {
1494
1495 (void)memset(&fd.senml_object, 0, sizeof(fd.senml_object));
1496 fd.object_bit_field = json_arr_separate_parse_object(&json_object, senml_descr,
1497 ARRAY_SIZE(senml_descr), &fd.senml_object);
1498 if (fd.object_bit_field == 0) {
1499 /* End of */
1500 break;
1501 } else if (fd.object_bit_field < 0 ||
1502 ((fd.object_bit_field & JSON_NAME_MASK) == 0 ||
1503 (fd.object_bit_field & JSON_VALUE_MASK) == 0)) {
1504 LOG_ERR("Json Write Parse object fail %d", fd.object_bit_field);
1505 ret = -EINVAL;
1506 goto end_of_operation;
1507 }
1508
1509 if (JSON_BIT_CHECK(fd.object_bit_field, JSON_BN_TYPE)) {
1510 base_name_ptr = fd.senml_object.base_name;
1511 }
1512
1513 /* Create object resource path */
1514 if (base_name_ptr) {
1515 if (JSON_BIT_CHECK(fd.object_bit_field, JSON_N_TYPE)) {
1516 ret = snprintk(full_name, sizeof(full_name), "%s%s", base_name_ptr,
1517 fd.senml_object.name);
1518 } else {
1519 ret = snprintk(full_name, sizeof(full_name), "%s", base_name_ptr);
1520 }
1521 } else {
1522 ret = snprintk(full_name, sizeof(full_name), "%s", fd.senml_object.name);
1523 }
1524
1525 if (ret >= MAX_RESOURCE_LEN) {
1526 ret = -EINVAL;
1527 goto end_of_operation;
1528 }
1529
1530 ret = lwm2m_string_to_path(full_name, &resource_path, '/');
1531 if (ret < 0) {
1532 LOG_ERR("Relative name too long");
1533 ret = -EINVAL;
1534 goto end_of_operation;
1535 }
1536
1537 msg->path = resource_path;
1538 ret = lwm2m_senml_write_operation(msg, &fd);
1539
1540 /*
1541 * for OP_CREATE and BOOTSTRAP WRITE: errors on
1542 * optional resources are ignored (ENOTSUP)
1543 */
1544 if (ret < 0 && !((ret == -ENOTSUP) &&
1545 (msg->ctx->bootstrap_mode || msg->operation == LWM2M_OP_CREATE))) {
1546 goto end_of_operation;
1547 }
1548 }
1549
1550 ret = 0;
1551
1552 end_of_operation:
1553 engine_clear_in_user_data(&msg->in);
1554
1555 return ret;
1556 }
1557
json_parse_composite_read_paths(struct lwm2m_message * msg,sys_slist_t * lwm2m_path_list,sys_slist_t * lwm2m_path_free_list)1558 static uint8_t json_parse_composite_read_paths(struct lwm2m_message *msg,
1559 sys_slist_t *lwm2m_path_list,
1560 sys_slist_t *lwm2m_path_free_list)
1561 {
1562 struct lwm2m_obj_path path;
1563 struct json_obj json_object;
1564 struct senml_context ts;
1565
1566 uint8_t full_name[MAX_RESOURCE_LEN + 1] = {0};
1567 uint8_t valid_path_cnt = 0;
1568 const char *base_name_ptr = NULL;
1569 char *data_ptr;
1570 int bit_field;
1571 uint16_t in_len;
1572 int ret;
1573
1574 data_ptr = (char *)coap_packet_get_payload(msg->in.in_cpkt, &in_len);
1575
1576 if (json_arr_separate_object_parse_init(&json_object, data_ptr, in_len)) {
1577 return 0;
1578 }
1579
1580 while (1) {
1581 bit_field = json_arr_separate_parse_object(&json_object, senml_descr,
1582 ARRAY_SIZE(senml_descr), &ts);
1583 if (bit_field < 0) {
1584 LOG_ERR("Json Read Parse object fail %d", bit_field);
1585 break;
1586 } else if (JSON_BIT_CHECK(bit_field, JSON_NAME_MASK) == 0) {
1587 break;
1588 }
1589
1590 if (JSON_BIT_CHECK(bit_field, JSON_BN_TYPE)) {
1591 base_name_ptr = ts.base_name;
1592 }
1593
1594 /* Create object resource path */
1595 if (base_name_ptr) {
1596 if (JSON_BIT_CHECK(bit_field, JSON_N_TYPE)) {
1597 ret = snprintk(full_name, sizeof(full_name), "%s%s", base_name_ptr,
1598 ts.name);
1599 } else {
1600 ret = snprintk(full_name, sizeof(full_name), "%s", base_name_ptr);
1601 }
1602 } else {
1603 ret = snprintk(full_name, sizeof(full_name), "%s", ts.name);
1604 }
1605
1606 if (ret < MAX_RESOURCE_LEN) {
1607 ret = lwm2m_string_to_path(full_name, &path, '/');
1608 if (ret == 0) {
1609 if (lwm2m_engine_add_path_to_list(
1610 lwm2m_path_list, lwm2m_path_free_list, &path) == 0) {
1611 valid_path_cnt++;
1612 }
1613 }
1614 }
1615 }
1616
1617 return valid_path_cnt;
1618 }
1619
do_composite_read_op_for_parsed_list_senml_json(struct lwm2m_message * msg,sys_slist_t * path_list)1620 int do_composite_read_op_for_parsed_list_senml_json(struct lwm2m_message *msg,
1621 sys_slist_t *path_list)
1622 {
1623 int ret;
1624 struct json_out_formatter_data fd;
1625
1626 (void)memset(&fd, 0, sizeof(fd));
1627 engine_set_out_user_data(&msg->out, &fd);
1628
1629 ret = lwm2m_perform_composite_read_op(msg, LWM2M_FORMAT_APP_SEML_JSON, path_list);
1630 engine_clear_out_user_data(&msg->out);
1631
1632 return ret;
1633 }
1634
do_composite_read_op_senml_json(struct lwm2m_message * msg)1635 int do_composite_read_op_senml_json(struct lwm2m_message *msg)
1636 {
1637 struct lwm2m_obj_path_list path_list_buf[CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE];
1638 sys_slist_t path_list;
1639 sys_slist_t free_list;
1640 uint8_t path_list_size;
1641
1642 /* Init list */
1643 lwm2m_engine_path_list_init(&path_list, &free_list, path_list_buf,
1644 CONFIG_LWM2M_COMPOSITE_PATH_LIST_SIZE);
1645
1646 /* Parse Path's from SenML JSO payload */
1647 path_list_size = json_parse_composite_read_paths(msg, &path_list, &free_list);
1648 if (path_list_size == 0) {
1649 LOG_ERR("No Valid Url at msg");
1650 return -ESRCH;
1651 }
1652
1653 /* Clear path which are part are part of recursive path /1 will include /1/0/1 */
1654 lwm2m_engine_clear_duplicate_path(&path_list, &free_list);
1655
1656 return do_composite_read_op_for_parsed_list(msg, LWM2M_FORMAT_APP_SEML_JSON, &path_list);
1657 }
1658
do_send_op_senml_json(struct lwm2m_message * msg,sys_slist_t * lwm2m_path_list)1659 int do_send_op_senml_json(struct lwm2m_message *msg, sys_slist_t *lwm2m_path_list)
1660 {
1661 struct json_out_formatter_data fd;
1662 int ret;
1663
1664 (void)memset(&fd, 0, sizeof(fd));
1665 engine_set_out_user_data(&msg->out, &fd);
1666
1667 ret = lwm2m_perform_composite_read_op(msg, LWM2M_FORMAT_APP_SEML_JSON, lwm2m_path_list);
1668 engine_clear_out_user_data(&msg->out);
1669
1670 return ret;
1671 }
1672
do_composite_observe_parse_path_senml_json(struct lwm2m_message * msg,sys_slist_t * lwm2m_path_list,sys_slist_t * lwm2m_path_free_list)1673 int do_composite_observe_parse_path_senml_json(struct lwm2m_message *msg,
1674 sys_slist_t *lwm2m_path_list,
1675 sys_slist_t *lwm2m_path_free_list)
1676 {
1677 uint8_t list_size;
1678 uint16_t original_offset;
1679
1680 original_offset = msg->in.offset;
1681 /* Parse Path's from SenML JSON payload */
1682 list_size = json_parse_composite_read_paths(msg, lwm2m_path_list, lwm2m_path_free_list);
1683 if (list_size == 0) {
1684 LOG_ERR("No Valid Url at msg");
1685 return -ESRCH;
1686 }
1687
1688 msg->in.offset = original_offset;
1689 return 0;
1690 }
1691