]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-icmp6.c
Fix the pointer tests in the non-ndoified TTEST2() macro as well.
[tcpdump] / print-icmp6.c
index 485d0bbeaf82fb73b82f8de590d170aedc063d3e..24765381b654c5a611fb1f69834f102547e8ca41 100644 (file)
@@ -20,8 +20,8 @@
  */
 
 #ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.21 2000-08-30 14:28:44 itojun Exp $";
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 guy Exp $";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -30,191 +30,399 @@ static const char rcsid[] =
 
 #ifdef INET6
 
-#include <ctype.h>
-
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-#include <netinet/ip_var.h>
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
-#include <netinet/tcp.h>
-
-#include <arpa/inet.h>
+#include <tcpdump-stdinc.h>
 
 #include <stdio.h>
-
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
+#include <string.h>
 
 #include "interface.h"
 #include "addrtoname.h"
+#include "extract.h"
 
-void icmp6_opt_print(const u_char *, int);
-void mld6_print(const u_char *);
-#ifdef HAVE_STRUCT_ICMP6_NODEINFO
+#include "ip6.h"
+#include "icmp6.h"
+#include "ipproto.h"
+
+#include "udp.h"
+#include "ah.h"
+
+static const char *get_rtpref(u_int);
+static const char *get_lifetime(u_int32_t);
+static void print_lladdr(const u_char *, size_t);
+static void icmp6_opt_print(const u_char *, int);
+static void mld6_print(const u_char *);
+static void mldv2_report_print(const u_char *, u_int);
+static void mldv2_query_print(const u_char *, u_int);
+static struct udphdr *get_upperlayer(u_char *, u_int *);
 static void dnsname_print(const u_char *, const u_char *);
-void icmp6_nodeinfo_print(int, const u_char *, const u_char *);
-#endif
+static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *);
+static void icmp6_rrenum_print(const u_char *, const u_char *);
 
 #ifndef abs
 #define abs(a) ((0 < (a)) ? (a) : -(a))
 #endif
 
