]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
frame: fix CDP checksum
authorudbxtd2008 <udbxtd2008@163.com>
Sun, 15 Jun 2014 07:05:06 +0000 (15:05 +0800)
committerVincent Bernat <vincent@bernat.im>
Sun, 15 Jun 2014 07:28:46 +0000 (09:28 +0200)
The checksum of CDP frame is calculated off-by-one error when the length
of frame is odd, and the highest bit of the last octet is 1, which is as
a known question mentioned in wireshark.

src/daemon/frame.c

index e1093ad3ac88d55acdfa68fca536688e79462f2b..a94fd3e4e9e2bb8a5af730b434c3f5720ca43dc3 100644 (file)
@@ -31,14 +31,34 @@ frame_checksum(const u_char *cp, int len, int cisco)
        if ((oddbyte = len & 1) != 0)
                v = *cp;
 
-       /* The remaining byte seems to be handled oddly by Cisco. Any hint about
-        * this is welcome. */
+       /* The remaining byte seems to be handled oddly by Cisco. From function
+        * dissect_cdp() in wireshark. 2014/6/14,zhengy@yealink.com:
+        *
+        * CDP doesn't adhere to RFC 1071 section 2. (B). It incorrectly assumes
+        * checksums are calculated on a big endian platform, therefore i.s.o.
+        * padding odd sized data with a zero byte _at the end_ it sets the last
+        * big endian _word_ to contain the last network _octet_. This byteswap
+        * has to be done on the last octet of network data before feeding it to
+        * the Internet checksum routine.
+        * CDP checksumming code has a bug in the addition of this last _word_
+        * as a signed number into the long word intermediate checksum. When
+        * reducing this long to word size checksum an off-by-one error can be
+        * made. This off-by-one error is compensated for in the last _word_ of
+        * the network data.
+        */
        if (oddbyte) {
-               if (cisco)
-                       sum += v;
-               else
+               if (cisco) {
+                       if (v & 0x80) {
+                               sum += 0xff << 8;
+                               sum += v - 1;
+                       } else {
+                               sum += v;
+                       }
+               } else {
                        sum += v << 8;
+               }
        }
+
        sum = (sum >> 16) + (sum & 0xffff);
        sum += sum >> 16;
        sum = ntohs(sum);