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