xref: /openbmc/linux/net/vmw_vsock/virtio_transport_common.c (revision aad29a73199b7fbccfbabea3f1ee627ad1924f52)
17a338472SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
206a8fc78SAsias He /*
306a8fc78SAsias He  * common code for virtio vsock
406a8fc78SAsias He  *
506a8fc78SAsias He  * Copyright (C) 2013-2015 Red Hat, Inc.
606a8fc78SAsias He  * Author: Asias He <asias@redhat.com>
706a8fc78SAsias He  *         Stefan Hajnoczi <stefanha@redhat.com>
806a8fc78SAsias He  */
906a8fc78SAsias He #include <linux/spinlock.h>
1006a8fc78SAsias He #include <linux/module.h>
11174cd4b1SIngo Molnar #include <linux/sched/signal.h>
1206a8fc78SAsias He #include <linux/ctype.h>
1306a8fc78SAsias He #include <linux/list.h>
1406a8fc78SAsias He #include <linux/virtio_vsock.h>
1582dfb540SGerard Garcia #include <uapi/linux/vsockmon.h>
1606a8fc78SAsias He 
1706a8fc78SAsias He #include <net/sock.h>
1806a8fc78SAsias He #include <net/af_vsock.h>
1906a8fc78SAsias He 
2006a8fc78SAsias He #define CREATE_TRACE_POINTS
2106a8fc78SAsias He #include <trace/events/vsock_virtio_transport_common.h>
2206a8fc78SAsias He 
2306a8fc78SAsias He /* How long to wait for graceful shutdown of a connection */
2406a8fc78SAsias He #define VSOCK_CLOSE_TIMEOUT (8 * HZ)
2506a8fc78SAsias He 
26473c7391SStefano Garzarella /* Threshold for detecting small packets to copy */
27473c7391SStefano Garzarella #define GOOD_COPY_LEN  128
28473c7391SStefano Garzarella 
29*dd93823fSStefano Garzarella static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,
30*dd93823fSStefano Garzarella 					       bool cancel_timeout);
31*dd93823fSStefano Garzarella 
32daabfbcaSStefano Garzarella static const struct virtio_transport *
virtio_transport_get_ops(struct vsock_sock * vsk)33daabfbcaSStefano Garzarella virtio_transport_get_ops(struct vsock_sock *vsk)
3406a8fc78SAsias He {
35daabfbcaSStefano Garzarella 	const struct vsock_transport *t = vsock_core_get_transport(vsk);
3606a8fc78SAsias He 
374aaf5961SStefano Garzarella 	if (WARN_ON(!t))
384aaf5961SStefano Garzarella 		return NULL;
394aaf5961SStefano Garzarella 
4006a8fc78SAsias He 	return container_of(t, struct virtio_transport, transport);
4106a8fc78SAsias He }
4206a8fc78SAsias He 
4371dc9ec9SBobby Eshleman /* Returns a new packet on success, otherwise returns NULL.
4471dc9ec9SBobby Eshleman  *
4571dc9ec9SBobby Eshleman  * If NULL is returned, errp is set to a negative errno.
4671dc9ec9SBobby Eshleman  */
4771dc9ec9SBobby Eshleman static struct sk_buff *
virtio_transport_alloc_skb(struct virtio_vsock_pkt_info * info,size_t len,u32 src_cid,u32 src_port,u32 dst_cid,u32 dst_port)4871dc9ec9SBobby Eshleman virtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info,
4906a8fc78SAsias He 			   size_t len,
5006a8fc78SAsias He 			   u32 src_cid,
5106a8fc78SAsias He 			   u32 src_port,
5206a8fc78SAsias He 			   u32 dst_cid,
5306a8fc78SAsias He 			   u32 dst_port)
5406a8fc78SAsias He {
5571dc9ec9SBobby Eshleman 	const size_t skb_len = VIRTIO_VSOCK_SKB_HEADROOM + len;
5671dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr;
5771dc9ec9SBobby Eshleman 	struct sk_buff *skb;
5871dc9ec9SBobby Eshleman 	void *payload;
5906a8fc78SAsias He 	int err;
6006a8fc78SAsias He 
6171dc9ec9SBobby Eshleman 	skb = virtio_vsock_alloc_skb(skb_len, GFP_KERNEL);
6271dc9ec9SBobby Eshleman 	if (!skb)
6306a8fc78SAsias He 		return NULL;
6406a8fc78SAsias He 
6571dc9ec9SBobby Eshleman 	hdr = virtio_vsock_hdr(skb);
6671dc9ec9SBobby Eshleman 	hdr->type	= cpu_to_le16(info->type);
6771dc9ec9SBobby Eshleman 	hdr->op		= cpu_to_le16(info->op);
6871dc9ec9SBobby Eshleman 	hdr->src_cid	= cpu_to_le64(src_cid);
6971dc9ec9SBobby Eshleman 	hdr->dst_cid	= cpu_to_le64(dst_cid);
7071dc9ec9SBobby Eshleman 	hdr->src_port	= cpu_to_le32(src_port);
7171dc9ec9SBobby Eshleman 	hdr->dst_port	= cpu_to_le32(dst_port);
7271dc9ec9SBobby Eshleman 	hdr->flags	= cpu_to_le32(info->flags);
7371dc9ec9SBobby Eshleman 	hdr->len	= cpu_to_le32(len);
740b8906fbSShigeru Yoshida 	hdr->buf_alloc	= cpu_to_le32(0);
750b8906fbSShigeru Yoshida 	hdr->fwd_cnt	= cpu_to_le32(0);
7606a8fc78SAsias He 
7706a8fc78SAsias He 	if (info->msg && len > 0) {
7871dc9ec9SBobby Eshleman 		payload = skb_put(skb, len);
7971dc9ec9SBobby Eshleman 		err = memcpy_from_msg(payload, info->msg, len);
8006a8fc78SAsias He 		if (err)
8106a8fc78SAsias He 			goto out;
829ac841f5SArseny Krasnov 
839ac841f5SArseny Krasnov 		if (msg_data_left(info->msg) == 0 &&
848d5ac871SArseny Krasnov 		    info->type == VIRTIO_VSOCK_TYPE_SEQPACKET) {
8571dc9ec9SBobby Eshleman 			hdr->flags |= cpu_to_le32(VIRTIO_VSOCK_SEQ_EOM);
868d5ac871SArseny Krasnov 
878d5ac871SArseny Krasnov 			if (info->msg->msg_flags & MSG_EOR)
8871dc9ec9SBobby Eshleman 				hdr->flags |= cpu_to_le32(VIRTIO_VSOCK_SEQ_EOR);
898d5ac871SArseny Krasnov 		}
9006a8fc78SAsias He 	}
9106a8fc78SAsias He 
9271dc9ec9SBobby Eshleman 	if (info->reply)
9371dc9ec9SBobby Eshleman 		virtio_vsock_skb_set_reply(skb);
9471dc9ec9SBobby Eshleman 
9506a8fc78SAsias He 	trace_virtio_transport_alloc_pkt(src_cid, src_port,
9606a8fc78SAsias He 					 dst_cid, dst_port,
9706a8fc78SAsias He 					 len,
9806a8fc78SAsias He 					 info->type,
9906a8fc78SAsias He 					 info->op,
10006a8fc78SAsias He 					 info->flags);
10106a8fc78SAsias He 
102f9d2b1e1SBobby Eshleman 	if (info->vsk && !skb_set_owner_sk_safe(skb, sk_vsock(info->vsk))) {
103f9d2b1e1SBobby Eshleman 		WARN_ONCE(1, "failed to allocate skb on vsock socket with sk_refcnt == 0\n");
104f9d2b1e1SBobby Eshleman 		goto out;
105f9d2b1e1SBobby Eshleman 	}
106f9d2b1e1SBobby Eshleman 
10771dc9ec9SBobby Eshleman 	return skb;
10806a8fc78SAsias He 
10906a8fc78SAsias He out:
11071dc9ec9SBobby Eshleman 	kfree_skb(skb);
11106a8fc78SAsias He 	return NULL;
11206a8fc78SAsias He }
11306a8fc78SAsias He 
11482dfb540SGerard Garcia /* Packet capture */
virtio_transport_build_skb(void * opaque)11582dfb540SGerard Garcia static struct sk_buff *virtio_transport_build_skb(void *opaque)
11682dfb540SGerard Garcia {
11771dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *pkt_hdr;
11871dc9ec9SBobby Eshleman 	struct sk_buff *pkt = opaque;
11982dfb540SGerard Garcia 	struct af_vsockmon_hdr *hdr;
12082dfb540SGerard Garcia 	struct sk_buff *skb;
1216dbd3e66SStefano Garzarella 	size_t payload_len;
1226dbd3e66SStefano Garzarella 	void *payload_buf;
12382dfb540SGerard Garcia 
1246dbd3e66SStefano Garzarella 	/* A packet could be split to fit the RX buffer, so we can retrieve
1256dbd3e66SStefano Garzarella 	 * the payload length from the header and the buffer pointer taking
1266dbd3e66SStefano Garzarella 	 * care of the offset in the original packet.
1276dbd3e66SStefano Garzarella 	 */
12871dc9ec9SBobby Eshleman 	pkt_hdr = virtio_vsock_hdr(pkt);
12971dc9ec9SBobby Eshleman 	payload_len = pkt->len;
13071dc9ec9SBobby Eshleman 	payload_buf = pkt->data;
1316dbd3e66SStefano Garzarella 
13271dc9ec9SBobby Eshleman 	skb = alloc_skb(sizeof(*hdr) + sizeof(*pkt_hdr) + payload_len,
13382dfb540SGerard Garcia 			GFP_ATOMIC);
13482dfb540SGerard Garcia 	if (!skb)
13582dfb540SGerard Garcia 		return NULL;
13682dfb540SGerard Garcia 
1374df864c1SJohannes Berg 	hdr = skb_put(skb, sizeof(*hdr));
13882dfb540SGerard Garcia 
13982dfb540SGerard Garcia 	/* pkt->hdr is little-endian so no need to byteswap here */
14071dc9ec9SBobby Eshleman 	hdr->src_cid = pkt_hdr->src_cid;
14171dc9ec9SBobby Eshleman 	hdr->src_port = pkt_hdr->src_port;
14271dc9ec9SBobby Eshleman 	hdr->dst_cid = pkt_hdr->dst_cid;
14371dc9ec9SBobby Eshleman 	hdr->dst_port = pkt_hdr->dst_port;
14482dfb540SGerard Garcia 
14582dfb540SGerard Garcia 	hdr->transport = cpu_to_le16(AF_VSOCK_TRANSPORT_VIRTIO);
14671dc9ec9SBobby Eshleman 	hdr->len = cpu_to_le16(sizeof(*pkt_hdr));
14782dfb540SGerard Garcia 	memset(hdr->reserved, 0, sizeof(hdr->reserved));
14882dfb540SGerard Garcia 
14971dc9ec9SBobby Eshleman 	switch (le16_to_cpu(pkt_hdr->op)) {
15082dfb540SGerard Garcia 	case VIRTIO_VSOCK_OP_REQUEST:
15182dfb540SGerard Garcia 	case VIRTIO_VSOCK_OP_RESPONSE:
15282dfb540SGerard Garcia 		hdr->op = cpu_to_le16(AF_VSOCK_OP_CONNECT);
15382dfb540SGerard Garcia 		break;
15482dfb540SGerard Garcia 	case VIRTIO_VSOCK_OP_RST:
15582dfb540SGerard Garcia 	case VIRTIO_VSOCK_OP_SHUTDOWN:
15682dfb540SGerard Garcia 		hdr->op = cpu_to_le16(AF_VSOCK_OP_DISCONNECT);
15782dfb540SGerard Garcia 		break;
15882dfb540SGerard Garcia 	case VIRTIO_VSOCK_OP_RW:
15982dfb540SGerard Garcia 		hdr->op = cpu_to_le16(AF_VSOCK_OP_PAYLOAD);
16082dfb540SGerard Garcia 		break;
16182dfb540SGerard Garcia 	case VIRTIO_VSOCK_OP_CREDIT_UPDATE:
16282dfb540SGerard Garcia 	case VIRTIO_VSOCK_OP_CREDIT_REQUEST:
16382dfb540SGerard Garcia 		hdr->op = cpu_to_le16(AF_VSOCK_OP_CONTROL);
16482dfb540SGerard Garcia 		break;
16582dfb540SGerard Garcia 	default:
16682dfb540SGerard Garcia 		hdr->op = cpu_to_le16(AF_VSOCK_OP_UNKNOWN);
16782dfb540SGerard Garcia 		break;
16882dfb540SGerard Garcia 	}
16982dfb540SGerard Garcia 
17071dc9ec9SBobby Eshleman 	skb_put_data(skb, pkt_hdr, sizeof(*pkt_hdr));
17182dfb540SGerard Garcia 
1726dbd3e66SStefano Garzarella 	if (payload_len) {
1736dbd3e66SStefano Garzarella 		skb_put_data(skb, payload_buf, payload_len);
17482dfb540SGerard Garcia 	}
17582dfb540SGerard Garcia 
17682dfb540SGerard Garcia 	return skb;
17782dfb540SGerard Garcia }
17882dfb540SGerard Garcia 
virtio_transport_deliver_tap_pkt(struct sk_buff * skb)17971dc9ec9SBobby Eshleman void virtio_transport_deliver_tap_pkt(struct sk_buff *skb)
18082dfb540SGerard Garcia {
18171dc9ec9SBobby Eshleman 	if (virtio_vsock_skb_tap_delivered(skb))
182a78d1639SStefano Garzarella 		return;
183a78d1639SStefano Garzarella 
18471dc9ec9SBobby Eshleman 	vsock_deliver_tap(virtio_transport_build_skb, skb);
18571dc9ec9SBobby Eshleman 	virtio_vsock_skb_set_tap_delivered(skb);
18682dfb540SGerard Garcia }
18782dfb540SGerard Garcia EXPORT_SYMBOL_GPL(virtio_transport_deliver_tap_pkt);
18882dfb540SGerard Garcia 
virtio_transport_get_type(struct sock * sk)189e4b1ef15SArseny Krasnov static u16 virtio_transport_get_type(struct sock *sk)
190e4b1ef15SArseny Krasnov {
191e4b1ef15SArseny Krasnov 	if (sk->sk_type == SOCK_STREAM)
192e4b1ef15SArseny Krasnov 		return VIRTIO_VSOCK_TYPE_STREAM;
193e4b1ef15SArseny Krasnov 	else
194e4b1ef15SArseny Krasnov 		return VIRTIO_VSOCK_TYPE_SEQPACKET;
195e4b1ef15SArseny Krasnov }
196e4b1ef15SArseny Krasnov 
1974aaf5961SStefano Garzarella /* This function can only be used on connecting/connected sockets,
1984aaf5961SStefano Garzarella  * since a socket assigned to a transport is required.
1994aaf5961SStefano Garzarella  *
2004aaf5961SStefano Garzarella  * Do not use on listener sockets!
2014aaf5961SStefano Garzarella  */
virtio_transport_send_pkt_info(struct vsock_sock * vsk,struct virtio_vsock_pkt_info * info)20206a8fc78SAsias He static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
20306a8fc78SAsias He 					  struct virtio_vsock_pkt_info *info)
20406a8fc78SAsias He {
20506a8fc78SAsias He 	u32 src_cid, src_port, dst_cid, dst_port;
2064aaf5961SStefano Garzarella 	const struct virtio_transport *t_ops;
20706a8fc78SAsias He 	struct virtio_vsock_sock *vvs;
20806a8fc78SAsias He 	u32 pkt_len = info->pkt_len;
209b68ffb1bSArseniy Krasnov 	u32 rest_len;
210b68ffb1bSArseniy Krasnov 	int ret;
21106a8fc78SAsias He 
2129ac841f5SArseny Krasnov 	info->type = virtio_transport_get_type(sk_vsock(vsk));
213b93f8877SArseny Krasnov 
2144aaf5961SStefano Garzarella 	t_ops = virtio_transport_get_ops(vsk);
2154aaf5961SStefano Garzarella 	if (unlikely(!t_ops))
2164aaf5961SStefano Garzarella 		return -EFAULT;
2174aaf5961SStefano Garzarella 
2184aaf5961SStefano Garzarella 	src_cid = t_ops->transport.get_local_cid();
21906a8fc78SAsias He 	src_port = vsk->local_addr.svm_port;
22006a8fc78SAsias He 	if (!info->remote_cid) {
22106a8fc78SAsias He 		dst_cid	= vsk->remote_addr.svm_cid;
22206a8fc78SAsias He 		dst_port = vsk->remote_addr.svm_port;
22306a8fc78SAsias He 	} else {
22406a8fc78SAsias He 		dst_cid = info->remote_cid;
22506a8fc78SAsias He 		dst_port = info->remote_port;
22606a8fc78SAsias He 	}
22706a8fc78SAsias He 
22806a8fc78SAsias He 	vvs = vsk->trans;
22906a8fc78SAsias He 
23006a8fc78SAsias He 	/* virtio_transport_get_credit might return less than pkt_len credit */
23106a8fc78SAsias He 	pkt_len = virtio_transport_get_credit(vvs, pkt_len);
23206a8fc78SAsias He 
23306a8fc78SAsias He 	/* Do not send zero length OP_RW pkt */
23406a8fc78SAsias He 	if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW)
23506a8fc78SAsias He 		return pkt_len;
23606a8fc78SAsias He 
237b68ffb1bSArseniy Krasnov 	rest_len = pkt_len;
238b68ffb1bSArseniy Krasnov 
239b68ffb1bSArseniy Krasnov 	do {
240b68ffb1bSArseniy Krasnov 		struct sk_buff *skb;
241b68ffb1bSArseniy Krasnov 		size_t skb_len;
242b68ffb1bSArseniy Krasnov 
243b68ffb1bSArseniy Krasnov 		skb_len = min_t(u32, VIRTIO_VSOCK_MAX_PKT_BUF_SIZE, rest_len);
244b68ffb1bSArseniy Krasnov 
245b68ffb1bSArseniy Krasnov 		skb = virtio_transport_alloc_skb(info, skb_len,
24606a8fc78SAsias He 						 src_cid, src_port,
24706a8fc78SAsias He 						 dst_cid, dst_port);
24871dc9ec9SBobby Eshleman 		if (!skb) {
249b68ffb1bSArseniy Krasnov 			ret = -ENOMEM;
250b68ffb1bSArseniy Krasnov 			break;
25106a8fc78SAsias He 		}
25206a8fc78SAsias He 
25371dc9ec9SBobby Eshleman 		virtio_transport_inc_tx_pkt(vvs, skb);
25406a8fc78SAsias He 
255b68ffb1bSArseniy Krasnov 		ret = t_ops->send_pkt(skb);
256b68ffb1bSArseniy Krasnov 		if (ret < 0)
257b68ffb1bSArseniy Krasnov 			break;
258b68ffb1bSArseniy Krasnov 
259b68ffb1bSArseniy Krasnov 		/* Both virtio and vhost 'send_pkt()' returns 'skb_len',
260b68ffb1bSArseniy Krasnov 		 * but for reliability use 'ret' instead of 'skb_len'.
261b68ffb1bSArseniy Krasnov 		 * Also if partial send happens (e.g. 'ret' != 'skb_len')
262b68ffb1bSArseniy Krasnov 		 * somehow, we break this loop, but account such returned
263b68ffb1bSArseniy Krasnov 		 * value in 'virtio_transport_put_credit()'.
264b68ffb1bSArseniy Krasnov 		 */
265b68ffb1bSArseniy Krasnov 		rest_len -= ret;
266b68ffb1bSArseniy Krasnov 
267b68ffb1bSArseniy Krasnov 		if (WARN_ONCE(ret != skb_len,
268b68ffb1bSArseniy Krasnov 			      "'send_pkt()' returns %i, but %zu expected\n",
269b68ffb1bSArseniy Krasnov 			      ret, skb_len))
270b68ffb1bSArseniy Krasnov 			break;
271b68ffb1bSArseniy Krasnov 	} while (rest_len);
272b68ffb1bSArseniy Krasnov 
273b68ffb1bSArseniy Krasnov 	virtio_transport_put_credit(vvs, rest_len);
274b68ffb1bSArseniy Krasnov 
275b68ffb1bSArseniy Krasnov 	/* Return number of bytes, if any data has been sent. */
276b68ffb1bSArseniy Krasnov 	if (rest_len != pkt_len)
277b68ffb1bSArseniy Krasnov 		ret = pkt_len - rest_len;
278b68ffb1bSArseniy Krasnov 
279b68ffb1bSArseniy Krasnov 	return ret;
28006a8fc78SAsias He }
28106a8fc78SAsias He 
virtio_transport_inc_rx_pkt(struct virtio_vsock_sock * vvs,u32 len)282ae6fcfbfSStefano Garzarella static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
28307770616SArseniy Krasnov 					u32 len)
28406a8fc78SAsias He {
28507770616SArseniy Krasnov 	if (vvs->rx_bytes + len > vvs->buf_alloc)
286ae6fcfbfSStefano Garzarella 		return false;
287ae6fcfbfSStefano Garzarella 
28807770616SArseniy Krasnov 	vvs->rx_bytes += len;
289ae6fcfbfSStefano Garzarella 	return true;
29006a8fc78SAsias He }
29106a8fc78SAsias He 
virtio_transport_dec_rx_pkt(struct virtio_vsock_sock * vvs,u32 len)29206a8fc78SAsias He static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs,
29307770616SArseniy Krasnov 					u32 len)
29406a8fc78SAsias He {
29571dc9ec9SBobby Eshleman 	vvs->rx_bytes -= len;
29671dc9ec9SBobby Eshleman 	vvs->fwd_cnt += len;
29706a8fc78SAsias He }
29806a8fc78SAsias He 
virtio_transport_inc_tx_pkt(struct virtio_vsock_sock * vvs,struct sk_buff * skb)29971dc9ec9SBobby Eshleman void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct sk_buff *skb)
30006a8fc78SAsias He {
30171dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
30271dc9ec9SBobby Eshleman 
3039632e9f6SStefano Garzarella 	spin_lock_bh(&vvs->rx_lock);
304b89d882dSStefano Garzarella 	vvs->last_fwd_cnt = vvs->fwd_cnt;
30571dc9ec9SBobby Eshleman 	hdr->fwd_cnt = cpu_to_le32(vvs->fwd_cnt);
30671dc9ec9SBobby Eshleman 	hdr->buf_alloc = cpu_to_le32(vvs->buf_alloc);
3079632e9f6SStefano Garzarella 	spin_unlock_bh(&vvs->rx_lock);
30806a8fc78SAsias He }
30906a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_inc_tx_pkt);
31006a8fc78SAsias He 
virtio_transport_get_credit(struct virtio_vsock_sock * vvs,u32 credit)31106a8fc78SAsias He u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit)
31206a8fc78SAsias He {
31306a8fc78SAsias He 	u32 ret;
31406a8fc78SAsias He 
315e3ec366eSArseniy Krasnov 	if (!credit)
316e3ec366eSArseniy Krasnov 		return 0;
317e3ec366eSArseniy Krasnov 
31806a8fc78SAsias He 	spin_lock_bh(&vvs->tx_lock);
31906a8fc78SAsias He 	ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
32006a8fc78SAsias He 	if (ret > credit)
32106a8fc78SAsias He 		ret = credit;
32206a8fc78SAsias He 	vvs->tx_cnt += ret;
32306a8fc78SAsias He 	spin_unlock_bh(&vvs->tx_lock);
32406a8fc78SAsias He 
32506a8fc78SAsias He 	return ret;
32606a8fc78SAsias He }
32706a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_get_credit);
32806a8fc78SAsias He 
virtio_transport_put_credit(struct virtio_vsock_sock * vvs,u32 credit)32906a8fc78SAsias He void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit)
33006a8fc78SAsias He {
331e3ec366eSArseniy Krasnov 	if (!credit)
332e3ec366eSArseniy Krasnov 		return;
333e3ec366eSArseniy Krasnov 
33406a8fc78SAsias He 	spin_lock_bh(&vvs->tx_lock);
33506a8fc78SAsias He 	vvs->tx_cnt -= credit;
33606a8fc78SAsias He 	spin_unlock_bh(&vvs->tx_lock);
33706a8fc78SAsias He }
33806a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_put_credit);
33906a8fc78SAsias He 
virtio_transport_send_credit_update(struct vsock_sock * vsk)340c10844c5SArseny Krasnov static int virtio_transport_send_credit_update(struct vsock_sock *vsk)
34106a8fc78SAsias He {
34206a8fc78SAsias He 	struct virtio_vsock_pkt_info info = {
34306a8fc78SAsias He 		.op = VIRTIO_VSOCK_OP_CREDIT_UPDATE,
34436d277baSPeng Tao 		.vsk = vsk,
34506a8fc78SAsias He 	};
34606a8fc78SAsias He 
34706a8fc78SAsias He 	return virtio_transport_send_pkt_info(vsk, &info);
34806a8fc78SAsias He }
34906a8fc78SAsias He 
35006a8fc78SAsias He static ssize_t
virtio_transport_stream_do_peek(struct vsock_sock * vsk,struct msghdr * msg,size_t len)351a786ab36SMatias Ezequiel Vara Larsen virtio_transport_stream_do_peek(struct vsock_sock *vsk,
352a786ab36SMatias Ezequiel Vara Larsen 				struct msghdr *msg,
353a786ab36SMatias Ezequiel Vara Larsen 				size_t len)
354a786ab36SMatias Ezequiel Vara Larsen {
355a786ab36SMatias Ezequiel Vara Larsen 	struct virtio_vsock_sock *vvs = vsk->trans;
356051e77e3SArseniy Krasnov 	struct sk_buff *skb;
357051e77e3SArseniy Krasnov 	size_t total = 0;
358051e77e3SArseniy Krasnov 	int err;
359a786ab36SMatias Ezequiel Vara Larsen 
360a786ab36SMatias Ezequiel Vara Larsen 	spin_lock_bh(&vvs->rx_lock);
361a786ab36SMatias Ezequiel Vara Larsen 
362051e77e3SArseniy Krasnov 	skb_queue_walk(&vvs->rx_queue, skb) {
363051e77e3SArseniy Krasnov 		size_t bytes;
364a786ab36SMatias Ezequiel Vara Larsen 
365a786ab36SMatias Ezequiel Vara Larsen 		bytes = len - total;
366051e77e3SArseniy Krasnov 		if (bytes > skb->len)
367051e77e3SArseniy Krasnov 			bytes = skb->len;
368051e77e3SArseniy Krasnov 
369051e77e3SArseniy Krasnov 		spin_unlock_bh(&vvs->rx_lock);
370a786ab36SMatias Ezequiel Vara Larsen 
371a786ab36SMatias Ezequiel Vara Larsen 		/* sk_lock is held by caller so no one else can dequeue.
372a786ab36SMatias Ezequiel Vara Larsen 		 * Unlock rx_lock since memcpy_to_msg() may sleep.
373a786ab36SMatias Ezequiel Vara Larsen 		 */
374051e77e3SArseniy Krasnov 		err = memcpy_to_msg(msg, skb->data, bytes);
375a786ab36SMatias Ezequiel Vara Larsen 		if (err)
376a786ab36SMatias Ezequiel Vara Larsen 			goto out;
377a786ab36SMatias Ezequiel Vara Larsen 
378051e77e3SArseniy Krasnov 		total += bytes;
379051e77e3SArseniy Krasnov 
380a786ab36SMatias Ezequiel Vara Larsen 		spin_lock_bh(&vvs->rx_lock);
381a786ab36SMatias Ezequiel Vara Larsen 
382051e77e3SArseniy Krasnov 		if (total == len)
383051e77e3SArseniy Krasnov 			break;
384a786ab36SMatias Ezequiel Vara Larsen 	}
385a786ab36SMatias Ezequiel Vara Larsen 
386a786ab36SMatias Ezequiel Vara Larsen 	spin_unlock_bh(&vvs->rx_lock);
387a786ab36SMatias Ezequiel Vara Larsen 
388a786ab36SMatias Ezequiel Vara Larsen 	return total;
389a786ab36SMatias Ezequiel Vara Larsen 
390a786ab36SMatias Ezequiel Vara Larsen out:
391a786ab36SMatias Ezequiel Vara Larsen 	if (total)
392a786ab36SMatias Ezequiel Vara Larsen 		err = total;
393a786ab36SMatias Ezequiel Vara Larsen 	return err;
394a786ab36SMatias Ezequiel Vara Larsen }
395a786ab36SMatias Ezequiel Vara Larsen 
396a786ab36SMatias Ezequiel Vara Larsen static ssize_t
virtio_transport_stream_do_dequeue(struct vsock_sock * vsk,struct msghdr * msg,size_t len)39706a8fc78SAsias He virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
39806a8fc78SAsias He 				   struct msghdr *msg,
39906a8fc78SAsias He 				   size_t len)
40006a8fc78SAsias He {
40106a8fc78SAsias He 	struct virtio_vsock_sock *vvs = vsk->trans;
40206a8fc78SAsias He 	size_t bytes, total = 0;
40371dc9ec9SBobby Eshleman 	struct sk_buff *skb;
404925c22d4SArseniy Krasnov 	u32 fwd_cnt_delta;
405925c22d4SArseniy Krasnov 	bool low_rx_bytes;
40606a8fc78SAsias He 	int err = -EFAULT;
40771dc9ec9SBobby Eshleman 	u32 free_space;
40806a8fc78SAsias He 
40906a8fc78SAsias He 	spin_lock_bh(&vvs->rx_lock);
410b8d2f61fSArseniy Krasnov 
411b8d2f61fSArseniy Krasnov 	if (WARN_ONCE(skb_queue_empty(&vvs->rx_queue) && vvs->rx_bytes,
412b8d2f61fSArseniy Krasnov 		      "rx_queue is empty, but rx_bytes is non-zero\n")) {
413b8d2f61fSArseniy Krasnov 		spin_unlock_bh(&vvs->rx_lock);
414b8d2f61fSArseniy Krasnov 		return err;
415b8d2f61fSArseniy Krasnov 	}
416b8d2f61fSArseniy Krasnov 
41771dc9ec9SBobby Eshleman 	while (total < len && !skb_queue_empty(&vvs->rx_queue)) {
4188daaf39fSArseniy Krasnov 		skb = skb_peek(&vvs->rx_queue);
41906a8fc78SAsias He 
42006a8fc78SAsias He 		bytes = len - total;
42171dc9ec9SBobby Eshleman 		if (bytes > skb->len)
42271dc9ec9SBobby Eshleman 			bytes = skb->len;
42306a8fc78SAsias He 
42406a8fc78SAsias He 		/* sk_lock is held by caller so no one else can dequeue.
42506a8fc78SAsias He 		 * Unlock rx_lock since memcpy_to_msg() may sleep.
42606a8fc78SAsias He 		 */
42706a8fc78SAsias He 		spin_unlock_bh(&vvs->rx_lock);
42806a8fc78SAsias He 
42971dc9ec9SBobby Eshleman 		err = memcpy_to_msg(msg, skb->data, bytes);
43006a8fc78SAsias He 		if (err)
43106a8fc78SAsias He 			goto out;
43206a8fc78SAsias He 
43306a8fc78SAsias He 		spin_lock_bh(&vvs->rx_lock);
43406a8fc78SAsias He 
43506a8fc78SAsias He 		total += bytes;
43671dc9ec9SBobby Eshleman 		skb_pull(skb, bytes);
43771dc9ec9SBobby Eshleman 
43871dc9ec9SBobby Eshleman 		if (skb->len == 0) {
43907770616SArseniy Krasnov 			u32 pkt_len = le32_to_cpu(virtio_vsock_hdr(skb)->len);
44007770616SArseniy Krasnov 
44107770616SArseniy Krasnov 			virtio_transport_dec_rx_pkt(vvs, pkt_len);
4428daaf39fSArseniy Krasnov 			__skb_unlink(skb, &vvs->rx_queue);
44371dc9ec9SBobby Eshleman 			consume_skb(skb);
44406a8fc78SAsias He 		}
44506a8fc78SAsias He 	}
446b89d882dSStefano Garzarella 
447925c22d4SArseniy Krasnov 	fwd_cnt_delta = vvs->fwd_cnt - vvs->last_fwd_cnt;
448925c22d4SArseniy Krasnov 	free_space = vvs->buf_alloc - fwd_cnt_delta;
449925c22d4SArseniy Krasnov 	low_rx_bytes = (vvs->rx_bytes <
450925c22d4SArseniy Krasnov 			sock_rcvlowat(sk_vsock(vsk), 0, INT_MAX));
451b89d882dSStefano Garzarella 
45206a8fc78SAsias He 	spin_unlock_bh(&vvs->rx_lock);
45306a8fc78SAsias He 
454f4d7c8e3SMichael S. Tsirkin 	/* To reduce the number of credit update messages,
455f4d7c8e3SMichael S. Tsirkin 	 * don't update credits as long as lots of space is available.
456f4d7c8e3SMichael S. Tsirkin 	 * Note: the limit chosen here is arbitrary. Setting the limit
457f4d7c8e3SMichael S. Tsirkin 	 * too high causes extra messages. Too low causes transmitter
458f4d7c8e3SMichael S. Tsirkin 	 * stalls. As stalls are in theory more expensive than extra
459f4d7c8e3SMichael S. Tsirkin 	 * messages, we set the limit to a high value. TODO: experiment
460925c22d4SArseniy Krasnov 	 * with different values. Also send credit update message when
461925c22d4SArseniy Krasnov 	 * number of bytes in rx queue is not enough to wake up reader.
462b89d882dSStefano Garzarella 	 */
463925c22d4SArseniy Krasnov 	if (fwd_cnt_delta &&
464925c22d4SArseniy Krasnov 	    (free_space < VIRTIO_VSOCK_MAX_PKT_BUF_SIZE || low_rx_bytes))
465c10844c5SArseny Krasnov 		virtio_transport_send_credit_update(vsk);
46606a8fc78SAsias He 
46706a8fc78SAsias He 	return total;
46806a8fc78SAsias He 
46906a8fc78SAsias He out:
47006a8fc78SAsias He 	if (total)
47106a8fc78SAsias He 		err = total;
47206a8fc78SAsias He 	return err;
47306a8fc78SAsias He }
47406a8fc78SAsias He 
475a75f501dSArseniy Krasnov static ssize_t
virtio_transport_seqpacket_do_peek(struct vsock_sock * vsk,struct msghdr * msg)476a75f501dSArseniy Krasnov virtio_transport_seqpacket_do_peek(struct vsock_sock *vsk,
477a75f501dSArseniy Krasnov 				   struct msghdr *msg)
478a75f501dSArseniy Krasnov {
479a75f501dSArseniy Krasnov 	struct virtio_vsock_sock *vvs = vsk->trans;
480a75f501dSArseniy Krasnov 	struct sk_buff *skb;
481a75f501dSArseniy Krasnov 	size_t total, len;
482a75f501dSArseniy Krasnov 
483a75f501dSArseniy Krasnov 	spin_lock_bh(&vvs->rx_lock);
484a75f501dSArseniy Krasnov 
485a75f501dSArseniy Krasnov 	if (!vvs->msg_count) {
486a75f501dSArseniy Krasnov 		spin_unlock_bh(&vvs->rx_lock);
487a75f501dSArseniy Krasnov 		return 0;
488a75f501dSArseniy Krasnov 	}
489a75f501dSArseniy Krasnov 
490a75f501dSArseniy Krasnov 	total = 0;
491a75f501dSArseniy Krasnov 	len = msg_data_left(msg);
492a75f501dSArseniy Krasnov 
493a75f501dSArseniy Krasnov 	skb_queue_walk(&vvs->rx_queue, skb) {
494a75f501dSArseniy Krasnov 		struct virtio_vsock_hdr *hdr;
495a75f501dSArseniy Krasnov 
496a75f501dSArseniy Krasnov 		if (total < len) {
497a75f501dSArseniy Krasnov 			size_t bytes;
498a75f501dSArseniy Krasnov 			int err;
499a75f501dSArseniy Krasnov 
500a75f501dSArseniy Krasnov 			bytes = len - total;
501a75f501dSArseniy Krasnov 			if (bytes > skb->len)
502a75f501dSArseniy Krasnov 				bytes = skb->len;
503a75f501dSArseniy Krasnov 
504a75f501dSArseniy Krasnov 			spin_unlock_bh(&vvs->rx_lock);
505a75f501dSArseniy Krasnov 
506a75f501dSArseniy Krasnov 			/* sk_lock is held by caller so no one else can dequeue.
507a75f501dSArseniy Krasnov 			 * Unlock rx_lock since memcpy_to_msg() may sleep.
508a75f501dSArseniy Krasnov 			 */
509a75f501dSArseniy Krasnov 			err = memcpy_to_msg(msg, skb->data, bytes);
510a75f501dSArseniy Krasnov 			if (err)
511a75f501dSArseniy Krasnov 				return err;
512a75f501dSArseniy Krasnov 
513a75f501dSArseniy Krasnov 			spin_lock_bh(&vvs->rx_lock);
514a75f501dSArseniy Krasnov 		}
515a75f501dSArseniy Krasnov 
516a75f501dSArseniy Krasnov 		total += skb->len;
517a75f501dSArseniy Krasnov 		hdr = virtio_vsock_hdr(skb);
518a75f501dSArseniy Krasnov 
519a75f501dSArseniy Krasnov 		if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM) {
520a75f501dSArseniy Krasnov 			if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOR)
521a75f501dSArseniy Krasnov 				msg->msg_flags |= MSG_EOR;
522a75f501dSArseniy Krasnov 
523a75f501dSArseniy Krasnov 			break;
524a75f501dSArseniy Krasnov 		}
525a75f501dSArseniy Krasnov 	}
526a75f501dSArseniy Krasnov 
527a75f501dSArseniy Krasnov 	spin_unlock_bh(&vvs->rx_lock);
528a75f501dSArseniy Krasnov 
529a75f501dSArseniy Krasnov 	return total;
530a75f501dSArseniy Krasnov }
531a75f501dSArseniy Krasnov 
virtio_transport_seqpacket_do_dequeue(struct vsock_sock * vsk,struct msghdr * msg,int flags)53244931195SArseny Krasnov static int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk,
53344931195SArseny Krasnov 						 struct msghdr *msg,
53444931195SArseny Krasnov 						 int flags)
53544931195SArseny Krasnov {
53644931195SArseny Krasnov 	struct virtio_vsock_sock *vvs = vsk->trans;
53744931195SArseny Krasnov 	int dequeued_len = 0;
53844931195SArseny Krasnov 	size_t user_buf_len = msg_data_left(msg);
53944931195SArseny Krasnov 	bool msg_ready = false;
54071dc9ec9SBobby Eshleman 	struct sk_buff *skb;
54144931195SArseny Krasnov 
54244931195SArseny Krasnov 	spin_lock_bh(&vvs->rx_lock);
54344931195SArseny Krasnov 
54444931195SArseny Krasnov 	if (vvs->msg_count == 0) {
54544931195SArseny Krasnov 		spin_unlock_bh(&vvs->rx_lock);
54644931195SArseny Krasnov 		return 0;
54744931195SArseny Krasnov 	}
54844931195SArseny Krasnov 
54944931195SArseny Krasnov 	while (!msg_ready) {
55071dc9ec9SBobby Eshleman 		struct virtio_vsock_hdr *hdr;
55107770616SArseniy Krasnov 		size_t pkt_len;
55271dc9ec9SBobby Eshleman 
55371dc9ec9SBobby Eshleman 		skb = __skb_dequeue(&vvs->rx_queue);
55471dc9ec9SBobby Eshleman 		if (!skb)
55571dc9ec9SBobby Eshleman 			break;
55671dc9ec9SBobby Eshleman 		hdr = virtio_vsock_hdr(skb);
55707770616SArseniy Krasnov 		pkt_len = (size_t)le32_to_cpu(hdr->len);
55844931195SArseny Krasnov 
55991aa49a8SStefano Garzarella 		if (dequeued_len >= 0) {
56044931195SArseny Krasnov 			size_t bytes_to_copy;
56144931195SArseny Krasnov 
56244931195SArseny Krasnov 			bytes_to_copy = min(user_buf_len, pkt_len);
56344931195SArseny Krasnov 
56444931195SArseny Krasnov 			if (bytes_to_copy) {
56544931195SArseny Krasnov 				int err;
56644931195SArseny Krasnov 
56744931195SArseny Krasnov 				/* sk_lock is held by caller so no one else can dequeue.
56844931195SArseny Krasnov 				 * Unlock rx_lock since memcpy_to_msg() may sleep.
56944931195SArseny Krasnov 				 */
57044931195SArseny Krasnov 				spin_unlock_bh(&vvs->rx_lock);
57144931195SArseny Krasnov 
57271dc9ec9SBobby Eshleman 				err = memcpy_to_msg(msg, skb->data, bytes_to_copy);
57344931195SArseny Krasnov 				if (err) {
57491aa49a8SStefano Garzarella 					/* Copy of message failed. Rest of
57544931195SArseny Krasnov 					 * fragments will be freed without copy.
57644931195SArseny Krasnov 					 */
57744931195SArseny Krasnov 					dequeued_len = err;
57844931195SArseny Krasnov 				} else {
57944931195SArseny Krasnov 					user_buf_len -= bytes_to_copy;
58044931195SArseny Krasnov 				}
58144931195SArseny Krasnov 
58244931195SArseny Krasnov 				spin_lock_bh(&vvs->rx_lock);
58344931195SArseny Krasnov 			}
58444931195SArseny Krasnov 
58544931195SArseny Krasnov 			if (dequeued_len >= 0)
58644931195SArseny Krasnov 				dequeued_len += pkt_len;
58744931195SArseny Krasnov 		}
58844931195SArseny Krasnov 
58971dc9ec9SBobby Eshleman 		if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM) {
59044931195SArseny Krasnov 			msg_ready = true;
59144931195SArseny Krasnov 			vvs->msg_count--;
5928d5ac871SArseny Krasnov 
59371dc9ec9SBobby Eshleman 			if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOR)
5948d5ac871SArseny Krasnov 				msg->msg_flags |= MSG_EOR;
59544931195SArseny Krasnov 		}
59644931195SArseny Krasnov 
59707770616SArseniy Krasnov 		virtio_transport_dec_rx_pkt(vvs, pkt_len);
59871dc9ec9SBobby Eshleman 		kfree_skb(skb);
59944931195SArseny Krasnov 	}
60044931195SArseny Krasnov 
60144931195SArseny Krasnov 	spin_unlock_bh(&vvs->rx_lock);
60244931195SArseny Krasnov 
60344931195SArseny Krasnov 	virtio_transport_send_credit_update(vsk);
60444931195SArseny Krasnov 
60544931195SArseny Krasnov 	return dequeued_len;
60644931195SArseny Krasnov }
60744931195SArseny Krasnov 
60806a8fc78SAsias He ssize_t
virtio_transport_stream_dequeue(struct vsock_sock * vsk,struct msghdr * msg,size_t len,int flags)60906a8fc78SAsias He virtio_transport_stream_dequeue(struct vsock_sock *vsk,
61006a8fc78SAsias He 				struct msghdr *msg,
61106a8fc78SAsias He 				size_t len, int flags)
61206a8fc78SAsias He {
61306a8fc78SAsias He 	if (flags & MSG_PEEK)
614a786ab36SMatias Ezequiel Vara Larsen 		return virtio_transport_stream_do_peek(vsk, msg, len);
615a786ab36SMatias Ezequiel Vara Larsen 	else
61606a8fc78SAsias He 		return virtio_transport_stream_do_dequeue(vsk, msg, len);
61706a8fc78SAsias He }
61806a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_stream_dequeue);
61906a8fc78SAsias He 
62044931195SArseny Krasnov ssize_t
virtio_transport_seqpacket_dequeue(struct vsock_sock * vsk,struct msghdr * msg,int flags)62144931195SArseny Krasnov virtio_transport_seqpacket_dequeue(struct vsock_sock *vsk,
62244931195SArseny Krasnov 				   struct msghdr *msg,
62344931195SArseny Krasnov 				   int flags)
62444931195SArseny Krasnov {
62544931195SArseny Krasnov 	if (flags & MSG_PEEK)
626a75f501dSArseniy Krasnov 		return virtio_transport_seqpacket_do_peek(vsk, msg);
627a75f501dSArseniy Krasnov 	else
62844931195SArseny Krasnov 		return virtio_transport_seqpacket_do_dequeue(vsk, msg, flags);
62944931195SArseny Krasnov }
63044931195SArseny Krasnov EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_dequeue);
63144931195SArseny Krasnov 
63206a8fc78SAsias He int
virtio_transport_seqpacket_enqueue(struct vsock_sock * vsk,struct msghdr * msg,size_t len)6339ac841f5SArseny Krasnov virtio_transport_seqpacket_enqueue(struct vsock_sock *vsk,
6349ac841f5SArseny Krasnov 				   struct msghdr *msg,
6359ac841f5SArseny Krasnov 				   size_t len)
6369ac841f5SArseny Krasnov {
6379ac841f5SArseny Krasnov 	struct virtio_vsock_sock *vvs = vsk->trans;
6389ac841f5SArseny Krasnov 
6399ac841f5SArseny Krasnov 	spin_lock_bh(&vvs->tx_lock);
6409ac841f5SArseny Krasnov 
6419ac841f5SArseny Krasnov 	if (len > vvs->peer_buf_alloc) {
6429ac841f5SArseny Krasnov 		spin_unlock_bh(&vvs->tx_lock);
6439ac841f5SArseny Krasnov 		return -EMSGSIZE;
6449ac841f5SArseny Krasnov 	}
6459ac841f5SArseny Krasnov 
6469ac841f5SArseny Krasnov 	spin_unlock_bh(&vvs->tx_lock);
6479ac841f5SArseny Krasnov 
6489ac841f5SArseny Krasnov 	return virtio_transport_stream_enqueue(vsk, msg, len);
6499ac841f5SArseny Krasnov }
6509ac841f5SArseny Krasnov EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_enqueue);
6519ac841f5SArseny Krasnov 
6529ac841f5SArseny Krasnov int
virtio_transport_dgram_dequeue(struct vsock_sock * vsk,struct msghdr * msg,size_t len,int flags)65306a8fc78SAsias He virtio_transport_dgram_dequeue(struct vsock_sock *vsk,
65406a8fc78SAsias He 			       struct msghdr *msg,
65506a8fc78SAsias He 			       size_t len, int flags)
65606a8fc78SAsias He {
65706a8fc78SAsias He 	return -EOPNOTSUPP;
65806a8fc78SAsias He }
65906a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_dgram_dequeue);
66006a8fc78SAsias He 
virtio_transport_stream_has_data(struct vsock_sock * vsk)66106a8fc78SAsias He s64 virtio_transport_stream_has_data(struct vsock_sock *vsk)
66206a8fc78SAsias He {
66306a8fc78SAsias He 	struct virtio_vsock_sock *vvs = vsk->trans;
66406a8fc78SAsias He 	s64 bytes;
66506a8fc78SAsias He 
66606a8fc78SAsias He 	spin_lock_bh(&vvs->rx_lock);
66706a8fc78SAsias He 	bytes = vvs->rx_bytes;
66806a8fc78SAsias He 	spin_unlock_bh(&vvs->rx_lock);
66906a8fc78SAsias He 
67006a8fc78SAsias He 	return bytes;
67106a8fc78SAsias He }
67206a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_stream_has_data);
67306a8fc78SAsias He 
virtio_transport_seqpacket_has_data(struct vsock_sock * vsk)6749ac841f5SArseny Krasnov u32 virtio_transport_seqpacket_has_data(struct vsock_sock *vsk)
6759ac841f5SArseny Krasnov {
6769ac841f5SArseny Krasnov 	struct virtio_vsock_sock *vvs = vsk->trans;
6779ac841f5SArseny Krasnov 	u32 msg_count;
6789ac841f5SArseny Krasnov 
6799ac841f5SArseny Krasnov 	spin_lock_bh(&vvs->rx_lock);
6809ac841f5SArseny Krasnov 	msg_count = vvs->msg_count;
6819ac841f5SArseny Krasnov 	spin_unlock_bh(&vvs->rx_lock);
6829ac841f5SArseny Krasnov 
6839ac841f5SArseny Krasnov 	return msg_count;
6849ac841f5SArseny Krasnov }
6859ac841f5SArseny Krasnov EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_has_data);
6869ac841f5SArseny Krasnov 
virtio_transport_has_space(struct vsock_sock * vsk)68706a8fc78SAsias He static s64 virtio_transport_has_space(struct vsock_sock *vsk)
68806a8fc78SAsias He {
68906a8fc78SAsias He 	struct virtio_vsock_sock *vvs = vsk->trans;
69006a8fc78SAsias He 	s64 bytes;
69106a8fc78SAsias He 
692fa634779SNikolay Kuratov 	bytes = (s64)vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
69306a8fc78SAsias He 	if (bytes < 0)
69406a8fc78SAsias He 		bytes = 0;
69506a8fc78SAsias He 
69606a8fc78SAsias He 	return bytes;
69706a8fc78SAsias He }
69806a8fc78SAsias He 
virtio_transport_stream_has_space(struct vsock_sock * vsk)69906a8fc78SAsias He s64 virtio_transport_stream_has_space(struct vsock_sock *vsk)
70006a8fc78SAsias He {
70106a8fc78SAsias He 	struct virtio_vsock_sock *vvs = vsk->trans;
70206a8fc78SAsias He 	s64 bytes;
70306a8fc78SAsias He 
70406a8fc78SAsias He 	spin_lock_bh(&vvs->tx_lock);
70506a8fc78SAsias He 	bytes = virtio_transport_has_space(vsk);
70606a8fc78SAsias He 	spin_unlock_bh(&vvs->tx_lock);
70706a8fc78SAsias He 
70806a8fc78SAsias He 	return bytes;
70906a8fc78SAsias He }
71006a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_stream_has_space);
71106a8fc78SAsias He 
virtio_transport_do_socket_init(struct vsock_sock * vsk,struct vsock_sock * psk)71206a8fc78SAsias He int virtio_transport_do_socket_init(struct vsock_sock *vsk,
71306a8fc78SAsias He 				    struct vsock_sock *psk)
71406a8fc78SAsias He {
71506a8fc78SAsias He 	struct virtio_vsock_sock *vvs;
71606a8fc78SAsias He 
71706a8fc78SAsias He 	vvs = kzalloc(sizeof(*vvs), GFP_KERNEL);
71806a8fc78SAsias He 	if (!vvs)
71906a8fc78SAsias He 		return -ENOMEM;
72006a8fc78SAsias He 
72106a8fc78SAsias He 	vsk->trans = vvs;
72206a8fc78SAsias He 	vvs->vsk = vsk;
723c0cfa2d8SStefano Garzarella 	if (psk && psk->trans) {
72406a8fc78SAsias He 		struct virtio_vsock_sock *ptrans = psk->trans;
72506a8fc78SAsias He 
72606a8fc78SAsias He 		vvs->peer_buf_alloc = ptrans->peer_buf_alloc;
72706a8fc78SAsias He 	}
72806a8fc78SAsias He 
729b9f2b0ffSStefano Garzarella 	if (vsk->buffer_size > VIRTIO_VSOCK_MAX_BUF_SIZE)
730b9f2b0ffSStefano Garzarella 		vsk->buffer_size = VIRTIO_VSOCK_MAX_BUF_SIZE;
731b9f2b0ffSStefano Garzarella 
732b9f2b0ffSStefano Garzarella 	vvs->buf_alloc = vsk->buffer_size;
73306a8fc78SAsias He 
73406a8fc78SAsias He 	spin_lock_init(&vvs->rx_lock);
73506a8fc78SAsias He 	spin_lock_init(&vvs->tx_lock);
73671dc9ec9SBobby Eshleman 	skb_queue_head_init(&vvs->rx_queue);
73706a8fc78SAsias He 
73806a8fc78SAsias He 	return 0;
73906a8fc78SAsias He }
74006a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_do_socket_init);
74106a8fc78SAsias He 
742b9f2b0ffSStefano Garzarella /* sk_lock held by the caller */
virtio_transport_notify_buffer_size(struct vsock_sock * vsk,u64 * val)743b9f2b0ffSStefano Garzarella void virtio_transport_notify_buffer_size(struct vsock_sock *vsk, u64 *val)
74406a8fc78SAsias He {
74506a8fc78SAsias He 	struct virtio_vsock_sock *vvs = vsk->trans;
74606a8fc78SAsias He 
747b9f2b0ffSStefano Garzarella 	if (*val > VIRTIO_VSOCK_MAX_BUF_SIZE)
748b9f2b0ffSStefano Garzarella 		*val = VIRTIO_VSOCK_MAX_BUF_SIZE;
74906a8fc78SAsias He 
750b9f2b0ffSStefano Garzarella 	vvs->buf_alloc = *val;
751ec3359b6SStefano Garzarella 
752c10844c5SArseny Krasnov 	virtio_transport_send_credit_update(vsk);
75306a8fc78SAsias He }
754b9f2b0ffSStefano Garzarella EXPORT_SYMBOL_GPL(virtio_transport_notify_buffer_size);
75506a8fc78SAsias He 
75606a8fc78SAsias He int
virtio_transport_notify_poll_in(struct vsock_sock * vsk,size_t target,bool * data_ready_now)75706a8fc78SAsias He virtio_transport_notify_poll_in(struct vsock_sock *vsk,
75806a8fc78SAsias He 				size_t target,
75906a8fc78SAsias He 				bool *data_ready_now)
76006a8fc78SAsias He {
761e7a3266cSArseniy Krasnov 	*data_ready_now = vsock_stream_has_data(vsk) >= target;
76206a8fc78SAsias He 
76306a8fc78SAsias He 	return 0;
76406a8fc78SAsias He }
76506a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_in);
76606a8fc78SAsias He 
76706a8fc78SAsias He int
virtio_transport_notify_poll_out(struct vsock_sock * vsk,size_t target,bool * space_avail_now)76806a8fc78SAsias He virtio_transport_notify_poll_out(struct vsock_sock *vsk,
76906a8fc78SAsias He 				 size_t target,
77006a8fc78SAsias He 				 bool *space_avail_now)
77106a8fc78SAsias He {
77206a8fc78SAsias He 	s64 free_space;
77306a8fc78SAsias He 
77406a8fc78SAsias He 	free_space = vsock_stream_has_space(vsk);
77506a8fc78SAsias He 	if (free_space > 0)
77606a8fc78SAsias He 		*space_avail_now = true;
77706a8fc78SAsias He 	else if (free_space == 0)
77806a8fc78SAsias He 		*space_avail_now = false;
77906a8fc78SAsias He 
78006a8fc78SAsias He 	return 0;
78106a8fc78SAsias He }
78206a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_out);
78306a8fc78SAsias He 
virtio_transport_notify_recv_init(struct vsock_sock * vsk,size_t target,struct vsock_transport_recv_notify_data * data)78406a8fc78SAsias He int virtio_transport_notify_recv_init(struct vsock_sock *vsk,
78506a8fc78SAsias He 	size_t target, struct vsock_transport_recv_notify_data *data)
78606a8fc78SAsias He {
78706a8fc78SAsias He 	return 0;
78806a8fc78SAsias He }
78906a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_init);
79006a8fc78SAsias He 
virtio_transport_notify_recv_pre_block(struct vsock_sock * vsk,size_t target,struct vsock_transport_recv_notify_data * data)79106a8fc78SAsias He int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk,
79206a8fc78SAsias He 	size_t target, struct vsock_transport_recv_notify_data *data)
79306a8fc78SAsias He {
79406a8fc78SAsias He 	return 0;
79506a8fc78SAsias He }
79606a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_block);
79706a8fc78SAsias He 
virtio_transport_notify_recv_pre_dequeue(struct vsock_sock * vsk,size_t target,struct vsock_transport_recv_notify_data * data)79806a8fc78SAsias He int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk,
79906a8fc78SAsias He 	size_t target, struct vsock_transport_recv_notify_data *data)
80006a8fc78SAsias He {
80106a8fc78SAsias He 	return 0;
80206a8fc78SAsias He }
80306a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_dequeue);
80406a8fc78SAsias He 
virtio_transport_notify_recv_post_dequeue(struct vsock_sock * vsk,size_t target,ssize_t copied,bool data_read,struct vsock_transport_recv_notify_data * data)80506a8fc78SAsias He int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk,
80606a8fc78SAsias He 	size_t target, ssize_t copied, bool data_read,
80706a8fc78SAsias He 	struct vsock_transport_recv_notify_data *data)
80806a8fc78SAsias He {
80906a8fc78SAsias He 	return 0;
81006a8fc78SAsias He }
81106a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_post_dequeue);
81206a8fc78SAsias He 
virtio_transport_notify_send_init(struct vsock_sock * vsk,struct vsock_transport_send_notify_data * data)81306a8fc78SAsias He int virtio_transport_notify_send_init(struct vsock_sock *vsk,
81406a8fc78SAsias He 	struct vsock_transport_send_notify_data *data)
81506a8fc78SAsias He {
81606a8fc78SAsias He 	return 0;
81706a8fc78SAsias He }
81806a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_send_init);
81906a8fc78SAsias He 
virtio_transport_notify_send_pre_block(struct vsock_sock * vsk,struct vsock_transport_send_notify_data * data)82006a8fc78SAsias He int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk,
82106a8fc78SAsias He 	struct vsock_transport_send_notify_data *data)
82206a8fc78SAsias He {
82306a8fc78SAsias He 	return 0;
82406a8fc78SAsias He }
82506a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_block);
82606a8fc78SAsias He 
virtio_transport_notify_send_pre_enqueue(struct vsock_sock * vsk,struct vsock_transport_send_notify_data * data)82706a8fc78SAsias He int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk,
82806a8fc78SAsias He 	struct vsock_transport_send_notify_data *data)
82906a8fc78SAsias He {
83006a8fc78SAsias He 	return 0;
83106a8fc78SAsias He }
83206a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_enqueue);
83306a8fc78SAsias He 
virtio_transport_notify_send_post_enqueue(struct vsock_sock * vsk,ssize_t written,struct vsock_transport_send_notify_data * data)83406a8fc78SAsias He int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk,
83506a8fc78SAsias He 	ssize_t written, struct vsock_transport_send_notify_data *data)
83606a8fc78SAsias He {
83706a8fc78SAsias He 	return 0;
83806a8fc78SAsias He }
83906a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_notify_send_post_enqueue);
84006a8fc78SAsias He 
virtio_transport_stream_rcvhiwat(struct vsock_sock * vsk)84106a8fc78SAsias He u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk)
84206a8fc78SAsias He {
843b9f2b0ffSStefano Garzarella 	return vsk->buffer_size;
84406a8fc78SAsias He }
84506a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_stream_rcvhiwat);
84606a8fc78SAsias He 
virtio_transport_stream_is_active(struct vsock_sock * vsk)84706a8fc78SAsias He bool virtio_transport_stream_is_active(struct vsock_sock *vsk)
84806a8fc78SAsias He {
84906a8fc78SAsias He 	return true;
85006a8fc78SAsias He }
85106a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_stream_is_active);
85206a8fc78SAsias He 
virtio_transport_stream_allow(u32 cid,u32 port)85306a8fc78SAsias He bool virtio_transport_stream_allow(u32 cid, u32 port)
85406a8fc78SAsias He {
85506a8fc78SAsias He 	return true;
85606a8fc78SAsias He }
85706a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_stream_allow);
85806a8fc78SAsias He 
virtio_transport_dgram_bind(struct vsock_sock * vsk,struct sockaddr_vm * addr)85906a8fc78SAsias He int virtio_transport_dgram_bind(struct vsock_sock *vsk,
86006a8fc78SAsias He 				struct sockaddr_vm *addr)
86106a8fc78SAsias He {
86206a8fc78SAsias He 	return -EOPNOTSUPP;
86306a8fc78SAsias He }
86406a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_dgram_bind);
86506a8fc78SAsias He 
virtio_transport_dgram_allow(u32 cid,u32 port)86606a8fc78SAsias He bool virtio_transport_dgram_allow(u32 cid, u32 port)
86706a8fc78SAsias He {
86806a8fc78SAsias He 	return false;
86906a8fc78SAsias He }
87006a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_dgram_allow);
87106a8fc78SAsias He 
virtio_transport_connect(struct vsock_sock * vsk)87206a8fc78SAsias He int virtio_transport_connect(struct vsock_sock *vsk)
87306a8fc78SAsias He {
87406a8fc78SAsias He 	struct virtio_vsock_pkt_info info = {
87506a8fc78SAsias He 		.op = VIRTIO_VSOCK_OP_REQUEST,
87636d277baSPeng Tao 		.vsk = vsk,
87706a8fc78SAsias He 	};
87806a8fc78SAsias He 
87906a8fc78SAsias He 	return virtio_transport_send_pkt_info(vsk, &info);
88006a8fc78SAsias He }
88106a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_connect);
88206a8fc78SAsias He 
virtio_transport_shutdown(struct vsock_sock * vsk,int mode)88306a8fc78SAsias He int virtio_transport_shutdown(struct vsock_sock *vsk, int mode)
88406a8fc78SAsias He {
88506a8fc78SAsias He 	struct virtio_vsock_pkt_info info = {
88606a8fc78SAsias He 		.op = VIRTIO_VSOCK_OP_SHUTDOWN,
88706a8fc78SAsias He 		.flags = (mode & RCV_SHUTDOWN ?
88806a8fc78SAsias He 			  VIRTIO_VSOCK_SHUTDOWN_RCV : 0) |
88906a8fc78SAsias He 			 (mode & SEND_SHUTDOWN ?
89006a8fc78SAsias He 			  VIRTIO_VSOCK_SHUTDOWN_SEND : 0),
89136d277baSPeng Tao 		.vsk = vsk,
89206a8fc78SAsias He 	};
89306a8fc78SAsias He 
89406a8fc78SAsias He 	return virtio_transport_send_pkt_info(vsk, &info);
89506a8fc78SAsias He }
89606a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_shutdown);
89706a8fc78SAsias He 
89806a8fc78SAsias He int
virtio_transport_dgram_enqueue(struct vsock_sock * vsk,struct sockaddr_vm * remote_addr,struct msghdr * msg,size_t dgram_len)89906a8fc78SAsias He virtio_transport_dgram_enqueue(struct vsock_sock *vsk,
90006a8fc78SAsias He 			       struct sockaddr_vm *remote_addr,
90106a8fc78SAsias He 			       struct msghdr *msg,
90206a8fc78SAsias He 			       size_t dgram_len)
90306a8fc78SAsias He {
90406a8fc78SAsias He 	return -EOPNOTSUPP;
90506a8fc78SAsias He }
90606a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_dgram_enqueue);
90706a8fc78SAsias He 
90806a8fc78SAsias He ssize_t
virtio_transport_stream_enqueue(struct vsock_sock * vsk,struct msghdr * msg,size_t len)90906a8fc78SAsias He virtio_transport_stream_enqueue(struct vsock_sock *vsk,
91006a8fc78SAsias He 				struct msghdr *msg,
91106a8fc78SAsias He 				size_t len)
91206a8fc78SAsias He {
91306a8fc78SAsias He 	struct virtio_vsock_pkt_info info = {
91406a8fc78SAsias He 		.op = VIRTIO_VSOCK_OP_RW,
91506a8fc78SAsias He 		.msg = msg,
91606a8fc78SAsias He 		.pkt_len = len,
91736d277baSPeng Tao 		.vsk = vsk,
91806a8fc78SAsias He 	};
91906a8fc78SAsias He 
92006a8fc78SAsias He 	return virtio_transport_send_pkt_info(vsk, &info);
92106a8fc78SAsias He }
92206a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_stream_enqueue);
92306a8fc78SAsias He 
virtio_transport_destruct(struct vsock_sock * vsk)92406a8fc78SAsias He void virtio_transport_destruct(struct vsock_sock *vsk)
92506a8fc78SAsias He {
92606a8fc78SAsias He 	struct virtio_vsock_sock *vvs = vsk->trans;
92706a8fc78SAsias He 
928*dd93823fSStefano Garzarella 	virtio_transport_cancel_close_work(vsk, true);
929*dd93823fSStefano Garzarella 
93006a8fc78SAsias He 	kfree(vvs);
931b110196fSHyunwoo Kim 	vsk->trans = NULL;
93206a8fc78SAsias He }
93306a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_destruct);
93406a8fc78SAsias He 
virtio_transport_reset(struct vsock_sock * vsk,struct sk_buff * skb)93506a8fc78SAsias He static int virtio_transport_reset(struct vsock_sock *vsk,
93671dc9ec9SBobby Eshleman 				  struct sk_buff *skb)
93706a8fc78SAsias He {
93806a8fc78SAsias He 	struct virtio_vsock_pkt_info info = {
93906a8fc78SAsias He 		.op = VIRTIO_VSOCK_OP_RST,
94071dc9ec9SBobby Eshleman 		.reply = !!skb,
94136d277baSPeng Tao 		.vsk = vsk,
94206a8fc78SAsias He 	};
94306a8fc78SAsias He 
94406a8fc78SAsias He 	/* Send RST only if the original pkt is not a RST pkt */
94571dc9ec9SBobby Eshleman 	if (skb && le16_to_cpu(virtio_vsock_hdr(skb)->op) == VIRTIO_VSOCK_OP_RST)
94606a8fc78SAsias He 		return 0;
94706a8fc78SAsias He 
94806a8fc78SAsias He 	return virtio_transport_send_pkt_info(vsk, &info);
94906a8fc78SAsias He }
95006a8fc78SAsias He 
95106a8fc78SAsias He /* Normally packets are associated with a socket.  There may be no socket if an
95206a8fc78SAsias He  * attempt was made to connect to a socket that does not exist.
95306a8fc78SAsias He  */
virtio_transport_reset_no_sock(const struct virtio_transport * t,struct sk_buff * skb)9544c7246dcSStefano Garzarella static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
95571dc9ec9SBobby Eshleman 					  struct sk_buff *skb)
95606a8fc78SAsias He {
95771dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
95806a8fc78SAsias He 	struct virtio_vsock_pkt_info info = {
95906a8fc78SAsias He 		.op = VIRTIO_VSOCK_OP_RST,
96071dc9ec9SBobby Eshleman 		.type = le16_to_cpu(hdr->type),
96106a8fc78SAsias He 		.reply = true,
96206a8fc78SAsias He 	};
96371dc9ec9SBobby Eshleman 	struct sk_buff *reply;
96406a8fc78SAsias He 
96506a8fc78SAsias He 	/* Send RST only if the original pkt is not a RST pkt */
96671dc9ec9SBobby Eshleman 	if (le16_to_cpu(hdr->op) == VIRTIO_VSOCK_OP_RST)
96706a8fc78SAsias He 		return 0;
96806a8fc78SAsias He 
9694d1f5155SArseniy Krasnov 	if (!t)
9704d1f5155SArseniy Krasnov 		return -ENOTCONN;
9714d1f5155SArseniy Krasnov 
97271dc9ec9SBobby Eshleman 	reply = virtio_transport_alloc_skb(&info, 0,
97371dc9ec9SBobby Eshleman 					   le64_to_cpu(hdr->dst_cid),
97471dc9ec9SBobby Eshleman 					   le32_to_cpu(hdr->dst_port),
97571dc9ec9SBobby Eshleman 					   le64_to_cpu(hdr->src_cid),
97671dc9ec9SBobby Eshleman 					   le32_to_cpu(hdr->src_port));
9774c404ce2SAdalbert Lazăr 	if (!reply)
97806a8fc78SAsias He 		return -ENOMEM;
97906a8fc78SAsias He 
9804c404ce2SAdalbert Lazăr 	return t->send_pkt(reply);
98106a8fc78SAsias He }
98206a8fc78SAsias He 
9838432b811SStefano Garzarella /* This function should be called with sk_lock held and SOCK_DONE set */
virtio_transport_remove_sock(struct vsock_sock * vsk)9848432b811SStefano Garzarella static void virtio_transport_remove_sock(struct vsock_sock *vsk)
9858432b811SStefano Garzarella {
9868432b811SStefano Garzarella 	struct virtio_vsock_sock *vvs = vsk->trans;
9878432b811SStefano Garzarella 
9888432b811SStefano Garzarella 	/* We don't need to take rx_lock, as the socket is closing and we are
9898432b811SStefano Garzarella 	 * removing it.
9908432b811SStefano Garzarella 	 */
99171dc9ec9SBobby Eshleman 	__skb_queue_purge(&vvs->rx_queue);
9928432b811SStefano Garzarella 	vsock_remove_sock(vsk);
9938432b811SStefano Garzarella }
9948432b811SStefano Garzarella 
virtio_transport_wait_close(struct sock * sk,long timeout)99506a8fc78SAsias He static void virtio_transport_wait_close(struct sock *sk, long timeout)
99606a8fc78SAsias He {
99706a8fc78SAsias He 	if (timeout) {
998d9dc8b0fSWANG Cong 		DEFINE_WAIT_FUNC(wait, woken_wake_function);
999d9dc8b0fSWANG Cong 
1000d9dc8b0fSWANG Cong 		add_wait_queue(sk_sleep(sk), &wait);
100106a8fc78SAsias He 
100206a8fc78SAsias He 		do {
100306a8fc78SAsias He 			if (sk_wait_event(sk, &timeout,
1004d9dc8b0fSWANG Cong 					  sock_flag(sk, SOCK_DONE), &wait))
100506a8fc78SAsias He 				break;
100606a8fc78SAsias He 		} while (!signal_pending(current) && timeout);
100706a8fc78SAsias He 
1008d9dc8b0fSWANG Cong 		remove_wait_queue(sk_sleep(sk), &wait);
100906a8fc78SAsias He 	}
101006a8fc78SAsias He }
101106a8fc78SAsias He 
virtio_transport_cancel_close_work(struct vsock_sock * vsk,bool cancel_timeout)1012*dd93823fSStefano Garzarella static void virtio_transport_cancel_close_work(struct vsock_sock *vsk,
1013*dd93823fSStefano Garzarella 					       bool cancel_timeout)
1014*dd93823fSStefano Garzarella {
1015*dd93823fSStefano Garzarella 	struct sock *sk = sk_vsock(vsk);
1016*dd93823fSStefano Garzarella 
1017*dd93823fSStefano Garzarella 	if (vsk->close_work_scheduled &&
1018*dd93823fSStefano Garzarella 	    (!cancel_timeout || cancel_delayed_work(&vsk->close_work))) {
1019*dd93823fSStefano Garzarella 		vsk->close_work_scheduled = false;
1020*dd93823fSStefano Garzarella 
1021*dd93823fSStefano Garzarella 		virtio_transport_remove_sock(vsk);
1022*dd93823fSStefano Garzarella 
1023*dd93823fSStefano Garzarella 		/* Release refcnt obtained when we scheduled the timeout */
1024*dd93823fSStefano Garzarella 		sock_put(sk);
1025*dd93823fSStefano Garzarella 	}
1026*dd93823fSStefano Garzarella }
1027*dd93823fSStefano Garzarella 
virtio_transport_do_close(struct vsock_sock * vsk,bool cancel_timeout)102806a8fc78SAsias He static void virtio_transport_do_close(struct vsock_sock *vsk,
102906a8fc78SAsias He 				      bool cancel_timeout)
103006a8fc78SAsias He {
103106a8fc78SAsias He 	struct sock *sk = sk_vsock(vsk);
103206a8fc78SAsias He 
103306a8fc78SAsias He 	sock_set_flag(sk, SOCK_DONE);
103406a8fc78SAsias He 	vsk->peer_shutdown = SHUTDOWN_MASK;
103506a8fc78SAsias He 	if (vsock_stream_has_data(vsk) <= 0)
10363b4477d2SStefan Hajnoczi 		sk->sk_state = TCP_CLOSING;
103706a8fc78SAsias He 	sk->sk_state_change(sk);
103806a8fc78SAsias He 
1039*dd93823fSStefano Garzarella 	virtio_transport_cancel_close_work(vsk, cancel_timeout);
104006a8fc78SAsias He }
104106a8fc78SAsias He 
virtio_transport_close_timeout(struct work_struct * work)104206a8fc78SAsias He static void virtio_transport_close_timeout(struct work_struct *work)
104306a8fc78SAsias He {
104406a8fc78SAsias He 	struct vsock_sock *vsk =
104506a8fc78SAsias He 		container_of(work, struct vsock_sock, close_work.work);
104606a8fc78SAsias He 	struct sock *sk = sk_vsock(vsk);
104706a8fc78SAsias He 
104806a8fc78SAsias He 	sock_hold(sk);
104906a8fc78SAsias He 	lock_sock(sk);
105006a8fc78SAsias He 
105106a8fc78SAsias He 	if (!sock_flag(sk, SOCK_DONE)) {
105206a8fc78SAsias He 		(void)virtio_transport_reset(vsk, NULL);
105306a8fc78SAsias He 
105406a8fc78SAsias He 		virtio_transport_do_close(vsk, false);
105506a8fc78SAsias He 	}
105606a8fc78SAsias He 
105706a8fc78SAsias He 	vsk->close_work_scheduled = false;
105806a8fc78SAsias He 
105906a8fc78SAsias He 	release_sock(sk);
106006a8fc78SAsias He 	sock_put(sk);
106106a8fc78SAsias He }
106206a8fc78SAsias He 
106306a8fc78SAsias He /* User context, vsk->sk is locked */
virtio_transport_close(struct vsock_sock * vsk)106406a8fc78SAsias He static bool virtio_transport_close(struct vsock_sock *vsk)
106506a8fc78SAsias He {
106606a8fc78SAsias He 	struct sock *sk = &vsk->sk;
106706a8fc78SAsias He 
10683b4477d2SStefan Hajnoczi 	if (!(sk->sk_state == TCP_ESTABLISHED ||
10693b4477d2SStefan Hajnoczi 	      sk->sk_state == TCP_CLOSING))
107006a8fc78SAsias He 		return true;
107106a8fc78SAsias He 
107206a8fc78SAsias He 	/* Already received SHUTDOWN from peer, reply with RST */
107306a8fc78SAsias He 	if ((vsk->peer_shutdown & SHUTDOWN_MASK) == SHUTDOWN_MASK) {
107406a8fc78SAsias He 		(void)virtio_transport_reset(vsk, NULL);
107506a8fc78SAsias He 		return true;
107606a8fc78SAsias He 	}
107706a8fc78SAsias He 
107806a8fc78SAsias He 	if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK)
107906a8fc78SAsias He 		(void)virtio_transport_shutdown(vsk, SHUTDOWN_MASK);
108006a8fc78SAsias He 
108106a8fc78SAsias He 	if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING))
108206a8fc78SAsias He 		virtio_transport_wait_close(sk, sk->sk_lingertime);
108306a8fc78SAsias He 
108406a8fc78SAsias He 	if (sock_flag(sk, SOCK_DONE)) {
108506a8fc78SAsias He 		return true;
108606a8fc78SAsias He 	}
108706a8fc78SAsias He 
108806a8fc78SAsias He 	sock_hold(sk);
108906a8fc78SAsias He 	INIT_DELAYED_WORK(&vsk->close_work,
109006a8fc78SAsias He 			  virtio_transport_close_timeout);
109106a8fc78SAsias He 	vsk->close_work_scheduled = true;
109206a8fc78SAsias He 	schedule_delayed_work(&vsk->close_work, VSOCK_CLOSE_TIMEOUT);
109306a8fc78SAsias He 	return false;
109406a8fc78SAsias He }
109506a8fc78SAsias He 
virtio_transport_release(struct vsock_sock * vsk)109606a8fc78SAsias He void virtio_transport_release(struct vsock_sock *vsk)
109706a8fc78SAsias He {
109806a8fc78SAsias He 	struct sock *sk = &vsk->sk;
109906a8fc78SAsias He 	bool remove_sock = true;
110006a8fc78SAsias He 
11019ac841f5SArseny Krasnov 	if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET)
110206a8fc78SAsias He 		remove_sock = virtio_transport_close(vsk);
1103ac03046eSStefano Garzarella 
11043fe356d5SStefano Garzarella 	if (remove_sock) {
11053fe356d5SStefano Garzarella 		sock_set_flag(sk, SOCK_DONE);
11068432b811SStefano Garzarella 		virtio_transport_remove_sock(vsk);
110706a8fc78SAsias He 	}
11083fe356d5SStefano Garzarella }
110906a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_release);
111006a8fc78SAsias He 
111106a8fc78SAsias He static int
virtio_transport_recv_connecting(struct sock * sk,struct sk_buff * skb)111206a8fc78SAsias He virtio_transport_recv_connecting(struct sock *sk,
111371dc9ec9SBobby Eshleman 				 struct sk_buff *skb)
111406a8fc78SAsias He {
111571dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
111606a8fc78SAsias He 	struct vsock_sock *vsk = vsock_sk(sk);
111706a8fc78SAsias He 	int skerr;
111871dc9ec9SBobby Eshleman 	int err;
111906a8fc78SAsias He 
112071dc9ec9SBobby Eshleman 	switch (le16_to_cpu(hdr->op)) {
112106a8fc78SAsias He 	case VIRTIO_VSOCK_OP_RESPONSE:
11223b4477d2SStefan Hajnoczi 		sk->sk_state = TCP_ESTABLISHED;
112306a8fc78SAsias He 		sk->sk_socket->state = SS_CONNECTED;
112406a8fc78SAsias He 		vsock_insert_connected(vsk);
112506a8fc78SAsias He 		sk->sk_state_change(sk);
112606a8fc78SAsias He 		break;
112706a8fc78SAsias He 	case VIRTIO_VSOCK_OP_INVALID:
112806a8fc78SAsias He 		break;
112906a8fc78SAsias He 	case VIRTIO_VSOCK_OP_RST:
113006a8fc78SAsias He 		skerr = ECONNRESET;
113106a8fc78SAsias He 		err = 0;
113206a8fc78SAsias He 		goto destroy;
113306a8fc78SAsias He 	default:
113406a8fc78SAsias He 		skerr = EPROTO;
113506a8fc78SAsias He 		err = -EINVAL;
113606a8fc78SAsias He 		goto destroy;
113706a8fc78SAsias He 	}
113806a8fc78SAsias He 	return 0;
113906a8fc78SAsias He 
114006a8fc78SAsias He destroy:
114171dc9ec9SBobby Eshleman 	virtio_transport_reset(vsk, skb);
11423b4477d2SStefan Hajnoczi 	sk->sk_state = TCP_CLOSE;
114306a8fc78SAsias He 	sk->sk_err = skerr;
1144e3ae2365SAlexander Aring 	sk_error_report(sk);
114506a8fc78SAsias He 	return err;
114606a8fc78SAsias He }
114706a8fc78SAsias He 
1148473c7391SStefano Garzarella static void
virtio_transport_recv_enqueue(struct vsock_sock * vsk,struct sk_buff * skb)1149473c7391SStefano Garzarella virtio_transport_recv_enqueue(struct vsock_sock *vsk,
115071dc9ec9SBobby Eshleman 			      struct sk_buff *skb)
1151473c7391SStefano Garzarella {
1152473c7391SStefano Garzarella 	struct virtio_vsock_sock *vvs = vsk->trans;
1153ae6fcfbfSStefano Garzarella 	bool can_enqueue, free_pkt = false;
115471dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr;
115571dc9ec9SBobby Eshleman 	u32 len;
1156473c7391SStefano Garzarella 
115771dc9ec9SBobby Eshleman 	hdr = virtio_vsock_hdr(skb);
115871dc9ec9SBobby Eshleman 	len = le32_to_cpu(hdr->len);
1159473c7391SStefano Garzarella 
1160473c7391SStefano Garzarella 	spin_lock_bh(&vvs->rx_lock);
1161473c7391SStefano Garzarella 
116207770616SArseniy Krasnov 	can_enqueue = virtio_transport_inc_rx_pkt(vvs, len);
1163ae6fcfbfSStefano Garzarella 	if (!can_enqueue) {
1164ae6fcfbfSStefano Garzarella 		free_pkt = true;
1165ae6fcfbfSStefano Garzarella 		goto out;
1166ae6fcfbfSStefano Garzarella 	}
1167473c7391SStefano Garzarella 
116871dc9ec9SBobby Eshleman 	if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM)
1169e4b1ef15SArseny Krasnov 		vvs->msg_count++;
1170e4b1ef15SArseny Krasnov 
1171473c7391SStefano Garzarella 	/* Try to copy small packets into the buffer of last packet queued,
1172473c7391SStefano Garzarella 	 * to avoid wasting memory queueing the entire buffer with a small
1173473c7391SStefano Garzarella 	 * payload.
1174473c7391SStefano Garzarella 	 */
117571dc9ec9SBobby Eshleman 	if (len <= GOOD_COPY_LEN && !skb_queue_empty(&vvs->rx_queue)) {
117671dc9ec9SBobby Eshleman 		struct virtio_vsock_hdr *last_hdr;
117771dc9ec9SBobby Eshleman 		struct sk_buff *last_skb;
1178473c7391SStefano Garzarella 
117971dc9ec9SBobby Eshleman 		last_skb = skb_peek_tail(&vvs->rx_queue);
118071dc9ec9SBobby Eshleman 		last_hdr = virtio_vsock_hdr(last_skb);
1181473c7391SStefano Garzarella 
1182473c7391SStefano Garzarella 		/* If there is space in the last packet queued, we copy the
1183e4b1ef15SArseny Krasnov 		 * new packet in its buffer. We avoid this if the last packet
11849af8f106SArseny Krasnov 		 * queued has VIRTIO_VSOCK_SEQ_EOM set, because this is
11859af8f106SArseny Krasnov 		 * delimiter of SEQPACKET message, so 'pkt' is the first packet
11869af8f106SArseny Krasnov 		 * of a new message.
1187473c7391SStefano Garzarella 		 */
118871dc9ec9SBobby Eshleman 		if (skb->len < skb_tailroom(last_skb) &&
118971dc9ec9SBobby Eshleman 		    !(le32_to_cpu(last_hdr->flags) & VIRTIO_VSOCK_SEQ_EOM)) {
119071dc9ec9SBobby Eshleman 			memcpy(skb_put(last_skb, skb->len), skb->data, skb->len);
1191473c7391SStefano Garzarella 			free_pkt = true;
119271dc9ec9SBobby Eshleman 			last_hdr->flags |= hdr->flags;
1193f7154d96SArseniy Krasnov 			le32_add_cpu(&last_hdr->len, len);
1194473c7391SStefano Garzarella 			goto out;
1195473c7391SStefano Garzarella 		}
1196473c7391SStefano Garzarella 	}
1197473c7391SStefano Garzarella 
119871dc9ec9SBobby Eshleman 	__skb_queue_tail(&vvs->rx_queue, skb);
1199473c7391SStefano Garzarella 
1200473c7391SStefano Garzarella out:
1201473c7391SStefano Garzarella 	spin_unlock_bh(&vvs->rx_lock);
1202473c7391SStefano Garzarella 	if (free_pkt)
120371dc9ec9SBobby Eshleman 		kfree_skb(skb);
1204473c7391SStefano Garzarella }
1205473c7391SStefano Garzarella 
120606a8fc78SAsias He static int
virtio_transport_recv_connected(struct sock * sk,struct sk_buff * skb)120706a8fc78SAsias He virtio_transport_recv_connected(struct sock *sk,
120871dc9ec9SBobby Eshleman 				struct sk_buff *skb)
120906a8fc78SAsias He {
121071dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
121106a8fc78SAsias He 	struct vsock_sock *vsk = vsock_sk(sk);
121206a8fc78SAsias He 	int err = 0;
121306a8fc78SAsias He 
121471dc9ec9SBobby Eshleman 	switch (le16_to_cpu(hdr->op)) {
121506a8fc78SAsias He 	case VIRTIO_VSOCK_OP_RW:
121671dc9ec9SBobby Eshleman 		virtio_transport_recv_enqueue(vsk, skb);
121739f1ed33SArseniy Krasnov 		vsock_data_ready(sk);
121806a8fc78SAsias He 		return err;
1219e3ea110dSHarshavardhan Unnibhavi 	case VIRTIO_VSOCK_OP_CREDIT_REQUEST:
1220e3ea110dSHarshavardhan Unnibhavi 		virtio_transport_send_credit_update(vsk);
1221e3ea110dSHarshavardhan Unnibhavi 		break;
122206a8fc78SAsias He 	case VIRTIO_VSOCK_OP_CREDIT_UPDATE:
122306a8fc78SAsias He 		sk->sk_write_space(sk);
122406a8fc78SAsias He 		break;
122506a8fc78SAsias He 	case VIRTIO_VSOCK_OP_SHUTDOWN:
122671dc9ec9SBobby Eshleman 		if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_RCV)
122706a8fc78SAsias He 			vsk->peer_shutdown |= RCV_SHUTDOWN;
122871dc9ec9SBobby Eshleman 		if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_SEND)
122906a8fc78SAsias He 			vsk->peer_shutdown |= SEND_SHUTDOWN;
12302ebff71eSFilippo Storniolo 		if (vsk->peer_shutdown == SHUTDOWN_MASK) {
12312ebff71eSFilippo Storniolo 			if (vsock_stream_has_data(vsk) <= 0 && !sock_flag(sk, SOCK_DONE)) {
1232ad8a7220SStefano Garzarella 				(void)virtio_transport_reset(vsk, NULL);
1233ad8a7220SStefano Garzarella 				virtio_transport_do_close(vsk, true);
123442f5cda5SStephen Barber 			}
12352ebff71eSFilippo Storniolo 			/* Remove this socket anyway because the remote peer sent
12362ebff71eSFilippo Storniolo 			 * the shutdown. This way a new connection will succeed
12372ebff71eSFilippo Storniolo 			 * if the remote peer uses the same source port,
12382ebff71eSFilippo Storniolo 			 * even if the old socket is still unreleased, but now disconnected.
12392ebff71eSFilippo Storniolo 			 */
12402ebff71eSFilippo Storniolo 			vsock_remove_sock(vsk);
12412ebff71eSFilippo Storniolo 		}
124271dc9ec9SBobby Eshleman 		if (le32_to_cpu(virtio_vsock_hdr(skb)->flags))
124306a8fc78SAsias He 			sk->sk_state_change(sk);
124406a8fc78SAsias He 		break;
124506a8fc78SAsias He 	case VIRTIO_VSOCK_OP_RST:
124606a8fc78SAsias He 		virtio_transport_do_close(vsk, true);
124706a8fc78SAsias He 		break;
124806a8fc78SAsias He 	default:
124906a8fc78SAsias He 		err = -EINVAL;
125006a8fc78SAsias He 		break;
125106a8fc78SAsias He 	}
125206a8fc78SAsias He 
125371dc9ec9SBobby Eshleman 	kfree_skb(skb);
125406a8fc78SAsias He 	return err;
125506a8fc78SAsias He }
125606a8fc78SAsias He 
125706a8fc78SAsias He static void
virtio_transport_recv_disconnecting(struct sock * sk,struct sk_buff * skb)125806a8fc78SAsias He virtio_transport_recv_disconnecting(struct sock *sk,
125971dc9ec9SBobby Eshleman 				    struct sk_buff *skb)
126006a8fc78SAsias He {
126171dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
126206a8fc78SAsias He 	struct vsock_sock *vsk = vsock_sk(sk);
126306a8fc78SAsias He 
126471dc9ec9SBobby Eshleman 	if (le16_to_cpu(hdr->op) == VIRTIO_VSOCK_OP_RST)
126506a8fc78SAsias He 		virtio_transport_do_close(vsk, true);
126606a8fc78SAsias He }
126706a8fc78SAsias He 
126806a8fc78SAsias He static int
virtio_transport_send_response(struct vsock_sock * vsk,struct sk_buff * skb)126906a8fc78SAsias He virtio_transport_send_response(struct vsock_sock *vsk,
127071dc9ec9SBobby Eshleman 			       struct sk_buff *skb)
127106a8fc78SAsias He {
127271dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
127306a8fc78SAsias He 	struct virtio_vsock_pkt_info info = {
127406a8fc78SAsias He 		.op = VIRTIO_VSOCK_OP_RESPONSE,
127571dc9ec9SBobby Eshleman 		.remote_cid = le64_to_cpu(hdr->src_cid),
127671dc9ec9SBobby Eshleman 		.remote_port = le32_to_cpu(hdr->src_port),
127706a8fc78SAsias He 		.reply = true,
127836d277baSPeng Tao 		.vsk = vsk,
127906a8fc78SAsias He 	};
128006a8fc78SAsias He 
128106a8fc78SAsias He 	return virtio_transport_send_pkt_info(vsk, &info);
128206a8fc78SAsias He }
128306a8fc78SAsias He 
virtio_transport_space_update(struct sock * sk,struct sk_buff * skb)1284c0cfa2d8SStefano Garzarella static bool virtio_transport_space_update(struct sock *sk,
128571dc9ec9SBobby Eshleman 					  struct sk_buff *skb)
1286c0cfa2d8SStefano Garzarella {
128771dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
1288c0cfa2d8SStefano Garzarella 	struct vsock_sock *vsk = vsock_sk(sk);
1289c0cfa2d8SStefano Garzarella 	struct virtio_vsock_sock *vvs = vsk->trans;
1290c0cfa2d8SStefano Garzarella 	bool space_available;
1291c0cfa2d8SStefano Garzarella 
1292c0cfa2d8SStefano Garzarella 	/* Listener sockets are not associated with any transport, so we are
1293c0cfa2d8SStefano Garzarella 	 * not able to take the state to see if there is space available in the
1294c0cfa2d8SStefano Garzarella 	 * remote peer, but since they are only used to receive requests, we
1295c0cfa2d8SStefano Garzarella 	 * can assume that there is always space available in the other peer.
1296c0cfa2d8SStefano Garzarella 	 */
1297c0cfa2d8SStefano Garzarella 	if (!vvs)
1298c0cfa2d8SStefano Garzarella 		return true;
1299c0cfa2d8SStefano Garzarella 
1300c0cfa2d8SStefano Garzarella 	/* buf_alloc and fwd_cnt is always included in the hdr */
1301c0cfa2d8SStefano Garzarella 	spin_lock_bh(&vvs->tx_lock);
130271dc9ec9SBobby Eshleman 	vvs->peer_buf_alloc = le32_to_cpu(hdr->buf_alloc);
130371dc9ec9SBobby Eshleman 	vvs->peer_fwd_cnt = le32_to_cpu(hdr->fwd_cnt);
1304c0cfa2d8SStefano Garzarella 	space_available = virtio_transport_has_space(vsk);
1305c0cfa2d8SStefano Garzarella 	spin_unlock_bh(&vvs->tx_lock);
1306c0cfa2d8SStefano Garzarella 	return space_available;
1307c0cfa2d8SStefano Garzarella }
1308c0cfa2d8SStefano Garzarella 
130906a8fc78SAsias He /* Handle server socket */
131006a8fc78SAsias He static int
virtio_transport_recv_listen(struct sock * sk,struct sk_buff * skb,struct virtio_transport * t)131171dc9ec9SBobby Eshleman virtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb,
1312c0cfa2d8SStefano Garzarella 			     struct virtio_transport *t)
131306a8fc78SAsias He {
131471dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
131506a8fc78SAsias He 	struct vsock_sock *vsk = vsock_sk(sk);
131606a8fc78SAsias He 	struct vsock_sock *vchild;
131706a8fc78SAsias He 	struct sock *child;
1318c0cfa2d8SStefano Garzarella 	int ret;
131906a8fc78SAsias He 
132071dc9ec9SBobby Eshleman 	if (le16_to_cpu(hdr->op) != VIRTIO_VSOCK_OP_REQUEST) {
132171dc9ec9SBobby Eshleman 		virtio_transport_reset_no_sock(t, skb);
132206a8fc78SAsias He 		return -EINVAL;
132306a8fc78SAsias He 	}
132406a8fc78SAsias He 
132506a8fc78SAsias He 	if (sk_acceptq_is_full(sk)) {
132671dc9ec9SBobby Eshleman 		virtio_transport_reset_no_sock(t, skb);
132706a8fc78SAsias He 		return -ENOMEM;
132806a8fc78SAsias He 	}
132906a8fc78SAsias He 
1330897617a4SMichal Luczaj 	/* __vsock_release() might have already flushed accept_queue.
1331897617a4SMichal Luczaj 	 * Subsequent enqueues would lead to a memory leak.
1332897617a4SMichal Luczaj 	 */
1333897617a4SMichal Luczaj 	if (sk->sk_shutdown == SHUTDOWN_MASK) {
1334897617a4SMichal Luczaj 		virtio_transport_reset_no_sock(t, skb);
1335897617a4SMichal Luczaj 		return -ESHUTDOWN;
1336897617a4SMichal Luczaj 	}
1337897617a4SMichal Luczaj 
1338b9ca2f5fSStefano Garzarella 	child = vsock_create_connected(sk);
133906a8fc78SAsias He 	if (!child) {
134071dc9ec9SBobby Eshleman 		virtio_transport_reset_no_sock(t, skb);
134106a8fc78SAsias He 		return -ENOMEM;
134206a8fc78SAsias He 	}
134306a8fc78SAsias He 
13447976a11bSEric Dumazet 	sk_acceptq_added(sk);
134506a8fc78SAsias He 
134606a8fc78SAsias He 	lock_sock_nested(child, SINGLE_DEPTH_NESTING);
134706a8fc78SAsias He 
13483b4477d2SStefan Hajnoczi 	child->sk_state = TCP_ESTABLISHED;
134906a8fc78SAsias He 
135006a8fc78SAsias He 	vchild = vsock_sk(child);
135171dc9ec9SBobby Eshleman 	vsock_addr_init(&vchild->local_addr, le64_to_cpu(hdr->dst_cid),
135271dc9ec9SBobby Eshleman 			le32_to_cpu(hdr->dst_port));
135371dc9ec9SBobby Eshleman 	vsock_addr_init(&vchild->remote_addr, le64_to_cpu(hdr->src_cid),
135471dc9ec9SBobby Eshleman 			le32_to_cpu(hdr->src_port));
135506a8fc78SAsias He 
1356c0cfa2d8SStefano Garzarella 	ret = vsock_assign_transport(vchild, vsk);
1357c0cfa2d8SStefano Garzarella 	/* Transport assigned (looking at remote_addr) must be the same
1358c0cfa2d8SStefano Garzarella 	 * where we received the request.
1359c0cfa2d8SStefano Garzarella 	 */
1360c0cfa2d8SStefano Garzarella 	if (ret || vchild->transport != &t->transport) {
1361c0cfa2d8SStefano Garzarella 		release_sock(child);
136271dc9ec9SBobby Eshleman 		virtio_transport_reset_no_sock(t, skb);
1363c0cfa2d8SStefano Garzarella 		sock_put(child);
1364c0cfa2d8SStefano Garzarella 		return ret;
1365c0cfa2d8SStefano Garzarella 	}
1366c0cfa2d8SStefano Garzarella 
136771dc9ec9SBobby Eshleman 	if (virtio_transport_space_update(child, skb))
1368c0cfa2d8SStefano Garzarella 		child->sk_write_space(child);
1369c0cfa2d8SStefano Garzarella 
137006a8fc78SAsias He 	vsock_insert_connected(vchild);
137106a8fc78SAsias He 	vsock_enqueue_accept(sk, child);
137271dc9ec9SBobby Eshleman 	virtio_transport_send_response(vchild, skb);
137306a8fc78SAsias He 
137406a8fc78SAsias He 	release_sock(child);
137506a8fc78SAsias He 
137606a8fc78SAsias He 	sk->sk_data_ready(sk);
137706a8fc78SAsias He 	return 0;
137806a8fc78SAsias He }
137906a8fc78SAsias He 
virtio_transport_valid_type(u16 type)1380e4b1ef15SArseny Krasnov static bool virtio_transport_valid_type(u16 type)
1381e4b1ef15SArseny Krasnov {
1382e4b1ef15SArseny Krasnov 	return (type == VIRTIO_VSOCK_TYPE_STREAM) ||
1383e4b1ef15SArseny Krasnov 	       (type == VIRTIO_VSOCK_TYPE_SEQPACKET);
1384e4b1ef15SArseny Krasnov }
1385e4b1ef15SArseny Krasnov 
138606a8fc78SAsias He /* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex
138706a8fc78SAsias He  * lock.
138806a8fc78SAsias He  */
virtio_transport_recv_pkt(struct virtio_transport * t,struct sk_buff * skb)13894c7246dcSStefano Garzarella void virtio_transport_recv_pkt(struct virtio_transport *t,
139071dc9ec9SBobby Eshleman 			       struct sk_buff *skb)
139106a8fc78SAsias He {
139271dc9ec9SBobby Eshleman 	struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb);
139306a8fc78SAsias He 	struct sockaddr_vm src, dst;
139406a8fc78SAsias He 	struct vsock_sock *vsk;
139506a8fc78SAsias He 	struct sock *sk;
139606a8fc78SAsias He 	bool space_available;
139706a8fc78SAsias He 
139871dc9ec9SBobby Eshleman 	vsock_addr_init(&src, le64_to_cpu(hdr->src_cid),
139971dc9ec9SBobby Eshleman 			le32_to_cpu(hdr->src_port));
140071dc9ec9SBobby Eshleman 	vsock_addr_init(&dst, le64_to_cpu(hdr->dst_cid),
140171dc9ec9SBobby Eshleman 			le32_to_cpu(hdr->dst_port));
140206a8fc78SAsias He 
140306a8fc78SAsias He 	trace_virtio_transport_recv_pkt(src.svm_cid, src.svm_port,
140406a8fc78SAsias He 					dst.svm_cid, dst.svm_port,
140571dc9ec9SBobby Eshleman 					le32_to_cpu(hdr->len),
140671dc9ec9SBobby Eshleman 					le16_to_cpu(hdr->type),
140771dc9ec9SBobby Eshleman 					le16_to_cpu(hdr->op),
140871dc9ec9SBobby Eshleman 					le32_to_cpu(hdr->flags),
140971dc9ec9SBobby Eshleman 					le32_to_cpu(hdr->buf_alloc),
141071dc9ec9SBobby Eshleman 					le32_to_cpu(hdr->fwd_cnt));
141106a8fc78SAsias He 
141271dc9ec9SBobby Eshleman 	if (!virtio_transport_valid_type(le16_to_cpu(hdr->type))) {
141371dc9ec9SBobby Eshleman 		(void)virtio_transport_reset_no_sock(t, skb);
141406a8fc78SAsias He 		goto free_pkt;
141506a8fc78SAsias He 	}
141606a8fc78SAsias He 
141706a8fc78SAsias He 	/* The socket must be in connected or bound table
141806a8fc78SAsias He 	 * otherwise send reset back
141906a8fc78SAsias He 	 */
142006a8fc78SAsias He 	sk = vsock_find_connected_socket(&src, &dst);
142106a8fc78SAsias He 	if (!sk) {
142206a8fc78SAsias He 		sk = vsock_find_bound_socket(&dst);
142306a8fc78SAsias He 		if (!sk) {
142471dc9ec9SBobby Eshleman 			(void)virtio_transport_reset_no_sock(t, skb);
142506a8fc78SAsias He 			goto free_pkt;
142606a8fc78SAsias He 		}
142706a8fc78SAsias He 	}
142806a8fc78SAsias He 
142971dc9ec9SBobby Eshleman 	if (virtio_transport_get_type(sk) != le16_to_cpu(hdr->type)) {
143071dc9ec9SBobby Eshleman 		(void)virtio_transport_reset_no_sock(t, skb);
1431e4b1ef15SArseny Krasnov 		sock_put(sk);
1432e4b1ef15SArseny Krasnov 		goto free_pkt;
1433e4b1ef15SArseny Krasnov 	}
1434e4b1ef15SArseny Krasnov 
1435f9d2b1e1SBobby Eshleman 	if (!skb_set_owner_sk_safe(skb, sk)) {
1436f9d2b1e1SBobby Eshleman 		WARN_ONCE(1, "receiving vsock socket has sk_refcnt == 0\n");
1437f9d2b1e1SBobby Eshleman 		goto free_pkt;
1438f9d2b1e1SBobby Eshleman 	}
1439f9d2b1e1SBobby Eshleman 
144006a8fc78SAsias He 	vsk = vsock_sk(sk);
144106a8fc78SAsias He 
144206a8fc78SAsias He 	lock_sock(sk);
144306a8fc78SAsias He 
1444d88b249eSStefano Garzarella 	/* Check if sk has been closed or assigned to another transport before
1445d88b249eSStefano Garzarella 	 * lock_sock (note: listener sockets are not assigned to any transport)
1446d88b249eSStefano Garzarella 	 */
1447d88b249eSStefano Garzarella 	if (sock_flag(sk, SOCK_DONE) ||
1448d88b249eSStefano Garzarella 	    (sk->sk_state != TCP_LISTEN && vsk->transport != &t->transport)) {
144971dc9ec9SBobby Eshleman 		(void)virtio_transport_reset_no_sock(t, skb);
14508692cefcSJia He 		release_sock(sk);
14518692cefcSJia He 		sock_put(sk);
14528692cefcSJia He 		goto free_pkt;
14538692cefcSJia He 	}
14548692cefcSJia He 
145571dc9ec9SBobby Eshleman 	space_available = virtio_transport_space_update(sk, skb);
1456ce7536bcSStefano Garzarella 
145706a8fc78SAsias He 	/* Update CID in case it has changed after a transport reset event */
14581db8f5fcSWei Wang 	if (vsk->local_addr.svm_cid != VMADDR_CID_ANY)
145906a8fc78SAsias He 		vsk->local_addr.svm_cid = dst.svm_cid;
146006a8fc78SAsias He 
146106a8fc78SAsias He 	if (space_available)
146206a8fc78SAsias He 		sk->sk_write_space(sk);
146306a8fc78SAsias He 
146406a8fc78SAsias He 	switch (sk->sk_state) {
14653b4477d2SStefan Hajnoczi 	case TCP_LISTEN:
146671dc9ec9SBobby Eshleman 		virtio_transport_recv_listen(sk, skb, t);
146771dc9ec9SBobby Eshleman 		kfree_skb(skb);
146806a8fc78SAsias He 		break;
14693b4477d2SStefan Hajnoczi 	case TCP_SYN_SENT:
147071dc9ec9SBobby Eshleman 		virtio_transport_recv_connecting(sk, skb);
147171dc9ec9SBobby Eshleman 		kfree_skb(skb);
147206a8fc78SAsias He 		break;
14733b4477d2SStefan Hajnoczi 	case TCP_ESTABLISHED:
147471dc9ec9SBobby Eshleman 		virtio_transport_recv_connected(sk, skb);
147506a8fc78SAsias He 		break;
14763b4477d2SStefan Hajnoczi 	case TCP_CLOSING:
147771dc9ec9SBobby Eshleman 		virtio_transport_recv_disconnecting(sk, skb);
147871dc9ec9SBobby Eshleman 		kfree_skb(skb);
147906a8fc78SAsias He 		break;
148006a8fc78SAsias He 	default:
148171dc9ec9SBobby Eshleman 		(void)virtio_transport_reset_no_sock(t, skb);
148271dc9ec9SBobby Eshleman 		kfree_skb(skb);
148306a8fc78SAsias He 		break;
148406a8fc78SAsias He 	}
1485c0cfa2d8SStefano Garzarella 
148606a8fc78SAsias He 	release_sock(sk);
148706a8fc78SAsias He 
148806a8fc78SAsias He 	/* Release refcnt obtained when we fetched this socket out of the
148906a8fc78SAsias He 	 * bound or connected list.
149006a8fc78SAsias He 	 */
149106a8fc78SAsias He 	sock_put(sk);
149206a8fc78SAsias He 	return;
149306a8fc78SAsias He 
149406a8fc78SAsias He free_pkt:
149571dc9ec9SBobby Eshleman 	kfree_skb(skb);
149606a8fc78SAsias He }
149706a8fc78SAsias He EXPORT_SYMBOL_GPL(virtio_transport_recv_pkt);
149806a8fc78SAsias He 
149971dc9ec9SBobby Eshleman /* Remove skbs found in a queue that have a vsk that matches.
150071dc9ec9SBobby Eshleman  *
150171dc9ec9SBobby Eshleman  * Each skb is freed.
150271dc9ec9SBobby Eshleman  *
150371dc9ec9SBobby Eshleman  * Returns the count of skbs that were reply packets.
150471dc9ec9SBobby Eshleman  */
virtio_transport_purge_skbs(void * vsk,struct sk_buff_head * queue)150571dc9ec9SBobby Eshleman int virtio_transport_purge_skbs(void *vsk, struct sk_buff_head *queue)
150606a8fc78SAsias He {
150771dc9ec9SBobby Eshleman 	struct sk_buff_head freeme;
150871dc9ec9SBobby Eshleman 	struct sk_buff *skb, *tmp;
150971dc9ec9SBobby Eshleman 	int cnt = 0;
151071dc9ec9SBobby Eshleman 
151171dc9ec9SBobby Eshleman 	skb_queue_head_init(&freeme);
151271dc9ec9SBobby Eshleman 
151371dc9ec9SBobby Eshleman 	spin_lock_bh(&queue->lock);
151471dc9ec9SBobby Eshleman 	skb_queue_walk_safe(queue, skb, tmp) {
151571dc9ec9SBobby Eshleman 		if (vsock_sk(skb->sk) != vsk)
151671dc9ec9SBobby Eshleman 			continue;
151771dc9ec9SBobby Eshleman 
151871dc9ec9SBobby Eshleman 		__skb_unlink(skb, queue);
151971dc9ec9SBobby Eshleman 		__skb_queue_tail(&freeme, skb);
152071dc9ec9SBobby Eshleman 
152171dc9ec9SBobby Eshleman 		if (virtio_vsock_skb_reply(skb))
152271dc9ec9SBobby Eshleman 			cnt++;
152306a8fc78SAsias He 	}
152471dc9ec9SBobby Eshleman 	spin_unlock_bh(&queue->lock);
152571dc9ec9SBobby Eshleman 
152671dc9ec9SBobby Eshleman 	__skb_queue_purge(&freeme);
152771dc9ec9SBobby Eshleman 
152871dc9ec9SBobby Eshleman 	return cnt;
152971dc9ec9SBobby Eshleman }
153071dc9ec9SBobby Eshleman EXPORT_SYMBOL_GPL(virtio_transport_purge_skbs);
153106a8fc78SAsias He 
virtio_transport_read_skb(struct vsock_sock * vsk,skb_read_actor_t recv_actor)1532634f1a71SBobby Eshleman int virtio_transport_read_skb(struct vsock_sock *vsk, skb_read_actor_t recv_actor)
1533634f1a71SBobby Eshleman {
1534634f1a71SBobby Eshleman 	struct virtio_vsock_sock *vvs = vsk->trans;
1535634f1a71SBobby Eshleman 	struct sock *sk = sk_vsock(vsk);
153666cd51deSMichal Luczaj 	struct virtio_vsock_hdr *hdr;
1537634f1a71SBobby Eshleman 	struct sk_buff *skb;
1538634f1a71SBobby Eshleman 	int off = 0;
1539634f1a71SBobby Eshleman 	int err;
1540634f1a71SBobby Eshleman 
1541634f1a71SBobby Eshleman 	spin_lock_bh(&vvs->rx_lock);
1542634f1a71SBobby Eshleman 	/* Use __skb_recv_datagram() for race-free handling of the receive. It
1543634f1a71SBobby Eshleman 	 * works for types other than dgrams.
1544634f1a71SBobby Eshleman 	 */
1545634f1a71SBobby Eshleman 	skb = __skb_recv_datagram(sk, &vvs->rx_queue, MSG_DONTWAIT, &off, &err);
154666cd51deSMichal Luczaj 	if (!skb) {
154766cd51deSMichal Luczaj 		spin_unlock_bh(&vvs->rx_lock);
154866cd51deSMichal Luczaj 		return err;
154966cd51deSMichal Luczaj 	}
155066cd51deSMichal Luczaj 
155166cd51deSMichal Luczaj 	hdr = virtio_vsock_hdr(skb);
15529dd9b160SMichal Luczaj 	if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM)
15539dd9b160SMichal Luczaj 		vvs->msg_count--;
15549dd9b160SMichal Luczaj 
155566cd51deSMichal Luczaj 	virtio_transport_dec_rx_pkt(vvs, le32_to_cpu(hdr->len));
1556634f1a71SBobby Eshleman 	spin_unlock_bh(&vvs->rx_lock);
1557634f1a71SBobby Eshleman 
155866cd51deSMichal Luczaj 	virtio_transport_send_credit_update(vsk);
1559634f1a71SBobby Eshleman 
156078fa0d61SJohn Fastabend 	return recv_actor(sk, skb);
1561634f1a71SBobby Eshleman }
1562634f1a71SBobby Eshleman EXPORT_SYMBOL_GPL(virtio_transport_read_skb);
1563634f1a71SBobby Eshleman 
virtio_transport_notify_set_rcvlowat(struct vsock_sock * vsk,int val)156494e5f642SArseniy Krasnov int virtio_transport_notify_set_rcvlowat(struct vsock_sock *vsk, int val)
156594e5f642SArseniy Krasnov {
156694e5f642SArseniy Krasnov 	struct virtio_vsock_sock *vvs = vsk->trans;
156794e5f642SArseniy Krasnov 	bool send_update;
156894e5f642SArseniy Krasnov 
156994e5f642SArseniy Krasnov 	spin_lock_bh(&vvs->rx_lock);
157094e5f642SArseniy Krasnov 
157194e5f642SArseniy Krasnov 	/* If number of available bytes is less than new SO_RCVLOWAT value,
157294e5f642SArseniy Krasnov 	 * kick sender to send more data, because sender may sleep in its
157394e5f642SArseniy Krasnov 	 * 'send()' syscall waiting for enough space at our side. Also
157494e5f642SArseniy Krasnov 	 * don't send credit update when peer already knows actual value -
157594e5f642SArseniy Krasnov 	 * such transmission will be useless.
157694e5f642SArseniy Krasnov 	 */
157794e5f642SArseniy Krasnov 	send_update = (vvs->rx_bytes < val) &&
157894e5f642SArseniy Krasnov 		      (vvs->fwd_cnt != vvs->last_fwd_cnt);
157994e5f642SArseniy Krasnov 
158094e5f642SArseniy Krasnov 	spin_unlock_bh(&vvs->rx_lock);
158194e5f642SArseniy Krasnov 
158294e5f642SArseniy Krasnov 	if (send_update) {
158394e5f642SArseniy Krasnov 		int err;
158494e5f642SArseniy Krasnov 
158594e5f642SArseniy Krasnov 		err = virtio_transport_send_credit_update(vsk);
158694e5f642SArseniy Krasnov 		if (err < 0)
158794e5f642SArseniy Krasnov 			return err;
158894e5f642SArseniy Krasnov 	}
158994e5f642SArseniy Krasnov 
159094e5f642SArseniy Krasnov 	return 0;
159194e5f642SArseniy Krasnov }
159294e5f642SArseniy Krasnov EXPORT_SYMBOL_GPL(virtio_transport_notify_set_rcvlowat);
159394e5f642SArseniy Krasnov 
159406a8fc78SAsias He MODULE_LICENSE("GPL v2");
159506a8fc78SAsias He MODULE_AUTHOR("Asias He");
159606a8fc78SAsias He MODULE_DESCRIPTION("common code for virtio vsock");
1597