print-olsr: Add basic IPv6 support.

Unfortunately OLSR uses the same IDs for IPv4 and IPv6 packets, even
though the size of "messages" differ. The version of the internet protocol
is therefore handed to the "olsr_print" function.

The code isn't very nice, due to a high density of #ifdef INET6'es. If
IPv6-support really should be optional, I'm afraid this is inevitable.
Both, compilation with and without IPv6 support has been tested.

The patch addresses fixes other issues, too. The length given in the packet
was used for pointer arithmetic without checking if the value was in a
reasonable range first in several places. It should now be possible to
decode more than one "namespace message" within a single packet. Other
changes remove trailing whitespace or fix lines indented with tabs (the
majority of the file is indented using spaces).

Signed-off-by: Florian Forster <octo@leeloo.lan.home.verplant.org>
diff --git a/CREDITS b/CREDITS
index fb9065e..aa43b92 100644
--- a/CREDITS
+++ b/CREDITS
@@ -51,6 +51,7 @@
 	Eddie Kohler			<xexd at sourceforge dot net>
 	Elmar Kirchner			<elmar at juniper dot net>
 	Florent Drouin			<Florent dot Drouin at alcatel-lucent dot fr>
+	Florian Forster			<octo at verplant dot org>
 	Francis Dupont			<Francis dot Dupont at enst-bretagne dot fr>
 	Francisco Matias Cuenca-Acuna	<mcuenca at george dot rutgers dot edu>
 	Francois-Xavier Le Bail		<fx dot lebail at yahoo dot com>
diff --git a/interface.h b/interface.h
index f6a4a19..afeaee9 100644
--- a/interface.h
+++ b/interface.h
@@ -229,7 +229,7 @@
 extern void ntp_print(const u_char *, u_int);
 extern u_int null_if_print(const struct pcap_pkthdr *, const u_char *);
 extern void ospf_print(const u_char *, u_int, const u_char *);
-extern void olsr_print (const u_char *, u_int);
+extern void olsr_print (const u_char *, u_int, int);
 extern void pimv1_print(const u_char *, u_int);
 extern void cisco_autorp_print(const u_char *, u_int);
 extern void rsvp_print(const u_char *, u_int);
diff --git a/print-olsr.c b/print-olsr.c
index 599fb1f..07a04b5 100644
--- a/print-olsr.c
+++ b/print-olsr.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 1998-2007 The TCPDUMP project
+ * Copyright (c) 2009  Florian Forster
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that: (1) source code
@@ -15,6 +16,7 @@
  * Optimized Link State Protocl (OLSR) as per rfc3626
  *
  * Original code by Hannes Gredler <hannes@juniper.net>
+ * IPv6 additions by Florian Forster <octo at verplant.org>
  */
 
 #ifdef HAVE_CONFIG_H
@@ -88,7 +90,7 @@
     { 0, NULL}
 };
 
