diff options
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.patch | 459 |
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); |