1

I see a few implementations, but I decided to look at exactly how the specification calls out the FCS for encoding.

So say my input is as follows:

dst: 0xAA AA AA AA AA AA
src: 0x55 55 55 55 55 55
len: 0x00 04
msg: 0xDE AD BE EF

concatenating this in the order that seems to be specified in the format (and the order expressed in the spec later on) seems to indicate my input is:

M(x) = 0xAA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF

a) "The first 32 bits of the frame are complemented."

complemented first 32 MSB of M(x): 0x55 55 55 55 AA AA 55 55 55 55 55 55 00 04 DE AD BE EF

b) "The n bits of the protected fields are then considered to be the coefficients of a polynomial M(x) of degree n – 1. (The first bit of the Destination Address field corresponds to the x(n–1) term and the last bit of the MAC Client Data field (or Pad field if present) corresponds to the x0 term.)"

I did this in previous. see M(x)

c) "M(x) is multiplied by x^32 and divided by G(x), producing a remainder R(x) of degree <=31."

Some options online seem to ignore the 33rd bit to represent x^32. I am going to ignore those simplified shortcuts for this exercise since it doesn't seem to specify that in the spec. It says to multiply M(x) by x^32. So this is just padding with 32 zeroes on the LSBs. (i.e. if m(x) = 1x^3 + 1, then m(x) * x^2 = 1x^5 + 1x^2 + 0)

padded: 0x55 55 55 55 AA AA 55 55 55 55 55 55 00 04 DE AD BE EF 00 00 00 00

Next step is to divide. I am dividing the whole M(x) / G(x). Can you use XOR shifting directly? I see some binary division examples have the dividened as 101 and the divisior as 110 and the remainder is 11. Other examples explain that by converting to decimal, you cannot divide. Which one is it for terms for this standard?

My remainder result is for option 1 (using XOR without carry bit consideration, shifting, no padding) was:

0x15 30 B0 FE

d) "The coefficients of R(x) are considered to be a 32-bit sequence."

e) "The bit sequence is complemented and the result is the CRC."

CRC = 0xEA CF 4F 01

so my entire Ethernet Frame should be:

0xAA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF EA CF 4F 01

In which my dst address is its original value.

When I check my work with an online CRC32 BZIP2 calculator, I see this result: 0xCACF4F01

Is there another option or online tool to calculate the Ethernet FCS field? (not just one of many CRC32 calculators)

What steps am I missing? Should I have padded the M(x)? Should I have complemented the 32 LSBs instead?

Update

There was an error in my CRC output in my software. It was a minor issue with copying a vector. My latest result for CRC is (before post-complement) 35 30 B0 FE.

The post-complement is: CA CF 4F 01 (matching most online CRC32 BZIP2 versions).

So my ethernet according to my programming is currently:

0xAA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF CA CF 4F 01
Cit5
  • 400
  • 5
  • 19

2 Answers2

3

The CRC you need is commonly available in zlib and other libraries as the standard PKZip CRC-32. It is stored in the message in little-endian order. So your frame with the CRC would be:

AA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF B0 5C 5D 85

Here is an online calculator, where the first result listed is the usual CRC-32, 0x855D5CB0.

Here is simple example code in C for calculating that CRC (calling with NULL for mem gives the initial CRC):

unsigned long crc32iso_hdlc(unsigned long crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0;
    crc ^= 0xffffffff;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0xedb88320 : crc >> 1;
    }
    return crc ^ 0xffffffff;
}

The 0xedb88320 constant is 0x04c11db7 reflected.

The actual code used in libraries is more complex and faster.

Here is the calculation of that same CRC (in Mathematica), using the approach described in the IEEE 802.3 document with polynomials, so you can see the correct resulting powers of x used for the remainder calculation:

show powers of x

If you click on the image, it will embiggen to make it easier to read the powers.

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • Why is "regular CRC32" using refIn and out? (reflecting?) I downloaded the the IEEE 802.3 standard and the section of FCS (which I copied the steps in my question) doesn't seem to state to bit reverse the calculation. Also, the poly vector has x^32, so 33-bits for poly. The wikipedia article for Ethernet Frame also states Ethernet standard does FCS using BZIP2. – Cit5 Dec 02 '20 at 18:22
  • The IEEE document describes the calculation by reversing all the bits, doing the forward CRC, and then reversing the result. Kind of silly, since you can just do the reflected CRC instead. – Mark Adler Dec 02 '20 at 18:31
  • A reflected CRC can be slightly faster in a simple implementation, and gives exactly the same error performance as the the corresponding forward CRC. That was why it was chosen for PKZip, and then that became a de facto standard CRC-32. However you see CRCs out there in use both forward and reflected. – Mark Adler Dec 02 '20 at 18:33
  • Yes, a CRC-32 polynomial has an x^32 term. It tends to be dropped, since the in usual software implementation, the constant used is 32 bits, which does not include, and does not need, that 1 in the 33rd position. Note that the remainder resulting from dividing by a polynomial whose highest term is x^n (degree n) cannot have an x^n term. Just like the remainder after dividing by an integer has to be less than that integer. – Mark Adler Dec 02 '20 at 18:48
  • Where in the IEEE spec does it say to reverse the bit order (reflect)? I copied the spec, and it clearly defines M(x) as MSB of dst address to LSB of payload. G(x) is defined. What am I missing? – Cit5 Dec 02 '20 at 19:38
  • I can see how the spec is not crystal clear on that point. It says "The first bit of the Destination Address field corresponds to the x^(n–1) term ...", but it doesn't say which bit of a byte is the "first bit". As noted elsewhere, Ethernet sends the least significant bits first, so when it says "first bit" there, it means the _least_ significant bit of the first byte, not the most significant bit. You might otherwise think the most significant bit is "first", since that's how we write it down. – Mark Adler Dec 02 '20 at 23:40
  • Also the taking the complement of the first 32 bits of the message is equivalent to having the initial CRC register contents be all ones. Again, it is a kind of roundabout way to get the same result. – Mark Adler Dec 02 '20 at 23:41
  • @rcgldr The spec is correct. The FCS _as they calculate it_ is sent with bit 31 first. What they calculate is the _reflection_ of the CRC-32/ISO-HDLC. So my answer, that CRC, is sent with bit 0 first. See my updated answer with the polynomial calculation, for clarification of what bits go where. – Mark Adler Dec 03 '20 at 03:23
  • @rcgldr By the way, the `CA CF...` from the question is not the correct FCS. – Mark Adler Dec 03 '20 at 03:24
  • They don't say that, because they never reference or discuss the reflected CRC (CRC-32/ISO-HDLC) that is the straightforward implementation. So they can't say that their CRC is the reflection of that one. I said that. If you follow the procedure they outline in the spec, you discover that that is what they calculate. – Mark Adler Dec 03 '20 at 03:39
  • For modern implementations it doesn't matter. I was referring to decisions made 30-some-odd years ago. When doing a byte at a time, there is an extra shift operation for non-reflected CRCs to move the data byte 24 bits up to exclusive-or with the CRC. That operation is not needed for a reflected CRC, where the data byte is directly xor'ed to the bottom of the CRC. – Mark Adler Dec 03 '20 at 04:08
  • @MarkAdler - I updated my answer. The spec indirectly states input is reflected, transmitted bit 0 first, CRC is not reflected, transmitted bit 31 first. Reflecting the 32 bit CRC and storing least significant byte first allows both data and CRC to be transmitted bit 0 first. – rcgldr Dec 03 '20 at 15:00
