]> Pileus Git - ~andy/linux/blobdiff - net/ipv4/tcp_output.c
net: Add skb_unclone() helper function.
[~andy/linux] / net / ipv4 / tcp_output.c
index 2798706cb06385aa87fdb05ba1ed2c6a0a14e6e5..fd0cea114b5d0d08e785bb65a67e5f904bd95df3 100644 (file)
@@ -314,7 +314,7 @@ static inline void TCP_ECN_send_syn(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
 
        tp->ecn_flags = 0;
-       if (sysctl_tcp_ecn == 1) {
+       if (sock_net(sk)->ipv4.sysctl_tcp_ecn == 1) {
                TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR;
                tp->ecn_flags = TCP_ECN_OK;
        }
@@ -622,7 +622,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
 
        if (likely(sysctl_tcp_timestamps && *md5 == NULL)) {
                opts->options |= OPTION_TS;
-               opts->tsval = TCP_SKB_CB(skb)->when;
+               opts->tsval = TCP_SKB_CB(skb)->when + tp->tsoffset;
                opts->tsecr = tp->rx_opt.ts_recent;
                remaining -= TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -806,7 +806,7 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
 
        if (likely(tp->rx_opt.tstamp_ok)) {
                opts->options |= OPTION_TS;
-               opts->tsval = tcb ? tcb->when : 0;
+               opts->tsval = tcb ? tcb->when + tp->tsoffset : 0;
                opts->tsecr = tp->rx_opt.ts_recent;
                size += TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -1331,7 +1331,7 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
 /* Remove acked data from a packet in the transmit queue. */
 int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
 {
-       if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+       if (skb_unclone(skb, GFP_ATOMIC))
                return -ENOMEM;
 
        __pskb_trim_head(skb, len);
@@ -2309,12 +2309,11 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
  * state updates are done by the caller.  Returns non-zero if an
  * error occurred which prevented the send.
  */
-int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
+int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
        unsigned int cur_mss;
-       int err;
 
        /* Inconslusive MTU probe */
        if (icsk->icsk_mtup.probe_size) {
@@ -2387,11 +2386,17 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3))) {
                struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
                                                   GFP_ATOMIC);
-               err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
-                            -ENOBUFS;
+               return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
+                             -ENOBUFS;
        } else {
-               err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
+               return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
        }
+}
+
+int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       int err = __tcp_retransmit_skb(sk, skb);
 
        if (err == 0) {
                /* Update global TCP statistics. */
@@ -2987,6 +2992,11 @@ int tcp_connect(struct sock *sk)
 
        tcp_connect_init(sk);
 
+       if (unlikely(tp->repair)) {
+               tcp_finish_connect(sk, NULL);
+               return 0;
+       }
+
        buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation);
        if (unlikely(buff == NULL))
                return -ENOBUFS;