netdev
[Top] [All Lists]

ether_crc wrong in 2.5.50

To: netdev@xxxxxxxxxxx
Subject: ether_crc wrong in 2.5.50
From: Manfred Spraul <manfred@xxxxxxxxxxxxxxxx>
Date: Tue, 10 Dec 2002 21:35:31 +0100
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2) Gecko/20021202
The ether_crc were converted to use the crc32 library in 2.5.
The conversion is incorrect:

crc32_le and _be are about the bit order in which the bits are processed:
_le means least significant bit first, _be msb first.

ethernet is always lsb first.
ether_crc means the output should be in the cpu bit order [msb in bit 31],
ether_crc_le means the output should be with msb in bit 0: that what crc32_le usually generates.

The attached patch is tested with winbond-840, natsemi and 8139too, i.e. ether_crc works. ether_crc_le generates the same output as the inline functions from 2.4.18, but it's untested due to lack of nics.

Could someone test it on a nic that uses ether_crc_le?

--
  Manfred

// $Header$
// Kernel Version:
//  VERSION = 2
//  PATCHLEVEL = 5
//  SUBLEVEL = 50
//  EXTRAVERSION =
--- 2.5/include/linux/crc32.h   2002-11-04 23:30:16.000000000 +0100
+++ build-2.5/include/linux/crc32.h     2002-12-10 19:15:50.000000000 +0100
@@ -9,9 +9,19 @@
 
 extern u32  crc32_le(u32 crc, unsigned char const *p, size_t len);
 extern u32  crc32_be(u32 crc, unsigned char const *p, size_t len);
+extern u32  bitreverse(u32 in);
 
 #define crc32(seed, data, length)  crc32_le(seed, (unsigned char const *)data, 
length)
+
+/*
+ * Helpers for hash table generation of ethernet nics:
+ *
+ * Ethernet sends the least significant bit of a byte first, thus crc32_le
+ * is used. The output of crc32_le is bit reversed [most significant bit
+ * is in bit nr 0], thus it must be reversed before use. Except for
+ * nics that bit swap the result internally...
+ */
+#define ether_crc(length, data)    bitreverse(crc32_le(~0, data, length))
 #define ether_crc_le(length, data) crc32_le(~0, data, length)
-#define ether_crc(length, data)    crc32_be(~0, data, length)
 
 #endif /* _LINUX_CRC32_H */
--- 2.5/lib/crc32.c     2002-11-04 23:30:03.000000000 +0100
+++ build-2.5/lib/crc32.c       2002-12-10 19:16:47.000000000 +0100
@@ -255,6 +255,16 @@
 }
 #endif
 
+u32 bitreverse(u32 x)
+{
+       x = (x >> 16) | (x << 16);
+       x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00);
+       x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0);
+       x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc);
+       x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa);
+       return x;
+}
+
 /*
  * A brief CRC tutorial.
  *
@@ -399,16 +409,6 @@
 }
 #endif
 
-static u32 attribute((const)) bitreverse(u32 x)
-{
-       x = (x >> 16) | (x << 16);
-       x = (x >> 8 & 0x00ff00ff) | (x << 8 & 0xff00ff00);
-       x = (x >> 4 & 0x0f0f0f0f) | (x << 4 & 0xf0f0f0f0);
-       x = (x >> 2 & 0x33333333) | (x << 2 & 0xcccccccc);
-       x = (x >> 1 & 0x55555555) | (x << 1 & 0xaaaaaaaa);
-       return x;
-}
-
 static void bytereverse(unsigned char *buf, size_t len)
 {
        while (len--) {
--- 2.5/drivers/net/natsemi.c   2002-11-04 23:30:05.000000000 +0100
+++ build-2.5/drivers/net/natsemi.c     2002-12-10 19:20:01.000000000 +0100
@@ -164,6 +164,7 @@
 #include <linux/delay.h>
 #include <linux/rtnetlink.h>
 #include <linux/mii.h>
+#include <linux/crc32.h>
 #include <asm/processor.h>     /* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -1898,44 +1899,6 @@
        return &np->stats;
 }
 
-/**
- * dp83815_crc - computer CRC for hash table entries
- *
- * Note - this is, for some reason, *not* the same function
- * as ether_crc_le() or ether_crc(), though it uses the
- * same big-endian polynomial.
- */
-#define DP_POLYNOMIAL                  0x04C11DB7
-static unsigned dp83815_crc(int length, unsigned char *data)
-{
-       u32 crc;
-       u8 cur_byte;
-       u8 msb;
-       u8 byte, bit;
-
-       crc = ~0;
-       for (byte=0; byte<length; byte++) {
-               cur_byte = *data++;
-               for (bit=0; bit<8; bit++) {
-                       msb = crc >> 31;
-                       crc <<= 1;
-                       if (msb ^ (cur_byte & 1)) {
-                               crc ^= DP_POLYNOMIAL;
-                               crc |= 1;
-                       }
-                       cur_byte >>= 1;
-               }
-       }
-       crc >>= 23;
-
-       return (crc);
-}
-
-
-void set_bit_le(int offset, unsigned char * data)
-{
-       data[offset >> 3] |= (1 << (offset & 0x07));
-}
 #define HASH_TABLE     0x200
 static void __set_rx_mode(struct net_device *dev)
 {
@@ -1960,9 +1923,8 @@
                memset(mc_filter, 0, sizeof(mc_filter));
                for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
                         i++, mclist = mclist->next) {
-                       set_bit_le(
-                               dp83815_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
-                               mc_filter);
+                       int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 
0x1ff;
+                       mc_filter[i/8] |= (1 << (i & 0x07));
                }
                rx_mode = RxFilterEnable | AcceptBroadcast
                        | AcceptMulticast | AcceptMyPhys;
<Prev in Thread] Current Thread [Next in Thread>
  • ether_crc wrong in 2.5.50, Manfred Spraul <=