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