-#ifndef HAVE_STRUCT_ICMP6_NODEINFO
-struct icmp6_nodeinfo {
-       struct icmp6_hdr icmp6_ni_hdr;
-       u_int8_t icmp6_ni_nonce[8];
-       /* could be followed by reply data */
+/* inline the various RPL definitions */
+#define ND_RPL_MESSAGE 0x9B
+
+static struct tok icmp6_type_values[] = {
+    { ICMP6_DST_UNREACH, "destination unreachable"},
+    { ICMP6_PACKET_TOO_BIG, "packet too big"},
+    { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"},
+    { ICMP6_PARAM_PROB, "parameter problem"},
+    { ICMP6_ECHO_REQUEST, "echo request"},
+    { ICMP6_ECHO_REPLY, "echo reply"},
+    { MLD6_LISTENER_QUERY, "multicast listener query"},
+    { MLD6_LISTENER_REPORT, "multicast listener report"},
+    { MLD6_LISTENER_DONE, "multicast listener done"},
+    { ND_ROUTER_SOLICIT, "router solicitation"},
+    { ND_ROUTER_ADVERT, "router advertisement"},
+    { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"},
+    { ND_NEIGHBOR_ADVERT, "neighbor advertisement"},
+    { ND_REDIRECT, "redirect"},
+    { ICMP6_ROUTER_RENUMBERING, "router renumbering"},
+    { IND_SOLICIT, "inverse neighbor solicitation"},
+    { IND_ADVERT, "inverse neighbor advertisement"},
+    { MLDV2_LISTENER_REPORT, "multicast listener report v2"},
+    { ICMP6_HADISCOV_REQUEST, "ha discovery request"},
+    { ICMP6_HADISCOV_REPLY, "ha discovery reply"},
+    { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"},
+    { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"},
+    { ICMP6_WRUREQUEST, "who-are-you request"},
+    { ICMP6_WRUREPLY, "who-are-you reply"},
+    { ICMP6_NI_QUERY, "node information query"},
+    { ICMP6_NI_REPLY, "node information reply"},
+    { MLD6_MTRACE, "mtrace message"},
+    { MLD6_MTRACE_RESP, "mtrace response"},
+    { ND_RPL_MESSAGE,   "RPL"},
+    { 0,       NULL }
 };
 
-#define ni_type                icmp6_ni_hdr.icmp6_type
-#define ni_code                icmp6_ni_hdr.icmp6_code
-#define ni_cksum       icmp6_ni_hdr.icmp6_cksum
-#define ni_qtype       icmp6_ni_hdr.icmp6_data16[0]
-#define ni_flags       icmp6_ni_hdr.icmp6_data16[1]
-#endif
+static struct tok icmp6_dst_unreach_code_values[] = {
+    { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" },
+    { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"},
+    { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"},
+    { ICMP6_DST_UNREACH_ADDR, "unreachable address"},
+    { ICMP6_DST_UNREACH_NOPORT, "unreachable port"},
+    { 0,       NULL }
+};
 
-/* cope with past KAME typo - shipped with freebsd4[01] and openbsd27 */
-#if defined(ICMP6_NI_SUCESS) && !defined(ICMP6_NI_SUCCESS)
-#define ICMP6_NI_SUCCESS       ICMP6_NI_SUCESS
-#endif
-#ifndef ICMP6_NI_SUCCESS
-#define ICMP6_NI_SUCCESS       0       /* node information successful reply */
-#define ICMP6_NI_REFUSED       1       /* node information request is refused */
-#define ICMP6_NI_UNKNOWN       2       /* unknown Qtype */
-#endif
+static struct tok icmp6_opt_pi_flag_values[] = {
+    { ND_OPT_PI_FLAG_ONLINK, "onlink" },
+    { ND_OPT_PI_FLAG_AUTO, "auto" },
+    { ND_OPT_PI_FLAG_ROUTER, "router" },
+    { 0,       NULL }
+};
 
-#ifdef NI_QTYPE_NOOP
-#define NI_QTYPE_NOOP          0 /* NOOP  */
-#define NI_QTYPE_SUPTYPES      1 /* Supported Qtypes */
-#define NI_QTYPE_FQDN          2 /* FQDN */
-#define NI_QTYPE_NODEADDR      3 /* Node Addresses. XXX: spec says 2, but it may be a typo... */
-#endif
+static struct tok icmp6_opt_ra_flag_values[] = {
+    { ND_RA_FLAG_MANAGED, "managed" },
+    { ND_RA_FLAG_OTHER, "other stateful"},
+    { ND_RA_FLAG_HOME_AGENT, "home agent"},
+    { 0,       NULL }
+};
+
+static struct tok icmp6_nd_na_flag_values[] = {
+    { ND_NA_FLAG_ROUTER, "router" },
+    { ND_NA_FLAG_SOLICITED, "solicited" },
+    { ND_NA_FLAG_OVERRIDE, "override" },
+    { 0,       NULL }
+};
+
+
+static struct tok icmp6_opt_values[] = {
+   { ND_OPT_SOURCE_LINKADDR, "source link-address"},
+   { ND_OPT_TARGET_LINKADDR, "destination link-address"},
+   { ND_OPT_PREFIX_INFORMATION, "prefix info"},
+   { ND_OPT_REDIRECTED_HEADER, "redirected header"},
+   { ND_OPT_MTU, "mtu"},
+   { ND_OPT_RDNSS, "rdnss"},
+   { ND_OPT_ADVINTERVAL, "advertisement interval"},
+   { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
+   { ND_OPT_ROUTE_INFO, "route info"},
+   { 0,        NULL }
+};
+
+/* mldv2 report types */
+static struct tok mldv2report2str[] = {
+       { 1,    "is_in" },
+       { 2,    "is_ex" },
+       { 3,    "to_in" },
+       { 4,    "to_ex" },
+       { 5,    "allow" },
+       { 6,    "block" },
+       { 0,    NULL }
+};
+
+static const char *
+get_rtpref(u_int v)
+{
+       static const char *rtpref_str[] = {
+               "medium",               /* 00 */
+               "high",                 /* 01 */
+               "rsv",                  /* 10 */
+               "low"                   /* 11 */
+       };
+
+       return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff];
+}
+
+static const char *
+get_lifetime(u_int32_t v)
+{
+       static char buf[20];
+
+       if (v == (u_int32_t)~0UL)
+               return "infinity";
+       else {
+               snprintf(buf, sizeof(buf), "%u", v);
+               return buf;
+       }
+}
+
+static void
+print_lladdr(const u_int8_t *p, size_t l)
+{
+       const u_int8_t *ep, *q;
+
+       q = p;
+       ep = p + l;
+       while (l > 0 && q < ep) {
+               if (q > p)
+                       printf(":");
+               printf("%02x", *q++);
+               l--;
+       }
+}
+
+static int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp,
+       u_int len)
+{
+       size_t i;
+       register const u_int16_t *sp;
+       u_int32_t sum;
+       union {
+               struct {
+                       struct in6_addr ph_src;
+                       struct in6_addr ph_dst;
+                       u_int32_t       ph_len;
+                       u_int8_t        ph_zero[3];
+                       u_int8_t        ph_nxt;
+               } ph;
+               u_int16_t pa[20];
+       } phu;
+
+       /* pseudo-header */
+       memset(&phu, 0, sizeof(phu));
+       phu.ph.ph_src = ip6->ip6_src;
+       phu.ph.ph_dst = ip6->ip6_dst;
+       phu.ph.ph_len = htonl(len);
+       phu.ph.ph_nxt = IPPROTO_ICMPV6;
+
+       sum = 0;
+       for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
+               sum += phu.pa[i];
+
+       sp = (const u_int16_t *)icp;
+
+       for (i = 0; i < (len & ~1); i += 2)
+               sum += *sp++;
+
+       if (len & 1)
+               sum += htons((*(const u_int8_t *)sp) << 8);
+
+       while (sum > 0xffff)
+               sum = (sum & 0xffff) + (sum >> 16);
+       sum = ~sum & 0xffff;
+
+       return (sum);
+}
+
+enum ND_RPL_CODE {
+        ND_RPL_DAG_IS=0x01,
+        ND_RPL_DAG_IO=0x02,
+        ND_RPL_DAO   =0x04
+};
+
+enum ND_RPL_DIO_FLAGS {
+        ND_RPL_DIO_GROUNDED = 0x80,
+        ND_RPL_DIO_DATRIG   = 0x40,
+        ND_RPL_DIO_DASUPPORT= 0x20,
+        ND_RPL_DIO_RES4     = 0x10,
+        ND_RPL_DIO_RES3     = 0x08,
+        ND_RPL_DIO_PRF_MASK = 0x07,  /* 3-bit preference */
+};
+
+struct nd_rpl_dio {
+        u_int8_t rpl_flags;
+        u_int8_t rpl_seq;
+        u_int8_t rpl_instanceid;
+        u_int8_t rpl_dagrank;
+        u_int8_t rpl_dagid[16];
+};
+
+static void
+rpl_print(netdissect_options *ndo,
+          const struct icmp6_hdr *hdr,
+          const u_char *bp, u_int length _U_)
+{
+        struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp;
+
+        ND_TCHECK(dio->rpl_dagid);
+
+        switch(hdr->icmp6_code) {
+        case ND_RPL_DAG_IS:
+                ND_PRINT((ndo, ", DAG Information Solicitation"));
+                if(ndo->ndo_vflag) {
+                }
+                break;
+        case ND_RPL_DAG_IO:
+                ND_PRINT((ndo, ", DAG Information Object"));
+                if(ndo->ndo_vflag) {
+                        char dagid[65];
+                        char *d = dagid;
+                        int  i;
+                        for(i=0;i<16;i++) {
+                                if(isprint(dio->rpl_dagid[i])) {
+                                        *d++ = dio->rpl_dagid[i];
+                                } else {
+                                        int cnt=snprintf(d,4,"0x%02x",
+                                                         dio->rpl_dagid[i]);
+                                        d += cnt;
+                                }
+                        }
+                        *d++ = '\0';
+                        ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]",
+                                  dio->rpl_seq,
+                                  dio->rpl_instanceid,
+                                  dio->rpl_dagrank,
+                                  dagid));
+                }
+                break;
+        case ND_RPL_DAO:
+                ND_PRINT((ndo, ", Destination Advertisement Object"));
+                if(ndo->ndo_vflag) {
+                }
+                break;
+        default:
+                ND_PRINT((ndo, ", RPL message, unknown code %u",hdr->icmp6_code));
+                break;
+        }
+       return;
+trunc:
+       ND_PRINT((ndo," [|truncated]"));
+       return;
+        
+}
 
-#ifndef ICMP6_NI_SUBJ_IPV6
-#define ICMP6_NI_SUBJ_IPV6     0       /* Query Subject is an IPv6 address */
-#define ICMP6_NI_SUBJ_FQDN     1       /* Query Subject is a Domain name */
-#define ICMP6_NI_SUBJ_IPV4     2       /* Query Subject is an IPv4 address */
-#endif
 
 void
-icmp6_print(register const u_char *bp, register const u_char *bp2)
+icmp6_print(netdissect_options *ndo,
+            const u_char *bp, u_int length, const u_char *bp2, int fragmented)
 {
        const struct icmp6_hdr *dp;
-       register const struct ip6_hdr *ip;
-       register const char *str;
-       register const struct ip6_hdr *oip;
-       register const struct udphdr *ouh;
-       register int hlen, dport;
-       register const u_char *ep;
-       char buf[256];
-       int icmp6len;
-
-#if 0
-#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
-#endif
+       const struct ip6_hdr *ip;
+       const struct ip6_hdr *oip;
+       const struct udphdr *ouh;
+       int dport;
+       const u_char *ep;
+       u_int prot;
 
        dp = (struct icmp6_hdr *)bp;
        ip = (struct ip6_hdr *)bp2;
        oip = (struct ip6_hdr *)(dp + 1);
-       str = buf;
-       /* 'ep' points to the end of avaible data. */
+       /* 'ep' points to the end of available data. */
        ep = snapend;
-       if (ip->ip6_plen)
-               icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
-                           (bp - bp2));
-       else                    /* XXX: jumbo payload case... */
-               icmp6len = snapend - bp;
-
-#if 0
-       (void)printf("%s > %s: ",
-               ip6addr_string(&ip->ip6_src),
-               ip6addr_string(&ip->ip6_dst));
-#endif
 
-       TCHECK(dp->icmp6_code);
+       TCHECK(dp->icmp6_cksum);
+
+       if (vflag && !fragmented) {
+               int sum = dp->icmp6_cksum;
+
+               if (TTEST2(bp[0], length)) {
+                       sum = icmp6_cksum(ip, dp, length);
+                       if (sum != 0)
+                               (void)printf("[bad icmp6 cksum %x!] ", sum);
+                       else
+                               (void)printf("[icmp6 sum ok] ");
+               }
+       }
+
+        printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type));
+
+        /* display cosmetics: print the packet length for printer that use the vflag now */
+        if (vflag && (dp->icmp6_type == ND_ROUTER_SOLICIT ||
+                      dp->icmp6_type == ND_ROUTER_ADVERT ||
+                      dp->icmp6_type == ND_NEIGHBOR_ADVERT ||
+                      dp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
+                      dp->icmp6_type == ND_REDIRECT ||
+                      dp->icmp6_type == ICMP6_HADISCOV_REPLY ||
+                      dp->icmp6_type == ICMP6_MOBILEPREFIX_ADVERT ))
+            printf(", length %u", length);
+                      
        switch (dp->icmp6_type) {
        case ICMP6_DST_UNREACH:
                TCHECK(oip->ip6_dst);
+                printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code));
                switch (dp->icmp6_code) {
-               case ICMP6_DST_UNREACH_NOROUTE:
-                       printf("icmp6: %s unreachable route",
-                              ip6addr_string(&oip->ip6_dst));
-                       break;
+
+               case ICMP6_DST_UNREACH_NOROUTE: /* fall through */
                case ICMP6_DST_UNREACH_ADMIN:
-                       printf("icmp6: %s unreachable prohibited",
-                              ip6addr_string(&oip->ip6_dst));
-                       break;
-#ifdef ICMP6_DST_UNREACH_BEYONDSCOPE
+               case ICMP6_DST_UNREACH_ADDR:
+                        printf(" %s",ip6addr_string(&oip->ip6_dst));
+                        break;
                case ICMP6_DST_UNREACH_BEYONDSCOPE:
-#else
-               case ICMP6_DST_UNREACH_NOTNEIGHBOR:
-#endif
-                       printf("icmp6: %s beyond scope of source address %s",
+                       printf(" %s, source address %s",
                               ip6addr_string(&oip->ip6_dst),
                               ip6addr_string(&oip->ip6_src));
                        break;
-               case ICMP6_DST_UNREACH_ADDR:
-                       printf("icmp6: %s unreachable address",
-                              ip6addr_string(&oip->ip6_dst));
-                       break;
                case ICMP6_DST_UNREACH_NOPORT:
-                       TCHECK(oip->ip6_nxt);
-                       hlen = sizeof(struct ip6_hdr);
-                       ouh = (struct udphdr *)(((u_char *)oip) + hlen);
-                       dport = ntohs(ouh->uh_dport);
-                       switch (oip->ip6_nxt) {
+                       if ((ouh = get_upperlayer((u_char *)oip, &prot))
+                           == NULL)
+                               goto trunc;
+
+                       dport = EXTRACT_16BITS(&ouh->uh_dport);
+                       switch (prot) {
                        case IPPROTO_TCP:
-                               printf("icmp6: %s tcp port %s unreachable",
+                               printf(", %s tcp port %s",
                                        ip6addr_string(&oip->ip6_dst),
                                        tcpport_string(dport));
                                break;
                        case IPPROTO_UDP:
-                               printf("icmp6: %s udp port %s unreachable",
+                               printf(", %s udp port %s",
                                        ip6addr_string(&oip->ip6_dst),
                                        udpport_string(dport));
                                break;
                        default:
-                               printf("icmp6: %s protocol %d port %d unreachable",
+                               printf(", %s protocol %d port %d unreachable",
                                        ip6addr_string(&oip->ip6_dst),
                                        oip->ip6_nxt, dport);
                                break;
                        }
                        break;
                default:
-                       printf("icmp6: %s unreachable code-#%d",
-                               ip6addr_string(&oip->ip6_dst),
-                               dp->icmp6_code);
-                       break;
+                    if (vflag <= 1) {
+                            print_unknown_data(bp,"\n\t",length);
+                            return;
+                    }
+                    break;
                }
                break;
        case ICMP6_PACKET_TOO_BIG:
                TCHECK(dp->icmp6_mtu);
-               printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu));
+               printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu));
                break;
        case ICMP6_TIME_EXCEEDED:
                TCHECK(oip->ip6_dst);
                switch (dp->icmp6_code) {
                case ICMP6_TIME_EXCEED_TRANSIT:
-                       printf("icmp6: time exceeded in-transit for %s",
+                       printf(" for %s",
                                ip6addr_string(&oip->ip6_dst));
                        break;
                case ICMP6_TIME_EXCEED_REASSEMBLY:
-                       printf("icmp6: ip6 reassembly time exceeded");
+                       printf(" (reassembly)");
                        break;
                default:
-                       printf("icmp6: time exceeded code-#%d",
-                               dp->icmp6_code);
+                       printf(", unknown code (%u)", dp->icmp6_code);
                        break;
                }
                break;
@@ -222,78 +430,66 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
                TCHECK(oip->ip6_dst);
                switch (dp->icmp6_code) {
                case ICMP6_PARAMPROB_HEADER:
-                       printf("icmp6: parameter problem errorneous - octet %u\n",
-                               (u_int32_t)ntohl(dp->icmp6_pptr));
+                       printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
                        break;
                case ICMP6_PARAMPROB_NEXTHEADER:
-                       printf("icmp6: parameter problem next header - octet %u\n",
-                               (u_int32_t)ntohl(dp->icmp6_pptr));
+                       printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
                        break;
                case ICMP6_PARAMPROB_OPTION:
-                       printf("icmp6: parameter problem option - octet %u\n",
-                               (u_int32_t)ntohl(dp->icmp6_pptr));
+                       printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr));
                        break;
                default:
-                       printf("icmp6: parameter problem code-#%d",
+                       printf(", code-#%d",
                               dp->icmp6_code);
                        break;
                }
                break;
        case ICMP6_ECHO_REQUEST:
-               printf("icmp6: echo request");
-               break;
        case ICMP6_ECHO_REPLY:
-               printf("icmp6: echo reply");
+               TCHECK(dp->icmp6_seq);
+               printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq));
                break;
