vserver 1.9.5.x5
[linux-2.6.git] / net / ipv6 / tcp_ipv6.c
index 2949cd1..5167758 100644 (file)
 #include <net/transp_v6.h>
 #include <net/addrconf.h>
 #include <net/ip6_route.h>
+#include <net/ip6_checksum.h>
 #include <net/inet_ecn.h>
 #include <net/protocol.h>
 #include <net/xfrm.h>
+#include <net/addrconf.h>
+#include <net/snmp.h>
+#include <net/dsfield.h>
 
 #include <asm/uaccess.h>
 
@@ -85,7 +89,7 @@ static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport,
 
 static __inline__ int tcp_v6_sk_hashfn(struct sock *sk)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct in6_addr *laddr = &np->rcv_saddr;
        struct in6_addr *faddr = &np->daddr;
@@ -231,7 +235,7 @@ static __inline__ void __tcp_v6_hash(struct sock *sk)
 static void tcp_v6_hash(struct sock *sk)
 {
        if (sk->sk_state != TCP_CLOSE) {
-               struct tcp_opt *tp = tcp_sk(sk);
+               struct tcp_sock *tp = tcp_sk(sk);
 
                if (tp->af_specific == &ipv6_mapped) {
                        tcp_prot.hash(sk);
@@ -258,7 +262,7 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor
                        
                        score = 1;
                        if (!ipv6_addr_any(&np->rcv_saddr)) {
-                               if (ipv6_addr_cmp(&np->rcv_saddr, daddr))
+                               if (!ipv6_addr_equal(&np->rcv_saddr, daddr))
                                        continue;
                                score++;
                        }
@@ -317,8 +321,8 @@ static inline struct sock *__tcp_v6_lookup_established(struct in6_addr *saddr, u
 
                if(*((__u32 *)&(tw->tw_dport))  == ports        &&
                   sk->sk_family                == PF_INET6) {
-                       if(!ipv6_addr_cmp(&tw->tw_v6_daddr, saddr)      &&
-                          !ipv6_addr_cmp(&tw->tw_v6_rcv_saddr, daddr)  &&
+                       if(ipv6_addr_equal(&tw->tw_v6_daddr, saddr)     &&
+                          ipv6_addr_equal(&tw->tw_v6_rcv_saddr, daddr) &&
                           (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
                                goto hit;
                }
@@ -360,6 +364,8 @@ inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
        return sk;
 }
 
+EXPORT_SYMBOL_GPL(tcp_v6_lookup);
+
 
 /*
  * Open request hash tables.
@@ -385,7 +391,7 @@ static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd)
        return c & (TCP_SYNQ_HSIZE - 1);
 }
 
-static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
+static struct open_request *tcp_v6_search_req(struct tcp_sock *tp,
                                              struct open_request ***prevp,
                                              __u16 rport,
                                              struct in6_addr *raddr,
@@ -400,8 +406,8 @@ static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
             prev = &req->dl_next) {
                if (req->rmt_port == rport &&
                    req->class->family == AF_INET6 &&
-                   !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, raddr) &&
-                   !ipv6_addr_cmp(&req->af.v6_req.loc_addr, laddr) &&
+                   ipv6_addr_equal(&req->af.v6_req.rmt_addr, raddr) &&
+                   ipv6_addr_equal(&req->af.v6_req.loc_addr, laddr) &&
                    (!req->af.v6_req.iif || req->af.v6_req.iif == iif)) {
                        BUG_TRAP(req->sk == NULL);
                        *prevp = prev;
@@ -437,7 +443,7 @@ static __u32 tcp_v6_init_sequence(struct sock *sk, struct sk_buff *skb)
 
 static int tcp_v6_check_established(struct sock *sk)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct in6_addr *daddr = &np->rcv_saddr;
        struct in6_addr *saddr = &np->daddr;
@@ -457,18 +463,18 @@ static int tcp_v6_check_established(struct sock *sk)
 
                if(*((__u32 *)&(tw->tw_dport))  == ports        &&
                   sk2->sk_family               == PF_INET6     &&
-                  !ipv6_addr_cmp(&tw->tw_v6_daddr, saddr)      &&
-                  !ipv6_addr_cmp(&tw->tw_v6_rcv_saddr, daddr)  &&
+                  ipv6_addr_equal(&tw->tw_v6_daddr, saddr)     &&
+                  ipv6_addr_equal(&tw->tw_v6_rcv_saddr, daddr) &&
                   sk2->sk_bound_dev_if == sk->sk_bound_dev_if) {
-                       struct tcp_opt *tp = tcp_sk(sk);
+                       struct tcp_sock *tp = tcp_sk(sk);
 
                        if (tw->tw_ts_recent_stamp) {
                                /* See comment in tcp_ipv4.c */
                                tp->write_seq = tw->tw_snd_nxt + 65535 + 2;
                                if (!tp->write_seq)
                                        tp->write_seq = 1;
-                               tp->ts_recent = tw->tw_ts_recent;
-                               tp->ts_recent_stamp = tw->tw_ts_recent_stamp;
+                               tp->rx_opt.ts_recent = tw->tw_ts_recent;
+                               tp->rx_opt.ts_recent_stamp = tw->tw_ts_recent_stamp;
                                sock_hold(sk2);
                                goto unique;
                        } else
@@ -479,7 +485,7 @@ static int tcp_v6_check_established(struct sock *sk)
 
        /* And established part... */
        sk_for_each(sk2, node, &head->chain) {
-               if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif))
+               if(TCP_IPV6_MATCH(sk2, saddr, daddr, ports, dif))
                        goto not_unique;
        }
 
@@ -494,7 +500,7 @@ unique:
                /* Silly. Should hash-dance instead... */
                local_bh_disable();
                tcp_tw_deschedule(tw);
-               NET_INC_STATS_BH(TimeWaitRecycled);
+               NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
                local_bh_enable();
 
                tcp_tw_put(tw);
@@ -536,18 +542,17 @@ static int tcp_v6_hash_connect(struct sock *sk)
 
 static __inline__ int tcp_v6_iif(struct sk_buff *skb)
 {
-       struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
-       return opt->iif;
+       return IP6CB(skb)->iif;
 }
 
 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 
                          int addr_len)
 {
        struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct tcp_opt *tp = tcp_sk(sk);
-       struct in6_addr *saddr = NULL;
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct in6_addr *saddr = NULL, *final_p = NULL, final;
        struct flowi fl;
        struct dst_entry *dst;
        int addr_type;
@@ -604,10 +609,10 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                        return -EINVAL;
        }
 
-       if (tp->ts_recent_stamp &&
-           ipv6_addr_cmp(&np->daddr, &usin->sin6_addr)) {
-               tp->ts_recent = 0;
-               tp->ts_recent_stamp = 0;
+       if (tp->rx_opt.ts_recent_stamp &&
+           !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) {
+               tp->rx_opt.ts_recent = 0;
+               tp->rx_opt.ts_recent_stamp = 0;
                tp->write_seq = 0;
        }
 
@@ -664,13 +669,21 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
 
        if (np->opt && np->opt->srcrt) {
                struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
+               ipv6_addr_copy(&final, &fl.fl6_dst);
                ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+               final_p = &final;
        }
 
        err = ip6_dst_lookup(sk, &dst, &fl);
-
        if (err)
                goto failure;
+       if (final_p)
+               ipv6_addr_copy(&fl.fl6_dst, final_p);
+
+       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+               dst_release(dst);
+               goto failure;
+       }
 
        if (saddr == NULL) {
                saddr = &fl.fl6_src;
@@ -690,7 +703,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
                tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
        tp->ext2_header_len = dst->header_len;
 
-       tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
+       tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
        inet->dport = usin->sin6_port;
 
@@ -728,13 +741,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct ipv6_pinfo *np;
        struct sock *sk;
        int err;
-       struct tcp_opt *tp; 
+       struct tcp_sock *tp; 
        __u32 seq;
 
        sk = tcp_v6_lookup(&hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
 
        if (sk == NULL) {
-               ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), Icmp6InErrors);
+               ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);
                return;
        }
 
@@ -745,7 +758,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk))
-               NET_INC_STATS_BH(LockDroppedIcmps);
+               NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);
 
        if (sk->sk_state == TCP_CLOSE)
                goto out;
