The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/vmware/vmci/vmci_datagram.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2018 VMware, Inc.
    3  *
    4  * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
    5  */
    6 
    7 /* This file implements the VMCI Simple Datagram API on the host. */
    8 
    9 #include <sys/cdefs.h>
   10 __FBSDID("$FreeBSD$");
   11 
   12 #include <sys/types.h>
   13 #include <sys/systm.h>
   14 
   15 #include "vmci_datagram.h"
   16 #include "vmci_driver.h"
   17 #include "vmci_kernel_api.h"
   18 #include "vmci_kernel_defs.h"
   19 #include "vmci_resource.h"
   20 
   21 #define LGPFX "vmci_datagram: "
   22 
   23 /*
   24  * datagram_entry describes the datagram entity. It is used for datagram
   25  * entities created only on the host.
   26  */
   27 struct datagram_entry {
   28         struct vmci_resource    resource;
   29         uint32_t                flags;
   30         bool                    run_delayed;
   31         vmci_datagram_recv_cb   recv_cb;
   32         void                    *client_data;
   33         vmci_event              destroy_event;
   34         vmci_privilege_flags    priv_flags;
   35 };
   36 
   37 struct vmci_delayed_datagram_info {
   38         struct datagram_entry   *entry;
   39         struct vmci_datagram    msg;
   40 };
   41 
   42 static int      vmci_datagram_get_priv_flags_int(vmci_id contextID,
   43                     struct vmci_handle handle,
   44                     vmci_privilege_flags *priv_flags);
   45 static void     datagram_free_cb(void *resource);
   46 static int      datagram_release_cb(void *client_data);
   47 
   48 /*------------------------------ Helper functions ----------------------------*/
   49 
   50 /*
   51  *------------------------------------------------------------------------------
   52  *
   53  * datagram_free_cb --
   54  *
   55  *     Callback to free datagram structure when resource is no longer used,
   56  *     ie. the reference count reached 0.
   57  *
   58  * Result:
   59  *     None.
   60  *
   61  * Side effects:
   62  *     None.
   63  *
   64  *------------------------------------------------------------------------------
   65  */
   66 
   67 static void
   68 datagram_free_cb(void *client_data)
   69 {
   70         struct datagram_entry *entry = (struct datagram_entry *)client_data;
   71 
   72         ASSERT(entry);
   73 
   74         vmci_signal_event(&entry->destroy_event);
   75 
   76         /*
   77          * The entry is freed in vmci_datagram_destroy_hnd, who is waiting for
   78          * the above signal.
   79          */
   80 }
   81 
   82 /*
   83  *------------------------------------------------------------------------------
   84  *
   85  * datagram_release_cb --
   86  *
   87  *     Callback to release the resource reference. It is called by the
   88  *     vmci_wait_on_event function before it blocks.
   89  *
   90  * Result:
   91  *     None.
   92  *
   93  * Side effects:
   94  *     None.
   95  *
   96  *------------------------------------------------------------------------------
   97  */
   98 
   99 static int
  100 datagram_release_cb(void *client_data)
  101 {
  102         struct datagram_entry *entry;
  103 
  104         entry = (struct datagram_entry *)client_data;
  105 
  106         ASSERT(entry);
  107 
  108         vmci_resource_release(&entry->resource);
  109 
  110         return (0);
  111 }
  112 
  113 /*
  114  *------------------------------------------------------------------------------
  115  *
  116  * datagram_create_hnd --
  117  *
  118  *     Internal function to create a datagram entry given a handle.
  119  *
  120  * Results:
  121  *     VMCI_SUCCESS if created, negative errno value otherwise.
  122  *
  123  * Side effects:
  124  *     None.
  125  *
  126  *------------------------------------------------------------------------------
  127  */
  128 
  129 static int
  130 datagram_create_hnd(vmci_id resource_id, uint32_t flags,
  131     vmci_privilege_flags priv_flags, vmci_datagram_recv_cb recv_cb,
  132     void *client_data, struct vmci_handle *out_handle)
  133 {
  134         struct datagram_entry *entry;
  135         struct vmci_handle handle;
  136         vmci_id context_id;
  137         int result;
  138 
  139         ASSERT(recv_cb != NULL);
  140         ASSERT(out_handle != NULL);
  141         ASSERT(!(priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS));
  142 
  143         if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0)
  144                 return (VMCI_ERROR_INVALID_ARGS);
  145         else {
  146                 if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0)
  147                         context_id = VMCI_INVALID_ID;
  148                 else {
  149                         context_id = vmci_get_context_id();
  150                         if (context_id == VMCI_INVALID_ID)
  151                                 return (VMCI_ERROR_NO_RESOURCES);
  152                 }
  153 
  154                 if (resource_id == VMCI_INVALID_ID) {
  155                         resource_id = vmci_resource_get_id(context_id);
  156                         if (resource_id == VMCI_INVALID_ID)
  157                                 return (VMCI_ERROR_NO_HANDLE);
  158                 }
  159 
  160                 handle = VMCI_MAKE_HANDLE(context_id, resource_id);
  161         }
  162 
  163         entry = vmci_alloc_kernel_mem(sizeof(*entry), VMCI_MEMORY_NORMAL);
  164         if (entry == NULL) {
  165                 VMCI_LOG_WARNING(LGPFX"Failed allocating memory for datagram "
  166                     "entry.\n");
  167                 return (VMCI_ERROR_NO_MEM);
  168         }
  169 
  170         if (!vmci_can_schedule_delayed_work()) {
  171                 if (flags & VMCI_FLAG_DG_DELAYED_CB) {
  172                         vmci_free_kernel_mem(entry, sizeof(*entry));
  173                         return (VMCI_ERROR_INVALID_ARGS);
  174                 }
  175                 entry->run_delayed = false;
  176         } else
  177                 entry->run_delayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ?
  178                     true : false;
  179 
  180         entry->flags = flags;
  181         entry->recv_cb = recv_cb;
  182         entry->client_data = client_data;
  183         vmci_create_event(&entry->destroy_event);
  184         entry->priv_flags = priv_flags;
  185 
  186         /* Make datagram resource live. */
  187         result = vmci_resource_add(&entry->resource,
  188             VMCI_RESOURCE_TYPE_DATAGRAM, handle, datagram_free_cb, entry);
  189         if (result != VMCI_SUCCESS) {
  190                 VMCI_LOG_WARNING(LGPFX"Failed to add new resource "
  191                     "(handle=0x%x:0x%x).\n", handle.context, handle.resource);
  192                 vmci_destroy_event(&entry->destroy_event);
  193                 vmci_free_kernel_mem(entry, sizeof(*entry));
  194                 return (result);
  195         }
  196         *out_handle = handle;
  197 
  198         return (VMCI_SUCCESS);
  199 }
  200 
  201 /*------------------------------ Public API functions ------------------------*/
  202 
  203 /*
  204  *------------------------------------------------------------------------------
  205  *
  206  * vmci_datagram_create_handle --
  207  *
  208  *     Creates a host context datagram endpoint and returns a handle to it.
  209  *
  210  * Results:
  211  *     VMCI_SUCCESS if created, negative errno value otherwise.
  212  *
  213  * Side effects:
  214  *     None.
  215  *
  216  *------------------------------------------------------------------------------
  217  */
  218 
  219 int
  220 vmci_datagram_create_handle(vmci_id resource_id, uint32_t flags,
  221     vmci_datagram_recv_cb recv_cb, void *client_data,
  222     struct vmci_handle *out_handle)
  223 {
  224 
  225         if (out_handle == NULL)
  226                 return (VMCI_ERROR_INVALID_ARGS);
  227 
  228         if (recv_cb == NULL) {
  229                 VMCI_LOG_DEBUG(LGPFX"Client callback needed when creating "
  230                     "datagram.\n");
  231                 return (VMCI_ERROR_INVALID_ARGS);
  232         }
  233 
  234         return (datagram_create_hnd(resource_id, flags,
  235             VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
  236             recv_cb, client_data, out_handle));
  237 }
  238 
  239 /*
  240  *------------------------------------------------------------------------------
  241  *
  242  * vmci_datagram_create_handle_priv --
  243  *
  244  *     Creates a host context datagram endpoint and returns a handle to it.
  245  *
  246  * Results:
  247  *     VMCI_SUCCESS if created, negative errno value otherwise.
  248  *
  249  * Side effects:
  250  *     None.
  251  *
  252  *------------------------------------------------------------------------------
  253  */
  254 
  255 int
  256 vmci_datagram_create_handle_priv(vmci_id resource_id, uint32_t flags,
  257     vmci_privilege_flags priv_flags, vmci_datagram_recv_cb recv_cb,
  258     void *client_data, struct vmci_handle *out_handle)
  259 {
  260 
  261         if (out_handle == NULL)
  262                 return (VMCI_ERROR_INVALID_ARGS);
  263 
  264         if (recv_cb == NULL) {
  265                 VMCI_LOG_DEBUG(LGPFX"Client callback needed when creating "
  266                     "datagram.\n");
  267                 return (VMCI_ERROR_INVALID_ARGS);
  268         }
  269 
  270         if (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS)
  271                 return (VMCI_ERROR_INVALID_ARGS);
  272 
  273         return (datagram_create_hnd(resource_id, flags, priv_flags, recv_cb,
  274             client_data, out_handle));
  275 }
  276 
  277 /*
  278  *------------------------------------------------------------------------------
  279  *
  280  * vmci_datagram_destroy_handle --
  281  *
  282  *     Destroys a handle.
  283  *
  284  * Results:
  285  *     None.
  286  *
  287  * Side effects:
  288  *     None.
  289  *
  290  *------------------------------------------------------------------------------
  291  */
  292 
  293 int
  294 vmci_datagram_destroy_handle(struct vmci_handle handle)
  295 {
  296         struct datagram_entry *entry;
  297         struct vmci_resource *resource;
  298 
  299         resource = vmci_resource_get(handle,
  300             VMCI_RESOURCE_TYPE_DATAGRAM);
  301         if (resource == NULL) {
  302                 VMCI_LOG_DEBUG(LGPFX"Failed to destroy datagram "
  303                     "(handle=0x%x:0x%x).\n", handle.context, handle.resource);
  304                 return (VMCI_ERROR_NOT_FOUND);
  305         }
  306         entry = RESOURCE_CONTAINER(resource, struct datagram_entry, resource);
  307 
  308         vmci_resource_remove(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
  309 
  310         /*
  311          * We now wait on the destroyEvent and release the reference we got
  312          * above.
  313          */
  314         vmci_wait_on_event(&entry->destroy_event, datagram_release_cb, entry);
  315 
  316         /*
  317          * We know that we are now the only reference to the above entry so
  318          * can safely free it.
  319          */
  320         vmci_destroy_event(&entry->destroy_event);
  321         vmci_free_kernel_mem(entry, sizeof(*entry));
  322 
  323         return (VMCI_SUCCESS);
  324 }
  325 
  326 /*
  327  *------------------------------------------------------------------------------
  328  *
  329  *  vmci_datagram_get_priv_flags_int --
  330  *
  331  *      Internal utilility function with the same purpose as
  332  *      vmci_datagram_get_priv_flags that also takes a context_id.
  333  *
  334  *  Result:
  335  *      VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
  336  *
  337  *  Side effects:
  338  *      None.
  339  *
  340  *------------------------------------------------------------------------------
  341  */
  342 
  343 static int
  344 vmci_datagram_get_priv_flags_int(vmci_id context_id, struct vmci_handle handle,
  345     vmci_privilege_flags *priv_flags)
  346 {
  347 
  348         ASSERT(priv_flags);
  349         ASSERT(context_id != VMCI_INVALID_ID);
  350 
  351         if (context_id == VMCI_HOST_CONTEXT_ID) {
  352                 struct datagram_entry *src_entry;
  353                 struct vmci_resource *resource;
  354 
  355                 resource = vmci_resource_get(handle,
  356                     VMCI_RESOURCE_TYPE_DATAGRAM);
  357                 if (resource == NULL)
  358                         return (VMCI_ERROR_INVALID_ARGS);
  359                 src_entry = RESOURCE_CONTAINER(resource, struct datagram_entry,
  360                     resource);
  361                 *priv_flags = src_entry->priv_flags;
  362                 vmci_resource_release(resource);
  363         } else if (context_id == VMCI_HYPERVISOR_CONTEXT_ID)
  364                 *priv_flags = VMCI_MAX_PRIVILEGE_FLAGS;
  365         else
  366                 *priv_flags = VMCI_NO_PRIVILEGE_FLAGS;
  367 
  368         return (VMCI_SUCCESS);
  369 }
  370 
  371 /*
  372  *------------------------------------------------------------------------------
  373  *
  374  *  vmci_datagram_fet_priv_flags --
  375  *
  376  *      Utility function that retrieves the privilege flags associated with a
  377  *      given datagram handle. For hypervisor and guest endpoints, the
  378  *      privileges are determined by the context ID, but for host endpoints
  379  *      privileges are associated with the complete handle.
  380  *
  381  *  Result:
  382  *      VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
  383  *
  384  *  Side effects:
  385  *      None.
  386  *
  387  *------------------------------------------------------------------------------
  388  */
  389 
  390 int
  391 vmci_datagram_get_priv_flags(struct vmci_handle handle,
  392     vmci_privilege_flags *priv_flags)
  393 {
  394 
  395         if (priv_flags == NULL || handle.context == VMCI_INVALID_ID)
  396                 return (VMCI_ERROR_INVALID_ARGS);
  397 
  398         return (vmci_datagram_get_priv_flags_int(handle.context, handle,
  399             priv_flags));
  400 }
  401 
  402 /*
  403  *------------------------------------------------------------------------------
  404  *
  405  * vmci_datagram_delayed_dispatch_cb --
  406  *
  407  *     Calls the specified callback in a delayed context.
  408  *
  409  * Results:
  410  *     None.
  411  *
  412  * Side effects:
  413  *     None.
  414  *
  415  *------------------------------------------------------------------------------
  416  */
  417 
  418 static void
  419 vmci_datagram_delayed_dispatch_cb(void *data)
  420 {
  421         struct vmci_delayed_datagram_info *dg_info;
  422 
  423         dg_info = (struct vmci_delayed_datagram_info *)data;
  424 
  425         ASSERT(data);
  426 
  427         dg_info->entry->recv_cb(dg_info->entry->client_data, &dg_info->msg);
  428 
  429         vmci_resource_release(&dg_info->entry->resource);
  430 
  431         vmci_free_kernel_mem(dg_info, sizeof(*dg_info) +
  432             (size_t)dg_info->msg.payload_size);
  433 }
  434 
  435 /*
  436  *------------------------------------------------------------------------------
  437  *
  438  * vmci_datagram_dispatch_as_guest --
  439  *
  440  *     Dispatch datagram as a guest, down through the VMX and potentially to
  441  *     the host.
  442  *
  443  * Result:
  444  *     Number of bytes sent on success, appropriate error code otherwise.
  445  *
  446  * Side effects:
  447  *     None.
  448  *
  449  *------------------------------------------------------------------------------
  450  */
  451 
  452 static int
  453 vmci_datagram_dispatch_as_guest(struct vmci_datagram *dg)
  454 {
  455         struct vmci_resource *resource;
  456         int retval;
  457 
  458         resource = vmci_resource_get(dg->src, VMCI_RESOURCE_TYPE_DATAGRAM);
  459         if (NULL == resource)
  460                 return VMCI_ERROR_NO_HANDLE;
  461 
  462         retval = vmci_send_datagram(dg);
  463         vmci_resource_release(resource);
  464 
  465         return (retval);
  466 }
  467 
  468 /*
  469  *------------------------------------------------------------------------------
  470  *
  471  * vmci_datagram_dispatch --
  472  *
  473  *     Dispatch datagram. This will determine the routing for the datagram and
  474  *     dispatch it accordingly.
  475  *
  476  * Result:
  477  *     Number of bytes sent on success, appropriate error code otherwise.
  478  *
  479  * Side effects:
  480  *     None.
  481  *
  482  *------------------------------------------------------------------------------
  483  */
  484 
  485 int
  486 vmci_datagram_dispatch(vmci_id context_id, struct vmci_datagram *dg)
  487 {
  488 
  489         ASSERT(dg);
  490         ASSERT_ON_COMPILE(sizeof(struct vmci_datagram) == 24);
  491 
  492         if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
  493                 VMCI_LOG_DEBUG(LGPFX"Payload (size=%lu bytes) too big to send."
  494                     "\n", dg->payload_size);
  495                 return (VMCI_ERROR_INVALID_ARGS);
  496         }
  497 
  498         return (vmci_datagram_dispatch_as_guest(dg));
  499 }
  500 
  501 /*
  502  *------------------------------------------------------------------------------
  503  *
  504  * vmci_datagram_invoke_guest_handler --
  505  *
  506  *     Invoke the handler for the given datagram. This is intended to be called
  507  *     only when acting as a guest and receiving a datagram from the virtual
  508  *     device.
  509  *
  510  * Result:
  511  *     VMCI_SUCCESS on success, other error values on failure.
  512  *
  513  * Side effects:
  514  *     None.
  515  *
  516  *------------------------------------------------------------------------------
  517  */
  518 
  519 int
  520 vmci_datagram_invoke_guest_handler(struct vmci_datagram *dg)
  521 {
  522         struct datagram_entry *dst_entry;
  523         struct vmci_resource *resource;
  524         int retval;
  525 
  526         ASSERT(dg);
  527 
  528         if (dg->payload_size > VMCI_MAX_DG_PAYLOAD_SIZE) {
  529                 VMCI_LOG_DEBUG(LGPFX"Payload (size=%lu bytes) too large to "
  530                     "deliver.\n", dg->payload_size);
  531                 return (VMCI_ERROR_PAYLOAD_TOO_LARGE);
  532         }
  533 
  534         resource = vmci_resource_get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
  535         if (NULL == resource) {
  536                 VMCI_LOG_DEBUG(LGPFX"destination (handle=0x%x:0x%x) doesn't "
  537                     "exist.\n", dg->dst.context, dg->dst.resource);
  538                 return (VMCI_ERROR_NO_HANDLE);
  539         }
  540 
  541         dst_entry = RESOURCE_CONTAINER(resource, struct datagram_entry,
  542             resource);
  543         if (dst_entry->run_delayed) {
  544                 struct vmci_delayed_datagram_info *dg_info;
  545 
  546                 dg_info = vmci_alloc_kernel_mem(sizeof(*dg_info) +
  547                     (size_t)dg->payload_size, VMCI_MEMORY_ATOMIC);
  548                 if (NULL == dg_info) {
  549                         vmci_resource_release(resource);
  550                         retval = VMCI_ERROR_NO_MEM;
  551                         goto exit;
  552                 }
  553 
  554                 dg_info->entry = dst_entry;
  555                 memcpy(&dg_info->msg, dg, VMCI_DG_SIZE(dg));
  556 
  557                 retval = vmci_schedule_delayed_work(
  558                     vmci_datagram_delayed_dispatch_cb, dg_info);
  559                 if (retval < VMCI_SUCCESS) {
  560                         VMCI_LOG_WARNING(LGPFX"Failed to schedule delayed "
  561                             "work for datagram (result=%d).\n", retval);
  562                         vmci_free_kernel_mem(dg_info, sizeof(*dg_info) +
  563                             (size_t)dg->payload_size);
  564                         vmci_resource_release(resource);
  565                         dg_info = NULL;
  566                         goto exit;
  567                 }
  568         } else {
  569                 dst_entry->recv_cb(dst_entry->client_data, dg);
  570                 vmci_resource_release(resource);
  571                 retval = VMCI_SUCCESS;
  572         }
  573 
  574 exit:
  575         return (retval);
  576 }
  577 
  578 /*
  579  *------------------------------------------------------------------------------
  580  *
  581  * vmci_datagram_send --
  582  *
  583  *     Sends the payload to the destination datagram handle.
  584  *
  585  * Results:
  586  *     Returns number of bytes sent if success, or error code if failure.
  587  *
  588  * Side effects:
  589  *     None.
  590  *
  591  *------------------------------------------------------------------------------
  592  */
  593 
  594 int
  595 vmci_datagram_send(struct vmci_datagram *msg)
  596 {
  597 
  598         if (msg == NULL)
  599                 return (VMCI_ERROR_INVALID_ARGS);
  600 
  601         return (vmci_datagram_dispatch(VMCI_INVALID_ID, msg));
  602 }
  603 
  604 /*
  605  *------------------------------------------------------------------------------
  606  *
  607  * vmci_datagram_sync --
  608  *
  609  *     Use this as a synchronization point when setting globals, for example,
  610  *     during device shutdown.
  611  *
  612  * Results:
  613  *     None.
  614  *
  615  * Side effects:
  616  *     None.
  617  *
  618  *------------------------------------------------------------------------------
  619  */
  620 
  621 void
  622 vmci_datagram_sync(void)
  623 {
  624 
  625         vmci_resource_sync();
  626 }
  627 
  628 /*
  629  *------------------------------------------------------------------------------
  630  *
  631  * vmci_datagram_check_host_capabilities --
  632  *
  633  *     Verify that the host supports the resources we need. None are required
  634  *     for datagrams since they are implicitly supported.
  635  *
  636  * Results:
  637  *     true.
  638  *
  639  * Side effects:
  640  *     None.
  641  *
  642  *------------------------------------------------------------------------------
  643  */
  644 
  645 bool
  646 vmci_datagram_check_host_capabilities(void)
  647 {
  648 
  649         return (true);
  650 }

Cache object: 479d7008de9e2c03a286c9282bf95934


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.