Fix Bug in RFC5444 address compression
authorHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 13 Jun 2017 08:22:26 +0000 (10:22 +0200)
committerHenning Rogge <henning.rogge@fkie.fraunhofer.de>
Tue, 13 Jun 2017 08:22:26 +0000 (10:22 +0200)
Fix Buf in list merge
Fix test cases to check for fixed bugs
Add new test case for address compression

src-api/common/list.h
src-plugins/subsystems/rfc5444/rfc5444_msg_generator.c
src-plugins/subsystems/rfc5444/rfc5444_print.c
src-plugins/subsystems/rfc5444/rfc5444_print.h
src-plugins/subsystems/rfc5444/rfc5444_writer.c
tests/common/test_common_list.c
tests/rfc5444/special/test_nhdp_1.c
tests/rfc5444/special/test_nhdp_3.c
tests/rfc5444/test_rfc5444_writer_mandatory.c

index 6ff67d7..c7ef5a1 100644 (file)
@@ -213,10 +213,11 @@ list_merge(struct list_entity *add_to, struct list_entity *remove_from) {
     return;
   }
 
-  add_to->next->prev = remove_from->prev;
-  remove_from->prev->next = add_to->next;
-  add_to->next = remove_from->next;
-  remove_from->next->prev = add_to;
+  add_to->prev->next = remove_from->next;
+  remove_from->next->prev = add_to->prev;
+
+  add_to->prev= remove_from->prev;
+  remove_from->prev->next = add_to;
 
   list_init_head(remove_from);
 }
index 1c224d9..2f03678 100644 (file)
@@ -343,7 +343,7 @@ rfc5444_writer_create_message(struct rfc5444_writer *writer, uint8_t msgid,
         writer->_state = RFC5444_WRITER_NONE;
 #endif
         _rfc5444_writer_free_addresses(writer, msg);
-        return -1;
+        return RFC5444_MTU_TOO_SMALL;
       }
       not_fragmented = false;
 
@@ -884,12 +884,11 @@ _compress_address(struct _rfc5444_internal_addr_compress_session *acs,
     printf("Compress Address %s (last: %s)\n",
         netaddr_to_string(&nbuf1, &addr->address),
         last_addr == NULL ? "" : netaddr_to_string(&nbuf2, &last_addr->address));
-    printf("\ttotal:");
+    printf("\ttotal:   ");
     for (i=0; i<addrlen; i++) {
       printf(" %4d ", acs[i].total);
     }
     printf("\n");
-    printf("\tcurrent:");
   }
 #endif
   /* add size for address part (and header if necessary) */
@@ -910,8 +909,19 @@ _compress_address(struct _rfc5444_internal_addr_compress_session *acs,
       }
     }
     _close_addrblock(acs, writer, last_addr, common_head);
+#ifdef DEBUG_OUTPUT
+    printf("\tt-closed:");
+    for (i=0; i<addrlen; i++) {
+      printf(" %4d ", acs[i].total);
+    }
+    printf("\n");
+#endif
   }
 
