2 * Copyright (c) 2018 VMware, Inc.
4 * SPDX-License-Identifier: (BSD-2-Clause OR GPL-2.0)
7 /* This file implements the VMCI Simple Datagram API on the host. */
10 __FBSDID("$FreeBSD$");
12 #include <sys/types.h>
13 #include <sys/systm.h>
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"
21 #define LGPFX "vmci_datagram: "
24 * datagram_entry describes the datagram entity. It is used for datagram
25 * entities created only on the host.
27 struct datagram_entry {
28 struct vmci_resource resource;
31 vmci_datagram_recv_cb recv_cb;
33 vmci_event destroy_event;
34 vmci_privilege_flags priv_flags;
37 struct vmci_delayed_datagram_info {
38 struct datagram_entry *entry;
39 struct vmci_datagram msg;
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);
48 /*------------------------------ Helper functions ----------------------------*/
51 *------------------------------------------------------------------------------
55 * Callback to free datagram structure when resource is no longer used,
56 * ie. the reference count reached 0.
64 *------------------------------------------------------------------------------
68 datagram_free_cb(void *client_data)
70 struct datagram_entry *entry = (struct datagram_entry *)client_data;
74 vmci_signal_event(&entry->destroy_event);
77 * The entry is freed in vmci_datagram_destroy_hnd, who is waiting for
83 *------------------------------------------------------------------------------
85 * datagram_release_cb --
87 * Callback to release the resource reference. It is called by the
88 * vmci_wait_on_event function before it blocks.
96 *------------------------------------------------------------------------------
100 datagram_release_cb(void *client_data)
102 struct datagram_entry *entry;
104 entry = (struct datagram_entry *)client_data;
108 vmci_resource_release(&entry->resource);
114 *------------------------------------------------------------------------------
116 * datagram_create_hnd --
118 * Internal function to create a datagram entry given a handle.
121 * VMCI_SUCCESS if created, negative errno value otherwise.
126 *------------------------------------------------------------------------------
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)
134 struct datagram_entry *entry;
135 struct vmci_handle handle;
139 ASSERT(recv_cb != NULL);
140 ASSERT(out_handle != NULL);
141 ASSERT(!(priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS));
143 if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0)
144 return (VMCI_ERROR_INVALID_ARGS);
146 if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0)
147 context_id = VMCI_INVALID_ID;
149 context_id = vmci_get_context_id();
150 if (context_id == VMCI_INVALID_ID)
151 return (VMCI_ERROR_NO_RESOURCES);
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);
160 handle = VMCI_MAKE_HANDLE(context_id, resource_id);
163 entry = vmci_alloc_kernel_mem(sizeof(*entry), VMCI_MEMORY_NORMAL);
165 VMCI_LOG_WARNING(LGPFX"Failed allocating memory for datagram "
167 return (VMCI_ERROR_NO_MEM);
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);
175 entry->run_delayed = false;
177 entry->run_delayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ?
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;
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));
196 *out_handle = handle;
198 return (VMCI_SUCCESS);
201 /*------------------------------ Public API functions ------------------------*/
204 *------------------------------------------------------------------------------
206 * vmci_datagram_create_handle --
208 * Creates a host context datagram endpoint and returns a handle to it.
211 * VMCI_SUCCESS if created, negative errno value otherwise.
216 *------------------------------------------------------------------------------
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)
225 if (out_handle == NULL)
226 return (VMCI_ERROR_INVALID_ARGS);
228 if (recv_cb == NULL) {
229 VMCI_LOG_DEBUG(LGPFX"Client callback needed when creating "
231 return (VMCI_ERROR_INVALID_ARGS);
234 return (datagram_create_hnd(resource_id, flags,
235 VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
236 recv_cb, client_data, out_handle));
240 *------------------------------------------------------------------------------
242 * vmci_datagram_create_handle_priv --
244 * Creates a host context datagram endpoint and returns a handle to it.
247 * VMCI_SUCCESS if created, negative errno value otherwise.
252 *------------------------------------------------------------------------------
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)
261 if (out_handle == NULL)
262 return (VMCI_ERROR_INVALID_ARGS);
264 if (recv_cb == NULL) {
265 VMCI_LOG_DEBUG(LGPFX"Client callback needed when creating "
267 return (VMCI_ERROR_INVALID_ARGS);
270 if (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS)
271 return (VMCI_ERROR_INVALID_ARGS);
273 return (datagram_create_hnd(resource_id, flags, priv_flags, recv_cb,
274 client_data, out_handle));
278 *------------------------------------------------------------------------------
280 * vmci_datagram_destroy_handle --
290 *------------------------------------------------------------------------------
294 vmci_datagram_destroy_handle(struct vmci_handle handle)
296 struct datagram_entry *entry;
297 struct vmci_resource *resource;
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);
306 entry = RESOURCE_CONTAINER(resource, struct datagram_entry, resource);
308 vmci_resource_remove(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
311 * We now wait on the destroyEvent and release the reference we got
314 vmci_wait_on_event(&entry->destroy_event, datagram_release_cb, entry);
317 * We know that we are now the only reference to the above entry so
318 * can safely free it.
320 vmci_destroy_event(&entry->destroy_event);
321 vmci_free_kernel_mem(entry, sizeof(*entry));
323 return (VMCI_SUCCESS);
327 *------------------------------------------------------------------------------
329 * vmci_datagram_get_priv_flags_int --
331 * Internal utilility function with the same purpose as
332 * vmci_datagram_get_priv_flags that also takes a context_id.
335 * VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
340 *------------------------------------------------------------------------------
344 vmci_datagram_get_priv_flags_int(vmci_id context_id, struct vmci_handle handle,
345 vmci_privilege_flags *priv_flags)
349 ASSERT(context_id != VMCI_INVALID_ID);
351 if (context_id == VMCI_HOST_CONTEXT_ID) {
352 struct datagram_entry *src_entry;
353 struct vmci_resource *resource;
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,
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;
366 *priv_flags = VMCI_NO_PRIVILEGE_FLAGS;
368 return (VMCI_SUCCESS);
372 *------------------------------------------------------------------------------
374 * vmci_datagram_fet_priv_flags --
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.
382 * VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
387 *------------------------------------------------------------------------------
391 vmci_datagram_get_priv_flags(struct vmci_handle handle,
392 vmci_privilege_flags *priv_flags)
395 if (priv_flags == NULL || handle.context == VMCI_INVALID_ID)
396 return (VMCI_ERROR_INVALID_ARGS);
398 return (vmci_datagram_get_priv_flags_int(handle.context, handle,
403 *------------------------------------------------------------------------------
405 * vmci_datagram_delayed_dispatch_cb --
407 * Calls the specified callback in a delayed context.
415 *------------------------------------------------------------------------------
419 vmci_datagram_delayed_dispatch_cb(void *data)
421 struct vmci_delayed_datagram_info *dg_info;
423 dg_info = (struct vmci_delayed_datagram_info *)data;
427 dg_info->entry->recv_cb(dg_info->entry->client_data, &dg_info->msg);
429 vmci_resource_release(&dg_info->entry->resource);
431 vmci_free_kernel_mem(dg_info, sizeof(*dg_info) +
432 (size_t)dg_info->msg.payload_size);
436 *------------------------------------------------------------------------------
438 * vmci_datagram_dispatch_as_guest --
440 * Dispatch datagram as a guest, down through the VMX and potentially to
444 * Number of bytes sent on success, appropriate error code otherwise.
449 *------------------------------------------------------------------------------
453 vmci_datagram_dispatch_as_guest(struct vmci_datagram *dg)
455 struct vmci_resource *resource;
458 resource = vmci_resource_get(dg->src, VMCI_RESOURCE_TYPE_DATAGRAM);
459 if (NULL == resource)
460 return VMCI_ERROR_NO_HANDLE;
462 retval = vmci_send_datagram(dg);
463 vmci_resource_release(resource);
469 *------------------------------------------------------------------------------
471 * vmci_datagram_dispatch --
473 * Dispatch datagram. This will determine the routing for the datagram and
474 * dispatch it accordingly.
477 * Number of bytes sent on success, appropriate error code otherwise.
482 *------------------------------------------------------------------------------
486 vmci_datagram_dispatch(vmci_id context_id, struct vmci_datagram *dg)
490 ASSERT_ON_COMPILE(sizeof(struct vmci_datagram) == 24);
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);
498 return (vmci_datagram_dispatch_as_guest(dg));
502 *------------------------------------------------------------------------------
504 * vmci_datagram_invoke_guest_handler --
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
511 * VMCI_SUCCESS on success, other error values on failure.
516 *------------------------------------------------------------------------------
520 vmci_datagram_invoke_guest_handler(struct vmci_datagram *dg)
522 struct datagram_entry *dst_entry;
523 struct vmci_resource *resource;
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);
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);
541 dst_entry = RESOURCE_CONTAINER(resource, struct datagram_entry,
543 if (dst_entry->run_delayed) {
544 struct vmci_delayed_datagram_info *dg_info;
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;
554 dg_info->entry = dst_entry;
555 memcpy(&dg_info->msg, dg, VMCI_DG_SIZE(dg));
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);
569 dst_entry->recv_cb(dst_entry->client_data, dg);
570 vmci_resource_release(resource);
571 retval = VMCI_SUCCESS;
579 *------------------------------------------------------------------------------
581 * vmci_datagram_send --
583 * Sends the payload to the destination datagram handle.
586 * Returns number of bytes sent if success, or error code if failure.
591 *------------------------------------------------------------------------------
595 vmci_datagram_send(struct vmci_datagram *msg)
599 return (VMCI_ERROR_INVALID_ARGS);
601 return (vmci_datagram_dispatch(VMCI_INVALID_ID, msg));
605 *------------------------------------------------------------------------------
607 * vmci_datagram_sync --
609 * Use this as a synchronization point when setting globals, for example,
610 * during device shutdown.
618 *------------------------------------------------------------------------------
622 vmci_datagram_sync(void)
625 vmci_resource_sync();
629 *------------------------------------------------------------------------------
631 * vmci_datagram_check_host_capabilities --
633 * Verify that the host supports the resources we need. None are required
634 * for datagrams since they are implicitly supported.
642 *------------------------------------------------------------------------------
646 vmci_datagram_check_host_capabilities(void)