diff options
author | Guo-Fu Tseng <cooldavid@cooldavid.org> | 2011-02-13 22:27:17 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-14 08:44:43 +0300 |
commit | c00cd82641023ade3c44b4f11140a8afad460415 (patch) | |
tree | ebabaf3e94536309efbfea8f0079d951db2b9114 /drivers/net/jme.c | |
parent | 8b53abae582cee9a17320460e0f05474097192b6 (diff) | |
download | linux-c00cd82641023ade3c44b4f11140a8afad460415.tar.xz |
jme: Don't show UDP Checksum error if HW misjudged
Some JMicron Chip treat 0 as error checksum for UDP packets.
Which should be "No checksum needed".
Reported-by: Adam Swift <Adam.Swift@omnitude.net>
Confirmed-by: "Aries Lee" <arieslee@jmicron.com>
Signed-off-by: Guo-Fu Tseng <cooldavid@cooldavid.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/jme.c')
-rw-r--r-- | drivers/net/jme.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/drivers/net/jme.c b/drivers/net/jme.c index ed35e17f43dc..5b441b75e138 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -956,8 +956,34 @@ jme_disable_rx_engine(struct jme_adapter *jme) jme_mac_rxclk_off(jme); } +static u16 +jme_udpsum(struct sk_buff *skb) +{ + u16 csum = 0xFFFFu; + + if (skb->len < (ETH_HLEN + sizeof(struct iphdr))) + return csum; + if (skb->protocol != htons(ETH_P_IP)) + return csum; + skb_set_network_header(skb, ETH_HLEN); + if ((ip_hdr(skb)->protocol != IPPROTO_UDP) || + (skb->len < (ETH_HLEN + + (ip_hdr(skb)->ihl << 2) + + sizeof(struct udphdr)))) { + skb_reset_network_header(skb); + return csum; + } + skb_set_transport_header(skb, + ETH_HLEN + (ip_hdr(skb)->ihl << 2)); + csum = udp_hdr(skb)->check; + skb_reset_transport_header(skb); + skb_reset_network_header(skb); + + return csum; +} + static int -jme_rxsum_ok(struct jme_adapter *jme, u16 flags) +jme_rxsum_ok(struct jme_adapter *jme, u16 flags, struct sk_buff *skb) { if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4))) return false; @@ -970,7 +996,7 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags) } if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS)) - == RXWBFLAG_UDPON)) { + == RXWBFLAG_UDPON) && jme_udpsum(skb)) { if (flags & RXWBFLAG_IPV4) netif_err(jme, rx_err, jme->dev, "UDP Checksum error\n"); return false; @@ -1018,7 +1044,7 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) skb_put(skb, framesize); skb->protocol = eth_type_trans(skb, jme->dev); - if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags))) + if (jme_rxsum_ok(jme, le16_to_cpu(rxdesc->descwb.flags), skb)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb_checksum_none_assert(skb); |