]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Go with Wireshark's Internet checksum routine.
authorGuy Harris <[email protected]>
Mon, 13 Jun 2011 21:08:51 +0000 (14:08 -0700)
committerGuy Harris <[email protected]>
Mon, 13 Jun 2011 21:08:51 +0000 (14:08 -0700)
The Wireshark routine is based on the BSD in-kernel portable checksum
routine (thus BSD-licensed); it takes a vector of pointers and lengths
and checksums the concatenation of the buffers in question (just as the
BSD in-kernel routine checksums a chain of mbufs).

This simplifies the "with a pseudo-header" checksums; hopefully it'll
fix up the problems being seen on some big-endian platforms, which might
be due to hand-calculating some or all of the checksum and doing so
incorrectly.  It also gets rid of some code that might be dereferencing
unaligned pointers.

15 files changed:
Makefile.in
in_cksum.c [new file with mode: 0644]
interface.h
ip6.h
netdissect.h
print-dccp.c
print-icmp.c
print-igmp.c
print-ip.c
print-ip6.c
print-mobile.c
print-pim.c
print-tcp.c
print-udp.c
print-vrrp.c

index 80034fd2cb1bf9b4f101f1d471e7e4f653062119..666420a440962449f50ef602e9a9f8b9f6007633 100644 (file)
@@ -69,7 +69,7 @@ RANLIB = @RANLIB@
        $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c
 
 CSRC = addrtoname.c af.c checksum.c cpack.c gmpls.c oui.c gmt2local.c ipproto.c \
-        nlpid.c l2vpn.c machdep.c parsenfsfh.c \
+        nlpid.c l2vpn.c machdep.c parsenfsfh.c in_cksum.c \
        print-802_11.c print-802_15_4.c print-ap1394.c print-ah.c \
        print-arcnet.c print-aodv.c print-arp.c print-ascii.c print-atalk.c \
        print-atm.c print-babel.c print-beep.c print-bfd.c print-bgp.c \
