netns xfrm: ipcomp support
[safe/jmp/linux-2.6] / net / ipv4 / tcp_minisocks.c
index 267cea1..f206ee5 100644 (file)
@@ -5,8 +5,6 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_minisocks.c,v 1.15 2002/02/01 22:01:04 davem Exp $
- *
  * Authors:    Ross Biro
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -20,7 +18,6 @@
  *             Jorge Cwik, <jorge@laser.satlink.net>
  */
 
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/sysctl.h>
 #include <net/inet_common.h>
 #include <net/xfrm.h>
 
-#ifdef CONFIG_SYSCTL
-#define SYNC_INIT 0 /* let the user enable it */
-#else
-#define SYNC_INIT 1
-#endif
+int sysctl_tcp_syncookies __read_mostly = 1;
+EXPORT_SYMBOL(sysctl_tcp_syncookies);
 
-int sysctl_tcp_tw_recycle;
-int sysctl_tcp_max_tw_buckets = NR_FILE*2;
+int sysctl_tcp_abort_on_overflow __read_mostly;
 
-int sysctl_tcp_syncookies = SYNC_INIT; 
-int sysctl_tcp_abort_on_overflow;
+struct inet_timewait_death_row tcp_death_row = {
+       .sysctl_max_tw_buckets = NR_FILE * 2,
+       .period         = TCP_TIMEWAIT_LEN / INET_TWDR_TWKILL_SLOTS,
+       .death_lock     = __SPIN_LOCK_UNLOCKED(tcp_death_row.death_lock),
+       .hashinfo       = &tcp_hashinfo,
+       .tw_timer       = TIMER_INITIALIZER(inet_twdr_hangman, 0,
+                                           (unsigned long)&tcp_death_row),
+       .twkill_work    = __WORK_INITIALIZER(tcp_death_row.twkill_work,
+                                            inet_twdr_twkill_work),
+/* Short-time timewait calendar */
 
-static void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo);
+       .twcal_hand     = -1,
+       .twcal_timer    = TIMER_INITIALIZER(inet_twdr_twcal_tick, 0,
+                                           (unsigned long)&tcp_death_row),
+};
+
+EXPORT_SYMBOL_GPL(tcp_death_row);
 
 static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
 {
@@ -52,48 +58,7 @@ static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
        return (seq == e_win && seq == end_seq);
 }
 
-/* New-style handling of TIME_WAIT sockets. */
-
-int tcp_tw_count;
-
-
-/* Must be called with locally disabled BHs. */
-static void tcp_timewait_kill(struct tcp_tw_bucket *tw)
-{
-       struct inet_ehash_bucket *ehead;
-       struct inet_bind_hashbucket *bhead;
-       struct inet_bind_bucket *tb;
-
-       /* Unlink from established hashes. */
-       ehead = &tcp_ehash[tw->tw_hashent];
-       write_lock(&ehead->lock);
-       if (hlist_unhashed(&tw->tw_node)) {
-               write_unlock(&ehead->lock);
-               return;
-       }
-       __hlist_del(&tw->tw_node);
-       sk_node_init(&tw->tw_node);
-       write_unlock(&ehead->lock);
-
-       /* Disassociate with bind bucket. */
-       bhead = &tcp_bhash[inet_bhashfn(tw->tw_num, tcp_bhash_size)];
-       spin_lock(&bhead->lock);
-       tb = tw->tw_tb;
-       __hlist_del(&tw->tw_bind_node);
-       tw->tw_tb = NULL;
-       inet_bind_bucket_destroy(tcp_bucket_cachep, tb);
-       spin_unlock(&bhead->lock);
-
-#ifdef SOCK_REFCNT_DEBUG
-       if (atomic_read(&tw->tw_refcnt) != 1) {
-               printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw,
-                      atomic_read(&tw->tw_refcnt));
-       }
-#endif
-       tcp_tw_put(tw);
-}
-
-/* 
+/*
  * * Main purpose of TIME-WAIT state is to close connection gracefully,
  *   when one of ends sits in LAST-ACK or CLOSING retransmitting FIN
  *   (and, probably, tail of data) and one or more our ACKs are lost.
@@ -122,20 +87,22 @@ static void tcp_timewait_kill(struct tcp_tw_bucket *tw)
  * to avoid misread sequence numbers, states etc.  --ANK
  */
 enum tcp_tw_status
-tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
-                          struct tcphdr *th, unsigned len)
+tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
+                          const struct tcphdr *th)
 {
        struct tcp_options_received tmp_opt;
+       u8 *hash_location;
+       struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
        int paws_reject = 0;
 
        tmp_opt.saw_tstamp = 0;
-       if (th->doff > (sizeof(struct tcphdr) >> 2) && tw->tw_ts_recent_stamp) {
-               tcp_parse_options(skb, &tmp_opt, 0);
+       if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
+               tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
 
                if (tmp_opt.saw_tstamp) {
-                       tmp_opt.ts_recent          = tw->tw_ts_recent;
-                       tmp_opt.ts_recent_stamp = tw->tw_ts_recent_stamp;
-                       paws_reject = tcp_paws_check(&tmp_opt, th->rst);
+                       tmp_opt.ts_recent       = tcptw->tw_ts_recent;
+                       tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
+                       paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
                }
        }
 
@@ -145,20 +112,21 @@ tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
                /* Out of window, send ACK */
                if (paws_reject ||
                    !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
-                                  tw->tw_rcv_nxt,
-                                  tw->tw_rcv_nxt + tw->tw_rcv_wnd))
+                                  tcptw->tw_rcv_nxt,
+                                  tcptw->tw_rcv_nxt + tcptw->tw_rcv_wnd))
                        return TCP_TW_ACK;
 
                if (th->rst)
                        goto kill;
 
-               if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->tw_rcv_nxt))
+               if (th->syn && !before(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt))
                        goto kill_with_rst;
 
                /* Dup ACK? */
-               if (!after(TCP_SKB_CB(skb)->end_seq, tw->tw_rcv_nxt) ||
+               if (!th->ack ||
+                   !after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) ||
                    TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) {
-                       tcp_tw_put(tw);
+                       inet_twsk_put(tw);
                        return TCP_TW_SUCCESS;
                }
 
