linux/net/vmw_vsock/af_vsock.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * VMware vSockets Driver
 *
 * Copyright (C) 2007-2013 VMware, Inc. All rights reserved.
 */

/* Implementation notes:
 *
 * - There are two kinds of sockets: those created by user action (such as
 * calling socket(2)) and those created by incoming connection request packets.
 *
 * - There are two "global" tables, one for bound sockets (sockets that have
 * specified an address that they are responsible for) and one for connected
 * sockets (sockets that have established a connection with another socket).
 * These tables are "global" in that all sockets on the system are placed
 * within them. - Note, though, that the bound table contains an extra entry
 * for a list of unbound sockets and SOCK_DGRAM sockets will always remain in
 * that list. The bound table is used solely for lookup of sockets when packets
 * are received and that's not necessary for SOCK_DGRAM sockets since we create
 * a datagram handle for each and need not perform a lookup.  Keeping SOCK_DGRAM
 * sockets out of the bound hash buckets will reduce the chance of collisions
 * when looking for SOCK_STREAM sockets and prevents us from having to check the
 * socket type in the hash table lookups.
 *
 * - Sockets created by user action will either be "client" sockets that
 * initiate a connection or "server" sockets that listen for connections; we do
 * not support simultaneous connects (two "client" sockets connecting).
 *
 * - "Server" sockets are referred to as listener sockets throughout this
 * implementation because they are in the TCP_LISTEN state.  When a
 * connection request is received (the second kind of socket mentioned above),
 * we create a new socket and refer to it as a pending socket.  These pending
 * sockets are placed on the pending connection list of the listener socket.
 * When future packets are received for the address the listener socket is
 * bound to, we check if the source of the packet is from one that has an
 * existing pending connection.  If it does, we process the packet for the
 * pending socket.  When that socket reaches the connected state, it is removed
 * from the listener socket's pending list and enqueued in the listener
 * socket's accept queue.  Callers of accept(2) will accept connected sockets
 * from the listener socket's accept queue.  If the socket cannot be accepted
 * for some reason then it is marked rejected.  Once the connection is
 * accepted, it is owned by the user process and the responsibility for cleanup
 * falls with that user process.
 *
 * - It is possible that these pending sockets will never reach the connected
 * state; in fact, we may never receive another packet after the connection
 * request.  Because of this, we must schedule a cleanup function to run in the
 * future, after some amount of time passes where a connection should have been
 * established.  This function ensures that the socket is off all lists so it
 * cannot be retrieved, then drops all references to the socket so it is cleaned
 * up (sock_put() -> sk_free() -> our sk_destruct implementation).  Note this
 * function will also cleanup rejected sockets, those that reach the connected
 * state but leave it before they have been accepted.
 *
 * - Lock ordering for pending or accept queue sockets is:
 *
 *     lock_sock(listener);
 *     lock_sock_nested(pending, SINGLE_DEPTH_NESTING);
 *
 * Using explicit nested locking keeps lockdep happy since normally only one
 * lock of a given class may be taken at a time.
 *
 * - Sockets created by user action will be cleaned up when the user process
 * calls close(2), causing our release implementation to be called. Our release
 * implementation will perform some cleanup then drop the last reference so our
 * sk_destruct implementation is invoked.  Our sk_destruct implementation will
 * perform additional cleanup that's common for both types of sockets.
 *
 * - A socket's reference count is what ensures that the structure won't be
 * freed.  Each entry in a list (such as the "global" bound and connected tables
 * and the listener socket's pending list and connected queue) ensures a
 * reference.  When we defer work until process context and pass a socket as our
 * argument, we must ensure the reference count is increased to ensure the
 * socket isn't freed before the function is run; the deferred function will
 * then drop the reference.
 *
 * - sk->sk_state uses the TCP state constants because they are widely used by
 * other address families and exposed to userspace tools like ss(8):
 *
 *   TCP_CLOSE - unconnected
 *   TCP_SYN_SENT - connecting
 *   TCP_ESTABLISHED - connected
 *   TCP_CLOSING - disconnecting
 *   TCP_LISTEN - listening
 */

#include <linux/compat.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/cred.h>
#include <linux/errqueue.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/kmod.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/net.h>
#include <linux/poll.h>
#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/smp.h>
#include <linux/socket.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <net/sock.h>
#include <net/af_vsock.h>
#include <uapi/linux/vm_sockets.h>

static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr);
static void vsock_sk_destruct(struct sock *sk);
static int vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);

/* Protocol family. */
struct proto vsock_proto =;

/* The default peer timeout indicates how long we will wait for a peer response
 * to a control message.
 */
#define VSOCK_DEFAULT_CONNECT_TIMEOUT

#define VSOCK_DEFAULT_BUFFER_SIZE
#define VSOCK_DEFAULT_BUFFER_MAX_SIZE
#define VSOCK_DEFAULT_BUFFER_MIN_SIZE

