X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fipv4%2Ftcp.c;h=f6a2d9223d07ca1503aecfdaa9124e09b8e22247;hb=e54f48933f414fa447c26d16524a4c9a8e2facc6;hp=c04176be7ed12826de51bcf036d2e64cd7f0b17e;hpb=81a07d7588d376c530d006e24d7981304ce96e16;p=linux-2.6 diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c04176be7e..f6a2d9223d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -247,7 +247,6 @@ * TCP_CLOSE socket is finished */ -#include #include #include #include @@ -643,7 +642,7 @@ static inline int select_size(struct sock *sk, struct tcp_sock *tp) int tmp = tp->mss_cache; if (sk->sk_route_caps & NETIF_F_SG) { - if (sk->sk_route_caps & NETIF_F_TSO) + if (sk_can_gso(sk)) tmp = 0; else { int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); @@ -2145,7 +2144,7 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(compat_tcp_getsockopt); #endif -struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) +struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = ERR_PTR(-EINVAL); struct tcphdr *th; @@ -2169,7 +2168,28 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) oldlen = (u16)~skb->len; __skb_pull(skb, thlen); - segs = skb_segment(skb, sg); + if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { + /* Packet is from an untrusted source, reset gso_segs. */ + int type = skb_shinfo(skb)->gso_type; + int mss; + + if (unlikely(type & + ~(SKB_GSO_TCPV4 | + SKB_GSO_DODGY | + SKB_GSO_TCP_ECN | + SKB_GSO_TCPV6 | + 0) || + !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) + goto out; + + mss = skb_shinfo(skb)->gso_size; + skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss; + + segs = NULL; + goto out; + } + + segs = skb_segment(skb, features); if (IS_ERR(segs)) goto out; @@ -2205,6 +2225,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg) out: return segs; } +EXPORT_SYMBOL(tcp_tso_segment); extern void __skb_cb_too_small_for_tcp(int, int); extern struct tcp_congestion_ops tcp_reno;