Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Mar 2003 07:43:19 +0900
From:      Chiharu Shibata <chi@bd.mbn.or.jp>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/49957: CRC32 generator should be the common routine
Message-ID:  <200303080155.h281tGD09709.chi@bd.mbn.or.jp>

next in thread | raw e-mail | index | archive | help

>Number:         49957
>Category:       kern
>Synopsis:       CRC32 generator should be the common routine
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Mar 12 05:30:10 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:     Chiharu Shibata
>Release:        any
>Organization:
Japan FreeBSD Users Group
>Environment:
	Using NIC for ethernet
>Description:
	Many NIC needs CRC32 generator to receive multicast packets,
	and each NIC driver has it locally.
	We should make the common routine of CRC32 generator.
	(NetBSD already did so.)
>How-To-Repeat:
	none
>Fix:
	Here is the patch of the common CRC32 generator routines.
	The table-driven version of big-endian is contributed by 
	Seishi Hiragushi.

--- sys/net/if_ethersubr.c	2003/02/02 11:29:47	1.2
+++ if_ethersubr.c	2003/03/07 07:36:36
@@ -49,6 +49,7 @@
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/sysctl.h>
+#include <sys/types.h>
 
 #include <net/if.h>
 #include <net/netisr.h>
@@ -914,3 +915,95 @@
 	}
 }
 
+#if 0
+#define CRC32_POLY_BE	0x04c11db7UL
+#define CRC32_POLY_LE	0xedb88320UL
+
+/*
+ * These are for reference.  We have a table-driven version
+ * of the crc32 generator, which is faster than the double-loop.
+ */
+u_int32_t
+ether_crc32_be(const u_int8_t *buf, size_t len)
+{
+	u_int32_t	crc = ~0;
+	u_int8_t	b;
+	int	carry, i, j;
+
+	for (i = 0; i < len; ++i) {
+		b = *buf++;
+		for (j = 8; --j >= 0;) {
+			carry = ((crc & 0x80000000) ? 1 : 0) ^ (b & 0x01);
+			crc <<= 1;
+			b >>= 1;
+			if (carry)
+				crc ^= CRC32_POLY_BE;
+		}
+	}
+	return crc;
+}
+
+u_int32_t
+ether_crc32_le(const u_int8_t *buf, size_t len)
+{
+	u_int32_t	crc = ~0;
+	u_int8_t	b;
+	int	carry, i, j;
+
+	for (i = 0; i < len; ++i) {
+		b = *buf++;
+		for (j = 8; --j >= 0;) {
+			carry = ((crc & 0x01) ? 1 : 0) ^ (b & 0x01);
+			crc >>= 1;
+			b >>= 1;
+			if (carry)
+				crc ^= CRC32_POLY_LE;
+		}
+	}
+	return crc;
+}
+#else
+u_int32_t
+ether_crc32_be(const u_int8_t *buf, size_t len)
+{
+	u_int32_t	crc = ~0;
+	int	i;
+
+	static u_int8_t	cnv[] = {
+		0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15,
+	};
+
+	static const u_int32_t	crctab[] = {
+		0x00000000UL, 0x04c11db7UL, 0x09823b6eUL, 0x0d4326d9UL,
+		0x130476dcUL, 0x17c56b6bUL, 0x1a864db2UL, 0x1e475005UL,
+		0x2608edb8UL, 0x22c9f00fUL, 0x2f8ad6d6UL, 0x2b4bcb61UL,
+		0x350c9b64UL, 0x31cd86d3UL, 0x3c8ea00aUL, 0x384fbdbdUL,
+	};
+
+	for (i = 0; i < len; ++i) {
+		crc = (crc << 4) ^ crctab[(crc >> 28) ^ cnv[*buf & 0xf]];
+		crc = (crc << 4) ^ crctab[(crc >> 28) ^ cnv[*buf++ >>4]];
+	}
+	return crc;
+}
+
+u_int32_t
+ether_crc32_le(const u_int8_t *buf, size_t len)
+{
+	u_int32_t	crc = ~0;
+	int	i;
+	static const u_int32_t	crctab[] = {
+		0x00000000UL, 0x1db71064UL, 0x3b6e20c8UL, 0x26d930acUL,
+		0x76dc4190UL, 0x6b6b51f4UL, 0x4db26158UL, 0x5005713cUL,
+		0xedb88320UL, 0xf00f9344UL, 0xd6d6a3e8UL, 0xcb61b38cUL,
+		0x9b64c2b0UL, 0x86d3d2d4UL, 0xa00ae278UL, 0xbdbdf21cUL,
+	};
+
+	for (i = 0; i < len; ++i) {
+		crc ^= *buf++;
+		crc = (crc >> 4) ^ crctab[crc & 0xf];
+		crc = (crc >> 4) ^ crctab[crc & 0xf];
+	}
+	return crc;
+}
+#endif
--- sys/net/if_var.h	2003/02/02 11:44:23	1.1
+++ if_var.h	2003/02/02 11:49:22
@@ -74,6 +74,9 @@
 #endif
 
 #include <sys/queue.h>		/* get TAILQ macros */
