diff options
| author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2015-11-23 09:04:05 +0100 | 
|---|---|---|
| committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2015-11-23 09:04:05 +0100 | 
| commit | 92907cbbef8625bb3998d1eb385fc88f23c97a3f (patch) | |
| tree | 15626ff9287e37c3cb81c7286d6db5a7fd77c854 /net/ipv4/tcp_ipv4.c | |
| parent | 15fbfccfe92c62ae8d1ecc647c44157ed01ac02e (diff) | |
| parent | 1ec218373b8ebda821aec00bb156a9c94fad9cd4 (diff) | |
Merge tag 'v4.4-rc2' into drm-intel-next-queued
Linux 4.4-rc2
Backmerge to get at
commit 1b0e3a049efe471c399674fd954500ce97438d30
Author: Imre Deak <imre.deak@intel.com>
Date:   Thu Nov 5 23:04:11 2015 +0200
    drm/i915/skl: disable display side power well support for now
so that we can proplery re-eanble skl power wells in -next.
Conflicts are just adjacent lines changed, except for intel_fbdev.c
where we need to interleave the changs. Nothing nefarious.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 219 | 
1 files changed, 91 insertions, 128 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 93898e093d4e..ba09016d1bfd 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -324,7 +324,6 @@ void tcp_req_err(struct sock *sk, u32 seq)  	if (seq != tcp_rsk(req)->snt_isn) {  		NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); -		reqsk_put(req);  	} else {  		/*  		 * Still in SYN_RECV, just remove it silently. @@ -332,9 +331,10 @@ void tcp_req_err(struct sock *sk, u32 seq)  		 * created socket, and POSIX does not want network  		 * errors returned from accept().  		 */ -		NET_INC_STATS_BH(net, LINUX_MIB_LISTENDROPS);  		inet_csk_reqsk_queue_drop(req->rsk_listener, req); +		NET_INC_STATS_BH(net, LINUX_MIB_LISTENDROPS);  	} +	reqsk_put(req);  }  EXPORT_SYMBOL(tcp_req_err); @@ -576,7 +576,7 @@ EXPORT_SYMBOL(tcp_v4_send_check);   *	Exception: precedence violation. We do not implement it in any case.   */ -static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) +static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)  {  	const struct tcphdr *th = tcp_hdr(skb);  	struct { @@ -795,7 +795,7 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)  	inet_twsk_put(tw);  } -static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, +static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,  				  struct request_sock *req)  {  	/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV @@ -803,7 +803,7 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,  	 */  	tcp_v4_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_rsk(req)->rcv_nxt, req->rsk_rcv_wnd,  			tcp_time_stamp,  			req->ts_recent,  			0, @@ -818,11 +818,11 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,   *	This still operates on a request_sock only, not on a big   *	socket.   */ -static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, +static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,  			      struct flowi *fl,  			      struct request_sock *req, -			      u16 queue_mapping, -			      struct tcp_fastopen_cookie *foc) +			      struct tcp_fastopen_cookie *foc, +				  bool attach_req)  {  	const struct inet_request_sock *ireq = inet_rsk(req);  	struct flowi4 fl4; @@ -833,12 +833,11 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,  	if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)  		return -1; -	skb = tcp_make_synack(sk, dst, req, foc); +	skb = tcp_make_synack(sk, dst, req, foc, attach_req);  	if (skb) {  		__tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); -		skb_set_queue_mapping(skb, queue_mapping);  		err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr,  					    ireq->ir_rmt_addr,  					    ireq->opt); @@ -865,7 +864,7 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req)   */  /* Find the Key structure for an address.  */ -struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk, +struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk,  					 const union tcp_md5_addr *addr,  					 int family)  { @@ -877,7 +876,7 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,  	/* caller either holds rcu_read_lock() or socket lock */  	md5sig = rcu_dereference_check(tp->md5sig_info,  				       sock_owned_by_user(sk) || -				       lockdep_is_held(&sk->sk_lock.slock)); +				       lockdep_is_held((spinlock_t *)&sk->sk_lock.slock));  	if (!md5sig)  		return NULL;  #if IS_ENABLED(CONFIG_IPV6) @@ -894,7 +893,7 @@ struct tcp_md5sig_key *tcp_md5_do_lookup(struct sock *sk,  }  EXPORT_SYMBOL(tcp_md5_do_lookup); -struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, +struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk,  					 const struct sock *addr_sk)  {  	const union tcp_md5_addr *addr; @@ -1112,10 +1111,13 @@ clear_hash_noput:  }  EXPORT_SYMBOL(tcp_v4_md5_hash_skb); +#endif +  /* Called with rcu_read_lock() */ -static bool tcp_v4_inbound_md5_hash(struct sock *sk, +static bool tcp_v4_inbound_md5_hash(const struct sock *sk,  				    const struct sk_buff *skb)  { +#ifdef CONFIG_TCP_MD5SIG  	/*  	 * This gets called for each TCP segment that arrives  	 * so we want to be efficient. @@ -1165,10 +1167,12 @@ static bool tcp_v4_inbound_md5_hash(struct sock *sk,  		return true;  	}  	return false; -}  #endif +	return false; +} -static void tcp_v4_init_req(struct request_sock *req, struct sock *sk_listener, +static void tcp_v4_init_req(struct request_sock *req, +			    const struct sock *sk_listener,  			    struct sk_buff *skb)  {  	struct inet_request_sock *ireq = inet_rsk(req); @@ -1179,7 +1183,8 @@ static void tcp_v4_init_req(struct request_sock *req, struct sock *sk_listener,  	ireq->opt = tcp_v4_save_options(skb);  } -static struct dst_entry *tcp_v4_route_req(struct sock *sk, struct flowi *fl, +static struct dst_entry *tcp_v4_route_req(const struct sock *sk, +					  struct flowi *fl,  					  const struct request_sock *req,  					  bool *strict)  { @@ -1218,7 +1223,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {  	.route_req	=	tcp_v4_route_req,  	.init_seq	=	tcp_v4_init_sequence,  	.send_synack	=	tcp_v4_send_synack, -	.queue_hash_add =	inet_csk_reqsk_queue_hash_add,  };  int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) @@ -1241,9 +1245,11 @@ EXPORT_SYMBOL(tcp_v4_conn_request);   * The three way handshake has completed - we got a valid synack -   * now create the new socket.   */ -struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, +struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,  				  struct request_sock *req, -				  struct dst_entry *dst) +				  struct dst_entry *dst, +				  struct request_sock *req_unhash, +				  bool *own_req)  {  	struct inet_request_sock *ireq;  	struct inet_sock *newinet; @@ -1277,7 +1283,6 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  	newinet->mc_ttl	      = ip_hdr(skb)->ttl;  	newinet->rcv_tos      = ip_hdr(skb)->tos;  	inet_csk(newsk)->icsk_ext_hdr_len = 0; -	sk_set_txhash(newsk);  	if (inet_opt)  		inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen;  	newinet->inet_id = newtp->write_seq ^ jiffies; @@ -1320,7 +1325,9 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,  	if (__inet_inherit_port(sk, newsk) < 0)  		goto put_and_exit; -	__inet_hash_nolisten(newsk, NULL); +	*own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); +	if (*own_req) +		tcp_move_syn(newtp, req);  	return newsk; @@ -1338,34 +1345,11 @@ put_and_exit:  }  EXPORT_SYMBOL(tcp_v4_syn_recv_sock); -static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) +static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb)  { +#ifdef CONFIG_SYN_COOKIES  	const struct tcphdr *th = tcp_hdr(skb); -	const struct iphdr *iph = ip_hdr(skb); -	struct request_sock *req; -	struct sock *nsk; - -	req = inet_csk_search_req(sk, th->source, iph->saddr, iph->daddr); -	if (req) { -		nsk = tcp_check_req(sk, skb, req, false); -		if (!nsk || nsk == sk) -			reqsk_put(req); -		return nsk; -	} - -	nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr, -			th->source, iph->daddr, th->dest, inet_iif(skb)); - -	if (nsk) { -		if (nsk->sk_state != TCP_TIME_WAIT) { -			bh_lock_sock(nsk); -			return nsk; -		} -		inet_twsk_put(inet_twsk(nsk)); -		return NULL; -	} -#ifdef CONFIG_SYN_COOKIES  	if (!th->syn)  		sk = cookie_v4_check(sk, skb);  #endif @@ -1373,7 +1357,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)  }  /* The socket must have it's spinlock held when we get - * here. + * here, unless it is a TCP_LISTEN socket.   *   * We have a potential double-lock case here, so even when   * doing backlog processing we use the BH locking scheme. @@ -1404,13 +1388,13 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)  		goto csum_err;  	if (sk->sk_state == TCP_LISTEN) { -		struct sock *nsk = tcp_v4_hnd_req(sk, skb); +		struct sock *nsk = tcp_v4_cookie_check(sk, skb); +  		if (!nsk)  			goto discard; -  		if (nsk != sk) {  			sock_rps_save_rxhash(nsk, skb); -			sk_mark_napi_id(sk, skb); +			sk_mark_napi_id(nsk, skb);  			if (tcp_child_process(sk, nsk, skb)) {  				rsk = nsk;  				goto reset; @@ -1420,7 +1404,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)  	} else  		sock_rps_save_rxhash(sk, skb); -	if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) { +	if (tcp_rcv_state_process(sk, skb)) {  		rsk = sk;  		goto reset;  	} @@ -1590,6 +1574,7 @@ int tcp_v4_rcv(struct sk_buff *skb)  	TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);  	TCP_SKB_CB(skb)->sacked	 = 0; +lookup:  	sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);  	if (!sk)  		goto no_tcp_socket; @@ -1598,6 +1583,33 @@ process:  	if (sk->sk_state == TCP_TIME_WAIT)  		goto do_time_wait; +	if (sk->sk_state == TCP_NEW_SYN_RECV) { +		struct request_sock *req = inet_reqsk(sk); +		struct sock *nsk = NULL; + +		sk = req->rsk_listener; +		if (tcp_v4_inbound_md5_hash(sk, skb)) +			goto discard_and_relse; +		if (likely(sk->sk_state == TCP_LISTEN)) { +			nsk = tcp_check_req(sk, skb, req, false); +		} else { +			inet_csk_reqsk_queue_drop_and_put(sk, req); +			goto lookup; +		} +		if (!nsk) { +			reqsk_put(req); +			goto discard_it; +		} +		if (nsk == sk) { +			sock_hold(sk); +			reqsk_put(req); +		} else if (tcp_child_process(sk, nsk, skb)) { +			tcp_v4_send_reset(nsk, skb); +			goto discard_it; +		} else { +			return 0; +		} +	}  	if (unlikely(iph->ttl < inet_sk(sk)->min_ttl)) {  		NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);  		goto discard_and_relse; @@ -1606,25 +1618,23 @@ process:  	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))  		goto discard_and_relse; -#ifdef CONFIG_TCP_MD5SIG -	/* -	 * We really want to reject the packet as early as possible -	 * if: -	 *  o We're expecting an MD5'd packet and this is no MD5 tcp option -	 *  o There is an MD5 option and we're not expecting one -	 */  	if (tcp_v4_inbound_md5_hash(sk, skb))  		goto discard_and_relse; -#endif  	nf_reset(skb);  	if (sk_filter(sk, skb))  		goto discard_and_relse; -	sk_incoming_cpu_update(sk);  	skb->dev = NULL; +	if (sk->sk_state == TCP_LISTEN) { +		ret = tcp_v4_do_rcv(sk, skb); +		goto put_and_return; +	} + +	sk_incoming_cpu_update(sk); +  	bh_lock_sock_nested(sk);  	tcp_sk(sk)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs);  	ret = 0; @@ -1639,6 +1649,7 @@ process:  	}  	bh_unlock_sock(sk); +put_and_return:  	sock_put(sk);  	return ret; @@ -1833,35 +1844,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)  	++st->num;  	++st->offset; -	if (st->state == TCP_SEQ_STATE_OPENREQ) { -		struct request_sock *req = cur; - -		icsk = inet_csk(st->syn_wait_sk); -		req = req->dl_next; -		while (1) { -			while (req) { -				if (req->rsk_ops->family == st->family) { -					cur = req; -					goto out; -				} -				req = req->dl_next; -			} -			if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries) -				break; -get_req: -			req = icsk->icsk_accept_queue.listen_opt->syn_table[st->sbucket]; -		} -		sk	  = sk_nulls_next(st->syn_wait_sk); -		st->state = TCP_SEQ_STATE_LISTENING; -		spin_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); -	} else { -		icsk = inet_csk(sk); -		spin_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock); -		if (reqsk_queue_len(&icsk->icsk_accept_queue)) -			goto start_req; -		spin_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); -		sk = sk_nulls_next(sk); -	} +	sk = sk_nulls_next(sk);  get_sk:  	sk_nulls_for_each_from(sk, node) {  		if (!net_eq(sock_net(sk), net)) @@ -1871,16 +1854,6 @@ get_sk:  			goto out;  		}  		icsk = inet_csk(sk); -		spin_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock); -		if (reqsk_queue_len(&icsk->icsk_accept_queue)) { -start_req: -			st->uid		= sock_i_uid(sk); -			st->syn_wait_sk = sk; -			st->state	= TCP_SEQ_STATE_OPENREQ; -			st->sbucket	= 0; -			goto get_req; -		} -		spin_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);  	}  	spin_unlock_bh(&ilb->lock);  	st->offset = 0; @@ -2012,7 +1985,6 @@ static void *tcp_seek_last_pos(struct seq_file *seq)  	void *rc = NULL;  	switch (st->state) { -	case TCP_SEQ_STATE_OPENREQ:  	case TCP_SEQ_STATE_LISTENING:  		if (st->bucket >= INET_LHTABLE_SIZE)  			break; @@ -2071,7 +2043,6 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)  	}  	switch (st->state) { -	case TCP_SEQ_STATE_OPENREQ:  	case TCP_SEQ_STATE_LISTENING:  		rc = listening_get_next(seq, v);  		if (!rc) { @@ -2096,11 +2067,6 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)  	struct tcp_iter_state *st = seq->private;  	switch (st->state) { -	case TCP_SEQ_STATE_OPENREQ: -		if (v) { -			struct inet_connection_sock *icsk = inet_csk(st->syn_wait_sk); -			spin_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); -		}  	case TCP_SEQ_STATE_LISTENING:  		if (v != SEQ_START_TOKEN)  			spin_unlock_bh(&tcp_hashinfo.listening_hash[st->bucket].lock); @@ -2154,7 +2120,7 @@ void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)  EXPORT_SYMBOL(tcp_proc_unregister);  static void get_openreq4(const struct request_sock *req, -			 struct seq_file *f, int i, kuid_t uid) +			 struct seq_file *f, int i)  {  	const struct inet_request_sock *ireq = inet_rsk(req);  	long delta = req->rsk_timer.expires - jiffies; @@ -2171,7 +2137,8 @@ static void get_openreq4(const struct request_sock *req,  		1,    /* timers active (only the expire timer) */  		jiffies_delta_to_clock_t(delta),  		req->num_timeout, -		from_kuid_munged(seq_user_ns(f), uid), +		from_kuid_munged(seq_user_ns(f), +				 sock_i_uid(req->rsk_listener)),  		0,  /* non standard timer */  		0, /* open_requests have no inode */  		0, @@ -2185,12 +2152,13 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)  	const struct tcp_sock *tp = tcp_sk(sk);  	const struct inet_connection_sock *icsk = inet_csk(sk);  	const struct inet_sock *inet = inet_sk(sk); -	struct fastopen_queue *fastopenq = icsk->icsk_accept_queue.fastopenq; +	const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq;  	__be32 dest = inet->inet_daddr;  	__be32 src = inet->inet_rcv_saddr;  	__u16 destp = ntohs(inet->inet_dport);  	__u16 srcp = ntohs(inet->inet_sport);  	int rx_queue; +	int state;  	if (icsk->icsk_pending == ICSK_TIME_RETRANS ||  	    icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || @@ -2208,17 +2176,18 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)  		timer_expires = jiffies;  	} -	if (sk->sk_state == TCP_LISTEN) +	state = sk_state_load(sk); +	if (state == TCP_LISTEN)  		rx_queue = sk->sk_ack_backlog;  	else -		/* -		 * because we dont lock socket, we might find a transient negative value +		/* Because we don't lock the socket, +		 * we might find a transient negative value.  		 */  		rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);  	seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "  			"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d", -		i, src, srcp, dest, destp, sk->sk_state, +		i, src, srcp, dest, destp, state,  		tp->write_seq - tp->snd_una,  		rx_queue,  		timer_active, @@ -2232,8 +2201,8 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)  		jiffies_to_clock_t(icsk->icsk_ack.ato),  		(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,  		tp->snd_cwnd, -		sk->sk_state == TCP_LISTEN ? -		    (fastopenq ? fastopenq->max_qlen : 0) : +		state == TCP_LISTEN ? +		    fastopenq->max_qlen :  		    (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh));  } @@ -2272,18 +2241,12 @@ static int tcp4_seq_show(struct seq_file *seq, void *v)  	}  	st = seq->private; -	switch (st->state) { -	case TCP_SEQ_STATE_LISTENING: -	case TCP_SEQ_STATE_ESTABLISHED: -		if (sk->sk_state == TCP_TIME_WAIT) -			get_timewait4_sock(v, seq, st->num); -		else -			get_tcp4_sock(v, seq, st->num); -		break; -	case TCP_SEQ_STATE_OPENREQ: -		get_openreq4(v, seq, st->num, st->uid); -		break; -	} +	if (sk->sk_state == TCP_TIME_WAIT) +		get_timewait4_sock(v, seq, st->num); +	else if (sk->sk_state == TCP_NEW_SYN_RECV) +		get_openreq4(v, seq, st->num); +	else +		get_tcp4_sock(v, seq, st->num);  out:  	seq_pad(seq, '\n');  	return 0;  | 