@@ -754,7 +767,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        seq = ntohl(th->seq); 
        if (sk->sk_state != TCP_LISTEN &&
            !between(seq, tp->snd_una, tp->snd_nxt)) {
-               NET_INC_STATS_BH(OutOfWindowIcmps);
+               NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
                goto out;
        }
 
@@ -772,7 +785,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                dst = __sk_dst_check(sk, np->dst_cookie);
 
                if (dst == NULL) {
-                       struct inet_opt *inet = inet_sk(sk);
+                       struct inet_sock *inet = inet_sk(sk);
                        struct flowi fl;
 
                        /* BUGGG_FUTURE: Again, it is not clear how
@@ -791,6 +804,12 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                                sk->sk_err_soft = -err;
                                goto out;
                        }
+
+                       if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+                               sk->sk_err_soft = -err;
+                               goto out;
+                       }
+
                } else
                        dst_hold(dst);
 
@@ -822,7 +841,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                BUG_TRAP(req->sk == NULL);
 
                if (seq != req->snt_isn) {
-                       NET_INC_STATS_BH(OutOfWindowIcmps);
+                       NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
                        goto out;
                }
 
@@ -833,7 +852,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        case TCP_SYN_RECV:  /* Cannot happen.
                               It can, it SYNs are crossed. --ANK */ 
                if (!sock_owned_by_user(sk)) {
-                       TCP_INC_STATS_BH(TcpAttemptFails);
+                       TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
                        sk->sk_err = err;
                        sk->sk_error_report(sk);                /* Wake people up to see the error (see connect in sock.c) */
 
@@ -861,6 +880,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct sk_buff * skb;
        struct ipv6_txoptions *opt = NULL;
+       struct in6_addr * final_p = NULL, final;
        struct flowi fl;
        int err = -1;
 
@@ -879,19 +899,25 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
                    np->rxopt.bits.srcrt == 2 &&
                    req->af.v6_req.pktopts) {
                        struct sk_buff *pktopts = req->af.v6_req.pktopts;
-                       struct inet6_skb_parm *rxopt = (struct inet6_skb_parm *)pktopts->cb;
+                       struct inet6_skb_parm *rxopt = IP6CB(pktopts);
                        if (rxopt->srcrt)
                                opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(pktopts->nh.raw + rxopt->srcrt));
                }
 
                if (opt && opt->srcrt) {
                        struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+                       ipv6_addr_copy(&final, &fl.fl6_dst);
                        ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+                       final_p = &final;
                }
 
                err = ip6_dst_lookup(sk, &dst, &fl);
                if (err)
                        goto done;