@@ -166,32 +134,34 @@ tcp_timewait_state_process(struct tcp_tw_bucket *tw, struct sk_buff *skb,
                 * reset.
                 */
                if (!th->fin ||
-                   TCP_SKB_CB(skb)->end_seq != tw->tw_rcv_nxt + 1) {
+                   TCP_SKB_CB(skb)->end_seq != tcptw->tw_rcv_nxt + 1) {
 kill_with_rst:
-                       tcp_tw_deschedule(tw);
-                       tcp_tw_put(tw);
+                       inet_twsk_deschedule(tw, &tcp_death_row);
+                       inet_twsk_put(tw);
                        return TCP_TW_RST;
                }
 
                /* FIN arrived, enter true time-wait state. */
-               tw->tw_substate = TCP_TIME_WAIT;
-               tw->tw_rcv_nxt  = TCP_SKB_CB(skb)->end_seq;
+               tw->tw_substate   = TCP_TIME_WAIT;
+               tcptw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq;
                if (tmp_opt.saw_tstamp) {
-                       tw->tw_ts_recent_stamp  = xtime.tv_sec;
-                       tw->tw_ts_recent        = tmp_opt.rcv_tsval;
+                       tcptw->tw_ts_recent_stamp = get_seconds();
+                       tcptw->tw_ts_recent       = tmp_opt.rcv_tsval;
                }
 
                /* I am shamed, but failed to make it more elegant.
                 * Yes, it is direct reference to IP, which is impossible
                 * to generalize to IPv6. Taking into account that IPv6
-                * do not undertsnad recycling in any case, it not
+                * do not understand recycling in any case, it not
                 * a big problem in practice. --ANK */
                if (tw->tw_family == AF_INET &&
-                   sysctl_tcp_tw_recycle && tw->tw_ts_recent_stamp &&
+                   tcp_death_row.sysctl_tw_recycle && tcptw->tw_ts_recent_stamp &&
                    tcp_v4_tw_remember_stamp(tw))
-                       tcp_tw_schedule(tw, tw->tw_timeout);
+                       inet_twsk_schedule(tw, &tcp_death_row, tw->tw_timeout,
+                                          TCP_TIMEWAIT_LEN);
                else
-                       tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
+                       inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
+                                          TCP_TIMEWAIT_LEN);
                return TCP_TW_ACK;
        }
 
@@ -202,41 +172,42 @@ kill_with_rst:
         *      "When a connection is [...] on TIME-WAIT state [...]
         *      [a TCP] MAY accept a new SYN from the remote TCP to
         *      reopen the connection directly, if it:
-        *      
+        *
         *      (1)  assigns its initial sequence number for the new
         *      connection to be larger than the largest sequence
         *      number it used on the previous connection incarnation,
         *      and
         *
-        *      (2)  returns to TIME-WAIT state if the SYN turns out 
+        *      (2)  returns to TIME-WAIT state if the SYN turns out
         *      to be an old duplicate".
         */
 
        if (!paws_reject &&
-           (TCP_SKB_CB(skb)->seq == tw->tw_rcv_nxt &&
+           (TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt &&
             (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) {
                /* In window segment, it may be only reset or bare ack. */
 
                if (th->rst) {
-                       /* This is TIME_WAIT assasination, in two flavors.
+                       /* This is TIME_WAIT assassination, in two flavors.
                         * Oh well... nobody has a sufficient solution to this
                         * protocol bug yet.
                         */
                        if (sysctl_tcp_rfc1337 == 0) {
 kill:
-                               tcp_tw_deschedule(tw);
-                               tcp_tw_put(tw);
+                               inet_twsk_deschedule(tw, &tcp_death_row);
+                               inet_twsk_put(tw);
                                return TCP_TW_SUCCESS;
                        }
                }
-               tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
+               inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
+                                  TCP_TIMEWAIT_LEN);
 
                if (tmp_opt.saw_tstamp) {
-                       tw->tw_ts_recent        = tmp_opt.rcv_tsval;
-                       tw->tw_ts_recent_stamp  = xtime.tv_sec;
+                       tcptw->tw_ts_recent       = tmp_opt.rcv_tsval;
+                       tcptw->tw_ts_recent_stamp = get_seconds();
                }
 
-               tcp_tw_put(tw);
+               inet_twsk_put(tw);
                return TCP_TW_SUCCESS;
        }
 
@@ -258,9 +229,10 @@ kill:
         */
 
        if (th->syn && !th->rst && !th->ack && !paws_reject &&
-           (after(TCP_SKB_CB(skb)->seq, tw->tw_rcv_nxt) ||
-            (tmp_opt.saw_tstamp && (s32)(tw->tw_ts_recent - tmp_opt.rcv_tsval) < 0))) {
-               u32 isn = tw->tw_snd_nxt + 65535 + 2;
+           (after(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt) ||
+            (tmp_opt.saw_tstamp &&
+             (s32)(tcptw->tw_ts_recent - tmp_opt.rcv_tsval) < 0))) {
+               u32 isn = tcptw->tw_snd_nxt + 65535 + 2;
                if (isn == 0)
                        isn++;
                TCP_SKB_CB(skb)->when = isn;
@@ -268,9 +240,9 @@ kill:
        }
 
        if (paws_reject)
-               NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED);
+               NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_PAWSESTABREJECTED);
 
-       if(!th->rst) {
+       if (!th->rst) {
                /* In this case we must reset the TIMEWAIT timer.
                 *
                 * If it is ACKless SYN it may be both old duplicate
@@ -278,107 +250,81 @@ kill:
                 * Do not reschedule in the last case.
                 */
                if (paws_reject || th->ack)
-                       tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN);
+                       inet_twsk_schedule(tw, &tcp_death_row, TCP_TIMEWAIT_LEN,
+                                          TCP_TIMEWAIT_LEN);
 
                /* Send ACK. Note, we do not put the bucket,
                 * it will be released by caller.
                 */
                return TCP_TW_ACK;
        }
-       tcp_tw_put(tw);
+       inet_twsk_put(tw);
        return TCP_TW_SUCCESS;
 }
 
