aboutsummaryrefslogtreecommitdiffstats
path: root/patches/linux-2.6.17/net-gso-2-checksum-fix.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/linux-2.6.17/net-gso-2-checksum-fix.patch')
-rw-r--r--patches/linux-2.6.17/net-gso-2-checksum-fix.patch459
1 files changed, 459 insertions, 0 deletions
diff --git a/patches/linux-2.6.17/net-gso-2-checksum-fix.patch b/patches/linux-2.6.17/net-gso-2-checksum-fix.patch
new file mode 100644
index 0000000000..db228e1546
--- /dev/null
+++ b/patches/linux-2.6.17/net-gso-2-checksum-fix.patch
@@ -0,0 +1,459 @@
+diff -pruN ../orig-linux-2.6.17/drivers/net/bnx2.c ./drivers/net/bnx2.c
+--- ../orig-linux-2.6.17/drivers/net/bnx2.c 2007-01-08 15:16:27.000000000 +0000
++++ ./drivers/net/bnx2.c 2007-01-08 15:25:03.000000000 +0000
+@@ -1638,7 +1638,7 @@ bnx2_tx_int(struct bnx2 *bp)
+ skb = tx_buf->skb;
+ #ifdef BCM_TSO
+ /* partial BD completions possible with TSO packets */
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ u16 last_idx, last_ring_idx;
+
+ last_idx = sw_cons +
+diff -pruN ../orig-linux-2.6.17/drivers/net/chelsio/sge.c ./drivers/net/chelsio/sge.c
+--- ../orig-linux-2.6.17/drivers/net/chelsio/sge.c 2007-01-08 15:16:27.000000000 +0000
++++ ./drivers/net/chelsio/sge.c 2007-01-08 15:25:03.000000000 +0000
+@@ -1418,7 +1418,7 @@ int t1_start_xmit(struct sk_buff *skb, s
+ struct cpl_tx_pkt *cpl;
+
+ #ifdef NETIF_F_TSO
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ int eth_type;
+ struct cpl_tx_pkt_lso *hdr;
+
+diff -pruN ../orig-linux-2.6.17/drivers/net/e1000/e1000_main.c ./drivers/net/e1000/e1000_main.c
+--- ../orig-linux-2.6.17/drivers/net/e1000/e1000_main.c 2007-01-08 15:22:36.000000000 +0000
++++ ./drivers/net/e1000/e1000_main.c 2007-01-08 15:26:24.000000000 +0000
+@@ -2413,7 +2413,7 @@ e1000_tso(struct e1000_adapter *adapter,
+ uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
+ int err;
+
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+@@ -2538,7 +2538,7 @@ e1000_tx_map(struct e1000_adapter *adapt
+ * tso gets written back prematurely before the data is fully
+ * DMA'd to the controller */
+ if (!skb->data_len && tx_ring->last_tx_tso &&
+- !skb_shinfo(skb)->gso_size) {
++ !skb_is_gso(skb)) {
+ tx_ring->last_tx_tso = 0;
+ size -= 4;
+ }
+@@ -2825,8 +2825,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
+
+ #ifdef NETIF_F_TSO
+ /* Controller Erratum workaround */
+- if (!skb->data_len && tx_ring->last_tx_tso &&
+- !skb_shinfo(skb)->gso_size)
++ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
+ count++;
+ #endif
+
+diff -pruN ../orig-linux-2.6.17/drivers/net/forcedeth.c ./drivers/net/forcedeth.c
+--- ../orig-linux-2.6.17/drivers/net/forcedeth.c 2007-01-08 15:23:05.000000000 +0000
++++ ./drivers/net/forcedeth.c 2007-01-08 15:25:03.000000000 +0000
+@@ -1303,7 +1303,7 @@ static int nv_start_xmit(struct sk_buff
+ np->tx_skbuff[nr] = skb;
+
+ #ifdef NETIF_F_TSO
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
+ else
+ #endif
+diff -pruN ../orig-linux-2.6.17/drivers/net/ixgb/ixgb_main.c ./drivers/net/ixgb/ixgb_main.c
+--- ../orig-linux-2.6.17/drivers/net/ixgb/ixgb_main.c 2007-01-08 15:16:27.000000000 +0000
++++ ./drivers/net/ixgb/ixgb_main.c 2007-01-08 15:25:03.000000000 +0000
+@@ -1168,7 +1168,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
+ uint16_t ipcse, tucse, mss;
+ int err;
+
+- if(likely(skb_shinfo(skb)->gso_size)) {
++ if (likely(skb_is_gso(skb))) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+diff -pruN ../orig-linux-2.6.17/drivers/net/loopback.c ./drivers/net/loopback.c
+--- ../orig-linux-2.6.17/drivers/net/loopback.c 2007-01-08 15:16:27.000000000 +0000
++++ ./drivers/net/loopback.c 2007-01-08 15:25:03.000000000 +0000
+@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff
+ #endif
+
+ #ifdef LOOPBACK_TSO
+- if (skb_shinfo(skb)->gso_size) {
++ if (skb_is_gso(skb)) {
+ BUG_ON(skb->protocol != htons(ETH_P_IP));
+ BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
+
+diff -pruN ../orig-linux-2.6.17/drivers/net/sky2.c ./drivers/net/sky2.c
+--- ../orig-linux-2.6.17/drivers/net/sky2.c 2007-01-08 15:16:27.000000000 +0000
++++ ./drivers/net/sky2.c 2007-01-08 15:25:03.000000000 +0000
+@@ -1160,7 +1160,7 @@ static unsigned tx_le_req(const struct s
+ count = sizeof(dma_addr_t) / sizeof(u32);
+ count += skb_shinfo(skb)->nr_frags * count;
+
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ ++count;
+
+ if (skb->ip_summed == CHECKSUM_HW)
+diff -pruN ../orig-linux-2.6.17/drivers/net/typhoon.c ./drivers/net/typhoon.c
+--- ../orig-linux-2.6.17/drivers/net/typhoon.c 2007-01-08 15:16:27.000000000 +0000
++++ ./drivers/net/typhoon.c 2007-01-08 15:25:03.000000000 +0000
+@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st
+ * If problems develop with TSO, check this first.
+ */
+ numDesc = skb_shinfo(skb)->nr_frags + 1;
+- if(skb_tso_size(skb))
++ if (skb_is_gso(skb))
+ numDesc++;
+
+ /* When checking for free space in the ring, we need to also
+@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, st
+ TYPHOON_TX_PF_VLAN_TAG_SHIFT);
+ }
+
+- if(skb_tso_size(skb)) {
++ if (skb_is_gso(skb)) {
+ first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
+ first_txd->numDesc++;
+
+diff -pruN ../orig-linux-2.6.17/drivers/s390/net/qeth_main.c ./drivers/s390/net/qeth_main.c
+--- ../orig-linux-2.6.17/drivers/s390/net/qeth_main.c 2007-01-08 15:23:29.000000000 +0000
++++ ./drivers/s390/net/qeth_main.c 2007-01-08 15:26:49.000000000 +0000
+@@ -4417,7 +4417,6 @@ qeth_send_packet(struct qeth_card *card,
+ struct qeth_eddp_context *ctx = NULL;
+ int tx_bytes = skb->len;
+ unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
+- unsigned short gso_size = skb_shinfo(skb)->gso_size;
+ int rc;
+
+ QETH_DBF_TEXT(trace, 6, "sendpkt");
+@@ -4453,7 +4452,7 @@ qeth_send_packet(struct qeth_card *card,
+ queue = card->qdio.out_qs
+ [qeth_get_priority_queue(card, skb, ipv, cast_type)];
+
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ large_send = card->options.large_send;
+
+ /*are we able to do TSO ? If so ,prepare and send it from here */
+@@ -4500,8 +4499,7 @@ qeth_send_packet(struct qeth_card *card,
+ card->stats.tx_packets++;
+ card->stats.tx_bytes += tx_bytes;
+ #ifdef CONFIG_QETH_PERF_STATS
+- if (gso_size &&
+- !(large_send == QETH_LARGE_SEND_NO)) {
++ if (skb_is_gso(skb) && !(large_send == QETH_LARGE_SEND_NO)) {
+ card->perf_stats.large_send_bytes += tx_bytes;
+ card->perf_stats.large_send_cnt++;
+ }
+diff -pruN ../orig-linux-2.6.17/include/linux/netdevice.h ./include/linux/netdevice.h
+--- ../orig-linux-2.6.17/include/linux/netdevice.h 2007-01-08 15:24:25.000000000 +0000
++++ ./include/linux/netdevice.h 2007-01-08 15:25:03.000000000 +0000
+@@ -546,6 +546,7 @@ struct packet_type {
+ struct net_device *);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb,
+ int features);
++ int (*gso_send_check)(struct sk_buff *skb);
+ void *af_packet_priv;
+ struct list_head list;
+ };
+@@ -990,14 +991,15 @@ extern void linkwatch_run_queue(void);
+
+ static inline int skb_gso_ok(struct sk_buff *skb, int features)
+ {
+- int feature = skb_shinfo(skb)->gso_size ?
+- skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
++ int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT;
+ return (features & feature) == feature;
+ }
+
+ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
+ {
+- return !skb_gso_ok(skb, dev->features);
++ return skb_is_gso(skb) &&
++ (!skb_gso_ok(skb, dev->features) ||
++ unlikely(skb->ip_summed != CHECKSUM_HW));
+ }
+
+ #endif /* __KERNEL__ */
+diff -pruN ../orig-linux-2.6.17/include/linux/skbuff.h ./include/linux/skbuff.h
+--- ../orig-linux-2.6.17/include/linux/skbuff.h 2007-01-08 15:16:27.000000000 +0000
++++ ./include/linux/skbuff.h 2007-01-08 15:25:03.000000000 +0000
+@@ -1422,5 +1422,10 @@ static inline void nf_reset(struct sk_bu
+ static inline void nf_reset(struct sk_buff *skb) {}
+ #endif /* CONFIG_NETFILTER */
+
++static inline int skb_is_gso(const struct sk_buff *skb)
++{
++ return skb_shinfo(skb)->gso_size;
++}
++
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_SKBUFF_H */
+diff -pruN ../orig-linux-2.6.17/include/net/protocol.h ./include/net/protocol.h
+--- ../orig-linux-2.6.17/include/net/protocol.h 2007-01-08 15:16:27.000000000 +0000
++++ ./include/net/protocol.h 2007-01-08 15:25:03.000000000 +0000
+@@ -37,6 +37,7 @@
+ struct net_protocol {
+ int (*handler)(struct sk_buff *skb);
+ void (*err_handler)(struct sk_buff *skb, u32 info);
++ int (*gso_send_check)(struct sk_buff *skb);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb,
+ int features);
+ int no_policy;
+diff -pruN ../orig-linux-2.6.17/include/net/tcp.h ./include/net/tcp.h
+--- ../orig-linux-2.6.17/include/net/tcp.h 2007-01-08 15:16:27.000000000 +0000
++++ ./include/net/tcp.h 2007-01-08 15:25:03.000000000 +0000
+@@ -1076,6 +1076,7 @@ extern struct request_sock_ops tcp_reque
+
+ extern int tcp_v4_destroy_sock(struct sock *sk);
+
++extern int tcp_v4_gso_send_check(struct sk_buff *skb);
+ extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
+
+ #ifdef CONFIG_PROC_FS
+diff -pruN ../orig-linux-2.6.17/net/bridge/br_forward.c ./net/bridge/br_forward.c
+--- ../orig-linux-2.6.17/net/bridge/br_forward.c 2007-01-08 15:22:15.000000000 +0000
++++ ./net/bridge/br_forward.c 2007-01-08 15:25:32.000000000 +0000
+@@ -38,7 +38,7 @@ static inline unsigned packet_length(con
+ int br_dev_queue_push_xmit(struct sk_buff *skb)
+ {
+ /* drop mtu oversized packets except tso */
+- if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
++ if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
+ kfree_skb(skb);
+ else {
+ #ifdef CONFIG_BRIDGE_NETFILTER
+diff -pruN ../orig-linux-2.6.17/net/bridge/br_netfilter.c ./net/bridge/br_netfilter.c
+--- ../orig-linux-2.6.17/net/bridge/br_netfilter.c 2007-01-08 15:16:27.000000000 +0000
++++ ./net/bridge/br_netfilter.c 2007-01-08 15:25:03.000000000 +0000
+@@ -769,7 +769,7 @@ static int br_nf_dev_queue_xmit(struct s
+ {
+ if (skb->protocol == htons(ETH_P_IP) &&
+ skb->len > skb->dev->mtu &&
+- !skb_shinfo(skb)->gso_size)
++ !skb_is_gso(skb))
+ return ip_fragment(skb, br_dev_queue_push_xmit);
+ else
+ return br_dev_queue_push_xmit(skb);
+diff -pruN ../orig-linux-2.6.17/net/core/dev.c ./net/core/dev.c
+--- ../orig-linux-2.6.17/net/core/dev.c 2007-01-08 15:20:44.000000000 +0000
++++ ./net/core/dev.c 2007-01-08 15:25:03.000000000 +0000
+@@ -1156,9 +1156,17 @@ int skb_checksum_help(struct sk_buff *sk
+ unsigned int csum;
+ int ret = 0, offset = skb->h.raw - skb->data;
+
+- if (inward) {
+- skb->ip_summed = CHECKSUM_NONE;
+- goto out;
++ if (inward)
++ goto out_set_summed;
++
++ if (unlikely(skb_shinfo(skb)->gso_size)) {
++ static int warned;
++
++ WARN_ON(!warned);
++ warned = 1;
++
++ /* Let GSO fix up the checksum. */
++ goto out_set_summed;
+ }
+
+ if (skb_cloned(skb)) {
+@@ -1175,6 +1183,8 @@ int skb_checksum_help(struct sk_buff *sk
+ BUG_ON(skb->csum + 2 > offset);
+
+ *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
++
++out_set_summed:
+ skb->ip_summed = CHECKSUM_NONE;
+ out:
+ return ret;
+@@ -1195,17 +1205,35 @@ struct sk_buff *skb_gso_segment(struct s
+ struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+ struct packet_type *ptype;
+ int type = skb->protocol;
++ int err;
+
+ BUG_ON(skb_shinfo(skb)->frag_list);
+- BUG_ON(skb->ip_summed != CHECKSUM_HW);
+
+ skb->mac.raw = skb->data;
+ skb->mac_len = skb->nh.raw - skb->data;
+ __skb_pull(skb, skb->mac_len);
+
++ if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
++ static int warned;
++
++ WARN_ON(!warned);
++ warned = 1;
++
++ if (skb_header_cloned(skb) &&
++ (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
++ return ERR_PTR(err);
++ }
++
+ rcu_read_lock();
+ list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
+ if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
++ if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
++ err = ptype->gso_send_check(skb);
++ segs = ERR_PTR(err);
++ if (err || skb_gso_ok(skb, features))
++ break;
++ __skb_push(skb, skb->data - skb->nh.raw);
++ }
+ segs = ptype->gso_segment(skb, features);
+ break;
+ }
+diff -pruN ../orig-linux-2.6.17/net/ipv4/af_inet.c ./net/ipv4/af_inet.c
+--- ../orig-linux-2.6.17/net/ipv4/af_inet.c 2007-01-08 15:16:27.000000000 +0000
++++ ./net/ipv4/af_inet.c 2007-01-08 15:25:03.000000000 +0000
+@@ -1097,6 +1097,40 @@ int inet_sk_rebuild_header(struct sock *
+
+ EXPORT_SYMBOL(inet_sk_rebuild_header);
+
++static int inet_gso_send_check(struct sk_buff *skb)
++{
++ struct iphdr *iph;
++ struct net_protocol *ops;
++ int proto;
++ int ihl;
++ int err = -EINVAL;
++
++ if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
++ goto out;
++
++ iph = skb->nh.iph;
++ ihl = iph->ihl * 4;
++ if (ihl < sizeof(*iph))
++ goto out;
++
++ if (unlikely(!pskb_may_pull(skb, ihl)))
++ goto out;
++
++ skb->h.raw = __skb_pull(skb, ihl);
++ iph = skb->nh.iph;
++ proto = iph->protocol & (MAX_INET_PROTOS - 1);
++ err = -EPROTONOSUPPORT;
++
++ rcu_read_lock();
++ ops = rcu_dereference(inet_protos[proto]);
++ if (likely(ops && ops->gso_send_check))
++ err = ops->gso_send_check(skb);
++ rcu_read_unlock();
++
++out:
++ return err;
++}
++
+ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
+ {
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+@@ -1154,6 +1188,7 @@ static struct net_protocol igmp_protocol
+ static struct net_protocol tcp_protocol = {
+ .handler = tcp_v4_rcv,
+ .err_handler = tcp_v4_err,
++ .gso_send_check = tcp_v4_gso_send_check,
+ .gso_segment = tcp_tso_segment,
+ .no_policy = 1,
+ };
+@@ -1200,6 +1235,7 @@ static int ipv4_proc_init(void);
+ static struct packet_type ip_packet_type = {
+ .type = __constant_htons(ETH_P_IP),
+ .func = ip_rcv,
++ .gso_send_check = inet_gso_send_check,
+ .gso_segment = inet_gso_segment,
+ };
+
+diff -pruN ../orig-linux-2.6.17/net/ipv4/ip_output.c ./net/ipv4/ip_output.c
+--- ../orig-linux-2.6.17/net/ipv4/ip_output.c 2007-01-08 15:16:27.000000000 +0000
++++ ./net/ipv4/ip_output.c 2007-01-08 15:25:03.000000000 +0000
+@@ -210,7 +210,7 @@ static inline int ip_finish_output(struc
+ return dst_output(skb);
+ }
+ #endif
+- if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
++ if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb))
+ return ip_fragment(skb, ip_finish_output2);
+ else
+ return ip_finish_output2(skb);
+@@ -1095,7 +1095,7 @@ ssize_t ip_append_page(struct sock *sk,
+ while (size > 0) {
+ int i;
+
+- if (skb_shinfo(skb)->gso_size)
++ if (skb_is_gso(skb))
+ len = size;
+ else {
+
+diff -pruN ../orig-linux-2.6.17/net/ipv4/tcp_ipv4.c ./net/ipv4/tcp_ipv4.c
+--- ../orig-linux-2.6.17/net/ipv4/tcp_ipv4.c 2006-06-18 02:49:35.000000000 +0100
++++ ./net/ipv4/tcp_ipv4.c 2007-01-08 15:25:03.000000000 +0000
+@@ -495,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk,
+ }
+ }
+
++int tcp_v4_gso_send_check(struct sk_buff *skb)
++{
++ struct iphdr *iph;
++ struct tcphdr *th;
++
++ if (!pskb_may_pull(skb, sizeof(*th)))
++ return -EINVAL;
++
++ iph = skb->nh.iph;
++ th = skb->h.th;
++
++ th->check = 0;
++ th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
++ skb->csum = offsetof(struct tcphdr, check);
++ skb->ip_summed = CHECKSUM_HW;
++ return 0;
++}
++
+ /*
+ * This routine will send an RST to the other tcp.
+ *
+diff -pruN ../orig-linux-2.6.17/net/ipv4/xfrm4_output.c ./net/ipv4/xfrm4_output.c
+--- ../orig-linux-2.6.17/net/ipv4/xfrm4_output.c 2007-01-08 15:16:27.000000000 +0000
++++ ./net/ipv4/xfrm4_output.c 2007-01-08 15:25:03.000000000 +0000
+@@ -195,7 +195,7 @@ static int xfrm4_output_finish(struct sk
+ }
+ #endif
+
+- if (!skb_shinfo(skb)->gso_size)
++ if (!skb_is_gso(skb))
+ return xfrm4_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);
+diff -pruN ../orig-linux-2.6.17/net/ipv6/ip6_output.c ./net/ipv6/ip6_output.c
+--- ../orig-linux-2.6.17/net/ipv6/ip6_output.c 2007-01-08 15:16:27.000000000 +0000
++++ ./net/ipv6/ip6_output.c 2007-01-08 15:25:03.000000000 +0000
+@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
+
+ int ip6_output(struct sk_buff *skb)
+ {
+- if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
++ if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) ||
+ dst_allfrag(skb->dst))
+ return ip6_fragment(skb, ip6_output2);
+ else
+diff -pruN ../orig-linux-2.6.17/net/ipv6/xfrm6_output.c ./net/ipv6/xfrm6_output.c
+--- ../orig-linux-2.6.17/net/ipv6/xfrm6_output.c 2007-01-08 15:16:27.000000000 +0000
++++ ./net/ipv6/xfrm6_output.c 2007-01-08 15:25:03.000000000 +0000
+@@ -179,7 +179,7 @@ static int xfrm6_output_finish(struct sk
+ {
+ struct sk_buff *segs;
+
+- if (!skb_shinfo(skb)->gso_size)
++ if (!skb_is_gso(skb))
+ return xfrm6_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);