+               if (final_p)
+                       ipv6_addr_copy(&fl.fl6_dst, final_p);
+               if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+                       goto done;
        }
 
        skb = tcp_make_synack(sk, dst, req);
@@ -932,7 +958,7 @@ static struct or_calltable or_ipv6 = {
 static int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+       struct inet6_skb_parm *opt = IP6CB(skb);
 
        if (np->rxopt.all) {
                if ((opt->hop && np->rxopt.bits.hopopts) ||
@@ -979,11 +1005,12 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
         * and then put it into the queue to be sent.
         */
 
-       buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC);
+       buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr),
+                        GFP_ATOMIC);
        if (buff == NULL) 
                return;
 
-       skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr));
+       skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
 
        t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
 
@@ -1019,9 +1046,15 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
 
        /* sk = NULL, but it is safe for now. RST socket required. */
        if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+
+               if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
+                       dst_release(buff->dst);
+                       return;
+               }
+
                ip6_xmit(NULL, buff, &fl, NULL, 0);
-               TCP_INC_STATS_BH(TcpOutSegs);
-               TCP_INC_STATS_BH(TcpOutRsts);
+               TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
+               TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
                return;
        }
 
@@ -1035,14 +1068,15 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
        struct flowi fl;
        int tot_len = sizeof(struct tcphdr);
 
-       buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC);
+       if (ts)
+               tot_len += 3*4;
+
+       buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
+                        GFP_ATOMIC);
        if (buff == NULL)
                return;
 
