1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include "cborattr/cborattr.h"
21 #include "tinycbor/cbor.h"
22 #include "tinycbor/cbor_buf_reader.h"
23
24 #ifdef __ZEPHYR__
25 #include <zephyr.h>
26 #ifdef CONFIG_MGMT_CBORATTR_MAX_SIZE
27 #define CBORATTR_MAX_SIZE CONFIG_MGMT_CBORATTR_MAX_SIZE
28 #else
29 #define CBORATTR_MAX_SIZE 512
30 #endif
31 #endif
32
33 #ifdef MYNEWT
34 #include "syscfg/syscfg.h"
35 #include "tinycbor/cbor_mbuf_reader.h"
36 #include "tinycbor/cbor_mbuf_writer.h"
37 #include "os/os_mbuf.h"
38 #define CBORATTR_MAX_SIZE MYNEWT_VAL(CBORATTR_MAX_SIZE)
39 #endif
40
41 /* this maps a CborType to a matching CborAtter Type. The mapping is not
42 * one-to-one because of signedness of integers
43 * and therefore we need a function to do this trickery */
44 static int
valid_attr_type(CborType ct,CborAttrType at)45 valid_attr_type(CborType ct, CborAttrType at)
46 {
47 switch (at) {
48 case CborAttrIntegerType:
49 case CborAttrUnsignedIntegerType:
50 if (ct == CborIntegerType) {
51 return 1;
52 }
53 break;
54 case CborAttrByteStringType:
55 if (ct == CborByteStringType) {
56 return 1;
57 }
58 break;
59 case CborAttrTextStringType:
60 if (ct == CborTextStringType) {
61 return 1;
62 }
63 break;
64 case CborAttrBooleanType:
65 if (ct == CborBooleanType) {
66 return 1;
67 }
68 break;
69 #if FLOAT_SUPPORT
70 case CborAttrHalfFloatType:
71 if (ct == CborHalfFloatType) {
72 return 1;
73 }
74 break;
75 case CborAttrFloatType:
76 if (ct == CborFloatType) {
77 return 1;
78 }
79 break;
80 case CborAttrDoubleType:
81 if (ct == CborDoubleType) {
82 return 1;
83 }
84 break;
85 #endif
86 case CborAttrArrayType:
87 if (ct == CborArrayType) {
88 return 1;
89 }
90 break;
91 case CborAttrObjectType:
92 if (ct == CborMapType) {
93 return 1;
94 }
95 break;
96 case CborAttrNullType:
97 if (ct == CborNullType) {
98 return 1;
99 }
100 break;
101 default:
102 break;
103 }
104 return 0;
105 }
106
107 /* this function find the pointer to the memory location to
108 * write or read and attribute from the cbor_attr_r structure */
109 static char *
cbor_target_address(const struct cbor_attr_t * cursor,const struct cbor_array_t * parent,int offset)110 cbor_target_address(const struct cbor_attr_t *cursor,
111 const struct cbor_array_t *parent, int offset)
112 {
113 char *targetaddr = NULL;
114
115 if (parent == NULL || parent->element_type != CborAttrStructObjectType) {
116 /* ordinary case - use the address in the cursor structure */
117 switch (cursor->type) {
118 case CborAttrNullType:
119 targetaddr = NULL;
120 break;
121 case CborAttrIntegerType:
122 targetaddr = (char *)&cursor->addr.integer[offset];
123 break;
124 case CborAttrUnsignedIntegerType:
125 targetaddr = (char *)&cursor->addr.uinteger[offset];
126 break;
127 #if FLOAT_SUPPORT
128 case CborAttrHalfFloatType:
129 targetaddr = (char *)&cursor->addr.halffloat[offset];
130 break;
131 case CborAttrFloatType:
132 targetaddr = (char *)&cursor->addr.fval[offset];
133 break;
134 case CborAttrDoubleType:
135 targetaddr = (char *)&cursor->addr.real[offset];
136 break;
137 #endif
138 case CborAttrByteStringType:
139 targetaddr = (char *) cursor->addr.bytestring.data;
140 break;
141 case CborAttrTextStringType:
142 targetaddr = cursor->addr.string;
143 break;
144 case CborAttrBooleanType:
145 targetaddr = (char *)&cursor->addr.boolean[offset];
146 break;
147 default:
148 targetaddr = NULL;
149 break;
150 }
151 } else {
152 /* tricky case - hacking a member in an array of structures */
153 targetaddr =
154 parent->arr.objects.base + (offset * parent->arr.objects.stride) +
155 cursor->addr.offset;
156 }
157 return targetaddr;
158 }
159
160 static int
cbor_internal_read_object(CborValue * root_value,const struct cbor_attr_t * attrs,const struct cbor_array_t * parent,int offset)161 cbor_internal_read_object(CborValue *root_value,
162 const struct cbor_attr_t *attrs,
163 const struct cbor_array_t *parent,
164 int offset)
165 {
166 const struct cbor_attr_t *cursor, *best_match;
167 char attrbuf[CBORATTR_MAX_SIZE + 1];
168 void *lptr;
169 CborValue cur_value;
170 CborError err = 0;
171 size_t len = 0;
172 CborType type = CborInvalidType;
173
174 /* stuff fields with defaults in case they're omitted in the JSON input */
175 for (cursor = attrs; cursor->attribute != NULL; cursor++) {
176 if (!cursor->nodefault) {
177 lptr = cbor_target_address(cursor, parent, offset);
178 if (lptr != NULL) {
179 switch (cursor->type) {
180 case CborAttrIntegerType:
181 memcpy(lptr, &cursor->dflt.integer, sizeof(long long int));
182 break;
183 case CborAttrUnsignedIntegerType:
184 memcpy(lptr, &cursor->dflt.integer,
185 sizeof(long long unsigned int));
186 break;
187 case CborAttrBooleanType:
188 memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
189 break;
190 #if FLOAT_SUPPORT
191 case CborAttrHalfFloatType:
192 memcpy(lptr, &cursor->dflt.halffloat, sizeof(uint16_t));
193 break;
194 case CborAttrFloatType:
195 memcpy(lptr, &cursor->dflt.fval, sizeof(float));
196 break;
197 case CborAttrDoubleType:
198 memcpy(lptr, &cursor->dflt.real, sizeof(double));
199 break;
200 #endif
201 default:
202 break;
203 }
204 }
205 }
206 }
207
208 if (cbor_value_is_map(root_value)) {
209 err |= cbor_value_enter_container(root_value, &cur_value);
210 } else {
211 err |= CborErrorIllegalType;
212 return err;
213 }
214
215 /* contains key value pairs */
216 while (cbor_value_is_valid(&cur_value) && !err) {
217 /* get the attribute */
218 if (cbor_value_is_text_string(&cur_value)) {
219 if (cbor_value_calculate_string_length(&cur_value, &len) == 0) {
220 if (len > CBORATTR_MAX_SIZE) {
221 err |= CborErrorDataTooLarge;
222 break;
223 }
224 err |= cbor_value_copy_text_string(&cur_value, attrbuf, &len,
225 NULL);
226 }
227
228 /* at least get the type of the next value so we can match the
229 * attribute name and type for a perfect match */
230 err |= cbor_value_advance(&cur_value);
231 if (cbor_value_is_valid(&cur_value)) {
232 type = cbor_value_get_type(&cur_value);
233 } else {
234 err |= CborErrorIllegalType;
235 break;
236 }
237 } else {
238 attrbuf[0] = '\0';
239 type = cbor_value_get_type(&cur_value);
240 }
241
242 /* find this attribute in our list */
243 best_match = NULL;
244 for (cursor = attrs; cursor->attribute != NULL; cursor++) {
245 if (valid_attr_type(type, cursor->type)) {
246 if (cursor->attribute == CBORATTR_ATTR_UNNAMED &&
247 attrbuf[0] == '\0') {
248 best_match = cursor;
249 } else if (strlen(cursor->attribute) == len &&
250 !memcmp(cursor->attribute, attrbuf, len)) {
251 break;
252 }
253 }
254 }
255 if (!cursor->attribute && best_match) {
256 cursor = best_match;
257 }
258 /* we found a match */
259 if (cursor->attribute != NULL) {
260 lptr = cbor_target_address(cursor, parent, offset);
261 switch (cursor->type) {
262 case CborAttrNullType:
263 /* nothing to do */
264 break;
265 case CborAttrBooleanType:
266 err |= cbor_value_get_boolean(&cur_value, lptr);
267 break;
268 case CborAttrIntegerType:
269 err |= cbor_value_get_int64(&cur_value, lptr);
270 break;
271 case CborAttrUnsignedIntegerType:
272 err |= cbor_value_get_uint64(&cur_value, lptr);
273 break;
274 #if FLOAT_SUPPORT
275 case CborAttrHalfFloatType:
276 err |= cbor_value_get_half_float(&cur_value, lptr);
277 break;
278 case CborAttrFloatType:
279 err |= cbor_value_get_float(&cur_value, lptr);
280 break;
281 case CborAttrDoubleType:
282 err |= cbor_value_get_double(&cur_value, lptr);
283 break;
284 #endif
285 case CborAttrByteStringType: {
286 size_t len = cursor->len;
287 err |= cbor_value_copy_byte_string(&cur_value, lptr,
288 &len, NULL);
289 *cursor->addr.bytestring.len = len;
290 break;
291 }
292 case CborAttrTextStringType: {
293 size_t len = cursor->len;
294 err |= cbor_value_copy_text_string(&cur_value, lptr,
295 &len, NULL);
296 break;
297 }
298 case CborAttrArrayType:
299 err |= cbor_read_array(&cur_value, &cursor->addr.array);
300 continue;
301 case CborAttrObjectType:
302 err |= cbor_internal_read_object(&cur_value, cursor->addr.obj,
303 NULL, 0);
304 continue;
305 default:
306 err |= CborErrorIllegalType;
307 }
308 }
309 cbor_value_advance(&cur_value);
310 }
311 if (!err) {
312 /* that should be it for this container */
313 err |= cbor_value_leave_container(root_value, &cur_value);
314 }
315 return err;
316 }
317
318 int
cbor_read_array(struct CborValue * value,const struct cbor_array_t * arr)319 cbor_read_array(struct CborValue *value, const struct cbor_array_t *arr)
320 {
321 CborError err = 0;
322 struct CborValue elem;
323 int off, arrcount;
324 size_t len;
325 void *lptr;
326 char *tp;
327
328 err = cbor_value_enter_container(value, &elem);
329 if (err) {
330 return err;
331 }
332 arrcount = 0;
333 tp = arr->arr.strings.store;
334 for (off = 0; off < arr->maxlen; off++) {
335 switch (arr->element_type) {
336 case CborAttrBooleanType:
337 lptr = &arr->arr.booleans.store[off];
338 err |= cbor_value_get_boolean(&elem, lptr);
339 break;
340 case CborAttrIntegerType:
341 lptr = &arr->arr.integers.store[off];
342 err |= cbor_value_get_int64(&elem, lptr);
343 break;
344 case CborAttrUnsignedIntegerType:
345 lptr = &arr->arr.uintegers.store[off];
346 err |= cbor_value_get_uint64(&elem, lptr);
347 break;
348 #if FLOAT_SUPPORT
349 case CborAttrHalfFloatType:
350 lptr = &arr->arr.halffloats.store[off];
351 err |= cbor_value_get_half_float(&elem, lptr);
352 break;
353 case CborAttrFloatType:
354 case CborAttrDoubleType:
355 lptr = &arr->arr.reals.store[off];
356 err |= cbor_value_get_double(&elem, lptr);
357 break;
358 #endif
359 case CborAttrTextStringType:
360 len = arr->arr.strings.storelen - (tp - arr->arr.strings.store);
361 err |= cbor_value_copy_text_string(&elem, tp, &len, NULL);
362 arr->arr.strings.ptrs[off] = tp;
363 tp += len + 1;
364 break;
365 case CborAttrStructObjectType:
366 err |= cbor_internal_read_object(&elem, arr->arr.objects.subtype,
367 arr, off);
368 break;
369 default:
370 err |= CborErrorIllegalType;
371 break;
372 }
373 arrcount++;
374 if (arr->element_type != CborAttrStructObjectType) {
375 err |= cbor_value_advance(&elem);
376 }
377 if (!cbor_value_is_valid(&elem)) {
378 break;
379 }
380 }
381 if (arr->count) {
382 *arr->count = arrcount;
383 }
384 while (!cbor_value_at_end(&elem)) {
385 err |= CborErrorDataTooLarge;
386 cbor_value_advance(&elem);
387 }
388 err |= cbor_value_leave_container(value, &elem);
389 return err;
390 }
391
392 int
cbor_read_object(struct CborValue * value,const struct cbor_attr_t * attrs)393 cbor_read_object(struct CborValue *value, const struct cbor_attr_t *attrs)
394 {
395 int st;
396
397 st = cbor_internal_read_object(value, attrs, NULL, 0);
398 return st;
399 }
400
401 /*
402 * Read in cbor key/values from flat buffer pointed by data, and fill them
403 * into attrs.
404 *
405 * @param data Pointer to beginning of cbor encoded data
406 * @param len Number of bytes in the buffer
407 * @param attrs Array of cbor objects to look for.
408 *
409 * @return 0 on success; non-zero on failure.
410 */
411 int
cbor_read_flat_attrs(const uint8_t * data,int len,const struct cbor_attr_t * attrs)412 cbor_read_flat_attrs(const uint8_t *data, int len,
413 const struct cbor_attr_t *attrs)
414 {
415 struct cbor_buf_reader reader;
416 struct CborParser parser;
417 struct CborValue value;
418 CborError err;
419
420 cbor_buf_reader_init(&reader, data, len);
421 err = cbor_parser_init(&reader.r, 0, &parser, &value);
422 if (err != CborNoError) {
423 return -1;
424 }
425 return cbor_read_object(&value, attrs);
426 }
427
428 #ifdef MYNEWT
429 static int cbor_write_val(struct CborEncoder *enc,
430 const struct cbor_out_val_t *val);
431
432 /*
433 * Read in cbor key/values from os_mbuf pointed by m, and fill them
434 * into attrs.
435 *
436 * @param m Pointer to os_mbuf containing cbor encoded data
437 * @param off Offset into mbuf where cbor data begins
438 * @param len Number of bytes to decode
439 * @param attrs Array of cbor objects to look for.
440 *
441 * @return 0 on success; non-zero on failure.
442 */
443 int
cbor_read_mbuf_attrs(struct os_mbuf * m,uint16_t off,uint16_t len,const struct cbor_attr_t * attrs)444 cbor_read_mbuf_attrs(struct os_mbuf *m, uint16_t off, uint16_t len,
445 const struct cbor_attr_t *attrs)
446 {
447 struct cbor_mbuf_reader cmr;
448 struct CborParser parser;
449 struct CborValue value;
450 CborError err;
451
452 cbor_mbuf_reader_init(&cmr, m, off);
453 err = cbor_parser_init(&cmr.r, 0, &parser, &value);
454 if (err != CborNoError) {
455 return -1;
456 }
457 return cbor_read_object(&value, attrs);
458 }
459
460 static int
cbor_write_arr_val(struct CborEncoder * enc,const struct cbor_out_arr_val_t * arr)461 cbor_write_arr_val(struct CborEncoder *enc,
462 const struct cbor_out_arr_val_t *arr)
463 {
464 struct CborEncoder arr_enc;
465 size_t i;
466 int rc;
467
468 rc = cbor_encoder_create_array(enc, &arr_enc, arr->len);
469 if (rc != 0) {
470 return SYS_ENOMEM;
471 }
472
473 for (i = 0; i < arr->len; i++) {
474 rc = cbor_write_val(&arr_enc, &arr->elems[i]);
475 if (rc != 0) {
476 return SYS_ENOMEM;
477 }
478 }
479
480 rc = cbor_encoder_close_container(enc, &arr_enc);
481 if (rc != 0) {
482 return SYS_ENOMEM;
483 }
484
485 return 0;
486 }
487
488 static int
cbor_write_val(struct CborEncoder * enc,const struct cbor_out_val_t * val)489 cbor_write_val(struct CborEncoder *enc, const struct cbor_out_val_t *val)
490 {
491 int len;
492 int rc;
493
494 switch (val->type) {
495 case CborAttrNullType:
496 rc = cbor_encode_null(enc);
497 break;
498
499 case CborAttrBooleanType:
500 rc = cbor_encode_boolean(enc, val->boolean);
501 break;
502
503 case CborAttrIntegerType:
504 rc = cbor_encode_int(enc, val->integer);
505 break;
506
507 case CborAttrUnsignedIntegerType:
508 rc = cbor_encode_uint(enc, val->uinteger);
509 break;
510
511 #if FLOAT_SUPPORT
512 case CborAttrHalfFloatType:
513 rc = cbor_encode_half_float(enc, &val->halffloat);
514 break;
515
516 case CborAttrFloatType:
517 rc = cbor_encode_float(enc, val->fval);
518 break;
519
520 case CborAttrDoubleType:
521 rc = cbor_encode_double(enc, val->real);
522 break;
523 #endif
524
525 case CborAttrByteStringType:
526 if (val->bytestring.data == NULL &&
527 val->bytestring.len != 0) {
528
529 return SYS_EINVAL;
530 }
531
532 rc = cbor_encode_byte_string(enc, val->bytestring.data,
533 val->bytestring.len);
534 break;
535
536 case CborAttrTextStringType:
537 if (val->string == NULL) {
538 len = 0;
539 } else {
540 len = strlen(val->string);
541 }
542 rc = cbor_encode_text_string(enc, val->string, len);
543 break;
544
545 case CborAttrObjectType:
546 rc = cbor_write_object(enc, val->obj);
547 break;
548
549 case CborAttrArrayType:
550 rc = cbor_write_arr_val(enc, &val->array);
551 break;
552
553 default:
554 return SYS_ENOTSUP;
555 }
556
557 if (rc != 0) {
558 return SYS_ENOMEM;
559 }
560
561 return 0;
562 }
563
564 static int
cbor_write_attr(struct CborEncoder * enc,const struct cbor_out_attr_t * attr)565 cbor_write_attr(struct CborEncoder *enc, const struct cbor_out_attr_t *attr)
566 {
567 int len;
568 int rc;
569
570 if (attr->omit) {
571 return 0;
572 }
573
574 if (!attr->attribute) {
575 rc = SYS_EINVAL;
576 return rc;
577 }
578
579 len = strlen(attr->attribute);
580 rc = cbor_encode_text_string(enc, attr->attribute, len);
581 if (rc != 0) {
582 return rc;
583 }
584
585 rc = cbor_write_val(enc, &attr->val);
586 if (rc != 0) {
587 return rc;
588 }
589
590 return 0;
591 }
592
593 int
cbor_write_object(struct CborEncoder * enc,const struct cbor_out_attr_t * attrs)594 cbor_write_object(struct CborEncoder *enc, const struct cbor_out_attr_t *attrs)
595 {
596 const struct cbor_out_attr_t *attr;
597 struct CborEncoder map;
598 int rc;
599
600 rc = cbor_encoder_create_map(enc, &map, CborIndefiniteLength);
601 if (rc != 0) {
602 return SYS_ENOMEM;
603 }
604
605 for (attr = attrs; attr->val.type != 0; attr++) {
606 rc = cbor_write_attr(&map, attr);
607 if (rc != 0) {
608 return rc;
609 }
610 }
611
612 rc = cbor_encoder_close_container(enc, &map);
613 if (rc != 0) {
614 return SYS_ENOMEM;
615 }
616
617 return 0;
618 }
619
620 int
cbor_write_object_msys(const struct cbor_out_attr_t * attrs,struct os_mbuf ** out_om)621 cbor_write_object_msys(const struct cbor_out_attr_t *attrs,
622 struct os_mbuf **out_om)
623 {
624 struct cbor_mbuf_writer writer;
625 struct CborEncoder encoder;
626 int rc;
627
628 *out_om = os_msys_get_pkthdr(0, 0);
629 if (*out_om == NULL) {
630 return SYS_ENOMEM;
631 }
632
633 cbor_mbuf_writer_init(&writer, *out_om);
634 cbor_encoder_init(&encoder, &writer.enc, 0);
635
636 rc = cbor_write_object(&encoder, attrs);
637 if (rc != 0) {
638 os_mbuf_free_chain(*out_om);
639 *out_om = NULL;
640 return rc;
641 }
642
643 return 0;
644 }
645 #endif
646