-struct olsr_msg {
+struct olsr_msg4 {
     u_int8_t msg_type;
     u_int8_t vtime;
     u_int8_t msg_len[2];
@@ -98,6 +100,16 @@
     u_int8_t msg_seq[2];
 };
 
+struct olsr_msg6 {
+    u_int8_t msg_type;
+    u_int8_t vtime;
+    u_int8_t msg_len[2];
+    u_int8_t originator[16];
+    u_int8_t ttl;
+    u_int8_t hopcount;
+    u_int8_t msg_seq[2];
+};
+
 struct olsr_hello {
     u_int8_t res[2];
     u_int8_t htime;
@@ -115,11 +127,16 @@
     u_int8_t res[2];
 };
 
-struct olsr_hna {
+struct olsr_hna4 {
     u_int8_t network[4];
     u_int8_t mask[4];
 };
 
+struct olsr_hna6 {
+    u_int8_t network[16];
+    u_int8_t mask[16];
+};
+
 
 #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3)
 #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2)
@@ -139,13 +156,20 @@
     { 0, NULL}
 };
 
-struct olsr_lq_neighbor {
+struct olsr_lq_neighbor4 {
     u_int8_t neighbor[4];
     u_int8_t link_quality;
     u_int8_t neighbor_link_quality;
     u_int8_t res[2];
 };
 
+struct olsr_lq_neighbor6 {
+    u_int8_t neighbor[16];
+    u_int8_t link_quality;
+    u_int8_t neighbor_link_quality;
+    u_int8_t res[2];
+};
+
 /*
  * macro to convert the 8-bit mantissa/exponent to a double float
  * taken from olsr.org.
@@ -158,13 +182,13 @@
  * print a neighbor list with LQ extensions.
  */
 static void
-olsr_print_lq_neighbor (const u_char *msg_data, u_int hello_len)
+olsr_print_lq_neighbor4 (const u_char *msg_data, u_int hello_len)
 {
-    struct olsr_lq_neighbor *lq_neighbor;
+    struct olsr_lq_neighbor4 *lq_neighbor;
 
-    while (hello_len >= sizeof(struct olsr_lq_neighbor)) {
+    while (hello_len >= sizeof(struct olsr_lq_neighbor4)) {
 
-        lq_neighbor = (struct olsr_lq_neighbor *)msg_data;
+        lq_neighbor = (struct olsr_lq_neighbor4 *)msg_data;
 
         printf("\n\t      neighbor %s, link-quality %.2lf%%"
                ", neighbor-link-quality %.2lf%%",
@@ -172,11 +196,33 @@
                ((double)lq_neighbor->link_quality/2.55),
                ((double)lq_neighbor->neighbor_link_quality/2.55));
 
-        msg_data += sizeof(struct olsr_lq_neighbor);
-        hello_len -= sizeof(struct olsr_lq_neighbor);
+        msg_data += sizeof(struct olsr_lq_neighbor4);
+        hello_len -= sizeof(struct olsr_lq_neighbor4);
     }
 }
 
+#if INET6
+static void
+olsr_print_lq_neighbor6 (const u_char *msg_data, u_int hello_len)
+{
+    struct olsr_lq_neighbor6 *lq_neighbor;
+
+    while (hello_len >= sizeof(struct olsr_lq_neighbor6)) {
+
+        lq_neighbor = (struct olsr_lq_neighbor6 *)msg_data;
+
+        printf("\n\t      neighbor %s, link-quality %.2lf%%"
+               ", neighbor-link-quality %.2lf%%",
+               ip6addr_string(lq_neighbor->neighbor),
+               ((double)lq_neighbor->link_quality/2.55),
+               ((double)lq_neighbor->neighbor_link_quality/2.55));
+
+        msg_data += sizeof(struct olsr_lq_neighbor6);
+        hello_len -= sizeof(struct olsr_lq_neighbor6);
+    }
+}
+#endif /* INET6 */
+
 /*
  * print a neighbor list.
  */
@@ -202,20 +248,20 @@
 
 
 void
-olsr_print (const u_char *pptr, u_int length)
+olsr_print (const u_char *pptr, u_int length, int is_ipv6)
 {
     union {
         const struct olsr_common *common;
-        const struct olsr_msg *msg;
+        const struct olsr_msg4 *msg4;
+        const struct olsr_msg6 *msg6;
         const struct olsr_hello *hello;
         const struct olsr_hello_link *hello_link;
-        const struct olsr_lq_neighbor *lq_neighbor;
         const struct olsr_tc *tc;
-        const struct olsr_hna *hna;
+        const struct olsr_hna4 *hna;
     } ptr;
 
-    u_int msg_type, msg_len, msg_tlen, hello_len, prefix;
-    u_int16_t name_entries, name_entry_type, name_entry_len;
+    u_int msg_type, msg_len, msg_tlen, hello_len;
+    u_int16_t name_entry_type, name_entry_len;
     u_int8_t link_type, neighbor_type;
     const u_char *tptr, *msg_data;
 
@@ -226,15 +272,16 @@
     }
 
     if (!TTEST2(*tptr, sizeof(struct olsr_common))) {
-	goto trunc;
+        goto trunc;
     }
 
     ptr.common = (struct olsr_common *)tptr;
     length = MIN(length, EXTRACT_16BITS(ptr.common->packet_len));
 
-    printf("OLSR, seq 0x%04x, length %u",
-           EXTRACT_16BITS(ptr.common->packet_seq),
-           length);
+    printf("OLSRv%i, seq 0x%04x, length %u",
+            (is_ipv6 == 0) ? 4 : 6,
+            EXTRACT_16BITS(ptr.common->packet_seq),
+            length);
 
     tptr += sizeof(struct olsr_common);
 
@@ -242,36 +289,76 @@
      * In non-verbose mode, just print version.
      */
     if (vflag < 1) {
-	return;
+        return;
     }
 
     while (tptr < (pptr+length)) {
+        union
+        {
+            struct olsr_msg4 *v4;
+            struct olsr_msg6 *v6;
+        } msgptr;
+        int msg_len_valid = 0;
 
-        if (!TTEST2(*tptr, sizeof(struct olsr_msg)))
+        if (!TTEST2(*tptr, sizeof(struct olsr_msg4)))
             goto trunc;
 
-        ptr.msg = (struct olsr_msg *)tptr;
+#if INET6
+        if (is_ipv6)
+        {
+            msgptr.v6 = (struct olsr_msg6 *) tptr;
+            msg_type = msgptr.v6->msg_type;
+            msg_len = EXTRACT_16BITS(msgptr.v6->msg_len);
+            if ((msg_len >= sizeof (struct olsr_msg6))
+                    && (msg_len <= length))
+                msg_len_valid = 1;
 
-        msg_type = ptr.msg->msg_type;
-        msg_len = EXTRACT_16BITS(ptr.msg->msg_len);
+            /* infinite loop check */
+            if (msg_type == 0 || msg_len == 0) {
+                return;
+            }
 
-        /* infinite loop check */
-        if (msg_type == 0 || msg_len == 0) {
-            return;
+            printf("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
+                    "\n\t  vtime %.3lfs, msg-seq 0x%04x, length %u%s",
+                    tok2str(olsr_msg_values, "Unknown", msg_type),
+                    msg_type, ip6addr_string(msgptr.v6->originator),
+                    msgptr.v6->ttl,
+                    msgptr.v6->hopcount,
+                    ME_TO_DOUBLE(msgptr.v6->vtime),
+                    EXTRACT_16BITS(msgptr.v6->msg_seq),
+                    msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
+
+            msg_tlen = msg_len - sizeof(struct olsr_msg6);
+            msg_data = tptr + sizeof(struct olsr_msg6);
         }
+        else /* (!is_ipv6) */
+#endif /* INET6 */
+        {
+            msgptr.v4 = (struct olsr_msg4 *) tptr;
+            msg_type = msgptr.v4->msg_type;
+            msg_len = EXTRACT_16BITS(msgptr.v4->msg_len);
+            if ((msg_len >= sizeof (struct olsr_msg4))
+                    && (msg_len <= length))
+                msg_len_valid = 1;
 
-        printf("\n\t%s Message (%u), originator %s, ttl %u, hop %u"
-               "\n\t  vtime %.3lfs, msg-seq 0x%04x, length %u",
-               tok2str(olsr_msg_values, "Unknown", msg_type),
-               msg_type, ipaddr_string(ptr.msg->originator),
-               ptr.msg->ttl,
-               ptr.msg->hopcount,
-               ME_TO_DOUBLE(ptr.msg->vtime),
-               EXTRACT_16BITS(ptr.msg->msg_seq),
-               msg_len);
+            /* infinite loop check */
+            if (msg_type == 0 || msg_len == 0) {
+                return;
+            }
 
-        msg_tlen = msg_len - sizeof(struct olsr_msg);
-        msg_data = tptr + sizeof(struct olsr_msg);
+            printf("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u"
+                    "\n\t  vtime %.3lfs, msg-seq 0x%04x, length %u%s",
+                    tok2str(olsr_msg_values, "Unknown", msg_type),
+                    msg_type, ipaddr_string(msgptr.v4->originator),
+                    msgptr.v4->ttl,
+                    msgptr.v4->hopcount,
+                    ME_TO_DOUBLE(msgptr.v4->vtime),
+                    EXTRACT_16BITS(msgptr.v4->msg_seq),
+                    msg_len, (msg_len_valid == 0) ? " (invalid)" : "");
+
+            msg_tlen = msg_len - sizeof(struct olsr_msg4);
+            msg_data = tptr + sizeof(struct olsr_msg4);
+        }
 
         switch (msg_type) {
         case OLSR_HELLO_MSG:
@@ -320,7 +407,12 @@
                 if (msg_type == OLSR_HELLO_MSG) {
                     olsr_print_neighbor(msg_data, hello_len);
                 } else {
-                    olsr_print_lq_neighbor(msg_data, hello_len);
+#if INET6
+                    if (is_ipv6)
+                        olsr_print_lq_neighbor6(msg_data, hello_len);
+                    else
+#endif
+                        olsr_print_lq_neighbor4(msg_data, hello_len);
                 }
 
                 msg_data += hello_len;
@@ -342,74 +434,159 @@
             if (msg_type == OLSR_TC_MSG) {
                 olsr_print_neighbor(msg_data, msg_tlen);
             } else {
-                olsr_print_lq_neighbor(msg_data, msg_tlen);
+#if INET6
+                if (is_ipv6)
+                    olsr_print_lq_neighbor6(msg_data, msg_tlen);
+                else
+#endif
+                    olsr_print_lq_neighbor4(msg_data, msg_tlen);
             }
             break;
 
         case OLSR_MID_MSG:
-            if (!TTEST2(*msg_data, sizeof(struct in_addr)))
+        {
+            size_t addr_size = sizeof(struct in_addr);
+
+#if INET6
+            if (is_ipv6)
+                addr_size = sizeof(struct in6_addr);
+#endif
+
+            if (!TTEST2(*msg_data, addr_size))
                 goto trunc;
 
-            while (msg_tlen >= sizeof(struct in_addr)) {
-                printf("\n\t  interface address %s", ipaddr_string(msg_data));
-                msg_data += sizeof(struct in_addr);
-                msg_tlen -= sizeof(struct in_addr);
+            while (msg_tlen >= addr_size) {
+                printf("\n\t  interface address %s",
+#if INET6
+                        is_ipv6 ? ip6addr_string(msg_data) :
+#endif
+                        ipaddr_string(msg_data));
+                msg_data += addr_size;
+                msg_tlen -= addr_size;
             }
             break;
+        }
 
         case OLSR_HNA_MSG:
-            prefix = 1;
-            printf("\n\t  advertised networks\n\t    ");
-            while (msg_tlen >= sizeof(struct olsr_hna)) {
-                if (!TTEST2(*msg_data, sizeof(struct olsr_hna)))
-                    goto trunc;
+            printf("\n\t  Advertised networks (total %u)",
+                    (unsigned int) (msg_tlen / sizeof(struct olsr_hna6)));
+#if INET6
+            if (is_ipv6)
+            {
+                int i = 0;
+                while (msg_tlen >= sizeof(struct olsr_hna6)) {
+                    struct olsr_hna6 *hna6;
 
-                ptr.hna = (struct olsr_hna *)msg_data;
+                    if (!TTEST2(*msg_data, sizeof(struct olsr_hna6)))
+                        goto trunc;
 
-                /* print 4 prefixes per line */
+                    hna6 = (struct olsr_hna6 *)msg_data;
 
-                printf("%s/%u%s",
-                       ipaddr_string(ptr.hna->network),
-                       mask2plen(EXTRACT_32BITS(ptr.hna->mask)),
-                       prefix % 4 == 0 ? "\n\t    " : " ");
+                    printf("\n\t    #%i: %s/%u",
+                            i, ip6addr_string(hna6->network),
+                            mask62plen (hna6->mask));
 
-                msg_data += sizeof(struct olsr_hna);
-                msg_tlen -= sizeof(struct olsr_hna);
-                prefix ++;
+                    msg_data += sizeof(struct olsr_hna6);
+                    msg_tlen -= sizeof(struct olsr_hna6);
+                }
+            }
+            else
+#endif
+            {
+                int col = 0;
+                while (msg_tlen >= sizeof(struct olsr_hna4)) {
+                    if (!TTEST2(*msg_data, sizeof(struct olsr_hna4)))
+                        goto trunc;
+
+                    ptr.hna = (struct olsr_hna4 *)msg_data;
+
+                    /* print 4 prefixes per line */
+                    if (col == 0)
+                        printf ("\n\t    ");
+                    else
+                        printf (", ");
+
+                    printf("%s/%u",
+                            ipaddr_string(ptr.hna->network),
+                            mask2plen(EXTRACT_32BITS(ptr.hna->mask)));
+
+                    msg_data += sizeof(struct olsr_hna4);
+                    msg_tlen -= sizeof(struct olsr_hna4);
+
+                    col = (col + 1) % 4;
+                }
             }
             break;
 
         case OLSR_NAMESERVICE_MSG:
-            name_entries = EXTRACT_16BITS(msg_data+2);
-            printf("\n\t  Version %u, Entries %u",
-                   EXTRACT_16BITS(msg_data), name_entries);
+        {
+            u_int16_t name_entries = EXTRACT_16BITS(msg_data+2);
+            u_int16_t addr_size = 4;
+            int name_entries_valid = 0;
+            u_int16_t i;
+
+            if (is_ipv6)
+                addr_size = 16;
+
+            if ((name_entries > 0)
+                    && ((name_entries * (4 + addr_size)) <= msg_tlen))
+                name_entries_valid = 1;
+
+            printf("\n\t  Version %u, Entries %u%s",
+                   EXTRACT_16BITS(msg_data),
+                   name_entries, (name_entries_valid == 0) ? " (invalid)" : "");
+
+            if (name_entries_valid == 0)
+                break;
+
             msg_data += 4;
             msg_tlen -= 4;
 
-            while (name_entries && msg_tlen) {
+            for (i = 0; i < name_entries; i++) {
+                int name_entry_len_valid = 0;
+
+                if (msg_tlen < 4)
+                    break;
 
                 name_entry_type = EXTRACT_16BITS(msg_data);
                 name_entry_len = EXTRACT_16BITS(msg_data+2);
+
                 msg_data += 4;
                 msg_tlen -= 4;
 
-                printf("\n\t    #%u Name Entry, length %u",
-                       name_entry_type,
-                       name_entry_len);
+                if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen))
+                    name_entry_len_valid = 1;
 
-                printf(", originator %s", ipaddr_string(msg_data));
+                printf("\n\t    #%u: type %#06x, length %u%s",
+                        (unsigned int) i, name_entry_type,
+                        name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : "");
 
-                /* 32-bit alignement */
+                if (name_entry_len_valid == 0)
+                    break;
+
+                {
+                    char name[name_entry_len + 1];
+                    memcpy (name, msg_data + addr_size, name_entry_len);
+                    name[name_entry_len] = 0;
+#if INET6
+                    if (is_ipv6)
+                        printf(", address %s, name \"%s\"",
+                                ip6addr_string(msg_data), name);
+                    else
+#endif
+                        printf(", address %s, name \"%s\"",
+                                ipaddr_string(msg_data), name);
+                }
+
+                /* 32-bit alignment */
                 if (name_entry_len%4 != 0)
                     name_entry_len+=4-(name_entry_len%4);
 
-
-                msg_data += name_entry_len;
-                msg_tlen -= name_entry_len;
-
-                name_entries--;
-            }
+                msg_data += addr_size + name_entry_len;
+                msg_tlen -= addr_size + name_entry_len;
+            } /* for (i = 0; i < name_entries; i++) */
             break;
+        } /* case OLSR_NAMESERVICE_MSG */
 
             /*
              * FIXME those are the defined messages that lack a decoder
@@ -417,11 +594,11 @@
              */
         case OLSR_POWERINFO_MSG:
         default:
-	    print_unknown_data(msg_data, "\n\t    ", msg_tlen);
+            print_unknown_data(msg_data, "\n\t    ", msg_tlen);
             break;
-        }
+        } /* switch (msg_type) */
         tptr += msg_len;
-    }
+    } /* while (tptr < (pptr+length)) */
 
     return;
 
diff --git a/print-udp.c b/print-udp.c
index 5e564cd..0f1528e 100644
--- a/print-udp.c
+++ b/print-udp.c
@@ -672,11 +672,16 @@
 			hsrp_print((const u_char *)(up + 1), length);
 		else if (ISPORT(LWRES_PORT))
 			lwres_print((const u_char *)(up + 1), length);
-                else if (ISPORT(LDP_PORT))
+		else if (ISPORT(LDP_PORT))
 			ldp_print((const u_char *)(up + 1), length);
-                else if (ISPORT(OLSR_PORT))
-			olsr_print((const u_char *)(up + 1), length);
-                else if (ISPORT(MPLS_LSP_PING_PORT))
+		else if (ISPORT(OLSR_PORT))
+			olsr_print((const u_char *)(up + 1), length,
+#if INET6
+					(IP_V(ip) == 6) ? 1 : 0);
+#else
+					0);
+#endif
+		else if (ISPORT(MPLS_LSP_PING_PORT))
 			lspping_print((const u_char *)(up + 1), length);
 		else if (dport == BFD_CONTROL_PORT ||
 			 dport == BFD_ECHO_PORT )