X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv6%2Ftcp_ipv6.c;h=fa13a74492abdab39b4837c1efac1c1d4c8511e1;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=5a19b3d7572055404705672f906dbc7741b130a9;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5a19b3d75..fa13a7449 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -57,6 +57,7 @@ #include #include #include +#include #include @@ -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 = {