pub fn checksum(data: &[u8]) -> u16Expand description
The CDP checksum: a 16-bit one’s-complement sum (RFC 1071) over the CDP payload with the checksum field zeroed — with Cisco’s non-standard treatment of an odd-length payload.
For an even-length payload this is the plain IP checksum. For an odd-length payload RFC 1071
says to pad with a trailing zero byte, which makes the final word last << 8. Cisco’s
implementation instead puts the last octet in the low half of the final big-endian word and
then compensates for an off-by-one in its own sign handling:
last byte L | final 16-bit word |
|---|---|
L < 0x80 | 0x00 << 8 | L |
L >= 0x80 | 0xFF << 8 | (L - 1) |
This is not a guess. It is transcribed from Wireshark’s packet-cdp.c, which builds exactly
that padded buffer (“Swap bytes in last word” / “Compensate off-by-one error”) before calling
in_cksum, and it is corroborated by scapy’s independent _CDPChecksum._check_len. The two
disagree on one value: scapy tests last <= 0x80 where Wireshark tests last & 0x80, so for
a payload ending in exactly 0x80 scapy produces 0x0080 and Wireshark 0xFF7F. This
implementation follows Wireshark, because Wireshark’s is the reading that treats the byte
as signed (0x80 is negative, so it takes the compensated branch) and because Wireshark is
what an operator will use to check our frames.
Emitting the RFC-1071 form instead is not a cosmetic difference: Wireshark flags the packet
[incorrect] and a real Cisco device discards it, which is precisely the failure mode this
project’s OSPF checksum bug had (src/server/ospf/CLAUDE.md).