Ваша реализация определенно верна (для NUL завершенных C строк). Возможно, это неправильная конфигурация сетевого интерфейса. В режиме по умолчанию Wireshark не получает FCS от сетевого драйвера. Если вы используете Linux и драйвер поддерживает это, то вы должны включить это с помощью ethtool , чтобы получить FCS.
К сожалению, в моей системе это работает только для получения кадров:
$ ethtool -K eth0 rx-fcs on
Подробнее см. this .
Я использую немного другой алгоритм во встроенных (для микроконтроллеров AVR) проектах, и он отлично работает для меня:
#define CRC_POLY 0xEDB88320
uint32_t crc32_calc(uint8_t *data, int len)
{
int i, j;
uint32_t crc;
if (!data)
return 0;
if (len < 1)
return 0;
crc = 0xFFFFFFFF;
for (j = 0; j < len; j++) {
crc ^= data[j];
for (i = 0; i < 8; i++) {
crc = (crc & 1) ? ((crc >> 1) ^ CRC_POLY) : (crc >> 1);
}
}
return (crc ^ 0xFFFFFFFF);
}
Пример из реального мира:
Рамка Ethe rnet в Wireshark (с включенным ethtool rx-fcs):
Тест с моей использованной реализацией:
uint8_t frame[] = { 0x20, 0xcf, 0x30, 0x1a, 0xce, 0xa1, 0x62, 0x38,
0xe0, 0xc2, 0xbd, 0x30, 0x08, 0x06, 0x00, 0x01,
0x08, 0x00 ,0x06 ,0x04 ,0x00 ,0x01 ,0x62 ,0x38,
0xe0 ,0xc2 ,0xbd ,0x30 ,0x0a, 0x2a, 0x2a, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x2a,
0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
printf("0x%x\n", crc32_calc(frame, sizeof(frame)));
Выход:
$ ./fcs-test
0x6026b722
$
Вы видите, Wireshark сообщает 0x22bf2660 как правильный FCS. Вот только другой вывод из-за порядка следования байтов. Но алгоритм расчета CR C правильный.
РЕДАКТИРОВАТЬ:
Я изменил ваш код:
uint32_t crc32b(uint8_t *message, int len) {
int i, j;
uint32_t crc, mask;
uint8_t byte;
crc = 0xFFFFFFFF;
for (j = 0; j < len; j++) {
byte = message[j];
crc = crc ^ byte;
for (i = 7; i >= 0; i--) {
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
}
return ~crc;
}
Я добавил длину аргумент, потому что ваша реализация работает правильно только тогда, когда сообщение является NUL-завершенной C строкой. Если ваш ввод представляет собой байтовый массив, то вы получите неправильное значение CR C.
См. Различия (массив и C строка):
uint8_t msg_arr[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x5c, 0xb9, 0x01, 0x7c, 0x5a, 0x53, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
char *msg_str = "aabbccddeeff5cb9017c5a53080000000000000000000000000000";
printf("0x%x\n", crc32b(msg_arr, sizeof(msg_arr)));
printf("0x%x\n", crc32b(msg_str, strlen(msg_str)));
Вывод :
$
0x3422dd71
0xd81e4af3
$