-#if defined(HAVE_STRUCT_MLD6_HDR) || defined(HAVE_STRUCT_ICMP6_MLD)
        case ICMP6_MEMBERSHIP_QUERY:
-               printf("icmp6: multicast listener query ");
-               mld6_print((const u_char *)dp);
+               if (length == MLD_MINLEN) {
+                       mld6_print((const u_char *)dp);
+               } else if (length >= MLDV2_MINLEN) {
+                       printf("v2 ");
+                       mldv2_query_print((const u_char *)dp, length);
+               } else {
+                       printf(" unknown-version (len %u) ", length);
+               }
                break;
        case ICMP6_MEMBERSHIP_REPORT:
-               printf("icmp6: multicast listener report ");
                mld6_print((const u_char *)dp);
                break;
        case ICMP6_MEMBERSHIP_REDUCTION:
-               printf("icmp6: multicast listener done ");
                mld6_print((const u_char *)dp);
                break;
-#endif
        case ND_ROUTER_SOLICIT:
-               printf("icmp6: router solicitation ");
-               if (vflag) {
 #define RTSOLLEN 8
+               if (vflag) {
                        icmp6_opt_print((const u_char *)dp + RTSOLLEN,
-                                       icmp6len - RTSOLLEN);
+                                       length - RTSOLLEN);
                }
                break;
        case ND_ROUTER_ADVERT:
