1
/*********************************************************
2
* Copyright (C) 2006 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License as published by the
6
* Free Software Foundation version 2 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* You should have received a copy of the GNU General Public License along
14
* with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
*********************************************************/
22
* This file implements the VMCI Simple Datagram API on the host.
25
#include "vmci_kernel_if.h"
26
#include "vm_assert.h"
27
#include "vmci_defs.h"
28
#include "vmci_infrastructure.h"
29
#include "vmciCommonInt.h"
30
#include "vmciContext.h"
31
#include "vmciDatagram.h"
32
#include "vmciDriver.h"
33
#include "vmciEvent.h"
34
#include "vmciHashtable.h"
35
#include "vmciKernelAPI.h"
36
#include "vmciResource.h"
37
#include "vmciRoute.h"
39
# include "vmciVmkInt.h"
41
# include "helper_ext.h"
44
#define LGPFX "VMCIDatagram: "
48
* DatagramEntry describes the datagram entity. It is used for datagram
49
* entities created only on the host.
51
typedef struct DatagramEntry {
52
VMCIResource resource;
55
VMCIDatagramRecvCB recvCB;
57
VMCIEvent destroyEvent;
58
VMCIPrivilegeFlags privFlags;
61
/* Mapping between wellknown resource and context. */
62
typedef struct DatagramWKMapping {
67
typedef struct VMCIDelayedDatagramInfo {
71
} VMCIDelayedDatagramInfo;
74
/* Wellknown mapping hashtable. */
75
static VMCIHashTable *wellKnownTable = NULL;
77
static Atomic_uint32 delayedDGHostQueueSize;
79
static int VMCIDatagramGetPrivFlagsInt(VMCIId contextID, VMCIHandle handle,
80
VMCIPrivilegeFlags *privFlags);
81
static void DatagramFreeCB(void *resource);
82
static int DatagramReleaseCB(void *clientData);
84
static DatagramWKMapping *DatagramGetWellKnownMap(VMCIId wellKnownID);
85
static void DatagramReleaseWellKnownMap(DatagramWKMapping *wkMap);
88
/*------------------------------ Helper functions ----------------------------*/
91
*------------------------------------------------------------------------------
94
* Callback to free datagram structure when resource is no longer used,
95
* ie. the reference count reached 0.
100
*------------------------------------------------------------------------------
104
DatagramFreeCB(void *clientData)
106
DatagramEntry *entry = (DatagramEntry *)clientData;
108
VMCI_SignalEvent(&entry->destroyEvent);
111
* The entry is freed in VMCIDatagram_DestroyHnd, who is waiting for the
118
*------------------------------------------------------------------------------
120
* DatagramReleaseCB --
122
* Callback to release the resource reference. It is called by the
123
* VMCI_WaitOnEvent function before it blocks.
128
*------------------------------------------------------------------------------
132
DatagramReleaseCB(void *clientData)
134
DatagramEntry *entry = (DatagramEntry *)clientData;
136
VMCIResource_Release(&entry->resource);
142
*------------------------------------------------------------------------------
144
* DatagramCreateHnd --
146
* Internal function to create a datagram entry given a handle.
149
* VMCI_SUCCESS if created, negative errno value otherwise.
154
*------------------------------------------------------------------------------
158
DatagramCreateHnd(VMCIId resourceID, // IN:
160
VMCIPrivilegeFlags privFlags, // IN:
161
VMCIDatagramRecvCB recvCB, // IN:
162
void *clientData, // IN:
163
VMCIHandle *outHandle) // OUT:
169
DatagramEntry *entry;
171
ASSERT(recvCB != NULL);
172
ASSERT(outHandle != NULL);
173
ASSERT(!(privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS));
175
if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
176
return VMCI_ERROR_INVALID_ARGS;
178
if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) {
179
contextID = VMCI_INVALID_ID;
181
contextID = VMCI_GetContextID();
182
if (contextID == VMCI_INVALID_ID) {
183
return VMCI_ERROR_NO_RESOURCES;
187
if (resourceID == VMCI_INVALID_ID) {
188
resourceID = VMCIResource_GetID(contextID);
189
if (resourceID == VMCI_INVALID_ID) {
190
return VMCI_ERROR_NO_HANDLE;
194
handle = VMCI_MAKE_HANDLE(contextID, resourceID);
197
entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED);
199
VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n"));
200
return VMCI_ERROR_NO_MEM;
203
if (!VMCI_CanScheduleDelayedWork()) {
204
if (flags & VMCI_FLAG_DG_DELAYED_CB) {
205
VMCI_FreeKernelMem(entry, sizeof *entry);
206
return VMCI_ERROR_INVALID_ARGS;
208
entry->runDelayed = FALSE;
210
entry->runDelayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ? TRUE : FALSE;
213
entry->flags = flags;
214
entry->recvCB = recvCB;
215
entry->clientData = clientData;
216
VMCI_CreateEvent(&entry->destroyEvent);
217
entry->privFlags = privFlags;
219
/* Make datagram resource live. */
220
result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DATAGRAM,
221
handle, DatagramFreeCB, entry);
222
if (result != VMCI_SUCCESS) {
223
VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n",
224
handle.context, handle.resource));
225
VMCI_DestroyEvent(&entry->destroyEvent);
226
VMCI_FreeKernelMem(entry, sizeof *entry);
235
/*------------------------------ Init functions ----------------------------*/
238
*------------------------------------------------------------------------------
240
* VMCIDatagram_Init --
242
* Initialize Datagram API, ie. register the API functions with their
243
* corresponding vectors.
251
*------------------------------------------------------------------------------
255
VMCIDatagram_Init(void)
257
/* Create hash table for wellknown mappings. */
258
wellKnownTable = VMCIHashTable_Create(32);
259
if (wellKnownTable == NULL) {
260
return VMCI_ERROR_NO_RESOURCES;
263
Atomic_Write(&delayedDGHostQueueSize, 0);
269
*------------------------------------------------------------------------------
271
* VMCIDatagram_Exit --
273
* Cleanup Datagram API.
281
*------------------------------------------------------------------------------
285
VMCIDatagram_Exit(void)
287
if (wellKnownTable != NULL) {
288
VMCIHashTable_Destroy(wellKnownTable);
289
wellKnownTable = NULL;
294
/*------------------------------ Public API functions ------------------------*/
297
*------------------------------------------------------------------------------
299
* VMCIDatagram_CreateHnd --
301
* Creates a host context datagram endpoint and returns a handle to it.
304
* VMCI_SUCCESS if created, negative errno value otherwise.
309
*------------------------------------------------------------------------------
312
VMCI_EXPORT_SYMBOL(VMCIDatagram_CreateHnd)
314
VMCIDatagram_CreateHnd(VMCIId resourceID, // IN: Optional, generated
315
// if VMCI_INVALID_ID
317
VMCIDatagramRecvCB recvCB, // IN:
318
void *clientData, // IN:
319
VMCIHandle *outHandle) // OUT: newly created handle
321
if (outHandle == NULL) {
322
return VMCI_ERROR_INVALID_ARGS;
325
if (recvCB == NULL) {
327
(LGPFX"Client callback needed when creating datagram.\n"));
328
return VMCI_ERROR_INVALID_ARGS;
331
return DatagramCreateHnd(resourceID, flags, VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
332
recvCB, clientData, outHandle);
337
*------------------------------------------------------------------------------
339
* VMCIDatagram_CreateHndPriv --
341
* Creates a host context datagram endpoint and returns a handle to it.
344
* VMCI_SUCCESS if created, negative errno value otherwise.
349
*------------------------------------------------------------------------------
352
VMCI_EXPORT_SYMBOL(VMCIDatagram_CreateHndPriv)
354
VMCIDatagram_CreateHndPriv(VMCIId resourceID, // IN: Optional, generated
355
// if VMCI_INVALID_ID
357
VMCIPrivilegeFlags privFlags,// IN:
358
VMCIDatagramRecvCB recvCB, // IN:
359
void *clientData, // IN:
360
VMCIHandle *outHandle) // OUT: newly created handle
362
if (outHandle == NULL) {
363
return VMCI_ERROR_INVALID_ARGS;
366
if (recvCB == NULL) {
368
(LGPFX"Client callback needed when creating datagram.\n"));
369
return VMCI_ERROR_INVALID_ARGS;
372
if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
373
return VMCI_ERROR_INVALID_ARGS;
376
return DatagramCreateHnd(resourceID, flags, privFlags, recvCB, clientData,
382
*------------------------------------------------------------------------------
384
* VMCIDatagram_DestroyHnd --
394
*------------------------------------------------------------------------------
397
VMCI_EXPORT_SYMBOL(VMCIDatagram_DestroyHnd)
399
VMCIDatagram_DestroyHnd(VMCIHandle handle) // IN
401
DatagramEntry *entry;
402
VMCIResource *resource = VMCIResource_Get(handle,
403
VMCI_RESOURCE_TYPE_DATAGRAM);
404
if (resource == NULL) {
405
VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy datagram (handle=0x%x:0x%x).\n",
406
handle.context, handle.resource));
407
return VMCI_ERROR_NOT_FOUND;
409
entry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
411
VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
414
* We now wait on the destroyEvent and release the reference we got
417
VMCI_WaitOnEvent(&entry->destroyEvent, DatagramReleaseCB, entry);
419
if ((entry->flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
420
VMCIDatagramRemoveWellKnownMap(handle.resource, VMCI_HOST_CONTEXT_ID);
424
* We know that we are now the only reference to the above entry so
425
* can safely free it.
427
VMCI_DestroyEvent(&entry->destroyEvent);
428
VMCI_FreeKernelMem(entry, sizeof *entry);
435
*------------------------------------------------------------------------------
437
* VMCIDatagramGetPrivFlagsInt --
439
* Internal utilility function with the same purpose as
440
* VMCIDatagram_GetPrivFlags that also takes a contextID.
443
* VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
448
*------------------------------------------------------------------------------
452
VMCIDatagramGetPrivFlagsInt(VMCIId contextID, // IN
453
VMCIHandle handle, // IN
454
VMCIPrivilegeFlags *privFlags) // OUT
457
ASSERT(contextID != VMCI_INVALID_ID);
459
if (contextID == VMCI_HOST_CONTEXT_ID) {
460
DatagramEntry *srcEntry;
461
VMCIResource *resource;
463
resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
464
if (resource == NULL) {
465
return VMCI_ERROR_INVALID_ARGS;
467
srcEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
468
*privFlags = srcEntry->privFlags;
469
VMCIResource_Release(resource);
470
} else if (contextID == VMCI_HYPERVISOR_CONTEXT_ID) {
471
*privFlags = VMCI_MAX_PRIVILEGE_FLAGS;
473
*privFlags = VMCIContext_GetPrivFlags(contextID);
481
*------------------------------------------------------------------------------
483
* VMCIDatagram_GetPrivFlags --
485
* Utilility function that retrieves the privilege flags
486
* associated with a given datagram handle. For hypervisor and
487
* guest endpoints, the privileges are determined by the context
488
* ID, but for host endpoints privileges are associated with the
492
* VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
497
*------------------------------------------------------------------------------
501
VMCIDatagram_GetPrivFlags(VMCIHandle handle, // IN
502
VMCIPrivilegeFlags *privFlags) // OUT
504
if (privFlags == NULL || handle.context == VMCI_INVALID_ID) {
505
return VMCI_ERROR_INVALID_ARGS;
508
return VMCIDatagramGetPrivFlagsInt(handle.context, handle, privFlags);
513
*-----------------------------------------------------------------------------
515
* VMCIDatagramDelayedDispatchCB --
517
* Calls the specified callback in a delayed context.
525
*-----------------------------------------------------------------------------
529
VMCIDatagramDelayedDispatchCB(void *data) // IN
532
VMCIDelayedDatagramInfo *dgInfo = (VMCIDelayedDatagramInfo *)data;
536
dgInfo->entry->recvCB(dgInfo->entry->clientData, &dgInfo->msg);
538
VMCIResource_Release(&dgInfo->entry->resource);
540
inDGHostQueue = dgInfo->inDGHostQueue;
541
VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dgInfo->msg.payloadSize);
544
Atomic_Dec(&delayedDGHostQueueSize);
550
*------------------------------------------------------------------------------
552
* VMCIDatagramDispatchAsHost --
554
* Dispatch datagram as a host, to the host or other vm context. This
555
* function cannot dispatch to hypervisor context handlers. This should
556
* have been handled before we get here by VMCIDatagramDispatch.
559
* Number of bytes sent on success, appropriate error code otherwise.
564
*------------------------------------------------------------------------------
568
VMCIDatagramDispatchAsHost(VMCIId contextID, // IN:
569
VMCIDatagram *dg) // IN:
574
VMCIPrivilegeFlags srcPrivFlags;
575
char srcDomain[VMCI_DOMAIN_NAME_MAXLEN]; /* Not used on hosted. */
576
char dstDomain[VMCI_DOMAIN_NAME_MAXLEN]; /* Not used on hosted. */
579
ASSERT(VMCI_HostPersonalityActive());
581
dgSize = VMCI_DG_SIZE(dg);
583
if (contextID == VMCI_HOST_CONTEXT_ID &&
584
dg->dst.context == VMCI_HYPERVISOR_CONTEXT_ID) {
585
return VMCI_ERROR_DST_UNREACHABLE;
588
ASSERT(dg->dst.context != VMCI_HYPERVISOR_CONTEXT_ID);
591
// VMCI_DEBUG_LOG(10, (LGPFX"Sending from (handle=0x%x:0x%x) to "
592
// "(handle=0x%x:0x%x) (size=%u bytes).\n",
593
// dg->src.context, dg->src.resource,
594
// dg->dst.context, dg->dst.resource, (uint32)dgSize));
597
* Check that source handle matches sending context.
599
if (dg->src.context != contextID) {
600
if (dg->src.context == VMCI_WELL_KNOWN_CONTEXT_ID) {
601
/* Determine mapping. */
602
DatagramWKMapping *wkMap = DatagramGetWellKnownMap(dg->src.resource);
604
VMCI_DEBUG_LOG(4, (LGPFX"Sending from invalid well-known resource "
605
"(handle=0x%x:0x%x).\n",
606
dg->src.context, dg->src.resource));
607
return VMCI_ERROR_INVALID_RESOURCE;
609
if (wkMap->contextID != contextID) {
610
VMCI_DEBUG_LOG(4, (LGPFX"Sender context (ID=0x%x) is not owner of "
611
"well-known src datagram entry "
612
"(handle=0x%x:0x%x).\n",
613
contextID, dg->src.context, dg->src.resource));
614
DatagramReleaseWellKnownMap(wkMap);
615
return VMCI_ERROR_NO_ACCESS;
617
DatagramReleaseWellKnownMap(wkMap);
619
VMCI_DEBUG_LOG(4, (LGPFX"Sender context (ID=0x%x) is not owner of src "
620
"datagram entry (handle=0x%x:0x%x).\n",
621
contextID, dg->src.context, dg->src.resource));
622
return VMCI_ERROR_NO_ACCESS;
626
if (dg->dst.context == VMCI_WELL_KNOWN_CONTEXT_ID) {
627
/* Determine mapping. */
628
DatagramWKMapping *wkMap = DatagramGetWellKnownMap(dg->dst.resource);
630
VMCI_DEBUG_LOG(4, (LGPFX"Sending to invalid wellknown destination "
631
"(handle=0x%x:0x%x).\n",
632
dg->dst.context, dg->dst.resource));
633
return VMCI_ERROR_DST_UNREACHABLE;
635
dstContext = wkMap->contextID;
636
DatagramReleaseWellKnownMap(wkMap);
638
dstContext = dg->dst.context;
642
* Get hold of privileges of sending endpoint.
645
retval = VMCIDatagramGetPrivFlagsInt(contextID, dg->src, &srcPrivFlags);
646
if (retval != VMCI_SUCCESS) {
647
VMCI_WARNING((LGPFX"Couldn't get privileges (handle=0x%x:0x%x).\n",
648
dg->src.context, dg->src.resource));
654
* In the vmkernel, all communicating contexts except the
655
* hypervisor context must belong to the same domain. If the
656
* hypervisor is the source, the domain doesn't matter.
659
if (contextID != VMCI_HYPERVISOR_CONTEXT_ID) {
660
retval = VMCIContext_GetDomainName(contextID, srcDomain,
662
if (retval < VMCI_SUCCESS) {
663
VMCI_WARNING((LGPFX"Failed to get domain name for context (ID=0x%x).\n",
670
/* Determine if we should route to host or guest destination. */
671
if (dstContext == VMCI_HOST_CONTEXT_ID) {
672
/* Route to host datagram entry. */
673
DatagramEntry *dstEntry;
674
VMCIResource *resource;
676
if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
677
dg->dst.resource == VMCI_EVENT_HANDLER) {
678
return VMCIEvent_Dispatch(dg);
681
resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
682
if (resource == NULL) {
683
VMCI_DEBUG_LOG(4, (LGPFX"Sending to invalid destination "
684
"(handle=0x%x:0x%x).\n",
685
dg->dst.context, dg->dst.resource));
686
return VMCI_ERROR_INVALID_RESOURCE;
688
dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
690
retval = VMCIContext_GetDomainName(VMCI_HOST_CONTEXT_ID, dstDomain,
692
if (retval < VMCI_SUCCESS) {
693
VMCI_WARNING((LGPFX"Failed to get domain name for context (ID=0x%x).\n",
694
VMCI_HOST_CONTEXT_ID));
695
VMCIResource_Release(resource);
699
if (VMCIDenyInteraction(srcPrivFlags, dstEntry->privFlags, srcDomain,
701
VMCIResource_Release(resource);
702
return VMCI_ERROR_NO_ACCESS;
704
ASSERT(dstEntry->recvCB);
707
* If a VMCI datagram destined for the host is also sent by the
708
* host, we always run it delayed. This ensures that no locks
709
* are held when the datagram callback runs.
712
if (dstEntry->runDelayed ||
713
(dg->src.context == VMCI_HOST_CONTEXT_ID &&
714
VMCI_CanScheduleDelayedWork())) {
715
VMCIDelayedDatagramInfo *dgInfo;
717
if (Atomic_FetchAndAdd(&delayedDGHostQueueSize, 1) ==
718
VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE) {
719
Atomic_Dec(&delayedDGHostQueueSize);
720
VMCIResource_Release(resource);
721
return VMCI_ERROR_NO_MEM;
724
dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize,
725
(VMCI_MEMORY_ATOMIC |
726
VMCI_MEMORY_NONPAGED));
727
if (NULL == dgInfo) {
728
Atomic_Dec(&delayedDGHostQueueSize);
729
VMCIResource_Release(resource);
730
return VMCI_ERROR_NO_MEM;
733
dgInfo->inDGHostQueue = TRUE;
734
dgInfo->entry = dstEntry;
735
memcpy(&dgInfo->msg, dg, dgSize);
737
retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
738
if (retval < VMCI_SUCCESS) {
739
VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram "
740
"(result=%d).\n", retval));
741
VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize);
742
VMCIResource_Release(resource);
743
Atomic_Dec(&delayedDGHostQueueSize);
747
retval = dstEntry->recvCB(dstEntry->clientData, dg);
748
VMCIResource_Release(resource);
749
if (retval < VMCI_SUCCESS) {
754
/* Route to destination VM context. */
758
retval = VMCIContext_GetDomainName(dstContext, dstDomain,
760
if (retval < VMCI_SUCCESS) {
761
VMCI_DEBUG_LOG(4, (LGPFX"Failed to get domain name for context "
762
"(ID=0x%x).\n", dstContext));
766
if (contextID != dstContext &&
767
VMCIDenyInteraction(srcPrivFlags, VMCIContext_GetPrivFlags(dstContext),
768
srcDomain, dstDomain)) {
769
return VMCI_ERROR_NO_ACCESS;
772
/* We make a copy to enqueue. */
773
newDG = VMCI_AllocKernelMem(dgSize, VMCI_MEMORY_NORMAL);
775
return VMCI_ERROR_NO_MEM;
777
memcpy(newDG, dg, dgSize);
778
retval = VMCIContext_EnqueueDatagram(dstContext, newDG);
779
if (retval < VMCI_SUCCESS) {
780
VMCI_FreeKernelMem(newDG, dgSize);
785
/* The datagram is freed when the context reads it. */
788
// VMCI_DEBUG_LOG(10, (LGPFX"Sent datagram (size=%u bytes).\n",
792
* We currently truncate the size to signed 32 bits. This doesn't
793
* matter for this handler as it only support 4Kb messages.
801
*------------------------------------------------------------------------------
803
* VMCIDatagramDispatchAsGuest --
805
* Dispatch datagram as a guest, down through the VMX and potentially to
809
* Number of bytes sent on success, appropriate error code otherwise.
814
*------------------------------------------------------------------------------
818
VMCIDatagramDispatchAsGuest(VMCIDatagram *dg)
820
#if defined(VMKERNEL)
821
VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
822
return VMCI_ERROR_DST_UNREACHABLE;
825
VMCIResource *resource;
827
ASSERT(VMCI_GuestPersonalityActive());
829
resource = VMCIResource_Get(dg->src, VMCI_RESOURCE_TYPE_DATAGRAM);
830
if (NULL == resource) {
831
return VMCI_ERROR_NO_HANDLE;
834
retval = VMCI_SendDatagram(dg);
835
VMCIResource_Release(resource);
843
*------------------------------------------------------------------------------
845
* VMCIDatagram_Dispatch --
847
* Dispatch datagram. This will determine the routing for the datagram
848
* and dispatch it accordingly.
851
* Number of bytes sent on success, appropriate error code otherwise.
856
*------------------------------------------------------------------------------
860
VMCIDatagram_Dispatch(VMCIId contextID,
868
ASSERT_ON_COMPILE(sizeof(VMCIDatagram) == 24);
870
if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
871
VMCI_DEBUG_LOG(4, (LGPFX"Payload (size=%"FMT64"u bytes) too big to "
872
"send.\n", dg->payloadSize));
873
return VMCI_ERROR_INVALID_ARGS;
876
retval = VMCI_Route(&dg->src, &dg->dst, fromGuest, &route);
877
if (retval < VMCI_SUCCESS) {
881
if (VMCI_ROUTE_AS_HOST == route) {
882
if (VMCI_INVALID_ID == contextID) {
883
contextID = VMCI_HOST_CONTEXT_ID;
885
return VMCIDatagramDispatchAsHost(contextID, dg);
888
if (VMCI_ROUTE_AS_GUEST == route) {
889
return VMCIDatagramDispatchAsGuest(dg);
892
VMCI_WARNING((LGPFX"Unknown route (%d) for datagram.\n", route));
893
return VMCI_ERROR_DST_UNREACHABLE;
898
*------------------------------------------------------------------------------
900
* VMCIDatagram_InvokeGuestHandler --
902
* Invoke the handler for the given datagram. This is intended to be
903
* called only when acting as a guest and receiving a datagram from the
907
* VMCI_SUCCESS on success, other error values on failure.
912
*------------------------------------------------------------------------------
916
VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg) // IN
918
#if defined(VMKERNEL)
919
VMCI_WARNING((LGPFX"Cannot dispatch within guest in VMKERNEL.\n"));
920
return VMCI_ERROR_DST_UNREACHABLE;
923
VMCIResource *resource;
924
DatagramEntry *dstEntry;
927
ASSERT(VMCI_GuestPersonalityActive());
929
resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
930
if (NULL == resource) {
931
VMCI_DEBUG_LOG(4, (LGPFX"destination (handle=0x%x:0x%x) doesn't exist.\n",
932
dg->dst.context, dg->dst.resource));
933
return VMCI_ERROR_NO_HANDLE;
936
dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
937
if (dstEntry->runDelayed) {
938
VMCIDelayedDatagramInfo *dgInfo;
940
dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize,
941
(VMCI_MEMORY_ATOMIC | VMCI_MEMORY_NONPAGED));
942
if (NULL == dgInfo) {
943
VMCIResource_Release(resource);
944
retval = VMCI_ERROR_NO_MEM;
948
dgInfo->inDGHostQueue = FALSE;
949
dgInfo->entry = dstEntry;
950
memcpy(&dgInfo->msg, dg, VMCI_DG_SIZE(dg));
952
retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
953
if (retval < VMCI_SUCCESS) {
954
VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram "
955
"(result=%d).\n", retval));
956
VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize);
957
VMCIResource_Release(resource);
962
dstEntry->recvCB(dstEntry->clientData, dg);
963
VMCIResource_Release(resource);
964
retval = VMCI_SUCCESS;
974
*------------------------------------------------------------------------------
976
* VMCIDatagram_Send --
978
* Sends the payload to the destination datagram handle.
981
* Returns number of bytes sent if success, or error code if failure.
986
*------------------------------------------------------------------------------
989
VMCI_EXPORT_SYMBOL(VMCIDatagram_Send)
991
VMCIDatagram_Send(VMCIDatagram *msg) // IN
994
return VMCI_ERROR_INVALID_ARGS;
997
return VMCIDatagram_Dispatch(VMCI_INVALID_ID, msg, FALSE);
1002
*------------------------------------------------------------------------------
1004
* DatagramGetWellKnownMap --
1006
* Gets a mapping between handle and wellknown resource.
1009
* DatagramWKMapping * if found, NULL if not.
1014
*------------------------------------------------------------------------------
1017
static DatagramWKMapping *
1018
DatagramGetWellKnownMap(VMCIId wellKnownID) // IN:
1020
VMCIHashEntry *entry;
1021
DatagramWKMapping *wkMap = NULL;
1022
VMCIHandle wkHandle = VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID,
1024
entry = VMCIHashTable_GetEntry(wellKnownTable, wkHandle);
1025
if (entry != NULL) {
1026
wkMap = RESOURCE_CONTAINER(entry, DatagramWKMapping, entry);
1033
*------------------------------------------------------------------------------
1035
* DatagramReleaseWellKnownMap --
1037
* Releases a wellknown mapping.
1045
*------------------------------------------------------------------------------
1049
DatagramReleaseWellKnownMap(DatagramWKMapping *wkMap) // IN:
1051
if (VMCIHashTable_ReleaseEntry(wellKnownTable, &wkMap->entry) ==
1052
VMCI_SUCCESS_ENTRY_DEAD) {
1053
VMCI_FreeKernelMem(wkMap, sizeof *wkMap);
1059
*------------------------------------------------------------------------------
1061
* VMCIDatagramRequestWellKnownMap --
1063
* Creates a mapping between handle and wellknown resource. If resource
1064
* is already used we fail the request.
1067
* VMCI_SUCCESS if created, negative errno value otherwise.
1072
*------------------------------------------------------------------------------
1076
VMCIDatagramRequestWellKnownMap(VMCIId wellKnownID, // IN:
1077
VMCIId contextID, // IN:
1078
VMCIPrivilegeFlags privFlags) // IN:
1081
DatagramWKMapping *wkMap;
1082
VMCIHandle wkHandle = VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID,
1085
if (privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED ||
1086
!VMCIWellKnownID_AllowMap(wellKnownID, privFlags)) {
1087
return VMCI_ERROR_NO_ACCESS;
1090
wkMap = VMCI_AllocKernelMem(sizeof *wkMap, VMCI_MEMORY_NONPAGED);
1091
if (wkMap == NULL) {
1092
return VMCI_ERROR_NO_MEM;
1095
VMCIHashTable_InitEntry(&wkMap->entry, wkHandle);
1096
wkMap->contextID = contextID;
1098
/* Fails if wkHandle (wellKnownID) already exists. */
1099
result = VMCIHashTable_AddEntry(wellKnownTable, &wkMap->entry);
1100
if (result != VMCI_SUCCESS) {
1101
VMCI_FreeKernelMem(wkMap, sizeof *wkMap);
1104
result = VMCIContext_AddWellKnown(contextID, wellKnownID);
1105
if (UNLIKELY(result < VMCI_SUCCESS)) {
1106
VMCIHashTable_RemoveEntry(wellKnownTable, &wkMap->entry);
1107
VMCI_FreeKernelMem(wkMap, sizeof *wkMap);
1114
*------------------------------------------------------------------------------
1116
* VMCIDatagramRemoveWellKnownMap --
1118
* Removes a mapping between handle and wellknown resource. Checks if
1119
* mapping belongs to calling context.
1122
* VMCI_SUCCESS if removed, negative errno value otherwise.
1127
*------------------------------------------------------------------------------
1131
VMCIDatagramRemoveWellKnownMap(VMCIId wellKnownID, // IN:
1132
VMCIId contextID) // IN:
1134
int result = VMCI_ERROR_NO_ACCESS;
1135
DatagramWKMapping *wkMap = DatagramGetWellKnownMap(wellKnownID);
1136
if (wkMap == NULL) {
1137
VMCI_DEBUG_LOG(4, (LGPFX"Failed to remove well-known mapping between "
1138
"resource (ID=0x%x) and context (ID=0x%x).\n",
1139
wellKnownID, contextID));
1140
return VMCI_ERROR_NOT_FOUND;
1143
if (contextID == wkMap->contextID) {
1144
VMCIHashTable_RemoveEntry(wellKnownTable, &wkMap->entry);
1145
VMCIContext_RemoveWellKnown(contextID, wellKnownID);
1146
result = VMCI_SUCCESS;
1148
DatagramReleaseWellKnownMap(wkMap);
1154
*-----------------------------------------------------------------------------
1156
* VMCIDatagram_Sync --
1158
* Use this as a synchronization point when setting globals, for example,
1159
* during device shutdown.
1167
*-----------------------------------------------------------------------------
1171
VMCIDatagram_Sync(void)
1173
VMCIResource_Sync();
1178
*-----------------------------------------------------------------------------
1180
* VMCIDatagram_CheckHostCapabilities --
1182
* Verify that the host supports the resources we need.
1183
* None are required for datagrams since they are implicitly supported.
1191
*-----------------------------------------------------------------------------
1195
VMCIDatagram_CheckHostCapabilities(void)