X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv6%2Ftcp_ipv6.c;h=fa13a74492abdab39b4837c1efac1c1d4c8511e1;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=2949cd143b40126dfc053868daf620c980c967b3;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2949cd143..fa13a7449 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -51,9 +51,13 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include @@ -479,7 +483,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 +498,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,8 +540,7 @@ 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, @@ -547,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; @@ -664,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; @@ -734,7 +745,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 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 +756,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 +765,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; } @@ -791,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); @@ -822,7 +839,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 +850,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 +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; @@ -879,19 +897,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 +956,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 +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)); @@ -1019,9 +1044,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 +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); @@ -1080,8 +1112,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; } @@ -1183,7 +1219,7 @@ 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(); @@ -1233,7 +1269,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 */ } @@ -1300,17 +1336,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 +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; @@ -1327,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); @@ -1409,9 +1454,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); @@ -1536,7 +1581,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 +1627,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 +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, @@ -1643,7 +1688,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 +1713,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; } @@ -1708,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)); @@ -1721,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 & @@ -1773,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); @@ -1871,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; @@ -1879,7 +1940,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 +1953,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 +1973,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], @@ -2019,7 +2059,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 +2076,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 +2123,32 @@ 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", + .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 = {