1
/*********************************************************
2
* Copyright (C) 2004 VMware, Inc. All rights reserved.
4
* The contents of this file are subject to the terms of the Common
5
* Development and Distribution License (the "License") version 1.0
6
* and no later version. You may not use this file except in
7
* compliance with the License.
9
* You can obtain a copy of the License at
10
* http://www.opensource.org/licenses/cddl1.php
12
* See the License for the specific language governing permissions
13
* and limitations under the License.
15
*********************************************************/
20
* Remote Procedure Call between VMware and guest applications
23
* This module contains implements the out (guest=>host) direction only.
24
* The in and out modules are separate since some applications (e.g.
25
* drivers that want to do RPC-based logging) only want/need/can have the
30
#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
31
# include "kernelStubs.h"
51
Message_Channel *channel;
56
*-----------------------------------------------------------------------------
60
* Constructor for the RpcOut object
68
*-----------------------------------------------------------------------------
72
RpcOut_Construct(void)
74
return (RpcOut *)calloc(1, sizeof(RpcOut));
79
*-----------------------------------------------------------------------------
83
* Destructor for the RpcOut object.
89
* Frees RpcOut object memory.
91
*-----------------------------------------------------------------------------
95
RpcOut_Destruct(RpcOut *out) // IN
98
ASSERT(out->channel == NULL);
105
*-----------------------------------------------------------------------------
118
*-----------------------------------------------------------------------------
122
RpcOut_start(RpcOut *out) // IN
125
ASSERT(out->channel == NULL);
126
out->channel = Message_Open(RPCI_PROTOCOL_NUM);
127
if (out->channel == NULL) {
128
Debug("RpcOut: couldn't open channel with RPCI protocol\n");
137
*-----------------------------------------------------------------------------
141
* Make VMware synchroneously execute a TCLO command
143
* Unlike the other send varieties, RpcOut_send requires that the
144
* caller pass non-NULL reply and repLen arguments.
147
* TRUE on success. 'reply' contains the result of the rpc
148
* FALSE on error. 'reply' will contain a description of the error
150
* In both cases, the caller should not free the reply.
155
*-----------------------------------------------------------------------------
159
RpcOut_send(RpcOut *out, // IN
160
char const *request, // IN
162
char const **reply, // OUT
163
size_t *repLen) // OUT
165
unsigned char *myReply;
171
ASSERT(out->channel);
172
if (Message_Send(out->channel, (const unsigned char *)request, reqLen) == FALSE) {
173
*reply = "RpcOut: Unable to send the RPCI command";
174
*repLen = strlen(*reply);
179
if (Message_Receive(out->channel, &myReply, &myRepLen) == FALSE) {
180
*reply = "RpcOut: Unable to receive the result of the RPCI command";
181
*repLen = strlen(*reply);
187
|| ( (success = strncmp((const char *)myReply, "1 ", 2) == 0) == FALSE
188
&& strncmp((const char *)myReply, "0 ", 2))) {
189
*reply = "RpcOut: Invalid format for the result of the RPCI command";
190
*repLen = strlen(*reply);
195
*reply = ((const char *)myReply) + 2;
196
*repLen = myRepLen - 2;
203
*-----------------------------------------------------------------------------
214
* Frees the result of the last command.
216
*-----------------------------------------------------------------------------
220
RpcOut_stop(RpcOut *out) // IN
229
/* Try to close the channel */
230
if (Message_Close(out->channel) == FALSE) {
231
Debug("RpcOut: couldn't close channel\n");
243
*-----------------------------------------------------------------------------
247
* Make VMware execute a RPCI command
249
* VMware closes a channel when it detects that there has been no activity
250
* on it for a while. Because we do not know how often this program will
251
* make VMware execute a RPCI, we open/close one channel per RPCI command
254
* TRUE on success. '*reply' contains an allocated result of the rpc
255
* FALSE on error. '*reply' contains an allocated description of the error
261
*-----------------------------------------------------------------------------
265
RpcOut_sendOne(char **reply, // OUT: Result
266
size_t *repLen, // OUT: Length of the result
267
char const *reqFmt, // IN: RPCI command
277
/* Format the request string */
278
va_start(args, reqFmt);
279
request = Str_Vasprintf(&reqLen, reqFmt, args);
283
* If Str_Vasprintf failed, write NULL into the reply if the caller wanted
286
if (request == NULL) {
294
* If the command doesn't contain a space, add one to the end to maintain
295
* compatibility with old VMXs.
297
* For a long time, the GuestRpc logic in the VMX was wired to expect a
298
* trailing space in every command, even commands without arguments. That is
299
* no longer true, but we must continue to add a trailing space because we
300
* don't know whether we're talking to an old or new VMX.
302
if (strchr(request, ' ') == NULL) {
305
tmp = Str_Asprintf(NULL, "%s ", request);
310
* If Str_Asprintf failed, write NULL into reply if the caller wanted
313
if (request == NULL) {
321
status = RpcOut_SendOneRaw(request, reqLen, reply, repLen);
330
*-----------------------------------------------------------------------------
332
* RpcOut_SendOneRaw --
334
* Make VMware execute a RPCI command
336
* VMware closes a channel when it detects that there has been no activity
337
* on it for a while. Because we do not know how often this program will
338
* make VMware execute a RPCI, we open/close one channel per RPCI command.
340
* This function sends a message over the backdoor without using
341
* any of the Str_ functions on the request buffer; Str_Asprintf() in
342
* particular uses FormatMessage on Win32, which corrupts some UTF-8
343
* strings. Using this function directly instead of using RpcOut_SendOne()
344
* avoids these problems.
346
* If this is not an issue, you can use RpcOut_sendOne(), which has
349
* Note: It is the caller's responsibility to ensure that the RPCI command
350
* followed by a space appear at the start of the request buffer. See
351
* the command in RpcOut_sendOne for details.
354
* TRUE on success. '*reply' contains an allocated result of the rpc
355
* FALSE on error. '*reply' contains an allocated description of the
362
*-----------------------------------------------------------------------------
366
RpcOut_SendOneRaw(void *request, // IN: RPCI command
367
size_t reqLen, // IN: Size of request buffer
368
char **reply, // OUT: Result
369
size_t *repLen) // OUT: Length of the result
378
Debug("Rpci: Sending request='%s'\n", (char *)request);
379
out = RpcOut_Construct();
381
myReply = "RpcOut: Unable to create the RpcOut object";
382
myRepLen = strlen(myReply);
385
} else if (RpcOut_start(out) == FALSE) {
386
myReply = "RpcOut: Unable to open the communication channel";
387
myRepLen = strlen(myReply);
390
} else if (RpcOut_send(out, request, reqLen, &myReply, &myRepLen)
392
/* We already have the description of the error */
399
Debug("Rpci: Sent request='%s', reply='%s', len=%"FMTSZ"u, status=%d\n",
400
(char *)request, myReply, myRepLen, status);
404
* If we got a non-NULL reply, make a copy of it, because the reply
405
* we got back is inside the channel buffer, which will get destroyed
406
* at the end of this function.
408
if (myReply != NULL) {
410
* We previously used strdup to duplicate myReply, but that
411
* breaks if you are sending binary (not string) data over the
412
* backdoor. Don't assume the data is a string.
414
* myRepLen is strlen(myReply), so we need an extra byte to
415
* cover the NUL terminator.
417
*reply = malloc(myRepLen + 1);
418
if (*reply != NULL) {
419
memcpy(*reply, myReply, myRepLen);
421
* The message layer already writes a trailing NUL but we might
422
* change that someday, so do it again here.
424
(*reply)[myRepLen] = 0;
428
* Our reply was NULL, so just pass the NULL back up to the caller.
434
* Only set the length if the caller wanted it and if we got a good
437
if (repLen != NULL && *reply != NULL) {
443
if (RpcOut_stop(out) == FALSE) {
445
* We couldn't stop the channel. Free anything we allocated, give our
446
* client a reply of NULL, and return FALSE.
453
Debug("Rpci: unable to close the communication channel\n");
457
RpcOut_Destruct(out);