/src/lldpd/src/daemon/frame.c
Line | Count | Source |
1 | | /* -*- mode: c; c-file-style: "openbsd" -*- */ |
2 | | /* |
3 | | * Copyright (c) 2009 Vincent Bernat <bernat@luffy.cx> |
4 | | * |
5 | | * Permission to use, copy, modify, and/or distribute this software for any |
6 | | * purpose with or without fee is hereby granted, provided that the above |
7 | | * copyright notice and this permission notice appear in all copies. |
8 | | * |
9 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | | */ |
17 | | |
18 | | #include "lldpd.h" |
19 | | |
20 | | /** |
21 | | * Compute the checksum as 16-bit word. |
22 | | */ |
23 | | u_int16_t |
24 | | frame_checksum(const u_char *cp, int len, int cisco) |
25 | 0 | { |
26 | 0 | unsigned int sum = 0, v = 0; |
27 | 0 | int oddbyte = 0; |
28 | |
|
29 | 0 | while ((len -= 2) >= 0) { |
30 | 0 | sum += *cp++ << 8; |
31 | 0 | sum += *cp++; |
32 | 0 | } |
33 | 0 | if ((oddbyte = len & 1) != 0) v = *cp; |
34 | | |
35 | | /* The remaining byte seems to be handled oddly by Cisco. From function |
36 | | * dissect_cdp() in wireshark. 2014/6/14,zhengy@yealink.com: |
37 | | * |
38 | | * CDP doesn't adhere to RFC 1071 section 2. (B). It incorrectly assumes |
39 | | * checksums are calculated on a big endian platform, therefore i.s.o. |
40 | | * padding odd sized data with a zero byte _at the end_ it sets the last |
41 | | * big endian _word_ to contain the last network _octet_. This byteswap |
42 | | * has to be done on the last octet of network data before feeding it to |
43 | | * the Internet checksum routine. |
44 | | * CDP checksumming code has a bug in the addition of this last _word_ |
45 | | * as a signed number into the long word intermediate checksum. When |
46 | | * reducing this long to word size checksum an off-by-one error can be |
47 | | * made. This off-by-one error is compensated for in the last _word_ of |
48 | | * the network data. |
49 | | */ |
50 | 0 | if (oddbyte) { |
51 | 0 | if (cisco) { |
52 | 0 | if (v & 0x80) { |
53 | 0 | sum += 0xff << 8; |
54 | 0 | sum += v - 1; |
55 | 0 | } else { |
56 | 0 | sum += v; |
57 | 0 | } |
58 | 0 | } else { |
59 | 0 | sum += v << 8; |
60 | 0 | } |
61 | 0 | } |
62 | |
|
63 | 0 | sum = (sum >> 16) + (sum & 0xffff); |
64 | 0 | sum += sum >> 16; |
65 | 0 | return (0xffff & ~sum); |
66 | 0 | } |