]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-icmp6.c
Add changes in 4.2.1.
[tcpdump] / print-icmp6.c
index 4a7aa2d9ac82704f31c4e070be802c68bfc95af3..ce1046ed2ea7493185e1a3baae6694bb4ae97e0a 100644 (file)
@@ -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"},
@@ -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,6 +135,7 @@ static struct tok icmp6_opt_values[] = {
    { 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"},
@@ -192,48 +197,110 @@ 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;
@@ -252,12 +319,15 @@ icmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented)
        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] ");
                }
@@ -266,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) {
@@ -505,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)
@@ -600,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
 
@@ -664,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);
@@ -753,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 */
@@ -812,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 {
@@ -841,7 +926,7 @@ 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 * sizeof(struct in6_addr))
            printf(" [invalid number of sources]");