-       skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr));
-
-       if (ts)
-               tot_len += 3*4;
+       skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
 
        t1 = (struct tcphdr *) skb_push(buff,tot_len);
 
@@ -1080,8 +1114,12 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
        fl.fl_ip_sport = t1->source;
 
        if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+               if ((xfrm_lookup(&buff->dst, &fl, NULL, 0)) < 0) {
+                       dst_release(buff->dst);
+                       return;
+               }
                ip6_xmit(NULL, buff, &fl, NULL, 0);
-               TCP_INC_STATS_BH(TcpOutSegs);
+               TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
                return;
        }
 
@@ -1108,7 +1146,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 {
        struct open_request *req, **prev;
        struct tcphdr *th = skb->h.th;
-       struct tcp_opt *tp = tcp_sk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
        struct sock *nsk;
 
        /* Find possible connection requests. */
@@ -1141,7 +1179,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 
 static void tcp_v6_synq_add(struct sock *sk, struct open_request *req)
 {
-       struct tcp_opt *tp = tcp_sk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
        struct tcp_listen_opt *lopt = tp->listen_opt;
        u32 h = tcp_v6_synq_hash(&req->af.v6_req.rmt_addr, req->rmt_port, lopt->hash_rnd);
 
@@ -1164,7 +1202,8 @@ static void tcp_v6_synq_add(struct sock *sk, struct open_request *req)
 static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct tcp_opt tmptp, *tp = tcp_sk(sk);
+       struct tcp_options_received tmp_opt;
+       struct tcp_sock *tp = tcp_sk(sk);
        struct open_request *req = NULL;
        __u32 isn = TCP_SKB_CB(skb)->when;
 
@@ -1183,21 +1222,21 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                goto drop;              
        }
 
-       if (tcp_acceptq_is_full(sk) && tcp_synq_young(sk) > 1)
+       if (sk_acceptq_is_full(sk) && tcp_synq_young(sk) > 1)
                goto drop;
 
        req = tcp_openreq_alloc();
        if (req == NULL)
                goto drop;
 
-       tcp_clear_options(&tmptp);
-       tmptp.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
-       tmptp.user_mss = tp->user_mss;
+       tcp_clear_options(&tmp_opt);
+       tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
+       tmp_opt.user_mss = tp->rx_opt.user_mss;
 
-       tcp_parse_options(skb, &tmptp, 0);
+       tcp_parse_options(skb, &tmp_opt, 0);
 
-       tmptp.tstamp_ok = tmptp.saw_tstamp;
-       tcp_openreq_init(req, &tmptp, skb);
+       tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
+       tcp_openreq_init(req, &tmp_opt, skb);
 
        req->class = &or_ipv6;
        ipv6_addr_copy(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr);
@@ -1233,7 +1272,7 @@ drop:
        if (req)
                tcp_openreq_free(req);
 
-       TCP_INC_STATS_BH(TcpAttemptFails);
+       TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS);
        return 0; /* don't send reset */
 }
 