/* Transport used for host->guest communication */
static const struct vsock_transport *transport_h2g;
/* Transport used for guest->host communication */
static const struct vsock_transport *transport_g2h;
/* Transport used for DGRAM communication */
static const struct vsock_transport *transport_dgram;
/* Transport used for local communication */
static const struct vsock_transport *transport_local;
static DEFINE_MUTEX(vsock_register_mutex);

/**** UTILS ****/

/* Each bound VSocket is stored in the bind hash table and each connected
 * VSocket is stored in the connected hash table.
 *
 * Unbound sockets are all put on the same list attached to the end of the hash
 * table (vsock_unbound_sockets).  Bound sockets are added to the hash table in
 * the bucket that their local address hashes to (vsock_bound_sockets(addr)
 * represents the list that addr hashes to).
 *
 * Specifically, we initialize the vsock_bind_table array to a size of
 * VSOCK_HASH_SIZE + 1 so that vsock_bind_table[0] through
 * vsock_bind_table[VSOCK_HASH_SIZE - 1] are for bound sockets and
 * vsock_bind_table[VSOCK_HASH_SIZE] is for unbound sockets.  The hash function
 * mods with VSOCK_HASH_SIZE to ensure this.
 */
#define MAX_PORT_RETRIES

#define VSOCK_HASH(addr)
#define vsock_bound_sockets(addr)
#define vsock_unbound_sockets

/* XXX This can probably be implemented in a better way. */
#define VSOCK_CONN_HASH(src, dst)
#define vsock_connected_sockets(src, dst)
#define vsock_connected_sockets_vsk(vsk)

struct list_head vsock_bind_table[VSOCK_HASH_SIZE + 1];
EXPORT_SYMBOL_GPL();
struct list_head vsock_connected_table[VSOCK_HASH_SIZE];
EXPORT_SYMBOL_GPL();
DEFINE_SPINLOCK();
EXPORT_SYMBOL_GPL();

/* Autobind this socket to the local address if necessary. */
static int vsock_auto_bind(struct vsock_sock *vsk)
{}

static void vsock_init_tables(void)
{}

static void __vsock_insert_bound(struct list_head *list,
				 struct vsock_sock *vsk)
{}

static void __vsock_insert_connected(struct list_head *list,
				     struct vsock_sock *vsk)
{}

static void __vsock_remove_bound(struct vsock_sock *vsk)
{}

static void __vsock_remove_connected(struct vsock_sock *vsk)
{}

static struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr)
{}

static struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src,
						  struct sockaddr_vm *dst)
{}

static void vsock_insert_unbound(struct vsock_sock *vsk)
{}

