]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Add a "in_cksum_shouldbe()" to compute, given an Internet checksum field
authorguy <guy>
Sun, 21 Jul 2002 20:48:26 +0000 (20:48 +0000)
committerguy <guy>
Sun, 21 Jul 2002 20:48:26 +0000 (20:48 +0000)
in a packet header and the computed checksum for the data that the
checksum covers, what the checksum field's value should have been.

Use that routine in the IP printer.

interface.h
print-ip.c

index 680c7f6706c4f578df0bbe00c6a4d2d9dcdd9941..ef2f12ba53f0f19f9d6cb9b712c0db25a56918ee 100644 (file)
@@ -18,7 +18,7 @@
  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * @(#) $Header: /tcpdump/master/tcpdump/interface.h,v 1.191 2002-07-18 00:04:13 hannes Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/tcpdump/interface.h,v 1.192 2002-07-21 20:48:26 guy Exp $ (LBL)
  */
 
 #ifndef tcpdump_interface_h
@@ -324,6 +324,7 @@ extern void ospf6_print(const u_char *, u_int);
 extern void dhcp6_print(const u_char *, u_int, u_int16_t, u_int16_t);
 #endif /*INET6*/
 extern u_short in_cksum(const u_short *, register u_int, int);
+extern u_int16_t in_cksum_shouldbe(u_int16_t, u_int16_t);
 
 #ifndef HAVE_BPF_DUMP
 struct bpf_program;
index f3cfb6560aa139e236e7dd089911d8abcc131bef..d8eda70a23e85fe7b490ac8a920dcd7d2b0c3a4b 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.108 2002-07-20 23:37:40 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.109 2002-07-21 20:48:26 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -247,6 +247,58 @@ in_cksum(const u_short *addr, register u_int len, int csum)
        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;
+}
+
 /*
  * print an IP datagram.
  */
@@ -536,15 +588,16 @@ again:
                (void)printf(" (DF)");
 
        if (vflag) {
-               int sum;
+               u_int16_t sum, ip_sum;
                char *sep = "";
 
                if ((u_char *)ip + hlen <= snapend) {
                        sum = in_cksum((const u_short *)ip, hlen, 0);
                        if (sum != 0) {
+                               ip_sum = ntohs(ip->ip_sum);
                                (void)printf("%sbad cksum %x (->%x)!", sep,
-                                            ntohs(ip->ip_sum),
-                                            ntohs(ip->ip_sum)-sum);
+                                            ip_sum,
+                                            in_cksum_shouldbe(ip_sum, sum));
                                sep = ", ";
                        }
                }