]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/e1000/e1000_main.c
e1000: don't generate bad checksums for tcp packets with 0 csum
[linux-2.6-omap-h63xx.git] / drivers / net / e1000 / e1000_main.c
index 2ab44db29fac308d1e800babe0bbf82143d1ca3a..3bafaede7916f844696cbdef0c6e01fa8ede6b1e 100644 (file)
@@ -2873,32 +2873,49 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter,
        struct e1000_buffer *buffer_info;
        unsigned int i;
        u8 css;
+       u32 cmd_len = E1000_TXD_CMD_DEXT;
 
-       if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
-               css = skb_transport_offset(skb);
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return false;
 
-               i = tx_ring->next_to_use;
-               buffer_info = &tx_ring->buffer_info[i];
-               context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP):
+               if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+                       cmd_len |= E1000_TXD_CMD_TCP;
+               break;
+       case __constant_htons(ETH_P_IPV6):
+               /* XXX not handling all IPV6 headers */
+               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+                       cmd_len |= E1000_TXD_CMD_TCP;
+               break;
+       default:
+               if (unlikely(net_ratelimit()))
+                       DPRINTK(DRV, WARNING,
+                               "checksum_partial proto=%x!\n", skb->protocol);
+               break;
+       }
 
-               context_desc->lower_setup.ip_config = 0;
-               context_desc->upper_setup.tcp_fields.tucss = css;
-               context_desc->upper_setup.tcp_fields.tucso =
-                       css + skb->csum_offset;
-               context_desc->upper_setup.tcp_fields.tucse = 0;
-               context_desc->tcp_seg_setup.data = 0;
-               context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
+       css = skb_transport_offset(skb);
 
-               buffer_info->time_stamp = jiffies;
-               buffer_info->next_to_watch = i;
+       i = tx_ring->next_to_use;
+       buffer_info = &tx_ring->buffer_info[i];
+       context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
 
-               if (unlikely(++i == tx_ring->count)) i = 0;
-               tx_ring->next_to_use = i;
+       context_desc->lower_setup.ip_config = 0;
+       context_desc->upper_setup.tcp_fields.tucss = css;
+       context_desc->upper_setup.tcp_fields.tucso =
+               css + skb->csum_offset;
+       context_desc->upper_setup.tcp_fields.tucse = 0;
+       context_desc->tcp_seg_setup.data = 0;
+       context_desc->cmd_and_length = cpu_to_le32(cmd_len);
 
-               return true;
-       }
+       buffer_info->time_stamp = jiffies;
+       buffer_info->next_to_watch = i;
 
-       return false;
+       if (unlikely(++i == tx_ring->count)) i = 0;
+       tx_ring->next_to_use = i;
+
+       return true;
 }
 
 #define E1000_MAX_TXD_PWR      12