void vsock_insert_connected(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

void vsock_remove_bound(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

void vsock_remove_connected(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr)
{}
EXPORT_SYMBOL_GPL();

struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
					 struct sockaddr_vm *dst)
{}
EXPORT_SYMBOL_GPL();

void vsock_remove_sock(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

void vsock_for_each_connected_socket(struct vsock_transport *transport,
				     void (*fn)(struct sock *sk))
{}
EXPORT_SYMBOL_GPL();

void vsock_add_pending(struct sock *listener, struct sock *pending)
{}
EXPORT_SYMBOL_GPL();

void vsock_remove_pending(struct sock *listener, struct sock *pending)
{}
EXPORT_SYMBOL_GPL();

void vsock_enqueue_accept(struct sock *listener, struct sock *connected)
{}
EXPORT_SYMBOL_GPL();

static bool vsock_use_local_transport(unsigned int remote_cid)
{}

static void vsock_deassign_transport(struct vsock_sock *vsk)
{}

/* Assign a transport to a socket and call the .init transport callback.
 *
 * Note: for connection oriented socket this must be called when vsk->remote_addr
 * is set (e.g. during the connect() or when a connection request on a listener
 * socket is received).
 * The vsk->remote_addr is used to decide which transport to use:
 *  - remote CID == VMADDR_CID_LOCAL or g2h->local_cid or VMADDR_CID_HOST if
 *    g2h is not loaded, will use local transport;
 *  - remote CID <= VMADDR_CID_HOST or h2g is not loaded or remote flags field
 *    includes VMADDR_FLAG_TO_HOST flag value, will use guest->host transport;
 *  - remote CID > VMADDR_CID_HOST will use host->guest transport;
 */
int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
{}
EXPORT_SYMBOL_GPL();

bool vsock_find_cid(unsigned int cid)
{}
EXPORT_SYMBOL_GPL();

static struct sock *vsock_dequeue_accept(struct sock *listener)
{}

static bool vsock_is_accept_queue_empty(struct sock *sk)
{}

static bool vsock_is_pending(struct sock *sk)
{}

static int vsock_send_shutdown(struct sock *sk, int mode)
{}

static void vsock_pending_work(struct work_struct *work)
{}

/**** SOCKET OPERATIONS ****/

static int __vsock_bind_connectible(struct vsock_sock *vsk,
				    struct sockaddr_vm *addr)
{}

static int __vsock_bind_dgram(struct vsock_sock *vsk,
			      struct sockaddr_vm *addr)
{}

static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr)
{}

static void vsock_connect_timeout(struct work_struct *work);

static struct sock *__vsock_create(struct net *net,
				   struct socket *sock,
				   struct sock *parent,
				   gfp_t priority,
				   unsigned short type,
				   int kern)
{}

static bool sock_type_connectible(u16 type)
{}

static void __vsock_release(struct sock *sk, int level)
{}

static void vsock_sk_destruct(struct sock *sk)
{}

static int vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{}

struct sock *vsock_create_connected(struct sock *parent)
{}
EXPORT_SYMBOL_GPL();

s64 vsock_stream_has_data(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

s64 vsock_connectible_has_data(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

s64 vsock_stream_has_space(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

void vsock_data_ready(struct sock *sk)
{}
EXPORT_SYMBOL_GPL();

static int vsock_release(struct socket *sock)
{}

static int
vsock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{}

static int vsock_getname(struct socket *sock,
			 struct sockaddr *addr, int peer)
{}

static int vsock_shutdown(struct socket *sock, int mode)
{}

static __poll_t vsock_poll(struct file *file, struct socket *sock,
			       poll_table *wait)
{}

static int vsock_read_skb(struct sock *sk, skb_read_actor_t read_actor)
{}

static int vsock_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
			       size_t len)
{}

static int vsock_dgram_connect(struct socket *sock,
			       struct sockaddr *addr, int addr_len, int flags)
{}

int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg,
			size_t len, int flags)
{}
EXPORT_SYMBOL_GPL();

static const struct proto_ops vsock_dgram_ops =;

static int vsock_transport_cancel_pkt(struct vsock_sock *vsk)
{}

static void vsock_connect_timeout(struct work_struct *work)
{}

static int vsock_connect(struct socket *sock, struct sockaddr *addr,
			 int addr_len, int flags)
{}

static int vsock_accept(struct socket *sock, struct socket *newsock,
			struct proto_accept_arg *arg)
{}

static int vsock_listen(struct socket *sock, int backlog)
{}

static void vsock_update_buffer_size(struct vsock_sock *vsk,
				     const struct vsock_transport *transport,
				     u64 val)
{}

static int vsock_connectible_setsockopt(struct socket *sock,
					int level,
					int optname,
					sockptr_t optval,
					unsigned int optlen)
{}

static int vsock_connectible_getsockopt(struct socket *sock,
					int level, int optname,
					char __user *optval,
					int __user *optlen)
{}

static int vsock_connectible_sendmsg(struct socket *sock, struct msghdr *msg,
				     size_t len)
{}

static int vsock_connectible_wait_data(struct sock *sk,
				       struct wait_queue_entry *wait,
				       long timeout,
				       struct vsock_transport_recv_notify_data *recv_data,
				       size_t target)
{}

static int __vsock_stream_recvmsg(struct sock *sk, struct msghdr *msg,
				  size_t len, int flags)
{}

static int __vsock_seqpacket_recvmsg(struct sock *sk, struct msghdr *msg,
				     size_t len, int flags)
{}

int
vsock_connectible_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
			  int flags)
{}
EXPORT_SYMBOL_GPL();

static int vsock_set_rcvlowat(struct sock *sk, int val)
{}

static const struct proto_ops vsock_stream_ops =;

static const struct proto_ops vsock_seqpacket_ops =;

static int vsock_create(struct net *net, struct socket *sock,
			int protocol, int kern)
{}

static const struct net_proto_family vsock_family_ops =;

static long vsock_dev_do_ioctl(struct file *filp,
			       unsigned int cmd, void __user *ptr)
{}

static long vsock_dev_ioctl(struct file *filp,
			    unsigned int cmd, unsigned long arg)
{}

#ifdef CONFIG_COMPAT
static long vsock_dev_compat_ioctl(struct file *filp,
				   unsigned int cmd, unsigned long arg)
{}
#endif

static const struct file_operations vsock_device_ops =;

static struct miscdevice vsock_device =;

static int __init vsock_init(void)
{}

static void __exit vsock_exit(void)
{}

const struct vsock_transport *vsock_core_get_transport(struct vsock_sock *vsk)
{}
EXPORT_SYMBOL_GPL();

int vsock_core_register(const struct vsock_transport *t, int features)
{}
EXPORT_SYMBOL_GPL();

void vsock_core_unregister(const struct vsock_transport *t)
{}
EXPORT_SYMBOL_GPL();

module_init();
module_exit(vsock_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_VERSION();
MODULE_LICENSE();