1
/*********************************************************
2
* Copyright (C) 2010 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 Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 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 Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along 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
* Channel abstraction for the HGFS server.
27
#include "vm_assert.h"
28
#include "vm_atomic.h"
31
#include "hgfsChannelGuestInt.h"
32
#include "hgfsServer.h"
33
#include "hgfsServerManager.h"
36
HGFS_GST_CONN_UNINITIALIZED,
37
HGFS_GST_CONN_NOTCONNECTED,
38
HGFS_GST_CONN_CONNECTED,
42
/* Since there is only one connection we use globals. */
43
typedef struct HgfsGuestConn {
44
Atomic_uint32 refCount; /* Reference count. */
45
HgfsGuestConnState state;
46
HgfsServerSessionCallbacks *serverCbTable; /* Server session callbacks. */
47
HgfsServerChannelCallbacks channelCbTable;
50
unsigned char *clientPacketOut; /* Client supplied buffer. */
51
unsigned char packetOut[HGFS_LARGE_PACKET_MAX]; /* For RPC msg callbacks. */
55
/* Callback functions. */
56
static Bool HgfsChannelGuestBdInit(HgfsServerSessionCallbacks *serverCBTable,
59
HgfsGuestConn **connection);
60
static void HgfsChannelGuestBdExit(HgfsGuestConn *data);
61
static Bool HgfsChannelGuestBdSend(void *data,
66
static Bool HgfsChannelGuestBdReceive(HgfsGuestConn *data,
70
size_t *packetOutSize);
72
HgfsGuestChannelCBTable gGuestBackdoorOps = {
73
HgfsChannelGuestBdInit,
74
HgfsChannelGuestBdExit,
75
HgfsChannelGuestBdReceive,
78
/* Private functions. */
79
static Bool HgfsChannelGuestConnConnect(HgfsGuestConn *connData);
80
static void HgfsChannelGuestConnDestroy(HgfsGuestConn *connData);
81
static Bool HgfsChannelGuestReceiveInternal(HgfsGuestConn *connData,
85
size_t *packetOutSize);
89
*----------------------------------------------------------------------------
91
* CONNECTION DATA FUNCTIONS
93
*----------------------------------------------------------------------------
98
*----------------------------------------------------------------------------
100
* HgfsChannelGuestConnGet --
102
* Increment connection reference count.
110
*----------------------------------------------------------------------------
114
HgfsChannelGuestConnGet(HgfsGuestConn *connData) // IN: connection
117
Atomic_Inc(&connData->refCount);
122
*----------------------------------------------------------------------------
124
* HgfsChannelGuestConnPut --
126
* Decrement connection reference count.
128
* Free connection data if this is the last reference.
136
*----------------------------------------------------------------------------
140
HgfsChannelGuestConnPut(HgfsGuestConn *connData) // IN: connection
143
if (Atomic_FetchAndDec(&connData->refCount) == 1) {
144
HgfsChannelGuestConnDestroy(connData);
150
*-----------------------------------------------------------------------------
152
* HgfsChannelGuestConnInit --
154
* Initializes the connection.
157
* TRUE always and the channel initialized.
162
*-----------------------------------------------------------------------------
166
HgfsChannelGuestConnInit(HgfsGuestConn **connData, // IN/OUT: channel object
167
HgfsServerSessionCallbacks *serverCBTable) // IN: server callbacks
169
HgfsGuestConn *conn = NULL;
171
conn = Util_SafeCalloc(1, sizeof *conn);
173
/* Give ourselves a reference of one. */
174
HgfsChannelGuestConnGet(conn);
175
conn->serverCbTable = serverCBTable;
176
conn->state = HGFS_GST_CONN_NOTCONNECTED;
184
*-----------------------------------------------------------------------------
186
* HgfsChannelGuestConnExit --
188
* Teardown the connection.
190
* Removes the reference and if it is the last will cause the connection
199
*-----------------------------------------------------------------------------
203
HgfsChannelGuestConnExit(HgfsGuestConn *connData) // IN/OUT: channel object
205
connData->state = HGFS_GST_CONN_UNINITIALIZED;
207
HgfsChannelGuestConnPut(connData);
212
*-----------------------------------------------------------------------------
214
* HgfsChannelGuestConnDestroy --
216
* Destroy the connection.
224
*-----------------------------------------------------------------------------
228
HgfsChannelGuestConnDestroy(HgfsGuestConn *connData) // IN/OUT: channel object
230
/* Make sure the server closes it's own session data. */
231
if (NULL != connData->serverSession) {
232
connData->serverCbTable->close(connData->serverSession);
233
connData->serverSession = NULL;
240
*-----------------------------------------------------------------------------
242
* HgfsChannelGuestConnCreate --
244
* Create's the RPC connection for the HGFS guest if asked.
246
* Create the pseudo connection for the guest - state transition.
247
* (See the comment in the function where the RPC initialization
248
* is expected to be added.
249
* This entails is registering our callback to receive messages for the
250
* connection object passed. We will have the ability to receive
251
* requests until we unregister our callback.)
253
* NOTE: There is only handler and connction that can be used for
254
* all HGFS guest requests.
262
*-----------------------------------------------------------------------------
266
HgfsChannelGuestConnCreate(HgfsGuestConn *connData, // IN: connection
267
void *rpc, // IN: Rpc channel unused
268
void *rpcCallback) // IN: Rpc callback unused
270
ASSERT(connData->state == HGFS_GST_CONN_NOTCONNECTED);
273
* Rpc may be NULL for some cases. For example, if we
274
* just need to provide an HGFS server connection
275
* not associated with an HGFS only RPC connection.
277
if (connData->state == HGFS_GST_CONN_NOTCONNECTED) {
279
/* XXX - Here is where we would register an RPC callback if required. */
281
connData->state = HGFS_GST_CONN_CONNECTED;
282
HgfsChannelGuestConnGet(connData);
288
*-----------------------------------------------------------------------------
290
* HgfsChannelGuestConnClose --
292
* Closes the connection for the HGFS guest.
294
* If required unregisters the callback will prevent us from
295
* receiving any more requests closing the connection.
298
* TRUE if closed, FALSE if was not connected.
303
*-----------------------------------------------------------------------------
307
HgfsChannelGuestConnClose(HgfsGuestConn *connData, // IN: Connection
308
void *rpc, // IN: Rpc channel unused
309
void *rpcCallback) // IN: Rpc callback unused
313
if (connData->state == HGFS_GST_CONN_CONNECTED) {
314
/* XXX - Here is where we would unregister an RPC callback. */
316
/* Clear the connection object since we are unregistered. */
317
connData->state = HGFS_GST_CONN_NOTCONNECTED;
318
HgfsChannelGuestConnPut(connData);
326
*-----------------------------------------------------------------------------
328
* HgfsChannelGuestConnConnect --
330
* Send connection to the server.
333
* TRUE if server returns a data object, FALSE if not.
338
*-----------------------------------------------------------------------------
342
HgfsChannelGuestConnConnect(HgfsGuestConn *connData) // IN: our connection data
346
connData->channelCbTable.getWriteVa = NULL;
347
connData->channelCbTable.getReadVa = NULL;
348
connData->channelCbTable.putVa = NULL;
349
connData->channelCbTable.send = HgfsChannelGuestBdSend;
350
result = connData->serverCbTable->connect(connData,
351
&connData->channelCbTable,
353
&connData->serverSession);
355
HgfsChannelGuestConnGet(connData);
362
*-----------------------------------------------------------------------------
364
* HgfsChannelGuestConnDisconnect --
366
* Send disconnect to the server.
368
* NOTE: The server data will be maintained until
369
* the connection is totally closed (last reference is gone).
377
*-----------------------------------------------------------------------------
381
HgfsChannelGuestConnDisconnect(HgfsGuestConn *connData) // IN: connection
383
if (connData->serverSession != NULL) {
384
/* Tell the server to to disconnect the session. */
385
connData->serverCbTable->disconnect(connData->serverSession);
386
HgfsChannelGuestConnPut(connData);
392
*----------------------------------------------------------------------------
394
* HgfsChannelGuestConnCloseInternal --
396
* Close the client and send a disconnect to the server for the session.
402
* Closes the client connection and empties the queues.
404
*----------------------------------------------------------------------------
408
HgfsChannelGuestConnCloseInternal(HgfsGuestConn *connData, // IN: Connection data
409
void *rpc, // IN: Rpc channel unused
410
void *rpcCallback) // IN: Rpc callback unused
412
/* Close (unregister the backdoor RPC) connection. */
413
if (HgfsChannelGuestConnClose(connData, rpc, rpcCallback)) {
414
/* Disconnect the connection from the server. */
415
HgfsChannelGuestConnDisconnect(connData);
421
*----------------------------------------------------------------------------
423
* HgfsChannelGuestReceiveInternal --
425
* Process packet not associated with any session.
427
* This function is used in the HGFS server inside Tools.
429
* Create an internal session if not already created, and process the packet.
432
* TRUE if received packet ok and processed, FALSE otherwise.
437
*----------------------------------------------------------------------------
441
HgfsChannelGuestReceiveInternal(HgfsGuestConn *connData, // IN: connection
442
char const *packetIn, // IN: incoming packet
443
size_t packetInSize, // IN: incoming packet size
444
char *packetOut, // OUT: outgoing packet
445
size_t *packetOutSize) // IN/OUT: outgoing packet size
451
ASSERT(packetOutSize);
453
if (connData->state == HGFS_GST_CONN_UNINITIALIZED) {
454
/* The connection was closed as we are exiting, so bail. */
459
/* This is just a ping, return nothing. */
460
if (*packetOutSize == 0) {
465
* Create the session if not already created.
466
* This session is destroyed in HgfsServer_ExitState.
468
if (connData->serverSession == NULL) {
469
/* Do our guest connect now which will inform the server. */
470
if (!HgfsChannelGuestConnConnect(connData)) {
476
memset(&packet, 0, sizeof packet);
477
/* For backdoor there is only one iov */
478
packet.iov[0].va = (void *)packetIn;
479
packet.iov[0].len = packetInSize;
481
packet.metaPacket = (void *)packetIn;
482
packet.metaPacketSize = packetInSize;
483
packet.replyPacket = packetOut;
484
packet.replyPacketSize = *packetOutSize;
486
/* The server will perform a synchronous processing of requests. */
487
connData->serverCbTable->receive(&packet, connData->serverSession);
489
*packetOutSize = connData->packetOutLen;
496
*----------------------------------------------------------------------------
498
* REGISTERED CALLBACK FUNCTIONS
500
* XXX - Where we would have any internally registered callback routines.
501
* This routine would call HgfsChannelGuestReceiveInternal to process the
504
*----------------------------------------------------------------------------
509
*----------------------------------------------------------------------------
511
* GUEST CHANNEL CALLBACKS
513
*----------------------------------------------------------------------------
518
*----------------------------------------------------------------------------
520
* HgfsChannelGuestBdReceive --
522
* Process packet not associated with our registered callback.
526
* TRUE if received packet ok and processed, FALSE otherwise.
531
*----------------------------------------------------------------------------
535
HgfsChannelGuestBdReceive(HgfsGuestConn *connData, // IN: connection
536
char const *packetIn, // IN: incoming packet
537
size_t packetInSize, // IN: incoming packet size
538
char *packetOut, // OUT: outgoing packet
539
size_t *packetOutSize) // IN/OUT: outgoing packet size
543
ASSERT(NULL != packetIn);
544
ASSERT(NULL != packetOut);
545
ASSERT(NULL != packetOutSize);
546
ASSERT(NULL != connData);
548
if (NULL == connData) {
553
connData->packetOutLen = *packetOutSize;
554
connData->clientPacketOut = packetOut;
556
result = HgfsChannelGuestReceiveInternal(connData,
559
connData->clientPacketOut,
562
connData->clientPacketOut = NULL;
563
connData->packetOutLen = sizeof connData->packetOut;
571
*-----------------------------------------------------------------------------
573
* HgfsChannelGuestBdSend --
575
* Send reply to the request
583
*-----------------------------------------------------------------------------
587
HgfsChannelGuestBdSend(void *conn, // IN: our connection data
588
HgfsPacket *packet, // IN/OUT: Hgfs Packet
589
char *buffer, // IN: buffer to be sent
590
size_t bufferLen, // IN: buffer length
591
HgfsSendFlags flags) // IN: Flags to say how to process
593
HgfsGuestConn *connData = conn;
594
unsigned char *packetOut = &connData->packetOut[0];
596
ASSERT(NULL != connData);
597
ASSERT(NULL != packet);
598
ASSERT(NULL != buffer);
599
ASSERT(bufferLen <= HGFS_LARGE_PACKET_MAX &&
600
bufferLen <= packet->replyPacketSize);
602
if (connData->clientPacketOut != NULL) {
603
/* Client passed us an out buffer so use it. */
604
packetOut = connData->clientPacketOut;
606
ASSERT(bufferLen <= connData->packetOutLen);
607
if (bufferLen > connData->packetOutLen) {
608
bufferLen = connData->packetOutLen;
610
connData->packetOutLen = (uint32)bufferLen;
612
if (!(flags & HGFS_SEND_NO_COMPLETE)) {
613
connData->serverCbTable->sendComplete(packet,
614
connData->serverSession);
622
*----------------------------------------------------------------------------
624
* HgfsChannelGuestBdInit --
626
* Called from channel manager.
628
* Initializes our channel connections.
634
* Registers RPC call.
636
*----------------------------------------------------------------------------
640
HgfsChannelGuestBdInit(HgfsServerSessionCallbacks *serverCBTable, // IN: server callbacks
641
void *rpc, // IN: Rpc channel unused
642
void *rpcCallback, // IN: Rpc callback unused
643
HgfsGuestConn **connection) // OUT: connection object
645
HgfsGuestConn *connData = NULL;
648
ASSERT(NULL != connection);
650
/* Create our connection object. */
651
result = HgfsChannelGuestConnInit(&connData,
654
Debug("%s: Error: guest connection initialized.\n", __FUNCTION__);
659
* Create our connection now with any rpc handle and callback.
661
HgfsChannelGuestConnCreate(connData,
667
if (NULL != connData) {
668
HgfsChannelGuestBdExit(connData);
672
*connection = connData;
673
Debug("%s: guest initialized.\n", __FUNCTION__);
679
*----------------------------------------------------------------------------
681
* HgfsChannelGuestBdExit --
683
* Tearsdown our channel connections.
689
* Unregisters RPC call.
691
*----------------------------------------------------------------------------
695
HgfsChannelGuestBdExit(HgfsGuestConn *connData)
697
ASSERT(NULL != connData);
699
if (NULL != connData) {
700
/* Currently no rpc to unregister. */
701
HgfsChannelGuestConnCloseInternal(connData, NULL, NULL);
702
HgfsChannelGuestConnExit(connData);