diff options
author | naddy <naddy@FreeBSD.org> | 2004-06-02 21:34:14 +0000 |
---|---|---|
committer | naddy <naddy@FreeBSD.org> | 2004-06-02 21:34:14 +0000 |
commit | 00ef0952615323d2902cc53eba57204553d65c76 (patch) | |
tree | 78c74dce0325352d0d283b6fd918081622ada4cf /sys/net | |
parent | f53d93d179b368c4c403823d034302b594307b2d (diff) | |
download | FreeBSD-src-00ef0952615323d2902cc53eba57204553d65c76.zip FreeBSD-src-00ef0952615323d2902cc53eba57204553d65c76.tar.gz |
Add helper functions to calculate the standard ethernet CRC in
little/big endian fashion, so that network drivers can just reference
the standard implementation and don't have to bring their own.
As discussed on arch@.
Obtained from: NetBSD
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/ethernet.h | 2 | ||||
-rw-r--r-- | sys/net/if_ethersubr.c | 73 |
2 files changed, 75 insertions, 0 deletions
diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h index f804591..27fb6d5 100644 --- a/sys/net/ethernet.h +++ b/sys/net/ethernet.h @@ -350,6 +350,8 @@ struct mbuf; struct rtentry; struct sockaddr; +extern uint32_t ether_crc32_le(const uint8_t *, size_t); +extern uint32_t ether_crc32_be(const uint8_t *, size_t); extern void ether_demux(struct ifnet *, struct mbuf *); extern void ether_ifattach(struct ifnet *, const u_int8_t *); extern void ether_ifdetach(struct ifnet *); diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 66941ac..6da30d24 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -879,6 +879,79 @@ SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); SYSCTL_INT(_net_link_ether, OID_AUTO, ipfw, CTLFLAG_RW, ðer_ipfw,0,"Pass ether pkts through firewall"); +#if 0 +/* + * This is for reference. We have a table-driven version + * of the little-endian crc32 generator, which is faster + * than the double-loop. + */ +uint32_t +ether_crc32_le(const uint8_t *buf, size_t len) +{ + size_t i; + uint32_t crc; + int bit; + uint8_t data; + + crc = 0xffffffff; /* initial value */ + + for (i = 0; i < len; i++) { + for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1) + carry = (crc ^ data) & 1; + crc >>= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_LE); + } + + return (crc); +} +#else +uint32_t +ether_crc32_le(const uint8_t *buf, size_t len) +{ + static const uint32_t crctab[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + size_t i; + uint32_t crc; + + crc = 0xffffffff; /* initial value */ + + for (i = 0; i < len; i++) { + crc ^= buf[i]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + crc = (crc >> 4) ^ crctab[crc & 0xf]; + } + + return (crc); +} +#endif + +uint32_t +ether_crc32_be(const uint8_t *buf, size_t len) +{ + size_t i; + uint32_t crc, carry; + int bit; + uint8_t data; + + crc = 0xffffffff; /* initial value */ + + for (i = 0; i < len; i++) { + for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1) { + carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01); + crc <<= 1; + if (carry) + crc = (crc ^ ETHER_CRC_POLY_BE) | carry; + } + } + + return (crc); +} + int ether_ioctl(struct ifnet *ifp, int command, caddr_t data) { |