-/* Enter the time wait state.  This is called with locally disabled BH.
- * Essentially we whip up a timewait bucket, copy the
- * relevant info into it from the SK, and mess with hash chains
- * and list linkage.
+/*
+ * Move a socket to time-wait or dead fin-wait-2 state.
  */
-static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw)
+void tcp_time_wait(struct sock *sk, int state, int timeo)
 {
-       const struct inet_sock *inet = inet_sk(sk);
-       struct inet_ehash_bucket *ehead = &tcp_ehash[sk->sk_hashent];
-       struct inet_bind_hashbucket *bhead;
-       /* Step 1: Put TW into bind hash. Original socket stays there too.
-          Note, that any socket with inet->num != 0 MUST be bound in
-          binding cache, even if it is closed.
-        */
-       bhead = &tcp_bhash[inet_bhashfn(inet->num, tcp_bhash_size)];
-       spin_lock(&bhead->lock);
-       tw->tw_tb = inet->bind_hash;
-       BUG_TRAP(inet->bind_hash);
-       tw_add_bind_node(tw, &tw->tw_tb->owners);
-       spin_unlock(&bhead->lock);
-
-       write_lock(&ehead->lock);
+       struct inet_timewait_sock *tw = NULL;
+       const struct inet_connection_sock *icsk = inet_csk(sk);
+       const struct tcp_sock *tp = tcp_sk(sk);
+       int recycle_ok = 0;
 
-       /* Step 2: Remove SK from established hash. */
-       if (__sk_del_node_init(sk))
-               sock_prot_dec_use(sk->sk_prot);
+       if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
+               recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);
 
-       /* Step 3: Hash TW into TIMEWAIT half of established hash table. */
-       tw_add_node(tw, &(ehead + tcp_ehash_size)->chain);
-       atomic_inc(&tw->tw_refcnt);
+       if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
+               tw = inet_twsk_alloc(sk, state);
 
-       write_unlock(&ehead->lock);
-}
+       if (tw != NULL) {
+               struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
+               const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
 
-/* 
- * Move a socket to time-wait or dead fin-wait-2 state.
- */ 
-void tcp_time_wait(struct sock *sk, int state, int timeo)
-{
-       struct tcp_tw_bucket *tw = NULL;
-       struct tcp_sock *tp = tcp_sk(sk);
-       int recycle_ok = 0;
-
-       if (sysctl_tcp_tw_recycle && tp->rx_opt.ts_recent_stamp)
-               recycle_ok = tp->af_specific->remember_stamp(sk);
-
-       if (tcp_tw_count < sysctl_tcp_max_tw_buckets)
-               tw = kmem_cache_alloc(tcp_timewait_cachep, SLAB_ATOMIC);
-
-       if(tw != NULL) {
-               struct inet_sock *inet = inet_sk(sk);
-               int rto = (tp->rto<<2) - (tp->rto>>1);
-
-               /* Give us an identity. */
-               tw->tw_daddr            = inet->daddr;
-               tw->tw_rcv_saddr        = inet->rcv_saddr;
-               tw->tw_bound_dev_if     = sk->sk_bound_dev_if;
-               tw->tw_num              = inet->num;
-               tw->tw_state            = TCP_TIME_WAIT;
-               tw->tw_substate         = state;
-               tw->tw_sport            = inet->sport;
-               tw->tw_dport            = inet->dport;
-               tw->tw_family           = sk->sk_family;
-               tw->tw_reuse            = sk->sk_reuse;
                tw->tw_rcv_wscale       = tp->rx_opt.rcv_wscale;
-               atomic_set(&tw->tw_refcnt, 1);
-
-               tw->tw_hashent          = sk->sk_hashent;
-               tw->tw_rcv_nxt          = tp->rcv_nxt;
-               tw->tw_snd_nxt          = tp->snd_nxt;
-               tw->tw_rcv_wnd          = tcp_receive_window(tp);
-               tw->tw_ts_recent        = tp->rx_opt.ts_recent;
-               tw->tw_ts_recent_stamp  = tp->rx_opt.ts_recent_stamp;
-               tw_dead_node_init(tw);
+               tcptw->tw_rcv_nxt       = tp->rcv_nxt;
+               tcptw->tw_snd_nxt       = tp->snd_nxt;
+               tcptw->tw_rcv_wnd       = tcp_receive_window(tp);
+               tcptw->tw_ts_recent     = tp->rx_opt.ts_recent;
+               tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp;
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
                if (tw->tw_family == PF_INET6) {
                        struct ipv6_pinfo *np = inet6_sk(sk);
+                       struct inet6_timewait_sock *tw6;
 
-                       ipv6_addr_copy(&tw->tw_v6_daddr, &np->daddr);
-                       ipv6_addr_copy(&tw->tw_v6_rcv_saddr, &np->rcv_saddr);
-                       tw->tw_v6_ipv6only = np->ipv6only;
-               } else {
-                       memset(&tw->tw_v6_daddr, 0, sizeof(tw->tw_v6_daddr));
-                       memset(&tw->tw_v6_rcv_saddr, 0, sizeof(tw->tw_v6_rcv_saddr));
-                       tw->tw_v6_ipv6only = 0;
+                       tw->tw_ipv6_offset = inet6_tw_offset(sk->sk_prot);
+                       tw6 = inet6_twsk((struct sock *)tw);
+                       ipv6_addr_copy(&tw6->tw_v6_daddr, &np->daddr);
+                       ipv6_addr_copy(&tw6->tw_v6_rcv_saddr, &np->rcv_saddr);
+                       tw->tw_ipv6only = np->ipv6only;
                }
 #endif
+
+#ifdef CONFIG_TCP_MD5SIG
+               /*
+                * The timewait bucket does not have the key DB from the
+                * sock structure. We just make a quick copy of the
+                * md5 key being used (if indeed we are using one)
+                * so the timewait ack generating code has the key.
+                */
+               do {
+                       struct tcp_md5sig_key *key;
+                       memset(tcptw->tw_md5_key, 0, sizeof(tcptw->tw_md5_key));
+                       tcptw->tw_md5_keylen = 0;
+                       key = tp->af_specific->md5_lookup(sk, sk);
+                       if (key != NULL) {
+                               memcpy(&tcptw->tw_md5_key, key->key, key->keylen);
+                               tcptw->tw_md5_keylen = key->keylen;
+                               if (tcp_alloc_md5sig_pool(sk) == NULL)
+                                       BUG();
+                       }
+               } while (0);
+#endif
+
                /* Linkage updates. */
-               __tcp_tw_hashdance(sk, tw);
+               __inet_twsk_hashdance(tw, sk, &tcp_hashinfo);
 
                /* Get the TIME_WAIT timeout firing. */
                if (timeo < rto)
@@ -392,290 +338,36 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
                                timeo = TCP_TIMEWAIT_LEN;
                }
 
-               tcp_tw_schedule(tw, timeo);
-               tcp_tw_put(tw);
+               inet_twsk_schedule(tw, &tcp_death_row, timeo,
+                                  TCP_TIMEWAIT_LEN);
+               inet_twsk_put(tw);
        } else {
                /* Sorry, if we're out of memory, just CLOSE this
                 * socket up.  We've got bigger problems than
                 * non-graceful socket closings.
                 */
-               if (net_ratelimit())
-                       printk(KERN_INFO "TCP: time wait bucket table overflow\n");
+               LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n");
        }
 
        tcp_update_metrics(sk);
        tcp_done(sk);
 }
 
