如何计算以太网帧中的 FCS 字段?

How do I calculate the FCS field in an Ethernet Frame?

我看到了一些实现,但我决定看看规范是如何调用 FCS 进行编码的。

所以说我的输入如下:

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

按照似乎在格式中指定的顺序(以及稍后在规范中表达的顺序)连接它似乎表明我的输入是:

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

a) “对帧的前 32 位进行补码。”

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) "然后将受保护字段的n位视为多项式M(x)的系数 度 n – 1。(目标地址字段的第一位对应于 x(n–1) 项和最后一位 MAC 客户端数据字段(或 Pad 字段,如果存在)的位对应于 x0 项。)"

我以前做过这个。参见 M(x)

c) "M(x) 乘以 x^32 并除以 G(x),产生 <=31 的余数 R(x)。"

网上有些选项好像忽略了第33位表示x^32。我将忽略此练习的那些简化的快捷方式,因为它似乎没有在规范中指定。 它表示将 M(x) 乘以 x^32。所以这只是在 LSB 上用 32 个零填充。 (即如果 m(x) = 1x^3 + 1,则 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

下一步是划分。我正在划分整个 M(x) / G(x)。可以直接用异或移位吗?我看到一些二进制除法示例将被除数设为 101,除数设为 110,余数为 11。其他示例说明,通过转换为十进制,您无法除法。这个标准的术语是哪一个?

选项 1(使用不考虑进位、移位、无填充的 XOR)的余数结果是:

0x15 30 B0 FE

d) "R(x) 的系数被认为是一个 32 位序列。"

e) "位序列求补,结果为CRC。"

CRC = 0xEA CF 4F 01

所以我的整个以太网帧应该是:

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

其中我的dst地址是它的原始值。

当我使用在线 CRC32 BZIP2 计算器检查我的工作时,我看到了这个结果:0xCACF4F01

是否有其他选项或在线工具可以计算以太网 FCS 字段? (不只是许多 CRC32 计算器中的一个)

我缺少哪些步骤?我应该填充 M(x) 吗?我应该改为补充 32 个 LSB 吗?

更新

我的软件中的 CRC 输出有错误。复制矢量是一个小问题。我的 CRC 最新结果是(在 post-补码之前)35 30 B0 FE.

post-补码是:CA CF 4F 01(匹配大多数在线 CRC32 BZIP2 版本)。

所以根据我的编程,我的以太网目前是:

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

您需要的 CRC 作为标准 PKZip CRC-32 在 zlib 和其他库中通常可用。它以小端顺序存储在消息中。所以你的 CRC 框架是:

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

这是一个在线计算器,其中first result listed is the usual CRC-320x855D5CB0

这是 C 中用于计算 CRC 的简单示例代码(使用 NULL 调用 mem 给出初始 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;
}

0xedb88320 常量被 0x04c11db7 反映。

库中使用的实际代码更复杂、更快。

这里是同一个 CRC(在 Mathematica 中)的计算,使用 IEEE 802.3 文档中描述的多项式方法,因此您可以看到 x 的正确结果幂用于余数计算:

如果你点击图片,它会被放大,以便更容易阅读权力。

这里的混淆因素是 802.3 规范。它提到第一位是 LSB(最低有效位 == 位 0)仅在一个地方,在第 3.2.3-b 节中,它提到对于 CRC,“目标地址字段的第一位对应于 x^ (n-1) 项”,因此输入到 CRC 计算的每个字节都会反映位。

使用这个在线计算器:

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

Select CRC-32 | CRC32,点击自定义,输入反映,结果反映关闭。使用此数据:

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

根据规范,计算出的 CRC 为 0x0D3ABAA1,存储和传输如下所示:

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

为了简化输出始终先传输位 0,位反映 CRC 字节:

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

请注意,位 0 始终在前的方法导致传输的位与规范相同。

更改 CRC 计算器的结果设置,反映输入,反映结果。使用此数据:

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

计算出的 CRC 为 0x855D5CB0,首先存储最低有效字节并按如下方式传输:

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

为了验证接收到的数据,不是将接收到的数据的计算出的 CRC 与接收到的 CRC 进行比较,该过程可以计算接收到的数据和 CRC 的 CRC。假设替代设置首先接收所有字节的位 0,然后接收到这个接收到的帧或任何没有错误的帧

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

计算出的 CRC 始终为 0x2144DF1C。在硬件实现的情况下,CRC 的 post 补码通常在位被移出时一次执行一位,在用于计算 CRC 的逻辑之外,在这种情况下,在收到帧没有错误,CRC 寄存器将始终包含 0xDEBB20E3 (0x2144DF1C ^ 0xFFFFFFFF)。因此,通过计算接收到的帧的 CRC 并将 CRC 与 32 位常量(0x2144DF1C 或 0xDEBB20E3)进行比较来完成验证。