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#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <linux/bitops.h> 108c2ecf20Sopenharmony_ci#include <linux/cred.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/kmod.h> 158c2ecf20Sopenharmony_ci#include <linux/list.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include <linux/net.h> 198c2ecf20Sopenharmony_ci#include <linux/poll.h> 208c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 218c2ecf20Sopenharmony_ci#include <linux/smp.h> 228c2ecf20Sopenharmony_ci#include <linux/socket.h> 238c2ecf20Sopenharmony_ci#include <linux/stddef.h> 248c2ecf20Sopenharmony_ci#include <linux/unistd.h> 258c2ecf20Sopenharmony_ci#include <linux/wait.h> 268c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 278c2ecf20Sopenharmony_ci#include <net/sock.h> 288c2ecf20Sopenharmony_ci#include <net/af_vsock.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "vmci_transport_notify.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int vmci_transport_recv_dgram_cb(void *data, struct vmci_datagram *dg); 338c2ecf20Sopenharmony_cistatic int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg); 348c2ecf20Sopenharmony_cistatic void vmci_transport_peer_detach_cb(u32 sub_id, 358c2ecf20Sopenharmony_ci const struct vmci_event_data *ed, 368c2ecf20Sopenharmony_ci void *client_data); 378c2ecf20Sopenharmony_cistatic void vmci_transport_recv_pkt_work(struct work_struct *work); 388c2ecf20Sopenharmony_cistatic void vmci_transport_cleanup(struct work_struct *work); 398c2ecf20Sopenharmony_cistatic int vmci_transport_recv_listen(struct sock *sk, 408c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt); 418c2ecf20Sopenharmony_cistatic int vmci_transport_recv_connecting_server( 428c2ecf20Sopenharmony_ci struct sock *sk, 438c2ecf20Sopenharmony_ci struct sock *pending, 448c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt); 458c2ecf20Sopenharmony_cistatic int vmci_transport_recv_connecting_client( 468c2ecf20Sopenharmony_ci struct sock *sk, 478c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt); 488c2ecf20Sopenharmony_cistatic int vmci_transport_recv_connecting_client_negotiate( 498c2ecf20Sopenharmony_ci struct sock *sk, 508c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt); 518c2ecf20Sopenharmony_cistatic int vmci_transport_recv_connecting_client_invalid( 528c2ecf20Sopenharmony_ci struct sock *sk, 538c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt); 548c2ecf20Sopenharmony_cistatic int vmci_transport_recv_connected(struct sock *sk, 558c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt); 568c2ecf20Sopenharmony_cistatic bool vmci_transport_old_proto_override(bool *old_pkt_proto); 578c2ecf20Sopenharmony_cistatic u16 vmci_transport_new_proto_supported_versions(void); 588c2ecf20Sopenharmony_cistatic bool vmci_transport_proto_to_notify_struct(struct sock *sk, u16 *proto, 598c2ecf20Sopenharmony_ci bool old_pkt_proto); 608c2ecf20Sopenharmony_cistatic bool vmci_check_transport(struct vsock_sock *vsk); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct vmci_transport_recv_pkt_info { 638c2ecf20Sopenharmony_ci struct work_struct work; 648c2ecf20Sopenharmony_ci struct sock *sk; 658c2ecf20Sopenharmony_ci struct vmci_transport_packet pkt; 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic LIST_HEAD(vmci_transport_cleanup_list); 698c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(vmci_transport_cleanup_lock); 708c2ecf20Sopenharmony_cistatic DECLARE_WORK(vmci_transport_cleanup_work, vmci_transport_cleanup); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic struct vmci_handle vmci_transport_stream_handle = { VMCI_INVALID_ID, 738c2ecf20Sopenharmony_ci VMCI_INVALID_ID }; 748c2ecf20Sopenharmony_cistatic u32 vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int PROTOCOL_OVERRIDE = -1; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic struct vsock_transport vmci_transport; /* forward declaration */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* Helper function to convert from a VMCI error code to a VSock error code. */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic s32 vmci_transport_error_to_vsock_error(s32 vmci_error) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci switch (vmci_error) { 858c2ecf20Sopenharmony_ci case VMCI_ERROR_NO_MEM: 868c2ecf20Sopenharmony_ci return -ENOMEM; 878c2ecf20Sopenharmony_ci case VMCI_ERROR_DUPLICATE_ENTRY: 888c2ecf20Sopenharmony_ci case VMCI_ERROR_ALREADY_EXISTS: 898c2ecf20Sopenharmony_ci return -EADDRINUSE; 908c2ecf20Sopenharmony_ci case VMCI_ERROR_NO_ACCESS: 918c2ecf20Sopenharmony_ci return -EPERM; 928c2ecf20Sopenharmony_ci case VMCI_ERROR_NO_RESOURCES: 938c2ecf20Sopenharmony_ci return -ENOBUFS; 948c2ecf20Sopenharmony_ci case VMCI_ERROR_INVALID_RESOURCE: 958c2ecf20Sopenharmony_ci return -EHOSTUNREACH; 968c2ecf20Sopenharmony_ci case VMCI_ERROR_INVALID_ARGS: 978c2ecf20Sopenharmony_ci default: 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci return -EINVAL; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic u32 vmci_transport_peer_rid(u32 peer_cid) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci if (VMADDR_CID_HYPERVISOR == peer_cid) 1068c2ecf20Sopenharmony_ci return VMCI_TRANSPORT_HYPERVISOR_PACKET_RID; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return VMCI_TRANSPORT_PACKET_RID; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline void 1128c2ecf20Sopenharmony_civmci_transport_packet_init(struct vmci_transport_packet *pkt, 1138c2ecf20Sopenharmony_ci struct sockaddr_vm *src, 1148c2ecf20Sopenharmony_ci struct sockaddr_vm *dst, 1158c2ecf20Sopenharmony_ci u8 type, 1168c2ecf20Sopenharmony_ci u64 size, 1178c2ecf20Sopenharmony_ci u64 mode, 1188c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait, 1198c2ecf20Sopenharmony_ci u16 proto, 1208c2ecf20Sopenharmony_ci struct vmci_handle handle) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci /* We register the stream control handler as an any cid handle so we 1238c2ecf20Sopenharmony_ci * must always send from a source address of VMADDR_CID_ANY 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci pkt->dg.src = vmci_make_handle(VMADDR_CID_ANY, 1268c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_RID); 1278c2ecf20Sopenharmony_ci pkt->dg.dst = vmci_make_handle(dst->svm_cid, 1288c2ecf20Sopenharmony_ci vmci_transport_peer_rid(dst->svm_cid)); 1298c2ecf20Sopenharmony_ci pkt->dg.payload_size = sizeof(*pkt) - sizeof(pkt->dg); 1308c2ecf20Sopenharmony_ci pkt->version = VMCI_TRANSPORT_PACKET_VERSION; 1318c2ecf20Sopenharmony_ci pkt->type = type; 1328c2ecf20Sopenharmony_ci pkt->src_port = src->svm_port; 1338c2ecf20Sopenharmony_ci pkt->dst_port = dst->svm_port; 1348c2ecf20Sopenharmony_ci memset(&pkt->proto, 0, sizeof(pkt->proto)); 1358c2ecf20Sopenharmony_ci memset(&pkt->_reserved2, 0, sizeof(pkt->_reserved2)); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci switch (pkt->type) { 1388c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_INVALID: 1398c2ecf20Sopenharmony_ci pkt->u.size = 0; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_REQUEST: 1438c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE: 1448c2ecf20Sopenharmony_ci pkt->u.size = size; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_OFFER: 1488c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_ATTACH: 1498c2ecf20Sopenharmony_ci pkt->u.handle = handle; 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_WROTE: 1538c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_READ: 1548c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_RST: 1558c2ecf20Sopenharmony_ci pkt->u.size = 0; 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_SHUTDOWN: 1598c2ecf20Sopenharmony_ci pkt->u.mode = mode; 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_WAITING_READ: 1638c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_WAITING_WRITE: 1648c2ecf20Sopenharmony_ci memcpy(&pkt->u.wait, wait, sizeof(pkt->u.wait)); 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_REQUEST2: 1688c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE2: 1698c2ecf20Sopenharmony_ci pkt->u.size = size; 1708c2ecf20Sopenharmony_ci pkt->proto = proto; 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic inline void 1768c2ecf20Sopenharmony_civmci_transport_packet_get_addresses(struct vmci_transport_packet *pkt, 1778c2ecf20Sopenharmony_ci struct sockaddr_vm *local, 1788c2ecf20Sopenharmony_ci struct sockaddr_vm *remote) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci vsock_addr_init(local, pkt->dg.dst.context, pkt->dst_port); 1818c2ecf20Sopenharmony_ci vsock_addr_init(remote, pkt->dg.src.context, pkt->src_port); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int 1858c2ecf20Sopenharmony_ci__vmci_transport_send_control_pkt(struct vmci_transport_packet *pkt, 1868c2ecf20Sopenharmony_ci struct sockaddr_vm *src, 1878c2ecf20Sopenharmony_ci struct sockaddr_vm *dst, 1888c2ecf20Sopenharmony_ci enum vmci_transport_packet_type type, 1898c2ecf20Sopenharmony_ci u64 size, 1908c2ecf20Sopenharmony_ci u64 mode, 1918c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait, 1928c2ecf20Sopenharmony_ci u16 proto, 1938c2ecf20Sopenharmony_ci struct vmci_handle handle, 1948c2ecf20Sopenharmony_ci bool convert_error) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci int err; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci vmci_transport_packet_init(pkt, src, dst, type, size, mode, wait, 1998c2ecf20Sopenharmony_ci proto, handle); 2008c2ecf20Sopenharmony_ci err = vmci_datagram_send(&pkt->dg); 2018c2ecf20Sopenharmony_ci if (convert_error && (err < 0)) 2028c2ecf20Sopenharmony_ci return vmci_transport_error_to_vsock_error(err); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return err; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int 2088c2ecf20Sopenharmony_civmci_transport_reply_control_pkt_fast(struct vmci_transport_packet *pkt, 2098c2ecf20Sopenharmony_ci enum vmci_transport_packet_type type, 2108c2ecf20Sopenharmony_ci u64 size, 2118c2ecf20Sopenharmony_ci u64 mode, 2128c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait, 2138c2ecf20Sopenharmony_ci struct vmci_handle handle) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct vmci_transport_packet reply; 2168c2ecf20Sopenharmony_ci struct sockaddr_vm src, dst; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_RST) { 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci } else { 2218c2ecf20Sopenharmony_ci vmci_transport_packet_get_addresses(pkt, &src, &dst); 2228c2ecf20Sopenharmony_ci return __vmci_transport_send_control_pkt(&reply, &src, &dst, 2238c2ecf20Sopenharmony_ci type, 2248c2ecf20Sopenharmony_ci size, mode, wait, 2258c2ecf20Sopenharmony_ci VSOCK_PROTO_INVALID, 2268c2ecf20Sopenharmony_ci handle, true); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int 2318c2ecf20Sopenharmony_civmci_transport_send_control_pkt_bh(struct sockaddr_vm *src, 2328c2ecf20Sopenharmony_ci struct sockaddr_vm *dst, 2338c2ecf20Sopenharmony_ci enum vmci_transport_packet_type type, 2348c2ecf20Sopenharmony_ci u64 size, 2358c2ecf20Sopenharmony_ci u64 mode, 2368c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait, 2378c2ecf20Sopenharmony_ci struct vmci_handle handle) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci /* Note that it is safe to use a single packet across all CPUs since 2408c2ecf20Sopenharmony_ci * two tasklets of the same type are guaranteed to not ever run 2418c2ecf20Sopenharmony_ci * simultaneously. If that ever changes, or VMCI stops using tasklets, 2428c2ecf20Sopenharmony_ci * we can use per-cpu packets. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci static struct vmci_transport_packet pkt; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return __vmci_transport_send_control_pkt(&pkt, src, dst, type, 2478c2ecf20Sopenharmony_ci size, mode, wait, 2488c2ecf20Sopenharmony_ci VSOCK_PROTO_INVALID, handle, 2498c2ecf20Sopenharmony_ci false); 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int 2538c2ecf20Sopenharmony_civmci_transport_alloc_send_control_pkt(struct sockaddr_vm *src, 2548c2ecf20Sopenharmony_ci struct sockaddr_vm *dst, 2558c2ecf20Sopenharmony_ci enum vmci_transport_packet_type type, 2568c2ecf20Sopenharmony_ci u64 size, 2578c2ecf20Sopenharmony_ci u64 mode, 2588c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait, 2598c2ecf20Sopenharmony_ci u16 proto, 2608c2ecf20Sopenharmony_ci struct vmci_handle handle) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt; 2638c2ecf20Sopenharmony_ci int err; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci pkt = kmalloc(sizeof(*pkt), GFP_KERNEL); 2668c2ecf20Sopenharmony_ci if (!pkt) 2678c2ecf20Sopenharmony_ci return -ENOMEM; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci err = __vmci_transport_send_control_pkt(pkt, src, dst, type, size, 2708c2ecf20Sopenharmony_ci mode, wait, proto, handle, 2718c2ecf20Sopenharmony_ci true); 2728c2ecf20Sopenharmony_ci kfree(pkt); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return err; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int 2788c2ecf20Sopenharmony_civmci_transport_send_control_pkt(struct sock *sk, 2798c2ecf20Sopenharmony_ci enum vmci_transport_packet_type type, 2808c2ecf20Sopenharmony_ci u64 size, 2818c2ecf20Sopenharmony_ci u64 mode, 2828c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait, 2838c2ecf20Sopenharmony_ci u16 proto, 2848c2ecf20Sopenharmony_ci struct vmci_handle handle) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (!vsock_addr_bound(&vsk->local_addr)) 2918c2ecf20Sopenharmony_ci return -EINVAL; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (!vsock_addr_bound(&vsk->remote_addr)) 2948c2ecf20Sopenharmony_ci return -EINVAL; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return vmci_transport_alloc_send_control_pkt(&vsk->local_addr, 2978c2ecf20Sopenharmony_ci &vsk->remote_addr, 2988c2ecf20Sopenharmony_ci type, size, mode, 2998c2ecf20Sopenharmony_ci wait, proto, handle); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int vmci_transport_send_reset_bh(struct sockaddr_vm *dst, 3038c2ecf20Sopenharmony_ci struct sockaddr_vm *src, 3048c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_RST) 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt_bh( 3098c2ecf20Sopenharmony_ci dst, src, 3108c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_RST, 0, 3118c2ecf20Sopenharmony_ci 0, NULL, VMCI_INVALID_HANDLE); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int vmci_transport_send_reset(struct sock *sk, 3158c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct sockaddr_vm *dst_ptr; 3188c2ecf20Sopenharmony_ci struct sockaddr_vm dst; 3198c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_RST) 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!vsock_addr_bound(&vsk->local_addr)) 3278c2ecf20Sopenharmony_ci return -EINVAL; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (vsock_addr_bound(&vsk->remote_addr)) { 3308c2ecf20Sopenharmony_ci dst_ptr = &vsk->remote_addr; 3318c2ecf20Sopenharmony_ci } else { 3328c2ecf20Sopenharmony_ci vsock_addr_init(&dst, pkt->dg.src.context, 3338c2ecf20Sopenharmony_ci pkt->src_port); 3348c2ecf20Sopenharmony_ci dst_ptr = &dst; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci return vmci_transport_alloc_send_control_pkt(&vsk->local_addr, dst_ptr, 3378c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_RST, 3388c2ecf20Sopenharmony_ci 0, 0, NULL, VSOCK_PROTO_INVALID, 3398c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int vmci_transport_send_negotiate(struct sock *sk, size_t size) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 3458c2ecf20Sopenharmony_ci sk, 3468c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE, 3478c2ecf20Sopenharmony_ci size, 0, NULL, 3488c2ecf20Sopenharmony_ci VSOCK_PROTO_INVALID, 3498c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int vmci_transport_send_negotiate2(struct sock *sk, size_t size, 3538c2ecf20Sopenharmony_ci u16 version) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 3568c2ecf20Sopenharmony_ci sk, 3578c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE2, 3588c2ecf20Sopenharmony_ci size, 0, NULL, version, 3598c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int vmci_transport_send_qp_offer(struct sock *sk, 3638c2ecf20Sopenharmony_ci struct vmci_handle handle) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 3668c2ecf20Sopenharmony_ci sk, VMCI_TRANSPORT_PACKET_TYPE_OFFER, 0, 3678c2ecf20Sopenharmony_ci 0, NULL, 3688c2ecf20Sopenharmony_ci VSOCK_PROTO_INVALID, handle); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int vmci_transport_send_attach(struct sock *sk, 3728c2ecf20Sopenharmony_ci struct vmci_handle handle) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 3758c2ecf20Sopenharmony_ci sk, VMCI_TRANSPORT_PACKET_TYPE_ATTACH, 3768c2ecf20Sopenharmony_ci 0, 0, NULL, VSOCK_PROTO_INVALID, 3778c2ecf20Sopenharmony_ci handle); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int vmci_transport_reply_reset(struct vmci_transport_packet *pkt) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci return vmci_transport_reply_control_pkt_fast( 3838c2ecf20Sopenharmony_ci pkt, 3848c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_RST, 3858c2ecf20Sopenharmony_ci 0, 0, NULL, 3868c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int vmci_transport_send_invalid_bh(struct sockaddr_vm *dst, 3908c2ecf20Sopenharmony_ci struct sockaddr_vm *src) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt_bh( 3938c2ecf20Sopenharmony_ci dst, src, 3948c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_INVALID, 3958c2ecf20Sopenharmony_ci 0, 0, NULL, VMCI_INVALID_HANDLE); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciint vmci_transport_send_wrote_bh(struct sockaddr_vm *dst, 3998c2ecf20Sopenharmony_ci struct sockaddr_vm *src) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt_bh( 4028c2ecf20Sopenharmony_ci dst, src, 4038c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_WROTE, 0, 4048c2ecf20Sopenharmony_ci 0, NULL, VMCI_INVALID_HANDLE); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ciint vmci_transport_send_read_bh(struct sockaddr_vm *dst, 4088c2ecf20Sopenharmony_ci struct sockaddr_vm *src) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt_bh( 4118c2ecf20Sopenharmony_ci dst, src, 4128c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_READ, 0, 4138c2ecf20Sopenharmony_ci 0, NULL, VMCI_INVALID_HANDLE); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ciint vmci_transport_send_wrote(struct sock *sk) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 4198c2ecf20Sopenharmony_ci sk, VMCI_TRANSPORT_PACKET_TYPE_WROTE, 0, 4208c2ecf20Sopenharmony_ci 0, NULL, VSOCK_PROTO_INVALID, 4218c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ciint vmci_transport_send_read(struct sock *sk) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 4278c2ecf20Sopenharmony_ci sk, VMCI_TRANSPORT_PACKET_TYPE_READ, 0, 4288c2ecf20Sopenharmony_ci 0, NULL, VSOCK_PROTO_INVALID, 4298c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciint vmci_transport_send_waiting_write(struct sock *sk, 4338c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 4368c2ecf20Sopenharmony_ci sk, VMCI_TRANSPORT_PACKET_TYPE_WAITING_WRITE, 4378c2ecf20Sopenharmony_ci 0, 0, wait, VSOCK_PROTO_INVALID, 4388c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ciint vmci_transport_send_waiting_read(struct sock *sk, 4428c2ecf20Sopenharmony_ci struct vmci_transport_waiting_info *wait) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 4458c2ecf20Sopenharmony_ci sk, VMCI_TRANSPORT_PACKET_TYPE_WAITING_READ, 4468c2ecf20Sopenharmony_ci 0, 0, wait, VSOCK_PROTO_INVALID, 4478c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int vmci_transport_shutdown(struct vsock_sock *vsk, int mode) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 4538c2ecf20Sopenharmony_ci &vsk->sk, 4548c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_SHUTDOWN, 4558c2ecf20Sopenharmony_ci 0, mode, NULL, 4568c2ecf20Sopenharmony_ci VSOCK_PROTO_INVALID, 4578c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int vmci_transport_send_conn_request(struct sock *sk, size_t size) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt(sk, 4638c2ecf20Sopenharmony_ci VMCI_TRANSPORT_PACKET_TYPE_REQUEST, 4648c2ecf20Sopenharmony_ci size, 0, NULL, 4658c2ecf20Sopenharmony_ci VSOCK_PROTO_INVALID, 4668c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int vmci_transport_send_conn_request2(struct sock *sk, size_t size, 4708c2ecf20Sopenharmony_ci u16 version) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci return vmci_transport_send_control_pkt( 4738c2ecf20Sopenharmony_ci sk, VMCI_TRANSPORT_PACKET_TYPE_REQUEST2, 4748c2ecf20Sopenharmony_ci size, 0, NULL, version, 4758c2ecf20Sopenharmony_ci VMCI_INVALID_HANDLE); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic struct sock *vmci_transport_get_pending( 4798c2ecf20Sopenharmony_ci struct sock *listener, 4808c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct vsock_sock *vlistener; 4838c2ecf20Sopenharmony_ci struct vsock_sock *vpending; 4848c2ecf20Sopenharmony_ci struct sock *pending; 4858c2ecf20Sopenharmony_ci struct sockaddr_vm src; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci vlistener = vsock_sk(listener); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci list_for_each_entry(vpending, &vlistener->pending_links, 4928c2ecf20Sopenharmony_ci pending_links) { 4938c2ecf20Sopenharmony_ci if (vsock_addr_equals_addr(&src, &vpending->remote_addr) && 4948c2ecf20Sopenharmony_ci pkt->dst_port == vpending->local_addr.svm_port) { 4958c2ecf20Sopenharmony_ci pending = sk_vsock(vpending); 4968c2ecf20Sopenharmony_ci sock_hold(pending); 4978c2ecf20Sopenharmony_ci goto found; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci pending = NULL; 5028c2ecf20Sopenharmony_cifound: 5038c2ecf20Sopenharmony_ci return pending; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic void vmci_transport_release_pending(struct sock *pending) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci sock_put(pending); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/* We allow two kinds of sockets to communicate with a restricted VM: 1) 5138c2ecf20Sopenharmony_ci * trusted sockets 2) sockets from applications running as the same user as the 5148c2ecf20Sopenharmony_ci * VM (this is only true for the host side and only when using hosted products) 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic bool vmci_transport_is_trusted(struct vsock_sock *vsock, u32 peer_cid) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci return vsock->trusted || 5208c2ecf20Sopenharmony_ci vmci_is_context_owner(peer_cid, vsock->owner->uid); 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/* We allow sending datagrams to and receiving datagrams from a restricted VM 5248c2ecf20Sopenharmony_ci * only if it is trusted as described in vmci_transport_is_trusted. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic bool vmci_transport_allow_dgram(struct vsock_sock *vsock, u32 peer_cid) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci if (VMADDR_CID_HYPERVISOR == peer_cid) 5308c2ecf20Sopenharmony_ci return true; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (vsock->cached_peer != peer_cid) { 5338c2ecf20Sopenharmony_ci vsock->cached_peer = peer_cid; 5348c2ecf20Sopenharmony_ci if (!vmci_transport_is_trusted(vsock, peer_cid) && 5358c2ecf20Sopenharmony_ci (vmci_context_get_priv_flags(peer_cid) & 5368c2ecf20Sopenharmony_ci VMCI_PRIVILEGE_FLAG_RESTRICTED)) { 5378c2ecf20Sopenharmony_ci vsock->cached_peer_allow_dgram = false; 5388c2ecf20Sopenharmony_ci } else { 5398c2ecf20Sopenharmony_ci vsock->cached_peer_allow_dgram = true; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return vsock->cached_peer_allow_dgram; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int 5478c2ecf20Sopenharmony_civmci_transport_queue_pair_alloc(struct vmci_qp **qpair, 5488c2ecf20Sopenharmony_ci struct vmci_handle *handle, 5498c2ecf20Sopenharmony_ci u64 produce_size, 5508c2ecf20Sopenharmony_ci u64 consume_size, 5518c2ecf20Sopenharmony_ci u32 peer, u32 flags, bool trusted) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci int err = 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (trusted) { 5568c2ecf20Sopenharmony_ci /* Try to allocate our queue pair as trusted. This will only 5578c2ecf20Sopenharmony_ci * work if vsock is running in the host. 5588c2ecf20Sopenharmony_ci */ 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci err = vmci_qpair_alloc(qpair, handle, produce_size, 5618c2ecf20Sopenharmony_ci consume_size, 5628c2ecf20Sopenharmony_ci peer, flags, 5638c2ecf20Sopenharmony_ci VMCI_PRIVILEGE_FLAG_TRUSTED); 5648c2ecf20Sopenharmony_ci if (err != VMCI_ERROR_NO_ACCESS) 5658c2ecf20Sopenharmony_ci goto out; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci err = vmci_qpair_alloc(qpair, handle, produce_size, consume_size, 5708c2ecf20Sopenharmony_ci peer, flags, VMCI_NO_PRIVILEGE_FLAGS); 5718c2ecf20Sopenharmony_ciout: 5728c2ecf20Sopenharmony_ci if (err < 0) { 5738c2ecf20Sopenharmony_ci pr_err_once("Could not attach to queue pair with %d\n", err); 5748c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return err; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int 5818c2ecf20Sopenharmony_civmci_transport_datagram_create_hnd(u32 resource_id, 5828c2ecf20Sopenharmony_ci u32 flags, 5838c2ecf20Sopenharmony_ci vmci_datagram_recv_cb recv_cb, 5848c2ecf20Sopenharmony_ci void *client_data, 5858c2ecf20Sopenharmony_ci struct vmci_handle *out_handle) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci int err = 0; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* Try to allocate our datagram handler as trusted. This will only work 5908c2ecf20Sopenharmony_ci * if vsock is running in the host. 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci err = vmci_datagram_create_handle_priv(resource_id, flags, 5948c2ecf20Sopenharmony_ci VMCI_PRIVILEGE_FLAG_TRUSTED, 5958c2ecf20Sopenharmony_ci recv_cb, 5968c2ecf20Sopenharmony_ci client_data, out_handle); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (err == VMCI_ERROR_NO_ACCESS) 5998c2ecf20Sopenharmony_ci err = vmci_datagram_create_handle(resource_id, flags, 6008c2ecf20Sopenharmony_ci recv_cb, client_data, 6018c2ecf20Sopenharmony_ci out_handle); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return err; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci/* This is invoked as part of a tasklet that's scheduled when the VMCI 6078c2ecf20Sopenharmony_ci * interrupt fires. This is run in bottom-half context and if it ever needs to 6088c2ecf20Sopenharmony_ci * sleep it should defer that work to a work queue. 6098c2ecf20Sopenharmony_ci */ 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int vmci_transport_recv_dgram_cb(void *data, struct vmci_datagram *dg) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct sock *sk; 6148c2ecf20Sopenharmony_ci size_t size; 6158c2ecf20Sopenharmony_ci struct sk_buff *skb; 6168c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci sk = (struct sock *)data; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* This handler is privileged when this module is running on the host. 6218c2ecf20Sopenharmony_ci * We will get datagrams from all endpoints (even VMs that are in a 6228c2ecf20Sopenharmony_ci * restricted context). If we get one from a restricted context then 6238c2ecf20Sopenharmony_ci * the destination socket must be trusted. 6248c2ecf20Sopenharmony_ci * 6258c2ecf20Sopenharmony_ci * NOTE: We access the socket struct without holding the lock here. 6268c2ecf20Sopenharmony_ci * This is ok because the field we are interested is never modified 6278c2ecf20Sopenharmony_ci * outside of the create and destruct socket functions. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 6308c2ecf20Sopenharmony_ci if (!vmci_transport_allow_dgram(vsk, dg->src.context)) 6318c2ecf20Sopenharmony_ci return VMCI_ERROR_NO_ACCESS; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci size = VMCI_DG_SIZE(dg); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* Attach the packet to the socket's receive queue as an sk_buff. */ 6368c2ecf20Sopenharmony_ci skb = alloc_skb(size, GFP_ATOMIC); 6378c2ecf20Sopenharmony_ci if (!skb) 6388c2ecf20Sopenharmony_ci return VMCI_ERROR_NO_MEM; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* sk_receive_skb() will do a sock_put(), so hold here. */ 6418c2ecf20Sopenharmony_ci sock_hold(sk); 6428c2ecf20Sopenharmony_ci skb_put(skb, size); 6438c2ecf20Sopenharmony_ci memcpy(skb->data, dg, size); 6448c2ecf20Sopenharmony_ci sk_receive_skb(sk, skb, 0); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return VMCI_SUCCESS; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic bool vmci_transport_stream_allow(u32 cid, u32 port) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci static const u32 non_socket_contexts[] = { 6528c2ecf20Sopenharmony_ci VMADDR_CID_LOCAL, 6538c2ecf20Sopenharmony_ci }; 6548c2ecf20Sopenharmony_ci int i; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(cid) != sizeof(*non_socket_contexts)); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(non_socket_contexts); i++) { 6598c2ecf20Sopenharmony_ci if (cid == non_socket_contexts[i]) 6608c2ecf20Sopenharmony_ci return false; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci return true; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci/* This is invoked as part of a tasklet that's scheduled when the VMCI 6678c2ecf20Sopenharmony_ci * interrupt fires. This is run in bottom-half context but it defers most of 6688c2ecf20Sopenharmony_ci * its work to the packet handling work queue. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci struct sock *sk; 6748c2ecf20Sopenharmony_ci struct sockaddr_vm dst; 6758c2ecf20Sopenharmony_ci struct sockaddr_vm src; 6768c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt; 6778c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 6788c2ecf20Sopenharmony_ci bool bh_process_pkt; 6798c2ecf20Sopenharmony_ci int err; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci sk = NULL; 6828c2ecf20Sopenharmony_ci err = VMCI_SUCCESS; 6838c2ecf20Sopenharmony_ci bh_process_pkt = false; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* Ignore incoming packets from contexts without sockets, or resources 6868c2ecf20Sopenharmony_ci * that aren't vsock implementations. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (!vmci_transport_stream_allow(dg->src.context, -1) 6908c2ecf20Sopenharmony_ci || vmci_transport_peer_rid(dg->src.context) != dg->src.resource) 6918c2ecf20Sopenharmony_ci return VMCI_ERROR_NO_ACCESS; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (VMCI_DG_SIZE(dg) < sizeof(*pkt)) 6948c2ecf20Sopenharmony_ci /* Drop datagrams that do not contain full VSock packets. */ 6958c2ecf20Sopenharmony_ci return VMCI_ERROR_INVALID_ARGS; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci pkt = (struct vmci_transport_packet *)dg; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* Find the socket that should handle this packet. First we look for a 7008c2ecf20Sopenharmony_ci * connected socket and if there is none we look for a socket bound to 7018c2ecf20Sopenharmony_ci * the destintation address. 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port); 7048c2ecf20Sopenharmony_ci vsock_addr_init(&dst, pkt->dg.dst.context, pkt->dst_port); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci sk = vsock_find_connected_socket(&src, &dst); 7078c2ecf20Sopenharmony_ci if (!sk) { 7088c2ecf20Sopenharmony_ci sk = vsock_find_bound_socket(&dst); 7098c2ecf20Sopenharmony_ci if (!sk) { 7108c2ecf20Sopenharmony_ci /* We could not find a socket for this specified 7118c2ecf20Sopenharmony_ci * address. If this packet is a RST, we just drop it. 7128c2ecf20Sopenharmony_ci * If it is another packet, we send a RST. Note that 7138c2ecf20Sopenharmony_ci * we do not send a RST reply to RSTs so that we do not 7148c2ecf20Sopenharmony_ci * continually send RSTs between two endpoints. 7158c2ecf20Sopenharmony_ci * 7168c2ecf20Sopenharmony_ci * Note that since this is a reply, dst is src and src 7178c2ecf20Sopenharmony_ci * is dst. 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_ci if (vmci_transport_send_reset_bh(&dst, &src, pkt) < 0) 7208c2ecf20Sopenharmony_ci pr_err("unable to send reset\n"); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci err = VMCI_ERROR_NOT_FOUND; 7238c2ecf20Sopenharmony_ci goto out; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* If the received packet type is beyond all types known to this 7288c2ecf20Sopenharmony_ci * implementation, reply with an invalid message. Hopefully this will 7298c2ecf20Sopenharmony_ci * help when implementing backwards compatibility in the future. 7308c2ecf20Sopenharmony_ci */ 7318c2ecf20Sopenharmony_ci if (pkt->type >= VMCI_TRANSPORT_PACKET_TYPE_MAX) { 7328c2ecf20Sopenharmony_ci vmci_transport_send_invalid_bh(&dst, &src); 7338c2ecf20Sopenharmony_ci err = VMCI_ERROR_INVALID_ARGS; 7348c2ecf20Sopenharmony_ci goto out; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* This handler is privileged when this module is running on the host. 7388c2ecf20Sopenharmony_ci * We will get datagram connect requests from all endpoints (even VMs 7398c2ecf20Sopenharmony_ci * that are in a restricted context). If we get one from a restricted 7408c2ecf20Sopenharmony_ci * context then the destination socket must be trusted. 7418c2ecf20Sopenharmony_ci * 7428c2ecf20Sopenharmony_ci * NOTE: We access the socket struct without holding the lock here. 7438c2ecf20Sopenharmony_ci * This is ok because the field we are interested is never modified 7448c2ecf20Sopenharmony_ci * outside of the create and destruct socket functions. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 7478c2ecf20Sopenharmony_ci if (!vmci_transport_allow_dgram(vsk, pkt->dg.src.context)) { 7488c2ecf20Sopenharmony_ci err = VMCI_ERROR_NO_ACCESS; 7498c2ecf20Sopenharmony_ci goto out; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* We do most everything in a work queue, but let's fast path the 7538c2ecf20Sopenharmony_ci * notification of reads and writes to help data transfer performance. 7548c2ecf20Sopenharmony_ci * We can only do this if there is no process context code executing 7558c2ecf20Sopenharmony_ci * for this socket since that may change the state. 7568c2ecf20Sopenharmony_ci */ 7578c2ecf20Sopenharmony_ci bh_lock_sock(sk); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (!sock_owned_by_user(sk)) { 7608c2ecf20Sopenharmony_ci /* The local context ID may be out of date, update it. */ 7618c2ecf20Sopenharmony_ci vsk->local_addr.svm_cid = dst.svm_cid; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_ESTABLISHED) 7648c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops->handle_notify_pkt( 7658c2ecf20Sopenharmony_ci sk, pkt, true, &dst, &src, 7668c2ecf20Sopenharmony_ci &bh_process_pkt); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci bh_unlock_sock(sk); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (!bh_process_pkt) { 7728c2ecf20Sopenharmony_ci struct vmci_transport_recv_pkt_info *recv_pkt_info; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci recv_pkt_info = kmalloc(sizeof(*recv_pkt_info), GFP_ATOMIC); 7758c2ecf20Sopenharmony_ci if (!recv_pkt_info) { 7768c2ecf20Sopenharmony_ci if (vmci_transport_send_reset_bh(&dst, &src, pkt) < 0) 7778c2ecf20Sopenharmony_ci pr_err("unable to send reset\n"); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci err = VMCI_ERROR_NO_MEM; 7808c2ecf20Sopenharmony_ci goto out; 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci recv_pkt_info->sk = sk; 7848c2ecf20Sopenharmony_ci memcpy(&recv_pkt_info->pkt, pkt, sizeof(recv_pkt_info->pkt)); 7858c2ecf20Sopenharmony_ci INIT_WORK(&recv_pkt_info->work, vmci_transport_recv_pkt_work); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci schedule_work(&recv_pkt_info->work); 7888c2ecf20Sopenharmony_ci /* Clear sk so that the reference count incremented by one of 7898c2ecf20Sopenharmony_ci * the Find functions above is not decremented below. We need 7908c2ecf20Sopenharmony_ci * that reference count for the packet handler we've scheduled 7918c2ecf20Sopenharmony_ci * to run. 7928c2ecf20Sopenharmony_ci */ 7938c2ecf20Sopenharmony_ci sk = NULL; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ciout: 7978c2ecf20Sopenharmony_ci if (sk) 7988c2ecf20Sopenharmony_ci sock_put(sk); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return err; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic void vmci_transport_handle_detach(struct sock *sk) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 8088c2ecf20Sopenharmony_ci if (!vmci_handle_is_invalid(vmci_trans(vsk)->qp_handle)) { 8098c2ecf20Sopenharmony_ci sock_set_flag(sk, SOCK_DONE); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* On a detach the peer will not be sending or receiving 8128c2ecf20Sopenharmony_ci * anymore. 8138c2ecf20Sopenharmony_ci */ 8148c2ecf20Sopenharmony_ci vsk->peer_shutdown = SHUTDOWN_MASK; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* We should not be sending anymore since the peer won't be 8178c2ecf20Sopenharmony_ci * there to receive, but we can still receive if there is data 8188c2ecf20Sopenharmony_ci * left in our consume queue. If the local endpoint is a host, 8198c2ecf20Sopenharmony_ci * we can't call vsock_stream_has_data, since that may block, 8208c2ecf20Sopenharmony_ci * but a host endpoint can't read data once the VM has 8218c2ecf20Sopenharmony_ci * detached, so there is no available data in that case. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ci if (vsk->local_addr.svm_cid == VMADDR_CID_HOST || 8248c2ecf20Sopenharmony_ci vsock_stream_has_data(vsk) <= 0) { 8258c2ecf20Sopenharmony_ci if (sk->sk_state == TCP_SYN_SENT) { 8268c2ecf20Sopenharmony_ci /* The peer may detach from a queue pair while 8278c2ecf20Sopenharmony_ci * we are still in the connecting state, i.e., 8288c2ecf20Sopenharmony_ci * if the peer VM is killed after attaching to 8298c2ecf20Sopenharmony_ci * a queue pair, but before we complete the 8308c2ecf20Sopenharmony_ci * handshake. In that case, we treat the detach 8318c2ecf20Sopenharmony_ci * event like a reset. 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 8358c2ecf20Sopenharmony_ci sk->sk_err = ECONNRESET; 8368c2ecf20Sopenharmony_ci sk->sk_error_report(sk); 8378c2ecf20Sopenharmony_ci return; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic void vmci_transport_peer_detach_cb(u32 sub_id, 8468c2ecf20Sopenharmony_ci const struct vmci_event_data *e_data, 8478c2ecf20Sopenharmony_ci void *client_data) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct vmci_transport *trans = client_data; 8508c2ecf20Sopenharmony_ci const struct vmci_event_payload_qp *e_payload; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci e_payload = vmci_event_data_const_payload(e_data); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* XXX This is lame, we should provide a way to lookup sockets by 8558c2ecf20Sopenharmony_ci * qp_handle. 8568c2ecf20Sopenharmony_ci */ 8578c2ecf20Sopenharmony_ci if (vmci_handle_is_invalid(e_payload->handle) || 8588c2ecf20Sopenharmony_ci !vmci_handle_is_equal(trans->qp_handle, e_payload->handle)) 8598c2ecf20Sopenharmony_ci return; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* We don't ask for delayed CBs when we subscribe to this event (we 8628c2ecf20Sopenharmony_ci * pass 0 as flags to vmci_event_subscribe()). VMCI makes no 8638c2ecf20Sopenharmony_ci * guarantees in that case about what context we might be running in, 8648c2ecf20Sopenharmony_ci * so it could be BH or process, blockable or non-blockable. So we 8658c2ecf20Sopenharmony_ci * need to account for all possible contexts here. 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci spin_lock_bh(&trans->lock); 8688c2ecf20Sopenharmony_ci if (!trans->sk) 8698c2ecf20Sopenharmony_ci goto out; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* Apart from here, trans->lock is only grabbed as part of sk destruct, 8728c2ecf20Sopenharmony_ci * where trans->sk isn't locked. 8738c2ecf20Sopenharmony_ci */ 8748c2ecf20Sopenharmony_ci bh_lock_sock(trans->sk); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci vmci_transport_handle_detach(trans->sk); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci bh_unlock_sock(trans->sk); 8798c2ecf20Sopenharmony_ci out: 8808c2ecf20Sopenharmony_ci spin_unlock_bh(&trans->lock); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic void vmci_transport_qp_resumed_cb(u32 sub_id, 8848c2ecf20Sopenharmony_ci const struct vmci_event_data *e_data, 8858c2ecf20Sopenharmony_ci void *client_data) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci vsock_for_each_connected_socket(&vmci_transport, 8888c2ecf20Sopenharmony_ci vmci_transport_handle_detach); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic void vmci_transport_recv_pkt_work(struct work_struct *work) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct vmci_transport_recv_pkt_info *recv_pkt_info; 8948c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt; 8958c2ecf20Sopenharmony_ci struct sock *sk; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci recv_pkt_info = 8988c2ecf20Sopenharmony_ci container_of(work, struct vmci_transport_recv_pkt_info, work); 8998c2ecf20Sopenharmony_ci sk = recv_pkt_info->sk; 9008c2ecf20Sopenharmony_ci pkt = &recv_pkt_info->pkt; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci lock_sock(sk); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* The local context ID may be out of date. */ 9058c2ecf20Sopenharmony_ci vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci switch (sk->sk_state) { 9088c2ecf20Sopenharmony_ci case TCP_LISTEN: 9098c2ecf20Sopenharmony_ci vmci_transport_recv_listen(sk, pkt); 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci case TCP_SYN_SENT: 9128c2ecf20Sopenharmony_ci /* Processing of pending connections for servers goes through 9138c2ecf20Sopenharmony_ci * the listening socket, so see vmci_transport_recv_listen() 9148c2ecf20Sopenharmony_ci * for that path. 9158c2ecf20Sopenharmony_ci */ 9168c2ecf20Sopenharmony_ci vmci_transport_recv_connecting_client(sk, pkt); 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci case TCP_ESTABLISHED: 9198c2ecf20Sopenharmony_ci vmci_transport_recv_connected(sk, pkt); 9208c2ecf20Sopenharmony_ci break; 9218c2ecf20Sopenharmony_ci default: 9228c2ecf20Sopenharmony_ci /* Because this function does not run in the same context as 9238c2ecf20Sopenharmony_ci * vmci_transport_recv_stream_cb it is possible that the 9248c2ecf20Sopenharmony_ci * socket has closed. We need to let the other side know or it 9258c2ecf20Sopenharmony_ci * could be sitting in a connect and hang forever. Send a 9268c2ecf20Sopenharmony_ci * reset to prevent that. 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_ci vmci_transport_send_reset(sk, pkt); 9298c2ecf20Sopenharmony_ci break; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci release_sock(sk); 9338c2ecf20Sopenharmony_ci kfree(recv_pkt_info); 9348c2ecf20Sopenharmony_ci /* Release reference obtained in the stream callback when we fetched 9358c2ecf20Sopenharmony_ci * this socket out of the bound or connected list. 9368c2ecf20Sopenharmony_ci */ 9378c2ecf20Sopenharmony_ci sock_put(sk); 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic int vmci_transport_recv_listen(struct sock *sk, 9418c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct sock *pending; 9448c2ecf20Sopenharmony_ci struct vsock_sock *vpending; 9458c2ecf20Sopenharmony_ci int err; 9468c2ecf20Sopenharmony_ci u64 qp_size; 9478c2ecf20Sopenharmony_ci bool old_request = false; 9488c2ecf20Sopenharmony_ci bool old_pkt_proto = false; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci err = 0; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* Because we are in the listen state, we could be receiving a packet 9538c2ecf20Sopenharmony_ci * for ourself or any previous connection requests that we received. 9548c2ecf20Sopenharmony_ci * If it's the latter, we try to find a socket in our list of pending 9558c2ecf20Sopenharmony_ci * connections and, if we do, call the appropriate handler for the 9568c2ecf20Sopenharmony_ci * state that that socket is in. Otherwise we try to service the 9578c2ecf20Sopenharmony_ci * connection request. 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_ci pending = vmci_transport_get_pending(sk, pkt); 9608c2ecf20Sopenharmony_ci if (pending) { 9618c2ecf20Sopenharmony_ci lock_sock(pending); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* The local context ID may be out of date. */ 9648c2ecf20Sopenharmony_ci vsock_sk(pending)->local_addr.svm_cid = pkt->dg.dst.context; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci switch (pending->sk_state) { 9678c2ecf20Sopenharmony_ci case TCP_SYN_SENT: 9688c2ecf20Sopenharmony_ci err = vmci_transport_recv_connecting_server(sk, 9698c2ecf20Sopenharmony_ci pending, 9708c2ecf20Sopenharmony_ci pkt); 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci default: 9738c2ecf20Sopenharmony_ci vmci_transport_send_reset(pending, pkt); 9748c2ecf20Sopenharmony_ci err = -EINVAL; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (err < 0) 9788c2ecf20Sopenharmony_ci vsock_remove_pending(sk, pending); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci release_sock(pending); 9818c2ecf20Sopenharmony_ci vmci_transport_release_pending(pending); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci return err; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* The listen state only accepts connection requests. Reply with a 9878c2ecf20Sopenharmony_ci * reset unless we received a reset. 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (!(pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST || 9918c2ecf20Sopenharmony_ci pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST2)) { 9928c2ecf20Sopenharmony_ci vmci_transport_reply_reset(pkt); 9938c2ecf20Sopenharmony_ci return -EINVAL; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (pkt->u.size == 0) { 9978c2ecf20Sopenharmony_ci vmci_transport_reply_reset(pkt); 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* If this socket can't accommodate this connection request, we send a 10028c2ecf20Sopenharmony_ci * reset. Otherwise we create and initialize a child socket and reply 10038c2ecf20Sopenharmony_ci * with a connection negotiation. 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_ci if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) { 10068c2ecf20Sopenharmony_ci vmci_transport_reply_reset(pkt); 10078c2ecf20Sopenharmony_ci return -ECONNREFUSED; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci pending = vsock_create_connected(sk); 10118c2ecf20Sopenharmony_ci if (!pending) { 10128c2ecf20Sopenharmony_ci vmci_transport_send_reset(sk, pkt); 10138c2ecf20Sopenharmony_ci return -ENOMEM; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci vpending = vsock_sk(pending); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci vsock_addr_init(&vpending->local_addr, pkt->dg.dst.context, 10198c2ecf20Sopenharmony_ci pkt->dst_port); 10208c2ecf20Sopenharmony_ci vsock_addr_init(&vpending->remote_addr, pkt->dg.src.context, 10218c2ecf20Sopenharmony_ci pkt->src_port); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci err = vsock_assign_transport(vpending, vsock_sk(sk)); 10248c2ecf20Sopenharmony_ci /* Transport assigned (looking at remote_addr) must be the same 10258c2ecf20Sopenharmony_ci * where we received the request. 10268c2ecf20Sopenharmony_ci */ 10278c2ecf20Sopenharmony_ci if (err || !vmci_check_transport(vpending)) { 10288c2ecf20Sopenharmony_ci vmci_transport_send_reset(sk, pkt); 10298c2ecf20Sopenharmony_ci sock_put(pending); 10308c2ecf20Sopenharmony_ci return err; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* If the proposed size fits within our min/max, accept it. Otherwise 10348c2ecf20Sopenharmony_ci * propose our own size. 10358c2ecf20Sopenharmony_ci */ 10368c2ecf20Sopenharmony_ci if (pkt->u.size >= vpending->buffer_min_size && 10378c2ecf20Sopenharmony_ci pkt->u.size <= vpending->buffer_max_size) { 10388c2ecf20Sopenharmony_ci qp_size = pkt->u.size; 10398c2ecf20Sopenharmony_ci } else { 10408c2ecf20Sopenharmony_ci qp_size = vpending->buffer_size; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* Figure out if we are using old or new requests based on the 10448c2ecf20Sopenharmony_ci * overrides pkt types sent by our peer. 10458c2ecf20Sopenharmony_ci */ 10468c2ecf20Sopenharmony_ci if (vmci_transport_old_proto_override(&old_pkt_proto)) { 10478c2ecf20Sopenharmony_ci old_request = old_pkt_proto; 10488c2ecf20Sopenharmony_ci } else { 10498c2ecf20Sopenharmony_ci if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST) 10508c2ecf20Sopenharmony_ci old_request = true; 10518c2ecf20Sopenharmony_ci else if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST2) 10528c2ecf20Sopenharmony_ci old_request = false; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (old_request) { 10578c2ecf20Sopenharmony_ci /* Handle a REQUEST (or override) */ 10588c2ecf20Sopenharmony_ci u16 version = VSOCK_PROTO_INVALID; 10598c2ecf20Sopenharmony_ci if (vmci_transport_proto_to_notify_struct( 10608c2ecf20Sopenharmony_ci pending, &version, true)) 10618c2ecf20Sopenharmony_ci err = vmci_transport_send_negotiate(pending, qp_size); 10628c2ecf20Sopenharmony_ci else 10638c2ecf20Sopenharmony_ci err = -EINVAL; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci } else { 10668c2ecf20Sopenharmony_ci /* Handle a REQUEST2 (or override) */ 10678c2ecf20Sopenharmony_ci int proto_int = pkt->proto; 10688c2ecf20Sopenharmony_ci int pos; 10698c2ecf20Sopenharmony_ci u16 active_proto_version = 0; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* The list of possible protocols is the intersection of all 10728c2ecf20Sopenharmony_ci * protocols the client supports ... plus all the protocols we 10738c2ecf20Sopenharmony_ci * support. 10748c2ecf20Sopenharmony_ci */ 10758c2ecf20Sopenharmony_ci proto_int &= vmci_transport_new_proto_supported_versions(); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* We choose the highest possible protocol version and use that 10788c2ecf20Sopenharmony_ci * one. 10798c2ecf20Sopenharmony_ci */ 10808c2ecf20Sopenharmony_ci pos = fls(proto_int); 10818c2ecf20Sopenharmony_ci if (pos) { 10828c2ecf20Sopenharmony_ci active_proto_version = (1 << (pos - 1)); 10838c2ecf20Sopenharmony_ci if (vmci_transport_proto_to_notify_struct( 10848c2ecf20Sopenharmony_ci pending, &active_proto_version, false)) 10858c2ecf20Sopenharmony_ci err = vmci_transport_send_negotiate2(pending, 10868c2ecf20Sopenharmony_ci qp_size, 10878c2ecf20Sopenharmony_ci active_proto_version); 10888c2ecf20Sopenharmony_ci else 10898c2ecf20Sopenharmony_ci err = -EINVAL; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci } else { 10928c2ecf20Sopenharmony_ci err = -EINVAL; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (err < 0) { 10978c2ecf20Sopenharmony_ci vmci_transport_send_reset(sk, pkt); 10988c2ecf20Sopenharmony_ci sock_put(pending); 10998c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 11008c2ecf20Sopenharmony_ci goto out; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci vsock_add_pending(sk, pending); 11048c2ecf20Sopenharmony_ci sk_acceptq_added(sk); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci pending->sk_state = TCP_SYN_SENT; 11078c2ecf20Sopenharmony_ci vmci_trans(vpending)->produce_size = 11088c2ecf20Sopenharmony_ci vmci_trans(vpending)->consume_size = qp_size; 11098c2ecf20Sopenharmony_ci vpending->buffer_size = qp_size; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci vmci_trans(vpending)->notify_ops->process_request(pending); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* We might never receive another message for this socket and it's not 11148c2ecf20Sopenharmony_ci * connected to any process, so we have to ensure it gets cleaned up 11158c2ecf20Sopenharmony_ci * ourself. Our delayed work function will take care of that. Note 11168c2ecf20Sopenharmony_ci * that we do not ever cancel this function since we have few 11178c2ecf20Sopenharmony_ci * guarantees about its state when calling cancel_delayed_work(). 11188c2ecf20Sopenharmony_ci * Instead we hold a reference on the socket for that function and make 11198c2ecf20Sopenharmony_ci * it capable of handling cases where it needs to do nothing but 11208c2ecf20Sopenharmony_ci * release that reference. 11218c2ecf20Sopenharmony_ci */ 11228c2ecf20Sopenharmony_ci vpending->listener = sk; 11238c2ecf20Sopenharmony_ci sock_hold(sk); 11248c2ecf20Sopenharmony_ci sock_hold(pending); 11258c2ecf20Sopenharmony_ci schedule_delayed_work(&vpending->pending_work, HZ); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ciout: 11288c2ecf20Sopenharmony_ci return err; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic int 11328c2ecf20Sopenharmony_civmci_transport_recv_connecting_server(struct sock *listener, 11338c2ecf20Sopenharmony_ci struct sock *pending, 11348c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci struct vsock_sock *vpending; 11378c2ecf20Sopenharmony_ci struct vmci_handle handle; 11388c2ecf20Sopenharmony_ci struct vmci_qp *qpair; 11398c2ecf20Sopenharmony_ci bool is_local; 11408c2ecf20Sopenharmony_ci u32 flags; 11418c2ecf20Sopenharmony_ci u32 detach_sub_id; 11428c2ecf20Sopenharmony_ci int err; 11438c2ecf20Sopenharmony_ci int skerr; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci vpending = vsock_sk(pending); 11468c2ecf20Sopenharmony_ci detach_sub_id = VMCI_INVALID_ID; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci switch (pkt->type) { 11498c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_OFFER: 11508c2ecf20Sopenharmony_ci if (vmci_handle_is_invalid(pkt->u.handle)) { 11518c2ecf20Sopenharmony_ci vmci_transport_send_reset(pending, pkt); 11528c2ecf20Sopenharmony_ci skerr = EPROTO; 11538c2ecf20Sopenharmony_ci err = -EINVAL; 11548c2ecf20Sopenharmony_ci goto destroy; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci default: 11588c2ecf20Sopenharmony_ci /* Close and cleanup the connection. */ 11598c2ecf20Sopenharmony_ci vmci_transport_send_reset(pending, pkt); 11608c2ecf20Sopenharmony_ci skerr = EPROTO; 11618c2ecf20Sopenharmony_ci err = pkt->type == VMCI_TRANSPORT_PACKET_TYPE_RST ? 0 : -EINVAL; 11628c2ecf20Sopenharmony_ci goto destroy; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* In order to complete the connection we need to attach to the offered 11668c2ecf20Sopenharmony_ci * queue pair and send an attach notification. We also subscribe to the 11678c2ecf20Sopenharmony_ci * detach event so we know when our peer goes away, and we do that 11688c2ecf20Sopenharmony_ci * before attaching so we don't miss an event. If all this succeeds, 11698c2ecf20Sopenharmony_ci * we update our state and wakeup anything waiting in accept() for a 11708c2ecf20Sopenharmony_ci * connection. 11718c2ecf20Sopenharmony_ci */ 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* We don't care about attach since we ensure the other side has 11748c2ecf20Sopenharmony_ci * attached by specifying the ATTACH_ONLY flag below. 11758c2ecf20Sopenharmony_ci */ 11768c2ecf20Sopenharmony_ci err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH, 11778c2ecf20Sopenharmony_ci vmci_transport_peer_detach_cb, 11788c2ecf20Sopenharmony_ci vmci_trans(vpending), &detach_sub_id); 11798c2ecf20Sopenharmony_ci if (err < VMCI_SUCCESS) { 11808c2ecf20Sopenharmony_ci vmci_transport_send_reset(pending, pkt); 11818c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 11828c2ecf20Sopenharmony_ci skerr = -err; 11838c2ecf20Sopenharmony_ci goto destroy; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci vmci_trans(vpending)->detach_sub_id = detach_sub_id; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci /* Now attach to the queue pair the client created. */ 11898c2ecf20Sopenharmony_ci handle = pkt->u.handle; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* vpending->local_addr always has a context id so we do not need to 11928c2ecf20Sopenharmony_ci * worry about VMADDR_CID_ANY in this case. 11938c2ecf20Sopenharmony_ci */ 11948c2ecf20Sopenharmony_ci is_local = 11958c2ecf20Sopenharmony_ci vpending->remote_addr.svm_cid == vpending->local_addr.svm_cid; 11968c2ecf20Sopenharmony_ci flags = VMCI_QPFLAG_ATTACH_ONLY; 11978c2ecf20Sopenharmony_ci flags |= is_local ? VMCI_QPFLAG_LOCAL : 0; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci err = vmci_transport_queue_pair_alloc( 12008c2ecf20Sopenharmony_ci &qpair, 12018c2ecf20Sopenharmony_ci &handle, 12028c2ecf20Sopenharmony_ci vmci_trans(vpending)->produce_size, 12038c2ecf20Sopenharmony_ci vmci_trans(vpending)->consume_size, 12048c2ecf20Sopenharmony_ci pkt->dg.src.context, 12058c2ecf20Sopenharmony_ci flags, 12068c2ecf20Sopenharmony_ci vmci_transport_is_trusted( 12078c2ecf20Sopenharmony_ci vpending, 12088c2ecf20Sopenharmony_ci vpending->remote_addr.svm_cid)); 12098c2ecf20Sopenharmony_ci if (err < 0) { 12108c2ecf20Sopenharmony_ci vmci_transport_send_reset(pending, pkt); 12118c2ecf20Sopenharmony_ci skerr = -err; 12128c2ecf20Sopenharmony_ci goto destroy; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci vmci_trans(vpending)->qp_handle = handle; 12168c2ecf20Sopenharmony_ci vmci_trans(vpending)->qpair = qpair; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* When we send the attach message, we must be ready to handle incoming 12198c2ecf20Sopenharmony_ci * control messages on the newly connected socket. So we move the 12208c2ecf20Sopenharmony_ci * pending socket to the connected state before sending the attach 12218c2ecf20Sopenharmony_ci * message. Otherwise, an incoming packet triggered by the attach being 12228c2ecf20Sopenharmony_ci * received by the peer may be processed concurrently with what happens 12238c2ecf20Sopenharmony_ci * below after sending the attach message, and that incoming packet 12248c2ecf20Sopenharmony_ci * will find the listening socket instead of the (currently) pending 12258c2ecf20Sopenharmony_ci * socket. Note that enqueueing the socket increments the reference 12268c2ecf20Sopenharmony_ci * count, so even if a reset comes before the connection is accepted, 12278c2ecf20Sopenharmony_ci * the socket will be valid until it is removed from the queue. 12288c2ecf20Sopenharmony_ci * 12298c2ecf20Sopenharmony_ci * If we fail sending the attach below, we remove the socket from the 12308c2ecf20Sopenharmony_ci * connected list and move the socket to TCP_CLOSE before 12318c2ecf20Sopenharmony_ci * releasing the lock, so a pending slow path processing of an incoming 12328c2ecf20Sopenharmony_ci * packet will not see the socket in the connected state in that case. 12338c2ecf20Sopenharmony_ci */ 12348c2ecf20Sopenharmony_ci pending->sk_state = TCP_ESTABLISHED; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci vsock_insert_connected(vpending); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* Notify our peer of our attach. */ 12398c2ecf20Sopenharmony_ci err = vmci_transport_send_attach(pending, handle); 12408c2ecf20Sopenharmony_ci if (err < 0) { 12418c2ecf20Sopenharmony_ci vsock_remove_connected(vpending); 12428c2ecf20Sopenharmony_ci pr_err("Could not send attach\n"); 12438c2ecf20Sopenharmony_ci vmci_transport_send_reset(pending, pkt); 12448c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 12458c2ecf20Sopenharmony_ci skerr = -err; 12468c2ecf20Sopenharmony_ci goto destroy; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* We have a connection. Move the now connected socket from the 12508c2ecf20Sopenharmony_ci * listener's pending list to the accept queue so callers of accept() 12518c2ecf20Sopenharmony_ci * can find it. 12528c2ecf20Sopenharmony_ci */ 12538c2ecf20Sopenharmony_ci vsock_remove_pending(listener, pending); 12548c2ecf20Sopenharmony_ci vsock_enqueue_accept(listener, pending); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* Callers of accept() will be be waiting on the listening socket, not 12578c2ecf20Sopenharmony_ci * the pending socket. 12588c2ecf20Sopenharmony_ci */ 12598c2ecf20Sopenharmony_ci listener->sk_data_ready(listener); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci return 0; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cidestroy: 12648c2ecf20Sopenharmony_ci pending->sk_err = skerr; 12658c2ecf20Sopenharmony_ci pending->sk_state = TCP_CLOSE; 12668c2ecf20Sopenharmony_ci /* As long as we drop our reference, all necessary cleanup will handle 12678c2ecf20Sopenharmony_ci * when the cleanup function drops its reference and our destruct 12688c2ecf20Sopenharmony_ci * implementation is called. Note that since the listen handler will 12698c2ecf20Sopenharmony_ci * remove pending from the pending list upon our failure, the cleanup 12708c2ecf20Sopenharmony_ci * function won't drop the additional reference, which is why we do it 12718c2ecf20Sopenharmony_ci * here. 12728c2ecf20Sopenharmony_ci */ 12738c2ecf20Sopenharmony_ci sock_put(pending); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return err; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic int 12798c2ecf20Sopenharmony_civmci_transport_recv_connecting_client(struct sock *sk, 12808c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 12838c2ecf20Sopenharmony_ci int err; 12848c2ecf20Sopenharmony_ci int skerr; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci switch (pkt->type) { 12898c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_ATTACH: 12908c2ecf20Sopenharmony_ci if (vmci_handle_is_invalid(pkt->u.handle) || 12918c2ecf20Sopenharmony_ci !vmci_handle_is_equal(pkt->u.handle, 12928c2ecf20Sopenharmony_ci vmci_trans(vsk)->qp_handle)) { 12938c2ecf20Sopenharmony_ci skerr = EPROTO; 12948c2ecf20Sopenharmony_ci err = -EINVAL; 12958c2ecf20Sopenharmony_ci goto destroy; 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* Signify the socket is connected and wakeup the waiter in 12998c2ecf20Sopenharmony_ci * connect(). Also place the socket in the connected table for 13008c2ecf20Sopenharmony_ci * accounting (it can already be found since it's in the bound 13018c2ecf20Sopenharmony_ci * table). 13028c2ecf20Sopenharmony_ci */ 13038c2ecf20Sopenharmony_ci sk->sk_state = TCP_ESTABLISHED; 13048c2ecf20Sopenharmony_ci sk->sk_socket->state = SS_CONNECTED; 13058c2ecf20Sopenharmony_ci vsock_insert_connected(vsk); 13068c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE: 13108c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE2: 13118c2ecf20Sopenharmony_ci if (pkt->u.size == 0 13128c2ecf20Sopenharmony_ci || pkt->dg.src.context != vsk->remote_addr.svm_cid 13138c2ecf20Sopenharmony_ci || pkt->src_port != vsk->remote_addr.svm_port 13148c2ecf20Sopenharmony_ci || !vmci_handle_is_invalid(vmci_trans(vsk)->qp_handle) 13158c2ecf20Sopenharmony_ci || vmci_trans(vsk)->qpair 13168c2ecf20Sopenharmony_ci || vmci_trans(vsk)->produce_size != 0 13178c2ecf20Sopenharmony_ci || vmci_trans(vsk)->consume_size != 0 13188c2ecf20Sopenharmony_ci || vmci_trans(vsk)->detach_sub_id != VMCI_INVALID_ID) { 13198c2ecf20Sopenharmony_ci skerr = EPROTO; 13208c2ecf20Sopenharmony_ci err = -EINVAL; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci goto destroy; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci err = vmci_transport_recv_connecting_client_negotiate(sk, pkt); 13268c2ecf20Sopenharmony_ci if (err) { 13278c2ecf20Sopenharmony_ci skerr = -err; 13288c2ecf20Sopenharmony_ci goto destroy; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci break; 13328c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_INVALID: 13338c2ecf20Sopenharmony_ci err = vmci_transport_recv_connecting_client_invalid(sk, pkt); 13348c2ecf20Sopenharmony_ci if (err) { 13358c2ecf20Sopenharmony_ci skerr = -err; 13368c2ecf20Sopenharmony_ci goto destroy; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci break; 13408c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_RST: 13418c2ecf20Sopenharmony_ci /* Older versions of the linux code (WS 6.5 / ESX 4.0) used to 13428c2ecf20Sopenharmony_ci * continue processing here after they sent an INVALID packet. 13438c2ecf20Sopenharmony_ci * This meant that we got a RST after the INVALID. We ignore a 13448c2ecf20Sopenharmony_ci * RST after an INVALID. The common code doesn't send the RST 13458c2ecf20Sopenharmony_ci * ... so we can hang if an old version of the common code 13468c2ecf20Sopenharmony_ci * fails between getting a REQUEST and sending an OFFER back. 13478c2ecf20Sopenharmony_ci * Not much we can do about it... except hope that it doesn't 13488c2ecf20Sopenharmony_ci * happen. 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_ci if (vsk->ignore_connecting_rst) { 13518c2ecf20Sopenharmony_ci vsk->ignore_connecting_rst = false; 13528c2ecf20Sopenharmony_ci } else { 13538c2ecf20Sopenharmony_ci skerr = ECONNRESET; 13548c2ecf20Sopenharmony_ci err = 0; 13558c2ecf20Sopenharmony_ci goto destroy; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci break; 13598c2ecf20Sopenharmony_ci default: 13608c2ecf20Sopenharmony_ci /* Close and cleanup the connection. */ 13618c2ecf20Sopenharmony_ci skerr = EPROTO; 13628c2ecf20Sopenharmony_ci err = -EINVAL; 13638c2ecf20Sopenharmony_ci goto destroy; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci return 0; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cidestroy: 13698c2ecf20Sopenharmony_ci vmci_transport_send_reset(sk, pkt); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 13728c2ecf20Sopenharmony_ci sk->sk_err = skerr; 13738c2ecf20Sopenharmony_ci sk->sk_error_report(sk); 13748c2ecf20Sopenharmony_ci return err; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic int vmci_transport_recv_connecting_client_negotiate( 13788c2ecf20Sopenharmony_ci struct sock *sk, 13798c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci int err; 13828c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 13838c2ecf20Sopenharmony_ci struct vmci_handle handle; 13848c2ecf20Sopenharmony_ci struct vmci_qp *qpair; 13858c2ecf20Sopenharmony_ci u32 detach_sub_id; 13868c2ecf20Sopenharmony_ci bool is_local; 13878c2ecf20Sopenharmony_ci u32 flags; 13888c2ecf20Sopenharmony_ci bool old_proto = true; 13898c2ecf20Sopenharmony_ci bool old_pkt_proto; 13908c2ecf20Sopenharmony_ci u16 version; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 13938c2ecf20Sopenharmony_ci handle = VMCI_INVALID_HANDLE; 13948c2ecf20Sopenharmony_ci detach_sub_id = VMCI_INVALID_ID; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* If we have gotten here then we should be past the point where old 13978c2ecf20Sopenharmony_ci * linux vsock could have sent the bogus rst. 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_ci vsk->sent_request = false; 14008c2ecf20Sopenharmony_ci vsk->ignore_connecting_rst = false; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* Verify that we're OK with the proposed queue pair size */ 14038c2ecf20Sopenharmony_ci if (pkt->u.size < vsk->buffer_min_size || 14048c2ecf20Sopenharmony_ci pkt->u.size > vsk->buffer_max_size) { 14058c2ecf20Sopenharmony_ci err = -EINVAL; 14068c2ecf20Sopenharmony_ci goto destroy; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* At this point we know the CID the peer is using to talk to us. */ 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (vsk->local_addr.svm_cid == VMADDR_CID_ANY) 14128c2ecf20Sopenharmony_ci vsk->local_addr.svm_cid = pkt->dg.dst.context; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci /* Setup the notify ops to be the highest supported version that both 14158c2ecf20Sopenharmony_ci * the server and the client support. 14168c2ecf20Sopenharmony_ci */ 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci if (vmci_transport_old_proto_override(&old_pkt_proto)) { 14198c2ecf20Sopenharmony_ci old_proto = old_pkt_proto; 14208c2ecf20Sopenharmony_ci } else { 14218c2ecf20Sopenharmony_ci if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE) 14228c2ecf20Sopenharmony_ci old_proto = true; 14238c2ecf20Sopenharmony_ci else if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_NEGOTIATE2) 14248c2ecf20Sopenharmony_ci old_proto = false; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (old_proto) 14298c2ecf20Sopenharmony_ci version = VSOCK_PROTO_INVALID; 14308c2ecf20Sopenharmony_ci else 14318c2ecf20Sopenharmony_ci version = pkt->proto; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci if (!vmci_transport_proto_to_notify_struct(sk, &version, old_proto)) { 14348c2ecf20Sopenharmony_ci err = -EINVAL; 14358c2ecf20Sopenharmony_ci goto destroy; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci /* Subscribe to detach events first. 14398c2ecf20Sopenharmony_ci * 14408c2ecf20Sopenharmony_ci * XXX We attach once for each queue pair created for now so it is easy 14418c2ecf20Sopenharmony_ci * to find the socket (it's provided), but later we should only 14428c2ecf20Sopenharmony_ci * subscribe once and add a way to lookup sockets by queue pair handle. 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_ci err = vmci_event_subscribe(VMCI_EVENT_QP_PEER_DETACH, 14458c2ecf20Sopenharmony_ci vmci_transport_peer_detach_cb, 14468c2ecf20Sopenharmony_ci vmci_trans(vsk), &detach_sub_id); 14478c2ecf20Sopenharmony_ci if (err < VMCI_SUCCESS) { 14488c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 14498c2ecf20Sopenharmony_ci goto destroy; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci /* Make VMCI select the handle for us. */ 14538c2ecf20Sopenharmony_ci handle = VMCI_INVALID_HANDLE; 14548c2ecf20Sopenharmony_ci is_local = vsk->remote_addr.svm_cid == vsk->local_addr.svm_cid; 14558c2ecf20Sopenharmony_ci flags = is_local ? VMCI_QPFLAG_LOCAL : 0; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci err = vmci_transport_queue_pair_alloc(&qpair, 14588c2ecf20Sopenharmony_ci &handle, 14598c2ecf20Sopenharmony_ci pkt->u.size, 14608c2ecf20Sopenharmony_ci pkt->u.size, 14618c2ecf20Sopenharmony_ci vsk->remote_addr.svm_cid, 14628c2ecf20Sopenharmony_ci flags, 14638c2ecf20Sopenharmony_ci vmci_transport_is_trusted( 14648c2ecf20Sopenharmony_ci vsk, 14658c2ecf20Sopenharmony_ci vsk-> 14668c2ecf20Sopenharmony_ci remote_addr.svm_cid)); 14678c2ecf20Sopenharmony_ci if (err < 0) 14688c2ecf20Sopenharmony_ci goto destroy; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci err = vmci_transport_send_qp_offer(sk, handle); 14718c2ecf20Sopenharmony_ci if (err < 0) { 14728c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 14738c2ecf20Sopenharmony_ci goto destroy; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci vmci_trans(vsk)->qp_handle = handle; 14778c2ecf20Sopenharmony_ci vmci_trans(vsk)->qpair = qpair; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci vmci_trans(vsk)->produce_size = vmci_trans(vsk)->consume_size = 14808c2ecf20Sopenharmony_ci pkt->u.size; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci vmci_trans(vsk)->detach_sub_id = detach_sub_id; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops->process_negotiate(sk); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci return 0; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_cidestroy: 14898c2ecf20Sopenharmony_ci if (detach_sub_id != VMCI_INVALID_ID) 14908c2ecf20Sopenharmony_ci vmci_event_unsubscribe(detach_sub_id); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci if (!vmci_handle_is_invalid(handle)) 14938c2ecf20Sopenharmony_ci vmci_qpair_detach(&qpair); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return err; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic int 14998c2ecf20Sopenharmony_civmci_transport_recv_connecting_client_invalid(struct sock *sk, 15008c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci int err = 0; 15038c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if (vsk->sent_request) { 15068c2ecf20Sopenharmony_ci vsk->sent_request = false; 15078c2ecf20Sopenharmony_ci vsk->ignore_connecting_rst = true; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci err = vmci_transport_send_conn_request(sk, vsk->buffer_size); 15108c2ecf20Sopenharmony_ci if (err < 0) 15118c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 15128c2ecf20Sopenharmony_ci else 15138c2ecf20Sopenharmony_ci err = 0; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci return err; 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_cistatic int vmci_transport_recv_connected(struct sock *sk, 15218c2ecf20Sopenharmony_ci struct vmci_transport_packet *pkt) 15228c2ecf20Sopenharmony_ci{ 15238c2ecf20Sopenharmony_ci struct vsock_sock *vsk; 15248c2ecf20Sopenharmony_ci bool pkt_processed = false; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* In cases where we are closing the connection, it's sufficient to 15278c2ecf20Sopenharmony_ci * mark the state change (and maybe error) and wake up any waiting 15288c2ecf20Sopenharmony_ci * threads. Since this is a connected socket, it's owned by a user 15298c2ecf20Sopenharmony_ci * process and will be cleaned up when the failure is passed back on 15308c2ecf20Sopenharmony_ci * the current or next system call. Our system call implementations 15318c2ecf20Sopenharmony_ci * must therefore check for error and state changes on entry and when 15328c2ecf20Sopenharmony_ci * being awoken. 15338c2ecf20Sopenharmony_ci */ 15348c2ecf20Sopenharmony_ci switch (pkt->type) { 15358c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_SHUTDOWN: 15368c2ecf20Sopenharmony_ci if (pkt->u.mode) { 15378c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci vsk->peer_shutdown |= pkt->u.mode; 15408c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci break; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci case VMCI_TRANSPORT_PACKET_TYPE_RST: 15458c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 15468c2ecf20Sopenharmony_ci /* It is possible that we sent our peer a message (e.g a 15478c2ecf20Sopenharmony_ci * WAITING_READ) right before we got notified that the peer had 15488c2ecf20Sopenharmony_ci * detached. If that happens then we can get a RST pkt back 15498c2ecf20Sopenharmony_ci * from our peer even though there is data available for us to 15508c2ecf20Sopenharmony_ci * read. In that case, don't shutdown the socket completely but 15518c2ecf20Sopenharmony_ci * instead allow the local client to finish reading data off 15528c2ecf20Sopenharmony_ci * the queuepair. Always treat a RST pkt in connected mode like 15538c2ecf20Sopenharmony_ci * a clean shutdown. 15548c2ecf20Sopenharmony_ci */ 15558c2ecf20Sopenharmony_ci sock_set_flag(sk, SOCK_DONE); 15568c2ecf20Sopenharmony_ci vsk->peer_shutdown = SHUTDOWN_MASK; 15578c2ecf20Sopenharmony_ci if (vsock_stream_has_data(vsk) <= 0) 15588c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSING; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 15618c2ecf20Sopenharmony_ci break; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci default: 15648c2ecf20Sopenharmony_ci vsk = vsock_sk(sk); 15658c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops->handle_notify_pkt( 15668c2ecf20Sopenharmony_ci sk, pkt, false, NULL, NULL, 15678c2ecf20Sopenharmony_ci &pkt_processed); 15688c2ecf20Sopenharmony_ci if (!pkt_processed) 15698c2ecf20Sopenharmony_ci return -EINVAL; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci break; 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci return 0; 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic int vmci_transport_socket_init(struct vsock_sock *vsk, 15788c2ecf20Sopenharmony_ci struct vsock_sock *psk) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci vsk->trans = kmalloc(sizeof(struct vmci_transport), GFP_KERNEL); 15818c2ecf20Sopenharmony_ci if (!vsk->trans) 15828c2ecf20Sopenharmony_ci return -ENOMEM; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci vmci_trans(vsk)->dg_handle = VMCI_INVALID_HANDLE; 15858c2ecf20Sopenharmony_ci vmci_trans(vsk)->qp_handle = VMCI_INVALID_HANDLE; 15868c2ecf20Sopenharmony_ci vmci_trans(vsk)->qpair = NULL; 15878c2ecf20Sopenharmony_ci vmci_trans(vsk)->produce_size = vmci_trans(vsk)->consume_size = 0; 15888c2ecf20Sopenharmony_ci vmci_trans(vsk)->detach_sub_id = VMCI_INVALID_ID; 15898c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops = NULL; 15908c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vmci_trans(vsk)->elem); 15918c2ecf20Sopenharmony_ci vmci_trans(vsk)->sk = &vsk->sk; 15928c2ecf20Sopenharmony_ci spin_lock_init(&vmci_trans(vsk)->lock); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci return 0; 15958c2ecf20Sopenharmony_ci} 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_cistatic void vmci_transport_free_resources(struct list_head *transport_list) 15988c2ecf20Sopenharmony_ci{ 15998c2ecf20Sopenharmony_ci while (!list_empty(transport_list)) { 16008c2ecf20Sopenharmony_ci struct vmci_transport *transport = 16018c2ecf20Sopenharmony_ci list_first_entry(transport_list, struct vmci_transport, 16028c2ecf20Sopenharmony_ci elem); 16038c2ecf20Sopenharmony_ci list_del(&transport->elem); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if (transport->detach_sub_id != VMCI_INVALID_ID) { 16068c2ecf20Sopenharmony_ci vmci_event_unsubscribe(transport->detach_sub_id); 16078c2ecf20Sopenharmony_ci transport->detach_sub_id = VMCI_INVALID_ID; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci if (!vmci_handle_is_invalid(transport->qp_handle)) { 16118c2ecf20Sopenharmony_ci vmci_qpair_detach(&transport->qpair); 16128c2ecf20Sopenharmony_ci transport->qp_handle = VMCI_INVALID_HANDLE; 16138c2ecf20Sopenharmony_ci transport->produce_size = 0; 16148c2ecf20Sopenharmony_ci transport->consume_size = 0; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci kfree(transport); 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci} 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic void vmci_transport_cleanup(struct work_struct *work) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci LIST_HEAD(pending); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci spin_lock_bh(&vmci_transport_cleanup_lock); 16268c2ecf20Sopenharmony_ci list_replace_init(&vmci_transport_cleanup_list, &pending); 16278c2ecf20Sopenharmony_ci spin_unlock_bh(&vmci_transport_cleanup_lock); 16288c2ecf20Sopenharmony_ci vmci_transport_free_resources(&pending); 16298c2ecf20Sopenharmony_ci} 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_cistatic void vmci_transport_destruct(struct vsock_sock *vsk) 16328c2ecf20Sopenharmony_ci{ 16338c2ecf20Sopenharmony_ci /* transport can be NULL if we hit a failure at init() time */ 16348c2ecf20Sopenharmony_ci if (!vmci_trans(vsk)) 16358c2ecf20Sopenharmony_ci return; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci /* Ensure that the detach callback doesn't use the sk/vsk 16388c2ecf20Sopenharmony_ci * we are about to destruct. 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_ci spin_lock_bh(&vmci_trans(vsk)->lock); 16418c2ecf20Sopenharmony_ci vmci_trans(vsk)->sk = NULL; 16428c2ecf20Sopenharmony_ci spin_unlock_bh(&vmci_trans(vsk)->lock); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (vmci_trans(vsk)->notify_ops) 16458c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops->socket_destruct(vsk); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci spin_lock_bh(&vmci_transport_cleanup_lock); 16488c2ecf20Sopenharmony_ci list_add(&vmci_trans(vsk)->elem, &vmci_transport_cleanup_list); 16498c2ecf20Sopenharmony_ci spin_unlock_bh(&vmci_transport_cleanup_lock); 16508c2ecf20Sopenharmony_ci schedule_work(&vmci_transport_cleanup_work); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci vsk->trans = NULL; 16538c2ecf20Sopenharmony_ci} 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_cistatic void vmci_transport_release(struct vsock_sock *vsk) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci vsock_remove_sock(vsk); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci if (!vmci_handle_is_invalid(vmci_trans(vsk)->dg_handle)) { 16608c2ecf20Sopenharmony_ci vmci_datagram_destroy_handle(vmci_trans(vsk)->dg_handle); 16618c2ecf20Sopenharmony_ci vmci_trans(vsk)->dg_handle = VMCI_INVALID_HANDLE; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic int vmci_transport_dgram_bind(struct vsock_sock *vsk, 16668c2ecf20Sopenharmony_ci struct sockaddr_vm *addr) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci u32 port; 16698c2ecf20Sopenharmony_ci u32 flags; 16708c2ecf20Sopenharmony_ci int err; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci /* VMCI will select a resource ID for us if we provide 16738c2ecf20Sopenharmony_ci * VMCI_INVALID_ID. 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_ci port = addr->svm_port == VMADDR_PORT_ANY ? 16768c2ecf20Sopenharmony_ci VMCI_INVALID_ID : addr->svm_port; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (port <= LAST_RESERVED_PORT && !capable(CAP_NET_BIND_SERVICE)) 16798c2ecf20Sopenharmony_ci return -EACCES; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci flags = addr->svm_cid == VMADDR_CID_ANY ? 16828c2ecf20Sopenharmony_ci VMCI_FLAG_ANYCID_DG_HND : 0; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci err = vmci_transport_datagram_create_hnd(port, flags, 16858c2ecf20Sopenharmony_ci vmci_transport_recv_dgram_cb, 16868c2ecf20Sopenharmony_ci &vsk->sk, 16878c2ecf20Sopenharmony_ci &vmci_trans(vsk)->dg_handle); 16888c2ecf20Sopenharmony_ci if (err < VMCI_SUCCESS) 16898c2ecf20Sopenharmony_ci return vmci_transport_error_to_vsock_error(err); 16908c2ecf20Sopenharmony_ci vsock_addr_init(&vsk->local_addr, addr->svm_cid, 16918c2ecf20Sopenharmony_ci vmci_trans(vsk)->dg_handle.resource); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci return 0; 16948c2ecf20Sopenharmony_ci} 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_cistatic int vmci_transport_dgram_enqueue( 16978c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 16988c2ecf20Sopenharmony_ci struct sockaddr_vm *remote_addr, 16998c2ecf20Sopenharmony_ci struct msghdr *msg, 17008c2ecf20Sopenharmony_ci size_t len) 17018c2ecf20Sopenharmony_ci{ 17028c2ecf20Sopenharmony_ci int err; 17038c2ecf20Sopenharmony_ci struct vmci_datagram *dg; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (len > VMCI_MAX_DG_PAYLOAD_SIZE) 17068c2ecf20Sopenharmony_ci return -EMSGSIZE; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (!vmci_transport_allow_dgram(vsk, remote_addr->svm_cid)) 17098c2ecf20Sopenharmony_ci return -EPERM; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci /* Allocate a buffer for the user's message and our packet header. */ 17128c2ecf20Sopenharmony_ci dg = kmalloc(len + sizeof(*dg), GFP_KERNEL); 17138c2ecf20Sopenharmony_ci if (!dg) 17148c2ecf20Sopenharmony_ci return -ENOMEM; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci err = memcpy_from_msg(VMCI_DG_PAYLOAD(dg), msg, len); 17178c2ecf20Sopenharmony_ci if (err) { 17188c2ecf20Sopenharmony_ci kfree(dg); 17198c2ecf20Sopenharmony_ci return err; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci dg->dst = vmci_make_handle(remote_addr->svm_cid, 17238c2ecf20Sopenharmony_ci remote_addr->svm_port); 17248c2ecf20Sopenharmony_ci dg->src = vmci_make_handle(vsk->local_addr.svm_cid, 17258c2ecf20Sopenharmony_ci vsk->local_addr.svm_port); 17268c2ecf20Sopenharmony_ci dg->payload_size = len; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci err = vmci_datagram_send(dg); 17298c2ecf20Sopenharmony_ci kfree(dg); 17308c2ecf20Sopenharmony_ci if (err < 0) 17318c2ecf20Sopenharmony_ci return vmci_transport_error_to_vsock_error(err); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci return err - sizeof(*dg); 17348c2ecf20Sopenharmony_ci} 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cistatic int vmci_transport_dgram_dequeue(struct vsock_sock *vsk, 17378c2ecf20Sopenharmony_ci struct msghdr *msg, size_t len, 17388c2ecf20Sopenharmony_ci int flags) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci int err; 17418c2ecf20Sopenharmony_ci int noblock; 17428c2ecf20Sopenharmony_ci struct vmci_datagram *dg; 17438c2ecf20Sopenharmony_ci size_t payload_len; 17448c2ecf20Sopenharmony_ci struct sk_buff *skb; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci noblock = flags & MSG_DONTWAIT; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (flags & MSG_OOB || flags & MSG_ERRQUEUE) 17498c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* Retrieve the head sk_buff from the socket's receive queue. */ 17528c2ecf20Sopenharmony_ci err = 0; 17538c2ecf20Sopenharmony_ci skb = skb_recv_datagram(&vsk->sk, flags, noblock, &err); 17548c2ecf20Sopenharmony_ci if (!skb) 17558c2ecf20Sopenharmony_ci return err; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci dg = (struct vmci_datagram *)skb->data; 17588c2ecf20Sopenharmony_ci if (!dg) 17598c2ecf20Sopenharmony_ci /* err is 0, meaning we read zero bytes. */ 17608c2ecf20Sopenharmony_ci goto out; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci payload_len = dg->payload_size; 17638c2ecf20Sopenharmony_ci /* Ensure the sk_buff matches the payload size claimed in the packet. */ 17648c2ecf20Sopenharmony_ci if (payload_len != skb->len - sizeof(*dg)) { 17658c2ecf20Sopenharmony_ci err = -EINVAL; 17668c2ecf20Sopenharmony_ci goto out; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci if (payload_len > len) { 17708c2ecf20Sopenharmony_ci payload_len = len; 17718c2ecf20Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci /* Place the datagram payload in the user's iovec. */ 17758c2ecf20Sopenharmony_ci err = skb_copy_datagram_msg(skb, sizeof(*dg), msg, payload_len); 17768c2ecf20Sopenharmony_ci if (err) 17778c2ecf20Sopenharmony_ci goto out; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci if (msg->msg_name) { 17808c2ecf20Sopenharmony_ci /* Provide the address of the sender. */ 17818c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_vm *, vm_addr, msg->msg_name); 17828c2ecf20Sopenharmony_ci vsock_addr_init(vm_addr, dg->src.context, dg->src.resource); 17838c2ecf20Sopenharmony_ci msg->msg_namelen = sizeof(*vm_addr); 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci err = payload_len; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ciout: 17888c2ecf20Sopenharmony_ci skb_free_datagram(&vsk->sk, skb); 17898c2ecf20Sopenharmony_ci return err; 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_cistatic bool vmci_transport_dgram_allow(u32 cid, u32 port) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci if (cid == VMADDR_CID_HYPERVISOR) { 17958c2ecf20Sopenharmony_ci /* Registrations of PBRPC Servers do not modify VMX/Hypervisor 17968c2ecf20Sopenharmony_ci * state and are allowed. 17978c2ecf20Sopenharmony_ci */ 17988c2ecf20Sopenharmony_ci return port == VMCI_UNITY_PBRPC_REGISTER; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci return true; 18028c2ecf20Sopenharmony_ci} 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_cistatic int vmci_transport_connect(struct vsock_sock *vsk) 18058c2ecf20Sopenharmony_ci{ 18068c2ecf20Sopenharmony_ci int err; 18078c2ecf20Sopenharmony_ci bool old_pkt_proto = false; 18088c2ecf20Sopenharmony_ci struct sock *sk = &vsk->sk; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci if (vmci_transport_old_proto_override(&old_pkt_proto) && 18118c2ecf20Sopenharmony_ci old_pkt_proto) { 18128c2ecf20Sopenharmony_ci err = vmci_transport_send_conn_request(sk, vsk->buffer_size); 18138c2ecf20Sopenharmony_ci if (err < 0) { 18148c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 18158c2ecf20Sopenharmony_ci return err; 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci } else { 18188c2ecf20Sopenharmony_ci int supported_proto_versions = 18198c2ecf20Sopenharmony_ci vmci_transport_new_proto_supported_versions(); 18208c2ecf20Sopenharmony_ci err = vmci_transport_send_conn_request2(sk, vsk->buffer_size, 18218c2ecf20Sopenharmony_ci supported_proto_versions); 18228c2ecf20Sopenharmony_ci if (err < 0) { 18238c2ecf20Sopenharmony_ci sk->sk_state = TCP_CLOSE; 18248c2ecf20Sopenharmony_ci return err; 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci vsk->sent_request = true; 18288c2ecf20Sopenharmony_ci } 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci return err; 18318c2ecf20Sopenharmony_ci} 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic ssize_t vmci_transport_stream_dequeue( 18348c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 18358c2ecf20Sopenharmony_ci struct msghdr *msg, 18368c2ecf20Sopenharmony_ci size_t len, 18378c2ecf20Sopenharmony_ci int flags) 18388c2ecf20Sopenharmony_ci{ 18398c2ecf20Sopenharmony_ci if (flags & MSG_PEEK) 18408c2ecf20Sopenharmony_ci return vmci_qpair_peekv(vmci_trans(vsk)->qpair, msg, len, 0); 18418c2ecf20Sopenharmony_ci else 18428c2ecf20Sopenharmony_ci return vmci_qpair_dequev(vmci_trans(vsk)->qpair, msg, len, 0); 18438c2ecf20Sopenharmony_ci} 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_cistatic ssize_t vmci_transport_stream_enqueue( 18468c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 18478c2ecf20Sopenharmony_ci struct msghdr *msg, 18488c2ecf20Sopenharmony_ci size_t len) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci return vmci_qpair_enquev(vmci_trans(vsk)->qpair, msg, len, 0); 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic s64 vmci_transport_stream_has_data(struct vsock_sock *vsk) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci return vmci_qpair_consume_buf_ready(vmci_trans(vsk)->qpair); 18568c2ecf20Sopenharmony_ci} 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_cistatic s64 vmci_transport_stream_has_space(struct vsock_sock *vsk) 18598c2ecf20Sopenharmony_ci{ 18608c2ecf20Sopenharmony_ci return vmci_qpair_produce_free_space(vmci_trans(vsk)->qpair); 18618c2ecf20Sopenharmony_ci} 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_cistatic u64 vmci_transport_stream_rcvhiwat(struct vsock_sock *vsk) 18648c2ecf20Sopenharmony_ci{ 18658c2ecf20Sopenharmony_ci return vmci_trans(vsk)->consume_size; 18668c2ecf20Sopenharmony_ci} 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_cistatic bool vmci_transport_stream_is_active(struct vsock_sock *vsk) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci return !vmci_handle_is_invalid(vmci_trans(vsk)->qp_handle); 18718c2ecf20Sopenharmony_ci} 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_cistatic int vmci_transport_notify_poll_in( 18748c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 18758c2ecf20Sopenharmony_ci size_t target, 18768c2ecf20Sopenharmony_ci bool *data_ready_now) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->poll_in( 18798c2ecf20Sopenharmony_ci &vsk->sk, target, data_ready_now); 18808c2ecf20Sopenharmony_ci} 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_cistatic int vmci_transport_notify_poll_out( 18838c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 18848c2ecf20Sopenharmony_ci size_t target, 18858c2ecf20Sopenharmony_ci bool *space_available_now) 18868c2ecf20Sopenharmony_ci{ 18878c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->poll_out( 18888c2ecf20Sopenharmony_ci &vsk->sk, target, space_available_now); 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_cistatic int vmci_transport_notify_recv_init( 18928c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 18938c2ecf20Sopenharmony_ci size_t target, 18948c2ecf20Sopenharmony_ci struct vsock_transport_recv_notify_data *data) 18958c2ecf20Sopenharmony_ci{ 18968c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->recv_init( 18978c2ecf20Sopenharmony_ci &vsk->sk, target, 18988c2ecf20Sopenharmony_ci (struct vmci_transport_recv_notify_data *)data); 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_cistatic int vmci_transport_notify_recv_pre_block( 19028c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 19038c2ecf20Sopenharmony_ci size_t target, 19048c2ecf20Sopenharmony_ci struct vsock_transport_recv_notify_data *data) 19058c2ecf20Sopenharmony_ci{ 19068c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->recv_pre_block( 19078c2ecf20Sopenharmony_ci &vsk->sk, target, 19088c2ecf20Sopenharmony_ci (struct vmci_transport_recv_notify_data *)data); 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_cistatic int vmci_transport_notify_recv_pre_dequeue( 19128c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 19138c2ecf20Sopenharmony_ci size_t target, 19148c2ecf20Sopenharmony_ci struct vsock_transport_recv_notify_data *data) 19158c2ecf20Sopenharmony_ci{ 19168c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->recv_pre_dequeue( 19178c2ecf20Sopenharmony_ci &vsk->sk, target, 19188c2ecf20Sopenharmony_ci (struct vmci_transport_recv_notify_data *)data); 19198c2ecf20Sopenharmony_ci} 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_cistatic int vmci_transport_notify_recv_post_dequeue( 19228c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 19238c2ecf20Sopenharmony_ci size_t target, 19248c2ecf20Sopenharmony_ci ssize_t copied, 19258c2ecf20Sopenharmony_ci bool data_read, 19268c2ecf20Sopenharmony_ci struct vsock_transport_recv_notify_data *data) 19278c2ecf20Sopenharmony_ci{ 19288c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->recv_post_dequeue( 19298c2ecf20Sopenharmony_ci &vsk->sk, target, copied, data_read, 19308c2ecf20Sopenharmony_ci (struct vmci_transport_recv_notify_data *)data); 19318c2ecf20Sopenharmony_ci} 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_cistatic int vmci_transport_notify_send_init( 19348c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 19358c2ecf20Sopenharmony_ci struct vsock_transport_send_notify_data *data) 19368c2ecf20Sopenharmony_ci{ 19378c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->send_init( 19388c2ecf20Sopenharmony_ci &vsk->sk, 19398c2ecf20Sopenharmony_ci (struct vmci_transport_send_notify_data *)data); 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cistatic int vmci_transport_notify_send_pre_block( 19438c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 19448c2ecf20Sopenharmony_ci struct vsock_transport_send_notify_data *data) 19458c2ecf20Sopenharmony_ci{ 19468c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->send_pre_block( 19478c2ecf20Sopenharmony_ci &vsk->sk, 19488c2ecf20Sopenharmony_ci (struct vmci_transport_send_notify_data *)data); 19498c2ecf20Sopenharmony_ci} 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_cistatic int vmci_transport_notify_send_pre_enqueue( 19528c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 19538c2ecf20Sopenharmony_ci struct vsock_transport_send_notify_data *data) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->send_pre_enqueue( 19568c2ecf20Sopenharmony_ci &vsk->sk, 19578c2ecf20Sopenharmony_ci (struct vmci_transport_send_notify_data *)data); 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_cistatic int vmci_transport_notify_send_post_enqueue( 19618c2ecf20Sopenharmony_ci struct vsock_sock *vsk, 19628c2ecf20Sopenharmony_ci ssize_t written, 19638c2ecf20Sopenharmony_ci struct vsock_transport_send_notify_data *data) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci return vmci_trans(vsk)->notify_ops->send_post_enqueue( 19668c2ecf20Sopenharmony_ci &vsk->sk, written, 19678c2ecf20Sopenharmony_ci (struct vmci_transport_send_notify_data *)data); 19688c2ecf20Sopenharmony_ci} 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_cistatic bool vmci_transport_old_proto_override(bool *old_pkt_proto) 19718c2ecf20Sopenharmony_ci{ 19728c2ecf20Sopenharmony_ci if (PROTOCOL_OVERRIDE != -1) { 19738c2ecf20Sopenharmony_ci if (PROTOCOL_OVERRIDE == 0) 19748c2ecf20Sopenharmony_ci *old_pkt_proto = true; 19758c2ecf20Sopenharmony_ci else 19768c2ecf20Sopenharmony_ci *old_pkt_proto = false; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci pr_info("Proto override in use\n"); 19798c2ecf20Sopenharmony_ci return true; 19808c2ecf20Sopenharmony_ci } 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci return false; 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_cistatic bool vmci_transport_proto_to_notify_struct(struct sock *sk, 19868c2ecf20Sopenharmony_ci u16 *proto, 19878c2ecf20Sopenharmony_ci bool old_pkt_proto) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci struct vsock_sock *vsk = vsock_sk(sk); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (old_pkt_proto) { 19928c2ecf20Sopenharmony_ci if (*proto != VSOCK_PROTO_INVALID) { 19938c2ecf20Sopenharmony_ci pr_err("Can't set both an old and new protocol\n"); 19948c2ecf20Sopenharmony_ci return false; 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops = &vmci_transport_notify_pkt_ops; 19978c2ecf20Sopenharmony_ci goto exit; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci switch (*proto) { 20018c2ecf20Sopenharmony_ci case VSOCK_PROTO_PKT_ON_NOTIFY: 20028c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops = 20038c2ecf20Sopenharmony_ci &vmci_transport_notify_pkt_q_state_ops; 20048c2ecf20Sopenharmony_ci break; 20058c2ecf20Sopenharmony_ci default: 20068c2ecf20Sopenharmony_ci pr_err("Unknown notify protocol version\n"); 20078c2ecf20Sopenharmony_ci return false; 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ciexit: 20118c2ecf20Sopenharmony_ci vmci_trans(vsk)->notify_ops->socket_init(sk); 20128c2ecf20Sopenharmony_ci return true; 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_cistatic u16 vmci_transport_new_proto_supported_versions(void) 20168c2ecf20Sopenharmony_ci{ 20178c2ecf20Sopenharmony_ci if (PROTOCOL_OVERRIDE != -1) 20188c2ecf20Sopenharmony_ci return PROTOCOL_OVERRIDE; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci return VSOCK_PROTO_ALL_SUPPORTED; 20218c2ecf20Sopenharmony_ci} 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_cistatic u32 vmci_transport_get_local_cid(void) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci return vmci_get_context_id(); 20268c2ecf20Sopenharmony_ci} 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_cistatic struct vsock_transport vmci_transport = { 20298c2ecf20Sopenharmony_ci .module = THIS_MODULE, 20308c2ecf20Sopenharmony_ci .init = vmci_transport_socket_init, 20318c2ecf20Sopenharmony_ci .destruct = vmci_transport_destruct, 20328c2ecf20Sopenharmony_ci .release = vmci_transport_release, 20338c2ecf20Sopenharmony_ci .connect = vmci_transport_connect, 20348c2ecf20Sopenharmony_ci .dgram_bind = vmci_transport_dgram_bind, 20358c2ecf20Sopenharmony_ci .dgram_dequeue = vmci_transport_dgram_dequeue, 20368c2ecf20Sopenharmony_ci .dgram_enqueue = vmci_transport_dgram_enqueue, 20378c2ecf20Sopenharmony_ci .dgram_allow = vmci_transport_dgram_allow, 20388c2ecf20Sopenharmony_ci .stream_dequeue = vmci_transport_stream_dequeue, 20398c2ecf20Sopenharmony_ci .stream_enqueue = vmci_transport_stream_enqueue, 20408c2ecf20Sopenharmony_ci .stream_has_data = vmci_transport_stream_has_data, 20418c2ecf20Sopenharmony_ci .stream_has_space = vmci_transport_stream_has_space, 20428c2ecf20Sopenharmony_ci .stream_rcvhiwat = vmci_transport_stream_rcvhiwat, 20438c2ecf20Sopenharmony_ci .stream_is_active = vmci_transport_stream_is_active, 20448c2ecf20Sopenharmony_ci .stream_allow = vmci_transport_stream_allow, 20458c2ecf20Sopenharmony_ci .notify_poll_in = vmci_transport_notify_poll_in, 20468c2ecf20Sopenharmony_ci .notify_poll_out = vmci_transport_notify_poll_out, 20478c2ecf20Sopenharmony_ci .notify_recv_init = vmci_transport_notify_recv_init, 20488c2ecf20Sopenharmony_ci .notify_recv_pre_block = vmci_transport_notify_recv_pre_block, 20498c2ecf20Sopenharmony_ci .notify_recv_pre_dequeue = vmci_transport_notify_recv_pre_dequeue, 20508c2ecf20Sopenharmony_ci .notify_recv_post_dequeue = vmci_transport_notify_recv_post_dequeue, 20518c2ecf20Sopenharmony_ci .notify_send_init = vmci_transport_notify_send_init, 20528c2ecf20Sopenharmony_ci .notify_send_pre_block = vmci_transport_notify_send_pre_block, 20538c2ecf20Sopenharmony_ci .notify_send_pre_enqueue = vmci_transport_notify_send_pre_enqueue, 20548c2ecf20Sopenharmony_ci .notify_send_post_enqueue = vmci_transport_notify_send_post_enqueue, 20558c2ecf20Sopenharmony_ci .shutdown = vmci_transport_shutdown, 20568c2ecf20Sopenharmony_ci .get_local_cid = vmci_transport_get_local_cid, 20578c2ecf20Sopenharmony_ci}; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_cistatic bool vmci_check_transport(struct vsock_sock *vsk) 20608c2ecf20Sopenharmony_ci{ 20618c2ecf20Sopenharmony_ci return vsk->transport == &vmci_transport; 20628c2ecf20Sopenharmony_ci} 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_cistatic void vmci_vsock_transport_cb(bool is_host) 20658c2ecf20Sopenharmony_ci{ 20668c2ecf20Sopenharmony_ci int features; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci if (is_host) 20698c2ecf20Sopenharmony_ci features = VSOCK_TRANSPORT_F_H2G; 20708c2ecf20Sopenharmony_ci else 20718c2ecf20Sopenharmony_ci features = VSOCK_TRANSPORT_F_G2H; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci vsock_core_register(&vmci_transport, features); 20748c2ecf20Sopenharmony_ci} 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic int __init vmci_transport_init(void) 20778c2ecf20Sopenharmony_ci{ 20788c2ecf20Sopenharmony_ci int err; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci /* Create the datagram handle that we will use to send and receive all 20818c2ecf20Sopenharmony_ci * VSocket control messages for this context. 20828c2ecf20Sopenharmony_ci */ 20838c2ecf20Sopenharmony_ci err = vmci_transport_datagram_create_hnd(VMCI_TRANSPORT_PACKET_RID, 20848c2ecf20Sopenharmony_ci VMCI_FLAG_ANYCID_DG_HND, 20858c2ecf20Sopenharmony_ci vmci_transport_recv_stream_cb, 20868c2ecf20Sopenharmony_ci NULL, 20878c2ecf20Sopenharmony_ci &vmci_transport_stream_handle); 20888c2ecf20Sopenharmony_ci if (err < VMCI_SUCCESS) { 20898c2ecf20Sopenharmony_ci pr_err("Unable to create datagram handle. (%d)\n", err); 20908c2ecf20Sopenharmony_ci return vmci_transport_error_to_vsock_error(err); 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci err = vmci_event_subscribe(VMCI_EVENT_QP_RESUMED, 20938c2ecf20Sopenharmony_ci vmci_transport_qp_resumed_cb, 20948c2ecf20Sopenharmony_ci NULL, &vmci_transport_qp_resumed_sub_id); 20958c2ecf20Sopenharmony_ci if (err < VMCI_SUCCESS) { 20968c2ecf20Sopenharmony_ci pr_err("Unable to subscribe to resumed event. (%d)\n", err); 20978c2ecf20Sopenharmony_ci err = vmci_transport_error_to_vsock_error(err); 20988c2ecf20Sopenharmony_ci vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; 20998c2ecf20Sopenharmony_ci goto err_destroy_stream_handle; 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* Register only with dgram feature, other features (H2G, G2H) will be 21038c2ecf20Sopenharmony_ci * registered when the first host or guest becomes active. 21048c2ecf20Sopenharmony_ci */ 21058c2ecf20Sopenharmony_ci err = vsock_core_register(&vmci_transport, VSOCK_TRANSPORT_F_DGRAM); 21068c2ecf20Sopenharmony_ci if (err < 0) 21078c2ecf20Sopenharmony_ci goto err_unsubscribe; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci err = vmci_register_vsock_callback(vmci_vsock_transport_cb); 21108c2ecf20Sopenharmony_ci if (err < 0) 21118c2ecf20Sopenharmony_ci goto err_unregister; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci return 0; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_cierr_unregister: 21168c2ecf20Sopenharmony_ci vsock_core_unregister(&vmci_transport); 21178c2ecf20Sopenharmony_cierr_unsubscribe: 21188c2ecf20Sopenharmony_ci vmci_event_unsubscribe(vmci_transport_qp_resumed_sub_id); 21198c2ecf20Sopenharmony_cierr_destroy_stream_handle: 21208c2ecf20Sopenharmony_ci vmci_datagram_destroy_handle(vmci_transport_stream_handle); 21218c2ecf20Sopenharmony_ci return err; 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_cimodule_init(vmci_transport_init); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_cistatic void __exit vmci_transport_exit(void) 21268c2ecf20Sopenharmony_ci{ 21278c2ecf20Sopenharmony_ci cancel_work_sync(&vmci_transport_cleanup_work); 21288c2ecf20Sopenharmony_ci vmci_transport_free_resources(&vmci_transport_cleanup_list); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci if (!vmci_handle_is_invalid(vmci_transport_stream_handle)) { 21318c2ecf20Sopenharmony_ci if (vmci_datagram_destroy_handle( 21328c2ecf20Sopenharmony_ci vmci_transport_stream_handle) != VMCI_SUCCESS) 21338c2ecf20Sopenharmony_ci pr_err("Couldn't destroy datagram handle\n"); 21348c2ecf20Sopenharmony_ci vmci_transport_stream_handle = VMCI_INVALID_HANDLE; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (vmci_transport_qp_resumed_sub_id != VMCI_INVALID_ID) { 21388c2ecf20Sopenharmony_ci vmci_event_unsubscribe(vmci_transport_qp_resumed_sub_id); 21398c2ecf20Sopenharmony_ci vmci_transport_qp_resumed_sub_id = VMCI_INVALID_ID; 21408c2ecf20Sopenharmony_ci } 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci vmci_register_vsock_callback(NULL); 21438c2ecf20Sopenharmony_ci vsock_core_unregister(&vmci_transport); 21448c2ecf20Sopenharmony_ci} 21458c2ecf20Sopenharmony_cimodule_exit(vmci_transport_exit); 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ciMODULE_AUTHOR("VMware, Inc."); 21488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VMCI transport for Virtual Sockets"); 21498c2ecf20Sopenharmony_ciMODULE_VERSION("1.0.5.0-k"); 21508c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 21518c2ecf20Sopenharmony_ciMODULE_ALIAS("vmware_vsock"); 21528c2ecf20Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_VSOCK); 2153