]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-icmp6.c
Add changes in 4.2.1.
[tcpdump] / print-icmp6.c
index a9f53cfef6d7b1842e15c0490109d2f4fe0eb1f8..ce1046ed2ea7493185e1a3baae6694bb4ae97e0a 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.79 2005-01-14 10:41:50 hannes Exp $";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 guy Exp $";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -35,14 +35,14 @@ static const char rcsid[] _U_ =
 #include <stdio.h>
 #include <string.h>
 
-#include "ip6.h"
-#include "icmp6.h"
-#include "ipproto.h"
-
 #include "interface.h"
 #include "addrtoname.h"
 #include "extract.h"
 
+#include "ip6.h"
+#include "icmp6.h"
+#include "ipproto.h"
+
 #include "udp.h"
 #include "ah.h"
 
@@ -62,6 +62,9 @@ static void icmp6_rrenum_print(const u_char *, const u_char *);
 #define abs(a) ((0 < (a)) ? (a) : -(a))
 #endif
 
+/* 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"},
@@ -69,18 +72,18 @@ static struct tok icmp6_type_values[] = {
     { 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 "},
+    { 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 advertisment"},
+    { 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 "},
+    { 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"},
@@ -91,6 +94,7 @@ static struct tok icmp6_type_values[] = {
     { ICMP6_NI_REPLY, "node information reply"},
     { MLD6_MTRACE, "mtrace message"},
     { MLD6_MTRACE_RESP, "mtrace response"},
+    { ND_RPL_MESSAGE,   "RPL"},
     { 0,       NULL }
 };
 
@@ -131,7 +135,8 @@ static struct tok icmp6_opt_values[] = {
    { ND_OPT_PREFIX_INFORMATION, "prefix info"},
    { ND_OPT_REDIRECTED_HEADER, "redirected header"},
    { ND_OPT_MTU, "mtu"},
-   { ND_OPT_ADVINTERVAL, "advertisment interval"},
+   { ND_OPT_RDNSS, "rdnss"},
+   { ND_OPT_ADVINTERVAL, "advertisement interval"},
    { ND_OPT_HOMEAGENT_INFO, "homeagent information"},
    { ND_OPT_ROUTE_INFO, "route info"},
    { 0,        NULL }
@@ -192,75 +197,137 @@ print_lladdr(const u_int8_t *p, size_t 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);
+       return (nextproto6_cksum(ip6, (const u_int8_t *)(void *)icp, len,
+           IPPROTO_ICMPV6));
 }
 
+enum ND_RPL_CODE {
+        ND_RPL_DIS   =0x00,
+        ND_RPL_DIO   =0x01,
+        ND_RPL_DAO   =0x02,
+        ND_RPL_DAO_ACK=0x03,
+        ND_RPL_SDIS  =0x80,
+        ND_RPL_SDIO  =0x81,
+        ND_RPL_SDAO  =0x82,
+        ND_RPL_SDAO_ACK=0x83,
+        ND_RPL_SCC   =0x8A,
+};
+
+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;
+        int secured = hdr->icmp6_code & 0x80;
+        int basecode= hdr->icmp6_code & 0x7f;
+
+        ND_TCHECK(dio->rpl_dagid);
+
+        if(secured) {
+                ND_PRINT((ndo, ", (SEC)"));
+        } else {
+                ND_PRINT((ndo, ", (CLR)"));
+        }
+                
+        switch(basecode) {
+        case ND_RPL_DIS:
+                ND_PRINT((ndo, "DODAG Information Solicitation"));
+                if(ndo->ndo_vflag) {
+                }
+                break;
+        case ND_RPL_DIO:
+                ND_PRINT((ndo, "DODAG 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;
+        case ND_RPL_DAO_ACK:
+                ND_PRINT((ndo, "Destination Advertisement Object Ack"));
+                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;
+        
+}
+
+
 void
-icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
+icmp6_print(netdissect_options *ndo,
+            const u_char *bp, u_int length, const u_char *bp2, int fragmented)
 {
        const struct icmp6_hdr *dp;
        const struct ip6_hdr *ip;
-       const char *str;
        const struct ip6_hdr *oip;
        const struct udphdr *ouh;
        int dport;
        const u_char *ep;
-       char buf[256];
        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 available data. */
        ep = snapend;
 
        TCHECK(dp->icmp6_cksum);
 
        if (vflag && !fragmented) {
-               int sum = dp->icmp6_cksum;
+               u_int16_t sum, udp_sum;
 
                if (TTEST2(bp[0], length)) {
+                       udp_sum = EXTRACT_16BITS(&dp->icmp6_cksum);
                        sum = icmp6_cksum(ip, dp, length);
                        if (sum != 0)
-                               (void)printf("[bad icmp6 cksum %x!] ", sum);
+                               (void)printf("[bad icmp6 cksum 0x%04x -> 0x%04x!] ",
+                                   udp_sum,
+                                   in_cksum_shouldbe(udp_sum, sum));
                        else
                                (void)printf("[icmp6 sum ok] ");
                }
@@ -269,14 +336,13 @@ icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
         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 ||
-                      ND_ROUTER_ADVERT ||
-                      ND_NEIGHBOR_ADVERT ||
-                      ND_NEIGHBOR_SOLICIT ||
-                      ND_REDIRECT ||
-                      ICMP6_HADISCOV_REPLY ||
-                      ICMP6_MOBILEPREFIX_ADVERT ))
+        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) {
@@ -508,6 +574,9 @@ icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
                                        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)
