[CASSINI]: Fix endianness bug.
Here's proposed fix for RX checksum handling in cassini; it affects
little-endian working with half-duplex gigabit, but obviously needs
testing on big-endian too.
The problem is, we need to convert checksum to fixed-endian *before*
correcting for (unstripped) FCS. On big-endian it won't matter
(conversion is no-op), on little-endian it will, but only if FCS is
not stripped by hardware; i.e. in half-duplex gigabit mode when
->crc_size is set.
cassini.c part is that fix, cassini.h one consists of trivial
endianness annotations. With that applied the sucker is endian-clean,
according to sparse.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 7df31b5..9030ca5 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -1979,6 +1979,7 @@
struct cas_page *page;
struct sk_buff *skb;
void *addr, *crcaddr;
+ __sum16 csum;
char *p;
hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
@@ -2158,14 +2159,15 @@
skb_put(skb, alloclen);
}
- i = CAS_VAL(RX_COMP4_TCP_CSUM, words[3]);
+ csum = (__force __sum16)htons(CAS_VAL(RX_COMP4_TCP_CSUM, words[3]));
if (cp->crc_size) {
/* checksum includes FCS. strip it out. */
- i = csum_fold(csum_partial(crcaddr, cp->crc_size, i));
+ csum = csum_fold(csum_partial(crcaddr, cp->crc_size,
+ csum_unfold(csum)));
if (addr)
cas_page_unmap(addr);
}
- skb->csum = ntohs(i ^ 0xffff);
+ skb->csum = csum_unfold(~csum);
skb->ip_summed = CHECKSUM_COMPLETE;
skb->protocol = eth_type_trans(skb, cp->dev);
return len;