vserver 1.9.3
[linux-2.6.git] / net / ipv6 / tcp_ipv6.c
index 5a19b3d..fa13a74 100644 (file)
@@ -57,6 +57,7 @@
 #include <net/xfrm.h>
 #include <net/addrconf.h>
 #include <net/snmp.h>
+#include <net/dsfield.h>
 
 #include <asm/uaccess.h>
 
@@ -549,7 +550,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
        struct inet_opt *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct tcp_opt *tp = tcp_sk(sk);
-       struct in6_addr *saddr = NULL;
+       struct in6_addr *saddr = NULL, *final_p = NULL, final;
        struct flowi fl;
        struct dst_entry *dst;
        int addr_type;
@@ -666,13 +667,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;
@@ -793,6 +802,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);
 
@@ -863,6 +878,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;
 
@@ -888,12 +904,18 @@ static int tcp_v6_send_synack(struct sock *sk, struct open_request *req,
 
                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);
@@ -981,11 +1003,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));
 
@@ -1021,6 +1044,12 @@ 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(TCP_MIB_OUTSEGS);
                TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
@@ -1037,14 +1066,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);
 
@@ -1082,6 +1112,10 @@ 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(TCP_MIB_OUTSEGS);
                return;
@@ -1313,6 +1347,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        }
 
        if (dst == NULL) {
+               struct in6_addr *final_p = NULL, final;
                struct flowi fl;
 
                memset(&fl, 0, sizeof(fl));
@@ -1320,7 +1355,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;
@@ -1329,6 +1366,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);
@@ -1606,7 +1649,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,
@@ -1710,6 +1753,7 @@ static int tcp_v6_rebuild_header(struct sock *sk)
 
        if (dst == NULL) {
                struct inet_opt *inet = inet_sk(sk);
+               struct in6_addr *final_p = NULL, final;
                struct flowi fl;
 
                memset(&fl, 0, sizeof(fl));
@@ -1723,15 +1767,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 &
@@ -1775,6 +1828,12 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok)
                        return err;
                }
 
+               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);
@@ -1873,7 +1932,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;
 
@@ -2089,6 +2148,7 @@ struct proto tcpv6_prot = {
        .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 = {