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 * Copyright (c) 2016, Eistec AB.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the copyright holder nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35 * OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Original Authors:
40 * Joakim Nohlgård <joakim.nohlgard@eistec.se>
41 * Joakim Eriksson <joakime@sics.se> added JSON reader parts
42 */
43
44 /*
45 * Zephyr Contribution by Michael Scott <michael.scott@linaro.org>
46 * - Zephyr code style changes / code cleanup
47 * - Move to Zephyr APIs where possible
48 * - Convert to Zephyr int/uint types
49 * - Remove engine dependency (replace with writer/reader context)
50 * - Add write / read int64 functions
51 */
52
53 /*
54 * TODO:
55 * - Debug formatting errors in Leshan
56 * - Replace magic #'s with defines
57 */
58
59 #define LOG_MODULE_NAME net_lwm2m_json
60 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
61
62 #include <zephyr/logging/log.h>
63 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
64
65 #include <stdio.h>
66 #include <stddef.h>
67 #include <stdint.h>
68 #include <inttypes.h>
69 #include <ctype.h>
70 #include <zephyr/data/json.h>
71
72 #include "lwm2m_object.h"
73 #include "lwm2m_rw_json.h"
74 #include "lwm2m_engine.h"
75 #include "lwm2m_util.h"
76
77 struct json_string_payload {
78 const char *name;
79 const char *val_string;
80 };
81
82 struct json_boolean_payload {
83 const char *name;
84 bool val_bool;
85 };
86
87 struct json_float_payload {
88 const char *name;
89 struct json_obj_token val_float;
90 };
91
92 struct json_array_object {
93 union {
94 struct json_float_payload float_obj;
95 struct json_boolean_payload boolean_obj;
96 struct json_string_payload string_obj;
97 } obj;
98 };
99
100 /* Decode payload structure */
101 struct json_context {
102 const char *base_name;
103 struct json_obj_token obj_array;
104 };
105
106 /* Decode description structure for parsing LwM2m JSON main object*/
107 static const struct json_obj_descr json_descr[] = {
108 JSON_OBJ_DESCR_PRIM_NAMED(struct json_context, "bn",
109 base_name, JSON_TOK_STRING),
110 JSON_OBJ_DESCR_PRIM_NAMED(struct json_context, "e",
111 obj_array, JSON_TOK_OBJ_ARRAY),
112 };
113
114 #define JSON_BN_TYPE 1
115 #define JSON_E_TYPE 2
116
117 /* Decode payload structure */
118 struct json_obj_struct {
119 const char *name;
120 char *val_object_link;
121 const char *val_string;
122 struct json_obj_token val_float;
123 bool val_bool;
124 };
125
126 /* Decode description structure for parsing LwM2m JSON Array object*/
127 static const struct json_obj_descr json_obj_descr[] = {
128 JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "n",
129 name, JSON_TOK_STRING),
130 JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "v",
131 val_float, JSON_TOK_FLOAT),
132 JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "bv",
133 val_bool, JSON_TOK_TRUE),
134 JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "ov",
135 val_object_link, JSON_TOK_STRING),
136 JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "sv",
137 val_string, JSON_TOK_STRING),
138 };
139
140 #define JSON_N_TYPE 1
141 #define JSON_V_TYPE 2
142 #define JSON_BV_TYPE 4
143 #define JSON_OV_TYPE 8
144 #define JSON_SV_TYPE 16
145
146 #define JSON_NAME_MASK (JSON_N_TYPE)
147 #define JSON_VAL_MASK (JSON_V_TYPE + JSON_BV_TYPE + JSON_OV_TYPE + JSON_SV_TYPE)
148
149 static const struct json_obj_descr json_float_descr[] = {
150 JSON_OBJ_DESCR_PRIM_NAMED(struct json_float_payload, "n",
151 name, JSON_TOK_STRING),
152 JSON_OBJ_DESCR_PRIM_NAMED(struct json_float_payload, "v",
153 val_float, JSON_TOK_FLOAT),
154 };
155
156 static const struct json_obj_descr json_boolean_descr[] = {
157 JSON_OBJ_DESCR_PRIM_NAMED(struct json_boolean_payload, "n",
158 name, JSON_TOK_STRING),
159 JSON_OBJ_DESCR_PRIM_NAMED(struct json_boolean_payload, "bv",
160 val_bool, JSON_TOK_TRUE),
161 };
162
163 static const struct json_obj_descr json_obj_lnk_descr[] = {
164 JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "n",
165 name, JSON_TOK_STRING),
166 JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "ov",
167 val_string, JSON_TOK_STRING),
168 };
169
170 static const struct json_obj_descr json_string_descr[] = {
171 JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "n",
172 name, JSON_TOK_STRING),
173 JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "sv",
174 val_string, JSON_TOK_STRING),
175 };
176
177 struct json_out_formatter_data {
178 uint8_t writer_flags;
179 char name_string[sizeof("/65535/65535/") + 1];
180 struct json_array_object json;
181 struct lwm2m_output_context *out;
182 };
183
184 struct json_in_formatter_data {
185 uint8_t json_flags;
186 int object_bit_field;
187 struct json_obj_struct array_object;
188 };
189
190 /* some temporary buffer space for format conversions */
191 static char pt_buffer[42];
192
init_object_name_parameters(struct json_out_formatter_data * fd,struct lwm2m_obj_path * path)193 static int init_object_name_parameters(struct json_out_formatter_data *fd,
194 struct lwm2m_obj_path *path)
195 {
196 int ret;
197
198 /* Init Name string */
199 if (fd->writer_flags & WRITER_RESOURCE_INSTANCE) {
200 ret = snprintk(fd->name_string, sizeof(fd->name_string), "%u/%u", path->res_id,
201 path->res_inst_id);
202 } else {
203 ret = snprintk(fd->name_string, sizeof(fd->name_string), "%u", path->res_id);
204 }
205
206 if (ret < 0) {
207 return ret;
208 }
209
210 return 0;
211 }
212
number_to_string(const char * format,...)213 static int number_to_string(const char *format, ...)
214 {
215 va_list vargs;
216 int n;
217
218 va_start(vargs, format);
219 n = vsnprintk(pt_buffer, sizeof(pt_buffer), format, vargs);
220 va_end(vargs);
221 if (n < 0 || n >= sizeof(pt_buffer)) {
222 return -EINVAL;
223 }
224
225 return n;
226 }
227
float_to_string(double * value)228 static int float_to_string(double *value)
229 {
230 int len;
231
232 len = lwm2m_ftoa(value, pt_buffer, sizeof(pt_buffer), 15);
233 if (len < 0 || len >= sizeof(pt_buffer)) {
234 LOG_ERR("Failed to encode float value");
235 return -EINVAL;
236 }
237
238 return len;
239 }
240
objlnk_to_string(struct lwm2m_objlnk * value)241 static int objlnk_to_string(struct lwm2m_objlnk *value)
242 {
243 return snprintk(pt_buffer, sizeof(pt_buffer), "%u:%u", value->obj_id, value->obj_inst);
244 }
245
json_add_separator(struct lwm2m_output_context * out,struct json_out_formatter_data * fd)246 static int json_add_separator(struct lwm2m_output_context *out, struct json_out_formatter_data *fd)
247 {
248 int len = 0;
249
250 if (fd->writer_flags & WRITER_OUTPUT_VALUE) {
251 /* Add separator */
252 char separator = ',';
253
254 len = buf_append(CPKT_BUF_WRITE(out->out_cpkt), &separator, sizeof(separator));
255 if (len < 0) {
256 return -ENOMEM;
257 }
258 }
259
260 return len;
261 }
262
json_postprefix(struct json_out_formatter_data * fd)263 static void json_postprefix(struct json_out_formatter_data *fd)
264 {
265 fd->writer_flags |= WRITER_OUTPUT_VALUE;
266 }
267
json_float_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,int float_string_length)268 static int json_float_object_write(struct lwm2m_output_context *out,
269 struct json_out_formatter_data *fd, int float_string_length)
270 {
271 int res, len;
272 ssize_t o_len;
273 const struct json_obj_descr *descr;
274 size_t descr_len;
275 void *obj_payload;
276
277 len = json_add_separator(out, fd);
278 if (len < 0) {
279 return len;
280 }
281
282 descr = json_float_descr;
283 descr_len = ARRAY_SIZE(json_float_descr);
284 obj_payload = &fd->json.obj.float_obj;
285 fd->json.obj.float_obj.name = fd->name_string;
286 fd->json.obj.float_obj.val_float.start = pt_buffer;
287 fd->json.obj.float_obj.val_float.length = float_string_length;
288
289 /* Calculate length */
290 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
291 if (o_len < 0) {
292 return -EINVAL;
293 }
294
295 /* Encode */
296 res = json_obj_encode_buf(descr, descr_len, obj_payload,
297 CPKT_BUF_W_REGION(out->out_cpkt));
298 if (res < 0) {
299 return -ENOMEM;
300 }
301
302 len += o_len;
303 out->out_cpkt->offset += len;
304 json_postprefix(fd);
305 return len;
306 }
307
json_string_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,char * buf)308 static int json_string_object_write(struct lwm2m_output_context *out,
309 struct json_out_formatter_data *fd, char *buf)
310 {
311 int res, len;
312 ssize_t o_len;
313 const struct json_obj_descr *descr;
314 size_t descr_len;
315 void *obj_payload;
316
317 len = json_add_separator(out, fd);
318 if (len < 0) {
319 return len;
320 }
321
322 descr = json_string_descr;
323 descr_len = ARRAY_SIZE(json_string_descr);
324 obj_payload = &fd->json.obj.string_obj;
325 fd->json.obj.string_obj.name = fd->name_string;
326 fd->json.obj.string_obj.val_string = buf;
327
328 /* Calculate length */
329 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
330 if (o_len < 0) {
331 return -EINVAL;
332 }
333
334 /* Encode */
335 res = json_obj_encode_buf(descr, descr_len, obj_payload,
336 CPKT_BUF_W_REGION(out->out_cpkt));
337 if (res < 0) {
338 return -ENOMEM;
339 }
340
341 len += o_len;
342 out->out_cpkt->offset += len;
343 json_postprefix(fd);
344 return len;
345 }
346
json_boolean_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,bool value)347 static int json_boolean_object_write(struct lwm2m_output_context *out,
348 struct json_out_formatter_data *fd, bool value)
349 {
350 int res, len;
351 ssize_t o_len;
352 const struct json_obj_descr *descr;
353 size_t descr_len;
354 void *obj_payload;
355
356 len = json_add_separator(out, fd);
357 if (len < 0) {
358 return len;
359 }
360
361 descr = json_boolean_descr;
362 descr_len = ARRAY_SIZE(json_boolean_descr);
363 obj_payload = &fd->json.obj.boolean_obj;
364 fd->json.obj.boolean_obj.name = fd->name_string;
365 fd->json.obj.boolean_obj.val_bool = value;
366
367 /* Calculate length */
368 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
369 if (o_len < 0) {
370 return -EINVAL;
371 }
372
373 /* Encode */
374 res = json_obj_encode_buf(descr, descr_len, obj_payload,
375 CPKT_BUF_W_REGION(out->out_cpkt));
376 if (res < 0) {
377 return -ENOMEM;
378 }
379
380 len += o_len;
381 out->out_cpkt->offset += len;
382 json_postprefix(fd);
383 return len;
384 }
385
json_objlnk_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd)386 static int json_objlnk_object_write(struct lwm2m_output_context *out,
387 struct json_out_formatter_data *fd)
388 {
389 int res, len;
390 ssize_t o_len;
391 const struct json_obj_descr *descr;
392 size_t descr_len;
393 void *obj_payload;
394
395 len = json_add_separator(out, fd);
396 if (len < 0) {
397 return len;
398 }
399
400 descr = json_obj_lnk_descr;
401 descr_len = ARRAY_SIZE(json_obj_lnk_descr);
402 obj_payload = &fd->json.obj.string_obj;
403 fd->json.obj.string_obj.name = fd->name_string;
404 fd->json.obj.string_obj.val_string = pt_buffer;
405
406 /* Calculate length */
407 o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
408 if (o_len < 0) {
409 return -EINVAL;
410 }
411
412 /* Encode */
413 res = json_obj_encode_buf(descr, descr_len, obj_payload,
414 CPKT_BUF_W_REGION(out->out_cpkt));
415 if (res < 0) {
416 return -ENOMEM;
417 }
418
419 len += o_len;
420 out->out_cpkt->offset += len;
421 json_postprefix(fd);
422 return len;
423 }
424
put_begin(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)425 static int put_begin(struct lwm2m_output_context *out,
426 struct lwm2m_obj_path *path)
427 {
428 int len = -1, res;
429
430 if (path->level >= 2U) {
431 len = snprintk(pt_buffer, sizeof(pt_buffer),
432 "{\"bn\":\"/%u/%u/\",\"e\":[",
433 path->obj_id, path->obj_inst_id);
434 } else {
435 len = snprintk(pt_buffer, sizeof(pt_buffer),
436 "{\"bn\":\"/%u/\",\"e\":[",
437 path->obj_id);
438 }
439
440 if (len < 0) {
441 return len;
442 }
443
444 res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), pt_buffer, len);
445 if (res < 0) {
446 return res;
447 }
448
449 return len;
450 }
451
put_end(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)452 static int put_end(struct lwm2m_output_context *out,
453 struct lwm2m_obj_path *path)
454 {
455 int res;
456
457 res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), "]}", 2);
458 if (res < 0) {
459 return res;
460 }
461
462 return 2;
463 }
464
put_begin_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)465 static int put_begin_ri(struct lwm2m_output_context *out,
466 struct lwm2m_obj_path *path)
467 {
468 struct json_out_formatter_data *fd;
469
470 fd = engine_get_out_user_data(out);
471 if (!fd) {
472 return -EINVAL;
473 }
474
475 fd->writer_flags |= WRITER_RESOURCE_INSTANCE;
476 return 0;
477 }
478
put_end_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)479 static int put_end_ri(struct lwm2m_output_context *out,
480 struct lwm2m_obj_path *path)
481 {
482 struct json_out_formatter_data *fd;
483
484 fd = engine_get_out_user_data(out);
485 if (!fd) {
486 return -EINVAL;
487 }
488
489 fd->writer_flags &= ~WRITER_RESOURCE_INSTANCE;
490 return 0;
491 }
492
put_s32(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int32_t value)493 static int put_s32(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int32_t value)
494 {
495 struct json_out_formatter_data *fd;
496 int len = 0;
497
498 fd = engine_get_out_user_data(out);
499
500 if (!out->out_cpkt || !fd) {
501 return -EINVAL;
502 }
503
504 if (init_object_name_parameters(fd, path)) {
505 return -EINVAL;
506 }
507
508 len = number_to_string("%d", value);
509 if (len < 0) {
510 return len;
511 }
512
513 return json_float_object_write(out, fd, len);
514 }
515
put_s16(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int16_t value)516 static int put_s16(struct lwm2m_output_context *out,
517 struct lwm2m_obj_path *path, int16_t value)
518 {
519 return put_s32(out, path, (int32_t)value);
520 }
521
put_s8(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int8_t value)522 static int put_s8(struct lwm2m_output_context *out, struct lwm2m_obj_path *path,
523 int8_t value)
524 {
525 return put_s32(out, path, (int32_t)value);
526 }
527
put_s64(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int64_t value)528 static int put_s64(struct lwm2m_output_context *out,
529 struct lwm2m_obj_path *path, int64_t value)
530 {
531 struct json_out_formatter_data *fd;
532 int len;
533
534 fd = engine_get_out_user_data(out);
535
536 if (!out->out_cpkt || !fd) {
537 return -EINVAL;
538 }
539
540 if (init_object_name_parameters(fd, path)) {
541 return -EINVAL;
542 }
543
544 len = number_to_string("%lld", value);
545 if (len < 0) {
546 return len;
547 }
548
549 return json_float_object_write(out, fd, len);
550 }
551
put_time(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,time_t value)552 static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, time_t value)
553 {
554 return put_s64(out, path, (int64_t) value);
555 }
556
put_string(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,char * buf,size_t buflen)557 static int put_string(struct lwm2m_output_context *out,
558 struct lwm2m_obj_path *path, char *buf, size_t buflen)
559 {
560 struct json_out_formatter_data *fd;
561
562 fd = engine_get_out_user_data(out);
563
564 if (!out->out_cpkt || !fd) {
565 return -EINVAL;
566 }
567
568 if (init_object_name_parameters(fd, path)) {
569 return -EINVAL;
570 }
571
572 return json_string_object_write(out, fd, buf);
573 }
574
put_float(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,double * value)575 static int put_float(struct lwm2m_output_context *out,
576 struct lwm2m_obj_path *path, double *value)
577 {
578 struct json_out_formatter_data *fd;
579 int len;
580
581 fd = engine_get_out_user_data(out);
582
583 if (!out->out_cpkt || !fd) {
584 return -EINVAL;
585 }
586
587 if (init_object_name_parameters(fd, path)) {
588 return -EINVAL;
589 }
590
591 len = float_to_string(value);
592 if (len < 0) {
593 return len;
594 }
595
596 return json_float_object_write(out, fd, len);
597 }
598
put_bool(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,bool value)599 static int put_bool(struct lwm2m_output_context *out,
600 struct lwm2m_obj_path *path, bool value)
601 {
602 struct json_out_formatter_data *fd;
603
604 fd = engine_get_out_user_data(out);
605
606 if (!out->out_cpkt || !fd) {
607 return -EINVAL;
608 }
609
610 if (init_object_name_parameters(fd, path)) {
611 return -EINVAL;
612 }
613
614 return json_boolean_object_write(out, fd, value);
615 }
616
put_objlnk(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,struct lwm2m_objlnk * value)617 static int put_objlnk(struct lwm2m_output_context *out,
618 struct lwm2m_obj_path *path, struct lwm2m_objlnk *value)
619 {
620 struct json_out_formatter_data *fd;
621
622 fd = engine_get_out_user_data(out);
623
624 if (!out->out_cpkt || !fd) {
625 return -EINVAL;
626 }
627
628 if (init_object_name_parameters(fd, path)) {
629 return -EINVAL;
630 }
631
632 if (objlnk_to_string(value) < 0) {
633 return -EINVAL;
634 }
635
636 return json_objlnk_object_write(out, fd);
637 }
638
read_int(struct lwm2m_input_context * in,int64_t * value,bool accept_sign)639 static int read_int(struct lwm2m_input_context *in, int64_t *value,
640 bool accept_sign)
641 {
642 struct json_in_formatter_data *fd;
643 uint64_t temp;
644 uint8_t *buf;
645 int i = 0;
646 bool neg = false;
647 char c;
648
649 /* initialize values to 0 */
650 temp = 0;
651
652 fd = engine_get_in_user_data(in);
653 if (!fd || (fd->object_bit_field & JSON_V_TYPE) == 0) {
654 return -EINVAL;
655 }
656
657 if (fd->array_object.val_float.length == 0) {
658 return -ENODATA;
659 }
660
661 buf = fd->array_object.val_float.start;
662 while (*(buf + i) && i < fd->array_object.val_float.length) {
663 c = *(buf + i);
664 if (c == '-' && accept_sign && i == 0) {
665 neg = true;
666 } else if (isdigit(c) != 0) {
667 temp = temp * 10ULL + (c - '0');
668 if (temp > ((uint64_t)INT64_MAX + (neg ? 1ULL : 0ULL))) {
669 return -EINVAL;
670 }
671 } else {
672 /* anything else stop reading */
673 break;
674 }
675 i++;
676 }
677
678 *value = neg ? -temp : temp;
679
680 return i;
681 }
682
get_s64(struct lwm2m_input_context * in,int64_t * value)683 static int get_s64(struct lwm2m_input_context *in, int64_t *value)
684 {
685 return read_int(in, value, true);
686 }
687
get_time(struct lwm2m_input_context * in,time_t * value)688 static int get_time(struct lwm2m_input_context *in, time_t *value)
689 {
690 int64_t temp64;
691 int ret;
692
693 ret = read_int(in, &temp64, true);
694 *value = (time_t)temp64;
695
696 return ret;
697 }
698
get_s32(struct lwm2m_input_context * in,int32_t * value)699 static int get_s32(struct lwm2m_input_context *in, int32_t *value)
700 {
701 int64_t tmp = 0;
702 int len = 0;
703
704 len = read_int(in, &tmp, true);
705 if (len > 0) {
706 *value = (int32_t)tmp;
707 }
708
709 return len;
710 }
711
get_string(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen)712 static int get_string(struct lwm2m_input_context *in, uint8_t *buf,
713 size_t buflen)
714 {
715 struct json_in_formatter_data *fd;
716 size_t string_length;
717
718 fd = engine_get_in_user_data(in);
719 if (!fd || (fd->object_bit_field & JSON_SV_TYPE) == 0) {
720 return -EINVAL;
721 }
722
723 string_length = strlen(fd->array_object.val_string);
724
725 if (string_length > buflen) {
726 LOG_WRN("Buffer too small to accommodate string");
727 return -ENOMEM;
728 }
729 memcpy(buf, fd->array_object.val_string, string_length);
730
731 /* add NULL */
732 buf[string_length] = '\0';
733
734 return string_length;
735 }
736
get_float(struct lwm2m_input_context * in,double * value)737 static int get_float(struct lwm2m_input_context *in, double *value)
738 {
739 struct json_in_formatter_data *fd;
740
741 int i = 0, len = 0;
742 bool has_dot = false;
743 uint8_t tmp, buf[24];
744 uint8_t *json_buf;
745
746 fd = engine_get_in_user_data(in);
747 if (!fd || (fd->object_bit_field & JSON_V_TYPE) == 0) {
748 return -EINVAL;
749 }
750
751 size_t value_length = fd->array_object.val_float.length;
752
753 if (value_length == 0) {
754 return -ENODATA;
755 }
756
757 json_buf = fd->array_object.val_float.start;
758 while (*(json_buf + len) && len < value_length) {
759 tmp = *(json_buf + len);
760
761 if ((tmp == '-' && i == 0) || (tmp == '.' && !has_dot) ||
762 isdigit(tmp) != 0) {
763 len++;
764
765 /* Copy only if it fits into provided buffer - we won't
766 * get better precision anyway.
767 */
768 if (i < sizeof(buf) - 1) {
769 buf[i++] = tmp;
770 }
771
772 if (tmp == '.') {
773 has_dot = true;
774 }
775 } else {
776 break;
777 }
778 }
779
780 buf[i] = '\0';
781
782 if (lwm2m_atof(buf, value) != 0) {
783 LOG_ERR("Failed to parse float value");
784 return -EBADMSG;
785 }
786
787 return len;
788 }
789
get_bool(struct lwm2m_input_context * in,bool * value)790 static int get_bool(struct lwm2m_input_context *in, bool *value)
791 {
792 struct json_in_formatter_data *fd;
793
794 fd = engine_get_in_user_data(in);
795 if (!fd || (fd->object_bit_field & JSON_BV_TYPE) == 0) {
796 return -EINVAL;
797 }
798
799 *value = fd->array_object.val_bool;
800
801 return 1;
802 }
803
get_opaque(struct lwm2m_input_context * in,uint8_t * value,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)804 static int get_opaque(struct lwm2m_input_context *in, uint8_t *value,
805 size_t buflen, struct lwm2m_opaque_context *opaque,
806 bool *last_block)
807 {
808 /* TODO */
809 return -EOPNOTSUPP;
810 }
811
get_objlnk(struct lwm2m_input_context * in,struct lwm2m_objlnk * value)812 static int get_objlnk(struct lwm2m_input_context *in,
813 struct lwm2m_objlnk *value)
814 {
815 int64_t tmp;
816 int len, total_len;
817 struct json_in_formatter_data *fd;
818 char *demiliter_pos;
819
820 fd = engine_get_in_user_data(in);
821 if (!fd || (fd->object_bit_field & JSON_OV_TYPE) == 0) {
822 return -EINVAL;
823 }
824
825 demiliter_pos = strchr(fd->array_object.val_object_link, ':');
826 if (!demiliter_pos) {
827 return -ENODATA;
828 }
829
830 fd->object_bit_field |= JSON_V_TYPE;
831 fd->array_object.val_float.start = fd->array_object.val_object_link;
832 fd->array_object.val_float.length = strlen(fd->array_object.val_object_link);
833
834 /* Set String end for first item */
835 *demiliter_pos = '\0';
836
837 len = read_int(in, &tmp, false);
838 if (len <= 0) {
839 return -ENODATA;
840 }
841
842 total_len = len;
843 value->obj_id = (uint16_t)tmp;
844
845 len++; /* +1 for ':' delimiter. */
846 demiliter_pos++;
847 fd->array_object.val_float.start = demiliter_pos;
848 fd->array_object.val_float.length = strlen(demiliter_pos);
849
850 len = read_int(in, &tmp, false);
851 if (len <= 0) {
852 return -ENODATA;
853 }
854
855 total_len += len;
856 value->obj_inst = (uint16_t)tmp;
857
858 return total_len;
859 }
860
861 const struct lwm2m_writer json_writer = {
862 .put_begin = put_begin,
863 .put_end = put_end,
864 .put_begin_ri = put_begin_ri,
865 .put_end_ri = put_end_ri,
866 .put_s8 = put_s8,
867 .put_s16 = put_s16,
868 .put_s32 = put_s32,
869 .put_s64 = put_s64,
870 .put_string = put_string,
871 .put_float = put_float,
872 .put_time = put_time,
873 .put_bool = put_bool,
874 .put_objlnk = put_objlnk,
875 };
876
877 const struct lwm2m_reader json_reader = {
878 .get_s32 = get_s32,
879 .get_s64 = get_s64,
880 .get_string = get_string,
881 .get_time = get_time,
882 .get_float = get_float,
883 .get_bool = get_bool,
884 .get_opaque = get_opaque,
885 .get_objlnk = get_objlnk,
886 };
887
do_read_op_json(struct lwm2m_message * msg,int content_format)888 int do_read_op_json(struct lwm2m_message *msg, int content_format)
889 {
890 struct json_out_formatter_data fd;
891 int ret;
892
893 (void)memset(&fd, 0, sizeof(fd));
894 engine_set_out_user_data(&msg->out, &fd);
895 ret = lwm2m_perform_read_op(msg, content_format);
896 engine_clear_out_user_data(&msg->out);
897
898 return ret;
899 }
900
do_write_op_json(struct lwm2m_message * msg)901 int do_write_op_json(struct lwm2m_message *msg)
902 {
903 struct lwm2m_engine_obj_field *obj_field = NULL;
904 struct lwm2m_engine_obj_inst *obj_inst = NULL;
905 struct lwm2m_engine_res *res = NULL;
906 struct lwm2m_engine_res_inst *res_inst = NULL;
907 struct lwm2m_obj_path orig_path;
908 struct json_in_formatter_data fd;
909 struct json_obj json_object;
910 struct json_context main_object;
911
912 char *data_ptr;
913 const char *base_name_ptr = NULL;
914 uint16_t in_len;
915 int ret = 0, obj_bit_field;
916
917 uint8_t full_name[MAX_RESOURCE_LEN + 1] = {0};
918 uint8_t created;
919
920 (void)memset(&fd, 0, sizeof(fd));
921 (void)memset(&main_object, 0, sizeof(main_object));
922 engine_set_in_user_data(&msg->in, &fd);
923
924 data_ptr = (char *)coap_packet_get_payload(msg->in.in_cpkt, &in_len);
925
926 obj_bit_field =
927 json_obj_parse(data_ptr, in_len, json_descr, ARRAY_SIZE(json_descr), &main_object);
928
929 if (obj_bit_field < 0 || (obj_bit_field & 2) == 0 || main_object.obj_array.length == 0) {
930 LOG_ERR("JSON object bits not valid %d", obj_bit_field);
931 ret = -EINVAL;
932 goto end_of_operation;
933 }
934
935 if (obj_bit_field & 1) {
936 base_name_ptr = main_object.base_name;
937 }
938
939 /* store a copy of the original path */
940 memcpy(&orig_path, &msg->path, sizeof(msg->path));
941
942 /* When No blockwise do Normal Init */
943 if (json_arr_separate_object_parse_init(&json_object, main_object.obj_array.start,
944 main_object.obj_array.length)) {
945 ret = -EINVAL;
946 goto end_of_operation;
947 }
948
949 while (1) {
950 (void)memset(&fd.array_object, 0, sizeof(fd.array_object));
951 fd.object_bit_field = json_arr_separate_parse_object(
952 &json_object, json_obj_descr, ARRAY_SIZE(json_obj_descr), &fd.array_object);
953 if (fd.object_bit_field == 0) {
954 /* End of */
955 break;
956 } else if (fd.object_bit_field < 0 ||
957 ((fd.object_bit_field & JSON_VAL_MASK) == 0)) {
958 LOG_ERR("Json Write Parse object fail %d", fd.object_bit_field);
959 ret = -EINVAL;
960 goto end_of_operation;
961 }
962
963 /* Create object resource path */
964 if (base_name_ptr) {
965 if (fd.object_bit_field & JSON_N_TYPE) {
966 ret = snprintk(full_name, sizeof(full_name), "%s%s", base_name_ptr,
967 fd.array_object.name);
968 } else {
969 ret = snprintk(full_name, sizeof(full_name), "%s", base_name_ptr);
970 }
971 } else {
972 if ((fd.object_bit_field & JSON_N_TYPE) == 0) {
973 ret = -EINVAL;
974 goto end_of_operation;
975 }
976 ret = snprintk(full_name, sizeof(full_name), "%s", fd.array_object.name);
977 }
978
979 if (ret >= MAX_RESOURCE_LEN) {
980 ret = -EINVAL;
981 goto end_of_operation;
982 }
983
984 /* handle resource value */
985 /* reset values */
986 created = 0U;
987
988 /* parse full_name into path */
989 ret = lwm2m_string_to_path(full_name, &msg->path, '/');
990 if (ret < 0) {
991 LOG_ERR("Relative name too long");
992 ret = -EINVAL;
993 goto end_of_operation;
994 }
995
996 ret = lwm2m_get_or_create_engine_obj(msg, &obj_inst, &created);
997 if (ret < 0) {
998 break;
999 }
1000
1001 ret = lwm2m_engine_validate_write_access(msg, obj_inst, &obj_field);
1002 if (ret < 0) {
1003 return ret;
1004 }
1005
1006 ret = lwm2m_engine_get_create_res_inst(&msg->path, &res, &res_inst);
1007 if (ret < 0) {
1008 return -ENOENT;
1009 }
1010
1011 /* Write the resource value */
1012 ret = lwm2m_write_handler(obj_inst, res, res_inst, obj_field, msg);
1013 if (orig_path.level >= 3U && ret < 0) {
1014 /* return errors on a single write */
1015 break;
1016 }
1017 }
1018
1019 end_of_operation:
1020 engine_clear_in_user_data(&msg->in);
1021
1022 return ret;
1023 }
1024