-               printf("icmp6: router advertisement");
+#define RTADVLEN 16
                if (vflag) {
                        struct nd_router_advert *p;
 
                        p = (struct nd_router_advert *)dp;
                        TCHECK(p->nd_ra_retransmit);
-                       printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
-                       if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
-                               printf("M");
-                       if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
-                               printf("O");
-#ifndef ND_RA_FLAG_HA
-#define ND_RA_FLAG_HA  0x20
-#endif
-                       if (p->nd_ra_flags_reserved & ND_RA_FLAG_HA)
-                               printf("H");
-                       if (p->nd_ra_flags_reserved != 0)
-                               printf(" ");
-                       printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
-                       printf("reachable_time=%u, ",
-                               (u_int32_t)ntohl(p->nd_ra_reachable));
-                       printf("retrans_time=%u)",
-                               (u_int32_t)ntohl(p->nd_ra_retransmit));
-#define RTADVLEN 16
+                       printf("\n\thop limit %u, Flags [%s]" \
+                               ", pref %s, router lifetime %us, reachable time %us, retrans time %us",
+                               (u_int)p->nd_ra_curhoplimit,
+                               bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)),
+                               get_rtpref(p->nd_ra_flags_reserved),
+                               EXTRACT_16BITS(&p->nd_ra_router_lifetime),
+                               EXTRACT_32BITS(&p->nd_ra_reachable),
+                               EXTRACT_32BITS(&p->nd_ra_retransmit));
+
                        icmp6_opt_print((const u_char *)dp + RTADVLEN,
-                                       icmp6len - RTADVLEN);
+                                       length - RTADVLEN);
                }
                break;
        case ND_NEIGHBOR_SOLICIT:
@@ -301,12 +497,11 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
                struct nd_neighbor_solicit *p;
                p = (struct nd_neighbor_solicit *)dp;
                TCHECK(p->nd_ns_target);
-               printf("icmp6: neighbor sol: who has %s",
-                       ip6addr_string(&p->nd_ns_target));
+               printf(", who has %s", ip6addr_string(&p->nd_ns_target));
                if (vflag) {
 #define NDSOLLEN 24
                        icmp6_opt_print((const u_char *)dp + NDSOLLEN,
-                                       icmp6len - NDSOLLEN);
+                                       length - NDSOLLEN);
                }
            }
                break;
@@ -316,29 +511,16 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
 
                p = (struct nd_neighbor_advert *)dp;
                TCHECK(p->nd_na_target);
-               printf("icmp6: neighbor adv: tgt is %s",
+               printf(", tgt is %s",
                        ip6addr_string(&p->nd_na_target));
                if (vflag) {
-#define ND_NA_FLAG_ALL \
-       (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
-                       /* we don't need ntohl() here.  see advanced-api-04. */
-                       if (p->nd_na_flags_reserved &  ND_NA_FLAG_ALL) {
-#undef ND_NA_FLAG_ALL
-                               u_int32_t flags;
-
-                               flags = p->nd_na_flags_reserved;
-                               printf("(");
-                               if (flags & ND_NA_FLAG_ROUTER)
-                                       printf("R");
-                               if (flags & ND_NA_FLAG_SOLICITED)
-                                       printf("S");
-                               if (flags & ND_NA_FLAG_OVERRIDE)
-                                       printf("O");
-                               printf(")");
-                       }
+                        printf(", Flags [%s]",
+                               bittok2str(icmp6_nd_na_flag_values,
+                                          "none",
+                                          EXTRACT_32BITS(&p->nd_na_flags_reserved)));
 #define NDADVLEN 24
                        icmp6_opt_print((const u_char *)dp + NDADVLEN,
-                                       icmp6len - NDADVLEN);
+                                       length - NDADVLEN);
 #undef NDADVLEN
                }
            }
@@ -346,240 +528,440 @@ icmp6_print(register const u_char *bp, register const u_char *bp2)
        case ND_REDIRECT:
 #define RDR(i) ((struct nd_redirect *)(i))
                TCHECK(RDR(dp)->nd_rd_dst);
-               printf("icmp6: redirect %s",
-                   getname6((const u_char *)&RDR(dp)->nd_rd_dst));
+               printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst));
+               TCHECK(RDR(dp)->nd_rd_target);
                printf(" to %s",
                    getname6((const u_char*)&RDR(dp)->nd_rd_target));
 #define REDIRECTLEN 40
                if (vflag) {
                        icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
-                                       icmp6len - REDIRECTLEN);
+                                       length - REDIRECTLEN);
                }
                break;
 #undef REDIRECTLEN
 #undef RDR
-#ifndef ICMP6_ROUTER_RENUMBERING
-#define ICMP6_ROUTER_RENUMBERING       138     /* router renumbering */
-#endif
        case ICMP6_ROUTER_RENUMBERING:
-               switch (dp->icmp6_code) {
-#ifndef ICMP6_ROUTER_RENUMBERING_COMMAND
-#define ICMP6_ROUTER_RENUMBERING_COMMAND  0    /* rr command */
-#endif
-               case ICMP6_ROUTER_RENUMBERING_COMMAND:
-                       printf("icmp6: router renum command");
-                       break;
-#ifndef ICMP6_ROUTER_RENUMBERING_RESULT
-#define ICMP6_ROUTER_RENUMBERING_RESULT   1    /* rr result */
-#endif
-               case ICMP6_ROUTER_RENUMBERING_RESULT:
-                       printf("icmp6: router renum result");
-                       break;
-               default:
-                       printf("icmp6: router renum code-#%d", dp->icmp6_code);
-                       break;
-               }
+               icmp6_rrenum_print(bp, ep);
                break;
