]> xenbits.xensource.com Git - xenclient/kernel.git/commitdiff
It turns out that Windows occasionally generates packets in which the netback-rx-offset
authort_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:06:02 +0000 (12:06 +0000)
committert_jeang <devnull@localhost>
Tue, 6 Jan 2009 12:06:02 +0000 (12:06 +0000)
IP and TCP headers are in different fragments.  Make sure that the
backends can handle this.

drivers/xen/netback/xenbus.c
net/core/dev.c

index a7835068ac655062e0215613f3b7e81198909af4..774da6dfba17961b26ddadfb16cd6026c1a76ac0 100644 (file)
@@ -112,6 +112,16 @@ static int netback_probe(struct xenbus_device *dev,
                        goto abort_transaction;
                }
 
+               /* We can cope with transmit checksum offload packets
+                  in which the TCP and IP headers are in separate
+                  fragments. */
+               err = xenbus_printf(xbt, dev->nodename,
+                                   "feature-tx-csum-split-header", "%d", 1);
+               if (err) {
+                       message = "writing feature-tx-csum-split-header";
+                       goto abort_transaction;
+               }
+
                /*
                 * We don't support rx-flip path (except old guests who don't
                 * grok this feature flag).
index be9c3f9358be1096bca4b4e700491332470b2829..82d943939e1c524beab131fe8a89d8957a6c49b2 100644 (file)
@@ -1399,14 +1399,26 @@ out_kfree_skb:
 }
 
 #ifdef CONFIG_XEN
+static int skb_pull_up_to(struct sk_buff *skb, void *ptr)
+{
+       if (ptr < (void *)skb->tail)
+               return 1;
+       if (__pskb_pull_tail(skb,
+                            ptr - (void *)skb->data - skb_headlen(skb))) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
 inline int skb_checksum_setup(struct sk_buff *skb)
 {
        if (skb->proto_csum_blank) {
                if (skb->protocol != htons(ETH_P_IP))
                        goto out;
-               skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
-               if (skb->h.raw >= skb->tail)
+               if (!skb_pull_up_to(skb, skb->nh.iph + 1))
                        goto out;
+               skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
                switch (skb->nh.iph->protocol) {
                case IPPROTO_TCP:
                        skb->csum = offsetof(struct tcphdr, check);
@@ -1421,7 +1433,7 @@ inline int skb_checksum_setup(struct sk_buff *skb)
                                       " %d packet", skb->nh.iph->protocol);
                        goto out;
                }
-               if ((skb->h.raw + skb->csum + 2) > skb->tail)
+               if (!skb_pull_up_to(skb, skb->h.raw + skb->csum + 2))
                        goto out;
                skb->ip_summed = CHECKSUM_HW;
                skb->proto_csum_blank = 0;