Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * VMware VMCI Driver
0004  *
0005  * Copyright (C) 2012 VMware, Inc. All rights reserved.
0006  */
0007 
0008 #include <linux/vmw_vmci_defs.h>
0009 #include <linux/vmw_vmci_api.h>
0010 
0011 #include "vmci_context.h"
0012 #include "vmci_driver.h"
0013 #include "vmci_route.h"
0014 
0015 /*
0016  * Make a routing decision for the given source and destination handles.
0017  * This will try to determine the route using the handles and the available
0018  * devices.  Will set the source context if it is invalid.
0019  */
0020 int vmci_route(struct vmci_handle *src,
0021            const struct vmci_handle *dst,
0022            bool from_guest,
0023            enum vmci_route *route)
0024 {
0025     bool has_host_device = vmci_host_code_active();
0026     bool has_guest_device = vmci_guest_code_active();
0027 
0028     *route = VMCI_ROUTE_NONE;
0029 
0030     /*
0031      * "from_guest" is only ever set to true by
0032      * IOCTL_VMCI_DATAGRAM_SEND (or by the vmkernel equivalent),
0033      * which comes from the VMX, so we know it is coming from a
0034      * guest.
0035      *
0036      * To avoid inconsistencies, test these once.  We will test
0037      * them again when we do the actual send to ensure that we do
0038      * not touch a non-existent device.
0039      */
0040 
0041     /* Must have a valid destination context. */
0042     if (VMCI_INVALID_ID == dst->context)
0043         return VMCI_ERROR_INVALID_ARGS;
0044 
0045     /* Anywhere to hypervisor. */
0046     if (VMCI_HYPERVISOR_CONTEXT_ID == dst->context) {
0047 
0048         /*
0049          * If this message already came from a guest then we
0050          * cannot send it to the hypervisor.  It must come
0051          * from a local client.
0052          */
0053         if (from_guest)
0054             return VMCI_ERROR_DST_UNREACHABLE;
0055 
0056         /*
0057          * We must be acting as a guest in order to send to
0058          * the hypervisor.
0059          */
0060         if (!has_guest_device)
0061             return VMCI_ERROR_DEVICE_NOT_FOUND;
0062 
0063         /* And we cannot send if the source is the host context. */
0064         if (VMCI_HOST_CONTEXT_ID == src->context)
0065             return VMCI_ERROR_INVALID_ARGS;
0066 
0067         /*
0068          * If the client passed the ANON source handle then
0069          * respect it (both context and resource are invalid).
0070          * However, if they passed only an invalid context,
0071          * then they probably mean ANY, in which case we
0072          * should set the real context here before passing it
0073          * down.
0074          */
0075         if (VMCI_INVALID_ID == src->context &&
0076             VMCI_INVALID_ID != src->resource)
0077             src->context = vmci_get_context_id();
0078 
0079         /* Send from local client down to the hypervisor. */
0080         *route = VMCI_ROUTE_AS_GUEST;
0081         return VMCI_SUCCESS;
0082     }
0083 
0084     /* Anywhere to local client on host. */
0085     if (VMCI_HOST_CONTEXT_ID == dst->context) {
0086         /*
0087          * If it is not from a guest but we are acting as a
0088          * guest, then we need to send it down to the host.
0089          * Note that if we are also acting as a host then this
0090          * will prevent us from sending from local client to
0091          * local client, but we accept that restriction as a
0092          * way to remove any ambiguity from the host context.
0093          */
0094         if (src->context == VMCI_HYPERVISOR_CONTEXT_ID) {
0095             /*
0096              * If the hypervisor is the source, this is
0097              * host local communication. The hypervisor
0098              * may send vmci event datagrams to the host
0099              * itself, but it will never send datagrams to
0100              * an "outer host" through the guest device.
0101              */
0102 
0103             if (has_host_device) {
0104                 *route = VMCI_ROUTE_AS_HOST;
0105                 return VMCI_SUCCESS;
0106             } else {
0107                 return VMCI_ERROR_DEVICE_NOT_FOUND;
0108             }
0109         }
0110 
0111         if (!from_guest && has_guest_device) {
0112             /* If no source context then use the current. */
0113             if (VMCI_INVALID_ID == src->context)
0114                 src->context = vmci_get_context_id();
0115 
0116             /* Send it from local client down to the host. */
0117             *route = VMCI_ROUTE_AS_GUEST;
0118             return VMCI_SUCCESS;
0119         }
0120 
0121         /*
0122          * Otherwise we already received it from a guest and
0123          * it is destined for a local client on this host, or
0124          * it is from another local client on this host.  We
0125          * must be acting as a host to service it.
0126          */
0127         if (!has_host_device)
0128             return VMCI_ERROR_DEVICE_NOT_FOUND;
0129 
0130         if (VMCI_INVALID_ID == src->context) {
0131             /*
0132              * If it came from a guest then it must have a
0133              * valid context.  Otherwise we can use the
0134              * host context.
0135              */
0136             if (from_guest)
0137                 return VMCI_ERROR_INVALID_ARGS;
0138 
0139             src->context = VMCI_HOST_CONTEXT_ID;
0140         }
0141 
0142         /* Route to local client. */
0143         *route = VMCI_ROUTE_AS_HOST;
0144         return VMCI_SUCCESS;
0145     }
0146 
0147     /*
0148      * If we are acting as a host then this might be destined for
0149      * a guest.
0150      */
0151     if (has_host_device) {
0152         /* It will have a context if it is meant for a guest. */
0153         if (vmci_ctx_exists(dst->context)) {
0154             if (VMCI_INVALID_ID == src->context) {
0155                 /*
0156                  * If it came from a guest then it
0157                  * must have a valid context.
0158                  * Otherwise we can use the host
0159                  * context.
0160                  */
0161 
0162                 if (from_guest)
0163                     return VMCI_ERROR_INVALID_ARGS;
0164 
0165                 src->context = VMCI_HOST_CONTEXT_ID;
0166             } else if (VMCI_CONTEXT_IS_VM(src->context) &&
0167                    src->context != dst->context) {
0168                 /*
0169                  * VM to VM communication is not
0170                  * allowed. Since we catch all
0171                  * communication destined for the host
0172                  * above, this must be destined for a
0173                  * VM since there is a valid context.
0174                  */
0175 
0176                 return VMCI_ERROR_DST_UNREACHABLE;
0177             }
0178 
0179             /* Pass it up to the guest. */
0180             *route = VMCI_ROUTE_AS_HOST;
0181             return VMCI_SUCCESS;
0182         } else if (!has_guest_device) {
0183             /*
0184              * The host is attempting to reach a CID
0185              * without an active context, and we can't
0186              * send it down, since we have no guest
0187              * device.
0188              */
0189 
0190             return VMCI_ERROR_DST_UNREACHABLE;
0191         }
0192     }
0193 
0194     /*
0195      * We must be a guest trying to send to another guest, which means
0196      * we need to send it down to the host. We do not filter out VM to
0197      * VM communication here, since we want to be able to use the guest
0198      * driver on older versions that do support VM to VM communication.
0199      */
0200     if (!has_guest_device) {
0201         /*
0202          * Ending up here means we have neither guest nor host
0203          * device.
0204          */
0205         return VMCI_ERROR_DEVICE_NOT_FOUND;
0206     }
0207 
0208     /* If no source context then use the current context. */
0209     if (VMCI_INVALID_ID == src->context)
0210         src->context = vmci_get_context_id();
0211 
0212     /*
0213      * Send it from local client down to the host, which will
0214      * route it to the other guest for us.
0215      */
0216     *route = VMCI_ROUTE_AS_GUEST;
0217     return VMCI_SUCCESS;
0218 }