diff options
Diffstat (limited to 'net/ipv4/tcp.c')
| -rw-r--r-- | net/ipv4/tcp.c | 112 | 
1 files changed, 80 insertions, 32 deletions
| diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 141acd92e58a..b8af2fec5ad5 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -494,21 +494,32 @@ static inline bool tcp_stream_is_readable(const struct tcp_sock *tp,  }  /* - * Socket is not locked. We are protected from async events by poll logic and - * correct handling of state changes made by other threads is impossible in - * any case. + *	Wait for a TCP event. + * + *	Note that we don't need to lock the socket, as the upper poll layers + *	take care of normal races (between the test and the event) and we don't + *	go look at any of the socket buffers directly.   */ -__poll_t tcp_poll_mask(struct socket *sock, __poll_t events) +__poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait)  { +	__poll_t mask;  	struct sock *sk = sock->sk;  	const struct tcp_sock *tp = tcp_sk(sk); -	__poll_t mask = 0;  	int state; +	sock_poll_wait(file, wait); +  	state = inet_sk_state_load(sk);  	if (state == TCP_LISTEN)  		return inet_csk_listen_poll(sk); +	/* Socket is not locked. We are protected from async events +	 * by poll logic and correct handling of state changes +	 * made by other threads is impossible in any case. +	 */ + +	mask = 0; +  	/*  	 * EPOLLHUP is certainly not done right. But poll() doesn't  	 * have a notion of HUP in just one direction, and for a @@ -589,7 +600,7 @@ __poll_t tcp_poll_mask(struct socket *sock, __poll_t events)  	return mask;  } -EXPORT_SYMBOL(tcp_poll_mask); +EXPORT_SYMBOL(tcp_poll);  int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)  { @@ -806,8 +817,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,  				 * This occurs when user tries to read  				 * from never connected socket.  				 */ -				if (!sock_flag(sk, SOCK_DONE)) -					ret = -ENOTCONN; +				ret = -ENOTCONN;  				break;  			}  			if (!timeo) { @@ -1230,7 +1240,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)  		/* 'common' sending to sendq */  	} -	sockc.tsflags = sk->sk_tsflags; +	sockcm_init(&sockc, sk);  	if (msg->msg_controllen) {  		err = sock_cmsg_send(sk, msg, &sockc);  		if (unlikely(err)) { @@ -1264,9 +1274,6 @@ restart:  			int linear;  new_segment: -			/* Allocate new segment. If the interface is SG, -			 * allocate skb fitting to single page. -			 */  			if (!sk_stream_memory_free(sk))  				goto wait_for_sndbuf; @@ -1987,7 +1994,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,  			 * shouldn't happen.  			 */  			if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), -				 "recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n", +				 "TCP recvmsg seq # bug: copied %X, seq %X, rcvnxt %X, fl %X\n",  				 *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt,  				 flags))  				break; @@ -2002,7 +2009,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,  			if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)  				goto found_fin_ok;  			WARN(!(flags & MSG_PEEK), -			     "recvmsg bug 2: copied %X seq %X rcvnxt %X fl %X\n", +			     "TCP recvmsg seq # bug 2: copied %X, seq %X, rcvnxt %X, fl %X\n",  			     *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, flags);  		} @@ -2031,13 +2038,10 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,  				break;  			if (sk->sk_state == TCP_CLOSE) { -				if (!sock_flag(sk, SOCK_DONE)) { -					/* This occurs when user tries to read -					 * from never connected socket. -					 */ -					copied = -ENOTCONN; -					break; -				} +				/* This occurs when user tries to read +				 * from never connected socket. +				 */ +				copied = -ENOTCONN;  				break;  			} @@ -2527,7 +2531,6 @@ int tcp_disconnect(struct sock *sk, int flags)  	struct inet_sock *inet = inet_sk(sk);  	struct inet_connection_sock *icsk = inet_csk(sk);  	struct tcp_sock *tp = tcp_sk(sk); -	int err = 0;  	int old_state = sk->sk_state;  	if (old_state != TCP_CLOSE) @@ -2551,6 +2554,8 @@ int tcp_disconnect(struct sock *sk, int flags)  	tcp_clear_xmit_timers(sk);  	__skb_queue_purge(&sk->sk_receive_queue); +	tp->copied_seq = tp->rcv_nxt; +	tp->urg_data = 0;  	tcp_write_queue_purge(sk);  	tcp_fastopen_active_disable_ofo_check(sk);  	skb_rbtree_purge(&tp->out_of_order_queue); @@ -2563,6 +2568,7 @@ int tcp_disconnect(struct sock *sk, int flags)  	sk->sk_shutdown = 0;  	sock_reset_flag(sk, SOCK_DONE);  	tp->srtt_us = 0; +	tp->rcv_rtt_last_tsecr = 0;  	tp->write_seq += tp->max_window + 2;  	if (tp->write_seq == 0)  		tp->write_seq = 1; @@ -2587,6 +2593,10 @@ int tcp_disconnect(struct sock *sk, int flags)  	sk->sk_rx_dst = NULL;  	tcp_saved_syn_free(tp);  	tp->compressed_ack = 0; +	tp->bytes_sent = 0; +	tp->bytes_retrans = 0; +	tp->dsack_dups = 0; +	tp->reord_seen = 0;  	/* Clean up fastopen related fields */  	tcp_free_fastopen_req(tp); @@ -2601,7 +2611,7 @@ int tcp_disconnect(struct sock *sk, int flags)  	}  	sk->sk_error_report(sk); -	return err; +	return 0;  }  EXPORT_SYMBOL(tcp_disconnect); @@ -2810,14 +2820,17 @@ static int do_tcp_setsockopt(struct sock *sk, int level,  	case TCP_REPAIR:  		if (!tcp_can_repair_sock(sk))  			err = -EPERM; -		else if (val == 1) { +		else if (val == TCP_REPAIR_ON) {  			tp->repair = 1;  			sk->sk_reuse = SK_FORCE_REUSE;  			tp->repair_queue = TCP_NO_QUEUE; -		} else if (val == 0) { +		} else if (val == TCP_REPAIR_OFF) {  			tp->repair = 0;  			sk->sk_reuse = SK_NO_REUSE;  			tcp_send_window_probe(sk); +		} else if (val == TCP_REPAIR_OFF_NO_WP) { +			tp->repair = 0; +			sk->sk_reuse = SK_NO_REUSE;  		} else  			err = -EINVAL; @@ -2979,7 +2992,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,  		if (val < 0)  			err = -EINVAL;  		else -			icsk->icsk_user_timeout = msecs_to_jiffies(val); +			icsk->icsk_user_timeout = val;  		break;  	case TCP_FASTOPEN: @@ -3191,10 +3204,41 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)  		info->tcpi_delivery_rate = rate64;  	info->tcpi_delivered = tp->delivered;  	info->tcpi_delivered_ce = tp->delivered_ce; +	info->tcpi_bytes_sent = tp->bytes_sent; +	info->tcpi_bytes_retrans = tp->bytes_retrans; +	info->tcpi_dsack_dups = tp->dsack_dups; +	info->tcpi_reord_seen = tp->reord_seen;  	unlock_sock_fast(sk, slow);  }  EXPORT_SYMBOL_GPL(tcp_get_info); +static size_t tcp_opt_stats_get_size(void) +{ +	return +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_BUSY */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_RWND_LIMITED */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_SNDBUF_LIMITED */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_DATA_SEGS_OUT */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_TOTAL_RETRANS */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_PACING_RATE */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_DELIVERY_RATE */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_SND_CWND */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_REORDERING */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_MIN_RTT */ +		nla_total_size(sizeof(u8)) + /* TCP_NLA_RECUR_RETRANS */ +		nla_total_size(sizeof(u8)) + /* TCP_NLA_DELIVERY_RATE_APP_LMT */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_SNDQ_SIZE */ +		nla_total_size(sizeof(u8)) + /* TCP_NLA_CA_STATE */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_SND_SSTHRESH */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_DELIVERED */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_DELIVERED_CE */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_BYTES_SENT */ +		nla_total_size_64bit(sizeof(u64)) + /* TCP_NLA_BYTES_RETRANS */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_DSACK_DUPS */ +		nla_total_size(sizeof(u32)) + /* TCP_NLA_REORD_SEEN */ +		0; +} +  struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk)  {  	const struct tcp_sock *tp = tcp_sk(sk); @@ -3203,9 +3247,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk)  	u64 rate64;  	u32 rate; -	stats = alloc_skb(7 * nla_total_size_64bit(sizeof(u64)) + -			  7 * nla_total_size(sizeof(u32)) + -			  3 * nla_total_size(sizeof(u8)), GFP_ATOMIC); +	stats = alloc_skb(tcp_opt_stats_get_size(), GFP_ATOMIC);  	if (!stats)  		return NULL; @@ -3241,6 +3283,13 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk)  	nla_put_u32(stats, TCP_NLA_SNDQ_SIZE, tp->write_seq - tp->snd_una);  	nla_put_u8(stats, TCP_NLA_CA_STATE, inet_csk(sk)->icsk_ca_state); +	nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent, +			  TCP_NLA_PAD); +	nla_put_u64_64bit(stats, TCP_NLA_BYTES_RETRANS, tp->bytes_retrans, +			  TCP_NLA_PAD); +	nla_put_u32(stats, TCP_NLA_DSACK_DUPS, tp->dsack_dups); +	nla_put_u32(stats, TCP_NLA_REORD_SEEN, tp->reord_seen); +  	return stats;  } @@ -3435,7 +3484,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level,  		break;  	case TCP_USER_TIMEOUT: -		val = jiffies_to_msecs(icsk->icsk_user_timeout); +		val = icsk->icsk_user_timeout;  		break;  	case TCP_FASTOPEN: @@ -3709,8 +3758,7 @@ int tcp_abort(struct sock *sk, int err)  			struct request_sock *req = inet_reqsk(sk);  			local_bh_disable(); -			inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, -							  req); +			inet_csk_reqsk_queue_drop(req->rsk_listener, req);  			local_bh_enable();  			return 0;  		} |