diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 305 | 
1 files changed, 168 insertions, 137 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5c71501fc91..229239ad96b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -39,7 +39,7 @@  #include <linux/ipsec.h>  #include <linux/times.h>  #include <linux/slab.h> - +#include <linux/uaccess.h>  #include <linux/ipv6.h>  #include <linux/icmpv6.h>  #include <linux/random.h> @@ -65,8 +65,6 @@  #include <net/tcp_memcontrol.h>  #include <net/busy_poll.h> -#include <asm/uaccess.h> -  #include <linux/proc_fs.h>  #include <linux/seq_file.h> @@ -156,7 +154,6 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);  			if (flowlabel == NULL)  				return -EINVAL; -			usin->sin6_addr = flowlabel->dst;  			fl6_sock_release(flowlabel);  		}  	} @@ -165,12 +162,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	 *	connect() to INADDR_ANY means loopback (BSD'ism).  	 */ -	if(ipv6_addr_any(&usin->sin6_addr)) +	if (ipv6_addr_any(&usin->sin6_addr))  		usin->sin6_addr.s6_addr[15] = 0x1;  	addr_type = ipv6_addr_type(&usin->sin6_addr); -	if(addr_type & IPV6_ADDR_MULTICAST) +	if (addr_type & IPV6_ADDR_MULTICAST)  		return -ENETUNREACH;  	if (addr_type&IPV6_ADDR_LINKLOCAL) { @@ -192,13 +189,13 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	}  	if (tp->rx_opt.ts_recent_stamp && -	    !ipv6_addr_equal(&np->daddr, &usin->sin6_addr)) { +	    !ipv6_addr_equal(&sk->sk_v6_daddr, &usin->sin6_addr)) {  		tp->rx_opt.ts_recent = 0;  		tp->rx_opt.ts_recent_stamp = 0;  		tp->write_seq = 0;  	} -	np->daddr = usin->sin6_addr; +	sk->sk_v6_daddr = usin->sin6_addr;  	np->flow_label = fl6.flowlabel;  	/* @@ -237,17 +234,17 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  		} else {  			ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr);  			ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, -					       &np->rcv_saddr); +					       &sk->sk_v6_rcv_saddr);  		}  		return err;  	} -	if (!ipv6_addr_any(&np->rcv_saddr)) -		saddr = &np->rcv_saddr; +	if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) +		saddr = &sk->sk_v6_rcv_saddr;  	fl6.flowi6_proto = IPPROTO_TCP; -	fl6.daddr = np->daddr; +	fl6.daddr = sk->sk_v6_daddr;  	fl6.saddr = saddr ? *saddr : np->saddr;  	fl6.flowi6_oif = sk->sk_bound_dev_if;  	fl6.flowi6_mark = sk->sk_mark; @@ -258,7 +255,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); -	dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); +	dst = ip6_dst_lookup_flow(sk, &fl6, final_p);  	if (IS_ERR(dst)) {  		err = PTR_ERR(dst);  		goto failure; @@ -266,7 +263,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	if (saddr == NULL) {  		saddr = &fl6.saddr; -		np->rcv_saddr = *saddr; +		sk->sk_v6_rcv_saddr = *saddr;  	}  	/* set the source address */ @@ -279,7 +276,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	rt = (struct rt6_info *) dst;  	if (tcp_death_row.sysctl_tw_recycle &&  	    !tp->rx_opt.ts_recent_stamp && -	    ipv6_addr_equal(&rt->rt6i_dst.addr, &np->daddr)) +	    ipv6_addr_equal(&rt->rt6i_dst.addr, &sk->sk_v6_daddr))  		tcp_fetch_timewait_stamp(sk, dst);  	icsk->icsk_ext_hdr_len = 0; @@ -298,7 +295,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  	if (!tp->write_seq && likely(!tp->repair))  		tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, -							     np->daddr.s6_addr32, +							     sk->sk_v6_daddr.s6_addr32,  							     inet->inet_sport,  							     inet->inet_dport); @@ -337,13 +334,14 @@ static void tcp_v6_mtu_reduced(struct sock *sk)  static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  		u8 type, u8 code, int offset, __be32 info)  { -	const struct ipv6hdr *hdr = (const struct ipv6hdr*)skb->data; +	const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;  	const struct tcphdr *th = (struct tcphdr *)(skb->data+offset);  	struct ipv6_pinfo *np;  	struct sock *sk;  	int err;  	struct tcp_sock *tp; -	__u32 seq; +	struct request_sock *fastopen; +	__u32 seq, snd_una;  	struct net *net = dev_net(skb->dev);  	sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr, @@ -374,8 +372,11 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  	tp = tcp_sk(sk);  	seq = ntohl(th->seq); +	/* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ +	fastopen = tp->fastopen_rsk; +	snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una;  	if (sk->sk_state != TCP_LISTEN && -	    !between(seq, tp->snd_una, tp->snd_nxt)) { +	    !between(seq, snd_una, tp->snd_nxt)) {  		NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);  		goto out;  	} @@ -398,6 +399,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  		if (sk->sk_state == TCP_LISTEN)  			goto out; +		if (!ip6_sk_accept_pmtu(sk)) +			goto out; +  		tp->mtu_info = ntohl(info);  		if (!sock_owned_by_user(sk))  			tcp_v6_mtu_reduced(sk); @@ -436,8 +440,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,  		goto out;  	case TCP_SYN_SENT: -	case TCP_SYN_RECV:  /* Cannot happen. -			       It can, it SYNs are crossed. --ANK */ +	case TCP_SYN_RECV: +		/* Only in fast or simultaneous open. If a fast open socket is +		 * is already accepted it is treated as a connected one below. +		 */ +		if (fastopen && fastopen->sk == NULL) +			break; +  		if (!sock_owned_by_user(sk)) {  			sk->sk_err = err;  			sk->sk_error_report(sk);		/* Wake people up to see the error (see connect in sock.c) */ @@ -463,23 +472,28 @@ out:  static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,  			      struct flowi6 *fl6,  			      struct request_sock *req, -			      u16 queue_mapping) +			      u16 queue_mapping, +			      struct tcp_fastopen_cookie *foc)  { -	struct inet6_request_sock *treq = inet6_rsk(req); +	struct inet_request_sock *ireq = inet_rsk(req);  	struct ipv6_pinfo *np = inet6_sk(sk); -	struct sk_buff * skb; +	struct sk_buff *skb;  	int err = -ENOMEM;  	/* First, grab a route. */  	if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)  		goto done; -	skb = tcp_make_synack(sk, dst, req, NULL); +	skb = tcp_make_synack(sk, dst, req, foc);  	if (skb) { -		__tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); +		__tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, +				    &ireq->ir_v6_rmt_addr); + +		fl6->daddr = ireq->ir_v6_rmt_addr; +		if (np->repflow && (ireq->pktopts != NULL)) +			fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); -		fl6->daddr = treq->rmt_addr;  		skb_set_queue_mapping(skb, queue_mapping);  		err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);  		err = net_xmit_eval(err); @@ -494,15 +508,17 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req)  	struct flowi6 fl6;  	int res; -	res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0); -	if (!res) +	res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0, NULL); +	if (!res) {  		TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); +		NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); +	}  	return res;  }  static void tcp_v6_reqsk_destructor(struct request_sock *req)  { -	kfree_skb(inet6_rsk(req)->pktopts); +	kfree_skb(inet_rsk(req)->pktopts);  }  #ifdef CONFIG_TCP_MD5SIG @@ -515,17 +531,17 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,  static struct tcp_md5sig_key *tcp_v6_md5_lookup(struct sock *sk,  						struct sock *addr_sk)  { -	return tcp_v6_md5_do_lookup(sk, &inet6_sk(addr_sk)->daddr); +	return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr);  }  static struct tcp_md5sig_key *tcp_v6_reqsk_md5_lookup(struct sock *sk,  						      struct request_sock *req)  { -	return tcp_v6_md5_do_lookup(sk, &inet6_rsk(req)->rmt_addr); +	return tcp_v6_md5_do_lookup(sk, &inet_rsk(req)->ir_v6_rmt_addr);  } -static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, -				  int optlen) +static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval, +				 int optlen)  {  	struct tcp_md5sig cmd;  	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; @@ -621,10 +637,10 @@ static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,  	if (sk) {  		saddr = &inet6_sk(sk)->saddr; -		daddr = &inet6_sk(sk)->daddr; +		daddr = &sk->sk_v6_daddr;  	} else if (req) { -		saddr = &inet6_rsk(req)->loc_addr; -		daddr = &inet6_rsk(req)->rmt_addr; +		saddr = &inet_rsk(req)->ir_v6_loc_addr; +		daddr = &inet_rsk(req)->ir_v6_rmt_addr;  	} else {  		const struct ipv6hdr *ip6h = ipv6_hdr(skb);  		saddr = &ip6h->saddr; @@ -709,7 +725,7 @@ struct request_sock_ops tcp6_request_sock_ops __read_mostly = {  	.send_ack	=	tcp_v6_reqsk_send_ack,  	.destructor	=	tcp_v6_reqsk_destructor,  	.send_reset	=	tcp_v6_send_reset, -	.syn_ack_timeout = 	tcp_syn_ack_timeout, +	.syn_ack_timeout =	tcp_syn_ack_timeout,  };  #ifdef CONFIG_TCP_MD5SIG @@ -720,8 +736,9 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {  #endif  static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, -				 u32 tsval, u32 tsecr, -				 struct tcp_md5sig_key *key, int rst, u8 tclass) +				 u32 tsval, u32 tsecr, int oif, +				 struct tcp_md5sig_key *key, int rst, u8 tclass, +				 u32 label)  {  	const struct tcphdr *th = tcp_hdr(skb);  	struct tcphdr *t1; @@ -783,6 +800,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,  	memset(&fl6, 0, sizeof(fl6));  	fl6.daddr = ipv6_hdr(skb)->saddr;  	fl6.saddr = ipv6_hdr(skb)->daddr; +	fl6.flowlabel = label;  	buff->ip_summed = CHECKSUM_PARTIAL;  	buff->csum = 0; @@ -790,8 +808,11 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,  	__tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr);  	fl6.flowi6_proto = IPPROTO_TCP; -	if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) +	if (rt6_need_strict(&fl6.daddr) && !oif)  		fl6.flowi6_oif = inet6_iif(skb); +	else +		fl6.flowi6_oif = oif; +	fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);  	fl6.fl6_dport = t1->dest;  	fl6.fl6_sport = t1->source;  	security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); @@ -800,7 +821,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,  	 * Underlying function will use this to retrieve the network  	 * namespace  	 */ -	dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL, false); +	dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);  	if (!IS_ERR(dst)) {  		skb_dst_set(buff, dst);  		ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass); @@ -825,6 +846,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)  	int genhash;  	struct sock *sk1 = NULL;  #endif +	int oif;  	if (th->rst)  		return; @@ -868,7 +890,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)  		ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len -  			  (th->doff << 2); -	tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, key, 1, 0); +	oif = sk ? sk->sk_bound_dev_if : 0; +	tcp_v6_send_response(skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0);  #ifdef CONFIG_TCP_MD5SIG  release_sk1: @@ -880,10 +903,12 @@ release_sk1:  }  static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, -			    u32 win, u32 tsval, u32 tsecr, -			    struct tcp_md5sig_key *key, u8 tclass) +			    u32 win, u32 tsval, u32 tsecr, int oif, +			    struct tcp_md5sig_key *key, u8 tclass, +			    u32 label)  { -	tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, key, 0, tclass); +	tcp_v6_send_response(skb, seq, ack, win, tsval, tsecr, oif, key, 0, tclass, +			     label);  }  static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) @@ -894,8 +919,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)  	tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,  			tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,  			tcp_time_stamp + tcptw->tw_ts_offset, -			tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw), -			tw->tw_tclass); +			tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), +			tw->tw_tclass, (tw->tw_flowlabel << 12));  	inet_twsk_put(tw);  } @@ -903,13 +928,19 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)  static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,  				  struct request_sock *req)  { -	tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, -			req->rcv_wnd, tcp_time_stamp, req->ts_recent, -			tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), 0); +	/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV +	 * sk->sk_state == TCP_SYN_RECV -> for Fast Open. +	 */ +	tcp_v6_send_ack(skb, (sk->sk_state == TCP_LISTEN) ? +			tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, +			tcp_rsk(req)->rcv_nxt, +			req->rcv_wnd, tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if, +			tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), +			0, 0);  } -static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) +static struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)  {  	struct request_sock *req, **prev;  	const struct tcphdr *th = tcp_hdr(skb); @@ -949,13 +980,15 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)  {  	struct tcp_options_received tmp_opt;  	struct request_sock *req; -	struct inet6_request_sock *treq; +	struct inet_request_sock *ireq;  	struct ipv6_pinfo *np = inet6_sk(sk);  	struct tcp_sock *tp = tcp_sk(sk);  	__u32 isn = TCP_SKB_CB(skb)->when;  	struct dst_entry *dst = NULL; +	struct tcp_fastopen_cookie foc = { .len = -1 }; +	bool want_cookie = false, fastopen;  	struct flowi6 fl6; -	bool want_cookie = false; +	int err;  	if (skb->protocol == htons(ETH_P_IP))  		return tcp_v4_conn_request(sk, skb); @@ -986,7 +1019,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)  	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, &tmp_opt, 0, NULL); +	tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc);  	if (want_cookie && !tmp_opt.saw_tstamp)  		tcp_clear_options(&tmp_opt); @@ -994,25 +1027,27 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)  	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;  	tcp_openreq_init(req, &tmp_opt, skb); -	treq = inet6_rsk(req); -	treq->rmt_addr = ipv6_hdr(skb)->saddr; -	treq->loc_addr = ipv6_hdr(skb)->daddr; +	ireq = inet_rsk(req); +	ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; +	ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr;  	if (!want_cookie || tmp_opt.tstamp_ok)  		TCP_ECN_create_request(req, skb, sock_net(sk)); -	treq->iif = sk->sk_bound_dev_if; +	ireq->ir_iif = sk->sk_bound_dev_if; +	ireq->ir_mark = inet_request_mark(sk, skb);  	/* So that link locals have meaning */  	if (!sk->sk_bound_dev_if && -	    ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) -		treq->iif = inet6_iif(skb); +	    ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) +		ireq->ir_iif = inet6_iif(skb);  	if (!isn) {  		if (ipv6_opt_accepted(sk, skb) ||  		    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || -		    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { +		    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim || +		    np->repflow) {  			atomic_inc(&skb->users); -			treq->pktopts = skb; +			ireq->pktopts = skb;  		}  		if (want_cookie) { @@ -1051,26 +1086,34 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)  			 * to the moment of synflood.  			 */  			LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI6/%u\n", -				       &treq->rmt_addr, ntohs(tcp_hdr(skb)->source)); +				       &ireq->ir_v6_rmt_addr, ntohs(tcp_hdr(skb)->source));  			goto drop_and_release;  		}  		isn = tcp_v6_init_sequence(skb);  	}  have_isn: -	tcp_rsk(req)->snt_isn = isn;  	if (security_inet_conn_request(sk, skb, req))  		goto drop_and_release; -	if (tcp_v6_send_synack(sk, dst, &fl6, req, -			       skb_get_queue_mapping(skb)) || -	    want_cookie) +	if (!dst && (dst = inet6_csk_route_req(sk, &fl6, req)) == NULL)  		goto drop_and_free; +	tcp_rsk(req)->snt_isn = isn;  	tcp_rsk(req)->snt_synack = tcp_time_stamp; -	tcp_rsk(req)->listener = NULL; -	inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); +	tcp_openreq_init_rwin(req, sk, dst); +	fastopen = !want_cookie && +		   tcp_try_fastopen(sk, skb, req, &foc, dst); +	err = tcp_v6_send_synack(sk, dst, &fl6, req, +				 skb_get_queue_mapping(skb), &foc); +	if (!fastopen) { +		if (err || want_cookie) +			goto drop_and_free; + +		tcp_rsk(req)->listener = NULL; +		inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); +	}  	return 0;  drop_and_release: @@ -1082,11 +1125,11 @@ drop:  	return 0; /* don't send reset */  } -static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, -					  struct request_sock *req, -					  struct dst_entry *dst) +static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, +					 struct request_sock *req, +					 struct dst_entry *dst)  { -	struct inet6_request_sock *treq; +	struct inet_request_sock *ireq;  	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);  	struct tcp6_sock *newtcp6sk;  	struct inet_sock *newinet; @@ -1116,11 +1159,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  		memcpy(newnp, np, sizeof(struct ipv6_pinfo)); -		ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr); +		ipv6_addr_set_v4mapped(newinet->inet_daddr, &newsk->sk_v6_daddr);  		ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); -		newnp->rcv_saddr = newnp->saddr; +		newsk->sk_v6_rcv_saddr = newnp->saddr;  		inet_csk(newsk)->icsk_af_ops = &ipv6_mapped;  		newsk->sk_backlog_rcv = tcp_v4_do_rcv; @@ -1134,7 +1177,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  		newnp->opt	   = NULL;  		newnp->mcast_oif   = inet6_iif(skb);  		newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit; -		newnp->rcv_tclass  = ipv6_get_dsfield(ipv6_hdr(skb)); +		newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); +		if (np->repflow) +			newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));  		/*  		 * No need to charge this sock to the relevant IPv6 refcnt debug socks count @@ -1151,7 +1196,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  		return newsk;  	} -	treq = inet6_rsk(req); +	ireq = inet_rsk(req);  	if (sk_acceptq_is_full(sk))  		goto out_overflow; @@ -1185,10 +1230,10 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  	memcpy(newnp, np, sizeof(struct ipv6_pinfo)); -	newnp->daddr = treq->rmt_addr; -	newnp->saddr = treq->loc_addr; -	newnp->rcv_saddr = treq->loc_addr; -	newsk->sk_bound_dev_if = treq->iif; +	newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr; +	newnp->saddr = ireq->ir_v6_loc_addr; +	newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; +	newsk->sk_bound_dev_if = ireq->ir_iif;  	/* Now IPv6 options... @@ -1203,18 +1248,20 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  	/* Clone pktoptions received with SYN */  	newnp->pktoptions = NULL; -	if (treq->pktopts != NULL) { -		newnp->pktoptions = skb_clone(treq->pktopts, +	if (ireq->pktopts != NULL) { +		newnp->pktoptions = skb_clone(ireq->pktopts,  					      sk_gfp_atomic(sk, GFP_ATOMIC)); -		consume_skb(treq->pktopts); -		treq->pktopts = NULL; +		consume_skb(ireq->pktopts); +		ireq->pktopts = NULL;  		if (newnp->pktoptions)  			skb_set_owner_r(newnp->pktoptions, newsk);  	}  	newnp->opt	  = NULL;  	newnp->mcast_oif  = inet6_iif(skb);  	newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; -	newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); +	newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); +	if (np->repflow) +		newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb));  	/* Clone native IPv6 options from listening socket (if any) @@ -1230,7 +1277,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +  						     newnp->opt->opt_flen); -	tcp_mtup_init(newsk);  	tcp_sync_mss(newsk, dst_mtu(dst));  	newtp->advmss = dst_metric_advmss(dst);  	if (tcp_sk(sk)->rx_opt.user_mss && @@ -1244,13 +1290,14 @@ static struct sock * tcp_v6_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_v6_md5_do_lookup(sk, &newnp->daddr)) != NULL) { +	key = tcp_v6_md5_do_lookup(sk, &newsk->sk_v6_daddr); +	if (key != NULL) {  		/* We're using one, so create a matching key  		 * on the newsk structure. If we fail to get  		 * memory, then we end up not copying the key  		 * across. Shucks.  		 */ -		tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newnp->daddr, +		tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr,  			       AF_INET6, key->key, key->keylen,  			       sk_gfp_atomic(sk, GFP_ATOMIC));  	} @@ -1274,26 +1321,6 @@ out:  	return NULL;  } -static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) -{ -	if (skb->ip_summed == CHECKSUM_COMPLETE) { -		if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr, -				  &ipv6_hdr(skb)->daddr, skb->csum)) { -			skb->ip_summed = CHECKSUM_UNNECESSARY; -			return 0; -		} -	} - -	skb->csum = ~csum_unfold(tcp_v6_check(skb->len, -					      &ipv6_hdr(skb)->saddr, -					      &ipv6_hdr(skb)->daddr, 0)); - -	if (skb->len <= 76) { -		return __skb_checksum_complete(skb); -	} -	return 0; -} -  /* The socket must have it's spinlock held when we get   * here.   * @@ -1320,7 +1347,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)  		return tcp_v4_do_rcv(sk, skb);  #ifdef CONFIG_TCP_MD5SIG -	if (tcp_v6_inbound_md5_hash (sk, skb)) +	if (tcp_v6_inbound_md5_hash(sk, skb))  		goto discard;  #endif @@ -1379,7 +1406,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)  		 * otherwise we just shortcircuit this and continue with  		 * the new socket..  		 */ -		if(nsk != sk) { +		if (nsk != sk) {  			sock_rps_save_rxhash(nsk, skb);  			if (tcp_child_process(sk, nsk, skb))  				goto reset; @@ -1424,8 +1451,10 @@ ipv6_pktoptions:  			np->mcast_oif = inet6_iif(opt_skb);  		if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)  			np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; -		if (np->rxopt.bits.rxtclass) -			np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(opt_skb)); +		if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) +			np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); +		if (np->repflow) +			np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));  		if (ipv6_opt_accepted(sk, opt_skb)) {  			skb_set_owner_r(opt_skb, sk);  			opt_skb = xchg(&np->pktoptions, opt_skb); @@ -1465,7 +1494,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)  	if (!pskb_may_pull(skb, th->doff*4))  		goto discard_it; -	if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb)) +	if (skb_checksum_init(skb, IPPROTO_TCP, ip6_compute_pseudo))  		goto csum_error;  	th = tcp_hdr(skb); @@ -1585,7 +1614,8 @@ do_time_wait:  		break;  	case TCP_TW_RST:  		goto no_tcp_socket; -	case TCP_TW_SUCCESS:; +	case TCP_TW_SUCCESS: +		;  	}  	goto discard_it;  } @@ -1630,7 +1660,7 @@ static void tcp_v6_early_demux(struct sk_buff *skb)  static struct timewait_sock_ops tcp6_timewait_sock_ops = {  	.twsk_obj_size	= sizeof(struct tcp6_timewait_sock),  	.twsk_unique	= tcp_twsk_unique, -	.twsk_destructor= tcp_twsk_destructor, +	.twsk_destructor = tcp_twsk_destructor,  };  static const struct inet_connection_sock_af_ops ipv6_specific = { @@ -1664,7 +1694,6 @@ static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {  /*   *	TCP over IPv4 via INET6 API   */ -  static const struct inet_connection_sock_af_ops ipv6_mapped = {  	.queue_xmit	   = ip_queue_xmit,  	.send_check	   = tcp_v4_send_check, @@ -1722,8 +1751,8 @@ static void get_openreq6(struct seq_file *seq,  			 const struct sock *sk, struct request_sock *req, int i, kuid_t uid)  {  	int ttd = req->expires - jiffies; -	const struct in6_addr *src = &inet6_rsk(req)->loc_addr; -	const struct in6_addr *dest = &inet6_rsk(req)->rmt_addr; +	const struct in6_addr *src = &inet_rsk(req)->ir_v6_loc_addr; +	const struct in6_addr *dest = &inet_rsk(req)->ir_v6_rmt_addr;  	if (ttd < 0)  		ttd = 0; @@ -1734,12 +1763,12 @@ static void get_openreq6(struct seq_file *seq,  		   i,  		   src->s6_addr32[0], src->s6_addr32[1],  		   src->s6_addr32[2], src->s6_addr32[3], -		   ntohs(inet_rsk(req)->loc_port), +		   inet_rsk(req)->ir_num,  		   dest->s6_addr32[0], dest->s6_addr32[1],  		   dest->s6_addr32[2], dest->s6_addr32[3], -		   ntohs(inet_rsk(req)->rmt_port), +		   ntohs(inet_rsk(req)->ir_rmt_port),  		   TCP_SYN_RECV, -		   0,0, /* could print option size, but that is af dependent. */ +		   0, 0, /* could print option size, but that is af dependent. */  		   1,   /* timers active (only the expire timer) */  		   jiffies_to_clock_t(ttd),  		   req->num_timeout, @@ -1758,10 +1787,10 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)  	const struct inet_sock *inet = inet_sk(sp);  	const struct tcp_sock *tp = tcp_sk(sp);  	const struct inet_connection_sock *icsk = inet_csk(sp); -	const struct ipv6_pinfo *np = inet6_sk(sp); +	struct fastopen_queue *fastopenq = icsk->icsk_accept_queue.fastopenq; -	dest  = &np->daddr; -	src   = &np->rcv_saddr; +	dest  = &sp->sk_v6_daddr; +	src   = &sp->sk_v6_rcv_saddr;  	destp = ntohs(inet->inet_dport);  	srcp  = ntohs(inet->inet_sport); @@ -1799,9 +1828,11 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)  		   atomic_read(&sp->sk_refcnt), sp,  		   jiffies_to_clock_t(icsk->icsk_rto),  		   jiffies_to_clock_t(icsk->icsk_ack.ato), -		   (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong, +		   (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,  		   tp->snd_cwnd, -		   tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh +		   sp->sk_state == TCP_LISTEN ? +			(fastopenq ? fastopenq->max_qlen : 0) : +			(tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh)  		   );  } @@ -1810,11 +1841,10 @@ static void get_timewait6_sock(struct seq_file *seq,  {  	const struct in6_addr *dest, *src;  	__u16 destp, srcp; -	const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw); -	long delta = tw->tw_ttd - jiffies; +	s32 delta = tw->tw_ttd - inet_tw_time_stamp(); -	dest = &tw6->tw_v6_daddr; -	src  = &tw6->tw_v6_rcv_saddr; +	dest = &tw->tw_v6_daddr; +	src  = &tw->tw_v6_rcv_saddr;  	destp = ntohs(tw->tw_dport);  	srcp  = ntohs(tw->tw_sport); @@ -1834,6 +1864,7 @@ static void get_timewait6_sock(struct seq_file *seq,  static int tcp6_seq_show(struct seq_file *seq, void *v)  {  	struct tcp_iter_state *st; +	struct sock *sk = v;  	if (v == SEQ_START_TOKEN) {  		seq_puts(seq, @@ -1849,14 +1880,14 @@ static int tcp6_seq_show(struct seq_file *seq, void *v)  	switch (st->state) {  	case TCP_SEQ_STATE_LISTENING:  	case TCP_SEQ_STATE_ESTABLISHED: -		get_tcp6_sock(seq, v, st->num); +		if (sk->sk_state == TCP_TIME_WAIT) +			get_timewait6_sock(seq, v, st->num); +		else +			get_tcp6_sock(seq, v, st->num);  		break;  	case TCP_SEQ_STATE_OPENREQ:  		get_openreq6(seq, st->syn_wait_sk, v, st->num, st->uid);  		break; -	case TCP_SEQ_STATE_TIME_WAIT: -		get_timewait6_sock(seq, v, st->num); -		break;  	}  out:  	return 0; @@ -1929,6 +1960,7 @@ struct proto tcpv6_prot = {  	.memory_allocated	= &tcp_memory_allocated,  	.memory_pressure	= &tcp_memory_pressure,  	.orphan_count		= &tcp_orphan_count, +	.sysctl_mem		= sysctl_tcp_mem,  	.sysctl_wmem		= sysctl_tcp_wmem,  	.sysctl_rmem		= sysctl_tcp_rmem,  	.max_header		= MAX_TCP_HEADER, @@ -1960,7 +1992,6 @@ static struct inet_protosw tcpv6_protosw = {  	.protocol	=	IPPROTO_TCP,  	.prot		=	&tcpv6_prot,  	.ops		=	&inet6_stream_ops, -	.no_check	=	0,  	.flags		=	INET_PROTOSW_PERMANENT |  				INET_PROTOSW_ICSK,  };  | 
