diff options
Diffstat (limited to 'drivers/net/ovpn/tcp.c')
| -rw-r--r-- | drivers/net/ovpn/tcp.c | 26 | 
1 files changed, 22 insertions, 4 deletions
diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c index 289f62c5d2c7..0d7f30360d87 100644 --- a/drivers/net/ovpn/tcp.c +++ b/drivers/net/ovpn/tcp.c @@ -560,16 +560,34 @@ static void ovpn_tcp_close(struct sock *sk, long timeout)  static __poll_t ovpn_tcp_poll(struct file *file, struct socket *sock,  			      poll_table *wait)  { -	__poll_t mask = datagram_poll(file, sock, wait); +	struct sk_buff_head *queue = &sock->sk->sk_receive_queue;  	struct ovpn_socket *ovpn_sock; +	struct ovpn_peer *peer = NULL; +	__poll_t mask;  	rcu_read_lock();  	ovpn_sock = rcu_dereference_sk_user_data(sock->sk); -	if (ovpn_sock && ovpn_sock->peer && -	    !skb_queue_empty(&ovpn_sock->peer->tcp.user_queue)) -		mask |= EPOLLIN | EPOLLRDNORM; +	/* if we landed in this callback, we expect to have a +	 * meaningful state. The ovpn_socket lifecycle would +	 * prevent it otherwise. +	 */ +	if (WARN(!ovpn_sock || !ovpn_sock->peer, +		 "ovpn: null state in ovpn_tcp_poll!")) { +		rcu_read_unlock(); +		return 0; +	} + +	if (ovpn_peer_hold(ovpn_sock->peer)) { +		peer = ovpn_sock->peer; +		queue = &peer->tcp.user_queue; +	}  	rcu_read_unlock(); +	mask = datagram_poll_queue(file, sock, wait, queue); + +	if (peer) +		ovpn_peer_put(peer); +  	return mask;  }  | 
