aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-06-22 06:02:40 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-23 05:07:33 -0400
commitf4c50d990dcf11a296679dc05de3873783236711 (patch)
treef4daf1c80fe591d45631e998b0b5d31d6fe76d85 /net/ipv4/tcp.c
parentf6a78bfcb141f963187464bac838d46a81c3882a (diff)
[NET]: Add software TSOv4
This patch adds the GSO implementation for IPv4 TCP. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 062dd1a0d8a8..0e029c4e2903 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -258,6 +258,7 @@
258#include <linux/random.h> 258#include <linux/random.h>
259#include <linux/bootmem.h> 259#include <linux/bootmem.h>
260#include <linux/cache.h> 260#include <linux/cache.h>
261#include <linux/err.h>
261 262
262#include <net/icmp.h> 263#include <net/icmp.h>
263#include <net/tcp.h> 264#include <net/tcp.h>
@@ -2144,6 +2145,67 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
2144EXPORT_SYMBOL(compat_tcp_getsockopt); 2145EXPORT_SYMBOL(compat_tcp_getsockopt);
2145#endif 2146#endif
2146 2147
2148struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
2149{
2150 struct sk_buff *segs = ERR_PTR(-EINVAL);
2151 struct tcphdr *th;
2152 unsigned thlen;
2153 unsigned int seq;
2154 unsigned int delta;
2155 unsigned int oldlen;
2156 unsigned int len;
2157
2158 if (!pskb_may_pull(skb, sizeof(*th)))
2159 goto out;
2160
2161 th = skb->h.th;
2162 thlen = th->doff * 4;
2163 if (thlen < sizeof(*th))
2164 goto out;
2165
2166 if (!pskb_may_pull(skb, thlen))
2167 goto out;
2168
2169 oldlen = ~htonl(skb->len);
2170 __skb_pull(skb, thlen);
2171
2172 segs = skb_segment(skb, sg);
2173 if (IS_ERR(segs))
2174 goto out;
2175
2176 len = skb_shinfo(skb)->gso_size;
2177 delta = csum_add(oldlen, htonl(thlen + len));
2178
2179 skb = segs;
2180 th = skb->h.th;
2181 seq = ntohl(th->seq);
2182
2183 do {
2184 th->fin = th->psh = 0;
2185
2186 if (skb->ip_summed == CHECKSUM_NONE) {
2187 th->check = csum_fold(csum_partial(
2188 skb->h.raw, thlen, csum_add(skb->csum, delta)));
2189 }
2190
2191 seq += len;
2192 skb = skb->next;
2193 th = skb->h.th;
2194
2195 th->seq = htonl(seq);
2196 th->cwr = 0;
2197 } while (skb->next);
2198
2199 if (skb->ip_summed == CHECKSUM_NONE) {
2200 delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw));
2201 th->check = csum_fold(csum_partial(
2202 skb->h.raw, thlen, csum_add(skb->csum, delta)));
2203 }
2204
2205out:
2206 return segs;
2207}
2208
2147extern void __skb_cb_too_small_for_tcp(int, int); 2209extern void __skb_cb_too_small_for_tcp(int, int);
2148extern struct tcp_congestion_ops tcp_reno; 2210extern struct tcp_congestion_ops tcp_reno;
2149 2211