Why TCP needs its own checksum
An Ethernet frame ends with a CRC that catches errors on one link, and an IP header has a checksum for the header only. Neither covers the TCP data end to end. Routers and switches can also corrupt a packet in memory between links, where no CRC is checked. The TCP checksum is the end-to-end check: it protects the data, the TCP header and the addresses of both hosts.
What the checksum covers
The pseudo-header is made of the source IP, destination IP, a zero byte, the protocol number (6 for TCP) and the TCP length. It is never sent; each end builds it from the IP header it already has. Including it means a segment delivered to the wrong host, or with a rewritten address, fails the check. This is also why NAT devices must recalculate the checksum when they change an address.
How it is calculated: a worked example
- Split the data into 16-bit words, padding with a zero byte if the length is odd.
- Set the checksum field to 0.
- Add the words. If the sum overflows 16 bits, add the carry back in (this is one's-complement addition).
- Invert every bit of the result. That is the checksum.
On small screens, swipe sideways or focus the diagram and use the arrow keys.
If one word changes in transit, the receiver's total is no longer all ones and the segment is discarded without any reply. TCP's retransmission timer (or duplicate acknowledgements) makes the sender send it again.
Limits of a 16-bit checksum
- It is weak: swapped words, or two errors that cancel, go undetected. The link-layer CRC and application-level checks (such as TLS) cover that.
- It guards against accidents only. Anyone who can change a segment can recompute the checksum.
- UDP uses the same method, but IPv4 allows a UDP checksum of zero to mean "not used". TCP has no such option.
Checksum offload in a capture
Modern network cards calculate checksums in hardware. The operating system hands the card a segment with the field empty, and the card fills it in as the frame leaves. A capture taken on the sending host sees the segment before that happens, so Wireshark flags it as an incorrect checksum. That is normal. A capture taken on another machine, or on a mirror port, shows the correct value.
# Linux: show whether offload is on
ethtool -k eth0 | grep checksumrx-checksumming and tx-checksumming show on when the card does the work. Switch it off only to test a capture, not as a fix.
The urgent pointer
When the URG flag is set, the 16-bit urgent pointer field is valid. It holds an offset from the segment's sequence number to the last byte of "urgent" data, so urgent bytes can be handed to the application ahead of the normal stream. Telnet used it to carry an interrupt key press through a stuffed buffer.
In practice it is almost never used. The standards documents disagree on whether the pointer marks the last urgent byte or the byte after it, which led to interoperability trouble. RFC 6093 advises applications to avoid urgent data altogether. When you see URG in a capture it is nearly always a scan or an oddity, not real traffic.
Checksum and urgent pointer in short
- The checksum is a 16-bit one's-complement sum over pseudo-header, header and data.
- The pseudo-header (IP addresses, protocol, length) is built at each end and not transmitted.
- A bad checksum means the segment is silently dropped and later retransmitted.
- "Incorrect checksum" on locally captured outgoing packets is usually offload.
- URG plus the urgent pointer is legacy and best avoided.
Test yourself
Why does the TCP checksum include a pseudo-header?
A receiver finds the TCP checksum wrong. What happens?
Wireshark on your own PC shows 'incorrect checksum' on every outgoing packet. Most likely cause?
Which flag makes the urgent pointer field valid?
A sum of 16-bit words is 0x11000. What is the folded sum?