-/* Kill off TIME_WAIT sockets once their lifetime has expired. */
-static int tcp_tw_death_row_slot;
-
-static void tcp_twkill(unsigned long);
-
-/* TIME_WAIT reaping mechanism. */
-#define TCP_TWKILL_SLOTS       8       /* Please keep this a power of 2. */
-#define TCP_TWKILL_PERIOD      (TCP_TIMEWAIT_LEN/TCP_TWKILL_SLOTS)
-
-#define TCP_TWKILL_QUOTA       100
-
-static struct hlist_head tcp_tw_death_row[TCP_TWKILL_SLOTS];
-static DEFINE_SPINLOCK(tw_death_lock);
-static struct timer_list tcp_tw_timer = TIMER_INITIALIZER(tcp_twkill, 0, 0);
-static void twkill_work(void *);
-static DECLARE_WORK(tcp_twkill_work, twkill_work, NULL);
-static u32 twkill_thread_slots;
-
-/* Returns non-zero if quota exceeded.  */
-static int tcp_do_twkill_work(int slot, unsigned int quota)
-{
-       struct tcp_tw_bucket *tw;
-       struct hlist_node *node;
-       unsigned int killed;
-       int ret;
-
-       /* NOTE: compare this to previous version where lock
-        * was released after detaching chain. It was racy,
-        * because tw buckets are scheduled in not serialized context
-        * in 2.3 (with netfilter), and with softnet it is common, because
-        * soft irqs are not sequenced.
-        */
-       killed = 0;
-       ret = 0;
-rescan:
-       tw_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) {
-               __tw_del_dead_node(tw);
-               spin_unlock(&tw_death_lock);
-               tcp_timewait_kill(tw);
-               tcp_tw_put(tw);
-               killed++;
-               spin_lock(&tw_death_lock);
-               if (killed > quota) {
-                       ret = 1;
-                       break;
-               }
-
-               /* While we dropped tw_death_lock, another cpu may have
-                * killed off the next TW bucket in the list, therefore
-                * do a fresh re-read of the hlist head node with the
-                * lock reacquired.  We still use the hlist traversal
-                * macro in order to get the prefetches.
-                */
-               goto rescan;
-       }
-
-       tcp_tw_count -= killed;
-       NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITED, killed);
-
-       return ret;
-}
-
-static void tcp_twkill(unsigned long dummy)
-{
-       int need_timer, ret;
-
-       spin_lock(&tw_death_lock);
-
-       if (tcp_tw_count == 0)
-               goto out;
-
-       need_timer = 0;
-       ret = tcp_do_twkill_work(tcp_tw_death_row_slot, TCP_TWKILL_QUOTA);
-       if (ret) {
-               twkill_thread_slots |= (1 << tcp_tw_death_row_slot);
-               mb();
-               schedule_work(&tcp_twkill_work);
-               need_timer = 1;
-       } else {
-               /* We purged the entire slot, anything left?  */
-               if (tcp_tw_count)
-                       need_timer = 1;
-       }
-       tcp_tw_death_row_slot =
-               ((tcp_tw_death_row_slot + 1) & (TCP_TWKILL_SLOTS - 1));
-       if (need_timer)
-               mod_timer(&tcp_tw_timer, jiffies + TCP_TWKILL_PERIOD);
-out:
-       spin_unlock(&tw_death_lock);
-}
-
-extern void twkill_slots_invalid(void);
-
-static void twkill_work(void *dummy)
-{
-       int i;
-
-       if ((TCP_TWKILL_SLOTS - 1) > (sizeof(twkill_thread_slots) * 8))
-               twkill_slots_invalid();
-
-       while (twkill_thread_slots) {
-               spin_lock_bh(&tw_death_lock);
-               for (i = 0; i < TCP_TWKILL_SLOTS; i++) {
-                       if (!(twkill_thread_slots & (1 << i)))
-                               continue;
-
-                       while (tcp_do_twkill_work(i, TCP_TWKILL_QUOTA) != 0) {
-                               if (need_resched()) {
-                                       spin_unlock_bh(&tw_death_lock);
-                                       schedule();
-                                       spin_lock_bh(&tw_death_lock);
-                               }
-                       }
-
-                       twkill_thread_slots &= ~(1 << i);
-               }
-               spin_unlock_bh(&tw_death_lock);
-       }
-}
-
-/* These are always called from BH context.  See callers in
- * tcp_input.c to verify this.
- */
-
-/* This is for handling early-kills of TIME_WAIT sockets. */
-void tcp_tw_deschedule(struct tcp_tw_bucket *tw)
+void tcp_twsk_destructor(struct sock *sk)
 {
-       spin_lock(&tw_death_lock);
-       if (tw_del_dead_node(tw)) {
-               tcp_tw_put(tw);
-               if (--tcp_tw_count == 0)
-                       del_timer(&tcp_tw_timer);
-       }
-       spin_unlock(&tw_death_lock);
-       tcp_timewait_kill(tw);
+#ifdef CONFIG_TCP_MD5SIG
+       struct tcp_timewait_sock *twsk = tcp_twsk(sk);
+       if (twsk->tw_md5_keylen)
+               tcp_free_md5sig_pool();
+#endif
 }
 
-/* Short-time timewait calendar */
-
-static int tcp_twcal_hand = -1;
-static int tcp_twcal_jiffie;
-static void tcp_twcal_tick(unsigned long);
-static struct timer_list tcp_twcal_timer =
-               TIMER_INITIALIZER(tcp_twcal_tick, 0, 0);
-static struct hlist_head tcp_twcal_row[TCP_TW_RECYCLE_SLOTS];
-
-static void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo)
-{
-       struct hlist_head *list;
-       int slot;
-
-       /* timeout := RTO * 3.5
-        *
-        * 3.5 = 1+2+0.5 to wait for two retransmits.
-        *
-        * RATIONALE: if FIN arrived and we entered TIME-WAIT state,
-        * our ACK acking that FIN can be lost. If N subsequent retransmitted
-        * FINs (or previous seqments) are lost (probability of such event
-        * is p^(N+1), where p is probability to lose single packet and
-        * time to detect the loss is about RTO*(2^N - 1) with exponential
-        * backoff). Normal timewait length is calculated so, that we
-        * waited at least for one retransmitted FIN (maximal RTO is 120sec).
-        * [ BTW Linux. following BSD, violates this requirement waiting
-        *   only for 60sec, we should wait at least for 240 secs.
-        *   Well, 240 consumes too much of resources 8)
-        * ]
-        * This interval is not reduced to catch old duplicate and
-        * responces to our wandering segments living for two MSLs.
-        * However, if we use PAWS to detect
-        * old duplicates, we can reduce the interval to bounds required
-        * by RTO, rather than MSL. So, if peer understands PAWS, we
-        * kill tw bucket after 3.5*RTO (it is important that this number
-        * is greater than TS tick!) and detect old duplicates with help
-        * of PAWS.
-        */
-       slot = (timeo + (1<<TCP_TW_RECYCLE_TICK) - 1) >> TCP_TW_RECYCLE_TICK;
-
-       spin_lock(&tw_death_lock);
-
-       /* Unlink it, if it was scheduled */
-       if (tw_del_dead_node(tw))
-               tcp_tw_count--;
-       else
-               atomic_inc(&tw->tw_refcnt);
-
-       if (slot >= TCP_TW_RECYCLE_SLOTS) {
-               /* Schedule to slow timer */
-               if (timeo >= TCP_TIMEWAIT_LEN) {
-                       slot = TCP_TWKILL_SLOTS-1;
-               } else {
-                       slot = (timeo + TCP_TWKILL_PERIOD-1) / TCP_TWKILL_PERIOD;
-                       if (slot >= TCP_TWKILL_SLOTS)
-                               slot = TCP_TWKILL_SLOTS-1;
-               }
-               tw->tw_ttd = jiffies + timeo;
-               slot = (tcp_tw_death_row_slot + slot) & (TCP_TWKILL_SLOTS - 1);
-               list = &tcp_tw_death_row[slot];
-       } else {
-               tw->tw_ttd = jiffies + (slot << TCP_TW_RECYCLE_TICK);
-
-               if (tcp_twcal_hand < 0) {
-                       tcp_twcal_hand = 0;
-                       tcp_twcal_jiffie = jiffies;
-                       tcp_twcal_timer.expires = tcp_twcal_jiffie + (slot<<TCP_TW_RECYCLE_TICK);
-                       add_timer(&tcp_twcal_timer);
-               } else {
-                       if (time_after(tcp_twcal_timer.expires, jiffies + (slot<<TCP_TW_RECYCLE_TICK)))
-                               mod_timer(&tcp_twcal_timer, jiffies + (slot<<TCP_TW_RECYCLE_TICK));
-                       slot = (tcp_twcal_hand + slot)&(TCP_TW_RECYCLE_SLOTS-1);
-               }
-               list = &tcp_twcal_row[slot];
-       }
-
-       hlist_add_head(&tw->tw_death_node, list);
+EXPORT_SYMBOL_GPL(tcp_twsk_destructor);
 
-       if (tcp_tw_count++ == 0)
-               mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD);
-       spin_unlock(&tw_death_lock);
-}
-
-void tcp_twcal_tick(unsigned long dummy)
+static inline void TCP_ECN_openreq_child(struct tcp_sock *tp,
+                                        struct request_sock *req)
 {
-       int n, slot;
-       unsigned long j;
-       unsigned long now = jiffies;
-       int killed = 0;
-       int adv = 0;
-
-       spin_lock(&tw_death_lock);
-       if (tcp_twcal_hand < 0)
-               goto out;
-
-       slot = tcp_twcal_hand;
-       j = tcp_twcal_jiffie;
-
-       for (n=0; n<TCP_TW_RECYCLE_SLOTS; n++) {
-               if (time_before_eq(j, now)) {
-                       struct hlist_node *node, *safe;
-                       struct tcp_tw_bucket *tw;
-
-                       tw_for_each_inmate_safe(tw, node, safe,
-                                          &tcp_twcal_row[slot]) {
-                               __tw_del_dead_node(tw);
-                               tcp_timewait_kill(tw);
-                               tcp_tw_put(tw);
-                               killed++;
-                       }
-               } else {
-                       if (!adv) {
-                               adv = 1;
-                               tcp_twcal_jiffie = j;
-                               tcp_twcal_hand = slot;
-                       }
-
-                       if (!hlist_empty(&tcp_twcal_row[slot])) {
-                               mod_timer(&tcp_twcal_timer, j);
-                               goto out;
-                       }
-               }
-               j += (1<<TCP_TW_RECYCLE_TICK);
-               slot = (slot+1)&(TCP_TW_RECYCLE_SLOTS-1);
-       }
-       tcp_twcal_hand = -1;
-
-out:
-       if ((tcp_tw_count -= killed) == 0)
-               del_timer(&tcp_tw_timer);
-       NET_ADD_STATS_BH(LINUX_MIB_TIMEWAITKILLED, killed);
-       spin_unlock(&tw_death_lock);
+       tp->ecn_flags = inet_rsk(req)->ecn_ok ? TCP_ECN_OK : 0;
 }
 
 /* This is not only more efficient than what we used to do, it eliminates
@@ -686,84 +378,63 @@ out:
  */
 struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb)
 {
-       /* allocate the newsk from the same slab of the master sock,
-        * if not, at sk_free time we'll try to free it from the wrong
-        * slabcache (i.e. is it TCPv4 or v6?), this is handled thru sk->sk_prot -acme */
-       struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, sk->sk_prot, 0);
+       struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
-       if(newsk != NULL) {
-               struct inet_request_sock *ireq = inet_rsk(req);
+       if (newsk != NULL) {
+               const struct inet_request_sock *ireq = inet_rsk(req);
                struct tcp_request_sock *treq = tcp_rsk(req);
-               struct inet_sock *newinet = inet_sk(newsk);
-               struct tcp_sock *newtp;
-               struct sk_filter *filter;
-
-               memcpy(newsk, sk, sizeof(struct tcp_sock));
-               newsk->sk_state = TCP_SYN_RECV;
-
-               /* SANITY */
-               sk_node_init(&newsk->sk_node);
-               newinet->bind_hash = NULL;
-
-               /* Clone the TCP header template */
-               newinet->dport = ireq->rmt_port;
-
-               sock_lock_init(newsk);
-               bh_lock_sock(newsk);
-
-               rwlock_init(&newsk->sk_dst_lock);
-               newsk->sk_dst_cache = NULL;
-               atomic_set(&newsk->sk_rmem_alloc, 0);
-               skb_queue_head_init(&newsk->sk_receive_queue);
-               atomic_set(&newsk->sk_wmem_alloc, 0);
-               skb_queue_head_init(&newsk->sk_write_queue);
-               atomic_set(&newsk->sk_omem_alloc, 0);
-               newsk->sk_wmem_queued = 0;
-               newsk->sk_forward_alloc = 0;
-
-               sock_reset_flag(newsk, SOCK_DONE);
-               newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK;
-               newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL;
-               newsk->sk_send_head = NULL;
-               rwlock_init(&newsk->sk_callback_lock);
-               skb_queue_head_init(&newsk->sk_error_queue);
-               newsk->sk_write_space = sk_stream_write_space;
-
-               if ((filter = newsk->sk_filter) != NULL)
-                       sk_filter_charge(newsk, filter);
-
-               if (unlikely(xfrm_sk_clone_policy(newsk))) {
-                       /* It is still raw copy of parent, so invalidate
-                        * destructor and make plain sk_free() */
-                       newsk->sk_destruct = NULL;
-                       sk_free(newsk);
-                       return NULL;
+               struct inet_connection_sock *newicsk = inet_csk(newsk);
+               struct tcp_sock *newtp = tcp_sk(newsk);
+               struct tcp_sock *oldtp = tcp_sk(sk);
+               struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
+
+               /* TCP Cookie Transactions require space for the cookie pair,
+                * as it differs for each connection.  There is no need to
+                * copy any s_data_payload stored at the original socket.
+                * Failure will prevent resuming the connection.
+                *
+                * Presumed copied, in order of appearance:
+                *      cookie_in_always, cookie_out_never
+                */
+               if (oldcvp != NULL) {
+                       struct tcp_cookie_values *newcvp =
+                               kzalloc(sizeof(*newtp->cookie_values),
+                                       GFP_ATOMIC);
+
+                       if (newcvp != NULL) {
+                               kref_init(&newcvp->kref);
+                               newcvp->cookie_desired =
+                                               oldcvp->cookie_desired;
+                               newtp->cookie_values = newcvp;
+                       } else {
+                               /* Not Yet Implemented */
+                               newtp->cookie_values = NULL;
+                       }
                }
 
                /* Now setup tcp_sock */
-               newtp = tcp_sk(newsk);
                newtp->pred_flags = 0;
+
+               newtp->rcv_wup = newtp->copied_seq =
                newtp->rcv_nxt = treq->rcv_isn + 1;
-               newtp->snd_nxt = treq->snt_isn + 1;
-               newtp->snd_una = treq->snt_isn + 1;
-               newtp->snd_sml = treq->snt_isn + 1;
+
+               newtp->snd_sml = newtp->snd_una =
+               newtp->snd_nxt = newtp->snd_up =
+                       treq->snt_isn + 1 + tcp_s_data_size(oldtp);
 
                tcp_prequeue_init(newtp);
 
-               tcp_init_wl(newtp, treq->snt_isn, treq->rcv_isn);
+               tcp_init_wl(newtp, treq->rcv_isn);
 
-               newtp->retransmits = 0;
-               newtp->backoff = 0;
                newtp->srtt = 0;
                newtp->mdev = TCP_TIMEOUT_INIT;
-               newtp->rto = TCP_TIMEOUT_INIT;
+               newicsk->icsk_rto = TCP_TIMEOUT_INIT;
 
                newtp->packets_out = 0;
-               newtp->left_out = 0;
                newtp->retrans_out = 0;
                newtp->sacked_out = 0;
                newtp->fackets_out = 0;
-               newtp->snd_ssthresh = 0x7fffffff;
+               newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
 
                /* So many TCP implementations out there (incorrectly) count the
                 * initial SYN frame in their delayed-ACK and congestion control
@@ -772,62 +443,34 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                 */
                newtp->snd_cwnd = 2;
                newtp->snd_cwnd_cnt = 0;
+               newtp->bytes_acked = 0;
 
                newtp->frto_counter = 0;
                newtp->frto_highmark = 0;
 
-               newtp->ca_ops = &tcp_reno;
+               newicsk->icsk_ca_ops = &tcp_init_congestion_ops;
 
-               tcp_set_ca_state(newtp, TCP_CA_Open);
+               tcp_set_ca_state(newsk, TCP_CA_Open);
                tcp_init_xmit_timers(newsk);
                skb_queue_head_init(&newtp->out_of_order_queue);
-               newtp->rcv_wup = treq->rcv_isn + 1;
-               newtp->write_seq = treq->snt_isn + 1;
-               newtp->pushed_seq = newtp->write_seq;
-               newtp->copied_seq = treq->rcv_isn + 1;
+               newtp->write_seq = newtp->pushed_seq =
+                       treq->snt_isn + 1 + tcp_s_data_size(oldtp);
 
                newtp->rx_opt.saw_tstamp = 0;
 
                newtp->rx_opt.dsack = 0;
-               newtp->rx_opt.eff_sacks = 0;
-
-               newtp->probes_out = 0;
                newtp->rx_opt.num_sacks = 0;
-               newtp->urg_data = 0;
-               /* Deinitialize accept_queue to trap illegal accesses. */
-               memset(&newtp->accept_queue, 0, sizeof(newtp->accept_queue));
 
-               /* Back to base struct sock members. */
-               newsk->sk_err = 0;
-               newsk->sk_priority = 0;
-               atomic_set(&newsk->sk_refcnt, 2);
-
-               /*
-                * Increment the counter in the same struct proto as the master
-                * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that
-                * is the same as sk->sk_prot->socks, as this field was copied
-                * with memcpy), same rationale as the first comment in this
-                * function.
-                *
-                * This _changes_ the previous behaviour, where
-                * tcp_create_openreq_child always was incrementing the
-                * equivalent to tcp_prot->socks (inet_sock_nr), so this have
-                * to be taken into account in all callers. -acme
-                */
-               sk_refcnt_debug_inc(newsk);
-
-               atomic_inc(&tcp_sockets_allocated);
+               newtp->urg_data = 0;
 
                if (sock_flag(newsk, SOCK_KEEPOPEN))
-                       tcp_reset_keepalive_timer(newsk,
-                                                 keepalive_time_when(newtp));
-               newsk->sk_socket = NULL;
-               newsk->sk_sleep = NULL;
+                       inet_csk_reset_keepalive_timer(newsk,
+                                                      keepalive_time_when(newtp));
 
                newtp->rx_opt.tstamp_ok = ireq->tstamp_ok;
-               if((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) {
+               if ((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) {
                        if (sysctl_tcp_fack)
-                               newtp->rx_opt.sack_ok |= 2;
+                               tcp_enable_fack(newtp);
                }
                newtp->window_clamp = req->window_clamp;
                newtp->rcv_ssthresh = req->rcv_wnd;
@@ -840,48 +483,52 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                        newtp->rx_opt.snd_wscale = newtp->rx_opt.rcv_wscale = 0;
                        newtp->window_clamp = min(newtp->window_clamp, 65535U);
                }
-               newtp->snd_wnd = ntohs(skb->h.th->window) << newtp->rx_opt.snd_wscale;
+               newtp->snd_wnd = (ntohs(tcp_hdr(skb)->window) <<
+                                 newtp->rx_opt.snd_wscale);
                newtp->max_window = newtp->snd_wnd;
 
                if (newtp->rx_opt.tstamp_ok) {
                        newtp->rx_opt.ts_recent = req->ts_recent;
-                       newtp->rx_opt.ts_recent_stamp = xtime.tv_sec;
+                       newtp->rx_opt.ts_recent_stamp = get_seconds();
                        newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
                } else {
                        newtp->rx_opt.ts_recent_stamp = 0;
                        newtp->tcp_header_len = sizeof(struct tcphdr);
                }
-               if (skb->len >= TCP_MIN_RCVMSS+newtp->tcp_header_len)
-                       newtp->ack.last_seg_size = skb->len-newtp->tcp_header_len;
+#ifdef CONFIG_TCP_MD5SIG
+               newtp->md5sig_info = NULL;      /*XXX*/
+               if (newtp->af_specific->md5_lookup(sk, newsk))
+                       newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED;
+#endif
+               if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len)
+                       newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;
                newtp->rx_opt.mss_clamp = req->mss;
                TCP_ECN_openreq_child(newtp, req);
-               if (newtp->ecn_flags&TCP_ECN_OK)
-                       sock_set_flag(newsk, SOCK_NO_LARGESEND);
 
-               TCP_INC_STATS_BH(TCP_MIB_PASSIVEOPENS);
+               TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_PASSIVEOPENS);
        }
        return newsk;
 }
 
-/* 
+/*
  *     Process an incoming packet for SYN_RECV sockets represented
  *     as a request_sock.
  */
 
-struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
+struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
                           struct request_sock *req,
                           struct request_sock **prev)
 {
-       struct tcphdr *th = skb->h.th;
-       struct tcp_sock *tp = tcp_sk(sk);
-       u32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
-       int paws_reject = 0;
        struct tcp_options_received tmp_opt;
+       u8 *hash_location;
        struct sock *child;
+       const struct tcphdr *th = tcp_hdr(skb);
+       __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
+       int paws_reject = 0;
 
        tmp_opt.saw_tstamp = 0;
        if (th->doff > (sizeof(struct tcphdr)>>2)) {
-               tcp_parse_options(skb, &tmp_opt, 0);
+               tcp_parse_options(skb, &tmp_opt, &hash_location, 0);
 
                if (tmp_opt.saw_tstamp) {
                        tmp_opt.ts_recent = req->ts_recent;
@@ -889,8 +536,8 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
                         * it can be estimated (approximately)
                         * from another data.
                         */
-                       tmp_opt.ts_recent_stamp = xtime.tv_sec - ((TCP_TIMEOUT_INIT/HZ)<<req->retrans);
-                       paws_reject = tcp_paws_check(&tmp_opt, th->rst);
+                       tmp_opt.ts_recent_stamp = get_seconds() - ((TCP_TIMEOUT_INIT/HZ)<<req->retrans);
+                       paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
                }
        }
 
@@ -948,9 +595,10 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
           does sequence test, SYN is truncated, and thus we consider
           it a bare ACK.
 
-          If tp->defer_accept, we silently drop this bare ACK.  Otherwise,
-          we create an established connection.  Both ends (listening sockets)
-          accept the new incoming connection and try to talk to each other. 8-)
+          If icsk->icsk_accept_queue.rskq_defer_accept, we silently drop this
+          bare ACK.  Otherwise, we create an established connection.  Both
+          ends (listening sockets) accept the new incoming connection and try
+          to talk to each other. 8-)
 
           Note: This case is both harmless, and rare.  Possibility is about the
           same as us discovering intelligent life on another plant tomorrow.
@@ -967,13 +615,14 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
 
        /* RFC793 page 36: "If the connection is in any non-synchronized state ...
         *                  and the incoming segment acknowledges something not yet
-        *                  sent (the segment carries an unaccaptable ACK) ...
+        *                  sent (the segment carries an unacceptable ACK) ...
         *                  a reset is sent."
         *
         * Invalid ACK: reset will be sent by listening socket
         */
        if ((flg & TCP_FLAG_ACK) &&
-           (TCP_SKB_CB(skb)->ack_seq != tcp_rsk(req)->snt_isn + 1))
+           (TCP_SKB_CB(skb)->ack_seq !=
+            tcp_rsk(req)->snt_isn + 1 + tcp_s_data_size(tcp_sk(sk))))
                return sk;
 
        /* Also, it would be not so bad idea to check rcv_tsecr, which
@@ -987,70 +636,73 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
                                          tcp_rsk(req)->rcv_isn + 1, tcp_rsk(req)->rcv_isn + 1 + req->rcv_wnd)) {
                /* Out of window: send ACK and drop. */
                if (!(flg & TCP_FLAG_RST))
-                       req->rsk_ops->send_ack(skb, req);
+                       req->rsk_ops->send_ack(sk, skb, req);
                if (paws_reject)
-                       NET_INC_STATS_BH(LINUX_MIB_PAWSESTABREJECTED);
+                       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
                return NULL;
        }
 
        /* In sequence, PAWS is OK. */
 
        if (tmp_opt.saw_tstamp && !after(TCP_SKB_CB(skb)->seq, tcp_rsk(req)->rcv_isn + 1))
-                       req->ts_recent = tmp_opt.rcv_tsval;
+               req->ts_recent = tmp_opt.rcv_tsval;
 
-               if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn) {
-                       /* Truncate SYN, it is out of window starting
-                          at tcp_rsk(req)->rcv_isn + 1. */
-                       flg &= ~TCP_FLAG_SYN;
-               }
+       if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn) {
+               /* Truncate SYN, it is out of window starting
+                  at tcp_rsk(req)->rcv_isn + 1. */
+               flg &= ~TCP_FLAG_SYN;
+       }
 
-               /* RFC793: "second check the RST bit" and
-                *         "fourth, check the SYN bit"
-                */
-               if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN))
-                       goto embryonic_reset;
+       /* RFC793: "second check the RST bit" and
+        *         "fourth, check the SYN bit"
+        */
+       if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) {
+               TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_ATTEMPTFAILS);
+               goto embryonic_reset;
+       }
 
-               /* ACK sequence verified above, just make sure ACK is
-                * set.  If ACK not set, just silently drop the packet.
-                */
-               if (!(flg & TCP_FLAG_ACK))
-                       return NULL;
+       /* ACK sequence verified above, just make sure ACK is
+        * set.  If ACK not set, just silently drop the packet.
+        */
+       if (!(flg & TCP_FLAG_ACK))
+               return NULL;
 
