162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * common code for virtio vsock 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013-2015 Red Hat, Inc. 662306a36Sopenharmony_ci * Author: Asias He <asias@redhat.com> 762306a36Sopenharmony_ci * Stefan Hajnoczi <stefanha@redhat.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/spinlock.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/sched/signal.h> 1262306a36Sopenharmony_ci#include <linux/ctype.h> 1362306a36Sopenharmony_ci#include <linux/list.h> 1462306a36Sopenharmony_ci#include <linux/virtio_vsock.h> 1562306a36Sopenharmony_ci#include <uapi/linux/vsockmon.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <net/sock.h> 1862306a36Sopenharmony_ci#include <net/af_vsock.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 2162306a36Sopenharmony_ci#include <trace/events/vsock_virtio_transport_common.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* How long to wait for graceful shutdown of a connection */ 2462306a36Sopenharmony_ci#define VSOCK_CLOSE_TIMEOUT (8 * HZ) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Threshold for detecting small packets to copy */ 2762306a36Sopenharmony_ci#define GOOD_COPY_LEN 128 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic const struct virtio_transport * 3062306a36Sopenharmony_civirtio_transport_get_ops(struct vsock_sock *vsk) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci const struct vsock_transport *t = vsock_core_get_transport(vsk); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (WARN_ON(!t)) 3562306a36Sopenharmony_ci return NULL; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return container_of(t, struct virtio_transport, transport); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Returns a new packet on success, otherwise returns NULL. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * If NULL is returned, errp is set to a negative errno. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistatic struct sk_buff * 4562306a36Sopenharmony_civirtio_transport_alloc_skb(struct virtio_vsock_pkt_info *info, 4662306a36Sopenharmony_ci size_t len, 4762306a36Sopenharmony_ci u32 src_cid, 4862306a36Sopenharmony_ci u32 src_port, 4962306a36Sopenharmony_ci u32 dst_cid, 5062306a36Sopenharmony_ci u32 dst_port) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci const size_t skb_len = VIRTIO_VSOCK_SKB_HEADROOM + len; 5362306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr; 5462306a36Sopenharmony_ci struct sk_buff *skb; 5562306a36Sopenharmony_ci void *payload; 5662306a36Sopenharmony_ci int err; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci skb = virtio_vsock_alloc_skb(skb_len, GFP_KERNEL); 5962306a36Sopenharmony_ci if (!skb) 6062306a36Sopenharmony_ci return NULL; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci hdr = virtio_vsock_hdr(skb); 6362306a36Sopenharmony_ci hdr->type = cpu_to_le16(info->type); 6462306a36Sopenharmony_ci hdr->op = cpu_to_le16(info->op); 6562306a36Sopenharmony_ci hdr->src_cid = cpu_to_le64(src_cid); 6662306a36Sopenharmony_ci hdr->dst_cid = cpu_to_le64(dst_cid); 6762306a36Sopenharmony_ci hdr->src_port = cpu_to_le32(src_port); 6862306a36Sopenharmony_ci hdr->dst_port = cpu_to_le32(dst_port); 6962306a36Sopenharmony_ci hdr->flags = cpu_to_le32(info->flags); 7062306a36Sopenharmony_ci hdr->len = cpu_to_le32(len); 7162306a36Sopenharmony_ci hdr->buf_alloc = cpu_to_le32(0); 7262306a36Sopenharmony_ci hdr->fwd_cnt = cpu_to_le32(0); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (info->msg && len > 0) { 7562306a36Sopenharmony_ci payload = skb_put(skb, len); 7662306a36Sopenharmony_ci err = memcpy_from_msg(payload, info->msg, len); 7762306a36Sopenharmony_ci if (err) 7862306a36Sopenharmony_ci goto out; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (msg_data_left(info->msg) == 0 && 8162306a36Sopenharmony_ci info->type == VIRTIO_VSOCK_TYPE_SEQPACKET) { 8262306a36Sopenharmony_ci hdr->flags |= cpu_to_le32(VIRTIO_VSOCK_SEQ_EOM); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (info->msg->msg_flags & MSG_EOR) 8562306a36Sopenharmony_ci hdr->flags |= cpu_to_le32(VIRTIO_VSOCK_SEQ_EOR); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (info->reply) 9062306a36Sopenharmony_ci virtio_vsock_skb_set_reply(skb); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci trace_virtio_transport_alloc_pkt(src_cid, src_port, 9362306a36Sopenharmony_ci dst_cid, dst_port, 9462306a36Sopenharmony_ci len, 9562306a36Sopenharmony_ci info->type, 9662306a36Sopenharmony_ci info->op, 9762306a36Sopenharmony_ci info->flags); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (info->vsk && !skb_set_owner_sk_safe(skb, sk_vsock(info->vsk))) { 10062306a36Sopenharmony_ci WARN_ONCE(1, "failed to allocate skb on vsock socket with sk_refcnt == 0\n"); 10162306a36Sopenharmony_ci goto out; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci return skb; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciout: 10762306a36Sopenharmony_ci kfree_skb(skb); 10862306a36Sopenharmony_ci return NULL; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* Packet capture */ 11262306a36Sopenharmony_cistatic struct sk_buff *virtio_transport_build_skb(void *opaque) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct virtio_vsock_hdr *pkt_hdr; 11562306a36Sopenharmony_ci struct sk_buff *pkt = opaque; 11662306a36Sopenharmony_ci struct af_vsockmon_hdr *hdr; 11762306a36Sopenharmony_ci struct sk_buff *skb; 11862306a36Sopenharmony_ci size_t payload_len; 11962306a36Sopenharmony_ci void *payload_buf; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* A packet could be split to fit the RX buffer, so we can retrieve 12262306a36Sopenharmony_ci * the payload length from the header and the buffer pointer taking 12362306a36Sopenharmony_ci * care of the offset in the original packet. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci pkt_hdr = virtio_vsock_hdr(pkt); 12662306a36Sopenharmony_ci payload_len = pkt->len; 12762306a36Sopenharmony_ci payload_buf = pkt->data; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci skb = alloc_skb(sizeof(*hdr) + sizeof(*pkt_hdr) + payload_len, 13062306a36Sopenharmony_ci GFP_ATOMIC); 13162306a36Sopenharmony_ci if (!skb) 13262306a36Sopenharmony_ci return NULL; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci hdr = skb_put(skb, sizeof(*hdr)); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* pkt->hdr is little-endian so no need to byteswap here */ 13762306a36Sopenharmony_ci hdr->src_cid = pkt_hdr->src_cid; 13862306a36Sopenharmony_ci hdr->src_port = pkt_hdr->src_port; 13962306a36Sopenharmony_ci hdr->dst_cid = pkt_hdr->dst_cid; 14062306a36Sopenharmony_ci hdr->dst_port = pkt_hdr->dst_port; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci hdr->transport = cpu_to_le16(AF_VSOCK_TRANSPORT_VIRTIO); 14362306a36Sopenharmony_ci hdr->len = cpu_to_le16(sizeof(*pkt_hdr)); 14462306a36Sopenharmony_ci memset(hdr->reserved, 0, sizeof(hdr->reserved)); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci switch (le16_to_cpu(pkt_hdr->op)) { 14762306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_REQUEST: 14862306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_RESPONSE: 14962306a36Sopenharmony_ci hdr->op = cpu_to_le16(AF_VSOCK_OP_CONNECT); 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_RST: 15262306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_SHUTDOWN: 15362306a36Sopenharmony_ci hdr->op = cpu_to_le16(AF_VSOCK_OP_DISCONNECT); 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_RW: 15662306a36Sopenharmony_ci hdr->op = cpu_to_le16(AF_VSOCK_OP_PAYLOAD); 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_CREDIT_UPDATE: 15962306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_CREDIT_REQUEST: 16062306a36Sopenharmony_ci hdr->op = cpu_to_le16(AF_VSOCK_OP_CONTROL); 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci default: 16362306a36Sopenharmony_ci hdr->op = cpu_to_le16(AF_VSOCK_OP_UNKNOWN); 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci skb_put_data(skb, pkt_hdr, sizeof(*pkt_hdr)); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (payload_len) { 17062306a36Sopenharmony_ci skb_put_data(skb, payload_buf, payload_len); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return skb; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_civoid virtio_transport_deliver_tap_pkt(struct sk_buff *skb) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci if (virtio_vsock_skb_tap_delivered(skb)) 17962306a36Sopenharmony_ci return; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci vsock_deliver_tap(virtio_transport_build_skb, skb); 18262306a36Sopenharmony_ci virtio_vsock_skb_set_tap_delivered(skb); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_deliver_tap_pkt); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic u16 virtio_transport_get_type(struct sock *sk) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci if (sk->sk_type == SOCK_STREAM) 18962306a36Sopenharmony_ci return VIRTIO_VSOCK_TYPE_STREAM; 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci return VIRTIO_VSOCK_TYPE_SEQPACKET; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* This function can only be used on connecting/connected sockets, 19562306a36Sopenharmony_ci * since a socket assigned to a transport is required. 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Do not use on listener sockets! 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_cistatic int virtio_transport_send_pkt_info(struct vsock_sock *vsk, 20062306a36Sopenharmony_ci struct virtio_vsock_pkt_info *info) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci u32 src_cid, src_port, dst_cid, dst_port; 20362306a36Sopenharmony_ci const struct virtio_transport *t_ops; 20462306a36Sopenharmony_ci struct virtio_vsock_sock *vvs; 20562306a36Sopenharmony_ci u32 pkt_len = info->pkt_len; 20662306a36Sopenharmony_ci u32 rest_len; 20762306a36Sopenharmony_ci int ret; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci info->type = virtio_transport_get_type(sk_vsock(vsk)); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci t_ops = virtio_transport_get_ops(vsk); 21262306a36Sopenharmony_ci if (unlikely(!t_ops)) 21362306a36Sopenharmony_ci return -EFAULT; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci src_cid = t_ops->transport.get_local_cid(); 21662306a36Sopenharmony_ci src_port = vsk->local_addr.svm_port; 21762306a36Sopenharmony_ci if (!info->remote_cid) { 21862306a36Sopenharmony_ci dst_cid = vsk->remote_addr.svm_cid; 21962306a36Sopenharmony_ci dst_port = vsk->remote_addr.svm_port; 22062306a36Sopenharmony_ci } else { 22162306a36Sopenharmony_ci dst_cid = info->remote_cid; 22262306a36Sopenharmony_ci dst_port = info->remote_port; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci vvs = vsk->trans; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* virtio_transport_get_credit might return less than pkt_len credit */ 22862306a36Sopenharmony_ci pkt_len = virtio_transport_get_credit(vvs, pkt_len); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Do not send zero length OP_RW pkt */ 23162306a36Sopenharmony_ci if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW) 23262306a36Sopenharmony_ci return pkt_len; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci rest_len = pkt_len; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci do { 23762306a36Sopenharmony_ci struct sk_buff *skb; 23862306a36Sopenharmony_ci size_t skb_len; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci skb_len = min_t(u32, VIRTIO_VSOCK_MAX_PKT_BUF_SIZE, rest_len); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci skb = virtio_transport_alloc_skb(info, skb_len, 24362306a36Sopenharmony_ci src_cid, src_port, 24462306a36Sopenharmony_ci dst_cid, dst_port); 24562306a36Sopenharmony_ci if (!skb) { 24662306a36Sopenharmony_ci ret = -ENOMEM; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci virtio_transport_inc_tx_pkt(vvs, skb); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci ret = t_ops->send_pkt(skb); 25362306a36Sopenharmony_ci if (ret < 0) 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Both virtio and vhost 'send_pkt()' returns 'skb_len', 25762306a36Sopenharmony_ci * but for reliability use 'ret' instead of 'skb_len'. 25862306a36Sopenharmony_ci * Also if partial send happens (e.g. 'ret' != 'skb_len') 25962306a36Sopenharmony_ci * somehow, we break this loop, but account such returned 26062306a36Sopenharmony_ci * value in 'virtio_transport_put_credit()'. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci rest_len -= ret; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (WARN_ONCE(ret != skb_len, 26562306a36Sopenharmony_ci "'send_pkt()' returns %i, but %zu expected\n", 26662306a36Sopenharmony_ci ret, skb_len)) 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci } while (rest_len); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci virtio_transport_put_credit(vvs, rest_len); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Return number of bytes, if any data has been sent. */ 27362306a36Sopenharmony_ci if (rest_len != pkt_len) 27462306a36Sopenharmony_ci ret = pkt_len - rest_len; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return ret; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs, 28062306a36Sopenharmony_ci u32 len) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci if (vvs->rx_bytes + len > vvs->buf_alloc) 28362306a36Sopenharmony_ci return false; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci vvs->rx_bytes += len; 28662306a36Sopenharmony_ci return true; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs, 29062306a36Sopenharmony_ci u32 len) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci vvs->rx_bytes -= len; 29362306a36Sopenharmony_ci vvs->fwd_cnt += len; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_civoid virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct sk_buff *skb) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 30162306a36Sopenharmony_ci vvs->last_fwd_cnt = vvs->fwd_cnt; 30262306a36Sopenharmony_ci hdr->fwd_cnt = cpu_to_le32(vvs->fwd_cnt); 30362306a36Sopenharmony_ci hdr->buf_alloc = cpu_to_le32(vvs->buf_alloc); 30462306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_inc_tx_pkt); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ciu32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci u32 ret; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (!credit) 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci spin_lock_bh(&vvs->tx_lock); 31662306a36Sopenharmony_ci ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); 31762306a36Sopenharmony_ci if (ret > credit) 31862306a36Sopenharmony_ci ret = credit; 31962306a36Sopenharmony_ci vvs->tx_cnt += ret; 32062306a36Sopenharmony_ci spin_unlock_bh(&vvs->tx_lock); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return ret; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_get_credit); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_civoid virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci if (!credit) 32962306a36Sopenharmony_ci return; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci spin_lock_bh(&vvs->tx_lock); 33262306a36Sopenharmony_ci vvs->tx_cnt -= credit; 33362306a36Sopenharmony_ci spin_unlock_bh(&vvs->tx_lock); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_put_credit); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int virtio_transport_send_credit_update(struct vsock_sock *vsk) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct virtio_vsock_pkt_info info = { 34062306a36Sopenharmony_ci .op = VIRTIO_VSOCK_OP_CREDIT_UPDATE, 34162306a36Sopenharmony_ci .vsk = vsk, 34262306a36Sopenharmony_ci }; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return virtio_transport_send_pkt_info(vsk, &info); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic ssize_t 34862306a36Sopenharmony_civirtio_transport_stream_do_peek(struct vsock_sock *vsk, 34962306a36Sopenharmony_ci struct msghdr *msg, 35062306a36Sopenharmony_ci size_t len) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 35362306a36Sopenharmony_ci struct sk_buff *skb; 35462306a36Sopenharmony_ci size_t total = 0; 35562306a36Sopenharmony_ci int err; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci skb_queue_walk(&vvs->rx_queue, skb) { 36062306a36Sopenharmony_ci size_t bytes; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci bytes = len - total; 36362306a36Sopenharmony_ci if (bytes > skb->len) 36462306a36Sopenharmony_ci bytes = skb->len; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* sk_lock is held by caller so no one else can dequeue. 36962306a36Sopenharmony_ci * Unlock rx_lock since memcpy_to_msg() may sleep. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci err = memcpy_to_msg(msg, skb->data, bytes); 37262306a36Sopenharmony_ci if (err) 37362306a36Sopenharmony_ci goto out; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci total += bytes; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (total == len) 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return total; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ciout: 38862306a36Sopenharmony_ci if (total) 38962306a36Sopenharmony_ci err = total; 39062306a36Sopenharmony_ci return err; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic ssize_t 39462306a36Sopenharmony_civirtio_transport_stream_do_dequeue(struct vsock_sock *vsk, 39562306a36Sopenharmony_ci struct msghdr *msg, 39662306a36Sopenharmony_ci size_t len) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 39962306a36Sopenharmony_ci size_t bytes, total = 0; 40062306a36Sopenharmony_ci struct sk_buff *skb; 40162306a36Sopenharmony_ci u32 fwd_cnt_delta; 40262306a36Sopenharmony_ci bool low_rx_bytes; 40362306a36Sopenharmony_ci int err = -EFAULT; 40462306a36Sopenharmony_ci u32 free_space; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (WARN_ONCE(skb_queue_empty(&vvs->rx_queue) && vvs->rx_bytes, 40962306a36Sopenharmony_ci "rx_queue is empty, but rx_bytes is non-zero\n")) { 41062306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 41162306a36Sopenharmony_ci return err; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci while (total < len && !skb_queue_empty(&vvs->rx_queue)) { 41562306a36Sopenharmony_ci skb = skb_peek(&vvs->rx_queue); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci bytes = len - total; 41862306a36Sopenharmony_ci if (bytes > skb->len) 41962306a36Sopenharmony_ci bytes = skb->len; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* sk_lock is held by caller so no one else can dequeue. 42262306a36Sopenharmony_ci * Unlock rx_lock since memcpy_to_msg() may sleep. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci err = memcpy_to_msg(msg, skb->data, bytes); 42762306a36Sopenharmony_ci if (err) 42862306a36Sopenharmony_ci goto out; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci total += bytes; 43362306a36Sopenharmony_ci skb_pull(skb, bytes); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (skb->len == 0) { 43662306a36Sopenharmony_ci u32 pkt_len = le32_to_cpu(virtio_vsock_hdr(skb)->len); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci virtio_transport_dec_rx_pkt(vvs, pkt_len); 43962306a36Sopenharmony_ci __skb_unlink(skb, &vvs->rx_queue); 44062306a36Sopenharmony_ci consume_skb(skb); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci fwd_cnt_delta = vvs->fwd_cnt - vvs->last_fwd_cnt; 44562306a36Sopenharmony_ci free_space = vvs->buf_alloc - fwd_cnt_delta; 44662306a36Sopenharmony_ci low_rx_bytes = (vvs->rx_bytes < 44762306a36Sopenharmony_ci sock_rcvlowat(sk_vsock(vsk), 0, INT_MAX)); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* To reduce the number of credit update messages, 45262306a36Sopenharmony_ci * don't update credits as long as lots of space is available. 45362306a36Sopenharmony_ci * Note: the limit chosen here is arbitrary. Setting the limit 45462306a36Sopenharmony_ci * too high causes extra messages. Too low causes transmitter 45562306a36Sopenharmony_ci * stalls. As stalls are in theory more expensive than extra 45662306a36Sopenharmony_ci * messages, we set the limit to a high value. TODO: experiment 45762306a36Sopenharmony_ci * with different values. Also send credit update message when 45862306a36Sopenharmony_ci * number of bytes in rx queue is not enough to wake up reader. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci if (fwd_cnt_delta && 46162306a36Sopenharmony_ci (free_space < VIRTIO_VSOCK_MAX_PKT_BUF_SIZE || low_rx_bytes)) 46262306a36Sopenharmony_ci virtio_transport_send_credit_update(vsk); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return total; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ciout: 46762306a36Sopenharmony_ci if (total) 46862306a36Sopenharmony_ci err = total; 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic ssize_t 47362306a36Sopenharmony_civirtio_transport_seqpacket_do_peek(struct vsock_sock *vsk, 47462306a36Sopenharmony_ci struct msghdr *msg) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 47762306a36Sopenharmony_ci struct sk_buff *skb; 47862306a36Sopenharmony_ci size_t total, len; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!vvs->msg_count) { 48362306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci total = 0; 48862306a36Sopenharmony_ci len = msg_data_left(msg); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci skb_queue_walk(&vvs->rx_queue, skb) { 49162306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (total < len) { 49462306a36Sopenharmony_ci size_t bytes; 49562306a36Sopenharmony_ci int err; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci bytes = len - total; 49862306a36Sopenharmony_ci if (bytes > skb->len) 49962306a36Sopenharmony_ci bytes = skb->len; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* sk_lock is held by caller so no one else can dequeue. 50462306a36Sopenharmony_ci * Unlock rx_lock since memcpy_to_msg() may sleep. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci err = memcpy_to_msg(msg, skb->data, bytes); 50762306a36Sopenharmony_ci if (err) 50862306a36Sopenharmony_ci return err; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci total += skb->len; 51462306a36Sopenharmony_ci hdr = virtio_vsock_hdr(skb); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM) { 51762306a36Sopenharmony_ci if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOR) 51862306a36Sopenharmony_ci msg->msg_flags |= MSG_EOR; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return total; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int virtio_transport_seqpacket_do_dequeue(struct vsock_sock *vsk, 53062306a36Sopenharmony_ci struct msghdr *msg, 53162306a36Sopenharmony_ci int flags) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 53462306a36Sopenharmony_ci int dequeued_len = 0; 53562306a36Sopenharmony_ci size_t user_buf_len = msg_data_left(msg); 53662306a36Sopenharmony_ci bool msg_ready = false; 53762306a36Sopenharmony_ci struct sk_buff *skb; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (vvs->msg_count == 0) { 54262306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 54362306a36Sopenharmony_ci return 0; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci while (!msg_ready) { 54762306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr; 54862306a36Sopenharmony_ci size_t pkt_len; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci skb = __skb_dequeue(&vvs->rx_queue); 55162306a36Sopenharmony_ci if (!skb) 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci hdr = virtio_vsock_hdr(skb); 55462306a36Sopenharmony_ci pkt_len = (size_t)le32_to_cpu(hdr->len); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (dequeued_len >= 0) { 55762306a36Sopenharmony_ci size_t bytes_to_copy; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci bytes_to_copy = min(user_buf_len, pkt_len); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (bytes_to_copy) { 56262306a36Sopenharmony_ci int err; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* sk_lock is held by caller so no one else can dequeue. 56562306a36Sopenharmony_ci * Unlock rx_lock since memcpy_to_msg() may sleep. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci err = memcpy_to_msg(msg, skb->data, bytes_to_copy); 57062306a36Sopenharmony_ci if (err) { 57162306a36Sopenharmony_ci /* Copy of message failed. Rest of 57262306a36Sopenharmony_ci * fragments will be freed without copy. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_ci dequeued_len = err; 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci user_buf_len -= bytes_to_copy; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (dequeued_len >= 0) 58362306a36Sopenharmony_ci dequeued_len += pkt_len; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM) { 58762306a36Sopenharmony_ci msg_ready = true; 58862306a36Sopenharmony_ci vvs->msg_count--; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOR) 59162306a36Sopenharmony_ci msg->msg_flags |= MSG_EOR; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci virtio_transport_dec_rx_pkt(vvs, pkt_len); 59562306a36Sopenharmony_ci kfree_skb(skb); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci virtio_transport_send_credit_update(vsk); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return dequeued_len; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cissize_t 60662306a36Sopenharmony_civirtio_transport_stream_dequeue(struct vsock_sock *vsk, 60762306a36Sopenharmony_ci struct msghdr *msg, 60862306a36Sopenharmony_ci size_t len, int flags) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci if (flags & MSG_PEEK) 61162306a36Sopenharmony_ci return virtio_transport_stream_do_peek(vsk, msg, len); 61262306a36Sopenharmony_ci else 61362306a36Sopenharmony_ci return virtio_transport_stream_do_dequeue(vsk, msg, len); 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_stream_dequeue); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cissize_t 61862306a36Sopenharmony_civirtio_transport_seqpacket_dequeue(struct vsock_sock *vsk, 61962306a36Sopenharmony_ci struct msghdr *msg, 62062306a36Sopenharmony_ci int flags) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci if (flags & MSG_PEEK) 62362306a36Sopenharmony_ci return virtio_transport_seqpacket_do_peek(vsk, msg); 62462306a36Sopenharmony_ci else 62562306a36Sopenharmony_ci return virtio_transport_seqpacket_do_dequeue(vsk, msg, flags); 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_seqpacket_dequeue); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ciint 63062306a36Sopenharmony_civirtio_transport_seqpacket_enqueue(struct vsock_sock *vsk, 63162306a36Sopenharmony_ci struct msghdr *msg, 63262306a36Sopenharmony_ci size_t len) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci spin_lock_bh(&vvs->tx_lock); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (len > vvs->peer_buf_alloc) { 63962306a36Sopenharmony_ci spin_unlock_bh(&vvs->tx_lock); 64062306a36Sopenharmony_ci return -EMSGSIZE; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci spin_unlock_bh(&vvs->tx_lock); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return virtio_transport_stream_enqueue(vsk, msg, len); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_seqpacket_enqueue); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ciint 65062306a36Sopenharmony_civirtio_transport_dgram_dequeue(struct vsock_sock *vsk, 65162306a36Sopenharmony_ci struct msghdr *msg, 65262306a36Sopenharmony_ci size_t len, int flags) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci return -EOPNOTSUPP; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_dgram_dequeue); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cis64 virtio_transport_stream_has_data(struct vsock_sock *vsk) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 66162306a36Sopenharmony_ci s64 bytes; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 66462306a36Sopenharmony_ci bytes = vvs->rx_bytes; 66562306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return bytes; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_stream_has_data); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ciu32 virtio_transport_seqpacket_has_data(struct vsock_sock *vsk) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 67462306a36Sopenharmony_ci u32 msg_count; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 67762306a36Sopenharmony_ci msg_count = vvs->msg_count; 67862306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return msg_count; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_seqpacket_has_data); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic s64 virtio_transport_has_space(struct vsock_sock *vsk) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 68762306a36Sopenharmony_ci s64 bytes; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci bytes = (s64)vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); 69062306a36Sopenharmony_ci if (bytes < 0) 69162306a36Sopenharmony_ci bytes = 0; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return bytes; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cis64 virtio_transport_stream_has_space(struct vsock_sock *vsk) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 69962306a36Sopenharmony_ci s64 bytes; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci spin_lock_bh(&vvs->tx_lock); 70262306a36Sopenharmony_ci bytes = virtio_transport_has_space(vsk); 70362306a36Sopenharmony_ci spin_unlock_bh(&vvs->tx_lock); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci return bytes; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_stream_has_space); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ciint virtio_transport_do_socket_init(struct vsock_sock *vsk, 71062306a36Sopenharmony_ci struct vsock_sock *psk) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct virtio_vsock_sock *vvs; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci vvs = kzalloc(sizeof(*vvs), GFP_KERNEL); 71562306a36Sopenharmony_ci if (!vvs) 71662306a36Sopenharmony_ci return -ENOMEM; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci vsk->trans = vvs; 71962306a36Sopenharmony_ci vvs->vsk = vsk; 72062306a36Sopenharmony_ci if (psk && psk->trans) { 72162306a36Sopenharmony_ci struct virtio_vsock_sock *ptrans = psk->trans; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci vvs->peer_buf_alloc = ptrans->peer_buf_alloc; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (vsk->buffer_size > VIRTIO_VSOCK_MAX_BUF_SIZE) 72762306a36Sopenharmony_ci vsk->buffer_size = VIRTIO_VSOCK_MAX_BUF_SIZE; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci vvs->buf_alloc = vsk->buffer_size; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci spin_lock_init(&vvs->rx_lock); 73262306a36Sopenharmony_ci spin_lock_init(&vvs->tx_lock); 73362306a36Sopenharmony_ci skb_queue_head_init(&vvs->rx_queue); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_do_socket_init); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci/* sk_lock held by the caller */ 74062306a36Sopenharmony_civoid virtio_transport_notify_buffer_size(struct vsock_sock *vsk, u64 *val) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (*val > VIRTIO_VSOCK_MAX_BUF_SIZE) 74562306a36Sopenharmony_ci *val = VIRTIO_VSOCK_MAX_BUF_SIZE; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci vvs->buf_alloc = *val; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci virtio_transport_send_credit_update(vsk); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_buffer_size); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ciint 75462306a36Sopenharmony_civirtio_transport_notify_poll_in(struct vsock_sock *vsk, 75562306a36Sopenharmony_ci size_t target, 75662306a36Sopenharmony_ci bool *data_ready_now) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci *data_ready_now = vsock_stream_has_data(vsk) >= target; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_poll_in); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ciint 76562306a36Sopenharmony_civirtio_transport_notify_poll_out(struct vsock_sock *vsk, 76662306a36Sopenharmony_ci size_t target, 76762306a36Sopenharmony_ci bool *space_avail_now) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci s64 free_space; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci free_space = vsock_stream_has_space(vsk); 77262306a36Sopenharmony_ci if (free_space > 0) 77362306a36Sopenharmony_ci *space_avail_now = true; 77462306a36Sopenharmony_ci else if (free_space == 0) 77562306a36Sopenharmony_ci *space_avail_now = false; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return 0; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_poll_out); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ciint virtio_transport_notify_recv_init(struct vsock_sock *vsk, 78262306a36Sopenharmony_ci size_t target, struct vsock_transport_recv_notify_data *data) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_recv_init); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ciint virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk, 78962306a36Sopenharmony_ci size_t target, struct vsock_transport_recv_notify_data *data) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci return 0; 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_block); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ciint virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk, 79662306a36Sopenharmony_ci size_t target, struct vsock_transport_recv_notify_data *data) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_dequeue); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ciint virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk, 80362306a36Sopenharmony_ci size_t target, ssize_t copied, bool data_read, 80462306a36Sopenharmony_ci struct vsock_transport_recv_notify_data *data) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci return 0; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_recv_post_dequeue); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ciint virtio_transport_notify_send_init(struct vsock_sock *vsk, 81162306a36Sopenharmony_ci struct vsock_transport_send_notify_data *data) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci return 0; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_send_init); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ciint virtio_transport_notify_send_pre_block(struct vsock_sock *vsk, 81862306a36Sopenharmony_ci struct vsock_transport_send_notify_data *data) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci return 0; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_block); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciint virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk, 82562306a36Sopenharmony_ci struct vsock_transport_send_notify_data *data) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_enqueue); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ciint virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk, 83262306a36Sopenharmony_ci ssize_t written, struct vsock_transport_send_notify_data *data) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci return 0; 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_send_post_enqueue); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ciu64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci return vsk->buffer_size; 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_stream_rcvhiwat); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cibool virtio_transport_stream_is_active(struct vsock_sock *vsk) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci return true; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_stream_is_active); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cibool virtio_transport_stream_allow(u32 cid, u32 port) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci return true; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_stream_allow); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ciint virtio_transport_dgram_bind(struct vsock_sock *vsk, 85762306a36Sopenharmony_ci struct sockaddr_vm *addr) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci return -EOPNOTSUPP; 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_dgram_bind); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cibool virtio_transport_dgram_allow(u32 cid, u32 port) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci return false; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_dgram_allow); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ciint virtio_transport_connect(struct vsock_sock *vsk) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct virtio_vsock_pkt_info info = { 87262306a36Sopenharmony_ci .op = VIRTIO_VSOCK_OP_REQUEST, 87362306a36Sopenharmony_ci .vsk = vsk, 87462306a36Sopenharmony_ci }; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return virtio_transport_send_pkt_info(vsk, &info); 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_connect); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ciint virtio_transport_shutdown(struct vsock_sock *vsk, int mode) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct virtio_vsock_pkt_info info = { 88362306a36Sopenharmony_ci .op = VIRTIO_VSOCK_OP_SHUTDOWN, 88462306a36Sopenharmony_ci .flags = (mode & RCV_SHUTDOWN ? 88562306a36Sopenharmony_ci VIRTIO_VSOCK_SHUTDOWN_RCV : 0) | 88662306a36Sopenharmony_ci (mode & SEND_SHUTDOWN ? 88762306a36Sopenharmony_ci VIRTIO_VSOCK_SHUTDOWN_SEND : 0), 88862306a36Sopenharmony_ci .vsk = vsk, 88962306a36Sopenharmony_ci }; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci return virtio_transport_send_pkt_info(vsk, &info); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_shutdown); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ciint 89662306a36Sopenharmony_civirtio_transport_dgram_enqueue(struct vsock_sock *vsk, 89762306a36Sopenharmony_ci struct sockaddr_vm *remote_addr, 89862306a36Sopenharmony_ci struct msghdr *msg, 89962306a36Sopenharmony_ci size_t dgram_len) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci return -EOPNOTSUPP; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_dgram_enqueue); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cissize_t 90662306a36Sopenharmony_civirtio_transport_stream_enqueue(struct vsock_sock *vsk, 90762306a36Sopenharmony_ci struct msghdr *msg, 90862306a36Sopenharmony_ci size_t len) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct virtio_vsock_pkt_info info = { 91162306a36Sopenharmony_ci .op = VIRTIO_VSOCK_OP_RW, 91262306a36Sopenharmony_ci .msg = msg, 91362306a36Sopenharmony_ci .pkt_len = len, 91462306a36Sopenharmony_ci .vsk = vsk, 91562306a36Sopenharmony_ci }; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return virtio_transport_send_pkt_info(vsk, &info); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_stream_enqueue); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_civoid virtio_transport_destruct(struct vsock_sock *vsk) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci kfree(vvs); 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_destruct); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic int virtio_transport_reset(struct vsock_sock *vsk, 93062306a36Sopenharmony_ci struct sk_buff *skb) 93162306a36Sopenharmony_ci{ 93262306a36Sopenharmony_ci struct virtio_vsock_pkt_info info = { 93362306a36Sopenharmony_ci .op = VIRTIO_VSOCK_OP_RST, 93462306a36Sopenharmony_ci .reply = !!skb, 93562306a36Sopenharmony_ci .vsk = vsk, 93662306a36Sopenharmony_ci }; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Send RST only if the original pkt is not a RST pkt */ 93962306a36Sopenharmony_ci if (skb && le16_to_cpu(virtio_vsock_hdr(skb)->op) == VIRTIO_VSOCK_OP_RST) 94062306a36Sopenharmony_ci return 0; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci return virtio_transport_send_pkt_info(vsk, &info); 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci/* Normally packets are associated with a socket. There may be no socket if an 94662306a36Sopenharmony_ci * attempt was made to connect to a socket that does not exist. 94762306a36Sopenharmony_ci */ 94862306a36Sopenharmony_cistatic int virtio_transport_reset_no_sock(const struct virtio_transport *t, 94962306a36Sopenharmony_ci struct sk_buff *skb) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 95262306a36Sopenharmony_ci struct virtio_vsock_pkt_info info = { 95362306a36Sopenharmony_ci .op = VIRTIO_VSOCK_OP_RST, 95462306a36Sopenharmony_ci .type = le16_to_cpu(hdr->type), 95562306a36Sopenharmony_ci .reply = true, 95662306a36Sopenharmony_ci }; 95762306a36Sopenharmony_ci struct sk_buff *reply; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* Send RST only if the original pkt is not a RST pkt */ 96062306a36Sopenharmony_ci if (le16_to_cpu(hdr->op) == VIRTIO_VSOCK_OP_RST) 96162306a36Sopenharmony_ci return 0; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (!t) 96462306a36Sopenharmony_ci return -ENOTCONN; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci reply = virtio_transport_alloc_skb(&info, 0, 96762306a36Sopenharmony_ci le64_to_cpu(hdr->dst_cid), 96862306a36Sopenharmony_ci le32_to_cpu(hdr->dst_port), 96962306a36Sopenharmony_ci le64_to_cpu(hdr->src_cid), 97062306a36Sopenharmony_ci le32_to_cpu(hdr->src_port)); 97162306a36Sopenharmony_ci if (!reply) 97262306a36Sopenharmony_ci return -ENOMEM; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci return t->send_pkt(reply); 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci/* This function should be called with sk_lock held and SOCK_DONE set */ 97862306a36Sopenharmony_cistatic void virtio_transport_remove_sock(struct vsock_sock *vsk) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* We don't need to take rx_lock, as the socket is closing and we are 98362306a36Sopenharmony_ci * removing it. 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci __skb_queue_purge(&vvs->rx_queue); 98662306a36Sopenharmony_ci vsock_remove_sock(vsk); 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic void virtio_transport_wait_close(struct sock *sk, long timeout) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci if (timeout) { 99262306a36Sopenharmony_ci DEFINE_WAIT_FUNC(wait, woken_wake_function); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci do { 99762306a36Sopenharmony_ci if (sk_wait_event(sk, &timeout, 99862306a36Sopenharmony_ci sock_flag(sk, SOCK_DONE), &wait)) 99962306a36Sopenharmony_ci break; 100062306a36Sopenharmony_ci } while (!signal_pending(current) && timeout); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic void virtio_transport_do_close(struct vsock_sock *vsk, 100762306a36Sopenharmony_ci bool cancel_timeout) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci struct sock *sk = sk_vsock(vsk); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci sock_set_flag(sk, SOCK_DONE); 101262306a36Sopenharmony_ci vsk->peer_shutdown = SHUTDOWN_MASK; 101362306a36Sopenharmony_ci if (vsock_stream_has_data(vsk) <= 0) 101462306a36Sopenharmony_ci sk->sk_state = TCP_CLOSING; 101562306a36Sopenharmony_ci sk->sk_state_change(sk); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (vsk->close_work_scheduled && 101862306a36Sopenharmony_ci (!cancel_timeout || cancel_delayed_work(&vsk->close_work))) { 101962306a36Sopenharmony_ci vsk->close_work_scheduled = false; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci virtio_transport_remove_sock(vsk); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* Release refcnt obtained when we scheduled the timeout */ 102462306a36Sopenharmony_ci sock_put(sk); 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic void virtio_transport_close_timeout(struct work_struct *work) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct vsock_sock *vsk = 103162306a36Sopenharmony_ci container_of(work, struct vsock_sock, close_work.work); 103262306a36Sopenharmony_ci struct sock *sk = sk_vsock(vsk); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci sock_hold(sk); 103562306a36Sopenharmony_ci lock_sock(sk); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DONE)) { 103862306a36Sopenharmony_ci (void)virtio_transport_reset(vsk, NULL); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci virtio_transport_do_close(vsk, false); 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci vsk->close_work_scheduled = false; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci release_sock(sk); 104662306a36Sopenharmony_ci sock_put(sk); 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci/* User context, vsk->sk is locked */ 105062306a36Sopenharmony_cistatic bool virtio_transport_close(struct vsock_sock *vsk) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct sock *sk = &vsk->sk; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (!(sk->sk_state == TCP_ESTABLISHED || 105562306a36Sopenharmony_ci sk->sk_state == TCP_CLOSING)) 105662306a36Sopenharmony_ci return true; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* Already received SHUTDOWN from peer, reply with RST */ 105962306a36Sopenharmony_ci if ((vsk->peer_shutdown & SHUTDOWN_MASK) == SHUTDOWN_MASK) { 106062306a36Sopenharmony_ci (void)virtio_transport_reset(vsk, NULL); 106162306a36Sopenharmony_ci return true; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK) 106562306a36Sopenharmony_ci (void)virtio_transport_shutdown(vsk, SHUTDOWN_MASK); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING)) 106862306a36Sopenharmony_ci virtio_transport_wait_close(sk, sk->sk_lingertime); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (sock_flag(sk, SOCK_DONE)) { 107162306a36Sopenharmony_ci return true; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci sock_hold(sk); 107562306a36Sopenharmony_ci INIT_DELAYED_WORK(&vsk->close_work, 107662306a36Sopenharmony_ci virtio_transport_close_timeout); 107762306a36Sopenharmony_ci vsk->close_work_scheduled = true; 107862306a36Sopenharmony_ci schedule_delayed_work(&vsk->close_work, VSOCK_CLOSE_TIMEOUT); 107962306a36Sopenharmony_ci return false; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_civoid virtio_transport_release(struct vsock_sock *vsk) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci struct sock *sk = &vsk->sk; 108562306a36Sopenharmony_ci bool remove_sock = true; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) 108862306a36Sopenharmony_ci remove_sock = virtio_transport_close(vsk); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (remove_sock) { 109162306a36Sopenharmony_ci sock_set_flag(sk, SOCK_DONE); 109262306a36Sopenharmony_ci virtio_transport_remove_sock(vsk); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_release); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic int 109862306a36Sopenharmony_civirtio_transport_recv_connecting(struct sock *sk, 109962306a36Sopenharmony_ci struct sk_buff *skb) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 110262306a36Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 110362306a36Sopenharmony_ci int skerr; 110462306a36Sopenharmony_ci int err; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci switch (le16_to_cpu(hdr->op)) { 110762306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_RESPONSE: 110862306a36Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 110962306a36Sopenharmony_ci sk->sk_socket->state = SS_CONNECTED; 111062306a36Sopenharmony_ci vsock_insert_connected(vsk); 111162306a36Sopenharmony_ci sk->sk_state_change(sk); 111262306a36Sopenharmony_ci break; 111362306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_INVALID: 111462306a36Sopenharmony_ci break; 111562306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_RST: 111662306a36Sopenharmony_ci skerr = ECONNRESET; 111762306a36Sopenharmony_ci err = 0; 111862306a36Sopenharmony_ci goto destroy; 111962306a36Sopenharmony_ci default: 112062306a36Sopenharmony_ci skerr = EPROTO; 112162306a36Sopenharmony_ci err = -EINVAL; 112262306a36Sopenharmony_ci goto destroy; 112362306a36Sopenharmony_ci } 112462306a36Sopenharmony_ci return 0; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cidestroy: 112762306a36Sopenharmony_ci virtio_transport_reset(vsk, skb); 112862306a36Sopenharmony_ci sk->sk_state = TCP_CLOSE; 112962306a36Sopenharmony_ci sk->sk_err = skerr; 113062306a36Sopenharmony_ci sk_error_report(sk); 113162306a36Sopenharmony_ci return err; 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic void 113562306a36Sopenharmony_civirtio_transport_recv_enqueue(struct vsock_sock *vsk, 113662306a36Sopenharmony_ci struct sk_buff *skb) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 113962306a36Sopenharmony_ci bool can_enqueue, free_pkt = false; 114062306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr; 114162306a36Sopenharmony_ci u32 len; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci hdr = virtio_vsock_hdr(skb); 114462306a36Sopenharmony_ci len = le32_to_cpu(hdr->len); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci can_enqueue = virtio_transport_inc_rx_pkt(vvs, len); 114962306a36Sopenharmony_ci if (!can_enqueue) { 115062306a36Sopenharmony_ci free_pkt = true; 115162306a36Sopenharmony_ci goto out; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SEQ_EOM) 115562306a36Sopenharmony_ci vvs->msg_count++; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci /* Try to copy small packets into the buffer of last packet queued, 115862306a36Sopenharmony_ci * to avoid wasting memory queueing the entire buffer with a small 115962306a36Sopenharmony_ci * payload. 116062306a36Sopenharmony_ci */ 116162306a36Sopenharmony_ci if (len <= GOOD_COPY_LEN && !skb_queue_empty(&vvs->rx_queue)) { 116262306a36Sopenharmony_ci struct virtio_vsock_hdr *last_hdr; 116362306a36Sopenharmony_ci struct sk_buff *last_skb; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci last_skb = skb_peek_tail(&vvs->rx_queue); 116662306a36Sopenharmony_ci last_hdr = virtio_vsock_hdr(last_skb); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci /* If there is space in the last packet queued, we copy the 116962306a36Sopenharmony_ci * new packet in its buffer. We avoid this if the last packet 117062306a36Sopenharmony_ci * queued has VIRTIO_VSOCK_SEQ_EOM set, because this is 117162306a36Sopenharmony_ci * delimiter of SEQPACKET message, so 'pkt' is the first packet 117262306a36Sopenharmony_ci * of a new message. 117362306a36Sopenharmony_ci */ 117462306a36Sopenharmony_ci if (skb->len < skb_tailroom(last_skb) && 117562306a36Sopenharmony_ci !(le32_to_cpu(last_hdr->flags) & VIRTIO_VSOCK_SEQ_EOM)) { 117662306a36Sopenharmony_ci memcpy(skb_put(last_skb, skb->len), skb->data, skb->len); 117762306a36Sopenharmony_ci free_pkt = true; 117862306a36Sopenharmony_ci last_hdr->flags |= hdr->flags; 117962306a36Sopenharmony_ci le32_add_cpu(&last_hdr->len, len); 118062306a36Sopenharmony_ci goto out; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci __skb_queue_tail(&vvs->rx_queue, skb); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ciout: 118762306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 118862306a36Sopenharmony_ci if (free_pkt) 118962306a36Sopenharmony_ci kfree_skb(skb); 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic int 119362306a36Sopenharmony_civirtio_transport_recv_connected(struct sock *sk, 119462306a36Sopenharmony_ci struct sk_buff *skb) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 119762306a36Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 119862306a36Sopenharmony_ci int err = 0; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci switch (le16_to_cpu(hdr->op)) { 120162306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_RW: 120262306a36Sopenharmony_ci virtio_transport_recv_enqueue(vsk, skb); 120362306a36Sopenharmony_ci vsock_data_ready(sk); 120462306a36Sopenharmony_ci return err; 120562306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_CREDIT_REQUEST: 120662306a36Sopenharmony_ci virtio_transport_send_credit_update(vsk); 120762306a36Sopenharmony_ci break; 120862306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_CREDIT_UPDATE: 120962306a36Sopenharmony_ci sk->sk_write_space(sk); 121062306a36Sopenharmony_ci break; 121162306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_SHUTDOWN: 121262306a36Sopenharmony_ci if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_RCV) 121362306a36Sopenharmony_ci vsk->peer_shutdown |= RCV_SHUTDOWN; 121462306a36Sopenharmony_ci if (le32_to_cpu(hdr->flags) & VIRTIO_VSOCK_SHUTDOWN_SEND) 121562306a36Sopenharmony_ci vsk->peer_shutdown |= SEND_SHUTDOWN; 121662306a36Sopenharmony_ci if (vsk->peer_shutdown == SHUTDOWN_MASK) { 121762306a36Sopenharmony_ci if (vsock_stream_has_data(vsk) <= 0 && !sock_flag(sk, SOCK_DONE)) { 121862306a36Sopenharmony_ci (void)virtio_transport_reset(vsk, NULL); 121962306a36Sopenharmony_ci virtio_transport_do_close(vsk, true); 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci /* Remove this socket anyway because the remote peer sent 122262306a36Sopenharmony_ci * the shutdown. This way a new connection will succeed 122362306a36Sopenharmony_ci * if the remote peer uses the same source port, 122462306a36Sopenharmony_ci * even if the old socket is still unreleased, but now disconnected. 122562306a36Sopenharmony_ci */ 122662306a36Sopenharmony_ci vsock_remove_sock(vsk); 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci if (le32_to_cpu(virtio_vsock_hdr(skb)->flags)) 122962306a36Sopenharmony_ci sk->sk_state_change(sk); 123062306a36Sopenharmony_ci break; 123162306a36Sopenharmony_ci case VIRTIO_VSOCK_OP_RST: 123262306a36Sopenharmony_ci virtio_transport_do_close(vsk, true); 123362306a36Sopenharmony_ci break; 123462306a36Sopenharmony_ci default: 123562306a36Sopenharmony_ci err = -EINVAL; 123662306a36Sopenharmony_ci break; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci kfree_skb(skb); 124062306a36Sopenharmony_ci return err; 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic void 124462306a36Sopenharmony_civirtio_transport_recv_disconnecting(struct sock *sk, 124562306a36Sopenharmony_ci struct sk_buff *skb) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 124862306a36Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if (le16_to_cpu(hdr->op) == VIRTIO_VSOCK_OP_RST) 125162306a36Sopenharmony_ci virtio_transport_do_close(vsk, true); 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic int 125562306a36Sopenharmony_civirtio_transport_send_response(struct vsock_sock *vsk, 125662306a36Sopenharmony_ci struct sk_buff *skb) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 125962306a36Sopenharmony_ci struct virtio_vsock_pkt_info info = { 126062306a36Sopenharmony_ci .op = VIRTIO_VSOCK_OP_RESPONSE, 126162306a36Sopenharmony_ci .remote_cid = le64_to_cpu(hdr->src_cid), 126262306a36Sopenharmony_ci .remote_port = le32_to_cpu(hdr->src_port), 126362306a36Sopenharmony_ci .reply = true, 126462306a36Sopenharmony_ci .vsk = vsk, 126562306a36Sopenharmony_ci }; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci return virtio_transport_send_pkt_info(vsk, &info); 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistatic bool virtio_transport_space_update(struct sock *sk, 127162306a36Sopenharmony_ci struct sk_buff *skb) 127262306a36Sopenharmony_ci{ 127362306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 127462306a36Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 127562306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 127662306a36Sopenharmony_ci bool space_available; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci /* Listener sockets are not associated with any transport, so we are 127962306a36Sopenharmony_ci * not able to take the state to see if there is space available in the 128062306a36Sopenharmony_ci * remote peer, but since they are only used to receive requests, we 128162306a36Sopenharmony_ci * can assume that there is always space available in the other peer. 128262306a36Sopenharmony_ci */ 128362306a36Sopenharmony_ci if (!vvs) 128462306a36Sopenharmony_ci return true; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* buf_alloc and fwd_cnt is always included in the hdr */ 128762306a36Sopenharmony_ci spin_lock_bh(&vvs->tx_lock); 128862306a36Sopenharmony_ci vvs->peer_buf_alloc = le32_to_cpu(hdr->buf_alloc); 128962306a36Sopenharmony_ci vvs->peer_fwd_cnt = le32_to_cpu(hdr->fwd_cnt); 129062306a36Sopenharmony_ci space_available = virtio_transport_has_space(vsk); 129162306a36Sopenharmony_ci spin_unlock_bh(&vvs->tx_lock); 129262306a36Sopenharmony_ci return space_available; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci/* Handle server socket */ 129662306a36Sopenharmony_cistatic int 129762306a36Sopenharmony_civirtio_transport_recv_listen(struct sock *sk, struct sk_buff *skb, 129862306a36Sopenharmony_ci struct virtio_transport *t) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 130162306a36Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 130262306a36Sopenharmony_ci struct vsock_sock *vchild; 130362306a36Sopenharmony_ci struct sock *child; 130462306a36Sopenharmony_ci int ret; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (le16_to_cpu(hdr->op) != VIRTIO_VSOCK_OP_REQUEST) { 130762306a36Sopenharmony_ci virtio_transport_reset_no_sock(t, skb); 130862306a36Sopenharmony_ci return -EINVAL; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (sk_acceptq_is_full(sk)) { 131262306a36Sopenharmony_ci virtio_transport_reset_no_sock(t, skb); 131362306a36Sopenharmony_ci return -ENOMEM; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci child = vsock_create_connected(sk); 131762306a36Sopenharmony_ci if (!child) { 131862306a36Sopenharmony_ci virtio_transport_reset_no_sock(t, skb); 131962306a36Sopenharmony_ci return -ENOMEM; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci sk_acceptq_added(sk); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci lock_sock_nested(child, SINGLE_DEPTH_NESTING); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci child->sk_state = TCP_ESTABLISHED; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci vchild = vsock_sk(child); 132962306a36Sopenharmony_ci vsock_addr_init(&vchild->local_addr, le64_to_cpu(hdr->dst_cid), 133062306a36Sopenharmony_ci le32_to_cpu(hdr->dst_port)); 133162306a36Sopenharmony_ci vsock_addr_init(&vchild->remote_addr, le64_to_cpu(hdr->src_cid), 133262306a36Sopenharmony_ci le32_to_cpu(hdr->src_port)); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci ret = vsock_assign_transport(vchild, vsk); 133562306a36Sopenharmony_ci /* Transport assigned (looking at remote_addr) must be the same 133662306a36Sopenharmony_ci * where we received the request. 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_ci if (ret || vchild->transport != &t->transport) { 133962306a36Sopenharmony_ci release_sock(child); 134062306a36Sopenharmony_ci virtio_transport_reset_no_sock(t, skb); 134162306a36Sopenharmony_ci sock_put(child); 134262306a36Sopenharmony_ci return ret; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (virtio_transport_space_update(child, skb)) 134662306a36Sopenharmony_ci child->sk_write_space(child); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci vsock_insert_connected(vchild); 134962306a36Sopenharmony_ci vsock_enqueue_accept(sk, child); 135062306a36Sopenharmony_ci virtio_transport_send_response(vchild, skb); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci release_sock(child); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci sk->sk_data_ready(sk); 135562306a36Sopenharmony_ci return 0; 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cistatic bool virtio_transport_valid_type(u16 type) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci return (type == VIRTIO_VSOCK_TYPE_STREAM) || 136162306a36Sopenharmony_ci (type == VIRTIO_VSOCK_TYPE_SEQPACKET); 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci/* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex 136562306a36Sopenharmony_ci * lock. 136662306a36Sopenharmony_ci */ 136762306a36Sopenharmony_civoid virtio_transport_recv_pkt(struct virtio_transport *t, 136862306a36Sopenharmony_ci struct sk_buff *skb) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct virtio_vsock_hdr *hdr = virtio_vsock_hdr(skb); 137162306a36Sopenharmony_ci struct sockaddr_vm src, dst; 137262306a36Sopenharmony_ci struct vsock_sock *vsk; 137362306a36Sopenharmony_ci struct sock *sk; 137462306a36Sopenharmony_ci bool space_available; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci vsock_addr_init(&src, le64_to_cpu(hdr->src_cid), 137762306a36Sopenharmony_ci le32_to_cpu(hdr->src_port)); 137862306a36Sopenharmony_ci vsock_addr_init(&dst, le64_to_cpu(hdr->dst_cid), 137962306a36Sopenharmony_ci le32_to_cpu(hdr->dst_port)); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci trace_virtio_transport_recv_pkt(src.svm_cid, src.svm_port, 138262306a36Sopenharmony_ci dst.svm_cid, dst.svm_port, 138362306a36Sopenharmony_ci le32_to_cpu(hdr->len), 138462306a36Sopenharmony_ci le16_to_cpu(hdr->type), 138562306a36Sopenharmony_ci le16_to_cpu(hdr->op), 138662306a36Sopenharmony_ci le32_to_cpu(hdr->flags), 138762306a36Sopenharmony_ci le32_to_cpu(hdr->buf_alloc), 138862306a36Sopenharmony_ci le32_to_cpu(hdr->fwd_cnt)); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (!virtio_transport_valid_type(le16_to_cpu(hdr->type))) { 139162306a36Sopenharmony_ci (void)virtio_transport_reset_no_sock(t, skb); 139262306a36Sopenharmony_ci goto free_pkt; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci /* The socket must be in connected or bound table 139662306a36Sopenharmony_ci * otherwise send reset back 139762306a36Sopenharmony_ci */ 139862306a36Sopenharmony_ci sk = vsock_find_connected_socket(&src, &dst); 139962306a36Sopenharmony_ci if (!sk) { 140062306a36Sopenharmony_ci sk = vsock_find_bound_socket(&dst); 140162306a36Sopenharmony_ci if (!sk) { 140262306a36Sopenharmony_ci (void)virtio_transport_reset_no_sock(t, skb); 140362306a36Sopenharmony_ci goto free_pkt; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (virtio_transport_get_type(sk) != le16_to_cpu(hdr->type)) { 140862306a36Sopenharmony_ci (void)virtio_transport_reset_no_sock(t, skb); 140962306a36Sopenharmony_ci sock_put(sk); 141062306a36Sopenharmony_ci goto free_pkt; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci if (!skb_set_owner_sk_safe(skb, sk)) { 141462306a36Sopenharmony_ci WARN_ONCE(1, "receiving vsock socket has sk_refcnt == 0\n"); 141562306a36Sopenharmony_ci goto free_pkt; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci vsk = vsock_sk(sk); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci lock_sock(sk); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci /* Check if sk has been closed before lock_sock */ 142362306a36Sopenharmony_ci if (sock_flag(sk, SOCK_DONE)) { 142462306a36Sopenharmony_ci (void)virtio_transport_reset_no_sock(t, skb); 142562306a36Sopenharmony_ci release_sock(sk); 142662306a36Sopenharmony_ci sock_put(sk); 142762306a36Sopenharmony_ci goto free_pkt; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci space_available = virtio_transport_space_update(sk, skb); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* Update CID in case it has changed after a transport reset event */ 143362306a36Sopenharmony_ci if (vsk->local_addr.svm_cid != VMADDR_CID_ANY) 143462306a36Sopenharmony_ci vsk->local_addr.svm_cid = dst.svm_cid; 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci if (space_available) 143762306a36Sopenharmony_ci sk->sk_write_space(sk); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci switch (sk->sk_state) { 144062306a36Sopenharmony_ci case TCP_LISTEN: 144162306a36Sopenharmony_ci virtio_transport_recv_listen(sk, skb, t); 144262306a36Sopenharmony_ci kfree_skb(skb); 144362306a36Sopenharmony_ci break; 144462306a36Sopenharmony_ci case TCP_SYN_SENT: 144562306a36Sopenharmony_ci virtio_transport_recv_connecting(sk, skb); 144662306a36Sopenharmony_ci kfree_skb(skb); 144762306a36Sopenharmony_ci break; 144862306a36Sopenharmony_ci case TCP_ESTABLISHED: 144962306a36Sopenharmony_ci virtio_transport_recv_connected(sk, skb); 145062306a36Sopenharmony_ci break; 145162306a36Sopenharmony_ci case TCP_CLOSING: 145262306a36Sopenharmony_ci virtio_transport_recv_disconnecting(sk, skb); 145362306a36Sopenharmony_ci kfree_skb(skb); 145462306a36Sopenharmony_ci break; 145562306a36Sopenharmony_ci default: 145662306a36Sopenharmony_ci (void)virtio_transport_reset_no_sock(t, skb); 145762306a36Sopenharmony_ci kfree_skb(skb); 145862306a36Sopenharmony_ci break; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci release_sock(sk); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* Release refcnt obtained when we fetched this socket out of the 146462306a36Sopenharmony_ci * bound or connected list. 146562306a36Sopenharmony_ci */ 146662306a36Sopenharmony_ci sock_put(sk); 146762306a36Sopenharmony_ci return; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cifree_pkt: 147062306a36Sopenharmony_ci kfree_skb(skb); 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_recv_pkt); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci/* Remove skbs found in a queue that have a vsk that matches. 147562306a36Sopenharmony_ci * 147662306a36Sopenharmony_ci * Each skb is freed. 147762306a36Sopenharmony_ci * 147862306a36Sopenharmony_ci * Returns the count of skbs that were reply packets. 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ciint virtio_transport_purge_skbs(void *vsk, struct sk_buff_head *queue) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci struct sk_buff_head freeme; 148362306a36Sopenharmony_ci struct sk_buff *skb, *tmp; 148462306a36Sopenharmony_ci int cnt = 0; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci skb_queue_head_init(&freeme); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci spin_lock_bh(&queue->lock); 148962306a36Sopenharmony_ci skb_queue_walk_safe(queue, skb, tmp) { 149062306a36Sopenharmony_ci if (vsock_sk(skb->sk) != vsk) 149162306a36Sopenharmony_ci continue; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci __skb_unlink(skb, queue); 149462306a36Sopenharmony_ci __skb_queue_tail(&freeme, skb); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci if (virtio_vsock_skb_reply(skb)) 149762306a36Sopenharmony_ci cnt++; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci spin_unlock_bh(&queue->lock); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci __skb_queue_purge(&freeme); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci return cnt; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_purge_skbs); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ciint virtio_transport_read_skb(struct vsock_sock *vsk, skb_read_actor_t recv_actor) 150862306a36Sopenharmony_ci{ 150962306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 151062306a36Sopenharmony_ci struct sock *sk = sk_vsock(vsk); 151162306a36Sopenharmony_ci struct sk_buff *skb; 151262306a36Sopenharmony_ci int off = 0; 151362306a36Sopenharmony_ci int err; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 151662306a36Sopenharmony_ci /* Use __skb_recv_datagram() for race-free handling of the receive. It 151762306a36Sopenharmony_ci * works for types other than dgrams. 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_ci skb = __skb_recv_datagram(sk, &vvs->rx_queue, MSG_DONTWAIT, &off, &err); 152062306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (!skb) 152362306a36Sopenharmony_ci return err; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci return recv_actor(sk, skb); 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_read_skb); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ciint virtio_transport_notify_set_rcvlowat(struct vsock_sock *vsk, int val) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci struct virtio_vsock_sock *vvs = vsk->trans; 153262306a36Sopenharmony_ci bool send_update; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci spin_lock_bh(&vvs->rx_lock); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci /* If number of available bytes is less than new SO_RCVLOWAT value, 153762306a36Sopenharmony_ci * kick sender to send more data, because sender may sleep in its 153862306a36Sopenharmony_ci * 'send()' syscall waiting for enough space at our side. Also 153962306a36Sopenharmony_ci * don't send credit update when peer already knows actual value - 154062306a36Sopenharmony_ci * such transmission will be useless. 154162306a36Sopenharmony_ci */ 154262306a36Sopenharmony_ci send_update = (vvs->rx_bytes < val) && 154362306a36Sopenharmony_ci (vvs->fwd_cnt != vvs->last_fwd_cnt); 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci spin_unlock_bh(&vvs->rx_lock); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci if (send_update) { 154862306a36Sopenharmony_ci int err; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci err = virtio_transport_send_credit_update(vsk); 155162306a36Sopenharmony_ci if (err < 0) 155262306a36Sopenharmony_ci return err; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci return 0; 155662306a36Sopenharmony_ci} 155762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_transport_notify_set_rcvlowat); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 156062306a36Sopenharmony_ciMODULE_AUTHOR("Asias He"); 156162306a36Sopenharmony_ciMODULE_DESCRIPTION("common code for virtio vsock"); 1562