0

The confusing factor here is the 802.3 spec. It mentions that first bit is LSB (least significant bit == bit 0) only in one place, in section 3.2.3-b, and it mentions that for CRC, "the first bit of the Destination Address field corresponds to the x^(n-1) term", so each byte input to the CRC calculation is bit reflected.

Using this online calculator:

http://www.sunshine2k.de/coding/javascript/crc/crc_js.html

Select CRC-32 | CRC32, click on custom, input reflected on, result reflected off. With this data:

AA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF

per the spec, the calculated CRC is 0x0D3ABAA1, stored and transmitted as shown:

bit 0 first                                           | bit 7 first
AA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF | 0D 3A BA A1

To simplify the output to always transmit bit 0 first, bit reflect the CRC bytes:

bit 0 first                                           | bit 0 first
AA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF | B0 5C 5D 85

Note that the bit 0 always first method results in transmitted bits identical to the spec.

Change result setting for the CRC calculator, input reflected on, result reflected on. With this data:

AA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF

the calculated CRC is 0x855D5CB0, stored least significant byte first and transmitted as shown:

bit 0 first                                           | bit 0 first
AA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF | B0 5C 5D 85

For verifying received data, rather than compare a calculated CRC of received data versus the received CRC, the process can calculate a CRC on received data and CRC. Assuming the alternative setup where all bytes are received bit 0 first, then with this received frame or any frame without error

bit 0 first                                           | bit 0 first
AA AA AA AA AA AA 55 55 55 55 55 55 00 04 DE AD BE EF | B0 5C 5D 85

the calculated CRC will always be 0x2144DF1C. In the case of a hardware implementation, the post complement of the CRC is usually performed one bit at a time as bits are shifted out, outside of the logic used to calculate the CRC, and in this case, after receiving a frame without error, the CRC register will always contain 0xDEBB20E3 (0x2144DF1C ^ 0xFFFFFFFF). So verification is done by computing CRC on a received frame and comparing the CRC to a 32 bit constant (0x2144DF1C or 0xDEBB20E3).

rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • In my software calculation (custom function that does xor and shifting) I made a minor but impactful error on my result. The results I got now match the CRC results from my quesiton: `CA CF 4F 01`. I'm curious, why do these calculators cut off the 33rd bit of poly? Also, isn't Ethernet FCS using CRC32 BZIP2 as you stated? The result of the calculator using bzip2 gave me `CA CF 4F 01`, while "regular CRC32" gave me your result: `85 5D 5C B0`. – Cit5 Dec 02 '20 at 18:17
  • The x^32 bit results in the rest of the polynomial being subtracted (xor'ed) with the current register contents to get the remainder modulo the polynomial. – Mark Adler Dec 02 '20 at 18:46
  • A key point is that the [BZIP2](https://reveng.sourceforge.io/crc-catalogue/17plus.htm#crc.cat.crc-32-bzip2) and [PKZip (ISO-HDLC)](https://reveng.sourceforge.io/crc-catalogue/17plus.htm#crc.cat.crc-32-iso-hdlc) CRC's are mathematically the _exact same CRC_ in terms of the bits you get out for the bits you put in. They differ only in which bits from a series of _bytes_ you feed in first, and how to order the bits that come out into the delivered CRC. – Mark Adler Dec 02 '20 at 23:22
  • @Cit5 - the issue is that the bytes input to the CRC calculator are bit reflected (input reflected option with CRC calculators). I've updated my answer to explain what the spec states for calculation and transmission (data byte bit 0 first, CRC bytes bit 7 first), and an alternative that allows for a simpler transmission (all bytes bit 0 first). – rcgldr Dec 03 '20 at 15:05
  • Thanks for the clarification. That was a mistake on my part for inferring M(x) is MSB to LSB. – Cit5 Dec 04 '20 at 05:52
  • @Cit5 - I updated my answer. The spec only mentions that "first bit" is LSB (least significant bit) once, in section 3.2.3-b, which would be easy to miss. – rcgldr Dec 04 '20 at 11:34