]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/tcp_output.c
tcp: fix crash in tcp_xmit_retransmit_queue
[net-next-2.6.git] / net / ipv4 / tcp_output.c
index 0dda86e72ad8b6d60e24d62128ccadf7ae65a0fe..7ed9dc1042d1930a7eb2107def30642cb367fa92 100644 (file)
@@ -350,6 +350,7 @@ static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
  */
 static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags)
 {
+       skb->ip_summed = CHECKSUM_PARTIAL;
        skb->csum = 0;
 
        TCP_SKB_CB(skb)->flags = flags;
@@ -667,7 +668,6 @@ static unsigned tcp_synack_options(struct sock *sk,
        u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ?
                         xvp->cookie_plus :
                         0;
-       bool doing_ts = ireq->tstamp_ok;
 
 #ifdef CONFIG_TCP_MD5SIG
        *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
@@ -680,7 +680,7 @@ static unsigned tcp_synack_options(struct sock *sk,
                 * rather than TS in order to fit in better with old,
                 * buggy kernels, but that was deemed to be unnecessary.
                 */
-               doing_ts &= !ireq->sack_ok;
+               ireq->tstamp_ok &= !ireq->sack_ok;
        }
 #else
        *md5 = NULL;
@@ -695,7 +695,7 @@ static unsigned tcp_synack_options(struct sock *sk,
                opts->options |= OPTION_WSCALE;
                remaining -= TCPOLEN_WSCALE_ALIGNED;
        }
-       if (likely(doing_ts)) {
+       if (likely(ireq->tstamp_ok)) {
                opts->options |= OPTION_TS;
                opts->tsval = TCP_SKB_CB(skb)->when;
                opts->tsecr = req->ts_recent;
@@ -703,7 +703,7 @@ static unsigned tcp_synack_options(struct sock *sk,
        }
        if (likely(ireq->sack_ok)) {
                opts->options |= OPTION_SACK_ADVERTISE;
-               if (unlikely(!doing_ts))
+               if (unlikely(!ireq->tstamp_ok))
                        remaining -= TCPOLEN_SACKPERM_ALIGNED;
        }
 
@@ -711,7 +711,7 @@ static unsigned tcp_synack_options(struct sock *sk,
         * If the <SYN> options fit, the same options should fit now!
         */
        if (*md5 == NULL &&
-           doing_ts &&
+           ireq->tstamp_ok &&
            cookie_plus > TCPOLEN_COOKIE_BASE) {
                int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */
 
@@ -860,7 +860,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                        th->urg_ptr = htons(tp->snd_up - tcb->seq);
                        th->urg = 1;
                } else if (after(tcb->seq + 0xFFFF, tp->snd_nxt)) {
-                       th->urg_ptr = 0xFFFF;
+                       th->urg_ptr = htons(0xFFFF);
                        th->urg = 1;
                }
        }
@@ -872,13 +872,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 #ifdef CONFIG_TCP_MD5SIG
        /* Calculate the MD5 hash, as we have all we need now */
        if (md5) {
-               sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+               sk_nocaps_add(sk, NETIF_F_GSO_MASK);
                tp->af_specific->calc_md5_hash(opts.hash_location,
                                               md5, sk, NULL, skb);
        }
 #endif
 
-       icsk->icsk_af_ops->send_check(sk, skb->len, skb);
+       icsk->icsk_af_ops->send_check(sk, skb);
 
        if (likely(tcb->flags & TCPCB_FLAG_ACK))
                tcp_event_ack_sent(sk, tcp_skb_pcount(skb));
@@ -887,9 +887,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                tcp_event_data_sent(tp, skb, sk);
 
        if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
-               TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
+               TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS,
+                             tcp_skb_pcount(skb));
 
-       err = icsk->icsk_af_ops->queue_xmit(skb, 0);
+       err = icsk->icsk_af_ops->queue_xmit(skb);
        if (likely(err <= 0))
                return err;
 
@@ -2207,6 +2208,9 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
        int mib_idx;
        int fwd_rexmitting = 0;
 
+       if (!tp->packets_out)
+               return;
+
        if (!tp->lost_out)
                tp->retransmit_high = tp->snd_una;
 
@@ -2484,7 +2488,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
                        *tail-- ^= TCP_SKB_CB(skb)->seq + 1;
 
                        /* recommended */
-                       *tail-- ^= ((th->dest << 16) | th->source);
+                       *tail-- ^= (((__force u32)th->dest << 16) | (__force u32)th->source);
                        *tail-- ^= (u32)(unsigned long)cvp; /* per sockopt */
 
                        sha_transform((__u32 *)&xvp->cookie_bakery[0],
@@ -2502,7 +2506,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        th->window = htons(min(req->rcv_wnd, 65535U));
        tcp_options_write((__be32 *)(th + 1), tp, &opts);
        th->doff = (tcp_header_size >> 2);
-       TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
+       TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, tcp_skb_pcount(skb));
 
 #ifdef CONFIG_TCP_MD5SIG
        /* Okay, we have all we need - do the md5 hash if needed */