-#ifdef HAVE_STRUCT_ICMP6_NODEINFO
-#ifndef ICMP6_NI_QUERY
-#define ICMP6_NI_QUERY 139
-#endif
        case ICMP6_NI_QUERY:
-               icmp6_nodeinfo_print(icmp6len, bp, ep);
-               break;
-#ifndef ICMP6_NI_REPLY
-#define ICMP6_NI_REPLY 140
-#endif
        case ICMP6_NI_REPLY:
-               icmp6_nodeinfo_print(icmp6len, bp, ep);
+               icmp6_nodeinfo_print(length, bp, ep);
                break;
-#endif
-       default:
-               printf("icmp6: type-#%d", dp->icmp6_type);
+       case IND_SOLICIT:
+       case IND_ADVERT:
                break;
-       }
+       case ICMP6_V2_MEMBERSHIP_REPORT:
+               mldv2_report_print((const u_char *) dp, length);
+               break;
+       case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */
+       case ICMP6_HADISCOV_REQUEST:
+                TCHECK(dp->icmp6_data16[0]);
+                printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+                break;
+       case ICMP6_HADISCOV_REPLY:
+               if (vflag) {
+                       struct in6_addr *in6;
+                       u_char *cp;
+
+                       TCHECK(dp->icmp6_data16[0]);
+                       printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+                       cp = (u_char *)dp + length;
+                       in6 = (struct in6_addr *)(dp + 1);
+                       for (; (u_char *)in6 < cp; in6++) {
+                               TCHECK(*in6);
+                               printf(", %s", ip6addr_string(in6));
+                       }
+               }
+               break;
+       case ICMP6_MOBILEPREFIX_ADVERT:
+               if (vflag) {
+                       TCHECK(dp->icmp6_data16[0]);
+                       printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0]));
+                       if (dp->icmp6_data16[1] & 0xc0)
+                               printf(" ");
+                       if (dp->icmp6_data16[1] & 0x80)
+                               printf("M");
+                       if (dp->icmp6_data16[1] & 0x40)
+                               printf("O");
+#define MPADVLEN 8
+                       icmp6_opt_print((const u_char *)dp + MPADVLEN,
+                                       length - MPADVLEN);
+               }
+               break;
+        case ND_RPL_MESSAGE:
+                rpl_print(ndo, dp, &dp->icmp6_data8[0], length);
+                break;
+       default:
+                printf(", length %u", length);
+                if (vflag <= 1)
+                    print_unknown_data(bp,"\n\t", length);
+                return;
+        }
+        if (!vflag)
+            printf(", length %u", length); 
        return;
 trunc:
        fputs("[|icmp6]", stdout);
-#if 0
-#undef TCHECK
-#endif
 }
 
