diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-02-11 04:27:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-13 13:30:10 -0500 |
commit | c9af6db4c11ccc6c3e7f19bbc15d54023956f97c (patch) | |
tree | c596e747d8940b848931ac31701e245a6c0efaf6 /net/ipv4/tcp_output.c | |
parent | b8fa4100350432504df438014e2e5e9c1bbb6325 (diff) |
net: Fix possible wrong checksum generation.
Patch cef401de7be8c4e (net: fix possible wrong checksum
generation) fixed wrong checksum calculation but it broke TSO by
defining new GSO type but not a netdev feature for that type.
net_gso_ok() would not allow hardware checksum/segmentation
offload of such packets without the feature.
Following patch fixes TSO and wrong checksum. This patch uses
same logic that Eric Dumazet used. Patch introduces new flag
SKBTX_SHARED_FRAG if at least one frag can be modified by
the user. but SKBTX_SHARED_FRAG flag is kept in skb shared
info tx_flags rather than gso_type.
tx_flags is better compared to gso_type since we can have skb with
shared frag without gso packet. It does not link SHARED_FRAG to
GSO, So there is no need to define netdev feature for this.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r-- | net/ipv4/tcp_output.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 564bf89d9fd3..6182d90e97b0 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -1133,7 +1133,6 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) | |||
1133 | static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, | 1133 | static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, |
1134 | unsigned int mss_now) | 1134 | unsigned int mss_now) |
1135 | { | 1135 | { |
1136 | skb_shinfo(skb)->gso_type &= SKB_GSO_SHARED_FRAG; | ||
1137 | if (skb->len <= mss_now || !sk_can_gso(sk) || | 1136 | if (skb->len <= mss_now || !sk_can_gso(sk) || |
1138 | skb->ip_summed == CHECKSUM_NONE) { | 1137 | skb->ip_summed == CHECKSUM_NONE) { |
1139 | /* Avoid the costly divide in the normal | 1138 | /* Avoid the costly divide in the normal |
@@ -1141,10 +1140,11 @@ static void tcp_set_skb_tso_segs(const struct sock *sk, struct sk_buff *skb, | |||
1141 | */ | 1140 | */ |
1142 | skb_shinfo(skb)->gso_segs = 1; | 1141 | skb_shinfo(skb)->gso_segs = 1; |
1143 | skb_shinfo(skb)->gso_size = 0; | 1142 | skb_shinfo(skb)->gso_size = 0; |
1143 | skb_shinfo(skb)->gso_type = 0; | ||
1144 | } else { | 1144 | } else { |
1145 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now); | 1145 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss_now); |
1146 | skb_shinfo(skb)->gso_size = mss_now; | 1146 | skb_shinfo(skb)->gso_size = mss_now; |
1147 | skb_shinfo(skb)->gso_type |= sk->sk_gso_type; | 1147 | skb_shinfo(skb)->gso_type = sk->sk_gso_type; |
1148 | } | 1148 | } |
1149 | } | 1149 | } |
1150 | 1150 | ||