+#ifdef _KERNEL
+#include <sys/types.h>		/* u_int* */
+#endif
 
 TAILQ_HEAD(ifnethead, ifnet);	/* we use TAILQs so that the order of */
 TAILQ_HEAD(ifaddrhead, ifaddr);	/* instantiation is preserved in the list */
@@ -332,6 +335,8 @@
 	   struct mbuf *, struct sockaddr *, struct rtentry *));
 int	ether_output_frame __P((struct ifnet *, struct mbuf *));
 int	ether_ioctl __P((struct ifnet *, int, caddr_t));
+u_int32_t ether_crc32_be __P((const u_int8_t *, size_t));
+u_int32_t ether_crc32_le __P((const u_int8_t *, size_t));
 
 int	if_addmulti __P((struct ifnet *, struct sockaddr *,
 			 struct ifmultiaddr **));

%%%%%%%%%%%%%%%%
	In addition, the follows are sample patches for NIC driver.
	Many NIC drivers need to modify like this.

--- sys/pci/if_dc.c	2003/02/02 12:26:40	1.1
+++ if_dc.c	2003/02/02 12:52:19
@@ -229,7 +229,6 @@
 
 static void dc_setcfg		__P((struct dc_softc *, int));
 static u_int32_t dc_crc_le	__P((struct dc_softc *, caddr_t));
-static u_int32_t dc_crc_be	__P((caddr_t));
 static void dc_setfilt_21143	__P((struct dc_softc *));
 static void dc_setfilt_asix	__P((struct dc_softc *));
 static void dc_setfilt_admtek	__P((struct dc_softc *));
@@ -901,7 +900,6 @@
 	return;
 }
 
-#define DC_POLY		0xEDB88320
 #define DC_BITS_512	9
 #define DC_BITS_128	7
 #define DC_BITS_64	6
@@ -910,15 +908,10 @@
 	struct dc_softc		*sc;
 	caddr_t			addr;
 {
-	u_int32_t		idx, bit, data, crc;
+	u_int32_t		crc;
 
 	/* Compute CRC for the address value. */
-	crc = 0xFFFFFFFF; /* initial value */
-
-	for (idx = 0; idx < 6; idx++) {
-		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
-			crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0);
-	}
+	crc = ether_crc32_le(addr, ETHER_ADDR_LEN);
 
 	/*
 	 * The hash table on the PNIC II and the MX98715AEC-C/D/E
@@ -937,30 +930,7 @@
 /*
  * Calculate CRC of a multicast group address, return the lower 6 bits.
  */
-static u_int32_t dc_crc_be(addr)
-	caddr_t			addr;
-{
-	u_int32_t		crc, carry;
-	int			i, j;
-	u_int8_t		c;
-
-	/* Compute CRC for the address value. */
-	crc = 0xFFFFFFFF; /* initial value */
-
-	for (i = 0; i < 6; i++) {
-		c = *(addr + i);
-		for (j = 0; j < 8; j++) {
-			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
-			crc <<= 1;
-			c >>= 1;
-			if (carry)
-				crc = (crc ^ 0x04c11db6) | carry;
-		}
-	}
-
-	/* return the filter bit position */
-	return((crc >> 26) & 0x0000003F);
-}
+#define dc_crc_be(addr)	((ether_crc32_be((addr), ETHER_ADDR_LEN) >> 26) & 0x3F)
 
 /*
  * 21143-style RX filter setup routine. Filter programming is done by
--- sys/i386/isa/if_lnc.c	2003/02/02 12:54:23	1.1
+++ if_lnc.c	2003/02/02 12:50:57
@@ -218,27 +218,11 @@
 	return (inw(sc->bdp));
 }
 
-static __inline u_long
-ether_crc(const u_char *ether_addr)
-{
-#define POLYNOMIAL           0xEDB88320UL
-    u_char i, j, addr;
-    u_int crc = 0xFFFFFFFFUL;
-
-    for (i = 0; i < ETHER_ADDR_LEN; i++) {
-	addr = *ether_addr++;
-	for (j = 0; j < MULTICAST_FILTER_LEN; j++) {
-	    crc = (crc >> 1) ^ (((crc ^ addr) & 1) ? POLYNOMIAL : 0);   
-	    addr >>= 1;
-	}
-    }
-    return crc;
-#undef POLYNOMIAL
-}
-
 /*
  * Set up the logical address filter for multicast packets
  */