-void
-icmp6_opt_print(register const u_char *bp, int resid)
+static struct udphdr *
+get_upperlayer(u_char *bp, u_int *prot)
 {
-       register const struct nd_opt_hdr *op;
-       register const struct nd_opt_hdr *opl;  /* why there's no struct? */
-       register const struct nd_opt_prefix_info *opp;
-       register const struct icmp6_opts_redirect *opr;
-       register const struct nd_opt_mtu *opm;
-       register const u_char *ep;
-       int     opts_len;
-#if 0
-       register const struct ip6_hdr *ip;
-       register const char *str;
-       register const struct ip6_hdr *oip;
-       register const struct udphdr *ouh;
-       register int hlen, dport;
-       char buf[256];
-#endif
+       const u_char *ep;
+       struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
+       struct udphdr *uh;
+       struct ip6_hbh *hbh;
+       struct ip6_frag *fragh;
+       struct ah *ah;
+       u_int nh;
+       int hlen;
+
+       /* 'ep' points to the end of available data. */
+       ep = snapend;
+
+       if (!TTEST(ip6->ip6_nxt))
+               return NULL;
+
+       nh = ip6->ip6_nxt;
+       hlen = sizeof(struct ip6_hdr);
+
+       while (bp < ep) {
+               bp += hlen;
+
+               switch(nh) {
+               case IPPROTO_UDP:
+               case IPPROTO_TCP:
+                       uh = (struct udphdr *)bp;
+                       if (TTEST(uh->uh_dport)) {
+                               *prot = nh;
+                               return(uh);
+                       }
+                       else
+                               return(NULL);
+                       /* NOTREACHED */
+
+               case IPPROTO_HOPOPTS:
+               case IPPROTO_DSTOPTS:
+               case IPPROTO_ROUTING:
+                       hbh = (struct ip6_hbh *)bp;
+                       if (!TTEST(hbh->ip6h_len))
+                               return(NULL);
+                       nh = hbh->ip6h_nxt;
+                       hlen = (hbh->ip6h_len + 1) << 3;
+                       break;
+
+               case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */
+                       fragh = (struct ip6_frag *)bp;
+                       if (!TTEST(fragh->ip6f_offlg))
+                               return(NULL);
+                       /* fragments with non-zero offset are meaningless */
+                       if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0)
+                               return(NULL);
+                       nh = fragh->ip6f_nxt;
+                       hlen = sizeof(struct ip6_frag);
+                       break;
+
+               case IPPROTO_AH:
+                       ah = (struct ah *)bp;
+                       if (!TTEST(ah->ah_len))
+                               return(NULL);
+                       nh = ah->ah_nxt;
+                       hlen = (ah->ah_len + 2) << 2;
+                       break;
+
+               default:        /* unknown or undecodable header */
+                       *prot = nh; /* meaningless, but set here anyway */
+                       return(NULL);
+               }
+       }
+
+       return(NULL);           /* should be notreached, though */
+}
+
+static void
+icmp6_opt_print(const u_char *bp, int resid)
+{
+       const struct nd_opt_hdr *op;
+       const struct nd_opt_hdr *opl;   /* why there's no struct? */
+       const struct nd_opt_prefix_info *opp;
+       const struct icmp6_opts_redirect *opr;
+       const struct nd_opt_mtu *opm;
+       const struct nd_opt_rdnss *oprd;
+       const struct nd_opt_advinterval *opa;
+       const struct nd_opt_homeagent_info *oph;
+       const struct nd_opt_route_info *opri;
+       const u_char *cp, *ep;
+       struct in6_addr in6, *in6p;
+       size_t l;
+       u_int i;
 
 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
 
-       op = (struct nd_opt_hdr *)bp;
-#if 0
-       ip = (struct ip6_hdr *)bp2;
-       oip = &dp->icmp6_ip6;
-       str = buf;
-#endif
-       /* 'ep' points to the end of avaible data. */
+       cp = bp;
+       /* 'ep' points to the end of available data. */
        ep = snapend;
 
-       ECHECK(op->nd_opt_len);
-       if (resid <= 0)
-               return;
-       switch (op->nd_opt_type) {
-       case ND_OPT_SOURCE_LINKADDR:
-               opl = (struct nd_opt_hdr *)op;
-#if 1
-               if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
+       while (cp < ep) {
+               op = (struct nd_opt_hdr *)cp;
+
+               ECHECK(op->nd_opt_len);
+               if (resid <= 0)
+                       return;
+               if (op->nd_opt_len == 0)
                        goto trunc;
-#else
-               TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
-#endif
-               printf("(src lladdr: %s",       /*)*/
-                       etheraddr_string((u_char *)(opl + 1)));
-               if (opl->nd_opt_len != 1)
-                       printf("!");
-               /*(*/
-               printf(")");
-               icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
-                               resid - (op->nd_opt_len << 3));
-               break;
-       case ND_OPT_TARGET_LINKADDR:
-               opl = (struct nd_opt_hdr *)op;
-#if 1
-               if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
+               if (cp + (op->nd_opt_len << 3) > ep)
                        goto trunc;
-#else
-               TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
-#endif
-               printf("(tgt lladdr: %s",       /*)*/
-                       etheraddr_string((u_char *)(opl + 1)));
-               if (opl->nd_opt_len != 1)
-                       printf("!");
-               /*(*/
-               printf(")");
-               icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
-                               resid - (op->nd_opt_len << 3));
-               break;
-       case ND_OPT_PREFIX_INFORMATION:
-               opp = (struct nd_opt_prefix_info *)op;
-               TCHECK(opp->nd_opt_pi_prefix);
-               printf("(prefix info: ");       /*)*/
-               if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
-                      printf("L");
-               if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
-                      printf("A");
-               if (opp->nd_opt_pi_flags_reserved)
-                       printf(" ");
-               printf("valid_ltime=");
-               if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
-                       printf("infinity");
-               else {
-                       printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
-               }
-               printf(", ");
-               printf("preffered_ltime=");
-               if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
-                       printf("infinity");
-               else {
-                       printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
+
+                printf("\n\t  %s option (%u), length %u (%u): ",
+                       tok2str(icmp6_opt_values, "unknown", op->nd_opt_type),
+                       op->nd_opt_type,
+                       op->nd_opt_len << 3,
+                       op->nd_opt_len);
+
+               switch (op->nd_opt_type) {
+               case ND_OPT_SOURCE_LINKADDR:
+                       opl = (struct nd_opt_hdr *)op;
+                       l = (op->nd_opt_len << 3) - 2;
+                       print_lladdr(cp + 2, l);
+                       break;
+               case ND_OPT_TARGET_LINKADDR:
+                       opl = (struct nd_opt_hdr *)op;
+                       l = (op->nd_opt_len << 3) - 2;
+                       print_lladdr(cp + 2, l);
+                       break;
+               case ND_OPT_PREFIX_INFORMATION:
+                       opp = (struct nd_opt_prefix_info *)op;
+                       TCHECK(opp->nd_opt_pi_prefix);
+                        printf("%s/%u%s, Flags [%s], valid time %ss",
+                               ip6addr_string(&opp->nd_opt_pi_prefix),
+                               opp->nd_opt_pi_prefix_len,
+                               (op->nd_opt_len != 4) ? "badlen" : "",
+                               bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved),
+                               get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time)));
+                        printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time)));
+                       break;
+               case ND_OPT_REDIRECTED_HEADER:
+                       opr = (struct icmp6_opts_redirect *)op;
+                        print_unknown_data(bp,"\n\t    ",op->nd_opt_len<<3);
+                       /* xxx */
+                       break;
+               case ND_OPT_MTU:
+                       opm = (struct nd_opt_mtu *)op;
+                       TCHECK(opm->nd_opt_mtu_mtu);
+                       printf(" %u%s",
+                               EXTRACT_32BITS(&opm->nd_opt_mtu_mtu),
+                               (op->nd_opt_len != 1) ? "bad option length" : "" );
+                        break;
+               case ND_OPT_RDNSS:
+                       oprd = (struct nd_opt_rdnss *)op;
+                       l = (op->nd_opt_len - 1) / 2;
+                       printf(" lifetime %us,", 
+                               EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)); 
+                       for (i = 0; i < l; i++) {
+                               TCHECK(oprd->nd_opt_rdnss_addr[i]);
+                               printf(" addr: %s", 
+                                   ip6addr_string(&oprd->nd_opt_rdnss_addr[i]));
+                       }
+                       break;
+               case ND_OPT_ADVINTERVAL:
+                       opa = (struct nd_opt_advinterval *)op;
+                       TCHECK(opa->nd_opt_adv_interval);
+                       printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval));
+                       break;
+               case ND_OPT_HOMEAGENT_INFO:
+                       oph = (struct nd_opt_homeagent_info *)op;
+                       TCHECK(oph->nd_opt_hai_lifetime);
+                       printf(" preference %u, lifetime %u",
+                               EXTRACT_16BITS(&oph->nd_opt_hai_preference),
+                               EXTRACT_16BITS(&oph->nd_opt_hai_lifetime));
+                       break;
+               case ND_OPT_ROUTE_INFO:
+                       opri = (struct nd_opt_route_info *)op;
+                       TCHECK(opri->nd_opt_rti_lifetime);
+                       memset(&in6, 0, sizeof(in6));
+                       in6p = (struct in6_addr *)(opri + 1);
+                       switch (op->nd_opt_len) {
+                       case 1:
+                               break;
+                       case 2:
+                               TCHECK2(*in6p, 8);
+                               memcpy(&in6, opri + 1, 8);
+                               break;
+                       case 3:
+                               TCHECK(*in6p);
+                               memcpy(&in6, opri + 1, sizeof(in6));
+                               break;
+                       default:
+                               goto trunc;
+                       }
+                       printf(" %s/%u", ip6addr_string(&in6),
+                           opri->nd_opt_rti_prefixlen);
+                       printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags));
+                       printf(", lifetime=%s",
+                           get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime)));
+                       break;
+               default:
+                        if (vflag <= 1) {
+                            print_unknown_data(cp+2,"\n\t  ", (op->nd_opt_len << 3) - 2); /* skip option header */
+                            return;
+                        }
+                        break;
                }
