18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VMware vSockets Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007-2013 VMware, Inc. All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* Implementation notes: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * - There are two kinds of sockets: those created by user action (such as 118c2ecf20Sopenharmony_ci * calling socket(2)) and those created by incoming connection request packets. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * - There are two "global" tables, one for bound sockets (sockets that have 148c2ecf20Sopenharmony_ci * specified an address that they are responsible for) and one for connected 158c2ecf20Sopenharmony_ci * sockets (sockets that have established a connection with another socket). 168c2ecf20Sopenharmony_ci * These tables are "global" in that all sockets on the system are placed 178c2ecf20Sopenharmony_ci * within them. - Note, though, that the bound table contains an extra entry 188c2ecf20Sopenharmony_ci * for a list of unbound sockets and SOCK_DGRAM sockets will always remain in 198c2ecf20Sopenharmony_ci * that list. The bound table is used solely for lookup of sockets when packets 208c2ecf20Sopenharmony_ci * are received and that's not necessary for SOCK_DGRAM sockets since we create 218c2ecf20Sopenharmony_ci * a datagram handle for each and need not perform a lookup. Keeping SOCK_DGRAM 228c2ecf20Sopenharmony_ci * sockets out of the bound hash buckets will reduce the chance of collisions 238c2ecf20Sopenharmony_ci * when looking for SOCK_STREAM sockets and prevents us from having to check the 248c2ecf20Sopenharmony_ci * socket type in the hash table lookups. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * - Sockets created by user action will either be "client" sockets that 278c2ecf20Sopenharmony_ci * initiate a connection or "server" sockets that listen for connections; we do 288c2ecf20Sopenharmony_ci * not support simultaneous connects (two "client" sockets connecting). 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * - "Server" sockets are referred to as listener sockets throughout this 318c2ecf20Sopenharmony_ci * implementation because they are in the TCP_LISTEN state. When a 328c2ecf20Sopenharmony_ci * connection request is received (the second kind of socket mentioned above), 338c2ecf20Sopenharmony_ci * we create a new socket and refer to it as a pending socket. These pending 348c2ecf20Sopenharmony_ci * sockets are placed on the pending connection list of the listener socket. 358c2ecf20Sopenharmony_ci * When future packets are received for the address the listener socket is 368c2ecf20Sopenharmony_ci * bound to, we check if the source of the packet is from one that has an 378c2ecf20Sopenharmony_ci * existing pending connection. If it does, we process the packet for the 388c2ecf20Sopenharmony_ci * pending socket. When that socket reaches the connected state, it is removed 398c2ecf20Sopenharmony_ci * from the listener socket's pending list and enqueued in the listener 408c2ecf20Sopenharmony_ci * socket's accept queue. Callers of accept(2) will accept connected sockets 418c2ecf20Sopenharmony_ci * from the listener socket's accept queue. If the socket cannot be accepted 428c2ecf20Sopenharmony_ci * for some reason then it is marked rejected. Once the connection is 438c2ecf20Sopenharmony_ci * accepted, it is owned by the user process and the responsibility for cleanup 448c2ecf20Sopenharmony_ci * falls with that user process. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * - It is possible that these pending sockets will never reach the connected 478c2ecf20Sopenharmony_ci * state; in fact, we may never receive another packet after the connection 488c2ecf20Sopenharmony_ci * request. Because of this, we must schedule a cleanup function to run in the 498c2ecf20Sopenharmony_ci * future, after some amount of time passes where a connection should have been 508c2ecf20Sopenharmony_ci * established. This function ensures that the socket is off all lists so it 518c2ecf20Sopenharmony_ci * cannot be retrieved, then drops all references to the socket so it is cleaned 528c2ecf20Sopenharmony_ci * up (sock_put() -> sk_free() -> our sk_destruct implementation). Note this 538c2ecf20Sopenharmony_ci * function will also cleanup rejected sockets, those that reach the connected 548c2ecf20Sopenharmony_ci * state but leave it before they have been accepted. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * - Lock ordering for pending or accept queue sockets is: 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * lock_sock(listener); 598c2ecf20Sopenharmony_ci * lock_sock_nested(pending, SINGLE_DEPTH_NESTING); 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * Using explicit nested locking keeps lockdep happy since normally only one 628c2ecf20Sopenharmony_ci * lock of a given class may be taken at a time. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * - Sockets created by user action will be cleaned up when the user process 658c2ecf20Sopenharmony_ci * calls close(2), causing our release implementation to be called. Our release 668c2ecf20Sopenharmony_ci * implementation will perform some cleanup then drop the last reference so our 678c2ecf20Sopenharmony_ci * sk_destruct implementation is invoked. Our sk_destruct implementation will 688c2ecf20Sopenharmony_ci * perform additional cleanup that's common for both types of sockets. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * - A socket's reference count is what ensures that the structure won't be 718c2ecf20Sopenharmony_ci * freed. Each entry in a list (such as the "global" bound and connected tables 728c2ecf20Sopenharmony_ci * and the listener socket's pending list and connected queue) ensures a 738c2ecf20Sopenharmony_ci * reference. When we defer work until process context and pass a socket as our 748c2ecf20Sopenharmony_ci * argument, we must ensure the reference count is increased to ensure the 758c2ecf20Sopenharmony_ci * socket isn't freed before the function is run; the deferred function will 768c2ecf20Sopenharmony_ci * then drop the reference. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * - sk->sk_state uses the TCP state constants because they are widely used by 798c2ecf20Sopenharmony_ci * other address families and exposed to userspace tools like ss(8): 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * TCP_CLOSE - unconnected 828c2ecf20Sopenharmony_ci * TCP_SYN_SENT - connecting 838c2ecf20Sopenharmony_ci * TCP_ESTABLISHED - connected 848c2ecf20Sopenharmony_ci * TCP_CLOSING - disconnecting 858c2ecf20Sopenharmony_ci * TCP_LISTEN - listening 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#include <linux/types.h> 898c2ecf20Sopenharmony_ci#include <linux/bitops.h> 908c2ecf20Sopenharmony_ci#include <linux/cred.h> 918c2ecf20Sopenharmony_ci#include <linux/init.h> 928c2ecf20Sopenharmony_ci#include <linux/io.h> 938c2ecf20Sopenharmony_ci#include <linux/kernel.h> 948c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 958c2ecf20Sopenharmony_ci#include <linux/kmod.h> 968c2ecf20Sopenharmony_ci#include <linux/list.h> 978c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 988c2ecf20Sopenharmony_ci#include <linux/module.h> 998c2ecf20Sopenharmony_ci#include <linux/mutex.h> 1008c2ecf20Sopenharmony_ci#include <linux/net.h> 1018c2ecf20Sopenharmony_ci#include <linux/poll.h> 1028c2ecf20Sopenharmony_ci#include <linux/random.h> 1038c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 1048c2ecf20Sopenharmony_ci#include <linux/smp.h> 1058c2ecf20Sopenharmony_ci#include <linux/socket.h> 1068c2ecf20Sopenharmony_ci#include <linux/stddef.h> 1078c2ecf20Sopenharmony_ci#include <linux/unistd.h> 1088c2ecf20Sopenharmony_ci#include <linux/wait.h> 1098c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 1108c2ecf20Sopenharmony_ci#include <net/sock.h> 1118c2ecf20Sopenharmony_ci#include <net/af_vsock.h> 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr); 1148c2ecf20Sopenharmony_cistatic void vsock_sk_destruct(struct sock *sk); 1158c2ecf20Sopenharmony_cistatic int vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* Protocol family. */ 1188c2ecf20Sopenharmony_cistatic struct proto vsock_proto = { 1198c2ecf20Sopenharmony_ci .name = "AF_VSOCK", 1208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1218c2ecf20Sopenharmony_ci .obj_size = sizeof(struct vsock_sock), 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* The default peer timeout indicates how long we will wait for a peer response 1258c2ecf20Sopenharmony_ci * to a control message. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci#define VSOCK_DEFAULT_CONNECT_TIMEOUT (2 * HZ) 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define VSOCK_DEFAULT_BUFFER_SIZE (1024 * 256) 1308c2ecf20Sopenharmony_ci#define VSOCK_DEFAULT_BUFFER_MAX_SIZE (1024 * 256) 1318c2ecf20Sopenharmony_ci#define VSOCK_DEFAULT_BUFFER_MIN_SIZE 128 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* Transport used for host->guest communication */ 1348c2ecf20Sopenharmony_cistatic const struct vsock_transport *transport_h2g; 1358c2ecf20Sopenharmony_ci/* Transport used for guest->host communication */ 1368c2ecf20Sopenharmony_cistatic const struct vsock_transport *transport_g2h; 1378c2ecf20Sopenharmony_ci/* Transport used for DGRAM communication */ 1388c2ecf20Sopenharmony_cistatic const struct vsock_transport *transport_dgram; 1398c2ecf20Sopenharmony_ci/* Transport used for local communication */ 1408c2ecf20Sopenharmony_cistatic const struct vsock_transport *transport_local; 1418c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(vsock_register_mutex); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/**** UTILS ****/ 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* Each bound VSocket is stored in the bind hash table and each connected 1468c2ecf20Sopenharmony_ci * VSocket is stored in the connected hash table. 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * Unbound sockets are all put on the same list attached to the end of the hash 1498c2ecf20Sopenharmony_ci * table (vsock_unbound_sockets). Bound sockets are added to the hash table in 1508c2ecf20Sopenharmony_ci * the bucket that their local address hashes to (vsock_bound_sockets(addr) 1518c2ecf20Sopenharmony_ci * represents the list that addr hashes to). 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci * Specifically, we initialize the vsock_bind_table array to a size of 1548c2ecf20Sopenharmony_ci * VSOCK_HASH_SIZE + 1 so that vsock_bind_table[0] through 1558c2ecf20Sopenharmony_ci * vsock_bind_table[VSOCK_HASH_SIZE - 1] are for bound sockets and 1568c2ecf20Sopenharmony_ci * vsock_bind_table[VSOCK_HASH_SIZE] is for unbound sockets. The hash function 1578c2ecf20Sopenharmony_ci * mods with VSOCK_HASH_SIZE to ensure this. 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci#define MAX_PORT_RETRIES 24 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define VSOCK_HASH(addr) ((addr)->svm_port % VSOCK_HASH_SIZE) 1628c2ecf20Sopenharmony_ci#define vsock_bound_sockets(addr) (&vsock_bind_table[VSOCK_HASH(addr)]) 1638c2ecf20Sopenharmony_ci#define vsock_unbound_sockets (&vsock_bind_table[VSOCK_HASH_SIZE]) 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* XXX This can probably be implemented in a better way. */ 1668c2ecf20Sopenharmony_ci#define VSOCK_CONN_HASH(src, dst) \ 1678c2ecf20Sopenharmony_ci (((src)->svm_cid ^ (dst)->svm_port) % VSOCK_HASH_SIZE) 1688c2ecf20Sopenharmony_ci#define vsock_connected_sockets(src, dst) \ 1698c2ecf20Sopenharmony_ci (&vsock_connected_table[VSOCK_CONN_HASH(src, dst)]) 1708c2ecf20Sopenharmony_ci#define vsock_connected_sockets_vsk(vsk) \ 1718c2ecf20Sopenharmony_ci vsock_connected_sockets(&(vsk)->remote_addr, &(vsk)->local_addr) 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistruct list_head vsock_bind_table[VSOCK_HASH_SIZE + 1]; 1748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_bind_table); 1758c2ecf20Sopenharmony_cistruct list_head vsock_connected_table[VSOCK_HASH_SIZE]; 1768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_connected_table); 1778c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(vsock_table_lock); 1788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_table_lock); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* Autobind this socket to the local address if necessary. */ 1818c2ecf20Sopenharmony_cistatic int vsock_auto_bind(struct vsock_sock *vsk) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct sock *sk = sk_vsock(vsk); 1848c2ecf20Sopenharmony_ci struct sockaddr_vm local_addr; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (vsock_addr_bound(&vsk->local_addr)) 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci vsock_addr_init(&local_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY); 1898c2ecf20Sopenharmony_ci return __vsock_bind(sk, &local_addr); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void vsock_init_tables(void) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci int i; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vsock_bind_table); i++) 1978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsock_bind_table[i]); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) 2008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsock_connected_table[i]); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void __vsock_insert_bound(struct list_head *list, 2048c2ecf20Sopenharmony_ci struct vsock_sock *vsk) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci sock_hold(&vsk->sk); 2078c2ecf20Sopenharmony_ci list_add(&vsk->bound_table, list); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void __vsock_insert_connected(struct list_head *list, 2118c2ecf20Sopenharmony_ci struct vsock_sock *vsk) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci sock_hold(&vsk->sk); 2148c2ecf20Sopenharmony_ci list_add(&vsk->connected_table, list); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic void __vsock_remove_bound(struct vsock_sock *vsk) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci list_del_init(&vsk->bound_table); 2208c2ecf20Sopenharmony_ci sock_put(&vsk->sk); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic void __vsock_remove_connected(struct vsock_sock *vsk) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci list_del_init(&vsk->connected_table); 2268c2ecf20Sopenharmony_ci sock_put(&vsk->sk); 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table) { 2348c2ecf20Sopenharmony_ci if (vsock_addr_equals_addr(addr, &vsk->local_addr)) 2358c2ecf20Sopenharmony_ci return sk_vsock(vsk); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (addr->svm_port == vsk->local_addr.svm_port && 2388c2ecf20Sopenharmony_ci (vsk->local_addr.svm_cid == VMADDR_CID_ANY || 2398c2ecf20Sopenharmony_ci addr->svm_cid == VMADDR_CID_ANY)) 2408c2ecf20Sopenharmony_ci return sk_vsock(vsk); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return NULL; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src, 2478c2ecf20Sopenharmony_ci struct sockaddr_vm *dst) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci list_for_each_entry(vsk, vsock_connected_sockets(src, dst), 2528c2ecf20Sopenharmony_ci connected_table) { 2538c2ecf20Sopenharmony_ci if (vsock_addr_equals_addr(src, &vsk->remote_addr) && 2548c2ecf20Sopenharmony_ci dst->svm_port == vsk->local_addr.svm_port) { 2558c2ecf20Sopenharmony_ci return sk_vsock(vsk); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return NULL; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic void vsock_insert_unbound(struct vsock_sock *vsk) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 2658c2ecf20Sopenharmony_ci __vsock_insert_bound(vsock_unbound_sockets, vsk); 2668c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_civoid vsock_insert_connected(struct vsock_sock *vsk) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct list_head *list = vsock_connected_sockets( 2728c2ecf20Sopenharmony_ci &vsk->remote_addr, &vsk->local_addr); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 2758c2ecf20Sopenharmony_ci __vsock_insert_connected(list, vsk); 2768c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_insert_connected); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_civoid vsock_remove_bound(struct vsock_sock *vsk) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 2838c2ecf20Sopenharmony_ci if (__vsock_in_bound_table(vsk)) 2848c2ecf20Sopenharmony_ci __vsock_remove_bound(vsk); 2858c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_remove_bound); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_civoid vsock_remove_connected(struct vsock_sock *vsk) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 2928c2ecf20Sopenharmony_ci if (__vsock_in_connected_table(vsk)) 2938c2ecf20Sopenharmony_ci __vsock_remove_connected(vsk); 2948c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_remove_connected); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistruct sock *vsock_find_bound_socket(struct sockaddr_vm *addr) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct sock *sk; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 3038c2ecf20Sopenharmony_ci sk = __vsock_find_bound_socket(addr); 3048c2ecf20Sopenharmony_ci if (sk) 3058c2ecf20Sopenharmony_ci sock_hold(sk); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return sk; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_find_bound_socket); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistruct sock *vsock_find_connected_socket(struct sockaddr_vm *src, 3148c2ecf20Sopenharmony_ci struct sockaddr_vm *dst) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct sock *sk; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 3198c2ecf20Sopenharmony_ci sk = __vsock_find_connected_socket(src, dst); 3208c2ecf20Sopenharmony_ci if (sk) 3218c2ecf20Sopenharmony_ci sock_hold(sk); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return sk; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_find_connected_socket); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_civoid vsock_remove_sock(struct vsock_sock *vsk) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci vsock_remove_bound(vsk); 3328c2ecf20Sopenharmony_ci vsock_remove_connected(vsk); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_remove_sock); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_civoid vsock_for_each_connected_socket(struct vsock_transport *transport, 3378c2ecf20Sopenharmony_ci void (*fn)(struct sock *sk)) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci int i; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) { 3448c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 3458c2ecf20Sopenharmony_ci list_for_each_entry(vsk, &vsock_connected_table[i], 3468c2ecf20Sopenharmony_ci connected_table) { 3478c2ecf20Sopenharmony_ci if (vsk->transport != transport) 3488c2ecf20Sopenharmony_ci continue; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci fn(sk_vsock(vsk)); 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_for_each_connected_socket); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_civoid vsock_add_pending(struct sock *listener, struct sock *pending) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct vsock_sock *vlistener; 3618c2ecf20Sopenharmony_ci struct vsock_sock *vpending; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci vlistener = vsock_sk(listener); 3648c2ecf20Sopenharmony_ci vpending = vsock_sk(pending); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci sock_hold(pending); 3678c2ecf20Sopenharmony_ci sock_hold(listener); 3688c2ecf20Sopenharmony_ci list_add_tail(&vpending->pending_links, &vlistener->pending_links); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_add_pending); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_civoid vsock_remove_pending(struct sock *listener, struct sock *pending) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct vsock_sock *vpending = vsock_sk(pending); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci list_del_init(&vpending->pending_links); 3778c2ecf20Sopenharmony_ci sock_put(listener); 3788c2ecf20Sopenharmony_ci sock_put(pending); 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_remove_pending); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_civoid vsock_enqueue_accept(struct sock *listener, struct sock *connected) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct vsock_sock *vlistener; 3858c2ecf20Sopenharmony_ci struct vsock_sock *vconnected; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci vlistener = vsock_sk(listener); 3888c2ecf20Sopenharmony_ci vconnected = vsock_sk(connected); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci sock_hold(connected); 3918c2ecf20Sopenharmony_ci sock_hold(listener); 3928c2ecf20Sopenharmony_ci list_add_tail(&vconnected->accept_queue, &vlistener->accept_queue); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_enqueue_accept); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic bool vsock_use_local_transport(unsigned int remote_cid) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci if (!transport_local) 3998c2ecf20Sopenharmony_ci return false; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (remote_cid == VMADDR_CID_LOCAL) 4028c2ecf20Sopenharmony_ci return true; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (transport_g2h) { 4058c2ecf20Sopenharmony_ci return remote_cid == transport_g2h->get_local_cid(); 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci return remote_cid == VMADDR_CID_HOST; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic void vsock_deassign_transport(struct vsock_sock *vsk) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci if (!vsk->transport) 4148c2ecf20Sopenharmony_ci return; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci vsk->transport->destruct(vsk); 4178c2ecf20Sopenharmony_ci module_put(vsk->transport->module); 4188c2ecf20Sopenharmony_ci vsk->transport = NULL; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/* Assign a transport to a socket and call the .init transport callback. 4228c2ecf20Sopenharmony_ci * 4238c2ecf20Sopenharmony_ci * Note: for stream socket this must be called when vsk->remote_addr is set 4248c2ecf20Sopenharmony_ci * (e.g. during the connect() or when a connection request on a listener 4258c2ecf20Sopenharmony_ci * socket is received). 4268c2ecf20Sopenharmony_ci * The vsk->remote_addr is used to decide which transport to use: 4278c2ecf20Sopenharmony_ci * - remote CID == VMADDR_CID_LOCAL or g2h->local_cid or VMADDR_CID_HOST if 4288c2ecf20Sopenharmony_ci * g2h is not loaded, will use local transport; 4298c2ecf20Sopenharmony_ci * - remote CID <= VMADDR_CID_HOST will use guest->host transport; 4308c2ecf20Sopenharmony_ci * - remote CID > VMADDR_CID_HOST will use host->guest transport; 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ciint vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci const struct vsock_transport *new_transport; 4358c2ecf20Sopenharmony_ci struct sock *sk = sk_vsock(vsk); 4368c2ecf20Sopenharmony_ci unsigned int remote_cid = vsk->remote_addr.svm_cid; 4378c2ecf20Sopenharmony_ci int ret; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci switch (sk->sk_type) { 4408c2ecf20Sopenharmony_ci case SOCK_DGRAM: 4418c2ecf20Sopenharmony_ci new_transport = transport_dgram; 4428c2ecf20Sopenharmony_ci break; 4438c2ecf20Sopenharmony_ci case SOCK_STREAM: 4448c2ecf20Sopenharmony_ci if (vsock_use_local_transport(remote_cid)) 4458c2ecf20Sopenharmony_ci new_transport = transport_local; 4468c2ecf20Sopenharmony_ci else if (remote_cid <= VMADDR_CID_HOST || !transport_h2g) 4478c2ecf20Sopenharmony_ci new_transport = transport_g2h; 4488c2ecf20Sopenharmony_ci else 4498c2ecf20Sopenharmony_ci new_transport = transport_h2g; 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci default: 4528c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (vsk->transport) { 4568c2ecf20Sopenharmony_ci if (vsk->transport == new_transport) 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* transport->release() must be called with sock lock acquired. 4608c2ecf20Sopenharmony_ci * This path can only be taken during vsock_stream_connect(), 4618c2ecf20Sopenharmony_ci * where we have already held the sock lock. 4628c2ecf20Sopenharmony_ci * In the other cases, this function is called on a new socket 4638c2ecf20Sopenharmony_ci * which is not assigned to any transport. 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_ci vsk->transport->release(vsk); 4668c2ecf20Sopenharmony_ci vsock_deassign_transport(vsk); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* We increase the module refcnt to prevent the transport unloading 4708c2ecf20Sopenharmony_ci * while there are open sockets assigned to it. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci if (!new_transport || !try_module_get(new_transport->module)) 4738c2ecf20Sopenharmony_ci return -ENODEV; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci ret = new_transport->init(vsk, psk); 4768c2ecf20Sopenharmony_ci if (ret) { 4778c2ecf20Sopenharmony_ci module_put(new_transport->module); 4788c2ecf20Sopenharmony_ci return ret; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci vsk->transport = new_transport; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return 0; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_assign_transport); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cibool vsock_find_cid(unsigned int cid) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci if (transport_g2h && cid == transport_g2h->get_local_cid()) 4908c2ecf20Sopenharmony_ci return true; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (transport_h2g && cid == VMADDR_CID_HOST) 4938c2ecf20Sopenharmony_ci return true; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (transport_local && cid == VMADDR_CID_LOCAL) 4968c2ecf20Sopenharmony_ci return true; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return false; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_find_cid); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic struct sock *vsock_dequeue_accept(struct sock *listener) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct vsock_sock *vlistener; 5058c2ecf20Sopenharmony_ci struct vsock_sock *vconnected; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci vlistener = vsock_sk(listener); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (list_empty(&vlistener->accept_queue)) 5108c2ecf20Sopenharmony_ci return NULL; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci vconnected = list_entry(vlistener->accept_queue.next, 5138c2ecf20Sopenharmony_ci struct vsock_sock, accept_queue); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci list_del_init(&vconnected->accept_queue); 5168c2ecf20Sopenharmony_ci sock_put(listener); 5178c2ecf20Sopenharmony_ci /* The caller will need a reference on the connected socket so we let 5188c2ecf20Sopenharmony_ci * it call sock_put(). 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return sk_vsock(vconnected); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic bool vsock_is_accept_queue_empty(struct sock *sk) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 5278c2ecf20Sopenharmony_ci return list_empty(&vsk->accept_queue); 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic bool vsock_is_pending(struct sock *sk) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 5338c2ecf20Sopenharmony_ci return !list_empty(&vsk->pending_links); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic int vsock_send_shutdown(struct sock *sk, int mode) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (!vsk->transport) 5418c2ecf20Sopenharmony_ci return -ENODEV; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return vsk->transport->shutdown(vsk, mode); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void vsock_pending_work(struct work_struct *work) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct sock *sk; 5498c2ecf20Sopenharmony_ci struct sock *listener; 5508c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 5518c2ecf20Sopenharmony_ci bool cleanup; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci vsk = container_of(work, struct vsock_sock, pending_work.work); 5548c2ecf20Sopenharmony_ci sk = sk_vsock(vsk); 5558c2ecf20Sopenharmony_ci listener = vsk->listener; 5568c2ecf20Sopenharmony_ci cleanup = true; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci lock_sock(listener); 5598c2ecf20Sopenharmony_ci lock_sock_nested(sk, SINGLE_DEPTH_NESTING); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (vsock_is_pending(sk)) { 5628c2ecf20Sopenharmony_ci vsock_remove_pending(listener, sk); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci sk_acceptq_removed(listener); 5658c2ecf20Sopenharmony_ci } else if (!vsk->rejected) { 5668c2ecf20Sopenharmony_ci /* We are not on the pending list and accept() did not reject 5678c2ecf20Sopenharmony_ci * us, so we must have been accepted by our user process. We 5688c2ecf20Sopenharmony_ci * just need to drop our references to the sockets and be on 5698c2ecf20Sopenharmony_ci * our way. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci cleanup = false; 5728c2ecf20Sopenharmony_ci goto out; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* We need to remove ourself from the global connected sockets list so 5768c2ecf20Sopenharmony_ci * incoming packets can't find this socket, and to reduce the reference 5778c2ecf20Sopenharmony_ci * count. 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci vsock_remove_connected(vsk); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ciout: 5848c2ecf20Sopenharmony_ci release_sock(sk); 5858c2ecf20Sopenharmony_ci release_sock(listener); 5868c2ecf20Sopenharmony_ci if (cleanup) 5878c2ecf20Sopenharmony_ci sock_put(sk); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci sock_put(sk); 5908c2ecf20Sopenharmony_ci sock_put(listener); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/**** SOCKET OPERATIONS ****/ 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int __vsock_bind_stream(struct vsock_sock *vsk, 5968c2ecf20Sopenharmony_ci struct sockaddr_vm *addr) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci static u32 port; 5998c2ecf20Sopenharmony_ci struct sockaddr_vm new_addr; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (!port) 6028c2ecf20Sopenharmony_ci port = LAST_RESERVED_PORT + 1 + 6038c2ecf20Sopenharmony_ci prandom_u32_max(U32_MAX - LAST_RESERVED_PORT); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci vsock_addr_init(&new_addr, addr->svm_cid, addr->svm_port); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (addr->svm_port == VMADDR_PORT_ANY) { 6088c2ecf20Sopenharmony_ci bool found = false; 6098c2ecf20Sopenharmony_ci unsigned int i; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci for (i = 0; i < MAX_PORT_RETRIES; i++) { 6128c2ecf20Sopenharmony_ci if (port <= LAST_RESERVED_PORT) 6138c2ecf20Sopenharmony_ci port = LAST_RESERVED_PORT + 1; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci new_addr.svm_port = port++; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (!__vsock_find_bound_socket(&new_addr)) { 6188c2ecf20Sopenharmony_ci found = true; 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (!found) 6248c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 6258c2ecf20Sopenharmony_ci } else { 6268c2ecf20Sopenharmony_ci /* If port is in reserved range, ensure caller 6278c2ecf20Sopenharmony_ci * has necessary privileges. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci if (addr->svm_port <= LAST_RESERVED_PORT && 6308c2ecf20Sopenharmony_ci !capable(CAP_NET_BIND_SERVICE)) { 6318c2ecf20Sopenharmony_ci return -EACCES; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (__vsock_find_bound_socket(&new_addr)) 6358c2ecf20Sopenharmony_ci return -EADDRINUSE; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci vsock_addr_init(&vsk->local_addr, new_addr.svm_cid, new_addr.svm_port); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Remove stream sockets from the unbound list and add them to the hash 6418c2ecf20Sopenharmony_ci * table for easy lookup by its address. The unbound list is simply an 6428c2ecf20Sopenharmony_ci * extra entry at the end of the hash table, a trick used by AF_UNIX. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ci __vsock_remove_bound(vsk); 6458c2ecf20Sopenharmony_ci __vsock_insert_bound(vsock_bound_sockets(&vsk->local_addr), vsk); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic int __vsock_bind_dgram(struct vsock_sock *vsk, 6518c2ecf20Sopenharmony_ci struct sockaddr_vm *addr) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci return vsk->transport->dgram_bind(vsk, addr); 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 6598c2ecf20Sopenharmony_ci int retval; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* First ensure this socket isn't already bound. */ 6628c2ecf20Sopenharmony_ci if (vsock_addr_bound(&vsk->local_addr)) 6638c2ecf20Sopenharmony_ci return -EINVAL; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Now bind to the provided address or select appropriate values if 6668c2ecf20Sopenharmony_ci * none are provided (VMADDR_CID_ANY and VMADDR_PORT_ANY). Note that 6678c2ecf20Sopenharmony_ci * like AF_INET prevents binding to a non-local IP address (in most 6688c2ecf20Sopenharmony_ci * cases), we only allow binding to a local CID. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci if (addr->svm_cid != VMADDR_CID_ANY && !vsock_find_cid(addr->svm_cid)) 6718c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci switch (sk->sk_socket->type) { 6748c2ecf20Sopenharmony_ci case SOCK_STREAM: 6758c2ecf20Sopenharmony_ci spin_lock_bh(&vsock_table_lock); 6768c2ecf20Sopenharmony_ci retval = __vsock_bind_stream(vsk, addr); 6778c2ecf20Sopenharmony_ci spin_unlock_bh(&vsock_table_lock); 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci case SOCK_DGRAM: 6818c2ecf20Sopenharmony_ci retval = __vsock_bind_dgram(vsk, addr); 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci default: 6858c2ecf20Sopenharmony_ci retval = -EINVAL; 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return retval; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic void vsock_connect_timeout(struct work_struct *work); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic struct sock *__vsock_create(struct net *net, 6958c2ecf20Sopenharmony_ci struct socket *sock, 6968c2ecf20Sopenharmony_ci struct sock *parent, 6978c2ecf20Sopenharmony_ci gfp_t priority, 6988c2ecf20Sopenharmony_ci unsigned short type, 6998c2ecf20Sopenharmony_ci int kern) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct sock *sk; 7028c2ecf20Sopenharmony_ci struct vsock_sock *psk; 7038c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci sk = sk_alloc(net, AF_VSOCK, priority, &vsock_proto, kern); 7068c2ecf20Sopenharmony_ci if (!sk) 7078c2ecf20Sopenharmony_ci return NULL; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* sk->sk_type is normally set in sock_init_data, but only if sock is 7128c2ecf20Sopenharmony_ci * non-NULL. We make sure that our sockets always have a type by 7138c2ecf20Sopenharmony_ci * setting it here if needed. 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci if (!sock) 7168c2ecf20Sopenharmony_ci sk->sk_type = type; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 7198c2ecf20Sopenharmony_ci vsock_addr_init(&vsk->local_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY); 7208c2ecf20Sopenharmony_ci vsock_addr_init(&vsk->remote_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci sk->sk_destruct = vsock_sk_destruct; 7238c2ecf20Sopenharmony_ci sk->sk_backlog_rcv = vsock_queue_rcv_skb; 7248c2ecf20Sopenharmony_ci sock_reset_flag(sk, SOCK_DONE); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsk->bound_table); 7278c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsk->connected_table); 7288c2ecf20Sopenharmony_ci vsk->listener = NULL; 7298c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsk->pending_links); 7308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsk->accept_queue); 7318c2ecf20Sopenharmony_ci vsk->rejected = false; 7328c2ecf20Sopenharmony_ci vsk->sent_request = false; 7338c2ecf20Sopenharmony_ci vsk->ignore_connecting_rst = false; 7348c2ecf20Sopenharmony_ci vsk->peer_shutdown = 0; 7358c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&vsk->connect_work, vsock_connect_timeout); 7368c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&vsk->pending_work, vsock_pending_work); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci psk = parent ? vsock_sk(parent) : NULL; 7398c2ecf20Sopenharmony_ci if (parent) { 7408c2ecf20Sopenharmony_ci vsk->trusted = psk->trusted; 7418c2ecf20Sopenharmony_ci vsk->owner = get_cred(psk->owner); 7428c2ecf20Sopenharmony_ci vsk->connect_timeout = psk->connect_timeout; 7438c2ecf20Sopenharmony_ci vsk->buffer_size = psk->buffer_size; 7448c2ecf20Sopenharmony_ci vsk->buffer_min_size = psk->buffer_min_size; 7458c2ecf20Sopenharmony_ci vsk->buffer_max_size = psk->buffer_max_size; 7468c2ecf20Sopenharmony_ci security_sk_clone(parent, sk); 7478c2ecf20Sopenharmony_ci } else { 7488c2ecf20Sopenharmony_ci vsk->trusted = ns_capable_noaudit(&init_user_ns, CAP_NET_ADMIN); 7498c2ecf20Sopenharmony_ci vsk->owner = get_current_cred(); 7508c2ecf20Sopenharmony_ci vsk->connect_timeout = VSOCK_DEFAULT_CONNECT_TIMEOUT; 7518c2ecf20Sopenharmony_ci vsk->buffer_size = VSOCK_DEFAULT_BUFFER_SIZE; 7528c2ecf20Sopenharmony_ci vsk->buffer_min_size = VSOCK_DEFAULT_BUFFER_MIN_SIZE; 7538c2ecf20Sopenharmony_ci vsk->buffer_max_size = VSOCK_DEFAULT_BUFFER_MAX_SIZE; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci return sk; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic void __vsock_release(struct sock *sk, int level) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci if (sk) { 7628c2ecf20Sopenharmony_ci struct sock *pending; 7638c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 7668c2ecf20Sopenharmony_ci pending = NULL; /* Compiler warning. */ 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* When "level" is SINGLE_DEPTH_NESTING, use the nested 7698c2ecf20Sopenharmony_ci * version to avoid the warning "possible recursive locking 7708c2ecf20Sopenharmony_ci * detected". When "level" is 0, lock_sock_nested(sk, level) 7718c2ecf20Sopenharmony_ci * is the same as lock_sock(sk). 7728c2ecf20Sopenharmony_ci */ 7738c2ecf20Sopenharmony_ci lock_sock_nested(sk, level); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (vsk->transport) 7768c2ecf20Sopenharmony_ci vsk->transport->release(vsk); 7778c2ecf20Sopenharmony_ci else if (sk->sk_type == SOCK_STREAM) 7788c2ecf20Sopenharmony_ci vsock_remove_sock(vsk); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci sock_orphan(sk); 7818c2ecf20Sopenharmony_ci sk->sk_shutdown = SHUTDOWN_MASK; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Clean up any sockets that never were accepted. */ 7868c2ecf20Sopenharmony_ci while ((pending = vsock_dequeue_accept(sk)) != NULL) { 7878c2ecf20Sopenharmony_ci __vsock_release(pending, SINGLE_DEPTH_NESTING); 7888c2ecf20Sopenharmony_ci sock_put(pending); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci release_sock(sk); 7928c2ecf20Sopenharmony_ci sock_put(sk); 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic void vsock_sk_destruct(struct sock *sk) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci vsock_deassign_transport(vsk); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* When clearing these addresses, there's no need to set the family and 8038c2ecf20Sopenharmony_ci * possibly register the address family with the kernel. 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_ci vsock_addr_init(&vsk->local_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY); 8068c2ecf20Sopenharmony_ci vsock_addr_init(&vsk->remote_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci put_cred(vsk->owner); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int vsock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci int err; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci err = sock_queue_rcv_skb(sk, skb); 8168c2ecf20Sopenharmony_ci if (err) 8178c2ecf20Sopenharmony_ci kfree_skb(skb); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci return err; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistruct sock *vsock_create_connected(struct sock *parent) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci return __vsock_create(sock_net(parent), NULL, parent, GFP_KERNEL, 8258c2ecf20Sopenharmony_ci parent->sk_type, 0); 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_create_connected); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cis64 vsock_stream_has_data(struct vsock_sock *vsk) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci return vsk->transport->stream_has_data(vsk); 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_stream_has_data); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cis64 vsock_stream_has_space(struct vsock_sock *vsk) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci return vsk->transport->stream_has_space(vsk); 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_stream_has_space); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic int vsock_release(struct socket *sock) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci __vsock_release(sock->sk, 0); 8448c2ecf20Sopenharmony_ci sock->sk = NULL; 8458c2ecf20Sopenharmony_ci sock->state = SS_FREE; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return 0; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic int 8518c2ecf20Sopenharmony_civsock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci int err; 8548c2ecf20Sopenharmony_ci struct sock *sk; 8558c2ecf20Sopenharmony_ci struct sockaddr_vm *vm_addr; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci sk = sock->sk; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (vsock_addr_cast(addr, addr_len, &vm_addr) != 0) 8608c2ecf20Sopenharmony_ci return -EINVAL; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci lock_sock(sk); 8638c2ecf20Sopenharmony_ci err = __vsock_bind(sk, vm_addr); 8648c2ecf20Sopenharmony_ci release_sock(sk); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return err; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cistatic int vsock_getname(struct socket *sock, 8708c2ecf20Sopenharmony_ci struct sockaddr *addr, int peer) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci int err; 8738c2ecf20Sopenharmony_ci struct sock *sk; 8748c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 8758c2ecf20Sopenharmony_ci struct sockaddr_vm *vm_addr; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci sk = sock->sk; 8788c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 8798c2ecf20Sopenharmony_ci err = 0; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci lock_sock(sk); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (peer) { 8848c2ecf20Sopenharmony_ci if (sock->state != SS_CONNECTED) { 8858c2ecf20Sopenharmony_ci err = -ENOTCONN; 8868c2ecf20Sopenharmony_ci goto out; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci vm_addr = &vsk->remote_addr; 8898c2ecf20Sopenharmony_ci } else { 8908c2ecf20Sopenharmony_ci vm_addr = &vsk->local_addr; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (!vm_addr) { 8948c2ecf20Sopenharmony_ci err = -EINVAL; 8958c2ecf20Sopenharmony_ci goto out; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* sys_getsockname() and sys_getpeername() pass us a 8998c2ecf20Sopenharmony_ci * MAX_SOCK_ADDR-sized buffer and don't set addr_len. Unfortunately 9008c2ecf20Sopenharmony_ci * that macro is defined in socket.c instead of .h, so we hardcode its 9018c2ecf20Sopenharmony_ci * value here. 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(*vm_addr) > 128); 9048c2ecf20Sopenharmony_ci memcpy(addr, vm_addr, sizeof(*vm_addr)); 9058c2ecf20Sopenharmony_ci err = sizeof(*vm_addr); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ciout: 9088c2ecf20Sopenharmony_ci release_sock(sk); 9098c2ecf20Sopenharmony_ci return err; 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic int vsock_shutdown(struct socket *sock, int mode) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci int err; 9158c2ecf20Sopenharmony_ci struct sock *sk; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* User level uses SHUT_RD (0) and SHUT_WR (1), but the kernel uses 9188c2ecf20Sopenharmony_ci * RCV_SHUTDOWN (1) and SEND_SHUTDOWN (2), so we must increment mode 9198c2ecf20Sopenharmony_ci * here like the other address families do. Note also that the 9208c2ecf20Sopenharmony_ci * increment makes SHUT_RDWR (2) into RCV_SHUTDOWN | SEND_SHUTDOWN (3), 9218c2ecf20Sopenharmony_ci * which is what we want. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci mode++; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if ((mode & ~SHUTDOWN_MASK) || !mode) 9268c2ecf20Sopenharmony_ci return -EINVAL; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci /* If this is a STREAM socket and it is not connected then bail out 9298c2ecf20Sopenharmony_ci * immediately. If it is a DGRAM socket then we must first kick the 9308c2ecf20Sopenharmony_ci * socket so that it wakes up from any sleeping calls, for example 9318c2ecf20Sopenharmony_ci * recv(), and then afterwards return the error. 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci sk = sock->sk; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci lock_sock(sk); 9378c2ecf20Sopenharmony_ci if (sock->state == SS_UNCONNECTED) { 9388c2ecf20Sopenharmony_ci err = -ENOTCONN; 9398c2ecf20Sopenharmony_ci if (sk->sk_type == SOCK_STREAM) 9408c2ecf20Sopenharmony_ci goto out; 9418c2ecf20Sopenharmony_ci } else { 9428c2ecf20Sopenharmony_ci sock->state = SS_DISCONNECTING; 9438c2ecf20Sopenharmony_ci err = 0; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* Receive and send shutdowns are treated alike. */ 9478c2ecf20Sopenharmony_ci mode = mode & (RCV_SHUTDOWN | SEND_SHUTDOWN); 9488c2ecf20Sopenharmony_ci if (mode) { 9498c2ecf20Sopenharmony_ci sk->sk_shutdown |= mode; 9508c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (sk->sk_type == SOCK_STREAM) { 9538c2ecf20Sopenharmony_ci sock_reset_flag(sk, SOCK_DONE); 9548c2ecf20Sopenharmony_ci vsock_send_shutdown(sk, mode); 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ciout: 9598c2ecf20Sopenharmony_ci release_sock(sk); 9608c2ecf20Sopenharmony_ci return err; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic __poll_t vsock_poll(struct file *file, struct socket *sock, 9648c2ecf20Sopenharmony_ci poll_table *wait) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct sock *sk; 9678c2ecf20Sopenharmony_ci __poll_t mask; 9688c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci sk = sock->sk; 9718c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci poll_wait(file, sk_sleep(sk), wait); 9748c2ecf20Sopenharmony_ci mask = 0; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (sk->sk_err) 9778c2ecf20Sopenharmony_ci /* Signify that there has been an error on this socket. */ 9788c2ecf20Sopenharmony_ci mask |= EPOLLERR; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* INET sockets treat local write shutdown and peer write shutdown as a 9818c2ecf20Sopenharmony_ci * case of EPOLLHUP set. 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_ci if ((sk->sk_shutdown == SHUTDOWN_MASK) || 9848c2ecf20Sopenharmony_ci ((sk->sk_shutdown & SEND_SHUTDOWN) && 9858c2ecf20Sopenharmony_ci (vsk->peer_shutdown & SEND_SHUTDOWN))) { 9868c2ecf20Sopenharmony_ci mask |= EPOLLHUP; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN || 9908c2ecf20Sopenharmony_ci vsk->peer_shutdown & SEND_SHUTDOWN) { 9918c2ecf20Sopenharmony_ci mask |= EPOLLRDHUP; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (sock->type == SOCK_DGRAM) { 9958c2ecf20Sopenharmony_ci /* For datagram sockets we can read if there is something in 9968c2ecf20Sopenharmony_ci * the queue and write as long as the socket isn't shutdown for 9978c2ecf20Sopenharmony_ci * sending. 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_ci if (!skb_queue_empty_lockless(&sk->sk_receive_queue) || 10008c2ecf20Sopenharmony_ci (sk->sk_shutdown & RCV_SHUTDOWN)) { 10018c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (!(sk->sk_shutdown & SEND_SHUTDOWN)) 10058c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci } else if (sock->type == SOCK_STREAM) { 10088c2ecf20Sopenharmony_ci const struct vsock_transport *transport; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci lock_sock(sk); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci transport = vsk->transport; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* Listening sockets that have connections in their accept 10158c2ecf20Sopenharmony_ci * queue can be read. 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_LISTEN 10188c2ecf20Sopenharmony_ci && !vsock_is_accept_queue_empty(sk)) 10198c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* If there is something in the queue then we can read. */ 10228c2ecf20Sopenharmony_ci if (transport && transport->stream_is_active(vsk) && 10238c2ecf20Sopenharmony_ci !(sk->sk_shutdown & RCV_SHUTDOWN)) { 10248c2ecf20Sopenharmony_ci bool data_ready_now = false; 10258c2ecf20Sopenharmony_ci int ret = transport->notify_poll_in( 10268c2ecf20Sopenharmony_ci vsk, 1, &data_ready_now); 10278c2ecf20Sopenharmony_ci if (ret < 0) { 10288c2ecf20Sopenharmony_ci mask |= EPOLLERR; 10298c2ecf20Sopenharmony_ci } else { 10308c2ecf20Sopenharmony_ci if (data_ready_now) 10318c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* Sockets whose connections have been closed, reset, or 10378c2ecf20Sopenharmony_ci * terminated should also be considered read, and we check the 10388c2ecf20Sopenharmony_ci * shutdown flag for that. 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN || 10418c2ecf20Sopenharmony_ci vsk->peer_shutdown & SEND_SHUTDOWN) { 10428c2ecf20Sopenharmony_ci mask |= EPOLLIN | EPOLLRDNORM; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci /* Connected sockets that can produce data can be written. */ 10468c2ecf20Sopenharmony_ci if (transport && sk->sk_state == TCP_ESTABLISHED) { 10478c2ecf20Sopenharmony_ci if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { 10488c2ecf20Sopenharmony_ci bool space_avail_now = false; 10498c2ecf20Sopenharmony_ci int ret = transport->notify_poll_out( 10508c2ecf20Sopenharmony_ci vsk, 1, &space_avail_now); 10518c2ecf20Sopenharmony_ci if (ret < 0) { 10528c2ecf20Sopenharmony_ci mask |= EPOLLERR; 10538c2ecf20Sopenharmony_ci } else { 10548c2ecf20Sopenharmony_ci if (space_avail_now) 10558c2ecf20Sopenharmony_ci /* Remove EPOLLWRBAND since INET 10568c2ecf20Sopenharmony_ci * sockets are not setting it. 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* Simulate INET socket poll behaviors, which sets 10658c2ecf20Sopenharmony_ci * EPOLLOUT|EPOLLWRNORM when peer is closed and nothing to read, 10668c2ecf20Sopenharmony_ci * but local send is not shutdown. 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_CLOSE || sk->sk_state == TCP_CLOSING) { 10698c2ecf20Sopenharmony_ci if (!(sk->sk_shutdown & SEND_SHUTDOWN)) 10708c2ecf20Sopenharmony_ci mask |= EPOLLOUT | EPOLLWRNORM; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci release_sock(sk); 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return mask; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic int vsock_dgram_sendmsg(struct socket *sock, struct msghdr *msg, 10818c2ecf20Sopenharmony_ci size_t len) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci int err; 10848c2ecf20Sopenharmony_ci struct sock *sk; 10858c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 10868c2ecf20Sopenharmony_ci struct sockaddr_vm *remote_addr; 10878c2ecf20Sopenharmony_ci const struct vsock_transport *transport; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (msg->msg_flags & MSG_OOB) 10908c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci /* For now, MSG_DONTWAIT is always assumed... */ 10938c2ecf20Sopenharmony_ci err = 0; 10948c2ecf20Sopenharmony_ci sk = sock->sk; 10958c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci lock_sock(sk); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci transport = vsk->transport; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci err = vsock_auto_bind(vsk); 11028c2ecf20Sopenharmony_ci if (err) 11038c2ecf20Sopenharmony_ci goto out; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* If the provided message contains an address, use that. Otherwise 11078c2ecf20Sopenharmony_ci * fall back on the socket's remote handle (if it has been connected). 11088c2ecf20Sopenharmony_ci */ 11098c2ecf20Sopenharmony_ci if (msg->msg_name && 11108c2ecf20Sopenharmony_ci vsock_addr_cast(msg->msg_name, msg->msg_namelen, 11118c2ecf20Sopenharmony_ci &remote_addr) == 0) { 11128c2ecf20Sopenharmony_ci /* Ensure this address is of the right type and is a valid 11138c2ecf20Sopenharmony_ci * destination. 11148c2ecf20Sopenharmony_ci */ 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (remote_addr->svm_cid == VMADDR_CID_ANY) 11178c2ecf20Sopenharmony_ci remote_addr->svm_cid = transport->get_local_cid(); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (!vsock_addr_bound(remote_addr)) { 11208c2ecf20Sopenharmony_ci err = -EINVAL; 11218c2ecf20Sopenharmony_ci goto out; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci } else if (sock->state == SS_CONNECTED) { 11248c2ecf20Sopenharmony_ci remote_addr = &vsk->remote_addr; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (remote_addr->svm_cid == VMADDR_CID_ANY) 11278c2ecf20Sopenharmony_ci remote_addr->svm_cid = transport->get_local_cid(); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* XXX Should connect() or this function ensure remote_addr is 11308c2ecf20Sopenharmony_ci * bound? 11318c2ecf20Sopenharmony_ci */ 11328c2ecf20Sopenharmony_ci if (!vsock_addr_bound(&vsk->remote_addr)) { 11338c2ecf20Sopenharmony_ci err = -EINVAL; 11348c2ecf20Sopenharmony_ci goto out; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci } else { 11378c2ecf20Sopenharmony_ci err = -EINVAL; 11388c2ecf20Sopenharmony_ci goto out; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (!transport->dgram_allow(remote_addr->svm_cid, 11428c2ecf20Sopenharmony_ci remote_addr->svm_port)) { 11438c2ecf20Sopenharmony_ci err = -EINVAL; 11448c2ecf20Sopenharmony_ci goto out; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci err = transport->dgram_enqueue(vsk, remote_addr, msg, len); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ciout: 11508c2ecf20Sopenharmony_ci release_sock(sk); 11518c2ecf20Sopenharmony_ci return err; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_cistatic int vsock_dgram_connect(struct socket *sock, 11558c2ecf20Sopenharmony_ci struct sockaddr *addr, int addr_len, int flags) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci int err; 11588c2ecf20Sopenharmony_ci struct sock *sk; 11598c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 11608c2ecf20Sopenharmony_ci struct sockaddr_vm *remote_addr; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci sk = sock->sk; 11638c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci err = vsock_addr_cast(addr, addr_len, &remote_addr); 11668c2ecf20Sopenharmony_ci if (err == -EAFNOSUPPORT && remote_addr->svm_family == AF_UNSPEC) { 11678c2ecf20Sopenharmony_ci lock_sock(sk); 11688c2ecf20Sopenharmony_ci vsock_addr_init(&vsk->remote_addr, VMADDR_CID_ANY, 11698c2ecf20Sopenharmony_ci VMADDR_PORT_ANY); 11708c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 11718c2ecf20Sopenharmony_ci release_sock(sk); 11728c2ecf20Sopenharmony_ci return 0; 11738c2ecf20Sopenharmony_ci } else if (err != 0) 11748c2ecf20Sopenharmony_ci return -EINVAL; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci lock_sock(sk); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci err = vsock_auto_bind(vsk); 11798c2ecf20Sopenharmony_ci if (err) 11808c2ecf20Sopenharmony_ci goto out; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (!vsk->transport->dgram_allow(remote_addr->svm_cid, 11838c2ecf20Sopenharmony_ci remote_addr->svm_port)) { 11848c2ecf20Sopenharmony_ci err = -EINVAL; 11858c2ecf20Sopenharmony_ci goto out; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci memcpy(&vsk->remote_addr, remote_addr, sizeof(vsk->remote_addr)); 11898c2ecf20Sopenharmony_ci sock->state = SS_CONNECTED; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ciout: 11928c2ecf20Sopenharmony_ci release_sock(sk); 11938c2ecf20Sopenharmony_ci return err; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg, 11978c2ecf20Sopenharmony_ci size_t len, int flags) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sock->sk); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci return vsk->transport->dgram_dequeue(vsk, msg, len, flags); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_cistatic const struct proto_ops vsock_dgram_ops = { 12058c2ecf20Sopenharmony_ci .family = PF_VSOCK, 12068c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12078c2ecf20Sopenharmony_ci .release = vsock_release, 12088c2ecf20Sopenharmony_ci .bind = vsock_bind, 12098c2ecf20Sopenharmony_ci .connect = vsock_dgram_connect, 12108c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 12118c2ecf20Sopenharmony_ci .accept = sock_no_accept, 12128c2ecf20Sopenharmony_ci .getname = vsock_getname, 12138c2ecf20Sopenharmony_ci .poll = vsock_poll, 12148c2ecf20Sopenharmony_ci .ioctl = sock_no_ioctl, 12158c2ecf20Sopenharmony_ci .listen = sock_no_listen, 12168c2ecf20Sopenharmony_ci .shutdown = vsock_shutdown, 12178c2ecf20Sopenharmony_ci .sendmsg = vsock_dgram_sendmsg, 12188c2ecf20Sopenharmony_ci .recvmsg = vsock_dgram_recvmsg, 12198c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 12208c2ecf20Sopenharmony_ci .sendpage = sock_no_sendpage, 12218c2ecf20Sopenharmony_ci}; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic int vsock_transport_cancel_pkt(struct vsock_sock *vsk) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci const struct vsock_transport *transport = vsk->transport; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (!transport || !transport->cancel_pkt) 12288c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci return transport->cancel_pkt(vsk); 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic void vsock_connect_timeout(struct work_struct *work) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct sock *sk; 12368c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci vsk = container_of(work, struct vsock_sock, connect_work.work); 12398c2ecf20Sopenharmony_ci sk = sk_vsock(vsk); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci lock_sock(sk); 12428c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_SYN_SENT && 12438c2ecf20Sopenharmony_ci (sk->sk_shutdown != SHUTDOWN_MASK)) { 12448c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 12458c2ecf20Sopenharmony_ci sk->sk_socket->state = SS_UNCONNECTED; 12468c2ecf20Sopenharmony_ci sk->sk_err = ETIMEDOUT; 12478c2ecf20Sopenharmony_ci sk->sk_error_report(sk); 12488c2ecf20Sopenharmony_ci vsock_transport_cancel_pkt(vsk); 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci release_sock(sk); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci sock_put(sk); 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic int vsock_stream_connect(struct socket *sock, struct sockaddr *addr, 12568c2ecf20Sopenharmony_ci int addr_len, int flags) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci int err; 12598c2ecf20Sopenharmony_ci struct sock *sk; 12608c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 12618c2ecf20Sopenharmony_ci const struct vsock_transport *transport; 12628c2ecf20Sopenharmony_ci struct sockaddr_vm *remote_addr; 12638c2ecf20Sopenharmony_ci long timeout; 12648c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci err = 0; 12678c2ecf20Sopenharmony_ci sk = sock->sk; 12688c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci lock_sock(sk); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* XXX AF_UNSPEC should make us disconnect like AF_INET. */ 12738c2ecf20Sopenharmony_ci switch (sock->state) { 12748c2ecf20Sopenharmony_ci case SS_CONNECTED: 12758c2ecf20Sopenharmony_ci err = -EISCONN; 12768c2ecf20Sopenharmony_ci goto out; 12778c2ecf20Sopenharmony_ci case SS_DISCONNECTING: 12788c2ecf20Sopenharmony_ci err = -EINVAL; 12798c2ecf20Sopenharmony_ci goto out; 12808c2ecf20Sopenharmony_ci case SS_CONNECTING: 12818c2ecf20Sopenharmony_ci /* This continues on so we can move sock into the SS_CONNECTED 12828c2ecf20Sopenharmony_ci * state once the connection has completed (at which point err 12838c2ecf20Sopenharmony_ci * will be set to zero also). Otherwise, we will either wait 12848c2ecf20Sopenharmony_ci * for the connection or return -EALREADY should this be a 12858c2ecf20Sopenharmony_ci * non-blocking call. 12868c2ecf20Sopenharmony_ci */ 12878c2ecf20Sopenharmony_ci err = -EALREADY; 12888c2ecf20Sopenharmony_ci if (flags & O_NONBLOCK) 12898c2ecf20Sopenharmony_ci goto out; 12908c2ecf20Sopenharmony_ci break; 12918c2ecf20Sopenharmony_ci default: 12928c2ecf20Sopenharmony_ci if ((sk->sk_state == TCP_LISTEN) || 12938c2ecf20Sopenharmony_ci vsock_addr_cast(addr, addr_len, &remote_addr) != 0) { 12948c2ecf20Sopenharmony_ci err = -EINVAL; 12958c2ecf20Sopenharmony_ci goto out; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* Set the remote address that we are connecting to. */ 12998c2ecf20Sopenharmony_ci memcpy(&vsk->remote_addr, remote_addr, 13008c2ecf20Sopenharmony_ci sizeof(vsk->remote_addr)); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci err = vsock_assign_transport(vsk, NULL); 13038c2ecf20Sopenharmony_ci if (err) 13048c2ecf20Sopenharmony_ci goto out; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci transport = vsk->transport; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* The hypervisor and well-known contexts do not have socket 13098c2ecf20Sopenharmony_ci * endpoints. 13108c2ecf20Sopenharmony_ci */ 13118c2ecf20Sopenharmony_ci if (!transport || 13128c2ecf20Sopenharmony_ci !transport->stream_allow(remote_addr->svm_cid, 13138c2ecf20Sopenharmony_ci remote_addr->svm_port)) { 13148c2ecf20Sopenharmony_ci err = -ENETUNREACH; 13158c2ecf20Sopenharmony_ci goto out; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci err = vsock_auto_bind(vsk); 13198c2ecf20Sopenharmony_ci if (err) 13208c2ecf20Sopenharmony_ci goto out; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci sk->sk_state = TCP_SYN_SENT; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci err = transport->connect(vsk); 13258c2ecf20Sopenharmony_ci if (err < 0) 13268c2ecf20Sopenharmony_ci goto out; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* Mark sock as connecting and set the error code to in 13298c2ecf20Sopenharmony_ci * progress in case this is a non-blocking connect. 13308c2ecf20Sopenharmony_ci */ 13318c2ecf20Sopenharmony_ci sock->state = SS_CONNECTING; 13328c2ecf20Sopenharmony_ci err = -EINPROGRESS; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* The receive path will handle all communication until we are able to 13368c2ecf20Sopenharmony_ci * enter the connected state. Here we wait for the connection to be 13378c2ecf20Sopenharmony_ci * completed or a notification of an error. 13388c2ecf20Sopenharmony_ci */ 13398c2ecf20Sopenharmony_ci timeout = vsk->connect_timeout; 13408c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci while (sk->sk_state != TCP_ESTABLISHED && sk->sk_err == 0) { 13438c2ecf20Sopenharmony_ci if (flags & O_NONBLOCK) { 13448c2ecf20Sopenharmony_ci /* If we're not going to block, we schedule a timeout 13458c2ecf20Sopenharmony_ci * function to generate a timeout on the connection 13468c2ecf20Sopenharmony_ci * attempt, in case the peer doesn't respond in a 13478c2ecf20Sopenharmony_ci * timely manner. We hold on to the socket until the 13488c2ecf20Sopenharmony_ci * timeout fires. 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_ci sock_hold(sk); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* If the timeout function is already scheduled, 13538c2ecf20Sopenharmony_ci * reschedule it, then ungrab the socket refcount to 13548c2ecf20Sopenharmony_ci * keep it balanced. 13558c2ecf20Sopenharmony_ci */ 13568c2ecf20Sopenharmony_ci if (mod_delayed_work(system_wq, &vsk->connect_work, 13578c2ecf20Sopenharmony_ci timeout)) 13588c2ecf20Sopenharmony_ci sock_put(sk); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* Skip ahead to preserve error code set above. */ 13618c2ecf20Sopenharmony_ci goto out_wait; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci release_sock(sk); 13658c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 13668c2ecf20Sopenharmony_ci lock_sock(sk); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (signal_pending(current)) { 13698c2ecf20Sopenharmony_ci err = sock_intr_errno(timeout); 13708c2ecf20Sopenharmony_ci sk->sk_state = sk->sk_state == TCP_ESTABLISHED ? TCP_CLOSING : TCP_CLOSE; 13718c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 13728c2ecf20Sopenharmony_ci vsock_transport_cancel_pkt(vsk); 13738c2ecf20Sopenharmony_ci vsock_remove_connected(vsk); 13748c2ecf20Sopenharmony_ci goto out_wait; 13758c2ecf20Sopenharmony_ci } else if ((sk->sk_state != TCP_ESTABLISHED) && (timeout == 0)) { 13768c2ecf20Sopenharmony_ci err = -ETIMEDOUT; 13778c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 13788c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 13798c2ecf20Sopenharmony_ci vsock_transport_cancel_pkt(vsk); 13808c2ecf20Sopenharmony_ci goto out_wait; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (sk->sk_err) { 13878c2ecf20Sopenharmony_ci err = -sk->sk_err; 13888c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 13898c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 13908c2ecf20Sopenharmony_ci } else { 13918c2ecf20Sopenharmony_ci err = 0; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ciout_wait: 13958c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 13968c2ecf20Sopenharmony_ciout: 13978c2ecf20Sopenharmony_ci release_sock(sk); 13988c2ecf20Sopenharmony_ci return err; 13998c2ecf20Sopenharmony_ci} 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic int vsock_accept(struct socket *sock, struct socket *newsock, int flags, 14028c2ecf20Sopenharmony_ci bool kern) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct sock *listener; 14058c2ecf20Sopenharmony_ci int err; 14068c2ecf20Sopenharmony_ci struct sock *connected; 14078c2ecf20Sopenharmony_ci struct vsock_sock *vconnected; 14088c2ecf20Sopenharmony_ci long timeout; 14098c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci err = 0; 14128c2ecf20Sopenharmony_ci listener = sock->sk; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci lock_sock(listener); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (sock->type != SOCK_STREAM) { 14178c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 14188c2ecf20Sopenharmony_ci goto out; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (listener->sk_state != TCP_LISTEN) { 14228c2ecf20Sopenharmony_ci err = -EINVAL; 14238c2ecf20Sopenharmony_ci goto out; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci /* Wait for children sockets to appear; these are the new sockets 14278c2ecf20Sopenharmony_ci * created upon connection establishment. 14288c2ecf20Sopenharmony_ci */ 14298c2ecf20Sopenharmony_ci timeout = sock_rcvtimeo(listener, flags & O_NONBLOCK); 14308c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci while ((connected = vsock_dequeue_accept(listener)) == NULL && 14338c2ecf20Sopenharmony_ci listener->sk_err == 0) { 14348c2ecf20Sopenharmony_ci release_sock(listener); 14358c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 14368c2ecf20Sopenharmony_ci finish_wait(sk_sleep(listener), &wait); 14378c2ecf20Sopenharmony_ci lock_sock(listener); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci if (signal_pending(current)) { 14408c2ecf20Sopenharmony_ci err = sock_intr_errno(timeout); 14418c2ecf20Sopenharmony_ci goto out; 14428c2ecf20Sopenharmony_ci } else if (timeout == 0) { 14438c2ecf20Sopenharmony_ci err = -EAGAIN; 14448c2ecf20Sopenharmony_ci goto out; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE); 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci finish_wait(sk_sleep(listener), &wait); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (listener->sk_err) 14528c2ecf20Sopenharmony_ci err = -listener->sk_err; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (connected) { 14558c2ecf20Sopenharmony_ci sk_acceptq_removed(listener); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci lock_sock_nested(connected, SINGLE_DEPTH_NESTING); 14588c2ecf20Sopenharmony_ci vconnected = vsock_sk(connected); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* If the listener socket has received an error, then we should 14618c2ecf20Sopenharmony_ci * reject this socket and return. Note that we simply mark the 14628c2ecf20Sopenharmony_ci * socket rejected, drop our reference, and let the cleanup 14638c2ecf20Sopenharmony_ci * function handle the cleanup; the fact that we found it in 14648c2ecf20Sopenharmony_ci * the listener's accept queue guarantees that the cleanup 14658c2ecf20Sopenharmony_ci * function hasn't run yet. 14668c2ecf20Sopenharmony_ci */ 14678c2ecf20Sopenharmony_ci if (err) { 14688c2ecf20Sopenharmony_ci vconnected->rejected = true; 14698c2ecf20Sopenharmony_ci } else { 14708c2ecf20Sopenharmony_ci newsock->state = SS_CONNECTED; 14718c2ecf20Sopenharmony_ci sock_graft(connected, newsock); 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci release_sock(connected); 14758c2ecf20Sopenharmony_ci sock_put(connected); 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ciout: 14798c2ecf20Sopenharmony_ci release_sock(listener); 14808c2ecf20Sopenharmony_ci return err; 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_cistatic int vsock_listen(struct socket *sock, int backlog) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci int err; 14868c2ecf20Sopenharmony_ci struct sock *sk; 14878c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci sk = sock->sk; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci lock_sock(sk); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci if (sock->type != SOCK_STREAM) { 14948c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 14958c2ecf20Sopenharmony_ci goto out; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (sock->state != SS_UNCONNECTED) { 14998c2ecf20Sopenharmony_ci err = -EINVAL; 15008c2ecf20Sopenharmony_ci goto out; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if (!vsock_addr_bound(&vsk->local_addr)) { 15068c2ecf20Sopenharmony_ci err = -EINVAL; 15078c2ecf20Sopenharmony_ci goto out; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci sk->sk_max_ack_backlog = backlog; 15118c2ecf20Sopenharmony_ci sk->sk_state = TCP_LISTEN; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci err = 0; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ciout: 15168c2ecf20Sopenharmony_ci release_sock(sk); 15178c2ecf20Sopenharmony_ci return err; 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cistatic void vsock_update_buffer_size(struct vsock_sock *vsk, 15218c2ecf20Sopenharmony_ci const struct vsock_transport *transport, 15228c2ecf20Sopenharmony_ci u64 val) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci if (val > vsk->buffer_max_size) 15258c2ecf20Sopenharmony_ci val = vsk->buffer_max_size; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci if (val < vsk->buffer_min_size) 15288c2ecf20Sopenharmony_ci val = vsk->buffer_min_size; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (val != vsk->buffer_size && 15318c2ecf20Sopenharmony_ci transport && transport->notify_buffer_size) 15328c2ecf20Sopenharmony_ci transport->notify_buffer_size(vsk, &val); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci vsk->buffer_size = val; 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_cistatic int vsock_stream_setsockopt(struct socket *sock, 15388c2ecf20Sopenharmony_ci int level, 15398c2ecf20Sopenharmony_ci int optname, 15408c2ecf20Sopenharmony_ci sockptr_t optval, 15418c2ecf20Sopenharmony_ci unsigned int optlen) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci int err; 15448c2ecf20Sopenharmony_ci struct sock *sk; 15458c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 15468c2ecf20Sopenharmony_ci const struct vsock_transport *transport; 15478c2ecf20Sopenharmony_ci u64 val; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (level != AF_VSOCK) 15508c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci#define COPY_IN(_v) \ 15538c2ecf20Sopenharmony_ci do { \ 15548c2ecf20Sopenharmony_ci if (optlen < sizeof(_v)) { \ 15558c2ecf20Sopenharmony_ci err = -EINVAL; \ 15568c2ecf20Sopenharmony_ci goto exit; \ 15578c2ecf20Sopenharmony_ci } \ 15588c2ecf20Sopenharmony_ci if (copy_from_sockptr(&_v, optval, sizeof(_v)) != 0) { \ 15598c2ecf20Sopenharmony_ci err = -EFAULT; \ 15608c2ecf20Sopenharmony_ci goto exit; \ 15618c2ecf20Sopenharmony_ci } \ 15628c2ecf20Sopenharmony_ci } while (0) 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci err = 0; 15658c2ecf20Sopenharmony_ci sk = sock->sk; 15668c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci lock_sock(sk); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci transport = vsk->transport; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci switch (optname) { 15738c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_BUFFER_SIZE: 15748c2ecf20Sopenharmony_ci COPY_IN(val); 15758c2ecf20Sopenharmony_ci vsock_update_buffer_size(vsk, transport, val); 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_BUFFER_MAX_SIZE: 15798c2ecf20Sopenharmony_ci COPY_IN(val); 15808c2ecf20Sopenharmony_ci vsk->buffer_max_size = val; 15818c2ecf20Sopenharmony_ci vsock_update_buffer_size(vsk, transport, vsk->buffer_size); 15828c2ecf20Sopenharmony_ci break; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_BUFFER_MIN_SIZE: 15858c2ecf20Sopenharmony_ci COPY_IN(val); 15868c2ecf20Sopenharmony_ci vsk->buffer_min_size = val; 15878c2ecf20Sopenharmony_ci vsock_update_buffer_size(vsk, transport, vsk->buffer_size); 15888c2ecf20Sopenharmony_ci break; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_CONNECT_TIMEOUT: { 15918c2ecf20Sopenharmony_ci struct __kernel_old_timeval tv; 15928c2ecf20Sopenharmony_ci COPY_IN(tv); 15938c2ecf20Sopenharmony_ci if (tv.tv_sec >= 0 && tv.tv_usec < USEC_PER_SEC && 15948c2ecf20Sopenharmony_ci tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1)) { 15958c2ecf20Sopenharmony_ci vsk->connect_timeout = tv.tv_sec * HZ + 15968c2ecf20Sopenharmony_ci DIV_ROUND_UP(tv.tv_usec, (1000000 / HZ)); 15978c2ecf20Sopenharmony_ci if (vsk->connect_timeout == 0) 15988c2ecf20Sopenharmony_ci vsk->connect_timeout = 15998c2ecf20Sopenharmony_ci VSOCK_DEFAULT_CONNECT_TIMEOUT; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci } else { 16028c2ecf20Sopenharmony_ci err = -ERANGE; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci break; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci default: 16088c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 16098c2ecf20Sopenharmony_ci break; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci#undef COPY_IN 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ciexit: 16158c2ecf20Sopenharmony_ci release_sock(sk); 16168c2ecf20Sopenharmony_ci return err; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistatic int vsock_stream_getsockopt(struct socket *sock, 16208c2ecf20Sopenharmony_ci int level, int optname, 16218c2ecf20Sopenharmony_ci char __user *optval, 16228c2ecf20Sopenharmony_ci int __user *optlen) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci int err; 16258c2ecf20Sopenharmony_ci int len; 16268c2ecf20Sopenharmony_ci struct sock *sk; 16278c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 16288c2ecf20Sopenharmony_ci u64 val; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci if (level != AF_VSOCK) 16318c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci err = get_user(len, optlen); 16348c2ecf20Sopenharmony_ci if (err != 0) 16358c2ecf20Sopenharmony_ci return err; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci#define COPY_OUT(_v) \ 16388c2ecf20Sopenharmony_ci do { \ 16398c2ecf20Sopenharmony_ci if (len < sizeof(_v)) \ 16408c2ecf20Sopenharmony_ci return -EINVAL; \ 16418c2ecf20Sopenharmony_ci \ 16428c2ecf20Sopenharmony_ci len = sizeof(_v); \ 16438c2ecf20Sopenharmony_ci if (copy_to_user(optval, &_v, len) != 0) \ 16448c2ecf20Sopenharmony_ci return -EFAULT; \ 16458c2ecf20Sopenharmony_ci \ 16468c2ecf20Sopenharmony_ci } while (0) 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci err = 0; 16498c2ecf20Sopenharmony_ci sk = sock->sk; 16508c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci switch (optname) { 16538c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_BUFFER_SIZE: 16548c2ecf20Sopenharmony_ci val = vsk->buffer_size; 16558c2ecf20Sopenharmony_ci COPY_OUT(val); 16568c2ecf20Sopenharmony_ci break; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_BUFFER_MAX_SIZE: 16598c2ecf20Sopenharmony_ci val = vsk->buffer_max_size; 16608c2ecf20Sopenharmony_ci COPY_OUT(val); 16618c2ecf20Sopenharmony_ci break; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_BUFFER_MIN_SIZE: 16648c2ecf20Sopenharmony_ci val = vsk->buffer_min_size; 16658c2ecf20Sopenharmony_ci COPY_OUT(val); 16668c2ecf20Sopenharmony_ci break; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci case SO_VM_SOCKETS_CONNECT_TIMEOUT: { 16698c2ecf20Sopenharmony_ci struct __kernel_old_timeval tv; 16708c2ecf20Sopenharmony_ci tv.tv_sec = vsk->connect_timeout / HZ; 16718c2ecf20Sopenharmony_ci tv.tv_usec = 16728c2ecf20Sopenharmony_ci (vsk->connect_timeout - 16738c2ecf20Sopenharmony_ci tv.tv_sec * HZ) * (1000000 / HZ); 16748c2ecf20Sopenharmony_ci COPY_OUT(tv); 16758c2ecf20Sopenharmony_ci break; 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci default: 16788c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci err = put_user(len, optlen); 16828c2ecf20Sopenharmony_ci if (err != 0) 16838c2ecf20Sopenharmony_ci return -EFAULT; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci#undef COPY_OUT 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci return 0; 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_cistatic int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, 16918c2ecf20Sopenharmony_ci size_t len) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci struct sock *sk; 16948c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 16958c2ecf20Sopenharmony_ci const struct vsock_transport *transport; 16968c2ecf20Sopenharmony_ci ssize_t total_written; 16978c2ecf20Sopenharmony_ci long timeout; 16988c2ecf20Sopenharmony_ci int err; 16998c2ecf20Sopenharmony_ci struct vsock_transport_send_notify_data send_data; 17008c2ecf20Sopenharmony_ci DEFINE_WAIT_FUNC(wait, woken_wake_function); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci sk = sock->sk; 17038c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 17048c2ecf20Sopenharmony_ci total_written = 0; 17058c2ecf20Sopenharmony_ci err = 0; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci if (msg->msg_flags & MSG_OOB) 17088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci lock_sock(sk); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci transport = vsk->transport; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci /* Callers should not provide a destination with stream sockets. */ 17158c2ecf20Sopenharmony_ci if (msg->msg_namelen) { 17168c2ecf20Sopenharmony_ci err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; 17178c2ecf20Sopenharmony_ci goto out; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* Send data only if both sides are not shutdown in the direction. */ 17218c2ecf20Sopenharmony_ci if (sk->sk_shutdown & SEND_SHUTDOWN || 17228c2ecf20Sopenharmony_ci vsk->peer_shutdown & RCV_SHUTDOWN) { 17238c2ecf20Sopenharmony_ci err = -EPIPE; 17248c2ecf20Sopenharmony_ci goto out; 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (!transport || sk->sk_state != TCP_ESTABLISHED || 17288c2ecf20Sopenharmony_ci !vsock_addr_bound(&vsk->local_addr)) { 17298c2ecf20Sopenharmony_ci err = -ENOTCONN; 17308c2ecf20Sopenharmony_ci goto out; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (!vsock_addr_bound(&vsk->remote_addr)) { 17348c2ecf20Sopenharmony_ci err = -EDESTADDRREQ; 17358c2ecf20Sopenharmony_ci goto out; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci /* Wait for room in the produce queue to enqueue our user's data. */ 17398c2ecf20Sopenharmony_ci timeout = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci err = transport->notify_send_init(vsk, &send_data); 17428c2ecf20Sopenharmony_ci if (err < 0) 17438c2ecf20Sopenharmony_ci goto out; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci while (total_written < len) { 17468c2ecf20Sopenharmony_ci ssize_t written; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 17498c2ecf20Sopenharmony_ci while (vsock_stream_has_space(vsk) == 0 && 17508c2ecf20Sopenharmony_ci sk->sk_err == 0 && 17518c2ecf20Sopenharmony_ci !(sk->sk_shutdown & SEND_SHUTDOWN) && 17528c2ecf20Sopenharmony_ci !(vsk->peer_shutdown & RCV_SHUTDOWN)) { 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci /* Don't wait for non-blocking sockets. */ 17558c2ecf20Sopenharmony_ci if (timeout == 0) { 17568c2ecf20Sopenharmony_ci err = -EAGAIN; 17578c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 17588c2ecf20Sopenharmony_ci goto out_err; 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci err = transport->notify_send_pre_block(vsk, &send_data); 17628c2ecf20Sopenharmony_ci if (err < 0) { 17638c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 17648c2ecf20Sopenharmony_ci goto out_err; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci release_sock(sk); 17688c2ecf20Sopenharmony_ci timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, timeout); 17698c2ecf20Sopenharmony_ci lock_sock(sk); 17708c2ecf20Sopenharmony_ci if (signal_pending(current)) { 17718c2ecf20Sopenharmony_ci err = sock_intr_errno(timeout); 17728c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 17738c2ecf20Sopenharmony_ci goto out_err; 17748c2ecf20Sopenharmony_ci } else if (timeout == 0) { 17758c2ecf20Sopenharmony_ci err = -EAGAIN; 17768c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 17778c2ecf20Sopenharmony_ci goto out_err; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci /* These checks occur both as part of and after the loop 17838c2ecf20Sopenharmony_ci * conditional since we need to check before and after 17848c2ecf20Sopenharmony_ci * sleeping. 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci if (sk->sk_err) { 17878c2ecf20Sopenharmony_ci err = -sk->sk_err; 17888c2ecf20Sopenharmony_ci goto out_err; 17898c2ecf20Sopenharmony_ci } else if ((sk->sk_shutdown & SEND_SHUTDOWN) || 17908c2ecf20Sopenharmony_ci (vsk->peer_shutdown & RCV_SHUTDOWN)) { 17918c2ecf20Sopenharmony_ci err = -EPIPE; 17928c2ecf20Sopenharmony_ci goto out_err; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci err = transport->notify_send_pre_enqueue(vsk, &send_data); 17968c2ecf20Sopenharmony_ci if (err < 0) 17978c2ecf20Sopenharmony_ci goto out_err; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci /* Note that enqueue will only write as many bytes as are free 18008c2ecf20Sopenharmony_ci * in the produce queue, so we don't need to ensure len is 18018c2ecf20Sopenharmony_ci * smaller than the queue size. It is the caller's 18028c2ecf20Sopenharmony_ci * responsibility to check how many bytes we were able to send. 18038c2ecf20Sopenharmony_ci */ 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci written = transport->stream_enqueue( 18068c2ecf20Sopenharmony_ci vsk, msg, 18078c2ecf20Sopenharmony_ci len - total_written); 18088c2ecf20Sopenharmony_ci if (written < 0) { 18098c2ecf20Sopenharmony_ci err = -ENOMEM; 18108c2ecf20Sopenharmony_ci goto out_err; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci total_written += written; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci err = transport->notify_send_post_enqueue( 18168c2ecf20Sopenharmony_ci vsk, written, &send_data); 18178c2ecf20Sopenharmony_ci if (err < 0) 18188c2ecf20Sopenharmony_ci goto out_err; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ciout_err: 18238c2ecf20Sopenharmony_ci if (total_written > 0) 18248c2ecf20Sopenharmony_ci err = total_written; 18258c2ecf20Sopenharmony_ciout: 18268c2ecf20Sopenharmony_ci release_sock(sk); 18278c2ecf20Sopenharmony_ci return err; 18288c2ecf20Sopenharmony_ci} 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic int 18328c2ecf20Sopenharmony_civsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 18338c2ecf20Sopenharmony_ci int flags) 18348c2ecf20Sopenharmony_ci{ 18358c2ecf20Sopenharmony_ci struct sock *sk; 18368c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 18378c2ecf20Sopenharmony_ci const struct vsock_transport *transport; 18388c2ecf20Sopenharmony_ci int err; 18398c2ecf20Sopenharmony_ci size_t target; 18408c2ecf20Sopenharmony_ci ssize_t copied; 18418c2ecf20Sopenharmony_ci long timeout; 18428c2ecf20Sopenharmony_ci struct vsock_transport_recv_notify_data recv_data; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci sk = sock->sk; 18478c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 18488c2ecf20Sopenharmony_ci err = 0; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci lock_sock(sk); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci transport = vsk->transport; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci if (!transport || sk->sk_state != TCP_ESTABLISHED) { 18558c2ecf20Sopenharmony_ci /* Recvmsg is supposed to return 0 if a peer performs an 18568c2ecf20Sopenharmony_ci * orderly shutdown. Differentiate between that case and when a 18578c2ecf20Sopenharmony_ci * peer has not connected or a local shutdown occured with the 18588c2ecf20Sopenharmony_ci * SOCK_DONE flag. 18598c2ecf20Sopenharmony_ci */ 18608c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_DONE)) 18618c2ecf20Sopenharmony_ci err = 0; 18628c2ecf20Sopenharmony_ci else 18638c2ecf20Sopenharmony_ci err = -ENOTCONN; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci goto out; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (flags & MSG_OOB) { 18698c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 18708c2ecf20Sopenharmony_ci goto out; 18718c2ecf20Sopenharmony_ci } 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci /* We don't check peer_shutdown flag here since peer may actually shut 18748c2ecf20Sopenharmony_ci * down, but there can be data in the queue that a local socket can 18758c2ecf20Sopenharmony_ci * receive. 18768c2ecf20Sopenharmony_ci */ 18778c2ecf20Sopenharmony_ci if (sk->sk_shutdown & RCV_SHUTDOWN) { 18788c2ecf20Sopenharmony_ci err = 0; 18798c2ecf20Sopenharmony_ci goto out; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci /* It is valid on Linux to pass in a zero-length receive buffer. This 18838c2ecf20Sopenharmony_ci * is not an error. We may as well bail out now. 18848c2ecf20Sopenharmony_ci */ 18858c2ecf20Sopenharmony_ci if (!len) { 18868c2ecf20Sopenharmony_ci err = 0; 18878c2ecf20Sopenharmony_ci goto out; 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* We must not copy less than target bytes into the user's buffer 18918c2ecf20Sopenharmony_ci * before returning successfully, so we wait for the consume queue to 18928c2ecf20Sopenharmony_ci * have that much data to consume before dequeueing. Note that this 18938c2ecf20Sopenharmony_ci * makes it impossible to handle cases where target is greater than the 18948c2ecf20Sopenharmony_ci * queue size. 18958c2ecf20Sopenharmony_ci */ 18968c2ecf20Sopenharmony_ci target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); 18978c2ecf20Sopenharmony_ci if (target >= transport->stream_rcvhiwat(vsk)) { 18988c2ecf20Sopenharmony_ci err = -ENOMEM; 18998c2ecf20Sopenharmony_ci goto out; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); 19028c2ecf20Sopenharmony_ci copied = 0; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci err = transport->notify_recv_init(vsk, target, &recv_data); 19058c2ecf20Sopenharmony_ci if (err < 0) 19068c2ecf20Sopenharmony_ci goto out; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci while (1) { 19108c2ecf20Sopenharmony_ci s64 ready; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 19138c2ecf20Sopenharmony_ci ready = vsock_stream_has_data(vsk); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci if (ready == 0) { 19168c2ecf20Sopenharmony_ci if (sk->sk_err != 0 || 19178c2ecf20Sopenharmony_ci (sk->sk_shutdown & RCV_SHUTDOWN) || 19188c2ecf20Sopenharmony_ci (vsk->peer_shutdown & SEND_SHUTDOWN)) { 19198c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 19208c2ecf20Sopenharmony_ci break; 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci /* Don't wait for non-blocking sockets. */ 19238c2ecf20Sopenharmony_ci if (timeout == 0) { 19248c2ecf20Sopenharmony_ci err = -EAGAIN; 19258c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 19268c2ecf20Sopenharmony_ci break; 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci err = transport->notify_recv_pre_block( 19308c2ecf20Sopenharmony_ci vsk, target, &recv_data); 19318c2ecf20Sopenharmony_ci if (err < 0) { 19328c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 19338c2ecf20Sopenharmony_ci break; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci release_sock(sk); 19368c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 19378c2ecf20Sopenharmony_ci lock_sock(sk); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (signal_pending(current)) { 19408c2ecf20Sopenharmony_ci err = sock_intr_errno(timeout); 19418c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 19428c2ecf20Sopenharmony_ci break; 19438c2ecf20Sopenharmony_ci } else if (timeout == 0) { 19448c2ecf20Sopenharmony_ci err = -EAGAIN; 19458c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 19468c2ecf20Sopenharmony_ci break; 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci } else { 19498c2ecf20Sopenharmony_ci ssize_t read; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci finish_wait(sk_sleep(sk), &wait); 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci if (ready < 0) { 19548c2ecf20Sopenharmony_ci /* Invalid queue pair content. XXX This should 19558c2ecf20Sopenharmony_ci * be changed to a connection reset in a later 19568c2ecf20Sopenharmony_ci * change. 19578c2ecf20Sopenharmony_ci */ 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci err = -ENOMEM; 19608c2ecf20Sopenharmony_ci goto out; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci err = transport->notify_recv_pre_dequeue( 19648c2ecf20Sopenharmony_ci vsk, target, &recv_data); 19658c2ecf20Sopenharmony_ci if (err < 0) 19668c2ecf20Sopenharmony_ci break; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci read = transport->stream_dequeue( 19698c2ecf20Sopenharmony_ci vsk, msg, 19708c2ecf20Sopenharmony_ci len - copied, flags); 19718c2ecf20Sopenharmony_ci if (read < 0) { 19728c2ecf20Sopenharmony_ci err = -ENOMEM; 19738c2ecf20Sopenharmony_ci break; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci copied += read; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci err = transport->notify_recv_post_dequeue( 19798c2ecf20Sopenharmony_ci vsk, target, read, 19808c2ecf20Sopenharmony_ci !(flags & MSG_PEEK), &recv_data); 19818c2ecf20Sopenharmony_ci if (err < 0) 19828c2ecf20Sopenharmony_ci goto out; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if (read >= target || flags & MSG_PEEK) 19858c2ecf20Sopenharmony_ci break; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci target -= read; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (sk->sk_err) 19928c2ecf20Sopenharmony_ci err = -sk->sk_err; 19938c2ecf20Sopenharmony_ci else if (sk->sk_shutdown & RCV_SHUTDOWN) 19948c2ecf20Sopenharmony_ci err = 0; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (copied > 0) 19978c2ecf20Sopenharmony_ci err = copied; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ciout: 20008c2ecf20Sopenharmony_ci release_sock(sk); 20018c2ecf20Sopenharmony_ci return err; 20028c2ecf20Sopenharmony_ci} 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_cistatic const struct proto_ops vsock_stream_ops = { 20058c2ecf20Sopenharmony_ci .family = PF_VSOCK, 20068c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 20078c2ecf20Sopenharmony_ci .release = vsock_release, 20088c2ecf20Sopenharmony_ci .bind = vsock_bind, 20098c2ecf20Sopenharmony_ci .connect = vsock_stream_connect, 20108c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 20118c2ecf20Sopenharmony_ci .accept = vsock_accept, 20128c2ecf20Sopenharmony_ci .getname = vsock_getname, 20138c2ecf20Sopenharmony_ci .poll = vsock_poll, 20148c2ecf20Sopenharmony_ci .ioctl = sock_no_ioctl, 20158c2ecf20Sopenharmony_ci .listen = vsock_listen, 20168c2ecf20Sopenharmony_ci .shutdown = vsock_shutdown, 20178c2ecf20Sopenharmony_ci .setsockopt = vsock_stream_setsockopt, 20188c2ecf20Sopenharmony_ci .getsockopt = vsock_stream_getsockopt, 20198c2ecf20Sopenharmony_ci .sendmsg = vsock_stream_sendmsg, 20208c2ecf20Sopenharmony_ci .recvmsg = vsock_stream_recvmsg, 20218c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 20228c2ecf20Sopenharmony_ci .sendpage = sock_no_sendpage, 20238c2ecf20Sopenharmony_ci}; 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_cistatic int vsock_create(struct net *net, struct socket *sock, 20268c2ecf20Sopenharmony_ci int protocol, int kern) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 20298c2ecf20Sopenharmony_ci struct sock *sk; 20308c2ecf20Sopenharmony_ci int ret; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci if (!sock) 20338c2ecf20Sopenharmony_ci return -EINVAL; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci if (protocol && protocol != PF_VSOCK) 20368c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci switch (sock->type) { 20398c2ecf20Sopenharmony_ci case SOCK_DGRAM: 20408c2ecf20Sopenharmony_ci sock->ops = &vsock_dgram_ops; 20418c2ecf20Sopenharmony_ci break; 20428c2ecf20Sopenharmony_ci case SOCK_STREAM: 20438c2ecf20Sopenharmony_ci sock->ops = &vsock_stream_ops; 20448c2ecf20Sopenharmony_ci break; 20458c2ecf20Sopenharmony_ci default: 20468c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci sk = __vsock_create(net, sock, NULL, GFP_KERNEL, 0, kern); 20528c2ecf20Sopenharmony_ci if (!sk) 20538c2ecf20Sopenharmony_ci return -ENOMEM; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci if (sock->type == SOCK_DGRAM) { 20588c2ecf20Sopenharmony_ci ret = vsock_assign_transport(vsk, NULL); 20598c2ecf20Sopenharmony_ci if (ret < 0) { 20608c2ecf20Sopenharmony_ci sock_put(sk); 20618c2ecf20Sopenharmony_ci return ret; 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci vsock_insert_unbound(vsk); 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci return 0; 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_cistatic const struct net_proto_family vsock_family_ops = { 20718c2ecf20Sopenharmony_ci .family = AF_VSOCK, 20728c2ecf20Sopenharmony_ci .create = vsock_create, 20738c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 20748c2ecf20Sopenharmony_ci}; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic long vsock_dev_do_ioctl(struct file *filp, 20778c2ecf20Sopenharmony_ci unsigned int cmd, void __user *ptr) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci u32 __user *p = ptr; 20808c2ecf20Sopenharmony_ci u32 cid = VMADDR_CID_ANY; 20818c2ecf20Sopenharmony_ci int retval = 0; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci switch (cmd) { 20848c2ecf20Sopenharmony_ci case IOCTL_VM_SOCKETS_GET_LOCAL_CID: 20858c2ecf20Sopenharmony_ci /* To be compatible with the VMCI behavior, we prioritize the 20868c2ecf20Sopenharmony_ci * guest CID instead of well-know host CID (VMADDR_CID_HOST). 20878c2ecf20Sopenharmony_ci */ 20888c2ecf20Sopenharmony_ci if (transport_g2h) 20898c2ecf20Sopenharmony_ci cid = transport_g2h->get_local_cid(); 20908c2ecf20Sopenharmony_ci else if (transport_h2g) 20918c2ecf20Sopenharmony_ci cid = transport_h2g->get_local_cid(); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci if (put_user(cid, p) != 0) 20948c2ecf20Sopenharmony_ci retval = -EFAULT; 20958c2ecf20Sopenharmony_ci break; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci default: 20988c2ecf20Sopenharmony_ci pr_err("Unknown ioctl %d\n", cmd); 20998c2ecf20Sopenharmony_ci retval = -EINVAL; 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci return retval; 21038c2ecf20Sopenharmony_ci} 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_cistatic long vsock_dev_ioctl(struct file *filp, 21068c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci return vsock_dev_do_ioctl(filp, cmd, (void __user *)arg); 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 21128c2ecf20Sopenharmony_cistatic long vsock_dev_compat_ioctl(struct file *filp, 21138c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 21148c2ecf20Sopenharmony_ci{ 21158c2ecf20Sopenharmony_ci return vsock_dev_do_ioctl(filp, cmd, compat_ptr(arg)); 21168c2ecf20Sopenharmony_ci} 21178c2ecf20Sopenharmony_ci#endif 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_cistatic const struct file_operations vsock_device_ops = { 21208c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 21218c2ecf20Sopenharmony_ci .unlocked_ioctl = vsock_dev_ioctl, 21228c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 21238c2ecf20Sopenharmony_ci .compat_ioctl = vsock_dev_compat_ioctl, 21248c2ecf20Sopenharmony_ci#endif 21258c2ecf20Sopenharmony_ci .open = nonseekable_open, 21268c2ecf20Sopenharmony_ci}; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_cistatic struct miscdevice vsock_device = { 21298c2ecf20Sopenharmony_ci .name = "vsock", 21308c2ecf20Sopenharmony_ci .fops = &vsock_device_ops, 21318c2ecf20Sopenharmony_ci}; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_cistatic int __init vsock_init(void) 21348c2ecf20Sopenharmony_ci{ 21358c2ecf20Sopenharmony_ci int err = 0; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci vsock_init_tables(); 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci vsock_proto.owner = THIS_MODULE; 21408c2ecf20Sopenharmony_ci vsock_device.minor = MISC_DYNAMIC_MINOR; 21418c2ecf20Sopenharmony_ci err = misc_register(&vsock_device); 21428c2ecf20Sopenharmony_ci if (err) { 21438c2ecf20Sopenharmony_ci pr_err("Failed to register misc device\n"); 21448c2ecf20Sopenharmony_ci goto err_reset_transport; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci err = proto_register(&vsock_proto, 1); /* we want our slab */ 21488c2ecf20Sopenharmony_ci if (err) { 21498c2ecf20Sopenharmony_ci pr_err("Cannot register vsock protocol\n"); 21508c2ecf20Sopenharmony_ci goto err_deregister_misc; 21518c2ecf20Sopenharmony_ci } 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci err = sock_register(&vsock_family_ops); 21548c2ecf20Sopenharmony_ci if (err) { 21558c2ecf20Sopenharmony_ci pr_err("could not register af_vsock (%d) address family: %d\n", 21568c2ecf20Sopenharmony_ci AF_VSOCK, err); 21578c2ecf20Sopenharmony_ci goto err_unregister_proto; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci return 0; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_cierr_unregister_proto: 21638c2ecf20Sopenharmony_ci proto_unregister(&vsock_proto); 21648c2ecf20Sopenharmony_cierr_deregister_misc: 21658c2ecf20Sopenharmony_ci misc_deregister(&vsock_device); 21668c2ecf20Sopenharmony_cierr_reset_transport: 21678c2ecf20Sopenharmony_ci return err; 21688c2ecf20Sopenharmony_ci} 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_cistatic void __exit vsock_exit(void) 21718c2ecf20Sopenharmony_ci{ 21728c2ecf20Sopenharmony_ci misc_deregister(&vsock_device); 21738c2ecf20Sopenharmony_ci sock_unregister(AF_VSOCK); 21748c2ecf20Sopenharmony_ci proto_unregister(&vsock_proto); 21758c2ecf20Sopenharmony_ci} 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ciconst struct vsock_transport *vsock_core_get_transport(struct vsock_sock *vsk) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci return vsk->transport; 21808c2ecf20Sopenharmony_ci} 21818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_core_get_transport); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ciint vsock_core_register(const struct vsock_transport *t, int features) 21848c2ecf20Sopenharmony_ci{ 21858c2ecf20Sopenharmony_ci const struct vsock_transport *t_h2g, *t_g2h, *t_dgram, *t_local; 21868c2ecf20Sopenharmony_ci int err = mutex_lock_interruptible(&vsock_register_mutex); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci if (err) 21898c2ecf20Sopenharmony_ci return err; 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci t_h2g = transport_h2g; 21928c2ecf20Sopenharmony_ci t_g2h = transport_g2h; 21938c2ecf20Sopenharmony_ci t_dgram = transport_dgram; 21948c2ecf20Sopenharmony_ci t_local = transport_local; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci if (features & VSOCK_TRANSPORT_F_H2G) { 21978c2ecf20Sopenharmony_ci if (t_h2g) { 21988c2ecf20Sopenharmony_ci err = -EBUSY; 21998c2ecf20Sopenharmony_ci goto err_busy; 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci t_h2g = t; 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci if (features & VSOCK_TRANSPORT_F_G2H) { 22058c2ecf20Sopenharmony_ci if (t_g2h) { 22068c2ecf20Sopenharmony_ci err = -EBUSY; 22078c2ecf20Sopenharmony_ci goto err_busy; 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci t_g2h = t; 22108c2ecf20Sopenharmony_ci } 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci if (features & VSOCK_TRANSPORT_F_DGRAM) { 22138c2ecf20Sopenharmony_ci if (t_dgram) { 22148c2ecf20Sopenharmony_ci err = -EBUSY; 22158c2ecf20Sopenharmony_ci goto err_busy; 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci t_dgram = t; 22188c2ecf20Sopenharmony_ci } 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (features & VSOCK_TRANSPORT_F_LOCAL) { 22218c2ecf20Sopenharmony_ci if (t_local) { 22228c2ecf20Sopenharmony_ci err = -EBUSY; 22238c2ecf20Sopenharmony_ci goto err_busy; 22248c2ecf20Sopenharmony_ci } 22258c2ecf20Sopenharmony_ci t_local = t; 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci transport_h2g = t_h2g; 22298c2ecf20Sopenharmony_ci transport_g2h = t_g2h; 22308c2ecf20Sopenharmony_ci transport_dgram = t_dgram; 22318c2ecf20Sopenharmony_ci transport_local = t_local; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_cierr_busy: 22348c2ecf20Sopenharmony_ci mutex_unlock(&vsock_register_mutex); 22358c2ecf20Sopenharmony_ci return err; 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_core_register); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_civoid vsock_core_unregister(const struct vsock_transport *t) 22408c2ecf20Sopenharmony_ci{ 22418c2ecf20Sopenharmony_ci mutex_lock(&vsock_register_mutex); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (transport_h2g == t) 22448c2ecf20Sopenharmony_ci transport_h2g = NULL; 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci if (transport_g2h == t) 22478c2ecf20Sopenharmony_ci transport_g2h = NULL; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci if (transport_dgram == t) 22508c2ecf20Sopenharmony_ci transport_dgram = NULL; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci if (transport_local == t) 22538c2ecf20Sopenharmony_ci transport_local = NULL; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci mutex_unlock(&vsock_register_mutex); 22568c2ecf20Sopenharmony_ci} 22578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vsock_core_unregister); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_cimodule_init(vsock_init); 22608c2ecf20Sopenharmony_cimodule_exit(vsock_exit); 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ciMODULE_AUTHOR("VMware, Inc."); 22638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VMware Virtual Socket Family"); 22648c2ecf20Sopenharmony_ciMODULE_VERSION("1.0.2.0-k"); 22658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2266