@@ -542,7 +611,7 @@ get_upperlayer(u_char *bp, u_int *prot)
        nh = ip6->ip6_nxt;
        hlen = sizeof(struct ip6_hdr);
 
-       while (bp < snapend) {
+       while (bp < ep) {
                bp += hlen;
 
                switch(nh) {
@@ -603,12 +672,14 @@ icmp6_opt_print(const u_char *bp, int resid)
        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
 
@@ -667,6 +738,17 @@ icmp6_opt_print(const u_char *bp, int resid)
                                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);
@@ -756,7 +838,7 @@ mldv2_report_print(const u_char *bp, u_int len)
     }
 
     TCHECK(icp->icmp6_data16[1]);
-    ngroups = ntohs(icp->icmp6_data16[1]);
+    ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]);
     printf(", %d group record(s)", ngroups);
     if (vflag > 0) {
        /* Print the group records */
@@ -767,13 +849,13 @@ mldv2_report_print(const u_char *bp, u_int len)
                printf(" [invalid number of groups]");
                return;
            }
-            TCHECK2(bp[group + 4], 16);
+            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 * 16)) {
+           if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) {
                printf(" [invalid number of sources %d]", nsrcs);
                return;
            }
@@ -783,13 +865,14 @@ mldv2_report_print(const u_char *bp, u_int len)
                /* Print the sources */
                 (void)printf(" {");
                 for (j = 0; j < nsrcs; j++) {
-                    TCHECK2(bp[group + 20 + j * 16], 16);
-                   printf(" %s", ip6addr_string(&bp[group + 20 + j * 16]));
+                    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 * 16;
+            group += 20 + nsrcs * sizeof(struct in6_addr);
            printf("]");
         }
     }
@@ -814,7 +897,7 @@ mldv2_query_print(const u_char *bp, u_int len)
        return;
     }
     TCHECK(icp->icmp6_data16[0]);
-    mrc = ntohs(icp->icmp6_data16[0]);
+    mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]);
     if (mrc < 32768) {
        mrt = mrc;
     } else {
@@ -823,7 +906,7 @@ mldv2_query_print(const u_char *bp, u_int len)
     if (vflag) {
        (void)printf(" [max resp delay=%d]", mrt);
     }
-    TCHECK2(bp[8], 16);
+    TCHECK2(bp[8], sizeof(struct in6_addr));
     printf(" [gaddr %s", ip6addr_string(&bp[8]));
 
     if (vflag) {
@@ -843,15 +926,16 @@ mldv2_query_print(const u_char *bp, u_int len)
     }
 
     TCHECK2(bp[26], 2);
-    nsrcs = ntohs(*(u_short *)&bp[26]);
+    nsrcs = EXTRACT_16BITS(&bp[26]);
     if (nsrcs > 0) {
-       if (len < 28 + nsrcs * 16)
+       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 * 16], 16);
-               printf(" %s", ip6addr_string(&bp[28 + i * 16]));
+               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
@@ -864,7 +948,7 @@ trunc:
     return;
 }
 
-void
+static void
 dnsname_print(const u_char *cp, const u_char *ep)
 {
        int i;
@@ -1153,8 +1237,6 @@ static void
 icmp6_rrenum_print(const u_char *bp, const u_char *ep)
 {
        struct icmp6_router_renum *rr6;
-       struct icmp6_hdr *dp;
-       size_t siz;
        const char *cp;
        struct rr_pco_match *match;
        struct rr_pco_use *use;
@@ -1163,9 +1245,7 @@ icmp6_rrenum_print(const u_char *bp, const u_char *ep)
 
        if (ep < bp)
                return;
-       dp = (struct icmp6_hdr *)bp;
        rr6 = (struct icmp6_router_renum *)bp;
-       siz = ep - bp;
        cp = (const char *)(rr6 + 1);
 
        TCHECK(rr6->rr_reserved);
@@ -1197,9 +1277,9 @@ icmp6_rrenum_print(const u_char *bp, const u_char *ep)
                            F(ICMP6_RR_FLAGS_PREVDONE, "P"));
                }
                printf("seg=%u,", rr6->rr_segnum);
-               printf("maxdelay=%u", rr6->rr_maxdelay);
+               printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay));
                if (rr6->rr_reserved)
-                       printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved));
+                       printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved));
                /*[*/
                printf("]");
 #undef F