-               printf(", ");
-               printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
-                       opp->nd_opt_pi_prefix_len);
-               if (opp->nd_opt_pi_len != 4)
-                       printf("!");
-               /*(*/
-               printf(")");
-               icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
-                               resid - (op->nd_opt_len << 3));
-               break;
-       case ND_OPT_REDIRECTED_HEADER:
-               opr = (struct icmp6_opts_redirect *)op;
-               printf("(redirect)");
-               /* xxx */
-               icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
-                               resid - (op->nd_opt_len << 3));
-               break;
-       case ND_OPT_MTU:
-               opm = (struct nd_opt_mtu *)op;
-               TCHECK(opm->nd_opt_mtu_mtu);
-               printf("(mtu: ");       /*)*/
-               printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
-               if (opm->nd_opt_mtu_len != 1)
-                       printf("!");
-               printf(")");
-               icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
-                               resid - (op->nd_opt_len << 3));
-               break;
-       default:
-               opts_len = op->nd_opt_len;
-               printf("(unknwon opt_type=%d, opt_len=%d)",
-                      op->nd_opt_type, opts_len);
-               if (opts_len == 0)
-                       opts_len = 1; /* XXX */
-               icmp6_opt_print((const u_char *)op + (opts_len << 3),
-                               resid - (opts_len << 3));
-               break;
+                /* do we want to see an additional hexdump ? */
+                if (vflag> 1)
+                    print_unknown_data(cp+2,"\n\t    ", (op->nd_opt_len << 3) - 2); /* skip option header */
+
+               cp += op->nd_opt_len << 3;
+               resid -= op->nd_opt_len << 3;
        }
        return;
+
  trunc:
        fputs("[ndp opt]", stdout);
        return;
 #undef ECHECK
 }
 
-#if defined(HAVE_STRUCT_MLD6_HDR)
-void
-mld6_print(register const u_char *bp)
+static void
+mld6_print(const u_char *bp)
 {
-       register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
-       register const u_char *ep;
+       struct mld6_hdr *mp = (struct mld6_hdr *)bp;
+       const u_char *ep;
 
-       /* 'ep' points to the end of avaible data. */
+       /* 'ep' points to the end of available data. */
        ep = snapend;
 
        if ((u_char *)mp + sizeof(*mp) > ep)
                return;
 
-       printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
+       printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay));
        printf("addr: %s", ip6addr_string(&mp->mld6_addr));
 }
 
-#elif defined(HAVE_STRUCT_ICMP6_MLD)
-
-void
-mld6_print(register const u_char *bp)
+static void
+mldv2_report_print(const u_char *bp, u_int len)
 {
-       register struct icmp6_mld *mp = (struct icmp6_mld *)bp;
-       register const u_char *ep;
+    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
+    u_int group, nsrcs, ngroups;
+    u_int i, j;
 
-       /* 'ep' points to the end of avaible data. */
-       ep = snapend;
+    /* Minimum len is 8 */
+    if (len < 8) {
+       printf(" [invalid len %d]", len);
+       return;
+    }
 
-       if ((u_char *)mp + sizeof(*mp) > ep)
+    TCHECK(icp->icmp6_data16[1]);
+    ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
+    printf(", %d group record(s)", ngroups);
+    if (vflag > 0) {
+       /* Print the group records */
+       group = 8;
+        for (i = 0; i < ngroups; i++) {
+           /* type(1) + auxlen(1) + numsrc(2) + grp(16) */
+           if (len < group + 20) {
+               printf(" [invalid number of groups]");
                return;
-
-       printf("max resp delay: %d ", ntohs(mp->icmp6m_hdr.icmp6_maxdelay));
-       printf("addr: %s", ip6addr_string(&mp->icmp6m_group));
+           }
+            TCHECK2(bp[group + 4], sizeof(struct in6_addr));
+            printf(" [gaddr %s", ip6addr_string(&bp[group + 4]));
+           printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]",
+                                                               bp[group]));
+            nsrcs = (bp[group + 2] << 8) + bp[group + 3];
+           /* Check the number of sources and print them */
+           if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
+               printf(" [invalid number of sources %d]", nsrcs);
+               return;
+           }
+            if (vflag == 1)
+                printf(", %d source(s)", nsrcs);
+            else {
+               /* Print the sources */
+                (void)printf(" {");
+                for (j = 0; j < nsrcs; j++) {
+                    TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)],
+                            sizeof(struct in6_addr));
+                   printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)]));
+               }
+                (void)printf(" }");
+            }
+           /* Next group record */
+            group += 20 + nsrcs * sizeof(struct in6_addr);
+           printf("]");
+        }
+    }
+    return;
+trunc:
+    (void)printf("[|icmp6]");
+    return;
 }
 
-#endif
+static void
+mldv2_query_print(const u_char *bp, u_int len)
+{
+    struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
+    u_int mrc;
+    int mrt, qqi;
+    u_int nsrcs;
+    register u_int i;
+
+    /* Minimum len is 28 */
+    if (len < 28) {
+       printf(" [invalid len %d]", len);
+       return;
+    }
+    TCHECK(icp->icmp6_data16[0]);
+    mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
+    if (mrc < 32768) {
+       mrt = mrc;
+    } else {
+        mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3);
+    }
+    if (vflag) {
+       (void)printf(" [max resp delay=%d]", mrt);
+    }
+    TCHECK2(bp[8], sizeof(struct in6_addr));
+    printf(" [gaddr %s", ip6addr_string(&bp[8]));
+
+    if (vflag) {
+        TCHECK(bp[25]);
+       if (bp[24] & 0x08) {
+               printf(" sflag");
+       }
+       if (bp[24] & 0x07) {
+               printf(" robustness=%d", bp[24] & 0x07);
+       }
+       if (bp[25] < 128) {
+               qqi = bp[25];
+       } else {
+               qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3);
+       }
+       printf(" qqi=%d", qqi);
+    }
+
+    TCHECK2(bp[26], 2);
+    nsrcs = EXTRACT_16BITS(&bp[26]);
+    if (nsrcs > 0) {
+       if (len < 28 + nsrcs * sizeof(struct in6_addr))
+           printf(" [invalid number of sources]");
+       else if (vflag > 1) {
+           printf(" {");
+           for (i = 0; i < nsrcs; i++) {
+               TCHECK2(bp[28 + i * sizeof(struct in6_addr)],
+                        sizeof(struct in6_addr));
+               printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)]));
+           }
+           printf(" }");
+       } else
+           printf(", %d source(s)", nsrcs);
+    }
+    printf("]");
+    return;
+trunc:
+    (void)printf("[|icmp6]");
+    return;
+}
 
-#ifdef HAVE_STRUCT_ICMP6_NODEINFO
 static void
 dnsname_print(const u_char *cp, const u_char *ep)
 {
@@ -616,15 +998,17 @@ dnsname_print(const u_char *cp, const u_char *ep)
        printf("\"");
 }
 
