1
/*********************************************************
2
* Copyright (C) 2007 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
* Implements the client-access API to the VMCI discovery service in
28
# include "driver-config.h"
30
# define EXPORT_SYMTAB
32
# include <linux/module.h>
33
# include "compat_kernel.h"
34
# include "compat_pci.h"
37
#elif defined(SOLARIS)
39
# include <sys/sunddi.h>
40
#elif defined(__APPLE__)
41
# include <IOKit/IOLib.h>
43
# error "Platform not support by VMCI datagram API."
46
#include "vm_basic_types.h"
47
#include "vm_atomic.h"
48
#include "vm_assert.h"
49
#include "vmci_defs.h"
50
#include "vmci_kernel_if.h"
51
#include "vmci_infrastructure.h"
54
#include "vmciDatagram.h"
55
#include "vmciKernelAPI.h"
57
static Atomic_uint32 MsgIdCounter = { 0 };
59
typedef struct VMCIDsRecvData {
63
uint8 buffer[VMCI_DS_MAX_MSG_SIZE];
66
static int VMCIDsDoCall(int action, const char *name, VMCIHandle handle,
67
VMCIHandle *handleOut);
68
static int VMCIDsRecvCB(void *clientData, struct VMCIDatagram *msg);
71
*-------------------------------------------------------------------------
75
* Look up a handle in the VMCI discovery service based on
79
* Error code. 0 if success.
84
*-------------------------------------------------------------------------
88
EXPORT_SYMBOL(VMCIDs_Lookup);
92
VMCIDs_Lookup(const char *name, // IN
95
return VMCIDsDoCall(VMCI_DS_ACTION_LOOKUP, name, VMCI_INVALID_HANDLE, out);
100
*-------------------------------------------------------------------------
104
* Serialize a call into the CDS wire-format, send it across
105
* the VMCI device, wait for a response, and return
109
* Error code. 0 if success.
114
*-------------------------------------------------------------------------
119
VMCIDsDoCall(int action, // IN
120
const char *name, // IN
121
VMCIHandle handle, // IN: For the "register" action
122
VMCIHandle *handleOut) // OUT: For the "lookup" action
124
int8 *sendBuffer = NULL;
125
const size_t sendBufferSize = VMCI_DS_MAX_MSG_SIZE + sizeof(VMCIDatagram);
126
int nameLen, requestSize, res;
127
uint32 savedMsgIdCounter;
128
VMCIDsReplyHeader *reply;
129
VMCIHandle dsHandle = VMCI_INVALID_HANDLE;
130
VMCIDsRecvData *recvData = NULL;
132
VMCIDsRequestHeader *request;
135
nameLen = strlen(name);
136
if (nameLen + sizeof *request > sendBufferSize) {
137
res = VMCI_ERROR_INVALID_ARGS;
141
sendBuffer = VMCI_AllocKernelMem(sendBufferSize, VMCI_MEMORY_NONPAGED);
142
if (sendBuffer == NULL) {
143
res = VMCI_ERROR_NO_MEM;
147
recvData = VMCI_AllocKernelMem(sizeof *recvData, VMCI_MEMORY_NONPAGED);
148
if (recvData == NULL) {
149
res = VMCI_ERROR_NO_MEM;
153
VMCIHost_InitContext(&recvData->context, (uintptr_t) recvData);
154
VMCI_InitLock(&recvData->lock, "VMCIDsRecvHandler", VMCI_LOCK_RANK_MIDDLE_BH);
156
savedMsgIdCounter = Atomic_FetchAndInc(&MsgIdCounter);
158
dgram = (VMCIDatagram *) sendBuffer;
159
request = (VMCIDsRequestHeader *) (sendBuffer + sizeof *dgram);
161
/* Serialize request. */
162
request->action = action;
163
request->msgid = savedMsgIdCounter;
164
request->handle = handle;
165
request->nameLen = nameLen;
166
memcpy(request->name, name, nameLen + 1);
168
requestSize = sizeof *request + nameLen;
170
if (VMCIDatagram_CreateHnd(VMCI_INVALID_ID, 0, VMCIDsRecvCB,
171
recvData, &dsHandle) != VMCI_SUCCESS) {
172
res = VMCI_ERROR_NO_HANDLE;
176
dgram->dst = VMCI_DS_HANDLE;
177
dgram->src = dsHandle;
178
dgram->payloadSize = requestSize;
180
/* Send the datagram to CDS. */
181
res = VMCIDatagram_Send(dgram);
186
/* Block here waiting for the reply */
187
VMCI_GrabLock_BH(&recvData->lock, &flags);
188
VMCIHost_WaitForCallLocked(&recvData->context, &recvData->lock, &flags, TRUE);
189
VMCI_ReleaseLock_BH(&recvData->lock, flags);
191
if (recvData->status != VMCI_SUCCESS) {
192
res = recvData->status;
196
reply = (VMCIDsReplyHeader *) recvData->buffer;
197
/* Check that the msgid matches what we expect. */
198
if (reply->msgid != savedMsgIdCounter) {
199
res = VMCI_ERROR_GENERIC;
203
if (handleOut != NULL) {
204
*handleOut = reply->handle;
210
if (!VMCI_HANDLE_EQUAL(dsHandle, VMCI_INVALID_HANDLE)) {
211
VMCIDatagram_DestroyHnd(dsHandle);
214
VMCI_CleanupLock(&recvData->lock);
215
VMCIHost_ReleaseContext(&recvData->context);
216
VMCI_FreeKernelMem(recvData, sizeof *recvData);
219
VMCI_FreeKernelMem(sendBuffer, sendBufferSize);
225
*-----------------------------------------------------------------------------
229
* Receive callback for the Discovery Service query datagram
233
* If the received payload is not larger than the MAX, it is
234
* copied into clientData.
237
* Signals the thread waiting for the reply.
239
*-----------------------------------------------------------------------------
244
VMCIDsRecvCB(void *clientData, // IN: client data for handler
245
struct VMCIDatagram *msg) // IN
247
VMCIDsRecvData *recvData = clientData;
250
ASSERT(msg->payloadSize <= VMCI_DS_MAX_MSG_SIZE);
251
if (msg->payloadSize <= VMCI_DS_MAX_MSG_SIZE) {
252
memcpy(recvData->buffer, VMCI_DG_PAYLOAD(msg), (size_t)msg->payloadSize);
253
recvData->status = VMCI_SUCCESS;
255
recvData->status = VMCI_ERROR_PAYLOAD_TOO_LARGE;
258
VMCI_GrabLock_BH(&recvData->lock, &flags);
259
VMCIHost_SignalCall(&recvData->context);
260
VMCI_ReleaseLock_BH(&recvData->lock, flags);