linux/drivers/misc/vmw_vmci/vmci_route.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * VMware VMCI Driver
   4 *
   5 * Copyright (C) 2012 VMware, Inc. All rights reserved.
   6 */
   7
   8#include <linux/vmw_vmci_defs.h>
   9#include <linux/vmw_vmci_api.h>
  10
  11#include "vmci_context.h"
  12#include "vmci_driver.h"
  13#include "vmci_route.h"
  14
  15/*
  16 * Make a routing decision for the given source and destination handles.
  17 * This will try to determine the route using the handles and the available
  18 * devices.  Will set the source context if it is invalid.
  19 */
  20int vmci_route(struct vmci_handle *src,
  21               const struct vmci_handle *dst,
  22               bool from_guest,
  23               enum vmci_route *route)
  24{
  25        bool has_host_device = vmci_host_code_active();
  26        bool has_guest_device = vmci_guest_code_active();
  27
  28        *route = VMCI_ROUTE_NONE;
  29
  30        /*
  31         * "from_guest" is only ever set to true by
  32         * IOCTL_VMCI_DATAGRAM_SEND (or by the vmkernel equivalent),
  33         * which comes from the VMX, so we know it is coming from a
  34         * guest.
  35         *
  36         * To avoid inconsistencies, test these once.  We will test
  37         * them again when we do the actual send to ensure that we do
  38         * not touch a non-existent device.
  39         */
  40
  41        /* Must have a valid destination context. */
  42        if (VMCI_INVALID_ID == dst->context)
  43                return VMCI_ERROR_INVALID_ARGS;
  44
  45        /* Anywhere to hypervisor. */
  46        if (VMCI_HYPERVISOR_CONTEXT_ID == dst->context) {
  47
  48                /*
  49                 * If this message already came from a guest then we
  50                 * cannot send it to the hypervisor.  It must come
  51                 * from a local client.
  52                 */
  53                if (from_guest)
  54                        return VMCI_ERROR_DST_UNREACHABLE;
  55
  56                /*
  57                 * We must be acting as a guest in order to send to
  58                 * the hypervisor.
  59                 */
  60                if (!has_guest_device)
  61                        return VMCI_ERROR_DEVICE_NOT_FOUND;
  62
  63                /* And we cannot send if the source is the host context. */
  64                if (VMCI_HOST_CONTEXT_ID == src->context)
  65                        return VMCI_ERROR_INVALID_ARGS;
  66
  67                /*
  68                 * If the client passed the ANON source handle then
  69                 * respect it (both context and resource are invalid).
  70                 * However, if they passed only an invalid context,
  71                 * then they probably mean ANY, in which case we
  72                 * should set the real context here before passing it
  73                 * down.
  74                 */
  75                if (VMCI_INVALID_ID == src->context &&
  76                    VMCI_INVALID_ID != src->resource)
  77                        src->context = vmci_get_context_id();
  78
  79                /* Send from local client down to the hypervisor. */
  80                *route = VMCI_ROUTE_AS_GUEST;
  81                return VMCI_SUCCESS;
  82        }
  83
  84        /* Anywhere to local client on host. */
  85        if (VMCI_HOST_CONTEXT_ID == dst->context) {
  86                /*
  87                 * If it is not from a guest but we are acting as a
  88                 * guest, then we need to send it down to the host.
  89                 * Note that if we are also acting as a host then this
  90                 * will prevent us from sending from local client to
  91                 * local client, but we accept that restriction as a
  92                 * way to remove any ambiguity from the host context.
  93                 */
  94                if (src->context == VMCI_HYPERVISOR_CONTEXT_ID) {
  95                        /*
  96                         * If the hypervisor is the source, this is
  97                         * host local communication. The hypervisor
  98                         * may send vmci event datagrams to the host
  99                         * itself, but it will never send datagrams to
 100                         * an "outer host" through the guest device.
 101                         */
 102
 103                        if (has_host_device) {
 104                                *route = VMCI_ROUTE_AS_HOST;
 105                                return VMCI_SUCCESS;
 106                        } else {
 107                                return VMCI_ERROR_DEVICE_NOT_FOUND;
 108                        }
 109                }
 110
 111                if (!from_guest && has_guest_device) {
 112                        /* If no source context then use the current. */
 113                        if (VMCI_INVALID_ID == src->context)
 114                                src->context = vmci_get_context_id();
 115
 116                        /* Send it from local client down to the host. */
 117                        *route = VMCI_ROUTE_AS_GUEST;
 118                        return VMCI_SUCCESS;
 119                }
 120
 121                /*
 122                 * Otherwise we already received it from a guest and
 123                 * it is destined for a local client on this host, or
 124                 * it is from another local client on this host.  We
 125                 * must be acting as a host to service it.
 126                 */
 127                if (!has_host_device)
 128                        return VMCI_ERROR_DEVICE_NOT_FOUND;
 129
 130                if (VMCI_INVALID_ID == src->context) {
 131                        /*
 132                         * If it came from a guest then it must have a
 133                         * valid context.  Otherwise we can use the
 134                         * host context.
 135                         */
 136                        if (from_guest)
 137                                return VMCI_ERROR_INVALID_ARGS;
 138
 139                        src->context = VMCI_HOST_CONTEXT_ID;
 140                }
 141
 142                /* Route to local client. */
 143                *route = VMCI_ROUTE_AS_HOST;
 144                return VMCI_SUCCESS;
 145        }
 146
 147        /*
 148         * If we are acting as a host then this might be destined for
 149         * a guest.
 150         */
 151        if (has_host_device) {
 152                /* It will have a context if it is meant for a guest. */
 153                if (vmci_ctx_exists(dst->context)) {
 154                        if (VMCI_INVALID_ID == src->context) {
 155                                /*
 156                                 * If it came from a guest then it
 157                                 * must have a valid context.
 158                                 * Otherwise we can use the host
 159                                 * context.
 160                                 */
 161
 162                                if (from_guest)
 163                                        return VMCI_ERROR_INVALID_ARGS;
 164
 165                                src->context = VMCI_HOST_CONTEXT_ID;
 166                        } else if (VMCI_CONTEXT_IS_VM(src->context) &&
 167                                   src->context != dst->context) {
 168                                /*
 169                                 * VM to VM communication is not
 170                                 * allowed. Since we catch all
 171                                 * communication destined for the host
 172                                 * above, this must be destined for a
 173                                 * VM since there is a valid context.
 174                                 */
 175
 176                                return VMCI_ERROR_DST_UNREACHABLE;
 177                        }
 178
 179                        /* Pass it up to the guest. */
 180                        *route = VMCI_ROUTE_AS_HOST;
 181                        return VMCI_SUCCESS;
 182                } else if (!has_guest_device) {
 183                        /*
 184                         * The host is attempting to reach a CID
 185                         * without an active context, and we can't
 186                         * send it down, since we have no guest
 187                         * device.
 188                         */
 189
 190                        return VMCI_ERROR_DST_UNREACHABLE;
 191                }
 192        }
 193
 194        /*
 195         * We must be a guest trying to send to another guest, which means
 196         * we need to send it down to the host. We do not filter out VM to
 197         * VM communication here, since we want to be able to use the guest
 198         * driver on older versions that do support VM to VM communication.
 199         */
 200        if (!has_guest_device) {
 201                /*
 202                 * Ending up here means we have neither guest nor host
 203                 * device.
 204                 */
 205                return VMCI_ERROR_DEVICE_NOT_FOUND;
 206        }
 207
 208        /* If no source context then use the current context. */
 209        if (VMCI_INVALID_ID == src->context)
 210                src->context = vmci_get_context_id();
 211
 212        /*
 213         * Send it from local client down to the host, which will
 214         * route it to the other guest for us.
 215         */
 216        *route = VMCI_ROUTE_AS_GUEST;
 217        return VMCI_SUCCESS;
 218}
 219