-void
-icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
+static void
+icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep)
 {
        struct icmp6_nodeinfo *ni6;
        struct icmp6_hdr *dp;
        const u_char *cp;
-       int siz, i;
+       size_t siz, i;
        int needcomma;
 
+       if (ep < bp)
+               return;
        dp = (struct icmp6_hdr *)bp;
        ni6 = (struct icmp6_nodeinfo *)bp;
        siz = ep - bp;
@@ -633,21 +1017,21 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
        case ICMP6_NI_QUERY:
                if (siz == sizeof(*dp) + 4) {
                        /* KAME who-are-you */
-                       printf("icmp6: who-are-you request");
+                       printf(" who-are-you request");
                        break;
                }
-               printf("icmp6: node information query");
+               printf(" node information query");
 
                TCHECK2(*dp, sizeof(*ni6));
                ni6 = (struct icmp6_nodeinfo *)dp;
                printf(" (");   /*)*/
-               switch (ntohs(ni6->ni_qtype)) {
+               switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
                case NI_QTYPE_NOOP:
                        printf("noop");
                        break;
                case NI_QTYPE_SUPTYPES:
                        printf("supported qtypes");
-                       i = ntohs(ni6->ni_flags);
+                       i = EXTRACT_16BITS(&ni6->ni_flags);
                        if (i)
                                printf(" [%s]", (i & 0x01) ? "C" : "");
                        break;
@@ -752,7 +1136,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                needcomma = 0;
 
                ni6 = (struct icmp6_nodeinfo *)dp;
-               printf("icmp6: node information reply");
+               printf(" node information reply");
                printf(" (");   /*)*/
                switch (ni6->ni_code) {
                case ICMP6_NI_SUCCESS:
@@ -783,7 +1167,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                        break;
                }
 
-               switch (ntohs(ni6->ni_qtype)) {
+               switch (EXTRACT_16BITS(&ni6->ni_qtype)) {
                case NI_QTYPE_NOOP:
                        if (needcomma)
                                printf(", ");
@@ -796,7 +1180,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                        if (needcomma)
                                printf(", ");
                        printf("supported qtypes");
-                       i = ntohs(ni6->ni_flags);
+                       i = EXTRACT_16BITS(&ni6->ni_flags);
                        if (i)
                                printf(" [%s]", (i & 0x01) ? "C" : "");
                        break;
@@ -818,7 +1202,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                                printf("\"");
                        } else
                                dnsname_print(cp, ep);
-                       if ((ntohs(ni6->ni_flags) & 0x01) != 0)
+                       if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0)
                                printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1));
                        break;
                case NI_QTYPE_NODEADDR:
@@ -831,7 +1215,7 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
                                        break;
                                printf(" %s", getname6(bp + i));
                                i += sizeof(struct in6_addr);
-                               printf("(%d)", ntohl(*(int32_t *)(bp + i)));
+                               printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i));
                                i += sizeof(int32_t);
                        }
                        i = ni6->ni_flags;
@@ -862,6 +1246,141 @@ icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep)
 trunc:
        fputs("[|icmp6]", stdout);
 }
-#endif
+
+static void
+icmp6_rrenum_print(const u_char *bp, const u_char *ep)
+{
+       struct icmp6_router_renum *rr6;
+       const char *cp;
+       struct rr_pco_match *match;
+       struct rr_pco_use *use;
+       char hbuf[NI_MAXHOST];
+       int n;
+
+       if (ep < bp)
+               return;
+       rr6 = (struct icmp6_router_renum *)bp;
+       cp = (const char *)(rr6 + 1);
+
+       TCHECK(rr6->rr_reserved);
+       switch (rr6->rr_code) {
+       case ICMP6_ROUTER_RENUMBERING_COMMAND:
+               printf("router renum: command");
+               break;
+       case ICMP6_ROUTER_RENUMBERING_RESULT:
+               printf("router renum: result");
+               break;
+       case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
+               printf("router renum: sequence number reset");
+               break;
+       default:
+               printf("router renum: code-#%d", rr6->rr_code);
+               break;
+       }
+
+       printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum));
+
+       if (vflag) {
+#define F(x, y)        ((rr6->rr_flags) & (x) ? (y) : "")
+               printf("[");    /*]*/
+               if (rr6->rr_flags) {
+                       printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"),
+                           F(ICMP6_RR_FLAGS_REQRESULT, "R"),
+                           F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"),
+                           F(ICMP6_RR_FLAGS_SPECSITE, "S"),
+                           F(ICMP6_RR_FLAGS_PREVDONE, "P"));
+               }
+               printf("seg=%u,", rr6->rr_segnum);
+               printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay));
+               if (rr6->rr_reserved)
+                       printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved));
+               /*[*/
+               printf("]");
+#undef F
+       }
+
+       if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) {
+               match = (struct rr_pco_match *)cp;
+               cp = (const char *)(match + 1);
+
+               TCHECK(match->rpm_prefix);
+
+               if (vflag > 1)
+                       printf("\n\t");
+               else
+                       printf(" ");
+               printf("match(");       /*)*/
+               switch (match->rpm_code) {
+               case RPM_PCO_ADD:       printf("add"); break;
+               case RPM_PCO_CHANGE:    printf("change"); break;
+               case RPM_PCO_SETGLOBAL: printf("setglobal"); break;
+               default:                printf("#%u", match->rpm_code); break;
+               }
+
+               if (vflag) {
+                       printf(",ord=%u", match->rpm_ordinal);
+                       printf(",min=%u", match->rpm_minlen);
+                       printf(",max=%u", match->rpm_maxlen);
+               }
+               if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf)))
+                       printf(",%s/%u", hbuf, match->rpm_matchlen);
+               else
+                       printf(",?/%u", match->rpm_matchlen);
+               /*(*/
+               printf(")");
+
+               n = match->rpm_len - 3;
+               if (n % 4)
+                       goto trunc;
+               n /= 4;
+               while (n-- > 0) {
+                       use = (struct rr_pco_use *)cp;
+                       cp = (const char *)(use + 1);
+
+                       TCHECK(use->rpu_prefix);
+
+                       if (vflag > 1)
+                               printf("\n\t");
+                       else
+                               printf(" ");
+                       printf("use("); /*)*/
+                       if (use->rpu_flags) {
+#define F(x, y)        ((use->rpu_flags) & (x) ? (y) : "")
+                               printf("%s%s,",
+                                   F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"),
+                                   F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P"));
+#undef F
+                       }
+                       if (vflag) {
+                               printf("mask=0x%x,", use->rpu_ramask);
+                               printf("raflags=0x%x,", use->rpu_raflags);
+                               if (~use->rpu_vltime == 0)
+                                       printf("vltime=infty,");
+                               else
+                                       printf("vltime=%u,",
+                                           EXTRACT_32BITS(&use->rpu_vltime));
+                               if (~use->rpu_pltime == 0)
+                                       printf("pltime=infty,");
+                               else
+                                       printf("pltime=%u,",
+                                           EXTRACT_32BITS(&use->rpu_pltime));
+                       }
+                       if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf,
+                           sizeof(hbuf)))
+                               printf("%s/%u/%u", hbuf, use->rpu_uselen,
+                                   use->rpu_keeplen);
+                       else
+                               printf("?/%u/%u", use->rpu_uselen,
+                                   use->rpu_keeplen);
+                       /*(*/
+                       printf(")");
+               }
+       }
+
+       return;
+
+trunc:
+       fputs("[|icmp6]", stdout);
+}
 
 #endif /* INET6 */