+#ifdef DEBUG_OUTPUT
+  printf("\tcurrent:");
+#endif
+
   /* calculate tlv flags */
   avl_for_each_element(&addr->_addrtlv_tree, tlv, addrtlv_node) {
     tlvtype = tlv->tlvtype;
@@ -1016,12 +1026,13 @@ _compress_address(struct _rfc5444_internal_addr_compress_session *acs,
     if (closed || acs[i].total + continue_cost > acs[addrlen-1].total + new_cost) {
       /* forget the last addresses, longer prefix is better. */
       /* store address block for later binary generation */
+#if 0
       if (last_addr) {
         last_addr->_block_start = acs[addrlen-1].ptr;
         last_addr->_block_multiple_prefixlen = acs[addrlen-1].multiplen;
         last_addr->_block_headlen = addrlen-1;
       }
-
+#endif
       /* Create a new address block */
       acs[i].ptr = addr;
       acs[i].multiplen = false;
index d3c686a..191f1ae 100644 (file)
@@ -148,6 +148,364 @@ rfc5444_print_direct(struct autobuf *out, void *buffer, size_t length) {
   return result;
 }
 
+static void
+_print_hex(struct autobuf *out, uint8_t *ptr, size_t length) {
+  size_t i;
+
+  for (i=0; i<length; i++) {
+    abuf_appendf(out, "%s%02x", i == 0 ? "" : " ", ptr[i]);
+  }
+}
+
+static int
+_print_raw_tlvblock(struct autobuf *out, const char *prefix,
+    uint8_t *ptr, size_t *idx, size_t length) {
+  char valueprefix[128];
+  uint16_t blocklength, tlv_len, tlv_singlelength;
+  size_t idx2;
+  uint8_t tlv_flags, startidx, endidx;
+
+  if (2 > length) {
+    return -1;
+  }
+
+  abuf_appendf(out, "%s,-------------------\n", prefix);
+  abuf_appendf(out, "%s|  TLV BLOCK\n", prefix);
+  abuf_appendf(out, "%s|-------------------\n", prefix);
+
+  blocklength = (ptr[*idx] << 8) | ptr[*idx + 1];
+  abuf_appendf(out, "%s| * TLV Block Size: %u\n", prefix, blocklength);
+
+  if (blocklength + 2u > length) {
+    return -1;
+  }
+
+  *idx += 2;
+  ptr = &ptr[*idx];
+  for (idx2 = 0; idx2 < blocklength;) {
+    if (idx2 + 2 > blocklength) {
+      return -1;
+    }
+
+    abuf_appendf(out, "%s|    ,-------------------\n", prefix);
+    abuf_appendf(out, "%s|    |  TLV\n", prefix);
+    abuf_appendf(out, "%s|    |-------------------\n", prefix);
+
+    abuf_appendf(out, "%s|    | type:        %u\n", prefix, ptr[idx2]);
+    idx2++;
+
+    tlv_flags = ptr[idx2];
+    abuf_appendf(out, "%s|    | flags:       0x%02x\n", prefix, tlv_flags);
+    idx2++;
+
+    if (tlv_flags & RFC5444_TLV_FLAG_TYPEEXT) {
+      if (idx2 + 1 > blocklength) {
+        return -1;
+      }
+      abuf_appendf(out, "%s|    | ext-type:    %u\n", prefix, ptr[idx2]);
+      idx2++;
+    }
+
+    startidx = 0;
+    endidx = 0;
+    if (tlv_flags & (RFC5444_TLV_FLAG_SINGLE_IDX | RFC5444_TLV_FLAG_MULTI_IDX)) {
+      if (idx2 + 1 > blocklength) {
+        return -1;
+      }
+      startidx = ptr[idx2];
+      endidx = startidx;
+      abuf_appendf(out, "%s|    | index-start: %u\n", prefix, startidx);
+      idx2++;
+    }
+    if (tlv_flags & (RFC5444_TLV_FLAG_MULTI_IDX)) {
+      if (idx2 + 1 > blocklength) {
+        return -1;
+      }
+      endidx = ptr[idx2];
+      abuf_appendf(out, "%s|    | index-end:   %u\n", prefix, endidx);
+      idx2++;
+    }
+    tlv_len = 0;
+    if (tlv_flags & (RFC5444_TLV_FLAG_EXTVALUE)) {
+      if (idx2 + 1 > blocklength) {
+        return -1;
+      }
+      tlv_len = ptr[idx2] << 8;
+      idx2++;
+    }
+    if (tlv_flags & (RFC5444_TLV_FLAG_VALUE)) {
+      if (idx2 + 1 > blocklength) {
+        return -1;
+      }
+      tlv_len |= ptr[idx2];
+      idx2++;
+    }
+    if (tlv_flags & (RFC5444_TLV_FLAG_EXTVALUE | RFC5444_TLV_FLAG_VALUE)) {
+      abuf_appendf(out, "%s|    | length:      %u\n", prefix, tlv_len);
+    }
+
+    if (idx2 + tlv_len > blocklength) {
+      return -1;
+    }
+    if (tlv_flags & RFC5444_TLV_FLAG_MULTIVALUE) {
+      if (tlv_len % (endidx - startidx + 1)) {
+        return -1;
+      }
+      tlv_singlelength = tlv_len / (endidx - startidx + 1);
+    }
+    else {
+      tlv_singlelength = tlv_len;
+      endidx = startidx;
+    }
+
+    snprintf(valueprefix, sizeof(valueprefix), "%s|    |   ", prefix);
+    for (; startidx <= endidx; startidx++) {
+      abuf_hexdump(out, valueprefix, &ptr[idx2], tlv_singlelength);
+      idx2 += tlv_singlelength;
+      abuf_puts(out, "\n");
+    }
+  }
+
+  if (blocklength != idx2) {
+    return -1;
+  }
+  *idx += blocklength;
+  return 0;
+}
+
+int
+rfc5444_print_raw(struct autobuf *out, void *buffer, size_t length) {
+  static uint8_t ZEROTAIL[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+  uint8_t *ptr;
+  size_t idx, idx2, prefix_idx, i;
+  uint8_t flags, head_len, tail_len, *head, *tail, num_addr;
+  uint16_t msg_size, addr_length, mid_len;
+
+  ptr = buffer;
+  idx = 0;
+
+  if (idx + 1> length) {
+    return -1;
+  }
+
+  abuf_puts(out, "\t,------------------\n");
+  abuf_puts(out, "\t|  PACKET\n");
+  abuf_puts(out, "\t|------------------\n");
+
+  flags = ptr[0];
+  abuf_appendf(out, "\t| Packet version:    %u\n", flags >> 4);
+  abuf_appendf(out, "\t| Packet flags:      0x%02x\n", flags & 0x0f);
+  idx++;
+
+  if (flags & RFC5444_PKT_FLAG_SEQNO) {
+    if (idx + 2 > length) {
+      return -1;
+    }
+
+    abuf_appendf(out, "\t| Packet seq number: %u\n", (ptr[0] << 8) | ptr[1]);
+    idx += 2;
+  }
+
+  if (flags & RFC5444_PKT_FLAG_TLV) {
+    if (_print_raw_tlvblock(out, "\t|    | ", ptr, &idx, length)) {
+      return -1;
+    }
+  }
+
+  while (idx < length) {
+    idx2 = idx;
+
+    /* print messages */
+    if (idx2 + 4 > length) {
+      return -1;
+    }
+
+    abuf_puts(out, "\t|    ,-------------------\n");
+    abuf_puts(out, "\t|    |  MESSAGE\n");
+    abuf_puts(out, "\t|    |-------------------\n");
+    abuf_appendf(out, "\t|    | Message type:       %u\n", ptr[idx]);
+
+    flags = ptr[idx2+1];
+    abuf_appendf(out, "\t|    | Message flags:      0x%02x\n", flags >> 4);
+
+    addr_length = (flags & 15) + 1;
+    abuf_appendf(out, "\t|    | Address length:     %u\n", addr_length);
+
+    msg_size = (ptr[idx2+2] << 8) + ptr[idx+3];
+    abuf_appendf(out, "\t|    | Size:             %u\n", msg_size);
+    idx2 += 4;
+
+    if (flags & RFC5444_MSG_FLAG_ORIGINATOR) {
+      if (idx2 + addr_length > idx + msg_size) {
+        return -1;
+      }
+      abuf_appendf(out, "\t|    | Originator address: ");
+      _print_hex(out, &ptr[idx2], addr_length);
+      idx2 += addr_length;
+    }
+    if (flags & RFC5444_MSG_FLAG_HOPLIMIT) {
+      if (idx2 + 1 > idx + msg_size) {
+        return -1;
+      }
+      abuf_appendf(out, "\t|    | Hop limit:          %u\n", ptr[idx2]);
+      idx2++;
+    }
+    if (flags & RFC5444_MSG_FLAG_HOPCOUNT) {
+      if (idx2 + 1 > idx + msg_size) {
+        return -1;
+      }
+      abuf_appendf(out, "\t|    | Hop count:          %u\n", ptr[idx2]);
+      idx2++;
+    }
+    if (flags & RFC5444_MSG_FLAG_SEQNO) {
+      if (idx2 + 2 > idx + msg_size) {
+        return -1;
+      }
+      abuf_appendf(out, "\t|    | Sequence Number:    %u\n",
+          (ptr[idx2] << 8) | ptr[idx2+1]);
+      idx2+=2;
+    }
+
+    if (_print_raw_tlvblock(out, "\t|    |    ", ptr, &idx2, msg_size)) {
+      return -1;
+    }
+
+    while (idx2 < idx + msg_size) {
+      /* print address blocks */
+      if (idx2 + 2 > idx + msg_size) {
+        return -1;
+      }
+
+      abuf_puts(out, "\t|    |    ,-------------------\n");
+      abuf_puts(out, "\t|    |    |  ADDRESS-BLOCK\n");
+      abuf_puts(out, "\t|    |    |-------------------\n");
+
+      num_addr = ptr[idx2];
+      abuf_appendf(out, "\t|    |    | Num-Addr: %u\n", num_addr);
+
+      flags = ptr[idx2+1];
+      abuf_appendf(out, "\t|    |    | Flags:    0x%02x\n", flags);
+
+      idx2 += 2;
+
+      head_len = tail_len = 0;
+      if (flags & RFC5444_ADDR_FLAG_HEAD) {
+        if (idx2 + 1 > idx + msg_size) {
+          return -1;
+        }
+
+        head_len = ptr[idx2];
+        idx2++;
+        if (idx2 + head_len > idx + msg_size) {
+          return -1;
+        }
+
+        head = &ptr[idx2];
+
+        abuf_appendf(out, "\t|    |    | Head:     ");
+        _print_hex(out, head, head_len);
+        abuf_puts(out, "\n");
+
+        idx2 += head_len;
+      }
+      if (flags & RFC5444_ADDR_FLAG_FULLTAIL) {
+        if (idx2 + 1 > idx + msg_size) {
+          return -1;
+        }
+
+        tail_len = ptr[idx2];
+        idx2++;
+        if (idx2 + tail_len > idx + msg_size) {
+          return -1;
+        }
+
+        tail = &ptr[idx2];
+        abuf_appendf(out, "\t|    |    | Tail:     ");
+        _print_hex(out, tail, tail_len);
+        abuf_puts(out, "\n");
+        idx2 += tail_len;
+      }
+      if (flags & RFC5444_ADDR_FLAG_ZEROTAIL) {
+        if (idx2 + 1 > idx + msg_size) {
+          return -1;
+        }
+
+        tail_len = ptr[idx2];
+
+        tail = ZEROTAIL;
+        abuf_appendf(out, "\t|    |    | ZeroTail: ");
+        _print_hex(out, tail, tail_len);
+        abuf_puts(out, "\n");
+
+        idx2++;
+      }
+
+      mid_len = (addr_length - head_len - tail_len) * num_addr;
+      if (idx2 + mid_len > idx + msg_size) {
+        return -1;
+      }
+
+      prefix_idx = idx + mid_len;
+      if (flags & RFC5444_ADDR_FLAG_SINGLEPLEN) {
+        if (prefix_idx + 1 > idx + msg_size) {
+          return -1;
+        }
+      }
+      else if (flags & RFC5444_ADDR_FLAG_MULTIPLEN) {
+        if (prefix_idx + num_addr > idx + msg_size) {
+          return -1;
+        }
+      }
+      else {
+        prefix_idx = 0;
+      }
+
+      for (i=0; i<num_addr; i++) {
+        abuf_puts(out, "\t|    |    |    ,-------------------\n");
+        abuf_puts(out, "\t|    |    |    |  Address\n");
+        abuf_puts(out, "\t|    |    |    |-------------------\n");
+
+        abuf_appendf(out, "\t|    |    |    | Address: ");
+
+        if (head_len) {
+          _print_hex(out, head, head_len);
+
+          abuf_puts(out, " | ");
+        }
+        _print_hex(out, &ptr[idx2], addr_length - head_len - tail_len);
+        idx2 += addr_length - head_len - tail_len;
+
+        if (tail_len) {
+          abuf_puts(out, " | ");
+
+          _print_hex(out, tail, tail_len);
+        }
+
+        if (prefix_idx) {
+          abuf_appendf(out, " / %u", ptr[prefix_idx]);
+        }
+        if (flags & RFC5444_ADDR_FLAG_MULTIPLEN) {
+          prefix_idx++;
+        }
+
+        abuf_puts(out, "\n");
+      }
+
+      if(_print_raw_tlvblock(out, "\t|    |    |    ", ptr, &idx2, msg_size)) {
+        return -1;
+      }
+    }
+
+    if (idx + msg_size != idx2) {
+      return -1;
+    }
+
+    idx = idx2;
+  }
+
+  return 0;
+}
+
 /**
  * Clear output buffer and print start of packet
  * @param context rfc5444 tlvblock reader context
index fe04540..9b27aa3 100644 (file)
@@ -83,4 +83,6 @@ EXPORT void rfc5444_print_remove(
 EXPORT enum rfc5444_result rfc5444_print_direct(
     struct autobuf *out, void *buffer, size_t length);
 
+EXPORT int rfc5444_print_raw(struct autobuf *out, void *buffer, size_t length);
+
 #endif /* PRINT_RFC5444_H_ */
index 5e26773..a7dd130 100644 (file)
@@ -635,6 +635,8 @@ _register_addrtlvtype(struct rfc5444_writer *writer,
   tlvtype->_creator = msg;
   tlvtype->_full_type = _get_fulltype(tlvtype->type, tlvtype->exttype);
 
+  assert(!list_is_node_added(&tlvtype->_tlvtype_node));
+
   if (msg) {
     /* add to message creator list */
     list_add_tail(&msg->_msgspecific_tlvtype_head, &tlvtype->_tlvtype_node);
index 893c644..80f57a7 100644 (file)
@@ -216,17 +216,21 @@ static void test_merge(void) {
     CHECK_TRUE(e == &elements1[i], "for_each iteration %d failed", i);
     i++;
   }
+  CHECK_TRUE(i == COUNT, "missing elements from list 1");
+
   i = 0;
   list_for_each_element(&head2, e, node) {
     CHECK_TRUE(e == &elements2[i], "for_each iteration %d failed", i);
     i++;
   }
+  CHECK_TRUE(i == COUNT, "missing elements from list 2");
 
   list_merge(&head, &head2);
-  CHECK_TRUE(list_is_empty(&head2), "list_is_empty (1)");
+  CHECK_TRUE(list_is_empty(&head2), "list_is_empty (2)");
+  CHECK_TRUE(!list_is_empty(&head), "!list_is_empty (1)");
 
   i = 0;
-  list_for_each_element(&head2, e, node) {
+  list_for_each_element(&head, e, node) {
     if (i < COUNT) {
       CHECK_TRUE(e == &elements1[i], "for_each iteration %d failed", i);
     }
@@ -235,6 +239,7 @@ static void test_merge(void) {
     }
     i++;
   }
+  CHECK_TRUE(i == COUNT*2, "missing elements from merged list");
 
   END_TEST();
 }
index 7f0a8ad..121eee3 100644 (file)
@@ -229,9 +229,6 @@ int main(int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))
   msg = rfc5444_writer_register_message(&writer, MSG_TYPE, false);
   msg->addMessageHeader = addMessageHeader;
 
-  rfc5444_writer_register_addrtlvtype(&writer, &addrtlvs[0], MSG_TYPE);
-  rfc5444_writer_register_addrtlvtype(&writer, &addrtlvs[1], MSG_TYPE);
-
   rfc5444_writer_register_msgcontentprovider(&writer, &cpr, addrtlvs, ARRAYSIZE(addrtlvs));
 
   BEGIN_TESTING(clear_elements);
index 3a0bc4e..8fb3527 100644 (file)
@@ -126,6 +126,7 @@ static void addAddresses(struct rfc5444_writer *wr) {
   CHECK_TRUE(0 == netaddr_from_string(&ip, "fe80::1234:5678:9abc:def0"), "failed to initialize ip");
   addr = rfc5444_writer_add_address(wr, cpr.creator, &ip, false);
   rfc5444_writer_add_addrtlv(wr, addr, &addrtlvs[1], &value1, 1, false);
+
 }
 
 static void write_packet(struct rfc5444_writer *w __attribute__ ((unused)),
@@ -146,7 +147,11 @@ static void write_packet(struct rfc5444_writer *w __attribute__ ((unused)),
   printf("\n");
 
   abuf_init(&out);
+  rfc5444_print_raw(&out, buf, length);
+#if 0
+  abuf_puts(&out, "\n\n\n");
   rfc5444_print_direct(&out, buf, length);
+#endif
 
   printf("%s\n", abuf_getptr(&out));
   abuf_free(&out);
@@ -181,9 +186,6 @@ int main(int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))
   msg = rfc5444_writer_register_message(&writer, MSG_TYPE, false);
   msg->addMessageHeader = addMessageHeader;
 
-  rfc5444_writer_register_addrtlvtype(&writer, &addrtlvs[0], MSG_TYPE);
-  rfc5444_writer_register_addrtlvtype(&writer, &addrtlvs[1], MSG_TYPE);
-
   rfc5444_writer_register_msgcontentprovider(&writer, &cpr, addrtlvs, ARRAYSIZE(addrtlvs));
 
   BEGIN_TESTING(clear_elements);
index 1b17f25..3439970 100644 (file)
@@ -145,7 +145,10 @@ static void write_packet(struct rfc5444_writer *w __attribute__ ((unused)),
 
   printf("Packet send with %zu bytes\n", length);
   abuf_hexdump(&dumpbuf, "", buffer, length);
+  rfc5444_print_raw(&dumpbuf, buffer, length);
+#if 0
   rfc5444_print_direct(&dumpbuf, buffer, length);
+#endif
   printf("%s", dumpbuf._buf);
   abuf_clear(&dumpbuf);
  }