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