Networking · Link Layer
The Frame Check Sequence: CRC-32 and the Errors It Misses
How the four-byte Ethernet trailer is computed, why CRC-32 catches every burst up to 32 bits, and which corruption patterns pass it undetected.
The last four bytes of every Ethernet frame are a number computed from all the bytes before them. A receiver recomputes it and compares. If the values differ, the frame is discarded with no notification to the sender and no record except a driver counter. The choice of a 32-bit cyclic redundancy check for this job, rather than a sum or a cryptographic hash, follows from what the check is asked to do: catch the error patterns that a physical medium actually produces, cheaply enough to run at wire speed in a shift register.
What a CRC is, mechanically
A cyclic redundancy check treats the message as a polynomial over GF(2), the field with two elements, where addition is exclusive-or and there is no carry. The message bits are coefficients; the check value is the remainder after dividing that polynomial by a fixed generator polynomial. The generator for Ethernet is:
$$G(x) = x^{32} + x^{26} + x^{23} + x^{22} + x^{16} + x^{12} + x^{11} + x^{10} + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1$$
In hexadecimal, with the leading term implicit, that is 0x04C11DB7. The choice of generator determines which error patterns are guaranteed to be caught, so it is not arbitrary.
Division here is long division with XOR instead of subtraction, and it is implemented as a shift register: for each input bit, shift the register left, XOR the incoming bit into the low position, and if the bit shifted out was one, XOR the whole register with the generator. The result after the last bit is the remainder. In software the same operation is done a byte at a time using a 256-entry table precomputed from the generator, so each byte costs one table lookup and one XOR.
Two details distinguish the Ethernet variant from a textbook CRC. The first is the initial value: the register starts at all ones, not zero, so a run of leading zero bytes changes the result; with an all-zero initial register those bytes would leave it unchanged. The second is the final XOR: the remainder is complemented before transmission. The complement does not change which errors are detected, since it is a bijection on the remainder, but it is part of the definition, and an implementation that omits it produces a different check value.
/* Reflected CRC-32 as Ethernet computes it: low bit of each byte first. */
static uint32_t crc32_eth(const uint8_t *p, size_t n)
{
uint32_t crc = 0xFFFFFFFFu;
while (n--) {
crc ^= *p++;
for (int i = 0; i < 8; i++)
crc = (crc & 1u) ? (crc >> 1) ^ 0xEDB88320u : (crc >> 1);
}
return crc ^ 0xFFFFFFFFu;
}
The constant 0xEDB88320 is 0x04C11DB7 with its 32 bits reversed, and the register shifts right instead of left. The reversal is not a different check: it is the same polynomial evaluated in the order the bits actually arrive, since Ethernet sends the least significant bit of each byte first. A left-shifting implementation of the unreversed polynomial consumes bits in the opposite order and therefore returns a different value for the same bytes; for the ASCII string 123456789 it returns 0xFC891918, while the Ethernet form returns 0xCBF43926. That second value is the one a correct implementation must produce, and it is the standard self-test for this variant.
The error patterns a CRC-32 is guaranteed to catch
The guarantees follow from polynomial arithmetic and are stronger than a probabilistic argument:
- Any single-bit error is detected, because a single-bit error is a monomial and no monomial is a multiple of a polynomial with more than one term.
- Any burst error of length 32 bits or less is detected. A burst of length $k$ is an error confined to a run of $k$ bits; the error polynomial then has degree below $k$, and since the generator has degree 32, no nonzero polynomial of degree below 32 can be a multiple of it.
- The generator has fifteen terms, an odd count, so it has no root at $x=1$ and is not divisible by $x+1$. The odd-error guarantee that comes from an $x+1$ factor therefore does not apply here; that property belongs to generators with an even number of terms, such as the CRC-16 polynomials used in some other protocols.
- The residual error rate for random corruption is about $2^{-32}$: for an $n$-bit message there are $2^n-1$ nonzero error patterns, and fewer than $2^{n-32}$ of them are multiples of the generator.
The burst guarantee is the one that matters in practice. Most physical-layer errors are bursts, not isolated bits: a noise impulse on a copper pair corrupts a contiguous run of symbols, and a bit slip corrupts everything after the slip point. A check designed to catch 32-bit bursts at a 32-bit cost is well matched to that error model.
Where the guarantee ends
The bound is over error polynomials, and it assumes the errors are confined to the frame. Three classes of failure escape it.
The first is an error pattern that happens to be an exact multiple of the generator. These exist and can be constructed deliberately, which is why CRC-32 is not a security mechanism. An attacker who can modify a frame can also recompute the trailer, because the algorithm is public and the initial state is fixed. Anyone who needs to know a frame was not modified needs a keyed check at a higher layer.
The second is a burst longer than 32 bits. The polynomial argument guarantees detection only up to the degree of the generator; beyond that, a burst can be a multiple of it. For a burst of random bit values the chance of that is still about $2^{-32}$, but real long bursts are not random: a radio fade or a bit slip imposes structure on the error pattern, so the guarantee that holds for short bursts no longer applies. Links with high burst error rates therefore add forward error correction at the physical layer rather than relying on the Ethernet trailer alone.
The third is misdirected frames rather than corrupted ones. A frame delivered intact to the wrong station has a valid checksum and is accepted. Nothing in the trailer detects that. The same is true of a frame that was truncated by a receive buffer overrun: the receiver computes the CRC over fewer bytes than were transmitted, gets a mismatch, and discards the frame, which is correct behaviour but indistinguishable from corruption.
FCS in the receive path
The check is computed as bits arrive, in the same logic that strips the preamble, so there is no buffering delay attributable to it. A frame that fails is dropped at the MAC and increments a counter, usually named for receive errors or CRC errors depending on the driver. The frame is never handed to the protocol stack and no ICMP message is sent, because the link layer has no notion of who sent it that it could trust; the source address in a corrupt frame is itself unreliable.
Some adapters can be put into a mode that passes frames with bad checksums upward, which is useful for a capture tool that wants to see what actually arrived; the normal receive path never accepts them, because a stack that accepted them would be accepting corrupt data as valid.
When a frame passes, the four trailer bytes are removed and the payload is delivered with a length the receiver determined from the physical layer. The removal is not free of assumptions: a NIC that reports a frame length including the trailer, and a driver that does not subtract four, hands the upper layer a payload four bytes longer than it should be. For IPv4 the total length field masks the error, since the receiver caps at that value; for a protocol without its own length field the extra bytes reach the application. Frame length accounting is described in Ethernet frame layout, where the same cap-the-length rule appears for padding.
Why not a stronger check
A 64-bit CRC would reduce the residual rate to $2^{-64}$ and cost four more bytes per frame, which on a maximum-length 1518-byte frame is about 0.26 percent of the bytes on the wire. The standard did not adopt one, and the reasons are instructive. The frame check is not the last line of defence: TCP and UDP checksums cover the payload end to end, and IPv4’s header checksum covers its own header, so a corruption that slips past the trailer is likely to be caught above. Raising the link check would duplicate protection that already exists, at a cost paid on every frame including the many that carry traffic already protected.
The corollary is that disabling upper-layer checksums because “the link checks it” is a mistake in the other direction. Checksum offload on modern NICs computes the transport checksum in hardware, so the cost argument for disabling it is weak, and the trailer’s guarantee is exactly the one described above: bursts up to 32 bits, not arbitrary corruption.
The trailer also interacts with the frame’s minimum size. Because the FCS is inside the 64-byte floor, a padded frame’s check covers the padding, which means the receiver must compute over the bytes as received rather than over the logical payload. The floor and the check are specified together for that reason. The remaining structural question, how a frame reaches a station that is not on the same cable, is the business of MAC learning and bridge forwarding.
References
- IEEE 802.3: Ethernet — IEEE
- RFC 3385: Internet Protocol Small Computer System Interface (iSCSI) Cyclic Redundancy Check (CRC)/Checksum Considerations — IETF
- A Painless Guide to CRC Error Detection Algorithms — Ross Williams