@@ -1243,8 +1282,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 {
        struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
        struct tcp6_sock *newtcp6sk;
-       struct inet_opt *newinet;
-       struct tcp_opt *newtp;
+       struct inet_sock *newinet;
+       struct tcp_sock *newtp;
        struct sock *newsk;
        struct ipv6_txoptions *opt;
 
@@ -1259,7 +1298,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                        return NULL;
 
                newtcp6sk = (struct tcp6_sock *)newsk;
-               newtcp6sk->pinet6 = &newtcp6sk->inet6;
+               inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
 
                newinet = inet_sk(newsk);
                newnp = inet6_sk(newsk);
@@ -1300,17 +1339,18 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
        opt = np->opt;
 
-       if (tcp_acceptq_is_full(sk))
+       if (sk_acceptq_is_full(sk))
                goto out_overflow;
 
        if (np->rxopt.bits.srcrt == 2 &&
            opt == NULL && req->af.v6_req.pktopts) {
-               struct inet6_skb_parm *rxopt = (struct inet6_skb_parm *)req->af.v6_req.pktopts->cb;
+               struct inet6_skb_parm *rxopt = IP6CB(req->af.v6_req.pktopts);
                if (rxopt->srcrt)
                        opt = ipv6_invert_rthdr(sk, (struct ipv6_rt_hdr*)(req->af.v6_req.pktopts->nh.raw+rxopt->srcrt));
        }
 
        if (dst == NULL) {
+               struct in6_addr *final_p = NULL, final;
                struct flowi fl;
 
                memset(&fl, 0, sizeof(fl));
@@ -1318,7 +1358,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                ipv6_addr_copy(&fl.fl6_dst, &req->af.v6_req.rmt_addr);
                if (opt && opt->srcrt) {
                        struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+                       ipv6_addr_copy(&final, &fl.fl6_dst);
                        ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+                       final_p = &final;
                }
                ipv6_addr_copy(&fl.fl6_src, &req->af.v6_req.loc_addr);
                fl.oif = sk->sk_bound_dev_if;
@@ -1327,6 +1369,12 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 
                if (ip6_dst_lookup(sk, &dst, &fl))
                        goto out;
+
+               if (final_p)
+                       ipv6_addr_copy(&fl.fl6_dst, final_p);
+
+               if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+                       goto out;
        } 
 
        newsk = tcp_create_openreq_child(sk, req, skb);
@@ -1343,7 +1391,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
 
        newtcp6sk = (struct tcp6_sock *)newsk;
-       newtcp6sk->pinet6 = &newtcp6sk->inet6;
+       inet_sk(newsk)->pinet6 = &newtcp6sk->inet6;
 
        newtp = tcp_sk(newsk);
        newinet = inet_sk(newsk);
@@ -1409,9 +1457,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        return newsk;
 
 out_overflow:
-       NET_INC_STATS_BH(ListenOverflows);
+       NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);
 out:
-       NET_INC_STATS_BH(ListenDrops);
+       NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);
        if (opt && opt != np->opt)
                sock_kfree_s(sk, opt, opt->tot_len);
        dst_release(dst);
@@ -1450,7 +1498,7 @@ static int tcp_v6_checksum_init(struct sk_buff *skb)
 static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct tcp_opt *tp;
+       struct tcp_sock *tp;
        struct sk_buff *opt_skb = NULL;
 
        /* Imagine: socket is IPv6. IPv4 packet arrives,
@@ -1536,7 +1584,7 @@ discard:
        kfree_skb(skb);
        return 0;
 csum_err:
-       TCP_INC_STATS_BH(TcpInErrs);
+       TCP_INC_STATS_BH(TCP_MIB_INERRS);
        goto discard;
 
 
@@ -1582,7 +1630,7 @@ static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
        /*
         *      Count it even if it's bad.
         */
-       TCP_INC_STATS_BH(TcpInSegs);
+       TCP_INC_STATS_BH(TCP_MIB_INSEGS);
 
        if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
                goto discard_it;
@@ -1604,7 +1652,7 @@ static int tcp_v6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
                                    skb->len - th->doff*4);
        TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
        TCP_SKB_CB(skb)->when = 0;
-       TCP_SKB_CB(skb)->flags = ip6_get_dsfield(skb->nh.ipv6h);
+       TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(skb->nh.ipv6h);
        TCP_SKB_CB(skb)->sacked = 0;
 
        sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source,
@@ -1643,7 +1691,7 @@ no_tcp_socket:
 
        if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 bad_packet:
-               TCP_INC_STATS_BH(TcpInErrs);
+               TCP_INC_STATS_BH(TCP_MIB_INERRS);
        } else {
                tcp_v6_send_reset(skb);
        }
@@ -1668,7 +1716,7 @@ do_time_wait:
        }
 
        if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
-               TCP_INC_STATS_BH(TcpInErrs);
+               TCP_INC_STATS_BH(TCP_MIB_INERRS);
                tcp_tw_put((struct tcp_tw_bucket *) sk);
                goto discard_it;
        }
