]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Porting the CBOR encoder from the YANG branch
authorMaria Matejka <mq@ucw.cz>
Fri, 14 Mar 2025 19:50:50 +0000 (20:50 +0100)
committerMaria Matejka <mq@ucw.cz>
Fri, 14 Mar 2025 19:50:50 +0000 (20:50 +0100)
Minor cleanups by commiter.

(source commit 43ff10204b1d9b76f6d5afc5252fb09480d5ffc5 but expected
to be rebased later, don't worry if you fail to find it)

lib/Makefile
lib/cbor.c [new file with mode: 0644]
lib/cbor.h [new file with mode: 0644]
lib/cbor_parse_tools.c [new file with mode: 0644]
lib/cbor_parse_tools.h [new file with mode: 0644]
lib/cbor_shortcuts.c [new file with mode: 0644]
lib/cbor_shortcuts.h [new file with mode: 0644]
lib/cbor_test.c [new file with mode: 0644]

index 5ed759e9d2e1c7021dae9ca557907fa4adcdbeb0..e2f9752ef6d2a482d35d8db35ae473c9db3e2884 100644 (file)
@@ -1,7 +1,7 @@
-src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := a-path.c a-set.c bitmap.c bitops.c blake2s.c blake2b.c cbor.c cbor_parse_tools.c cbor_shortcuts.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
 obj := $(src-o-files)
 $(all-daemon)
 
-tests_src := a-set_test.c a-path_test.c attribute_cleanup_test.c bitmap_test.c heap_test.c buffer_test.c event_test.c flowspec_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c rt-normalize_test.c checksum_test.c lists_test.c locking_test.c mac_test.c ip_test.c hash_test.c printf_test.c rcu_test.c slab_test.c tlists_test.c type_test.c
+tests_src := a-set_test.c a-path_test.c attribute_cleanup_test.c bitmap_test.c cbor_test.c heap_test.c buffer_test.c event_test.c flowspec_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c rt-normalize_test.c checksum_test.c lists_test.c locking_test.c mac_test.c ip_test.c hash_test.c printf_test.c rcu_test.c slab_test.c tlists_test.c type_test.c
 tests_targets := $(tests_targets) $(tests-target-files)
 tests_objs := $(tests_objs) $(src-o-files)
diff --git a/lib/cbor.c b/lib/cbor.c
new file mode 100644 (file)
index 0000000..a50319e
--- /dev/null
@@ -0,0 +1,237 @@
+#include <stdint.h>
+#include <string.h>
+
+#include "lib/cbor.h"
+
+
+void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num);
+void check_memory(struct cbor_writer *writer, int add_size);
+
+struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp)
+{
+  struct cbor_writer *writer = (struct cbor_writer*)lp_alloc(lp, sizeof(struct cbor_writer));
+  writer->cbor = buff;
+  writer->capacity = capacity;
+  writer->pt = 0;
+  writer->lp = lp;
+  return writer;
+}
+  
+void cbor_open_block(struct cbor_writer *writer) { // We will need to close the block later manualy
+  check_memory(writer, 2);
+  writer->cbor[writer->pt] = 0xbf;
+  writer->pt++;
+}
+
+void cbor_open_list(struct cbor_writer *writer)
+{
+  check_memory(writer, 2);
+  writer->cbor[writer->pt] = 0x9f;
+  writer->pt++;
+}
+
+void cbor_close_block_or_list(struct cbor_writer *writer)
+{
+  check_memory(writer, 2);
+  writer->cbor[writer->pt] = 0xff;
+  writer->pt++;
+}
+
+void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length)
+{
+  write_item(writer, 5, length);
+}
+
+void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length)
+{
+  write_item(writer, 4, length);
+}
+
+
+void cbor_add_int(struct cbor_writer *writer, int64_t item)
+{
+  if (item >= 0)
+  {
+    write_item(writer, 0, item); // 0 is the "major" (three bits) introducing positive int, 1 is for negative
+  }
+  else
+  {
+    write_item(writer, 1, -item - 1);
+  }
+}
+
+void cbor_epoch_time(struct cbor_writer *writer, int64_t time, int shift)
+{
+  write_item(writer, 6, 1); // 6 is TAG, 1 is tag number for epoch time
+  cbor_relativ_time(writer, time, shift);
+}
+
+void cbor_relativ_time(struct cbor_writer *writer, int64_t time, int shift)
+{
+  write_item(writer, 6, 4); // 6 is TAG, 4 is tag number for decimal fraction
+  cbor_open_list_with_length(writer, 2);
+  cbor_add_int(writer, shift);
+  cbor_add_int(writer, time);
+}
+
+void cbor_add_ipv4(struct cbor_writer *writer, ip4_addr addr)
+{
+  write_item(writer, 6, 52); // 6 is TAG, 52 is tag number for ipv4
+  write_item(writer, 2, 4); // bytestring of length 4
+  put_ip4(&writer->cbor[writer->pt], addr);
+  writer->pt += 4;
+}
+
+void cbor_add_ipv6(struct cbor_writer *writer, ip6_addr addr)
+{
+  write_item(writer, 6, 54); // 6 is TAG, 54 is tag number for ipv6
+  write_item(writer, 2, 16); // bytestring of length 16
+  put_ip6(&writer->cbor[writer->pt], addr);
+  writer->pt += 16;
+}
+
+
+void cbor_add_ipv4_prefix(struct cbor_writer *writer, net_addr_ip4 *n)
+{
+  write_item(writer, 6, 52); // 6 is TAG, 52 is tag number for ipv4
+  cbor_open_block_with_length(writer, 2);
+  cbor_add_int(writer, n->pxlen);
+  write_item(writer, 2, 4); // bytestring of length 4
+  put_ip4(&writer->cbor[writer->pt], n->prefix);
+  writer->pt += 4;
+}
+
+
+void cbor_add_ipv6_prefix(struct cbor_writer *writer, net_addr_ip6 *n)
+{
+  write_item(writer, 6, 54); // 6 is TAG, 54 is tag number for ipv6
+  cbor_open_block_with_length(writer, 2);
+  cbor_add_int(writer, n->pxlen);
+
+  write_item(writer, 2, 16);
+  put_ip6(&writer->cbor[writer->pt], n->prefix);
+  writer->pt += 16;
+}
+
+
+void cbor_add_uint(struct cbor_writer *writer, uint64_t item)
+{
+  write_item(writer, 0, item);
+}
+
+void cbor_add_tag(struct cbor_writer *writer, int item)
+{
+  write_item(writer, 6, item);
+}
+
+void cbor_add_string(struct cbor_writer *writer, const char *string)
+{
+  int length = strlen(string);
+  write_item(writer, 3, length);  // 3 is major, then goes length of string and string
+  check_memory(writer, length);
+  memcpy(writer->cbor+writer->pt, string, length);
+  writer->pt+=length;
+}
+
+void cbor_nonterminated_string(struct cbor_writer *writer, const char *string, uint32_t length)
+{
+  write_item(writer, 3, length);  // 3 is major, then goes length of string and string
+  check_memory(writer, length);
+  memcpy(writer->cbor+writer->pt, string, length);
+  writer->pt+=length;
+}
+
+void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num)
+{
+  //log("write major %i %li", major, num);
+  major = major<<5;
+  check_memory(writer, 10);
+  if (num > ((uint64_t)1<<(4*8))-1)
+  { // We need 8 bytes to encode the num
+    major += 0x1b; // reserving those bytes
+    writer->cbor[writer->pt] = major;
+    writer->pt++;
+    for (int i = 7; i>=0; i--)
+    { // write n-th byte of num
+      uint8_t to_write = (num>>(i*8)) & 0xff;
+      writer->cbor[writer->pt] = to_write;
+      writer->pt++;
+    }
+    return;
+  }
+  if (num > (1<<(2*8))-1)
+  { // We need 4 bytes to encode the num
+    major += 0x1a; // reserving those bytes
+    writer->cbor[writer->pt] = major;
+    writer->pt++;
+    for (int i = 3; i>=0; i--)
+    { // write n-th byte of num
+      uint8_t to_write = (num>>(i*8)) & 0xff;
+      writer->cbor[writer->pt] = to_write;
+      writer->pt++;
+    }
+    return;
+  }
+  if (num > (1<<(8))-1)
+  { // We need 2 bytes to encode the num
+    major += 0x19; // reserving those bytes
+    writer->cbor[writer->pt] = major;
+    writer->pt++;
+    for (int i = 1; i>=0; i--)
+    { // write n-th byte of num
+      uint8_t to_write = (num>>(i*8)) & 0xff;
+      writer->cbor[writer->pt] = to_write;
+      writer->pt++;
+    }
+    return;
+  }
+  if (num > 23)
+  { // byte is enough, but aditional value would be too big
+    major += 0x18; // reserving that byte
+    writer->cbor[writer->pt] = major;
+    writer->pt++;
+    uint8_t to_write = num & 0xff;
+    writer->cbor[writer->pt] = to_write;
+    writer->pt++;
+    return;
+  }
+  //log("write item major %i num %i writer->pt %i writer->capacity %i writer %i", major, num, writer->pt, writer->capacity, writer);
+  major += num;  // we can store the num as additional value 
+  writer->cbor[writer->pt] = major;
+  writer->pt++;
+}
+
+void cbor_write_item_with_constant_val_length_4(struct cbor_writer *writer, uint8_t major, uint64_t num)
+{
+// this is only for headers which should be constantly long. 
+  major = major<<5;
+  check_memory(writer, 10);
+  major += 0x1a; // reserving those bytes
+  writer->cbor[writer->pt] = major;
+  writer->pt++;
+  for (int i = 3; i>=0; i--)
+  { // write n-th byte of num
+    uint8_t to_write = (num>>(i*8)) & 0xff;
+    writer->cbor[writer->pt] = to_write;
+    writer->pt++;
+  }
+}
+
+
+void rewrite_4bytes_int(struct cbor_writer *writer, int pt, int num)
+{
+  for (int i = 3; i>=0; i--)
+  {
+    uint8_t to_write = (num>>(i*8)) & 0xff;
+    writer->cbor[pt] = to_write;
+    pt++;
+  }
+}
+
+void check_memory(struct cbor_writer *writer, int add_size)
+{
+  if (writer->capacity - writer->pt-add_size < 0)
+  {
+    bug("There is not enough space for cbor response in given buffer");
+  }
+}
diff --git a/lib/cbor.h b/lib/cbor.h
new file mode 100644 (file)
index 0000000..36c16f6
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef CBOR_H
+#define CBOR_H
+
+#include "nest/bird.h"
+
+
+struct cbor_writer {
+  int pt; // where will next byte go
+  int capacity;
+  int8_t *cbor;
+  struct linpool *lp;
+};
+
+
+struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp);
+  
+void cbor_open_block(struct cbor_writer *writer);
+
+void cbor_open_list(struct cbor_writer *writer);
+
+void cbor_close_block_or_list(struct cbor_writer *writer);
+
+void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length);
+
+void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length);
+
+
+void cbor_add_int(struct cbor_writer *writer, int64_t item);
+
+void cbor_add_ipv4(struct cbor_writer *writer, ip4_addr);
+
+void cbor_add_ipv6(struct cbor_writer *writer, ip6_addr);
+
+void cbor_epoch_time(struct cbor_writer *writer, int64_t time, int shift);
+
+void cbor_relativ_time(struct cbor_writer *writer, int64_t time, int shift);
+
+void cbor_add_ipv4_prefix(struct cbor_writer *writer, net_addr_ip4 *n);
+
+
+void cbor_add_ipv6_prefix(struct cbor_writer *writer, net_addr_ip6 *n);
+
+
+void cbor_add_uint(struct cbor_writer *writer, uint64_t item);
+
+void cbor_add_tag(struct cbor_writer *writer, int item);
+
+void cbor_add_string(struct cbor_writer *writer, const char *string);
+
+void cbor_nonterminated_string(struct cbor_writer *writer, const char *string, uint32_t length);
+
+void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num);
+
+void cbor_write_item_with_constant_val_length_4(struct cbor_writer *writer, uint8_t major, uint64_t num);
+
+void rewrite_4bytes_int(struct cbor_writer *writer, int pt, int num);
+
+#endif
diff --git a/lib/cbor_parse_tools.c b/lib/cbor_parse_tools.c
new file mode 100644 (file)
index 0000000..b647e4f
--- /dev/null
@@ -0,0 +1,69 @@
+#include <string.h>
+#include "lib/cbor_parse_tools.h"
+
+uint compare_buff_str(struct buff_reader *buf_read, uint length, char *string) {
+  if (length != strlen(string)) {
+    return 0;
+  }
+  for (size_t i = 0; i < strlen(string); i++) {
+    if (buf_read->buff[i+buf_read->pt]!=string[i]) {
+      return 0;
+    }
+  }
+  return 1;
+};
+
+struct value
+get_value(struct buff_reader *reader)
+{
+  struct value val;
+  byte *buff = reader->buff;
+  val.major = buff[reader->pt]>>5;
+  int first_byte_val = buff[reader->pt] - (val.major<<5);
+  if (first_byte_val <=23) {
+    val.val = first_byte_val;
+    reader->pt++;
+  } else if (first_byte_val == 0x18)
+  {
+    val.val = buff[reader->pt+1];
+    reader->pt+=2;
+  } else if (first_byte_val == 0x19)
+  {
+    val.val = buff[reader->pt+1];
+    val.val = val.val << 8;
+    val.val += buff[reader->pt+2];
+    reader->pt += 3;
+  } else if (first_byte_val == 0x1a)
+  {
+    val.val = 0;
+    for (int i = 1; i < 4; i++)
+    {
+      val.val += buff[reader->pt+i];
+      val.val = val.val << 8;
+    }
+    val.val += buff[reader->pt+4];
+    reader->pt+=5;
+  } else if (first_byte_val == 0x1b)
+  {
+    val.val = 0;
+    for (int i = 1; i < 8; i++) {
+      val.val += buff[reader->pt+i];
+      val.val = val.val << 8;
+    }
+    val.val += buff[reader->pt+8];
+    reader->pt += 9;
+  } else if (first_byte_val == 0x1f)
+  {
+    val.val = -1;
+    reader->pt++;
+  }
+  if (val.major == NEG_INT)
+    val.val = -1 - val.val;
+  return val;
+}
+
+
+int val_is_break(struct value val)
+{
+  return val.major == FLOAT && val.val == -1; // break code is 0xff, so the major is same for float and break
+}
diff --git a/lib/cbor_parse_tools.h b/lib/cbor_parse_tools.h
new file mode 100644 (file)
index 0000000..b3e0264
--- /dev/null
@@ -0,0 +1,42 @@
+#include "sysdep/config.h"
+#include "lib/birdlib.h"
+
+enum functions {
+  SHOW_STATUS = 0,
+  SHOW_MEMORY = 1,
+  SHOW_SYMBOLS = 2,
+  SHOW_OSPF = 3,
+  SHOW_PROTOCOLS = 4,
+};
+
+enum cbor_majors {
+  UINT = 0,
+  NEG_INT = 1,
+  BYTE_STR = 2,
+  TEXT = 3,
+  ARRAY = 4,
+  BLOCK = 5,
+  TAG = 6,
+  FLOAT = 7,
+};
+
+
+struct value {
+ int major;
+ int64_t val;
+};
+
+struct buff_reader {
+  byte *buff;
+  uint pt;
+  uint size;
+};
+
+
+uint compare_buff_str(struct buff_reader *buf_read, uint length, char *string);
+
+struct value
+get_value(struct buff_reader *reader);
+
+
+int val_is_break(struct value val);
diff --git a/lib/cbor_shortcuts.c b/lib/cbor_shortcuts.c
new file mode 100644 (file)
index 0000000..b1d0c93
--- /dev/null
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lib/cbor_shortcuts.h"
+
+
+
+void cbor_string_string(struct cbor_writer *writer, char *key, const char *value) {
+  cbor_add_string(writer, key);
+  cbor_add_string(writer, value);
+}
+
+void cbor_string_int(struct cbor_writer *writer, char *key, int64_t value) {
+  cbor_add_string(writer, key);
+  cbor_add_int(writer, value);
+}
+
+void cbor_string_uint(struct cbor_writer *writer, char *key, u64 value) {
+  cbor_add_string(writer, key);
+  cbor_add_uint(writer, value);
+}
+
+void cbor_string_epoch_time(struct cbor_writer *writer, char *key, int64_t time, int shift) {
+  cbor_add_string(writer, key);
+  cbor_epoch_time(writer, time, shift);
+}
+
+void cbor_string_relativ_time(struct cbor_writer *writer, char *key, int64_t time, int shift) {
+  cbor_add_string(writer, key);
+  cbor_relativ_time(writer, time, shift);
+}
+
+void cbor_string_ip(struct cbor_writer *writer, char *key, ip_addr addr) {
+  cbor_add_string(writer, key);
+  if (ipa_is_ip4(addr))
+    cbor_add_ipv4(writer, ipa_to_ip4(addr));
+  else
+    cbor_add_ipv6(writer, ipa_to_ip6(addr));
+}
+
+void cbor_string_ipv4(struct cbor_writer *writer, char *key, ip4_addr addr) {
+  cbor_add_string(writer, key);
+  cbor_add_ipv4(writer, addr);
+}
+
+void cbor_string_ipv6(struct cbor_writer *writer, char *key, ip6_addr addr) {
+  cbor_add_string(writer, key);
+  cbor_add_ipv6(writer, addr);
+}
+
+void cbor_named_block_two_ints(struct cbor_writer *writer, char *key, char *name1, int val1, char *name2, int val2) {
+  cbor_add_string(writer, key);
+  cbor_open_block_with_length(writer, 2);
+  cbor_add_string(writer, name1);
+  cbor_add_int(writer, val1);
+  cbor_add_string(writer, name2);
+  cbor_add_int(writer, val2);
+}
+
+void cbor_write_to_file(struct cbor_writer *writer, char *filename) {
+  FILE *write_ptr;
+
+  write_ptr = fopen(filename, "wb");
+
+  fwrite(writer->cbor, writer->pt, 1, write_ptr);
+  fclose(write_ptr);
+}
+
+void cbor_add_net(struct cbor_writer *writer, const net_addr *N) {
+  // Original switch comes from lib/net.c and contains more cases.
+  net_addr_union *n = (void *) N;
+
+  switch (n->n.type)
+  {
+  case NET_IP4:
+    cbor_add_ipv4_prefix(writer, &n->ip4);
+    return;
+  case NET_IP6:
+    cbor_add_ipv6_prefix(writer, &n->ip6);
+    return;
+  default:
+    bug("net type unsupported by cbor (yet)."); 
+  }
+}
+
+
+
diff --git a/lib/cbor_shortcuts.h b/lib/cbor_shortcuts.h
new file mode 100644 (file)
index 0000000..e9bac67
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef CBOR_SHORTCUTS_H
+#define CBOR_SHORTCUTS_H
+
+#include "lib/cbor.h"
+#include "sysdep/config.h"
+#include "lib/birdlib.h"
+#include "nest/protocol.h"
+#include "lib/ip.h"
+
+
+void cbor_string_string(struct cbor_writer *writer, char *key, const char *value);
+
+void cbor_string_int(struct cbor_writer *writer, char *key, int64_t value);
+
+void cbor_string_epoch_time(struct cbor_writer *writer, char *key, int64_t time, int shift);
+void cbor_string_relativ_time(struct cbor_writer *writer, char *key, int64_t time, int shift);
+void cbor_string_uint(struct cbor_writer *writer, char *key, u64 value);
+void cbor_string_ip(struct cbor_writer *writer, char *key, ip_addr);
+void cbor_string_ipv4(struct cbor_writer *writer, char *key, ip4_addr);
+void cbor_string_ipv6(struct cbor_writer *writer, char *key, ip6_addr);
+void cbor_named_block_two_ints(struct cbor_writer *writer, char *key, char *name1, int val1, char *name2, int val2);
+void cbor_write_to_file(struct cbor_writer *writer, char *filename);
+
+void cbor_add_net(struct cbor_writer *writer, const net_addr *N);
+
+#endif
diff --git a/lib/cbor_test.c b/lib/cbor_test.c
new file mode 100644 (file)
index 0000000..6ef8a3a
--- /dev/null
@@ -0,0 +1,137 @@
+
+#include "test/birdtest.h"
+#include "lib/cbor.h"
+#include "lib/cbor_parse_tools.h"
+
+#define BUFF_LEN 100
+
+struct cbor_writer *w;
+struct buff_reader reader;
+
+void print_to_file_for_control_from_outside(void)
+{
+  FILE *write_ptr;
+
+  write_ptr = fopen("a.cbor", "wb");
+
+  fwrite(w->cbor, w->pt, 1, write_ptr);
+  fclose(write_ptr);
+
+}
+
+static int test_int(void)
+{
+  reader.pt = w->pt = 0;
+  int num_items = 13;
+  int64_t test_int[] = {-123456789012345678, -1234567890, -12345, -123, -25, -13, 0, 13, 25, 123, 12345, 1234567890, 123456789012345678};
+  byte bin_int[] = {0x8d, 0x3b, 0x1, 0xb6, 0x9b, 0x4b, 0xa6, 0x30, 0xf3, 0x4d, 0x3a, 0x49, 0x96, 0x2, 0xd1, 0x39, 0x30, 0x38, 0x38, 0x7a, 0x38, 0x18, 0x2c, 0x0, 0xd, 0x18, 0x19, 0x18, 0x7b, 0x19, 0x30, 0x39, 0x1a, 0x49, 0x96, 0x2, 0xd2, 0x1b, 0x1, 0xb6, 0x9b, 0x4b, 0xa6, 0x30, 0xf3, 0x4e};
+  cbor_open_list_with_length(w, num_items);
+  for (int i = 0; i < num_items; i++)
+  {
+    cbor_add_int(w, test_int[i]);
+  }
+
+  for (long unsigned int i = 0; i < sizeof(bin_int); i++)
+  {
+    bt_assert((w->cbor[i] & 0xff) == (bin_int[i] & 0xff));
+  }
+
+  struct value val = get_value(&reader);
+  bt_assert(val.major = ARRAY);
+  bt_assert(val.val = num_items);
+  for (int i = 0; i < num_items; i++)
+  {
+    val = get_value(&reader);
+    bt_assert(val.major == NEG_INT || val.major == UINT);
+    bt_assert(val.val == test_int[i]);
+  }
+  return 1;
+}
+
+static int non_aligned_int(void)
+{
+  w->pt = reader.pt = 0;
+  int num_items = 4;
+  cbor_open_list_with_length(w, num_items);
+
+  cbor_add_int(w, 30);
+  w->cbor[w->pt - 1] = 1;
+
+  cbor_add_int(w, 300);
+  w->cbor[w->pt - 2] = 0;
+  w->cbor[w->pt - 1] = 1;
+
+  cbor_add_int(w, 300000000);
+  for (int i = 4; i > 1; i--)
+  {
+    w->cbor[w->pt - i] = 0;
+  }
+  w->cbor[w->pt - 1] = 1;
+
+  cbor_add_int(w, 30000000000000000);
+  for (int i = 8; i > 1; i--)
+  {
+    w->cbor[w->pt - i] = 0;
+  }
+  w->cbor[w->pt - 1] = 1;
+
+  struct value val = get_value(&reader);
+  bt_assert(val.major = ARRAY);
+  bt_assert(val.val = num_items);
+
+  for (int i = 0; i < num_items; i++)
+  {
+    val = get_value(&reader);
+    bt_assert(val.major == UINT);
+    bt_assert(val.val == 1);
+  }
+  return 1;
+}
+
+static int test_majors(void)
+{
+  w->pt = reader.pt = 0;
+  cbor_open_block(w);
+  cbor_open_list_with_length(w, 4);
+  cbor_add_string(w, "b");
+  cbor_add_int(w, 1);
+  cbor_add_int(w, -1);
+  cbor_add_ipv4(w, ip4_build(18, 4, 0, 0));
+  cbor_close_block_or_list(w);
+
+  struct value val = get_value(&reader);
+  bt_assert(val.major == BLOCK);
+  val = get_value(&reader);
+  bt_assert(val.major == ARRAY);
+  val = get_value(&reader);
+  bt_assert(val.major == TEXT);
+  reader.pt += val.val;
+  val = get_value(&reader);
+  bt_assert(val.major == UINT);
+  val = get_value(&reader);
+  bt_assert(val.major == NEG_INT);
+  val = get_value(&reader);
+  bt_assert(val.major == TAG);
+  val = get_value(&reader);
+  bt_assert(val.major == BYTE_STR);
+  reader.pt += val.val;
+  val = get_value(&reader);
+  bt_assert(val_is_break(val));
+  return 1;
+}
+
+int main(int argc, char *argv[])
+{
+  bt_init(argc, argv);
+  byte buff[BUFF_LEN];
+  w = cbor_init(buff, BUFF_LEN, tmp_linpool);
+  reader.buff = buff;
+  reader.size = BUFF_LEN;
+  reader.pt = 0;
+
+  bt_test_suite(test_int, "Adding and reading integer from cbor.");
+  bt_test_suite(non_aligned_int, "Reading non-alligned int from cbor.");
+  bt_test_suite(test_majors, "Test cbor datatypes.");
+
+  return bt_exit_value();
+}