]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/tcp.c
[NET]: Replace CHECKSUM_HW by CHECKSUM_PARTIAL/CHECKSUM_COMPLETE
[net-next-2.6.git] / net / ipv4 / tcp.c
index c04176be7ed12826de51bcf036d2e64cd7f0b17e..b0124e69ab3839b9d5c5a5a4e55f0b4f91bea3fc 100644 (file)
  *     TCP_CLOSE               socket is finished
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -569,7 +568,7 @@ new_segment:
                skb->truesize += copy;
                sk->sk_wmem_queued += copy;
                sk->sk_forward_alloc -= copy;
-               skb->ip_summed = CHECKSUM_HW;
+               skb->ip_summed = CHECKSUM_PARTIAL;
                tp->write_seq += copy;
                TCP_SKB_CB(skb)->end_seq += copy;
                skb_shinfo(skb)->gso_segs = 0;
@@ -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);
@@ -724,7 +723,7 @@ new_segment:
                                 * Check whether we can use HW checksum.
                                 */
                                if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
-                                       skb->ip_summed = CHECKSUM_HW;
+                                       skb->ip_summed = CHECKSUM_PARTIAL;
 
                                skb_entail(sk, tp, skb);
                                copy = size_goal;
@@ -1133,7 +1132,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        tp->ucopy.dma_chan = NULL;
        preempt_disable();
        if ((len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) &&
-           !sysctl_tcp_low_latency && __get_cpu_var(softnet_data.net_dma)) {
+           !sysctl_tcp_low_latency && __get_cpu_var(softnet_data).net_dma) {
                preempt_enable_no_resched();
                tp->ucopy.pinned_list = dma_pin_iovec_pages(msg->msg_iov, len);
        } else
@@ -1660,7 +1659,8 @@ adjudge_to_death:
                        const int tmo = tcp_fin_time(sk);
 
                        if (tmo > TCP_TIMEWAIT_LEN) {
-                               inet_csk_reset_keepalive_timer(sk, tcp_fin_time(sk));
+                               inet_csk_reset_keepalive_timer(sk,
+                                               tmo - TCP_TIMEWAIT_LEN);
                        } else {
                                tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
                                goto out;
@@ -2145,7 +2145,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 +2169,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;
 
@@ -2184,7 +2205,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
                th->fin = th->psh = 0;
 
                th->check = ~csum_fold(th->check + delta);
-               if (skb->ip_summed != CHECKSUM_HW)
+               if (skb->ip_summed != CHECKSUM_PARTIAL)
                        th->check = csum_fold(csum_partial(skb->h.raw, thlen,
                                                           skb->csum));
 
@@ -2198,13 +2219,14 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
 
        delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
        th->check = ~csum_fold(th->check + delta);
-       if (skb->ip_summed != CHECKSUM_HW)
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
                th->check = csum_fold(csum_partial(skb->h.raw, thlen,
                                                   skb->csum));
 
 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;