+#ifdef NEED_CSUM_NORMALIZE
+
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
+/* This code is based on skb_checksum_setup() from Xen's net/dev/core.c. We
+ * can't call this function directly because it isn't exported in all
+ * versions. */
+static int vswitch_skb_checksum_setup(struct sk_buff *skb)
+{
+ struct iphdr *iph;
+ unsigned char *th;
+ int err = -EPROTO;
+ __u16 csum_start, csum_offset;
+
+ if (!skb->proto_csum_blank)
+ return 0;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ goto out;
+
+ if (!pskb_may_pull(skb, skb_network_header(skb) + sizeof(struct iphdr) - skb->data))
+ goto out;
+
+ iph = ip_hdr(skb);
+ th = skb_network_header(skb) + 4 * iph->ihl;
+
+ csum_start = th - skb->head;
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ csum_offset = offsetof(struct tcphdr, check);
+ break;
+ case IPPROTO_UDP:
+ csum_offset = offsetof(struct udphdr, check);
+ break;
+ default:
+ if (net_ratelimit())
+ pr_err("Attempting to checksum a non-TCP/UDP packet, "
+ "dropping a protocol %d packet",
+ iph->protocol);
+ goto out;
+ }
+
+ if (!pskb_may_pull(skb, th + csum_offset + 2 - skb->data))
+ goto out;
+
+ skb->proto_csum_blank = 0;
+ set_ip_summed(skb, OVS_CSUM_PARTIAL);
+ set_skb_csum_pointers(skb, csum_start, csum_offset);
+
+ err = 0;
+
+out:
+ return err;
+}
+#else
+static int vswitch_skb_checksum_setup(struct sk_buff *skb)
+{
+ return 0;
+}
+#endif /* not Xen old style checksums */
+
+/*
+ * compute_ip_summed - map external checksum state onto OVS representation
+ *
+ * @skb: Packet to manipulate.
+ * @xmit: Whether we were on transmit path of network stack. For example,
+ * this is true for the internal dev vport because it receives skbs
+ * that passed through dev_queue_xmit() but false for the netdev vport
+ * because its packets come from netif_receive_skb().
+ *
+ * Older kernels (and various versions of Xen) were not explicit enough about
+ * checksum offload parameters and rely on a combination of context and
+ * non standard fields. This deals with all those variations so that we
+ * can internally manipulate checksum offloads without worrying about kernel
+ * version.
+ *
+ * Types of checksums that we can receive (these all refer to L4 checksums):