1685a6bf8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a110b7ebSGeorge Zhang /*
3a110b7ebSGeorge Zhang  * VMware VMCI Driver
4a110b7ebSGeorge Zhang  *
5a110b7ebSGeorge Zhang  * Copyright (C) 2012 VMware, Inc. All rights reserved.
6a110b7ebSGeorge Zhang  */
7a110b7ebSGeorge Zhang 
8a110b7ebSGeorge Zhang #include <linux/vmw_vmci_defs.h>
9a110b7ebSGeorge Zhang #include <linux/vmw_vmci_api.h>
10a110b7ebSGeorge Zhang #include <linux/module.h>
11a110b7ebSGeorge Zhang #include <linux/sched.h>
12a110b7ebSGeorge Zhang #include <linux/slab.h>
13a110b7ebSGeorge Zhang #include <linux/bug.h>
14a110b7ebSGeorge Zhang 
15a110b7ebSGeorge Zhang #include "vmci_datagram.h"
16a110b7ebSGeorge Zhang #include "vmci_resource.h"
17a110b7ebSGeorge Zhang #include "vmci_context.h"
18a110b7ebSGeorge Zhang #include "vmci_driver.h"
19a110b7ebSGeorge Zhang #include "vmci_event.h"
20a110b7ebSGeorge Zhang #include "vmci_route.h"
21a110b7ebSGeorge Zhang 
22a110b7ebSGeorge Zhang /*
23a110b7ebSGeorge Zhang  * struct datagram_entry describes the datagram entity. It is used for datagram
24a110b7ebSGeorge Zhang  * entities created only on the host.
25a110b7ebSGeorge Zhang  */
26a110b7ebSGeorge Zhang struct datagram_entry {
27a110b7ebSGeorge Zhang 	struct vmci_resource resource;
28a110b7ebSGeorge Zhang 	u32 flags;
29a110b7ebSGeorge Zhang 	bool run_delayed;
30a110b7ebSGeorge Zhang 	vmci_datagram_recv_cb recv_cb;
31a110b7ebSGeorge Zhang 	void *client_data;
32a110b7ebSGeorge Zhang 	u32 priv_flags;
33a110b7ebSGeorge Zhang };
34a110b7ebSGeorge Zhang 
35a110b7ebSGeorge Zhang struct delayed_datagram_info {
36a110b7ebSGeorge Zhang 	struct datagram_entry *entry;
37a110b7ebSGeorge Zhang 	struct work_struct work;
38a110b7ebSGeorge Zhang 	bool in_dg_host_queue;
39347e0899SAndy King 	/* msg and msg_payload must be together. */
40347e0899SAndy King 	struct vmci_datagram msg;
41347e0899SAndy King 	u8 msg_payload[];
42a110b7ebSGeorge Zhang };
43a110b7ebSGeorge Zhang 
44a110b7ebSGeorge Zhang /* Number of in-flight host->host datagrams */
45a110b7ebSGeorge Zhang static atomic_t delayed_dg_host_queue_size = ATOMIC_INIT(0);
46a110b7ebSGeorge Zhang 
47a110b7ebSGeorge Zhang /*
48a110b7ebSGeorge Zhang  * Create a datagram entry given a handle pointer.
49a110b7ebSGeorge Zhang  */
dg_create_handle(u32 resource_id,u32 flags,u32 priv_flags,vmci_datagram_recv_cb recv_cb,void * client_data,struct vmci_handle * out_handle)50a110b7ebSGeorge Zhang static int dg_create_handle(u32 resource_id,
51a110b7ebSGeorge Zhang 			    u32 flags,
52a110b7ebSGeorge Zhang 			    u32 priv_flags,
53a110b7ebSGeorge Zhang 			    vmci_datagram_recv_cb recv_cb,
54a110b7ebSGeorge Zhang 			    void *client_data, struct vmci_handle *out_handle)
55a110b7ebSGeorge Zhang {
56a110b7ebSGeorge Zhang 	int result;
57a110b7ebSGeorge Zhang 	u32 context_id;
58a110b7ebSGeorge Zhang 	struct vmci_handle handle;
59a110b7ebSGeorge Zhang 	struct datagram_entry *entry;
60a110b7ebSGeorge Zhang 
61a110b7ebSGeorge Zhang 	if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0)
62a110b7ebSGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
63a110b7ebSGeorge Zhang 
64a110b7ebSGeorge Zhang 	if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) {
65a110b7ebSGeorge Zhang 		context_id = VMCI_INVALID_ID;
66a110b7ebSGeorge Zhang 	} else {
67a110b7ebSGeorge Zhang 		context_id = vmci_get_context_id();
68a110b7ebSGeorge Zhang 		if (context_id == VMCI_INVALID_ID)
69a110b7ebSGeorge Zhang 			return VMCI_ERROR_NO_RESOURCES;
70a110b7ebSGeorge Zhang 	}
71a110b7ebSGeorge Zhang 
72a110b7ebSGeorge Zhang 	handle = vmci_make_handle(context_id, resource_id);
73a110b7ebSGeorge Zhang 
74a110b7ebSGeorge Zhang 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
75a110b7ebSGeorge Zhang 	if (!entry) {
76a110b7ebSGeorge Zhang 		pr_warn("Failed allocating memory for datagram entry\n");
77a110b7ebSGeorge Zhang 		return VMCI_ERROR_NO_MEM;
78a110b7ebSGeorge Zhang 	}
79a110b7ebSGeorge Zhang 
80a110b7ebSGeorge Zhang 	entry->run_delayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ? true : false;
81a110b7ebSGeorge Zhang 	entry->flags = flags;
82a110b7ebSGeorge Zhang 	entry->recv_cb = recv_cb;
83a110b7ebSGeorge Zhang 	entry->client_data = client_data;
84a110b7ebSGeorge Zhang 	entry->priv_flags = priv_flags;
85a110b7ebSGeorge Zhang 
86a110b7ebSGeorge Zhang 	/* Make datagram resource live. */
87a110b7ebSGeorge Zhang 	result = vmci_resource_add(&entry->resource,
88a110b7ebSGeorge Zhang 				   VMCI_RESOURCE_TYPE_DATAGRAM,
89a110b7ebSGeorge Zhang 				   handle);
90a110b7ebSGeorge Zhang 	if (result != VMCI_SUCCESS) {
91a110b7ebSGeorge Zhang 		pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d\n",
92a110b7ebSGeorge Zhang 			handle.context, handle.resource, result);
93a110b7ebSGeorge Zhang 		kfree(entry);
94a110b7ebSGeorge Zhang 		return result;
95a110b7ebSGeorge Zhang 	}
96a110b7ebSGeorge Zhang 
97a110b7ebSGeorge Zhang 	*out_handle = vmci_resource_handle(&entry->resource);
98a110b7ebSGeorge Zhang 	return VMCI_SUCCESS;
99a110b7ebSGeorge Zhang }
100a110b7ebSGeorge Zhang 
101a110b7ebSGeorge Zhang /*
102a110b7ebSGeorge Zhang  * Internal utility function with the same purpose as
103a110b7ebSGeorge Zhang  * vmci_datagram_get_priv_flags that also takes a context_id.
104a110b7ebSGeorge Zhang  */
vmci_datagram_get_priv_flags(u32 context_id,struct vmci_handle handle,u32 * priv_flags)105a110b7ebSGeorge Zhang static int vmci_datagram_get_priv_flags(u32 context_id,
106a110b7ebSGeorge Zhang 					struct vmci_handle handle,
107a110b7ebSGeorge Zhang 					u32 *priv_flags)
108a110b7ebSGeorge Zhang {
109a110b7ebSGeorge Zhang 	if (context_id == VMCI_INVALID_ID)
110a110b7ebSGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
111a110b7ebSGeorge Zhang 
112a110b7ebSGeorge Zhang 	if (context_id == VMCI_HOST_CONTEXT_ID) {
113a110b7ebSGeorge Zhang 		struct datagram_entry *src_entry;
114a110b7ebSGeorge Zhang 		struct vmci_resource *resource;
115a110b7ebSGeorge Zhang 
116a110b7ebSGeorge Zhang 		resource = vmci_resource_by_handle(handle,
117a110b7ebSGeorge Zhang 						   VMCI_RESOURCE_TYPE_DATAGRAM);
118a110b7ebSGeorge Zhang 		if (!resource)
119a110b7ebSGeorge Zhang 			return VMCI_ERROR_INVALID_ARGS;
120a110b7ebSGeorge Zhang 
121a110b7ebSGeorge Zhang 		src_entry = container_of(resource, struct datagram_entry,
122a110b7ebSGeorge Zhang 					 resource);
123a110b7ebSGeorge Zhang 		*priv_flags = src_entry->priv_flags;
124a110b7ebSGeorge Zhang 		vmci_resource_put(resource);
125a110b7ebSGeorge Zhang 	} else if (context_id == VMCI_HYPERVISOR_CONTEXT_ID)
126a110b7ebSGeorge Zhang 		*priv_flags = VMCI_MAX_PRIVILEGE_FLAGS;
127a110b7ebSGeorge Zhang 	else
128a110b7ebSGeorge Zhang 		*priv_flags = vmci_context_get_priv_flags(context_id);
129a110b7ebSGeorge Zhang 
130a110b7ebSGeorge Zhang 	return VMCI_SUCCESS;
131a110b7ebSGeorge Zhang }
132a110b7ebSGeorge Zhang 
133a110b7ebSGeorge Zhang /*
134a110b7ebSGeorge Zhang  * Calls the specified callback in a delayed context.
135a110b7ebSGeorge Zhang  */
dg_delayed_dispatch(struct work_struct * work)136a110b7ebSGeorge Zhang static void dg_delayed_dispatch(struct work_struct *work)
137a110b7ebSGeorge Zhang {
138a110b7ebSGeorge Zhang 	struct delayed_datagram_info *dg_info =
139a110b7ebSGeorge Zhang 			container_of(work, struct delayed_datagram_info, work);
140a110b7ebSGeorge Zhang 
141a110b7ebSGeorge Zhang 	dg_info->entry->recv_cb(dg_info->entry->client_data, &dg_info->msg);
142a110b7ebSGeorge Zhang 
143a110b7ebSGeorge Zhang 	vmci_resource_put(&dg_info->entry->resource);
144a110b7ebSGeorge Zhang 
145a110b7ebSGeorge Zhang 	if (dg_info->in_dg_host_queue)
146a110b7ebSGeorge Zhang 		atomic_dec(&delayed_dg_host_queue_size);
147a110b7ebSGeorge Zhang 
148a110b7ebSGeorge Zhang 	kfree(dg_info);
149a110b7ebSGeorge Zhang }
150a110b7ebSGeorge Zhang 
151a110b7ebSGeorge Zhang /*
152a110b7ebSGeorge Zhang  * Dispatch datagram as a host, to the host, or other vm context. This
153a110b7ebSGeorge Zhang  * function cannot dispatch to hypervisor context handlers. This should
154a110b7ebSGeorge Zhang  * have been handled before we get here by vmci_datagram_dispatch.
155a110b7ebSGeorge Zhang  * Returns number of bytes sent on success, error code otherwise.
156a110b7ebSGeorge Zhang  */
dg_dispatch_as_host(u32 context_id,struct vmci_datagram * dg)157a110b7ebSGeorge Zhang static int dg_dispatch_as_host(u32 context_id, struct vmci_datagram *dg)
158a110b7ebSGeorge Zhang {
159a110b7ebSGeorge Zhang 	int retval;
160a110b7ebSGeorge Zhang 	size_t dg_size;
161a110b7ebSGeorge Zhang 	u32 src_priv_flags;
162a110b7ebSGeorge Zhang 
163a110b7ebSGeorge Zhang 	dg_size = VMCI_DG_SIZE(dg);
164a110b7ebSGeorge Zhang 
165a110b7ebSGeorge Zhang 	/* Host cannot send to the hypervisor. */
166a110b7ebSGeorge Zhang 	if (dg->dst.context == VMCI_HYPERVISOR_CONTEXT_ID)
167a110b7ebSGeorge Zhang 		return VMCI_ERROR_DST_UNREACHABLE;
168a110b7ebSGeorge Zhang 
169a110b7ebSGeorge Zhang 	/* Check that source handle matches sending context. */
170a110b7ebSGeorge Zhang 	if (dg->src.context != context_id) {
171a110b7ebSGeorge Zhang 		pr_devel("Sender context (ID=0x%x) is not owner of src datagram entry (handle=0x%x:0x%x)\n",
172a110b7ebSGeorge Zhang 			 context_id, dg->src.context, dg->src.resource);
173a110b7ebSGeorge Zhang 		return VMCI_ERROR_NO_ACCESS;
174a110b7ebSGeorge Zhang 	}
175a110b7ebSGeorge Zhang 
176a110b7ebSGeorge Zhang 	/* Get hold of privileges of sending endpoint. */
177a110b7ebSGeorge Zhang 	retval = vmci_datagram_get_priv_flags(context_id, dg->src,
178a110b7ebSGeorge Zhang 					      &src_priv_flags);
179a110b7ebSGeorge Zhang 	if (retval != VMCI_SUCCESS) {
180a110b7ebSGeorge Zhang 		pr_warn("Couldn't get privileges (handle=0x%x:0x%x)\n",
181a110b7ebSGeorge Zhang 			dg->src.context, dg->src.resource);
182a110b7ebSGeorge Zhang 		return retval;
183a110b7ebSGeorge Zhang 	}
184a110b7ebSGeorge Zhang 
185a110b7ebSGeorge Zhang 	/* Determine if we should route to host or guest destination. */
186a110b7ebSGeorge Zhang 	if (dg->dst.context == VMCI_HOST_CONTEXT_ID) {
187a110b7ebSGeorge Zhang 		/* Route to host datagram entry. */
188a110b7ebSGeorge Zhang 		struct datagram_entry *dst_entry;
189a110b7ebSGeorge Zhang 		struct vmci_resource *resource;
190a110b7ebSGeorge Zhang 
191a110b7ebSGeorge Zhang 		if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
192a110b7ebSGeorge Zhang 		    dg->dst.resource == VMCI_EVENT_HANDLER) {
193a110b7ebSGeorge Zhang 			return vmci_event_dispatch(dg);
194a110b7ebSGeorge Zhang 		}
195a110b7ebSGeorge Zhang 
196a110b7ebSGeorge Zhang 		resource = vmci_resource_by_handle(dg->dst,
197a110b7ebSGeorge Zhang 						   VMCI_RESOURCE_TYPE_DATAGRAM);
198a110b7ebSGeorge Zhang 		if (!resource) {
199a110b7ebSGeorge Zhang 			pr_devel("Sending to invalid destination (handle=0x%x:0x%x)\n",
200a110b7ebSGeorge Zhang 				 dg->dst.context, dg->dst.resource);
201a110b7ebSGeorge Zhang 			return VMCI_ERROR_INVALID_RESOURCE;
202a110b7ebSGeorge Zhang 		}
203a110b7ebSGeorge Zhang 		dst_entry = container_of(resource, struct datagram_entry,
204a110b7ebSGeorge Zhang 					 resource);
205a110b7ebSGeorge Zhang 		if (vmci_deny_interaction(src_priv_flags,
206a110b7ebSGeorge Zhang 					  dst_entry->priv_flags)) {
207a110b7ebSGeorge Zhang 			vmci_resource_put(resource);
208a110b7ebSGeorge Zhang 			return VMCI_ERROR_NO_ACCESS;
209a110b7ebSGeorge Zhang 		}
210a110b7ebSGeorge Zhang 
211a110b7ebSGeorge Zhang 		/*
212a110b7ebSGeorge Zhang 		 * If a VMCI datagram destined for the host is also sent by the
213a110b7ebSGeorge Zhang 		 * host, we always run it delayed. This ensures that no locks
214a110b7ebSGeorge Zhang 		 * are held when the datagram callback runs.
215a110b7ebSGeorge Zhang 		 */
216a110b7ebSGeorge Zhang 		if (dst_entry->run_delayed ||
217a110b7ebSGeorge Zhang 		    dg->src.context == VMCI_HOST_CONTEXT_ID) {
218a110b7ebSGeorge Zhang 			struct delayed_datagram_info *dg_info;
219a110b7ebSGeorge Zhang 
220a110b7ebSGeorge Zhang 			if (atomic_add_return(1, &delayed_dg_host_queue_size)
221a110b7ebSGeorge Zhang 			    == VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE) {
222a110b7ebSGeorge Zhang 				atomic_dec(&delayed_dg_host_queue_size);
223a110b7ebSGeorge Zhang 				vmci_resource_put(resource);
224a110b7ebSGeorge Zhang 				return VMCI_ERROR_NO_MEM;
225a110b7ebSGeorge Zhang 			}
226a110b7ebSGeorge Zhang 
227a110b7ebSGeorge Zhang 			dg_info = kmalloc(sizeof(*dg_info) +
228a110b7ebSGeorge Zhang 				    (size_t) dg->payload_size, GFP_ATOMIC);
229a110b7ebSGeorge Zhang 			if (!dg_info) {
230a110b7ebSGeorge Zhang 				atomic_dec(&delayed_dg_host_queue_size);
231a110b7ebSGeorge Zhang 				vmci_resource_put(resource);
232a110b7ebSGeorge Zhang 				return VMCI_ERROR_NO_MEM;
233a110b7ebSGeorge Zhang 			}
234a110b7ebSGeorge Zhang 
235a110b7ebSGeorge Zhang 			dg_info->in_dg_host_queue = true;
236a110b7ebSGeorge Zhang 			dg_info->entry = dst_entry;
237dae70a57SHarshit Mogalapalli 			dg_info->msg = *dg;
238dae70a57SHarshit Mogalapalli 			memcpy(&dg_info->msg_payload, dg + 1, dg->payload_size);
239a110b7ebSGeorge Zhang 
240a110b7ebSGeorge Zhang 			INIT_WORK(&dg_info->work, dg_delayed_dispatch);
241a110b7ebSGeorge Zhang 			schedule_work(&dg_info->work);
242a110b7ebSGeorge Zhang 			retval = VMCI_SUCCESS;
243a110b7ebSGeorge Zhang 
244a110b7ebSGeorge Zhang 		} else {
245a110b7ebSGeorge Zhang 			retval = dst_entry->recv_cb(dst_entry->client_data, dg);
246a110b7ebSGeorge Zhang 			vmci_resource_put(resource);
247a110b7ebSGeorge Zhang 			if (retval < VMCI_SUCCESS)
248a110b7ebSGeorge Zhang 				return retval;
249a110b7ebSGeorge Zhang 		}
250a110b7ebSGeorge Zhang 	} else {
251a110b7ebSGeorge Zhang 		/* Route to destination VM context. */
252a110b7ebSGeorge Zhang 		struct vmci_datagram *new_dg;
253a110b7ebSGeorge Zhang 
254a110b7ebSGeorge Zhang 		if (context_id != dg->dst.context) {
255a110b7ebSGeorge Zhang 			if (vmci_deny_interaction(src_priv_flags,
256a110b7ebSGeorge Zhang 						  vmci_context_get_priv_flags
257a110b7ebSGeorge Zhang 						  (dg->dst.context))) {
258a110b7ebSGeorge Zhang 				return VMCI_ERROR_NO_ACCESS;
259a110b7ebSGeorge Zhang 			} else if (VMCI_CONTEXT_IS_VM(context_id)) {
260a110b7ebSGeorge Zhang 				/*
261a110b7ebSGeorge Zhang 				 * If the sending context is a VM, it
262a110b7ebSGeorge Zhang 				 * cannot reach another VM.
263a110b7ebSGeorge Zhang 				 */
264a110b7ebSGeorge Zhang 
265a110b7ebSGeorge Zhang 				pr_devel("Datagram communication between VMs not supported (src=0x%x, dst=0x%x)\n",
266a110b7ebSGeorge Zhang 					 context_id, dg->dst.context);
267a110b7ebSGeorge Zhang 				return VMCI_ERROR_DST_UNREACHABLE;
268a110b7ebSGeorge Zhang 			}
269a110b7ebSGeorge Zhang 		}
270a110b7ebSGeorge Zhang 
271a110b7ebSGeorge Zhang 		/* We make a copy to enqueue. */
272bf84b140SAndrzej Hajda 		new_dg = kmemdup(dg, dg_size, GFP_KERNEL);
273a110b7ebSGeorge Zhang 		if (new_dg == NULL)
274a110b7ebSGeorge Zhang 			return VMCI_ERROR_NO_MEM;
275a110b7ebSGeorge Zhang 
276a110b7ebSGeorge Zhang 		retval = vmci_ctx_enqueue_datagram(dg->dst.context, new_dg);
277a110b7ebSGeorge Zhang 		if (retval < VMCI_SUCCESS) {
278a110b7ebSGeorge Zhang 			kfree(new_dg);
279a110b7ebSGeorge Zhang 			return retval;
280a110b7ebSGeorge Zhang 		}
281a110b7ebSGeorge Zhang 	}
282a110b7ebSGeorge Zhang 
283a110b7ebSGeorge Zhang 	/*
284a110b7ebSGeorge Zhang 	 * We currently truncate the size to signed 32 bits. This doesn't
285a110b7ebSGeorge Zhang 	 * matter for this handler as it only support 4Kb messages.
286a110b7ebSGeorge Zhang 	 */
287a110b7ebSGeorge Zhang 	return (int)dg_size;
288a110b7ebSGeorge Zhang }
289a110b7ebSGeorge Zhang 
290a110b7ebSGeorge Zhang /*
291a110b7ebSGeorge Zhang  * Dispatch datagram as a guest, down through the VMX and potentially to
292a110b7ebSGeorge Zhang  * the host.
293a110b7ebSGeorge Zhang  * Returns number of bytes sent on success, error code otherwise.
294a110b7ebSGeorge Zhang  */
dg_dispatch_as_guest(struct vmci_datagram * dg)295a110b7ebSGeorge Zhang static int dg_dispatch_as_guest(struct vmci_datagram *dg)
296a110b7ebSGeorge Zhang {
297a110b7ebSGeorge Zhang 	int retval;
298a110b7ebSGeorge Zhang 	struct vmci_resource *resource;
299a110b7ebSGeorge Zhang 
300a110b7ebSGeorge Zhang 	resource = vmci_resource_by_handle(dg->src,
301a110b7ebSGeorge Zhang 					   VMCI_RESOURCE_TYPE_DATAGRAM);
302a110b7ebSGeorge Zhang 	if (!resource)
303a110b7ebSGeorge Zhang 		return VMCI_ERROR_NO_HANDLE;
304a110b7ebSGeorge Zhang 
305a110b7ebSGeorge Zhang 	retval = vmci_send_datagram(dg);
306a110b7ebSGeorge Zhang 	vmci_resource_put(resource);
307a110b7ebSGeorge Zhang 	return retval;
308a110b7ebSGeorge Zhang }
309a110b7ebSGeorge Zhang 
310a110b7ebSGeorge Zhang /*
311a110b7ebSGeorge Zhang  * Dispatch datagram.  This will determine the routing for the datagram
312a110b7ebSGeorge Zhang  * and dispatch it accordingly.
313a110b7ebSGeorge Zhang  * Returns number of bytes sent on success, error code otherwise.
314a110b7ebSGeorge Zhang  */
vmci_datagram_dispatch(u32 context_id,struct vmci_datagram * dg,bool from_guest)315a110b7ebSGeorge Zhang int vmci_datagram_dispatch(u32 context_id,
316a110b7ebSGeorge Zhang 			   struct vmci_datagram *dg, bool from_guest)
317a110b7ebSGeorge Zhang {
318a110b7ebSGeorge Zhang 	int retval;
319a110b7ebSGeorge Zhang 	enum vmci_route route;
320a110b7ebSGeorge Zhang 
321a110b7ebSGeorge Zhang 	BUILD_BUG_ON(sizeof(struct vmci_datagram) != 24);
322a110b7ebSGeorge Zhang 
3232e453546SDan Carpenter 	if (dg->payload_size > VMCI_MAX_DG_SIZE ||
3242e453546SDan Carpenter 	    VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
325a110b7ebSGeorge Zhang 		pr_devel("Payload (size=%llu bytes) too big to send\n",
326a110b7ebSGeorge Zhang 			 (unsigned long long)dg->payload_size);
327a110b7ebSGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
328a110b7ebSGeorge Zhang 	}
329a110b7ebSGeorge Zhang 
330a110b7ebSGeorge Zhang 	retval = vmci_route(&dg->src, &dg->dst, from_guest, &route);
331a110b7ebSGeorge Zhang 	if (retval < VMCI_SUCCESS) {
332a110b7ebSGeorge Zhang 		pr_devel("Failed to route datagram (src=0x%x, dst=0x%x, err=%d)\n",
333a110b7ebSGeorge Zhang 			 dg->src.context, dg->dst.context, retval);
334a110b7ebSGeorge Zhang 		return retval;
335a110b7ebSGeorge Zhang 	}
336a110b7ebSGeorge Zhang 
337a110b7ebSGeorge Zhang 	if (VMCI_ROUTE_AS_HOST == route) {
338a110b7ebSGeorge Zhang 		if (VMCI_INVALID_ID == context_id)
339a110b7ebSGeorge Zhang 			context_id = VMCI_HOST_CONTEXT_ID;
340a110b7ebSGeorge Zhang 		return dg_dispatch_as_host(context_id, dg);
341a110b7ebSGeorge Zhang 	}
342a110b7ebSGeorge Zhang 
343a110b7ebSGeorge Zhang 	if (VMCI_ROUTE_AS_GUEST == route)
344a110b7ebSGeorge Zhang 		return dg_dispatch_as_guest(dg);
345a110b7ebSGeorge Zhang 
346a110b7ebSGeorge Zhang 	pr_warn("Unknown route (%d) for datagram\n", route);
347a110b7ebSGeorge Zhang 	return VMCI_ERROR_DST_UNREACHABLE;
348a110b7ebSGeorge Zhang }
349a110b7ebSGeorge Zhang 
350a110b7ebSGeorge Zhang /*
351a110b7ebSGeorge Zhang  * Invoke the handler for the given datagram.  This is intended to be
352a110b7ebSGeorge Zhang  * called only when acting as a guest and receiving a datagram from the
353a110b7ebSGeorge Zhang  * virtual device.
354a110b7ebSGeorge Zhang  */
vmci_datagram_invoke_guest_handler(struct vmci_datagram * dg)355a110b7ebSGeorge Zhang int vmci_datagram_invoke_guest_handler(struct vmci_datagram *dg)
356a110b7ebSGeorge Zhang {
357a110b7ebSGeorge Zhang 	struct vmci_resource *resource;
358a110b7ebSGeorge Zhang 	struct datagram_entry *dst_entry;
359a110b7ebSGeorge Zhang 
360a110b7ebSGeorge Zhang 	resource = vmci_resource_by_handle(dg->dst,
361a110b7ebSGeorge Zhang 					   VMCI_RESOURCE_TYPE_DATAGRAM);
362a110b7ebSGeorge Zhang 	if (!resource) {
363a110b7ebSGeorge Zhang 		pr_devel("destination (handle=0x%x:0x%x) doesn't exist\n",
364a110b7ebSGeorge Zhang 			 dg->dst.context, dg->dst.resource);
365a110b7ebSGeorge Zhang 		return VMCI_ERROR_NO_HANDLE;
366a110b7ebSGeorge Zhang 	}
367a110b7ebSGeorge Zhang 
368a110b7ebSGeorge Zhang 	dst_entry = container_of(resource, struct datagram_entry, resource);
369a110b7ebSGeorge Zhang 	if (dst_entry->run_delayed) {
370a110b7ebSGeorge Zhang 		struct delayed_datagram_info *dg_info;
371a110b7ebSGeorge Zhang 
372a110b7ebSGeorge Zhang 		dg_info = kmalloc(sizeof(*dg_info) + (size_t)dg->payload_size,
373a110b7ebSGeorge Zhang 				  GFP_ATOMIC);
374a110b7ebSGeorge Zhang 		if (!dg_info) {
375a110b7ebSGeorge Zhang 			vmci_resource_put(resource);
376a110b7ebSGeorge Zhang 			return VMCI_ERROR_NO_MEM;
377a110b7ebSGeorge Zhang 		}
378a110b7ebSGeorge Zhang 
379a110b7ebSGeorge Zhang 		dg_info->in_dg_host_queue = false;
380a110b7ebSGeorge Zhang 		dg_info->entry = dst_entry;
38191fb03ceSVasiliy Kovalev 		dg_info->msg = *dg;
38291fb03ceSVasiliy Kovalev 		memcpy(&dg_info->msg_payload, dg + 1, dg->payload_size);
383a110b7ebSGeorge Zhang 
384a110b7ebSGeorge Zhang 		INIT_WORK(&dg_info->work, dg_delayed_dispatch);
385a110b7ebSGeorge Zhang 		schedule_work(&dg_info->work);
386a110b7ebSGeorge Zhang 	} else {
387a110b7ebSGeorge Zhang 		dst_entry->recv_cb(dst_entry->client_data, dg);
388a110b7ebSGeorge Zhang 		vmci_resource_put(resource);
389a110b7ebSGeorge Zhang 	}
390a110b7ebSGeorge Zhang 
391a110b7ebSGeorge Zhang 	return VMCI_SUCCESS;
392a110b7ebSGeorge Zhang }
393a110b7ebSGeorge Zhang 
394a110b7ebSGeorge Zhang /*
395a110b7ebSGeorge Zhang  * vmci_datagram_create_handle_priv() - Create host context datagram endpoint
396a110b7ebSGeorge Zhang  * @resource_id:        The resource ID.
397a110b7ebSGeorge Zhang  * @flags:      Datagram Flags.
398a110b7ebSGeorge Zhang  * @priv_flags: Privilege Flags.
399a110b7ebSGeorge Zhang  * @recv_cb:    Callback when receiving datagrams.
400a110b7ebSGeorge Zhang  * @client_data:        Pointer for a datagram_entry struct
401a110b7ebSGeorge Zhang  * @out_handle: vmci_handle that is populated as a result of this function.
402a110b7ebSGeorge Zhang  *
403a110b7ebSGeorge Zhang  * Creates a host context datagram endpoint and returns a handle to it.
404a110b7ebSGeorge Zhang  */
vmci_datagram_create_handle_priv(u32 resource_id,u32 flags,u32 priv_flags,vmci_datagram_recv_cb recv_cb,void * client_data,struct vmci_handle * out_handle)405a110b7ebSGeorge Zhang int vmci_datagram_create_handle_priv(u32 resource_id,
406a110b7ebSGeorge Zhang 				     u32 flags,
407a110b7ebSGeorge Zhang 				     u32 priv_flags,
408a110b7ebSGeorge Zhang 				     vmci_datagram_recv_cb recv_cb,
409a110b7ebSGeorge Zhang 				     void *client_data,
410a110b7ebSGeorge Zhang 				     struct vmci_handle *out_handle)
411a110b7ebSGeorge Zhang {
412a110b7ebSGeorge Zhang 	if (out_handle == NULL)
413a110b7ebSGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
414a110b7ebSGeorge Zhang 
415a110b7ebSGeorge Zhang 	if (recv_cb == NULL) {
416a110b7ebSGeorge Zhang 		pr_devel("Client callback needed when creating datagram\n");
417a110b7ebSGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
418a110b7ebSGeorge Zhang 	}
419a110b7ebSGeorge Zhang 
420a110b7ebSGeorge Zhang 	if (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS)
421a110b7ebSGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
422a110b7ebSGeorge Zhang 
423a110b7ebSGeorge Zhang 	return dg_create_handle(resource_id, flags, priv_flags, recv_cb,
424a110b7ebSGeorge Zhang 				client_data, out_handle);
425a110b7ebSGeorge Zhang }
426a110b7ebSGeorge Zhang EXPORT_SYMBOL_GPL(vmci_datagram_create_handle_priv);
427a110b7ebSGeorge Zhang 
428a110b7ebSGeorge Zhang /*
429a110b7ebSGeorge Zhang  * vmci_datagram_create_handle() - Create host context datagram endpoint
430a110b7ebSGeorge Zhang  * @resource_id:        Resource ID.
431a110b7ebSGeorge Zhang  * @flags:      Datagram Flags.
432a110b7ebSGeorge Zhang  * @recv_cb:    Callback when receiving datagrams.
433a110b7ebSGeorge Zhang  * @client_ata: Pointer for a datagram_entry struct
434a110b7ebSGeorge Zhang  * @out_handle: vmci_handle that is populated as a result of this function.
435a110b7ebSGeorge Zhang  *
436a110b7ebSGeorge Zhang  * Creates a host context datagram endpoint and returns a handle to
437a110b7ebSGeorge Zhang  * it.  Same as vmci_datagram_create_handle_priv without the priviledge
438a110b7ebSGeorge Zhang  * flags argument.
439a110b7ebSGeorge Zhang  */
vmci_datagram_create_handle(u32 resource_id,u32 flags,vmci_datagram_recv_cb recv_cb,void * client_data,struct vmci_handle * out_handle)440a110b7ebSGeorge Zhang int vmci_datagram_create_handle(u32 resource_id,
441a110b7ebSGeorge Zhang 				u32 flags,
442a110b7ebSGeorge Zhang 				vmci_datagram_recv_cb recv_cb,
443a110b7ebSGeorge Zhang 				void *client_data,
444a110b7ebSGeorge Zhang 				struct vmci_handle *out_handle)
445a110b7ebSGeorge Zhang {
446a110b7ebSGeorge Zhang 	return vmci_datagram_create_handle_priv(
447a110b7ebSGeorge Zhang 		resource_id, flags,
448a110b7ebSGeorge Zhang 		VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
449a110b7ebSGeorge Zhang 		recv_cb, client_data,
450a110b7ebSGeorge Zhang 		out_handle);
451a110b7ebSGeorge Zhang }
452a110b7ebSGeorge Zhang EXPORT_SYMBOL_GPL(vmci_datagram_create_handle);
453a110b7ebSGeorge Zhang 
454a110b7ebSGeorge Zhang /*
455a110b7ebSGeorge Zhang  * vmci_datagram_destroy_handle() - Destroys datagram handle
456a110b7ebSGeorge Zhang  * @handle:     vmci_handle to be destroyed and reaped.
457a110b7ebSGeorge Zhang  *
458a110b7ebSGeorge Zhang  * Use this function to destroy any datagram handles created by
459a110b7ebSGeorge Zhang  * vmci_datagram_create_handle{,Priv} functions.
460a110b7ebSGeorge Zhang  */
vmci_datagram_destroy_handle(struct vmci_handle handle)461a110b7ebSGeorge Zhang int vmci_datagram_destroy_handle(struct vmci_handle handle)
462a110b7ebSGeorge Zhang {
463a110b7ebSGeorge Zhang 	struct datagram_entry *entry;
464a110b7ebSGeorge Zhang 	struct vmci_resource *resource;
465a110b7ebSGeorge Zhang 
466a110b7ebSGeorge Zhang 	resource = vmci_resource_by_handle(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
467a110b7ebSGeorge Zhang 	if (!resource) {
468a110b7ebSGeorge Zhang 		pr_devel("Failed to destroy datagram (handle=0x%x:0x%x)\n",
469a110b7ebSGeorge Zhang 			 handle.context, handle.resource);
470a110b7ebSGeorge Zhang 		return VMCI_ERROR_NOT_FOUND;
471a110b7ebSGeorge Zhang 	}
472a110b7ebSGeorge Zhang 
473a110b7ebSGeorge Zhang 	entry = container_of(resource, struct datagram_entry, resource);
474a110b7ebSGeorge Zhang 
475a110b7ebSGeorge Zhang 	vmci_resource_put(&entry->resource);
476a110b7ebSGeorge Zhang 	vmci_resource_remove(&entry->resource);
477a110b7ebSGeorge Zhang 	kfree(entry);
478a110b7ebSGeorge Zhang 
479a110b7ebSGeorge Zhang 	return VMCI_SUCCESS;
480a110b7ebSGeorge Zhang }
481a110b7ebSGeorge Zhang EXPORT_SYMBOL_GPL(vmci_datagram_destroy_handle);
482a110b7ebSGeorge Zhang 
483a110b7ebSGeorge Zhang /*
484a110b7ebSGeorge Zhang  * vmci_datagram_send() - Send a datagram
485a110b7ebSGeorge Zhang  * @msg:        The datagram to send.
486a110b7ebSGeorge Zhang  *
487a110b7ebSGeorge Zhang  * Sends the provided datagram on its merry way.
488a110b7ebSGeorge Zhang  */
vmci_datagram_send(struct vmci_datagram * msg)489a110b7ebSGeorge Zhang int vmci_datagram_send(struct vmci_datagram *msg)
490a110b7ebSGeorge Zhang {
491a110b7ebSGeorge Zhang 	if (msg == NULL)
492a110b7ebSGeorge Zhang 		return VMCI_ERROR_INVALID_ARGS;
493a110b7ebSGeorge Zhang 
494a110b7ebSGeorge Zhang 	return vmci_datagram_dispatch(VMCI_INVALID_ID, msg, false);
495a110b7ebSGeorge Zhang }
496a110b7ebSGeorge Zhang EXPORT_SYMBOL_GPL(vmci_datagram_send);
497