diff --git a/in_cksum.c b/in_cksum.c
new file mode 100644 (file)
index 0000000..b9c4da1
--- /dev/null
@@ -0,0 +1,202 @@
+/* in_cksum.c
+ * 4.4-Lite-2 Internet checksum routine, modified to take a vector of
+ * pointers/lengths giving the pieces to be checksummed.  Also using
+ * Tahoe/CGI version of ADDCARRY(x) macro instead of from portable version.
+ *
+ * $Id: in_cksum.c 36796 2011-04-22 04:04:20Z guy $
+ */
+
+/*
+ * Copyright (c) 1988, 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)in_cksum.c  8.1 (Berkeley) 6/10/93
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <tcpdump-stdinc.h>
+
+#include "interface.h"
+
+/*
+ * Checksum routine for Internet Protocol family headers (Portable Version).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ */
+
+#define ADDCARRY(x)  {if ((x) > 65535) (x) -= 65535;}
+#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
+
+u_int16_t
+in_cksum(const struct cksum_vec *vec, int veclen)
+{
+       register const u_int16_t *w;
+       register int sum = 0;
+       register int mlen = 0;
+       int byte_swapped = 0;
+
+       union {
+               u_int8_t        c[2];
+               u_int16_t       s;
+       } s_util;
+       union {
+               u_int16_t       s[2];
+               u_int32_t       l;
+       } l_util;
+
+       for (; veclen != 0; vec++, veclen--) {
+               if (vec->len == 0)
+                       continue;
+               w = (const u_int16_t *)(void *)vec->ptr;
+               if (mlen == -1) {
+                       /*
+                        * The first byte of this chunk is the continuation
+                        * of a word spanning between this chunk and the
+                        * last chunk.
+                        *
+                        * s_util.c[0] is already saved when scanning previous
+                        * chunk.
+                        */
+                       s_util.c[1] = *(const u_int8_t *)w;
+                       sum += s_util.s;
+                       w = (const u_int16_t *)(void *)((const u_int8_t *)w + 1);
+                       mlen = vec->len - 1;
+               } else
+                       mlen = vec->len;
+               /*
+                * Force to even boundary.
+                */
+               if ((1 & (unsigned long) w) && (mlen > 0)) {
+                       REDUCE;
+                       sum <<= 8;
+                       s_util.c[0] = *(const u_int8_t *)w;
+                       w = (const u_int16_t *)(void *)((const u_int8_t *)w + 1);
+                       mlen--;
+                       byte_swapped = 1;
+               }
+               /*
+                * Unroll the loop to make overhead from
+                * branches &c small.
+                */
+               while ((mlen -= 32) >= 0) {
+                       sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+                       sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
+                       sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
+                       sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
+                       w += 16;
+               }
+               mlen += 32;
+               while ((mlen -= 8) >= 0) {
+                       sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
+                       w += 4;
+               }
+               mlen += 8;
+               if (mlen == 0 && byte_swapped == 0)
+                       continue;
+               REDUCE;
+               while ((mlen -= 2) >= 0) {
+                       sum += *w++;
+               }
+               if (byte_swapped) {
+                       REDUCE;
+                       sum <<= 8;
+                       byte_swapped = 0;
+                       if (mlen == -1) {
+                               s_util.c[1] = *(const u_int8_t *)w;
+                               sum += s_util.s;
+                               mlen = 0;
+                       } else
+                               mlen = -1;
+               } else if (mlen == -1)
+                       s_util.c[0] = *(const u_int8_t *)w;
+       }
+       if (mlen == -1) {
+               /* The last mbuf has odd # of bytes. Follow the
+                  standard (the odd byte may be shifted left by 8 bits
+                  or not as determined by endian-ness of the machine) */
+               s_util.c[1] = 0;
+               sum += s_util.s;
+       }
+       REDUCE;
+       return (~sum & 0xffff);
+}
+
+/*
+ * Given the host-byte-order value of the checksum field in a packet
+ * header, and the network-byte-order computed checksum of the data
+ * that the checksum covers (including the checksum itself), compute
+ * what the checksum field *should* have been.
+ */
+u_int16_t
+in_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum)
+{
+       u_int32_t shouldbe;
+
+       /*
+        * The value that should have gone into the checksum field
+        * is the negative of the value gotten by summing up everything
+        * *but* the checksum field.
+        *
+        * We can compute that by subtracting the value of the checksum
+        * field from the sum of all the data in the packet, and then
+        * computing the negative of that value.
+        *
+        * "sum" is the value of the checksum field, and "computed_sum"
+        * is the negative of the sum of all the data in the packets,
+        * so that's -(-computed_sum - sum), or (sum + computed_sum).
+        *
+        * All the arithmetic in question is one's complement, so the
+        * addition must include an end-around carry; we do this by
+        * doing the arithmetic in 32 bits (with no sign-extension),
+        * and then adding the upper 16 bits of the sum, which contain
+        * the carry, to the lower 16 bits of the sum, and then do it
+        * again in case *that* sum produced a carry.
+        *
+        * As RFC 1071 notes, the checksum can be computed without
+        * byte-swapping the 16-bit words; summing 16-bit words
+        * on a big-endian machine gives a big-endian checksum, which
+        * can be directly stuffed into the big-endian checksum fields
+        * in protocol headers, and summing words on a little-endian
+        * machine gives a little-endian checksum, which must be
+        * byte-swapped before being stuffed into a big-endian checksum
+        * field.
+        *
+        * "computed_sum" is a network-byte-order value, so we must put
+        * it in host byte order before subtracting it from the
+        * host-byte-order value from the header; the adjusted checksum
+        * will be in host byte order, which is what we'll return.
+        */
+       shouldbe = sum;
+       shouldbe += ntohs(computed_sum);
+       shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
+       shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
+       return shouldbe;
+}
index 1ea322eddb085032ea4ec948b898f6629686b6e7..4862ff3cb0a904dd8cdf92b0953dc07a80d354d0 100644 (file)
@@ -328,7 +328,12 @@ extern void dhcp6_print(const u_char *, u_int);
 extern void babel_print(const u_char *, u_int);
 extern int mask62plen(const u_char *);
 #endif /*INET6*/
-extern u_short in_cksum(const u_short *, register u_int, int);
+
+struct cksum_vec {
+       const u_int8_t  *ptr;
+       int             len;
+};
+extern u_int16_t in_cksum(const struct cksum_vec *, int);
 extern u_int16_t in_cksum_shouldbe(u_int16_t, u_int16_t);
 
 #ifndef HAVE_BPF_DUMP
