[665] in linux-net channel archive
Checksum problem fixed
daemon@ATHENA.MIT.EDU (Paul Gortmaker)
Thu Jul 13 21:03:14 1995
From: Paul Gortmaker <gpg109@rsphy1.anu.edu.au>
To: iialan@www.linux.org.uk (Alan Cox)
Date: Fri, 14 Jul 1995 00:51:20 +1000 (EST)
Cc: ftom@netcom.com, torvalds@cs.Helsinki.FI (Linus Torvalds),
linux-net@vger.rutgers.edu
Hi Alan,
I found the checksum problem, and it was not Tom's asm code
afterall (sorry Tom). The fix is obvious once you know the problem.
It was breaking on packets that were padded up to the 60 byte minimum
because we were copying and csuming the padding as well.
Now that eth_copy_and_sum() works, I will work on converting shared
memory 8390 cards to use it. The only snag will be if the packet
is wrapped around the Rx ring boundary (and thus in 2 chunks) then
we won't be able to use eth_copy_and_sum(). In that case, the csum
will be done later by the upper layers as it is now.
Anyway, here is the fix. Lance cards finally work again.
Regards,
Paul.
--- /linux-oem-139/net/ethernet/eth.c Wed Jul 12 13:34:55 1995
+++ linux/net/ethernet/eth.c Fri Jul 14 00:04:42 1995
@@ -26,6 +26,7 @@
* Alan Cox : ARP only when compiled with CONFIG_INET
* Greg Page : 802.2 and SNAP stuff.
* Alan Cox : MAC layer pointers/new format.
+ * Paul Gortmaker : eth_copy_and_sum shouldn't csum padding.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -231,11 +232,13 @@
/*
* Copy from an ethernet device memory space to an sk_buff while checksumming if IP
+ * The magic "34" is Rx_addr+Tx_addr+type_field+sizeof(struct iphdr) == 6+6+2+20.
*/
void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base)
{
struct ethhdr *eth;
+ struct iphdr *iph;
IS_SKB(dest);
eth=(struct ethhdr *)dest->data;
@@ -246,6 +249,14 @@
memcpy(dest->data+34,src+34,length);
return;
}
+ /*
+ * We have to watch for padded packets. The csum doesn't include the
+ * padding, and there is no point in copying the padding anyway.
+ */
+ iph=(struct iphdr*)(src+14); /* 14 = Rx_addr+Tx_addr+type_field */
+ if (ntohs(iph->tot_len)-sizeof(struct iphdr) <= length)
+ length=ntohs(iph->tot_len)-sizeof(struct iphdr);
+
dest->csum=csum_partial_copy(src+34,dest->data+34,length,base);
dest->ip_summed=1;
}