@@ -1707,7 +1755,8 @@ static int tcp_v6_rebuild_header(struct sock *sk)
        dst = __sk_dst_check(sk, np->dst_cookie);
 
        if (dst == NULL) {
-               struct inet_opt *inet = inet_sk(sk);
+               struct inet_sock *inet = inet_sk(sk);
+               struct in6_addr *final_p = NULL, final;
                struct flowi fl;
 
                memset(&fl, 0, sizeof(fl));
@@ -1721,15 +1770,24 @@ static int tcp_v6_rebuild_header(struct sock *sk)
 
                if (np->opt && np->opt->srcrt) {
                        struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+                       ipv6_addr_copy(&final, &fl.fl6_dst);
                        ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+                       final_p = &final;
                }
 
                err = ip6_dst_lookup(sk, &dst, &fl);
-
                if (err) {
                        sk->sk_route_caps = 0;
                        return err;
                }
+               if (final_p)
+                       ipv6_addr_copy(&fl.fl6_dst, final_p);
+
+               if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+                       sk->sk_err_soft = -err;
+                       dst_release(dst);
+                       return err;
+               }
 
                ip6_dst_store(sk, dst, NULL);
                sk->sk_route_caps = dst->dev->features &
@@ -1743,10 +1801,11 @@ static int tcp_v6_rebuild_header(struct sock *sk)
 static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
 {
        struct sock *sk = skb->sk;
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct flowi fl;
        struct dst_entry *dst;
+       struct in6_addr *final_p = NULL, final;
 
        memset(&fl, 0, sizeof(fl));
        fl.proto = IPPROTO_TCP;
@@ -1760,7 +1819,9 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
 
        if (np->opt && np->opt->srcrt) {
                struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+               ipv6_addr_copy(&final, &fl.fl6_dst);
                ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+               final_p = &final;
        }
 
        dst = __sk_dst_check(sk, np->dst_cookie);
@@ -1773,6 +1834,15 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
                        return err;
                }
 
+               if (final_p)
+                       ipv6_addr_copy(&fl.fl6_dst, final_p);
+
+               if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
+                       sk->sk_route_caps = 0;
+                       dst_release(dst);
+                       return err;
+               }
+
                ip6_dst_store(sk, dst, NULL);
                sk->sk_route_caps = dst->dev->features &
                        ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
