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