Title: [8241] branches/2009R1/drivers/net/bfin_mac.c: Bug[#5847] bfin mac hw csum doesn't support ipv6 and ipv4 with head options.
- Revision
- 8241
- Author
- sonicz
- Date
- 2010-01-27 01:16:07 -0500 (Wed, 27 Jan 2010)
Log Message
Bug[#5847] bfin mac hw csum doesn't support ipv6 and ipv4 with head options.
Apply patch from Jon Kowal<[email protected]>
blackfin checksum calculation is based on the assumption that a standard
IP packet has a header length of 20 bytes which is true for most IPv4
packets. This assumption is not true for IPv6 packets or IPv4 packets
that make use of header options. We must NOT use the blackfin calculated
checksum for those packets.
Modified Paths
Diff
Modified: branches/2009R1/drivers/net/bfin_mac.c (8240 => 8241)
--- branches/2009R1/drivers/net/bfin_mac.c 2010-01-27 06:12:09 UTC (rev 8240)
+++ branches/2009R1/drivers/net/bfin_mac.c 2010-01-27 06:16:07 UTC (rev 8241)
@@ -680,6 +680,7 @@
return 0;
}
+#define IP_HEADER_OFF 0
#define ETH_FCS_LENGTH 4
#define RX_ERROR_MASK (RX_LONG | RX_ALIGN | RX_CRC | RX_LEN | \
RX_FRAG | RX_ADDR | RX_DMAO | RX_PHY | RX_LATE | RX_RANGE)
@@ -730,25 +731,32 @@
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
#if defined(BFIN_MAC_CSUM_OFFLOAD)
- skb->csum = current_rx_ptr->status.ip_payload_csum;
- /*
- * Deduce Ethernet FCS from hardware generated IP payload checksum.
- * IP checksum is based on 16-bit one's complement algorithm.
- * To deduce a value from checksum is equal to add its inversion.
- * If the IP payload len is odd, the inversed FCS should also
- * begin from odd address and leave first byte zero.
+ /* Checksum offloading only works for IPv4 packets with the standard IP header
+ * length of 20 bytes, because the blackfin MAC checksum calculation is
+ * based on that assumption. We must NOT use the calculated checksum if our
+ * IP version or header break that assumption.
*/
- if (skb->len % 2) {
- fcs[0] = 0;
- for (i = 0; i < ETH_FCS_LENGTH; i++)
- fcs[i + 1] = ~skb->data[skb->len + i];
- skb->csum = csum_partial(fcs, ETH_FCS_LENGTH + 1, skb->csum);
- } else {
- for (i = 0; i < ETH_FCS_LENGTH; i++)
- fcs[i] = ~skb->data[skb->len + i];
- skb->csum = csum_partial(fcs, ETH_FCS_LENGTH, skb->csum);
+ if (skb->data[IP_HEADER_OFF] == 0x45) {
+ skb->csum = current_rx_ptr->status.ip_payload_csum;
+ /*
+ * Deduce Ethernet FCS from hardware generated IP payload checksum.
+ * IP checksum is based on 16-bit one's complement algorithm.
+ * To deduce a value from checksum is equal to add its inversion.
+ * If the IP payload len is odd, the inversed FCS should also
+ * begin from odd address and leave first byte zero.
+ */
+ if (skb->len % 2) {
+ fcs[0] = 0;
+ for (i = 0; i < ETH_FCS_LENGTH; i++)
+ fcs[i + 1] = ~skb->data[skb->len + i];
+ skb->csum = csum_partial(fcs, ETH_FCS_LENGTH + 1, skb->csum);
+ } else {
+ for (i = 0; i < ETH_FCS_LENGTH; i++)
+ fcs[i] = ~skb->data[skb->len + i];
+ skb->csum = csum_partial(fcs, ETH_FCS_LENGTH, skb->csum);
+ }
+ skb->ip_summed = CHECKSUM_COMPLETE;
}
- skb->ip_summed = CHECKSUM_COMPLETE;
#endif
netif_rx(skb);
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits