TCPCT part 1d: define TCP cookie option, extend existing struct's
[safe/jmp/linux-2.6] / net / ipv4 / tcp_ipv4.c
index 19d7b42..a2bcac9 100644 (file)
@@ -165,10 +165,10 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                nexthop = inet->opt->faddr;
        }
 
-       tmp = ip_route_connect(&rt, nexthop, inet->saddr,
+       tmp = ip_route_connect(&rt, nexthop, inet->inet_saddr,
                               RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
                               IPPROTO_TCP,
-                              inet->sport, usin->sin_port, sk, 1);
+                              inet->inet_sport, usin->sin_port, sk, 1);
        if (tmp < 0) {
                if (tmp == -ENETUNREACH)
                        IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
@@ -183,11 +183,11 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        if (!inet->opt || !inet->opt->srr)
                daddr = rt->rt_dst;
 
-       if (!inet->saddr)
-               inet->saddr = rt->rt_src;
-       inet->rcv_saddr = inet->saddr;
+       if (!inet->inet_saddr)
+               inet->inet_saddr = rt->rt_src;
+       inet->inet_rcv_saddr = inet->inet_saddr;
 
-       if (tp->rx_opt.ts_recent_stamp && inet->daddr != daddr) {
+       if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {
                /* Reset inherited state */
                tp->rx_opt.ts_recent       = 0;
                tp->rx_opt.ts_recent_stamp = 0;
@@ -204,20 +204,20 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                 * when trying new connection.
                 */
                if (peer != NULL &&
-                   peer->tcp_ts_stamp + TCP_PAWS_MSL >= get_seconds()) {
+                   (u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) {
                        tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp;
                        tp->rx_opt.ts_recent = peer->tcp_ts;
                }
        }
 
-       inet->dport = usin->sin_port;
-       inet->daddr = daddr;
+       inet->inet_dport = usin->sin_port;
+       inet->inet_daddr = daddr;
 
        inet_csk(sk)->icsk_ext_hdr_len = 0;
        if (inet->opt)
                inet_csk(sk)->icsk_ext_hdr_len = inet->opt->optlen;
 
-       tp->rx_opt.mss_clamp = 536;
+       tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT;
 
        /* Socket identity is still unknown (sport may be zero).
         * However we set state to SYN-SENT and not releasing socket
@@ -230,7 +230,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
                goto failure;
 
        err = ip_route_newports(&rt, IPPROTO_TCP,
-                               inet->sport, inet->dport, sk);
+                               inet->inet_sport, inet->inet_dport, sk);
        if (err)
                goto failure;
 
@@ -239,12 +239,12 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        sk_setup_caps(sk, &rt->u.dst);
 
        if (!tp->write_seq)
-               tp->write_seq = secure_tcp_sequence_number(inet->saddr,
-                                                          inet->daddr,
-                                                          inet->sport,
+               tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
+                                                          inet->inet_daddr,
+                                                          inet->inet_sport,
                                                           usin->sin_port);
 
-       inet->id = tp->write_seq ^ jiffies;
+       inet->inet_id = tp->write_seq ^ jiffies;
 
        err = tcp_connect(sk);
        rt = NULL;
@@ -261,7 +261,7 @@ failure:
        tcp_set_state(sk, TCP_CLOSE);
        ip_rt_put(rt);
        sk->sk_route_caps = 0;
-       inet->dport = 0;
+       inet->inet_dport = 0;
        return err;
 }
 
@@ -328,26 +328,29 @@ static void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, u32 mtu)
  *
  */
 
-void tcp_v4_err(struct sk_buff *skb, u32 info)
+void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
 {
-       struct iphdr *iph = (struct iphdr *)skb->data;
-       struct tcphdr *th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+       struct iphdr *iph = (struct iphdr *)icmp_skb->data;
+       struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2));
+       struct inet_connection_sock *icsk;
        struct tcp_sock *tp;
        struct inet_sock *inet;
-       const int type = icmp_hdr(skb)->type;
-       const int code = icmp_hdr(skb)->code;
+       const int type = icmp_hdr(icmp_skb)->type;
+       const int code = icmp_hdr(icmp_skb)->code;
        struct sock *sk;
+       struct sk_buff *skb;
        __u32 seq;
+       __u32 remaining;
        int err;
-       struct net *net = dev_net(skb->dev);
+       struct net *net = dev_net(icmp_skb->dev);
 
-       if (skb->len < (iph->ihl << 2) + 8) {
+       if (icmp_skb->len < (iph->ihl << 2) + 8) {
                ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
                return;
        }
 
        sk = inet_lookup(net, &tcp_hashinfo, iph->daddr, th->dest,
-                       iph->saddr, th->source, inet_iif(skb));
+                       iph->saddr, th->source, inet_iif(icmp_skb));
        if (!sk) {
                ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
                return;
@@ -367,6 +370,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
        if (sk->sk_state == TCP_CLOSE)
                goto out;
 
+       icsk = inet_csk(sk);
        tp = tcp_sk(sk);
        seq = ntohl(th->seq);
        if (sk->sk_state != TCP_LISTEN &&
@@ -393,6 +397,39 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
                }
 
                err = icmp_err_convert[code].errno;
+               /* check if icmp_skb allows revert of backoff
+                * (see draft-zimmermann-tcp-lcd) */
+               if (code != ICMP_NET_UNREACH && code != ICMP_HOST_UNREACH)
+                       break;
+               if (seq != tp->snd_una  || !icsk->icsk_retransmits ||
+                   !icsk->icsk_backoff)
+                       break;
+
+               icsk->icsk_backoff--;
+               inet_csk(sk)->icsk_rto = __tcp_set_rto(tp) <<
+                                        icsk->icsk_backoff;
+               tcp_bound_rto(sk);
+
+               skb = tcp_write_queue_head(sk);
+               BUG_ON(!skb);
+
+               remaining = icsk->icsk_rto - min(icsk->icsk_rto,
+                               tcp_time_stamp - TCP_SKB_CB(skb)->when);
+
+               if (remaining) {
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                                 remaining, TCP_RTO_MAX);
+               } else if (sock_owned_by_user(sk)) {
+                       /* RTO revert clocked out retransmission,
+                        * but socket is locked. Will defer. */
+                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                                 HZ/20, TCP_RTO_MAX);
+               } else {
+                       /* RTO revert clocked out retransmission.
+                        * Will retransmit now */
+                       tcp_retransmit_timer(sk);
+               }
+
                break;
        case ICMP_TIME_EXCEEDED:
                err = EHOSTUNREACH;
@@ -483,12 +520,13 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
        struct tcphdr *th = tcp_hdr(skb);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               th->check = ~tcp_v4_check(len, inet->saddr,
-                                         inet->daddr, 0);
+               th->check = ~tcp_v4_check(len, inet->inet_saddr,
+                                         inet->inet_daddr, 0);
                skb->csum_start = skb_transport_header(skb) - skb->head;
                skb->csum_offset = offsetof(struct tcphdr, check);
        } else {
-               th->check = tcp_v4_check(len, inet->saddr, inet->daddr,
+               th->check = tcp_v4_check(len, inet->inet_saddr,
+                                        inet->inet_daddr,
                                         csum_partial(th,
                                                      th->doff << 2,
                                                      skb->csum));
@@ -546,7 +584,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
        if (th->rst)
                return;
 
-       if (skb->rtable->rt_type != RTN_LOCAL)
+       if (skb_rtable(skb)->rt_type != RTN_LOCAL)
                return;
 
        /* Swap the send and the receive. */
@@ -590,7 +628,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
        arg.csumoffset = offsetof(struct tcphdr, check) / 2;
        arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0;
 
-       net = dev_net(skb->dst->dev);
+       net = dev_net(skb_dst(skb)->dev);
        ip_send_reply(net->ipv4.tcp_sock, skb,
                      &arg, arg.iov[0].iov_len);
 
@@ -617,7 +655,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
                        ];
        } rep;
        struct ip_reply_arg arg;
-       struct net *net = dev_net(skb->dst->dev);
+       struct net *net = dev_net(skb_dst(skb)->dev);
 
        memset(&rep.th, 0, sizeof(struct tcphdr));
        memset(&arg, 0, sizeof(arg));
@@ -704,8 +742,9 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
  *     This still operates on a request_sock only, not on a big
  *     socket.
  */
-static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
-                               struct dst_entry *dst)
+static int __tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
+                               struct request_sock *req,
+                               struct request_values *rvp)
 {
        const struct inet_request_sock *ireq = inet_rsk(req);
        int err = -1;
@@ -715,7 +754,7 @@ static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
        if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
                return -1;
 
-       skb = tcp_make_synack(sk, dst, req);
+       skb = tcp_make_synack(sk, dst, req, rvp);
 
        if (skb) {
                struct tcphdr *th = tcp_hdr(skb);
@@ -736,9 +775,10 @@ static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
        return err;
 }
 
-static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req)
+static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+                             struct request_values *rvp)
 {
-       return __tcp_v4_send_synack(sk, req, NULL);
+       return __tcp_v4_send_synack(sk, NULL, req, rvp);
 }
 
 /*
@@ -811,7 +851,7 @@ static struct tcp_md5sig_key *
 struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
                                         struct sock *addr_sk)
 {
-       return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->daddr);
+       return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr);
 }
 
 EXPORT_SYMBOL(tcp_v4_md5_lookup);
@@ -849,7 +889,7 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr,
                        }
                        sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
                }
-               if (tcp_alloc_md5sig_pool() == NULL) {
+               if (tcp_alloc_md5sig_pool(sk) == NULL) {
                        kfree(newkey);
                        return -ENOMEM;
                }
@@ -886,7 +926,7 @@ EXPORT_SYMBOL(tcp_v4_md5_do_add);
 static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk,
                               u8 *newkey, u8 newkeylen)
 {
-       return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->daddr,
+       return tcp_v4_md5_do_add(sk, inet_sk(addr_sk)->inet_daddr,
                                 newkey, newkeylen);
 }
 
@@ -970,8 +1010,9 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
 
        if (!tcp_sk(sk)->md5sig_info) {
                struct tcp_sock *tp = tcp_sk(sk);
-               struct tcp_md5sig_info *p = kzalloc(sizeof(*p), GFP_KERNEL);
+               struct tcp_md5sig_info *p;
 
+               p = kzalloc(sizeof(*p), sk->sk_allocation);
                if (!p)
                        return -EINVAL;
 
@@ -979,7 +1020,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
                sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
        }
 
-       newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
+       newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, sk->sk_allocation);
        if (!newkey)
                return -ENOMEM;
        return tcp_v4_md5_do_add(sk, sin->sin_addr.s_addr,
@@ -1051,8 +1092,8 @@ int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
        __be32 saddr, daddr;
 
        if (sk) {
-               saddr = inet_sk(sk)->saddr;
-               daddr = inet_sk(sk)->daddr;
+               saddr = inet_sk(sk)->inet_saddr;
+               daddr = inet_sk(sk)->inet_daddr;
        } else if (req) {
                saddr = inet_rsk(req)->loc_addr;
                daddr = inet_rsk(req)->rmt_addr;
@@ -1158,8 +1199,9 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = {
 };
 
 #ifdef CONFIG_TCP_MD5SIG
-static struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
+static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
        .md5_lookup     =       tcp_v4_reqsk_md5_lookup,
+       .calc_md5_hash  =       tcp_v4_md5_hash_skb,
 };
 #endif
 
@@ -1171,13 +1213,13 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
 
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 {
-       struct inet_request_sock *ireq;
        struct tcp_options_received tmp_opt;
        struct request_sock *req;
+       struct inet_request_sock *ireq;
+       struct dst_entry *dst = NULL;
        __be32 saddr = ip_hdr(skb)->saddr;
        __be32 daddr = ip_hdr(skb)->daddr;
        __u32 isn = TCP_SKB_CB(skb)->when;
-       struct dst_entry *dst = NULL;
 #ifdef CONFIG_SYN_COOKIES
        int want_cookie = 0;
 #else
@@ -1185,7 +1227,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 #endif
 
        /* Never answer to SYNs send to broadcast or multicast */
-       if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+       if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
                goto drop;
 
        /* TW buckets are converted to open requests without
@@ -1217,36 +1259,32 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops;
 #endif
 
+       ireq = inet_rsk(req);
+       ireq->loc_addr = daddr;
+       ireq->rmt_addr = saddr;
+       ireq->no_srccheck = inet_sk(sk)->transparent;
+       ireq->opt = tcp_v4_save_options(sk, skb);
+
+       dst = inet_csk_route_req(sk, req);
+       if(!dst)
+               goto drop_and_free;
+
        tcp_clear_options(&tmp_opt);
-       tmp_opt.mss_clamp = 536;
+       tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
        tmp_opt.user_mss  = tcp_sk(sk)->rx_opt.user_mss;
 
-       tcp_parse_options(skb, &tmp_opt, 0);
+       tcp_parse_options(skb, &tmp_opt, 0, dst);
 
        if (want_cookie && !tmp_opt.saw_tstamp)
                tcp_clear_options(&tmp_opt);
 
-       if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) {
-               /* Some OSes (unknown ones, but I see them on web server, which
-                * contains information interesting only for windows'
-                * users) do not send their stamp in SYN. It is easy case.
-                * We simply do not advertise TS support.
-                */
-               tmp_opt.saw_tstamp = 0;
-               tmp_opt.tstamp_ok  = 0;
-       }
        tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 
        tcp_openreq_init(req, &tmp_opt, skb);
 
        if (security_inet_conn_request(sk, skb, req))
-               goto drop_and_free;
+               goto drop_and_release;
 
-       ireq = inet_rsk(req);
-       ireq->loc_addr = daddr;
-       ireq->rmt_addr = saddr;
-       ireq->no_srccheck = inet_sk(sk)->transparent;
-       ireq->opt = tcp_v4_save_options(sk, skb);
        if (!want_cookie)
                TCP_ECN_create_request(req, tcp_hdr(skb));
 
@@ -1270,10 +1308,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                 */
                if (tmp_opt.saw_tstamp &&
                    tcp_death_row.sysctl_tw_recycle &&
-                   (dst = inet_csk_route_req(sk, req)) != NULL &&
                    (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
                    peer->v4daddr == saddr) {
-                       if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
+                       if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
                            (s32)(peer->tcp_ts - req->ts_recent) >
                                                        TCP_PAWS_WINDOW) {
                                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
@@ -1302,7 +1339,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        }
        tcp_rsk(req)->snt_isn = isn;
 
-       if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
+       if (__tcp_v4_send_synack(sk, dst, req, NULL) || want_cookie)
                goto drop_and_free;
 
        inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
@@ -1349,9 +1386,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        newtp                 = tcp_sk(newsk);
        newinet               = inet_sk(newsk);
        ireq                  = inet_rsk(req);
-       newinet->daddr        = ireq->rmt_addr;
-       newinet->rcv_saddr    = ireq->loc_addr;
-       newinet->saddr        = ireq->loc_addr;
+       newinet->inet_daddr   = ireq->rmt_addr;
+       newinet->inet_rcv_saddr = ireq->loc_addr;
+       newinet->inet_saddr           = ireq->loc_addr;
        newinet->opt          = ireq->opt;
        ireq->opt             = NULL;
        newinet->mc_index     = inet_iif(skb);
@@ -1359,7 +1396,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        inet_csk(newsk)->icsk_ext_hdr_len = 0;
        if (newinet->opt)
                inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen;
-       newinet->id = newtp->write_seq ^ jiffies;
+       newinet->inet_id = newtp->write_seq ^ jiffies;
 
        tcp_mtup_init(newsk);
        tcp_sync_mss(newsk, dst_mtu(dst));
@@ -1372,7 +1409,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
 #ifdef CONFIG_TCP_MD5SIG
        /* Copy over the MD5 key from the original socket */
-       if ((key = tcp_v4_md5_do_lookup(sk, newinet->daddr)) != NULL) {
+       key = tcp_v4_md5_do_lookup(sk, newinet->inet_daddr);
+       if (key != NULL) {
                /*
                 * We're using one, so create a matching key
                 * on the newsk structure. If we fail to get
@@ -1381,7 +1419,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                 */
                char *newkey = kmemdup(key->key, key->keylen, GFP_ATOMIC);
                if (newkey != NULL)
-                       tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr,
+                       tcp_v4_md5_do_add(newsk, newinet->inet_daddr,
                                          newkey, key->keylen);
                newsk->sk_route_caps &= ~NETIF_F_GSO_MASK;
        }
@@ -1601,7 +1639,7 @@ process:
 #endif
                {
                        if (!tcp_prequeue(sk, skb))
-                       ret = tcp_v4_do_rcv(sk, skb);
+                               ret = tcp_v4_do_rcv(sk, skb);
                }
        } else
                sk_add_backlog(sk, skb);
@@ -1680,8 +1718,8 @@ int tcp_v4_remember_stamp(struct sock *sk)
        struct inet_peer *peer = NULL;
        int release_it = 0;
 
-       if (!rt || rt->rt_dst != inet->daddr) {
-               peer = inet_getpeer(inet->daddr, 1);
+       if (!rt || rt->rt_dst != inet->inet_daddr) {
+               peer = inet_getpeer(inet->inet_daddr, 1);
                release_it = 1;
        } else {
                if (!rt->peer)
@@ -1691,9 +1729,9 @@ int tcp_v4_remember_stamp(struct sock *sk)
 
        if (peer) {
                if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 ||
-                   (peer->tcp_ts_stamp + TCP_PAWS_MSL < get_seconds() &&
-                    peer->tcp_ts_stamp <= tp->rx_opt.ts_recent_stamp)) {
-                       peer->tcp_ts_stamp = tp->rx_opt.ts_recent_stamp;
+                   ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
+                    peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) {
+                       peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp;
                        peer->tcp_ts = tp->rx_opt.ts_recent;
                }
                if (release_it)
@@ -1712,9 +1750,9 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
                const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
 
                if ((s32)(peer->tcp_ts - tcptw->tw_ts_recent) <= 0 ||
-                   (peer->tcp_ts_stamp + TCP_PAWS_MSL < get_seconds() &&
-                    peer->tcp_ts_stamp <= tcptw->tw_ts_recent_stamp)) {
-                       peer->tcp_ts_stamp = tcptw->tw_ts_recent_stamp;
+                   ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
+                    peer->tcp_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) {
+                       peer->tcp_ts_stamp = (u32)tcptw->tw_ts_recent_stamp;
                        peer->tcp_ts       = tcptw->tw_ts_recent;
                }
                inet_putpeer(peer);
@@ -1724,7 +1762,7 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
        return 0;
 }
 
-struct inet_connection_sock_af_ops ipv4_specific = {
+const struct inet_connection_sock_af_ops ipv4_specific = {
        .queue_xmit        = ip_queue_xmit,
        .send_check        = tcp_v4_send_check,
        .rebuild_header    = inet_sk_rebuild_header,
@@ -1744,7 +1782,7 @@ struct inet_connection_sock_af_ops ipv4_specific = {
 };
 
 #ifdef CONFIG_TCP_MD5SIG
-static struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
+static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
        .md5_lookup             = tcp_v4_md5_lookup,
        .calc_md5_hash          = tcp_v4_md5_hash_skb,
        .md5_add                = tcp_v4_md5_add_func,
@@ -1777,9 +1815,9 @@ static int tcp_v4_init_sock(struct sock *sk)
        /* See draft-stevens-tcpca-spec-01 for discussion of the
         * initialization of these values.
         */
-       tp->snd_ssthresh = 0x7fffffff;  /* Infinity */
+       tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
        tp->snd_cwnd_clamp = ~0;
-       tp->mss_cache = 536;
+       tp->mss_cache = TCP_MSS_DEFAULT;
 
        tp->reordering = sysctl_tcp_reordering;
        icsk->icsk_ca_ops = &tcp_init_congestion_ops;
@@ -1795,6 +1833,19 @@ static int tcp_v4_init_sock(struct sock *sk)
        tp->af_specific = &tcp_sock_ipv4_specific;
 #endif
 
+       /* TCP Cookie Transactions */
+       if (sysctl_tcp_cookie_size > 0) {
+               /* Default, cookies without s_data_payload. */
+               tp->cookie_values =
+                       kzalloc(sizeof(*tp->cookie_values),
+                               sk->sk_allocation);
+               if (tp->cookie_values != NULL)
+                       kref_init(&tp->cookie_values->kref);
+       }
+       /* Presumed zeroed, in order of appearance:
+        *      cookie_in_always, cookie_out_never,
+        *      s_data_constant, s_data_in, s_data_out
+        */
        sk->sk_sndbuf = sysctl_tcp_wmem[1];
        sk->sk_rcvbuf = sysctl_tcp_rmem[1];
 
@@ -1848,6 +1899,13 @@ void tcp_v4_destroy_sock(struct sock *sk)
                sk->sk_sndmsg_page = NULL;
        }
 
+       /* TCP Cookie Transactions */
+       if (tp->cookie_values != NULL) {
+               kref_put(&tp->cookie_values->kref,
+                        tcp_cookie_values_release);
+               tp->cookie_values = NULL;
+       }
+
        percpu_counter_dec(&tcp_sockets_allocated);
 }
 
@@ -1969,7 +2027,7 @@ static void *established_get_first(struct seq_file *seq)
        struct net *net = seq_file_net(seq);
        void *rc = NULL;
 
-       for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
+       for (st->bucket = 0; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) {
                struct sock *sk;
                struct hlist_nulls_node *node;
                struct inet_timewait_sock *tw;
@@ -2030,10 +2088,10 @@ get_tw:
                st->state = TCP_SEQ_STATE_ESTABLISHED;
 
                /* Look for next non empty bucket */
-               while (++st->bucket < tcp_hashinfo.ehash_size &&
+               while (++st->bucket <= tcp_hashinfo.ehash_mask &&
                                empty_bucket(st))
                        ;
-               if (st->bucket >= tcp_hashinfo.ehash_size)
+               if (st->bucket > tcp_hashinfo.ehash_mask)
                        return NULL;
 
                spin_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
@@ -2194,7 +2252,7 @@ static void get_openreq4(struct sock *sk, struct request_sock *req,
                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n",
                i,
                ireq->loc_addr,
-               ntohs(inet_sk(sk)->sport),
+               ntohs(inet_sk(sk)->inet_sport),
                ireq->rmt_addr,
                ntohs(ireq->rmt_port),
                TCP_SYN_RECV,
@@ -2217,10 +2275,10 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
        struct tcp_sock *tp = tcp_sk(sk);
        const struct inet_connection_sock *icsk = inet_csk(sk);
        struct inet_sock *inet = inet_sk(sk);
-       __be32 dest = inet->daddr;
-       __be32 src = inet->rcv_saddr;
-       __u16 destp = ntohs(inet->dport);
-       __u16 srcp = ntohs(inet->sport);
+       __be32 dest = inet->inet_daddr;
+       __be32 src = inet->inet_rcv_saddr;
+       __u16 destp = ntohs(inet->inet_dport);
+       __u16 srcp = ntohs(inet->inet_sport);
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
                timer_active    = 1;
@@ -2253,7 +2311,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
                jiffies_to_clock_t(icsk->icsk_ack.ato),
                (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
                tp->snd_cwnd,
-               tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh,
+               tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh,
                len);
 }
 
@@ -2351,11 +2409,11 @@ void tcp4_proc_exit(void)
 
 struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 {
-       struct iphdr *iph = ip_hdr(skb);
+       struct iphdr *iph = skb_gro_network_header(skb);
 
        switch (skb->ip_summed) {
        case CHECKSUM_COMPLETE:
-               if (!tcp_v4_check(skb->len, iph->saddr, iph->daddr,
+               if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
                                  skb->csum)) {
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                        break;
@@ -2443,7 +2501,7 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
 void __init tcp_v4_init(void)
 {
        inet_hashinfo_init(&tcp_hashinfo);
-       if (register_pernet_device(&tcp_sk_ops))
+       if (register_pernet_subsys(&tcp_sk_ops))
                panic("Failed to create the TCP control socket.\n");
 }