+#define	ether_crc(ep)	(ether_crc32_le((ep), ETHER_ADDR_LEN) >> 26)
+
 static __inline void
 lnc_setladrf(struct lnc_softc *sc)
 {
@@ -266,8 +250,7 @@
 		if (ifma->ifma_addr->sa_family != AF_LINK)
 			continue;
 
-		index = ether_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr))
-				>> 26;
+		index = ether_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
 		sc->init_block->ladrf[index >> 3] |= 1 << (index & 7);
 	}
 }
--- sys/dev/ed/if_ed.c	2003/02/02 11:12:50	1.1
+++ if_ed.c	2003/02/02 11:12:53
@@ -102,7 +102,6 @@
 
 static void	ed_setrcr	__P((struct ed_softc *));
 
-static u_int32_t ds_crc		__P((u_char *ep));
 
 /*
  * Interrupt conversion table for WD/SMC ASIC/83C584
@@ -3398,35 +3397,11 @@
 }
 
 /*
- * Compute crc for ethernet address
- */
-static u_int32_t
-ds_crc(ep)
-	u_char *ep;
-{
-#define POLYNOMIAL 0x04c11db6
-	register u_int32_t crc = 0xffffffff;
-	register int carry, i, j;
-	register u_char b;
-
-	for (i = 6; --i >= 0;) {
-		b = *ep++;
-		for (j = 8; --j >= 0;) {
-			carry = ((crc & 0x80000000) ? 1 : 0) ^ (b & 0x01);
-			crc <<= 1;
-			b >>= 1;
-			if (carry)
-				crc = (crc ^ POLYNOMIAL) | carry;
-		}
-	}
-	return crc;
-#undef POLYNOMIAL
-}
-
-/*
  * Compute the multicast address filter from the
  * list of multicast addresses we need to listen to.
  */
+#define	ds_crc(ep)	(ether_crc32_be((ep), ETHER_ADDR_LEN) >> 26)
+
 static void
 ds_getmcaf(sc, mcaf)
 	struct ed_softc *sc;
@@ -3443,8 +3418,7 @@
 	     ifma = ifma->ifma_link.le_next) {
 		if (ifma->ifma_addr->sa_family != AF_LINK)
 			continue;
-		index = ds_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr))
-			>> 26;
+		index = ds_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
 		af[index >> 3] |= 1 << (index & 7);
 	}
 }
--- sys/dev/fe/if_fe.c	2003/02/02 12:48:36	1.1
+++ if_fe.c	2003/02/02 12:51:52
@@ -2085,34 +2085,11 @@
 }
 
 /*
- * Compute hash value for an Ethernet address
- */
-static int
-fe_hash ( u_char * ep )
-{
-#define FE_HASH_MAGIC_NUMBER 0xEDB88320L
-
-	u_long hash = 0xFFFFFFFFL;
-	int i, j;
-	u_char b;
-	u_long m;
-
-	for ( i = ETHER_ADDR_LEN; --i >= 0; ) {
-		b = *ep++;
-		for ( j = 8; --j >= 0; ) {
-			m = hash;
-			hash >>= 1;
-			if ( ( m ^ b ) & 1 ) hash ^= FE_HASH_MAGIC_NUMBER;
-			b >>= 1;
-		}
-	}
-	return ( ( int )( hash >> 26 ) );
-}
-
-/*
  * Compute the multicast address filter from the
  * list of multicast addresses we need to listen to.
  */
+#define	fe_hash(ep)	(ether_crc32_le((ep), ETHER_ADDR_LEN) >> 26)
+
 static struct fe_filter
 fe_mcaf ( struct fe_softc *sc )
 {
--- sys/dev/usb/if_cue.c	2003/02/02 02:18:59	1.1
+++ if_cue.c	2003/02/02 02:22:48
@@ -117,7 +117,6 @@
 Static void cue_shutdown		__P((device_t));
 
 Static void cue_setmulti	__P((struct cue_softc *));
-Static u_int32_t cue_crc	__P((caddr_t));
 Static void cue_reset		__P((struct cue_softc *));
 
 Static int csr_read_1		__P((struct cue_softc *, int));
@@ -348,24 +347,10 @@
 	return(0);
 }
 
-#define CUE_POLY	0xEDB88320
 #define CUE_BITS	9
 
-Static u_int32_t cue_crc(addr)
-	caddr_t			addr;
-{
-	u_int32_t		idx, bit, data, crc;
-
-	/* Compute CRC for the address value. */
-	crc = 0xFFFFFFFF; /* initial value */
-
-	for (idx = 0; idx < 6; idx++) {
-		for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1)
-			crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CUE_POLY : 0);
-	}
-
-	return (crc & ((1 << CUE_BITS) - 1));
-}
+#define	cue_crc(addr)	(ether_crc32_le((addr), ETHER_ADDR_LEN) \
+				& ((1 << CUE_BITS) - 1))
 
 Static void cue_setmulti(sc)
 	struct cue_softc	*sc;
>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200303080155.h281tGD09709.chi>