@@ -1850,7 +1920,7 @@ static struct tcp_func ipv6_mapped = {
  */
 static int tcp_v6_init_sock(struct sock *sk)
 {
-       struct tcp_opt *tp = tcp_sk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
 
        skb_queue_head_init(&tp->out_of_order_queue);
        tcp_init_xmit_timers(sk);
@@ -1871,7 +1941,7 @@ static int tcp_v6_init_sock(struct sock *sk)
         */
        tp->snd_ssthresh = 0x7fffffff;
        tp->snd_cwnd_clamp = ~0;
-       tp->mss_cache = 536;
+       tp->mss_cache_std = tp->mss_cache = 536;
 
        tp->reordering = sysctl_tcp_reordering;
 
@@ -1879,7 +1949,7 @@ static int tcp_v6_init_sock(struct sock *sk)
 
        tp->af_specific = &ipv6_specific;
 
-       sk->sk_write_space = tcp_write_space;
+       sk->sk_write_space = sk_stream_write_space;
        sk->sk_use_write_queue = 1;
 
        sk->sk_sndbuf = sysctl_tcp_wmem[1];
@@ -1892,30 +1962,9 @@ static int tcp_v6_init_sock(struct sock *sk)
 
 static int tcp_v6_destroy_sock(struct sock *sk)
 {
-       struct tcp_opt *tp = tcp_sk(sk);
-       struct inet_opt *inet = inet_sk(sk);
-
-       tcp_clear_xmit_timers(sk);
-
-       /* Cleanup up the write buffer. */
-       tcp_writequeue_purge(sk);
-
-       /* Cleans up our, hopefully empty, out_of_order_queue. */
-       __skb_queue_purge(&tp->out_of_order_queue);
-
-       /* Clean prequeue, it must be empty really */
-       __skb_queue_purge(&tp->ucopy.prequeue);
-
-       /* Clean up a referenced TCP bind bucket. */
-       if (tcp_sk(sk)->bind_hash)
-               tcp_put_port(sk);
-
-       /* If sendmsg cached page exists, toss it. */
-       if (inet->sndmsg_page != NULL)
-               __free_page(inet->sndmsg_page);
-
-       atomic_dec(&tcp_sockets_allocated);
+       extern int tcp_v4_destroy_sock(struct sock *sk);
 
+       tcp_v4_destroy_sock(sk);
        return inet6_destroy_sock(sk);
 }
 
@@ -1933,7 +1982,7 @@ static void get_openreq6(struct seq_file *seq,
        dest = &req->af.v6_req.rmt_addr;
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3],
@@ -1958,8 +2007,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
        __u16 destp, srcp;
        int timer_active;
        unsigned long timer_expires;
-       struct inet_opt *inet = inet_sk(sp);
-       struct tcp_opt *tp = tcp_sk(sp);
+       struct inet_sock *inet = inet_sk(sp);
+       struct tcp_sock *tp = tcp_sk(sp);
        struct ipv6_pinfo *np = inet6_sk(sp);
 
        dest  = &np->daddr;
@@ -2019,7 +2068,7 @@ static void get_timewait6_sock(struct seq_file *seq,
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
@@ -2036,12 +2085,12 @@ static int tcp6_seq_show(struct seq_file *seq, void *v)
        struct tcp_iter_state *st;
 
        if (v == SEQ_START_TOKEN) {
-               seq_printf(seq,
-                          "  sl  "
-                          "local_address                         "
-                          "remote_address                        "
-                          "st tx_queue rx_queue tr tm->when retrnsmt"
-                          "   uid  timeout inode\n");
+               seq_puts(seq,
+                        "  sl  "
+                        "local_address                         "
+                        "remote_address                        "
+                        "st tx_queue rx_queue tr tm->when retrnsmt"
+                        "   uid  timeout inode\n");
                goto out;
        }
        st = seq->private;
@@ -2083,23 +2132,33 @@ void tcp6_proc_exit(void)
 #endif
 
 struct proto tcpv6_prot = {
-       .name           =       "TCPv6",
-       .close          =       tcp_close,
-       .connect        =       tcp_v6_connect,
-       .disconnect     =       tcp_disconnect,
-       .accept         =       tcp_accept,
-       .ioctl          =       tcp_ioctl,
-       .init           =       tcp_v6_init_sock,
-       .destroy        =       tcp_v6_destroy_sock,
-       .shutdown       =       tcp_shutdown,
-       .setsockopt     =       tcp_setsockopt,
-       .getsockopt     =       tcp_getsockopt,
-       .sendmsg        =       tcp_sendmsg,
-       .recvmsg        =       tcp_recvmsg,
-       .backlog_rcv    =       tcp_v6_do_rcv,
-       .hash           =       tcp_v6_hash,
-       .unhash         =       tcp_unhash,
-       .get_port       =       tcp_v6_get_port,
+       .name                   = "TCPv6",
+       .owner                  = THIS_MODULE,
+       .close                  = tcp_close,
+       .connect                = tcp_v6_connect,
+       .disconnect             = tcp_disconnect,
+       .accept                 = tcp_accept,
+       .ioctl                  = tcp_ioctl,
+       .init                   = tcp_v6_init_sock,
+       .destroy                = tcp_v6_destroy_sock,
+       .shutdown               = tcp_shutdown,
+       .setsockopt             = tcp_setsockopt,
+       .getsockopt             = tcp_getsockopt,
+       .sendmsg                = tcp_sendmsg,
+       .recvmsg                = tcp_recvmsg,
+       .backlog_rcv            = tcp_v6_do_rcv,
+       .hash                   = tcp_v6_hash,
+       .unhash                 = tcp_unhash,
+       .get_port               = tcp_v6_get_port,
+       .enter_memory_pressure  = tcp_enter_memory_pressure,
+       .sockets_allocated      = &tcp_sockets_allocated,
+       .memory_allocated       = &tcp_memory_allocated,
+       .memory_pressure        = &tcp_memory_pressure,
+       .sysctl_mem             = sysctl_tcp_mem,
+       .sysctl_wmem            = sysctl_tcp_wmem,
+       .sysctl_rmem            = sysctl_tcp_rmem,
+       .max_header             = MAX_TCP_HEADER,
+       .slab_obj_size          = sizeof(struct tcp6_sock),
 };
 
 static struct inet6_protocol tcpv6_protocol = {