-               /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
-               if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
-                       inet_rsk(req)->acked = 1;
-                       return NULL;
-               }
+       /* While TCP_DEFER_ACCEPT is active, drop bare ACK. */
+       if (req->retrans < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&
+           TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
+               inet_rsk(req)->acked = 1;
+               return NULL;
+       }
 
-               /* OK, ACK is valid, create big socket and
-                * feed this segment to it. It will repeat all
-                * the tests. THIS SEGMENT MUST MOVE SOCKET TO
-                * ESTABLISHED STATE. If it will be dropped after
-                * socket is created, wait for troubles.
-                */
-               child = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
-               if (child == NULL)
-                       goto listen_overflow;
+       /* OK, ACK is valid, create big socket and
+        * feed this segment to it. It will repeat all
+        * the tests. THIS SEGMENT MUST MOVE SOCKET TO
+        * ESTABLISHED STATE. If it will be dropped after
+        * socket is created, wait for troubles.
+        */
+       child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
+       if (child == NULL)
+               goto listen_overflow;
 
-               tcp_synq_unlink(tp, req, prev);
-               tcp_synq_removed(sk, req);
+       inet_csk_reqsk_queue_unlink(sk, req, prev);
+       inet_csk_reqsk_queue_removed(sk, req);
 
-               tcp_acceptq_queue(sk, req, child);
-               return child;
+       inet_csk_reqsk_queue_add(sk, req, child);
+       return child;
 
-       listen_overflow:
-               if (!sysctl_tcp_abort_on_overflow) {
-                       inet_rsk(req)->acked = 1;
-                       return NULL;
-               }
+listen_overflow:
+       if (!sysctl_tcp_abort_on_overflow) {
+               inet_rsk(req)->acked = 1;
+               return NULL;
+       }
 
-       embryonic_reset:
-               NET_INC_STATS_BH(LINUX_MIB_EMBRYONICRSTS);
-               if (!(flg & TCP_FLAG_RST))
-                       req->rsk_ops->send_reset(skb);
+embryonic_reset:
+       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_EMBRYONICRSTS);
+       if (!(flg & TCP_FLAG_RST))
+               req->rsk_ops->send_reset(sk, skb);
 
-               tcp_synq_drop(sk, req, prev);
-               return NULL;
+       inet_csk_reqsk_queue_drop(sk, req, prev);
+       return NULL;
 }
 
 /*
@@ -1066,8 +718,8 @@ int tcp_child_process(struct sock *parent, struct sock *child,
        int state = child->sk_state;
 
        if (!sock_owned_by_user(child)) {
-               ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len);
-
+               ret = tcp_rcv_state_process(child, skb, tcp_hdr(skb),
+                                           skb->len);
                /* Wakeup parent, send SIGIO */
                if (state == TCP_SYN_RECV && child->sk_state != state)
                        parent->sk_data_ready(parent, 0);
@@ -1088,4 +740,3 @@ EXPORT_SYMBOL(tcp_check_req);
 EXPORT_SYMBOL(tcp_child_process);
 EXPORT_SYMBOL(tcp_create_openreq_child);
 EXPORT_SYMBOL(tcp_timewait_state_process);
-EXPORT_SYMBOL(tcp_tw_deschedule);