diff --git a/ip6.h b/ip6.h
index 0a80f39448d428c1dcf12b6abd13f261b43b175d..c54b5b2e69eaa5b78e4c79f36374aeb8f2450d79 100644 (file)
--- a/ip6.h
+++ b/ip6.h
@@ -88,20 +88,6 @@ struct ip6_hdr {
        struct in6_addr ip6_dst;        /* destination address */
 } UNALIGNED;
 
-/*
- * Pseudo header, used for higher layer checksumming.
- */
-union ip6_pseudo_hdr {
-    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];
-} UNALIGNED;
-
 #define ip6_vfc                ip6_ctlun.ip6_un2_vfc
 #define ip6_flow       ip6_ctlun.ip6_un1.ip6_un1_flow
 #define ip6_plen       ip6_ctlun.ip6_un1.ip6_un1_plen
index 19d3394eeaa771115c3d644f775a23cc13600cfa..c459b4c9f0936e647ec29e5bcd8859adf8828846 100644 (file)
@@ -480,8 +480,12 @@ extern void zephyr_print(netdissect_options * ndo,
 #endif /*INET6*/
 
 #if 0
-extern u_short in_cksum(const u_short *,
-                       register u_int, int);
+struct cksum_vec {
+       const u_int8_t  *ptr;
+       int             len;
+};
+extern u_int16_t in_cksum(const struct cksum_vec *, int);
+extern u_int16_t in_cksum_shouldbe(u_int16_t, u_int16_t);
 #endif
 
 extern void esp_print_decodesecret(netdissect_options *ndo);
index fee4a6e50574f8d71eb69fe9eeff552a27cb4022..460c43a0511ad1cc8137bfcdc72b9a39b2100845 100644 (file)
@@ -74,60 +74,57 @@ static int dccp_cksum(const struct ip *ip,
        const struct dccp_hdr *dh, u_int len)
 {
        int cov = dccp_csum_coverage(dh, len);
-       union phu {
-               struct phdr {
-                       u_int32_t src;
-                       u_int32_t dst;
-                       u_char mbz;
-                       u_char proto;
-                       u_int16_t len;
-               } ph;
-               u_int16_t pa[6];
-       } phu;
-       const u_int16_t *sp;
+       struct phdr {
+               u_int32_t src;
+               u_int32_t dst;
+               u_char mbz;
+               u_char proto;
+               u_int16_t len;
+       } ph;
+       struct cksum_vec vec[2];
 
        /* pseudo-header.. */
-       phu.ph.mbz = 0;
-       phu.ph.len = htons(len);
-       phu.ph.proto = IPPROTO_DCCP;
-       memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
+       ph.mbz = 0;
+       ph.len = htons(len);
+       ph.proto = IPPROTO_DCCP;
+       memcpy(&ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
        if (IP_HL(ip) == 5)
-               memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
+               memcpy(&ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
        else
-               phu.ph.dst = ip_finddst(ip);
+               ph.dst = ip_finddst(ip);
 
-       sp = &phu.pa[0];
-       return in_cksum((u_short *)dh, cov, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
+       vec[0].ptr = (const u_int8_t *)(void *)&ph;
+       vec[0].len = sizeof(ph);
+       vec[1].ptr = (const u_int8_t *)(void *)dh;
+       vec[1].len = cov;
+       return in_cksum(vec, 2);
 }
 
 #ifdef INET6
 static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len)
 {
-       size_t i;
-       u_int32_t sum = 0;
        int cov = dccp_csum_coverage(dh, len);
-       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;
+       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;
+       struct cksum_vec vec[2];
 
        /* 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_DCCP;
-
-       for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
-               sum += phu.pa[i];
-
-       return in_cksum((u_short *)dh, cov, sum);
+       memset(&ph, 0, sizeof(ph));
+       ph.ph_src = ip6->ip6_src;
+       ph.ph_dst = ip6->ip6_dst;
+       ph.ph_len = htonl(len);
+       ph.ph_nxt = IPPROTO_DCCP;
+
+       vec[0].ptr = (const u_int8_t *)(void *)&ph;
+       vec[0].len = sizeof(ph);
+       vec[1].ptr = (const u_int8_t *)(void *)dh;
+       vec[1].len = cov;
+       return in_cksum(vec, 2);
 }
 #endif
 
index 36bff6a41214c217d54560c7ca46cd75f406f2a2..03b9505b1146da6f0dc91ad38466ece3ae1ef8ab 100644 (file)
@@ -346,6 +346,7 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented)
        const struct icmp_mpls_ext_object_header_t *icmp_mpls_ext_object_header;
        u_int hlen, dport, mtu, obj_tlen, obj_class_num, obj_ctype;
        char buf[MAXHOSTNAMELEN + 100];
+       struct cksum_vec vec[1];
 
        dp = (struct icmp *)bp;
         ext_dp = (struct icmp_ext_t *)bp;
@@ -560,8 +561,11 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented)
        (void)printf("ICMP %s, length %u", str, plen);
        if (vflag && !fragmented) { /* don't attempt checksumming if this is a frag */
                u_int16_t sum, icmp_sum;
+               struct cksum_vec vec[1];
                if (TTEST2(*bp, plen)) {
-                       sum = in_cksum((u_short*)dp, plen, 0);
+                       vec[0].ptr = (const u_int8_t *)(void *)dp;
+                       vec[0].len = plen;
+                       sum = in_cksum(vec, 1);
                        if (sum != 0) {
                                icmp_sum = EXTRACT_16BITS(&dp->icmp_cksum);
                                (void)printf(" (wrong icmp cksum %x (->%x)!)",
@@ -598,10 +602,12 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented)
              * to check if an extension header is present. This is expedient,
              * however not all implementations set the length field proper.
              */
-            if (!ext_dp->icmp_length &&
-                in_cksum((const u_short *)&ext_dp->icmp_ext_version_res,
-                         plen - ICMP_EXTD_MINLEN, 0)) {
-                return;
+            if (!ext_dp->icmp_length) {
+                vec[0].ptr = (const u_int8_t *)(void *)&ext_dp->icmp_ext_version_res;
+                vec[0].len = plen - ICMP_EXTD_MINLEN;
+                if (in_cksum(vec, 1)) {
+                    return;
+                }
             }
 
             printf("\n\tMPLS extension v%u",
@@ -617,10 +623,11 @@ icmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented)
             }
 
             hlen = plen - ICMP_EXTD_MINLEN;
+            vec[0].ptr = (const u_int8_t *)(void *)&ext_dp->icmp_ext_version_res;
+            vec[0].len = hlen;
             printf(", checksum 0x%04x (%scorrect), length %u",
                    EXTRACT_16BITS(ext_dp->icmp_ext_checksum),
-                   in_cksum((const u_short *)&ext_dp->icmp_ext_version_res,
-                            plen - ICMP_EXTD_MINLEN, 0) ? "in" : "",
+                   in_cksum(vec, 1) ? "in" : "",
                    hlen);
 
             hlen -= 4; /* subtract common header size */
index a848562985d90f89c391fe700bc0a1b87789d92a..6522bc3044d04ae881d72020e6823f802190fa90 100644 (file)
@@ -259,6 +259,8 @@ trunc:
 void
 igmp_print(register const u_char *bp, register u_int len)
 {
+    struct cksum_vec vec[1];
+
     if (qflag) {
         (void)printf("igmp");
         return;
@@ -327,7 +329,9 @@ igmp_print(register const u_char *bp, register u_int len)
 
     if (vflag && TTEST2(bp[0], len)) {
         /* Check the IGMP checksum */
-        if (in_cksum((const u_short*)bp, len, 0))
+        vec[0].ptr = bp;
+        vec[0].len = len;
+        if (in_cksum(vec, 1))
             printf(" bad igmp cksum %x!", EXTRACT_16BITS(&bp[2]));
     }
     return;
index f42276dc71ade61b4413ffb9ba8e3b4a75d51d8f..21f83c10eb92c2768bf17ac3d52e7a02a692f94d 100644 (file)
@@ -268,92 +268,6 @@ trunc:
        printf("[|ip]");
 }
 
-/*
- * compute an IP header checksum.
- * don't modifiy the packet.
- */
-u_short
-in_cksum(const u_short *addr, register u_int len, int csum)
-{
-       int nleft = len;
-       const u_short *w = addr;
-       u_short answer;
-       int sum = csum;
-
-       /*
-        *  Our algorithm is simple, using a 32 bit accumulator (sum),
-        *  we add sequential 16 bit words to it, and at the end, fold
-        *  back all the carry bits from the top 16 bits into the lower
-        *  16 bits.
-        */
-       while (nleft > 1)  {
-               sum += *w++;
-               nleft -= 2;
-       }
-       if (nleft == 1)
-               sum += htons(*(u_char *)w<<8);
-
-       /*
-        * add back carry outs from top 16 bits to low 16 bits
-        */
-       sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
-       sum += (sum >> 16);                     /* add carry */
-       answer = ~sum;                          /* truncate to 16 bits */
-       return (answer);
-}
-
-/*
- * Given the host-byte-order value of the checksum field in a packet
- * header, and the network-byte-order computed checksum of the data
- * that the checksum covers (including the checksum itself), compute
- * what the checksum field *should* have been.
- */
-u_int16_t
-in_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum)
-{
-       u_int32_t shouldbe;
-
-       /*
-        * The value that should have gone into the checksum field
-        * is the negative of the value gotten by summing up everything
-        * *but* the checksum field.
-        *
-        * We can compute that by subtracting the value of the checksum
-        * field from the sum of all the data in the packet, and then
-        * computing the negative of that value.
-        *
-        * "sum" is the value of the checksum field, and "computed_sum"
-        * is the negative of the sum of all the data in the packets,
-        * so that's -(-computed_sum - sum), or (sum + computed_sum).
-        *
-        * All the arithmetic in question is one's complement, so the
-        * addition must include an end-around carry; we do this by
-        * doing the arithmetic in 32 bits (with no sign-extension),
-        * and then adding the upper 16 bits of the sum, which contain
-        * the carry, to the lower 16 bits of the sum, and then do it
-        * again in case *that* sum produced a carry.
-        *
-        * As RFC 1071 notes, the checksum can be computed without
-        * byte-swapping the 16-bit words; summing 16-bit words
-        * on a big-endian machine gives a big-endian checksum, which
-        * can be directly stuffed into the big-endian checksum fields
-        * in protocol headers, and summing words on a little-endian
-        * machine gives a little-endian checksum, which must be
-        * byte-swapped before being stuffed into a big-endian checksum
-        * field.
-        *
-        * "computed_sum" is a network-byte-order value, so we must put
-        * it in host byte order before subtracting it from the
-        * host-byte-order value from the header; the adjusted checksum
-        * will be in host byte order, which is what we'll return.
-        */
-       shouldbe = sum;
-       shouldbe += ntohs(computed_sum);
-       shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
-       shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
-       return shouldbe;
-}
-
 #define IP_RES 0x8000
 
 static struct tok ip_frag_values[] = {
@@ -376,6 +290,7 @@ ip_print_demux(netdissect_options *ndo,
               struct ip_print_demux_state *ipds)
 {
        struct protoent *proto;
+       struct cksum_vec vec[1];
 
 again:
        switch (ipds->nh) {
@@ -508,8 +423,9 @@ again:
                break;
 
        case IPPROTO_PIM:
-               pim_print(ipds->cp,  ipds->len,
-                         in_cksum((const u_short*)ipds->cp, ipds->len, 0));
+               vec[0].ptr = ipds->cp;
+               vec[0].len = ipds->len;
+               pim_print(ipds->cp, ipds->len, in_cksum(vec, 1));
                break;
 
        case IPPROTO_VRRP:
@@ -561,6 +477,7 @@ ip_print(netdissect_options *ndo,
        struct ip_print_demux_state *ipds=&ipd;
        const u_char *ipend;
        u_int hlen;
+       struct cksum_vec vec[1];
        u_int16_t sum, ip_sum;
        struct protoent *proto;
 
@@ -659,7 +576,9 @@ ip_print(netdissect_options *ndo,
             }
 
            if (!Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
-               sum = in_cksum((const u_short *)ipds->ip, hlen, 0);
+               vec[0].ptr = (const u_int8_t *)(void *)ipds->ip;
+               vec[0].len = hlen;
+               sum = in_cksum(vec, 1);
                if (sum != 0) {
                    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
                    (void)printf(", bad cksum %x (->%x)!", ip_sum,
index 9add03efa28afa15e224d2be92dfd63abf4bf3aa..fad1a9a2d3a4bfa8fb0d13155da0ec932532a241 100644 (file)
@@ -51,22 +51,28 @@ int
 nextproto6_cksum(const struct ip6_hdr *ip6, const u_short *data,
                 u_int len, u_int next_proto)
 {
-        size_t i;
-        u_int32_t sum = 0;
-       union ip6_pseudo_hdr phu;
+        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;
+        struct cksum_vec vec[2];
 
         /* 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 = next_proto;
-
-        for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) {
-                sum += phu.pa[i];
-       }
-
-        return in_cksum(data, len, sum);
+        memset(&ph, 0, sizeof(ph));
+        ph.ph_src = ip6->ip6_src;
+        ph.ph_dst = ip6->ip6_dst;
+        ph.ph_len = htonl(len);
+        ph.ph_nxt = next_proto;
+
+        vec[0].ptr = (const u_int8_t *)(void *)&ph;
+        vec[0].len = sizeof(ph);
+        vec[1].ptr = (const u_int8_t *)(void *)data;
+        vec[1].len = len;
+
+        return in_cksum(vec, 2);
 }
 
 /*
index 816ffd6e65859917f76da3960b47629d2557a6c7..de4eab1dce3b97e4c4e58a6a2d0c18fa44cd93af 100644 (file)
@@ -72,6 +72,7 @@ mobile_print(const u_char *bp, u_int length)
 {
        const u_char *cp = bp +8 ;
        const struct mobile_ip *mob;
+       struct cksum_vec vec[1];
        u_short proto,crc;
        u_char osp =0;                  /* old source address present */
 
@@ -101,7 +102,9 @@ mobile_print(const u_char *bp, u_int length)
                (void)printf("> %s ",ipaddr_string(&mob->odst));
                (void)printf("(oproto=%d)",proto>>8);
        }
-       if (in_cksum((u_short *)mob, osp ? 12 : 8, 0)!=0) {
+       vec[0].ptr = (const u_int8_t *)(void *)mob;
+       vec[0].len = osp ? 12 : 8;
+       if (in_cksum(vec, 1)!=0) {
                (void)printf(" (bad checksum %d)",crc);
        }
 
index 34b1dd46ea6a69a09725627590fe9c6db10b3aa9..25c8576601984481d0ad27f2261470f3314bd63f 100644 (file)
@@ -29,7 +29,15 @@ static const char rcsid[] _U_ =
 #endif
 
 #include <tcpdump-stdinc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
 #include "interface.h"
+#include "addrtoname.h"
+#include "extract.h"
+
+#include "ip.h"
 
 #define PIMV2_TYPE_HELLO         0
 #define PIMV2_TYPE_REGISTER      1
@@ -108,16 +116,6 @@ struct pim {
        u_short pim_cksum;      /* IP style check sum */
 };
 
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "interface.h"
-#include "addrtoname.h"
-#include "extract.h"
-
-#include "ip.h"
-
 static void pimv2_print(register const u_char *bp, register u_int len, u_int cksum);
 
 static void
index 1ef3961e8b2051e444c7b1f86742b2a32221aa1e..1381799cd8003b968c20a27f553c549dfd36c9ab 100644 (file)
@@ -129,31 +129,30 @@ static int tcp_cksum(register const struct ip *ip,
                     register const struct tcphdr *tp,
                     register u_int len)
 {
-        union phu {
-                struct phdr {
-                        u_int32_t src;
-                        u_int32_t dst;
-                        u_char mbz;
-                        u_char proto;
-                        u_int16_t len;
-                } ph;
-                u_int16_t pa[6];
-        } phu;
-        const u_int16_t *sp;
+        struct phdr {
+                u_int32_t src;
+                u_int32_t dst;
+                u_char mbz;
+                u_char proto;
+                u_int16_t len;
+        } ph;
+        struct cksum_vec vec[2];
 
         /* pseudo-header.. */
-        phu.ph.len = htons((u_int16_t)len);
-        phu.ph.mbz = 0;
-        phu.ph.proto = IPPROTO_TCP;
-        memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
+        ph.len = htons((u_int16_t)len);
+        ph.mbz = 0;
+        ph.proto = IPPROTO_TCP;
+        memcpy(&ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
         if (IP_HL(ip) == 5)
-                memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
+                memcpy(&ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
         else
-                phu.ph.dst = ip_finddst(ip);
+                ph.dst = ip_finddst(ip);
 
-        sp = &phu.pa[0];
-        return in_cksum((u_short *)tp, len,
-                        sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
+        vec[0].ptr = (const u_int8_t *)(void *)&ph;
+        vec[0].len = sizeof(ph);
+        vec[1].ptr = (const u_int8_t *)tp;
+        vec[1].len = len;
+        return in_cksum(vec, 2);
 }
 
 void
index 278d648f83e761734ba67f2e10bf3b6bdaf803f8..640ac0d3cd9b5a48dd9c7653ba700387e8338c82 100644 (file)
@@ -286,75 +286,57 @@ static int udp_cksum(register const struct ip *ip,
                     register const struct udphdr *up,
                     register u_int len)
 {
-       union phu {
-               struct phdr {
-                       u_int32_t src;
-                       u_int32_t dst;
-                       u_char mbz;
-                       u_char proto;
-                       u_int16_t len;
-               } ph;
-               u_int16_t pa[6];
-       } phu;
-       register const u_int16_t *sp;
+       struct phdr {
+               u_int32_t src;
+               u_int32_t dst;
+               u_char mbz;
+               u_char proto;
+               u_int16_t len;
+       } ph;
+       struct cksum_vec vec[2];
 
        /* pseudo-header.. */
-       phu.ph.len = htons((u_int16_t)len);
-       phu.ph.mbz = 0;
-       phu.ph.proto = IPPROTO_UDP;
-       memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
+       ph.len = htons((u_int16_t)len);
+       ph.mbz = 0;
+       ph.proto = IPPROTO_UDP;
+       memcpy(&ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
        if (IP_HL(ip) == 5)
-               memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
+               memcpy(&ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
        else
-               phu.ph.dst = ip_finddst(ip);
+               ph.dst = ip_finddst(ip);
 
-       sp = &phu.pa[0];
-       return in_cksum((u_short *)up, len,
-                       sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
+       vec[0].ptr = (const u_int8_t *)(void *)&ph;
+       vec[0].len = sizeof(ph);
+       vec[1].ptr = (const u_int8_t *)(void *)up;
+       vec[1].len = len;
+       return (in_cksum(vec, 2));
 }
 
 #ifdef INET6
 static int udp6_cksum(const struct ip6_hdr *ip6, const struct udphdr *up,
        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;
+       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;
+       struct cksum_vec vec[2];
 
        /* 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_UDP;
-
-       sum = 0;
-       for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
-               sum += phu.pa[i];
-
-       sp = (const u_int16_t *)up;
-
-       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);
+       memset(&ph, 0, sizeof(ph));
+       ph.ph_src = ip6->ip6_src;
+       ph.ph_dst = ip6->ip6_dst;
+       ph.ph_len = htonl(len);
+       ph.ph_nxt = IPPROTO_UDP;
+
+       vec[0].ptr = (const u_int8_t *)(void *)&ph;
+       vec[0].len = sizeof(ph);
+       vec[1].ptr = (const u_int8_t *)(void *)up;
+       vec[1].len = len;
+       return (in_cksum(vec, 2));
 }
 #endif
 
index 899542dac42938bb703addd9c8b3374f90f4d17b..8b733d228c3c293dea78abcc57619171aa11be90 100644 (file)
@@ -110,9 +110,15 @@ vrrp_print(register const u_char *bp, register u_int len, int ttl)
                int i;
                char c;
 
-               if (TTEST2(bp[0], len) && in_cksum((const u_short*)bp, len, 0))
-                       printf(", (bad vrrp cksum %x)",
-                               EXTRACT_16BITS(&bp[6]));
+               if (TTEST2(bp[0], len)) {
+                       struct cksum_vec vec[1];
+
+                       vec[0].ptr = bp;
+                       vec[0].len = len;
+                       if (in_cksum(vec, 1))
+                               printf(", (bad vrrp cksum %x)",
+                                       EXTRACT_16BITS(&bp[6]));
+               }
                printf(", addrs");
                if (naddrs > 1)
                        printf("(%d)", naddrs);