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