]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Guest/Host Interface for VMCI.
authorVMware, Inc <>
Mon, 26 Apr 2010 17:56:09 +0000 (10:56 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Mon, 26 Apr 2010 17:56:09 +0000 (10:56 -0700)
This change consist of 2 part.

Part-1: Hgfs VMCI Interface for linux Guest.

Guest VMCI Interface: Every request will pass meta Packet as contiguous buffer and data packet
as set of struct pages. This is linux guest only. Note that even contiguous buffer will be sliced
down into many pages when passed to the host.

Use req->bufferSize instead of HGFS_PACKET_MAX so that each transport can allocate packet
of variable size.

Part-2: Hgfs VMCI Interface for linux host.

Implement new interfaces for communication between hgfsServer
and transport layer. Earlier hgfsUtil.c was implemented which
was thought to be too complicated. Now a less(?) complicated
version hgfsServerPacketUtil.c has been added.

Removed memcpy from backdoor, tools code. Write reply directly
into guest memory.

I thought about reference counting but realized that it is not
required. It would have been useful if the system could hold onto
memory for long time but we are guaranteed to release all the
memory at packet Send, so I am not too worried about it.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
31 files changed:
open-vm-tools/lib/hgfsServer/Makefile.am
open-vm-tools/lib/hgfsServer/hgfsServer.c
open-vm-tools/lib/hgfsServer/hgfsServerInt.h
open-vm-tools/lib/hgfsServer/hgfsServerLinux.c
open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c [new file with mode: 0644]
open-vm-tools/lib/include/hgfsChannel.h
open-vm-tools/lib/include/hgfsProto.h
open-vm-tools/lib/include/hgfsServer.h
open-vm-tools/lib/include/hgfsTransport.h [new file with mode: 0644]
open-vm-tools/lib/include/hgfsUtil.h
open-vm-tools/lib/include/vmci_defs.h [new file with mode: 0644]
open-vm-tools/modules/freebsd/vmhgfs/transport.c
open-vm-tools/modules/freebsd/vmhgfs/vfsopscommon.c
open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c
open-vm-tools/modules/linux/shared/vmci_defs.h
open-vm-tools/modules/linux/vmhgfs/bdhandler.c
open-vm-tools/modules/linux/vmhgfs/bdhandler.h [deleted file]
open-vm-tools/modules/linux/vmhgfs/dir.c
open-vm-tools/modules/linux/vmhgfs/file.c
open-vm-tools/modules/linux/vmhgfs/filesystem.c
open-vm-tools/modules/linux/vmhgfs/fsutil.c
open-vm-tools/modules/linux/vmhgfs/inode.c
open-vm-tools/modules/linux/vmhgfs/page.c
open-vm-tools/modules/linux/vmhgfs/request.c
open-vm-tools/modules/linux/vmhgfs/request.h
open-vm-tools/modules/linux/vmhgfs/super.c
open-vm-tools/modules/linux/vmhgfs/tcp.c
open-vm-tools/modules/linux/vmhgfs/tcp.h [deleted file]
open-vm-tools/modules/linux/vmhgfs/transport.c
open-vm-tools/modules/linux/vmhgfs/transport.h
open-vm-tools/modules/linux/vmhgfs/vmci.c [new file with mode: 0644]

index acd2b39544554803dbe340a979b0ee5e103404a2..d39942f0e50520541ef6f9b796aafadfb9d6ed1b 100644 (file)
@@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libHgfsServer.la
 libHgfsServer_la_SOURCES =
 libHgfsServer_la_SOURCES += hgfsServer.c
 libHgfsServer_la_SOURCES += hgfsServerLinux.c
+libHgfsServer_la_SOURCES += hgfsServerPacketUtil.c
 libHgfsServer_la_SOURCES += hgfsDirNotifyStub.c
 
 AM_CFLAGS =
index bcfeaf185aa0c611ff6255060d916228607dc13c..3218c702952cad8c603fd092db6309ba89888d1b 100644 (file)
@@ -31,6 +31,7 @@
 #include "util.h"
 #include "wiper.h"
 #include "hgfsDirNotify.h"
+#include "hgfsTransport.h"
 
 #if defined(_WIN32)
 #include <io.h>
@@ -153,18 +154,17 @@ struct HgfsStaticSession {
 #endif
 
 /* Session related callbacks. */
-static void HgfsServerSessionReceive(char const *packetIn,
-                                     size_t packetSize,
+static void HgfsServerSessionReceive(HgfsPacket *packet,
                                      void *clientData,
                                      HgfsReceiveFlags flags);
 static Bool HgfsServerSessionConnect(void *transportData,
-                                     HgfsSessionSendFunc *send,
+                                     HgfsServerChannelCallbacks *channelCbTable,
                                      void **clientData);
 static void HgfsServerSessionDisconnect(void *clientData);
 static void HgfsServerSessionClose(void *clientData);
 static void HgfsServerSessionInvalidateObjects(void *clientData,
                                                DblLnkLst_Links *shares);
-static void HgfsServerSessionSendComplete(void *clientData, char *buffer);
+static void HgfsServerSessionSendComplete(HgfsPacket *packet, void *clientData);
 
 /*
  * Callback table passed to transport and any channels.
@@ -2489,10 +2489,11 @@ HgfsUpdateNodeNames(const char *oldLocalName,  // IN: Name of file to look for
  */
 
 static HgfsInternalStatus
-HgfsServerClose(char const *packetIn,      // IN: incoming packet
-                size_t packetSize,         // IN: size of packet
-                HgfsSessionInfo *session)  // IN: session info
+HgfsServerClose(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsHandle file;
    char *packetOut = NULL;
    size_t replySize;
@@ -2516,8 +2517,9 @@ HgfsServerClose(char const *packetIn,      // IN: incoming packet
       HgfsFreeFileNode(file, session);
    }
 
-   if (!HgfsPackCloseReply(packetIn, status, op, &packetOut, &replySize) ||
-       !HgfsPacketSend(packetOut, replySize, session, 0)) {
+   if (!HgfsPackCloseReply(input->packet, packetIn, status, op,
+                           &packetOut, &replySize, session) ||
+       !HgfsPacketSend(input->packet, packetOut, replySize, session, 0)) {
       status = HGFS_INTERNAL_STATUS_ERROR;
       goto error;
    }
@@ -2525,8 +2527,7 @@ HgfsServerClose(char const *packetIn,      // IN: incoming packet
    return 0;
 
 error:
-   free(packetOut);
-
+   HSPU_PutReplyPacket(input->packet, session);
    return status;
 }
 
@@ -2549,10 +2550,11 @@ error:
  */
 
 static HgfsInternalStatus
-HgfsServerSearchClose(char const *packetIn,      // IN: incoming packet
-                      size_t packetSize,         // IN: size of packet
-                      HgfsSessionInfo *session)  // IN: session info
+HgfsServerSearchClose(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsHandle search;
    char *packetOut = NULL;
    size_t replySize;
@@ -2576,8 +2578,9 @@ HgfsServerSearchClose(char const *packetIn,      // IN: incoming packet
       goto error;
    }
 
-   if (!HgfsPackSearchCloseReply(packetIn, status, op,  &packetOut, &replySize) ||
-       !HgfsPacketSend(packetOut, replySize, session, 0)) {
+   if (!HgfsPackSearchCloseReply(input->packet, packetIn, status, op,
+                                 &packetOut, &replySize, session) ||
+       !HgfsPacketSend(input->packet, packetOut, replySize, session, 0)) {
       status = HGFS_INTERNAL_STATUS_ERROR;
       goto error;
    }
@@ -2585,8 +2588,7 @@ HgfsServerSearchClose(char const *packetIn,      // IN: incoming packet
    return 0;
 
 error:
-   free(packetOut);
-
+   HSPU_PutReplyPacket(input->packet, session);
    return status;
 }
 
@@ -2596,9 +2598,7 @@ error:
 /* Opcode handlers, indexed by opcode */
 static struct {
    HgfsInternalStatus
-   (*handler)(const char *packetIn,
-              size_t packetSize,
-              HgfsSessionInfo *session);
+   (*handler)(HgfsInputParam *input);
 
    /* Minimal size of the request packet */
    unsigned int minReqSize;
@@ -2646,7 +2646,8 @@ static struct {
    { HgfsServerSymlinkCreate,    HGFS_SIZEOF_OP(HgfsRequestSymlinkCreateV3)    },
    { HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange)          },
    { HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3) },
-
+   { HgfsServerRead,             HGFS_SIZEOF_OP(HgfsRequestReadV3)             },
+   { HgfsServerWrite,            HGFS_SIZEOF_OP(HgfsRequestWriteV3)            },
 };
 
 
@@ -2669,6 +2670,8 @@ static struct {
  *    make a copy of it. The validity of packetIn for the HGFS server is only
  *    within the scope of this function.
  *
+ *    Definitions of Meta Packet, Data packet can be looked up in hgfsChannelVmci.c
+ *
  * Results:
  *    None
  *
@@ -2679,20 +2682,21 @@ static struct {
  */
 
 static void
-HgfsServerSessionReceive(char const *packetIn,    // IN: incoming packet
-                          size_t packetSize,       // IN: size of packet
-                          void *clientData,        // IN: session info
-                          HgfsReceiveFlags flags)  // IN: flags to indicate processing
+HgfsServerSessionReceive(HgfsPacket *packet,      // IN: Hgfs Packet
+                         void *clientData,        // IN: session info
+                         HgfsReceiveFlags flags)  // IN: flags to indicate processing
 {
    HgfsSessionInfo *session = (HgfsSessionInfo *)clientData;
-   HgfsRequest *request = (HgfsRequest *)packetIn;
+   HgfsRequest *request;
    HgfsHandle id;
    HgfsOp op;
    HgfsStatus status;
    Bool v4header = FALSE;
+   HgfsInputParam input;
+   size_t metaPacketSize;
+   char *metaPacket;
 
    ASSERT(session);
-   ASSERT(request);
 
    if (session->state == HGFS_SESSION_STATE_CLOSED) {
       LOG(4, ("%s: %d: Received packet after disconnected.\n", __FUNCTION__,
@@ -2701,14 +2705,28 @@ HgfsServerSessionReceive(char const *packetIn,    // IN: incoming packet
       return;
    }
 
-   /* Error out if less than HgfsRequest size. */
-   if (packetSize < sizeof *request) {
-      if (packetSize >= sizeof id) {
+   metaPacket = HSPU_GetMetaPacket(packet, &metaPacketSize, session);
+   request = (HgfsRequest *)metaPacket;
+   ASSERT_DEVEL(request);
+   if (!request) {
+      /*
+       * How can I return error back to the client, clearly the client is either broken or
+       * malicious ? We cannot continue from here.
+       */
+      return;
+   }
+
+   /*
+    * Error out if less than HgfsRequest size.
+    */
+   if (metaPacketSize < sizeof *request) {
+      if (metaPacketSize >= sizeof id) {
          id = request->id;
       } else {
          id = 0;
       }
       status = HGFS_STATUS_PROTOCOL_ERROR;
+      ASSERT_DEVEL(0);
       goto err;
    }
 
@@ -2717,18 +2735,20 @@ HgfsServerSessionReceive(char const *packetIn,    // IN: incoming packet
 
    id = request->id;
    op = request->op;
+
    /* If it is a V4 packet then handle it appropriately. */
-   if (HGFS_V4_LEGACY_OPCODE == op) {
-      HgfsHeader *header = (HgfsHeader *)packetIn;
-      if (packetSize < sizeof *header) {
+  if (HGFS_V4_LEGACY_OPCODE == op) {
+      HgfsHeader *header = (HgfsHeader *)metaPacket;
+      if (metaPacketSize < sizeof *header) {
          status = HGFS_STATUS_PROTOCOL_ERROR;
+         ASSERT_DEVEL(0);
          goto err;
       }
       op = header->op;
       v4header = TRUE;
    }
 
-   if (!HgfsValidatePacket(packetIn, packetSize)) {
+   if (!HgfsValidatePacket(metaPacket, metaPacketSize)) {
       status = HGFS_STATUS_PROTOCOL_ERROR;
       LOG(4, ("%s: %d: Possible BUG! malformed packet.\n", __FUNCTION__,
                __LINE__));
@@ -2737,10 +2757,13 @@ HgfsServerSessionReceive(char const *packetIn,    // IN: incoming packet
 
    HGFS_ASSERT_MINIMUM_OP(op);
    if (op < sizeof handlers / sizeof handlers[0]) {
-      if (packetSize >= handlers[op].minReqSize) {
+      if (metaPacketSize >= handlers[op].minReqSize) {
          HgfsInternalStatus internalStatus;
-         internalStatus = (*handlers[op].handler)(packetIn, packetSize,
-                                                  session);
+         input.metaPacket = metaPacket;
+         input.metaPacketSize = metaPacketSize;
+         input.session = session;
+         input.packet = packet;
+         internalStatus = (*handlers[op].handler)(&input);
          status = HgfsConvertFromInternalStatus(internalStatus);
       } else {
          /*
@@ -2765,26 +2788,41 @@ err:
    if (status != HGFS_STATUS_SUCCESS) {
       char *packetOut;
       uint32 replySize;
+      size_t replyPacketSize;
       if (v4header) {
          HgfsHeader *header;
-
-         header = Util_SafeMalloc(sizeof *header);
-         HgfsPackReplyHeaderV4(status, 0, (HgfsHeader *)packetIn, header);
+         replyPacketSize = sizeof *header;
+         header = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
+         if (!header || sizeof *header > replyPacketSize) {
+            /*
+             * Transport should probably check for minimum hgfs packet size.
+             * How should we send an error back if there is no meta packet ?
+             */
+            return;
+         }
+         HgfsPackReplyHeaderV4(status, 0, (HgfsHeader *)metaPacket, header);
          packetOut = (char *)header;
          replySize = sizeof *header;
       } else {
          HgfsReply *reply;
-
-         reply = Util_SafeMalloc(sizeof *reply);
+         replyPacketSize = sizeof *reply;
+         reply = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
+         if (!reply || sizeof *reply > replyPacketSize) {
+            /*
+             * Transport should probably check for minimum hgfs packet size.
+             * How should we send an error back if there is no meta packet ?
+             */
+            return;
+         }
          reply->id = id;
          reply->status = status;
          packetOut = (char *)reply;
          replySize = sizeof *reply;
       }
-
-      if (!HgfsPacketSend(packetOut, replySize, session, 0)) {
+      LOG(4, ("Error occured for id = %u\n", (uint32)id));
+      if (!HgfsPacketSend(packet, packetOut, replySize, session, 0)) {
          /* Send failed. Drop the reply. */
-         free(packetOut);
+         HSPU_PutReplyPacket(packet, session);
       }
    }
 }
@@ -2905,9 +2943,9 @@ HgfsServer_ExitState(void)
  */
 
 static Bool
-HgfsServerSessionConnect(void *transportData,        // IN: transport session context
-                         HgfsSessionSendFunc *send,  // IN: send reply callback
-                         void **sessionData)         // OUT: server session context
+HgfsServerSessionConnect(void *transportData,                         // IN: transport session context
+                         HgfsServerChannelCallbacks *channelCbTable,  // IN: Channel callbacks
+                         void **sessionData)                          // OUT: server session context
 {
    int i;
    HgfsSessionInfo *session = Util_SafeMalloc(sizeof *session);
@@ -2991,7 +3029,7 @@ HgfsServerSessionConnect(void *transportData,        // IN: transport session co
    session->type = HGFS_SESSION_TYPE_REGULAR;
    session->state = HGFS_SESSION_STATE_OPEN;
    session->transportData = transportData;
-   session->send = send;
+   session->channelCbTable = channelCbTable;
    Atomic_Write(&session->refCount, 0);
 
    /* Give our session a reference to hold while we are open. */
@@ -3220,6 +3258,7 @@ HgfsServer_ProcessPacket(char const *packetIn,   // IN: incoming packet
                          size_t *packetLen,      // IN/OUT: packet length
                          HgfsReceiveFlags flags) // IN: flags
 {
+   HgfsPacket packet;
    ASSERT(packetIn);
    ASSERT(packetOut);
    ASSERT(packetLen);
@@ -3245,7 +3284,18 @@ HgfsServer_ProcessPacket(char const *packetIn,   // IN: incoming packet
       hgfsStaticSession.session->type = HGFS_SESSION_TYPE_INTERNAL;
    }
 
-   HgfsServerSessionReceive(packetIn, *packetLen, hgfsStaticSession.session, 0);
+   memset(&packet, 0, sizeof packet);
+   packet.iov[0].va = (void *)packetIn;
+   packet.iov[0].len = *packetLen;
+   packet.iovCount = 1;
+   packet.metaPacket = (void *)packetIn;
+   packet.metaPacketSize = *packetLen;
+   packet.replyPacket = packetOut;
+   packet.replyPacketSize = HGFS_LARGE_PACKET_MAX;
+
+   HgfsServerSessionReceive(&packet,
+                            hgfsStaticSession.session,
+                            0);
 
    /*
     * At this point, all the HGFS ops send reply synchronously. So
@@ -3255,12 +3305,10 @@ HgfsServer_ProcessPacket(char const *packetIn,   // IN: incoming packet
 
    ASSERT(hgfsStaticSession.bufferOut);
 
-   memcpy(packetOut, hgfsStaticSession.bufferOut,
-          hgfsStaticSession.bufferOutLen);
    *packetLen = hgfsStaticSession.bufferOutLen;
 
-   HgfsServerSessionSendComplete(hgfsStaticSession.session,
-                           hgfsStaticSession.bufferOut);
+   HgfsServerSessionSendComplete(&packet,
+                                 hgfsStaticSession.session);
    hgfsStaticSession.bufferOut = NULL;
 }
 #endif
@@ -3285,10 +3333,12 @@ HgfsServer_ProcessPacket(char const *packetIn,   // IN: incoming packet
  */
 
 void
-HgfsServerSessionSendComplete(void *clientData, // IN: session currently unused
-                              char *buffer)     // IN: sent buffer
+HgfsServerSessionSendComplete(HgfsPacket *packet,   // IN/OUT: Hgfs packet
+                              void *clientData)     // IN: session info
 {
-   free(buffer);
+   HgfsSessionInfo *session = (HgfsSessionInfo *)clientData;
+   HSPU_PutMetaPacket(packet, session);
+   HSPU_PutReplyPacket(packet, session);
 }
 
 
@@ -3309,25 +3359,29 @@ HgfsServerSessionSendComplete(void *clientData, // IN: session currently unused
  */
 
 Bool
-HgfsPacketSend(char *packet,                // IN: packet buffer
-               size_t packetSize,           // IN: packet size
-               HgfsSessionInfo *session,    // IN: session info
-               HgfsSendFlags flags)         // IN: flags for how to process
+HgfsPacketSend(HgfsPacket *packet,            // IN/OUT: Hgfs Packet
+               char *packetOut,               // IN: output buffer
+               size_t packetOutLen,           // IN: packet size
+               HgfsSessionInfo *session,      // IN: session info
+               HgfsSendFlags flags)           // IN: flags for how to process
 {
    Bool result = FALSE;
 
    ASSERT(packet);
+   ASSERT(packetOut);
    ASSERT(session);
 
    if (session->state == HGFS_SESSION_STATE_OPEN) {
 #ifndef VMX86_TOOLS
       ASSERT(session->type == HGFS_SESSION_TYPE_REGULAR);
-      result = session->send(session->transportData, packet, packetSize, flags);
+      result = session->channelCbTable->send(session->transportData,
+                                             packet, packetOut,
+                                             packetOutLen, flags);
 #else
       /* This is internal session. */
       ASSERT(session->type == HGFS_SESSION_TYPE_INTERNAL);
-      hgfsStaticSession.bufferOut = packet;
-      hgfsStaticSession.bufferOutLen = packetSize;
+      hgfsStaticSession.bufferOut = packetOut;
+      hgfsStaticSession.bufferOutLen = packetOutLen;
       result = TRUE;
 #endif
    }
@@ -3355,23 +3409,25 @@ HgfsPacketSend(char *packet,                // IN: packet buffer
  */
 
 Bool
-HgfsPackAndSendPacket(char *packet,               // IN: packet to send
-                      size_t packetSize,          // IN: packet size
+HgfsPackAndSendPacket(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                      char *packetOut,            // IN: Output packet to send
+                      size_t packetOutLen,        // IN: Output packet size
                       HgfsInternalStatus status,  // IN: status
                       HgfsHandle id,              // IN: id of the request packet
                       HgfsSessionInfo *session,   // IN: session info
                       HgfsSendFlags flags)        // IN: flags how to send
 {
-   HgfsReply *reply = (HgfsReply *)packet;
+   HgfsReply *reply = (HgfsReply *)packetOut;
 
    ASSERT(packet);
+   ASSERT(packetOut);
    ASSERT(session);
-   ASSERT(packetSize <= HGFS_LARGE_PACKET_MAX);
+   ASSERT(packetOutLen <= HGFS_LARGE_PACKET_MAX);
 
    reply->id = id;
    reply->status = HgfsConvertFromInternalStatus(status);
 
-   return HgfsPacketSend(packet, packetSize, session, flags);
+   return HgfsPacketSend(packet, packetOut, packetOutLen, session, flags);
 }
 
 
@@ -5093,7 +5149,7 @@ HgfsPackOpenV1Reply(HgfsFileOpenInfo *openInfo,   // IN: open info struct
  *    Allocates hgfs reply packet and initializes its header.
  *
  * Results:
- *    Size of the allocated packet.
+ *    TRUE on success, FALSE on failure.
  *
  * Side effects:
  *    None
@@ -5101,24 +5157,31 @@ HgfsPackOpenV1Reply(HgfsFileOpenInfo *openInfo,   // IN: open info struct
  *-----------------------------------------------------------------------------
  */
 
-void
-HgfsAllocInitReply(char const *packetIn,         // IN: incoming packet
+Bool
+HgfsAllocInitReply(HgfsPacket *packet,           // IN/OUT: Hgfs Packet
+                   char const *packetIn,         // IN: incoming packet
                    size_t payloadSize,           // IN: payload size
                    HgfsInternalStatus status,    // IN: reply status
                    char **packetOut,             // OUT: allocated reply
                    void **payload,               // OUT: pointer to the reply payload
-                   size_t *packetSize)           // OUT: size of the allocated packet
+                   size_t *packetSize,           // OUT: size of the allocated packet
+                   HgfsSessionInfo *session)     // IN: Session Info
 {
    HgfsRequest *request = (HgfsRequest *)packetIn;
+   size_t replyPacketSize;
    size_t headerSize = 0; /* Replies prior to V3 do not have a header. */
+   HgfsInternalStatus dummyStatus;
+
    if (HGFS_V4_LEGACY_OPCODE == request->op) {
       headerSize = sizeof(HgfsHeader);
    } else if (request->op < HGFS_OP_CREATE_SESSION_V4 &&
               request->op > HGFS_OP_RENAME_V2) {
       headerSize = sizeof(HgfsReply);
    }
-   *packetSize = headerSize + payloadSize;
-   *packetOut = Util_SafeCalloc(1, *packetSize);
+   replyPacketSize = *packetSize = headerSize + payloadSize;
+   *packetOut = HSPU_GetReplyPacket(packet, &replyPacketSize, session);
+   HGFS_REPLYPKT_CHECK(packetOut, *packetSize, replyPacketSize, dummyStatus, exit);
+
    *payload = *packetOut + headerSize;
    if (HGFS_V4_LEGACY_OPCODE == request->op) {
       HgfsPackReplyHeaderV4(status,
@@ -5129,6 +5192,10 @@ HgfsAllocInitReply(char const *packetIn,         // IN: incoming packet
       HgfsRequest const *request = (HgfsRequest const *)packetIn;
       HgfsPackLegacyReplyHeader(status, request->id, (HgfsReply *)*packetOut);
    }
+
+   return TRUE;
+exit:
+   return FALSE;
 }
 
 
@@ -5149,12 +5216,15 @@ HgfsAllocInitReply(char const *packetIn,         // IN: incoming packet
  */
 
 Bool
-HgfsPackOpenReply(char const *packetIn,         // IN: incoming packet
+HgfsPackOpenReply(HgfsPacket *packet,           // IN/OUT: Hgfs Packet
+                  char const *packetIn,         // IN: incoming packet
                   HgfsInternalStatus status,    // IN: reply status
                   HgfsFileOpenInfo *openInfo,   // IN: open info struct
                   char **packetOut,             // OUT: outgoing packet
-                  size_t *packetSize)           // OUT: size of packet
+                  size_t *packetSize,           // OUT: size of packet
+                  HgfsSessionInfo *session)     // IN: Session info
 {
+   Bool result;
    ASSERT(packetIn);
    ASSERT(openInfo);
    ASSERT(packetSize);
@@ -5166,32 +5236,43 @@ HgfsPackOpenReply(char const *packetIn,         // IN: incoming packet
    case HGFS_OP_OPEN_V3: {
       HgfsReplyOpenV3 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                 (void **)&reply, packetSize, session);
+      if (result == FALSE) {
+         goto error;
+      }
       HgfsPackOpenReplyV3(openInfo, reply);
       break;
    }
    case HGFS_OP_OPEN_V2: {
       HgfsReplyOpenV2 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                 (void **)&reply, packetSize, session);
+      if (result == FALSE) {
+         goto error;
+      }
       HgfsPackOpenV2Reply(openInfo, reply);
       break;
    }
    case HGFS_OP_OPEN: {
       HgfsReplyOpen *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                 (void **)&reply, packetSize, session);
+      if (result == FALSE) {
+         goto error;
+      }
       HgfsPackOpenV1Reply(openInfo, reply);
       break;
    }
    default:
-      return FALSE;
+      goto error;
    }
 
    return TRUE;
+error:
+   return FALSE;
 }
 
 
@@ -5323,7 +5404,7 @@ HgfsUnpackCloseRequest(char const *packetIn,        // IN: request packet
  *    Pack hgfs close reply to the HgfsReplyClose(V3) structure.
  *
  * Results:
- *    Always TRUE.
+ *    TRUE on success, FALSE on failure
  *
  * Side effects:
  *    None
@@ -5332,12 +5413,15 @@ HgfsUnpackCloseRequest(char const *packetIn,        // IN: request packet
  */
 
 Bool
-HgfsPackCloseReply(char const *packetIn,      // IN: incoming packet
-                  HgfsInternalStatus status,  // IN: reply status
-                  HgfsOp op,                  // IN: request type
-                  char **packetOut,           // OUT: outgoing packet
-                  size_t *packetSize)         // OUT: size of packet
+HgfsPackCloseReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                   char const *packetIn,       // IN: incoming packet
+                   HgfsInternalStatus status,  // IN: reply status
+                   HgfsOp op,                  // IN: request type
+                   char **packetOut,           // OUT: outgoing packet
+                   size_t *packetSize,         // OUT: size of packet
+                   HgfsSessionInfo *session)   // IN: Session Info
 {
+   Bool result;
    ASSERT(packetIn);
    ASSERT(packetSize);
 
@@ -5348,23 +5432,23 @@ HgfsPackCloseReply(char const *packetIn,      // IN: incoming packet
    case HGFS_OP_CLOSE_V3: {
       HgfsReplyCloseV3 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    case HGFS_OP_CLOSE: {
       HgfsReplyClose *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    default:
+      result = FALSE;
       NOT_REACHED();
-      return FALSE;
    }
 
-   return TRUE;
+   return result;
 }
 
 
@@ -5497,8 +5581,7 @@ HgfsUnpackSearchCloseRequest(char const *packetIn,        // IN: request packet
  *    Pack hgfs SearchClose reply into a HgfsReplySearchClose(V3) structure.
  *
  * Results:
- *    Always TRUE, except when it is called with a
- *    wrong op (which is a programming error).
+ *    TRUE on success, FALSE on failure.
  *
  * Side effects:
  *    None
@@ -5507,12 +5590,15 @@ HgfsUnpackSearchCloseRequest(char const *packetIn,        // IN: request packet
  */
 
 Bool
-HgfsPackSearchCloseReply(char const *packetIn,       // IN: incoming packet
+HgfsPackSearchCloseReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                         char const *packetIn,       // IN: incoming packet
                          HgfsInternalStatus status,  // IN: reply status
                          HgfsOp op,                  // IN: request type
                          char **packetOut,           // OUT: outgoing packet
-                         size_t *packetSize)         // OUT: size of packet
+                         size_t *packetSize,         // OUT: size of packet
+                         HgfsSessionInfo *session)   // IN: Session Info
 {
+   Bool result;
    ASSERT(packetIn);
    ASSERT(packetSize);
 
@@ -5523,23 +5609,23 @@ HgfsPackSearchCloseReply(char const *packetIn,       // IN: incoming packet
    case HGFS_OP_SEARCH_CLOSE_V3: {
       HgfsReplyCloseV3 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    case HGFS_OP_SEARCH_CLOSE: {
       HgfsReplyClose *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    default:
       NOT_REACHED();
-      return FALSE;
+      result = FALSE;
    }
 
-   return TRUE;
+   return result;
 }
 
 
@@ -5911,11 +5997,13 @@ HgfsUnpackDeleteRequest(char const *packetIn,       // IN: request packet
  */
 
 Bool
-HgfsPackDeleteReply(char const *packetIn,      // IN: incoming packet
+HgfsPackDeleteReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                    char const *packetIn,      // IN: incoming packet
                     HgfsInternalStatus status, // IN: reply status
                     HgfsOp op,                 // IN: requested operation
                     char **packetOut,          // OUT: outgoing packet
-                    size_t *packetSize)        // OUT: size of packet
+                    size_t *packetSize,        // OUT: size of packet
+                    HgfsSessionInfo *session)  // IN: Session Info
 {
    Bool result = TRUE;
    ASSERT(packetIn);
@@ -5930,8 +6018,8 @@ HgfsPackDeleteReply(char const *packetIn,      // IN: incoming packet
    case HGFS_OP_DELETE_DIR_V3: {
       HgfsReplyDeleteV3 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    case HGFS_OP_DELETE_FILE_V2:
@@ -5940,8 +6028,8 @@ HgfsPackDeleteReply(char const *packetIn,      // IN: incoming packet
    case HGFS_OP_DELETE_DIR: {
       HgfsReplyDelete *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    default:
@@ -6319,11 +6407,13 @@ HgfsUnpackRenameRequest(char const *packetIn,       // IN: request packet
  */
 
 Bool
-HgfsPackRenameReply(char const *packetIn,      // IN: incoming packet
+HgfsPackRenameReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                    char const *packetIn,      // IN: incoming packet
                     HgfsInternalStatus status, // IN: reply status
                     HgfsOp op,                 // IN: requested operation
                     char **packetOut,          // OUT: outgoing packet
-                    size_t *packetSize)        // OUT: size of packet
+                    size_t *packetSize,        // OUT: size of packet
+                    HgfsSessionInfo *session)  // IN: Session Info
 {
    Bool result = TRUE;
    ASSERT(packetIn);
@@ -6336,16 +6426,16 @@ HgfsPackRenameReply(char const *packetIn,      // IN: incoming packet
    case HGFS_OP_RENAME_V3: {
       HgfsReplyRenameV3 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    case HGFS_OP_RENAME_V2:
    case HGFS_OP_RENAME: {
       HgfsReplyRename *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
       break;
    }
    default:
@@ -6897,14 +6987,17 @@ HgfsUnpackGetattrRequest(char const *packetIn,       // IN: request packet
  */
 
 Bool
-HgfsPackGetattrReply(char const *packetIn,       // IN: incoming packet
+HgfsPackGetattrReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                     char const *packetIn,       // IN: incoming packet
                      HgfsInternalStatus status,  // IN: reply status
                      HgfsFileAttrInfo *attr,     // IN: attr stucture
                      const char *utf8TargetName, // IN: optional target name
                      uint32 utf8TargetNameLen,   // IN: file name length
                      char **packetOut,           // OUT: outgoing packet
-                     size_t *packetSize)         // OUT: size of packet
+                     size_t *packetSize,         // OUT: size of packet
+                     HgfsSessionInfo *session)   // IN: Session Info
 {
+   Bool result;
    ASSERT(packetIn);
    ASSERT(attr);
 
@@ -6916,11 +7009,15 @@ HgfsPackGetattrReply(char const *packetIn,       // IN: incoming packet
       HgfsReplyGetattrV3 *reply;
       uint32 payloadSize = sizeof *reply + utf8TargetNameLen;
 
-      HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+                                  (void **)&reply, packetSize, session);
+      if (result == FALSE) {
+         goto error;
+      }
+
       if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
          free(reply);
-         return FALSE;
+         goto error;
       }
       HgfsPackGetattrReplyPayloadV3(attr, utf8TargetName, utf8TargetNameLen, reply);
       break;
@@ -6931,11 +7028,15 @@ HgfsPackGetattrReply(char const *packetIn,       // IN: incoming packet
       HgfsRequest *request = (HgfsRequest *)packetIn;
       uint32 payloadSize = sizeof *reply + utf8TargetNameLen;
 
-      HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+                                  (void **)&reply, packetSize, session);
+      if (result == FALSE) {
+         goto error;
+      }
+
       if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
          free(reply);
-         return FALSE;
+         goto error;
       }
       HgfsPackGetattrReplyPayloadV2(request->id,
                                     status,
@@ -6950,8 +7051,12 @@ HgfsPackGetattrReply(char const *packetIn,       // IN: incoming packet
       HgfsReplyGetattr *reply;
       HgfsRequest *request = (HgfsRequest *)packetIn;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                                  (void **)&reply, packetSize, session);
+      if (result == FALSE) {
+         goto error;
+      }
+
       HgfsPackGetattrReplyPayloadV1(request->id, status, attr, reply);
       break;
    }
@@ -6959,11 +7064,11 @@ HgfsPackGetattrReply(char const *packetIn,       // IN: incoming packet
    default:
       LOG(4, ("%s: Invalid GetAttr op.\n", __FUNCTION__));
       NOT_REACHED();
-
-      return FALSE;
+      result =  FALSE;
    }
 
-   return TRUE;
+error:
+   return result;
 }
 
 
@@ -7173,14 +7278,17 @@ HgfsUnpackSearchReadRequest(const char *packetIn,         // IN: request packet
  */
 
 Bool
-HgfsPackSearchReadReply(char const *packetIn,      // IN: incoming packet
+HgfsPackSearchReadReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                        char const *packetIn,      // IN: incoming packet
                         HgfsInternalStatus status, // IN: reply status
                         const char *utf8Name,      // IN: file name
                         size_t utf8NameLen,        // IN: file name length
                         HgfsFileAttrInfo *attr,    // IN: file attr struct
                         char **packetOut,          // OUT: outgoing packet
-                        size_t *packetSize)        // OUT: size of packet
+                        size_t *packetSize,        // OUT: size of packet
+                        HgfsSessionInfo *session)  // IN: Session Info
 {
+   Bool result = TRUE;
    ASSERT(packetIn);
 
    *packetOut = NULL;
@@ -7191,11 +7299,16 @@ HgfsPackSearchReadReply(char const *packetIn,      // IN: incoming packet
       HgfsReplySearchReadV3 *reply;
       uint32 payloadSize = sizeof *reply + utf8NameLen + sizeof(HgfsDirEntry);
 
-      HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
-                         (void **)&reply, packetSize);
+      if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+                                  (void **)&reply, packetSize, session)) {
+         result = FALSE;
+         goto error;
+      }
+
       if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
          free(reply);
-         return FALSE;
+         result = FALSE;
+         goto error;
       }
       HgfsPackSearchReadReplyPayloadV3(attr, utf8Name, utf8NameLen, reply);
       break;
@@ -7205,11 +7318,16 @@ HgfsPackSearchReadReply(char const *packetIn,      // IN: incoming packet
       HgfsReplySearchReadV2 *reply;
       uint32 payloadSize = sizeof *reply + utf8NameLen;
 
-      HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
-                         (void **)&reply, packetSize);
+      if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+                                  (void **)&reply, packetSize, session)) {
+         result = FALSE;
+         goto error;
+      }
+
       if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
          free(reply);
-         return FALSE;
+         result = FALSE;
+         goto error;
       }
       HgfsPackSearchReadReplyPayloadV2(attr,
                                        utf8Name,
@@ -7222,11 +7340,16 @@ HgfsPackSearchReadReply(char const *packetIn,      // IN: incoming packet
       HgfsReplySearchRead *reply;
       uint32 payloadSize = sizeof *reply + utf8NameLen;
 
-      HgfsAllocInitReply(packetIn, payloadSize, status, packetOut,
-                         (void **)&reply, packetSize);
+      if (!HgfsAllocInitReply(packet, packetIn, payloadSize, status, packetOut,
+                                  (void **)&reply, packetSize, session)) {
+         result = FALSE;
+         goto error;
+      }
+
       if (!HgfsValidateReplySize(packetIn, attr->requestType, *packetSize)) {
          free(reply);
-         return FALSE;
+         result = FALSE;
+         goto error;
       }
       HgfsPackSearchReadReplyPayloadV1(attr,
                                        utf8Name,
@@ -7238,11 +7361,12 @@ HgfsPackSearchReadReply(char const *packetIn,      // IN: incoming packet
    default: {
       LOG(4, ("%s: Invalid SearchRead Op.", __FUNCTION__));
       NOT_REACHED();
-      return FALSE;
+      result = FALSE;
    }
    }
 
-   return TRUE;
+error:
+   return result;
 }
 
 
@@ -7544,11 +7668,13 @@ HgfsUnpackSetattrRequest(char const *packetIn,       // IN: request packet
  */
 
 Bool
-HgfsPackSetattrReply(char const *packetIn,      // IN: incoming packet
+HgfsPackSetattrReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                     char const *packetIn,      // IN: incoming packet
                      HgfsInternalStatus status, // IN: reply status
                      HgfsOp op,                 // IN: request type
                      char **packetOut,          // OUT: outgoing packet
-                     size_t *packetSize)        // OUT: size of packet
+                     size_t *packetSize,        // OUT: size of packet
+                     HgfsSessionInfo *session)  // IN: Session Info
 {
    Bool result = TRUE;
 
@@ -7561,16 +7687,16 @@ HgfsPackSetattrReply(char const *packetIn,      // IN: incoming packet
    case HGFS_OP_SETATTR_V3: {
       HgfsReplySetattrV3 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                         (void **)&reply, packetSize, session);
       break;
    }
    case HGFS_OP_SETATTR_V2:
    case HGFS_OP_SETATTR: {
       HgfsReplySetattr *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                         (void **)&reply, packetSize, session);
       break;
    }
    default:
@@ -7842,11 +7968,13 @@ HgfsUnpackCreateDirRequest(char const *packetIn,    // IN: incoming packet
  */
 
 Bool
-HgfsPackCreateDirReply(char const *packetIn,      // IN: create dir operation version
+HgfsPackCreateDirReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                       char const *packetIn,      // IN: create dir operation version
                        HgfsInternalStatus status, // IN: reply status
                        HgfsOp op,                 // IN: request type
                        char **packetOut,          // OUT: outgoing packet
-                       size_t *packetSize)        // OUT: size of packet
+                       size_t *packetSize,        // OUT: size of packet
+                       HgfsSessionInfo *session)  // IN: Session Info
 {
    Bool result = TRUE;
 
@@ -7859,22 +7987,22 @@ HgfsPackCreateDirReply(char const *packetIn,      // IN: create dir operation ve
    case HGFS_OP_CREATE_DIR_V3: {
       HgfsReplyCreateDirV3 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                         (void **)&reply, packetSize, session);
       break;
    }
    case HGFS_OP_CREATE_DIR_V2: {
       HgfsReplyCreateDirV2 *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                         (void **)&reply, packetSize, session);
       break;
    }
    case HGFS_OP_CREATE_DIR: {
       HgfsReplyCreateDir *reply;
 
-      HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                         (void **)&reply, packetSize);
+      result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                         (void **)&reply, packetSize, session);
       break;
    }
    default:
@@ -8003,14 +8131,17 @@ HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
  */
 
 Bool
-HgfsPackWriteWin32StreamReply(char const *packetIn,      // IN: incoming packet
-                                            HgfsInternalStatus status, // IN: reply status
+HgfsPackWriteWin32StreamReply(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                              char const *packetIn,      // IN: incoming packet
+                             HgfsInternalStatus status, // IN: reply status
                               HgfsOp op,                 // IN: request type
-                                            uint32 actualSize,         // IN: amount written
-                                            char **packetOut,          // OUT: outgoing packet
-                                            size_t *packetSize)        // OUT: size of packet
+                             uint32 actualSize,         // IN: amount written
+                             char **packetOut,          // OUT: outgoing packet
+                             size_t *packetSize,        // OUT: size of packet
+                              HgfsSessionInfo *session)  // IN:Session Info
 {
    HgfsReplyWriteWin32StreamV3 *reply;
+   Bool result;
 
    ASSERT(packetIn);
 
@@ -8022,11 +8153,13 @@ HgfsPackWriteWin32StreamReply(char const *packetIn,      // IN: incoming packet
       return FALSE;
    }
 
-   HgfsAllocInitReply(packetIn, sizeof *reply, status, packetOut,
-                      (void **)&reply, packetSize);
-   reply->actualSize = actualSize;
+   result = HgfsAllocInitReply(packet, packetIn, sizeof *reply, status, packetOut,
+                              (void **)&reply, packetSize, session);
+   if (result != FALSE) {
+      reply->actualSize = actualSize;
+   }
 
-   return TRUE;
+   return result;
 }
 
 
index 83e493726d5bd3475a8707fd55f13b2eab843d27..34f8c0aa242b3421d2b4d195a05b4ddf2ef9b841 100644 (file)
 #  define HGFS_LOCK_DESTROY(lock)   MXUser_DestroyExclLock(lock)
 #endif
 
+#ifdef _WIN32
+# define HGFS_REPLYPKT_STATUS  RPC_S_PROTOCOL_ERROR
+#else
+# define HGFS_REPLYPKT_STATUS  EPROTO
+#endif
+
+#define HGFS_REPLYPKT_CHECK(replyPacket, replySize, replyPacketSize, status, label)  \
+   do {                                                         \
+      LOG(4, ("%s: \n", __FUNCTION__));                         \
+      ASSERT_DEVEL(replyPacket);                                \
+      if (!replyPacket || ((replySize) > (replyPacketSize))) {  \
+         status = HGFS_REPLYPKT_STATUS;                         \
+         goto label;                                            \
+      }                                                         \
+   } while(0)
+
 
 /*
  * Does this platform have oplock support? We define it here to avoid long
@@ -305,8 +321,8 @@ typedef struct HgfsSessionInfo {
    /* Session is dynamic or internal. */
    HgfsSessionInfoType type;
 
-   /* Function to send reply for a packet after processing. */
-   HgfsSessionSendFunc *send;
+   /* Function callbacks into Hgfs Channels. */
+   HgfsServerChannelCallbacks *channelCbTable;
 
    /* Lock to ensure some fileIO requests are atomic for a handle. */
    HgfsLock *fileIOLock;
@@ -438,6 +454,14 @@ typedef struct {
    HgfsServerLock serverLock;
 } ServerLockData;
 
+typedef
+struct HgfsInputParam {
+   const char *metaPacket;
+   size_t metaPacketSize;
+   HgfsSessionInfo *session;
+   HgfsPacket *packet;
+}
+HgfsInputParam;
 
 Bool
 HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct
@@ -524,79 +548,49 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName,     // IN: Name enumerator
  */
 
 HgfsInternalStatus
-HgfsServerOpen(char const *packetIn,       // IN: incoming packet
-               size_t packetSize,          // IN: size of packet
-               HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerOpen(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerRead(char const *packetIn,       // IN: incoming packet
-               size_t packetSize,          // IN: size of packet
-               HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerRead(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerWrite(char const *packetIn,       // IN: incoming packet
-                size_t packetSize,          // IN: size of packet
-                HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerWrite(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerSearchOpen(char const *packetIn,       // IN: incoming packet
-                     size_t packetSize,          // IN: size of packet
-                     HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerSearchOpen(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerSearchRead(char const *packetIn,       // IN: incoming packet
-                     size_t packetSize,          // IN: size of packet
-                     HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerSearchRead(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerGetattr(char const *packetIn,       // IN: incoming packet
-                  size_t packetSize,          // IN: size of packet
-                  HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerGetattr(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerSetattr(char const *packetIn,       // IN: incoming packet
-                  size_t packetSize,          // IN: size of packet
-                  HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerSetattr(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerCreateDir(char const *packetIn,       // IN: incoming packet
-                    size_t packetSize,          // IN: size of packet
-                    HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerCreateDir(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerDeleteFile(char const *packetIn,       // IN: incoming packet
-                     size_t packetSize,          // IN: size of packet
-                     HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerDeleteFile(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerDeleteDir(char const *packetIn,       // IN: incoming packet
-                    size_t packetSize,          // IN: size of packet
-                    HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerDeleteDir(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerRename(char const *packetIn,      // IN: incoming packet
-                 size_t packetSize,          // IN: size of packet
-                 HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerRename(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerQueryVolume(char const *packetIn,       // IN: incoming packet
-                      size_t packetSize,          // IN: size of packet
-                      HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerQueryVolume(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerSymlinkCreate(char const *packetIn,       // IN: incoming packet
-                        size_t packetSize,          // IN: size of packet
-                        HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerSymlinkCreate(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerServerLockChange(char const *packetIn,       // IN: incoming packet
-                           size_t packetSize,          // IN: size of packet
-                           HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerServerLockChange(HgfsInputParam *input);  // IN: Input params
 
 HgfsInternalStatus
-HgfsServerWriteWin32Stream(char const *packetIn,       // IN: incoming packet
-                           size_t packetSize,          // IN: size of packet
-                           HgfsSessionInfo *session);  // IN: opaque transport data
+HgfsServerWriteWin32Stream(HgfsInputParam *input);  // IN: Input params
 
 /* Unpack/pack requests/reply helper functions. */
 
@@ -606,12 +600,13 @@ HgfsUnpackOpenRequest(char const *packetIn,        // IN: incoming packet
                      HgfsFileOpenInfo *openInfo);  // IN/OUT: open info struct
 
 Bool
-HgfsPackOpenReply(char const *packetIn,         // IN: incoming packet
-                  HgfsInternalStatus status,    // IN: reply status
-                  HgfsFileOpenInfo *openInfo,   // IN: open info struct
-                  char **packetOut,             // OUT: outgoing packet
-                  size_t *packetSize);          // OUT: outgoing packet size
-
+HgfsPackOpenReply(HgfsPacket *packet,            // IN/OUT: Hgfs Packet
+                  char const *packetIn,          // IN: incoming packet
+                  HgfsInternalStatus status,     // IN: reply status
+                  HgfsFileOpenInfo *openInfo,    // IN: open info struct
+                  char **packetOut,              // OUT: outgoing packet
+                  size_t *packetSize,            // OUT: size of packet
+                  HgfsSessionInfo *session);     // IN: Session info
 Bool
 HgfsUnpackGetattrRequest(char const *packetIn,       // IN: request packet
                          size_t packetSize,          // IN: request packet size
@@ -633,11 +628,13 @@ HgfsUnpackDeleteRequest(char const *packetIn,       // IN: request packet
                         uint32 *caseFlags);         // OUT: case-sensitivity flags
 
 Bool
-HgfsPackDeleteReply(char const *packetIn,          // IN: incoming packet
-                    HgfsInternalStatus status,     // IN: reply status
-                    HgfsOp op,                     // IN: requested operation
-                    char **packetOut,              // OUT: outgoing packet
-                    size_t *packetSize);           // OUT: size of packet
+HgfsPackDeleteReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                    char const *packetIn,       // IN: incoming packet
+                    HgfsInternalStatus status,  // IN: reply status
+                    HgfsOp op,                  // IN: requested operation
+                    char **packetOut,           // OUT: outgoing packet
+                    size_t *packetSize,         // OUT: size of packet
+                    HgfsSessionInfo *session);  // IN: Session Info
 
 Bool
 HgfsUnpackRenameRequest(char const *packetIn,       // IN: request packet
@@ -654,21 +651,24 @@ HgfsUnpackRenameRequest(char const *packetIn,       // IN: request packet
                         uint32 *newCaseFlags);      // OUT: new case-sensitivity flags
 
 Bool
-HgfsPackRenameReply(char const *packetIn,      // IN: incoming packet
-                    HgfsInternalStatus status, // IN: reply status
-                    HgfsOp op,                 // IN: requested operation
-                    char **packetOut,          // OUT: outgoing packet
-                    size_t *packetSize);       // OUT: size of packet
+HgfsPackRenameReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                    char const *packetIn,       // IN: incoming packet
+                    HgfsInternalStatus status,  // IN: reply status
+                    HgfsOp op,                  // IN: requested operation
+                    char **packetOut,           // OUT: outgoing packet
+                    size_t *packetSize,         // OUT: size of packet
+                    HgfsSessionInfo *session);  // IN: Session Info
 
 Bool
-HgfsPackGetattrReply(char const *packetIn,       // IN: incoming packet
-                     HgfsInternalStatus status,  // IN: reply status
-                     HgfsFileAttrInfo *attr,     // IN: attr stucture
-                     const char *utf8TargetName, // IN: optional target name
-                     uint32 utf8TargetNameLen,   // IN: file name length
-                     char **packetOut,           // OUT: outgoing packet
-                     size_t *packetSize);        // OUT: size of packet
-
+HgfsPackGetattrReply(HgfsPacket *packet,          // IN/OUT: Hgfs packet
+                     char const *packetIn,        // IN: incoming packet
+                     HgfsInternalStatus status,   // IN: reply status
+                     HgfsFileAttrInfo *attr,      // IN: attr stucture
+                     const char *utf8TargetName,  // IN: optional target name
+                     uint32 utf8TargetNameLen,    // IN: file name length
+                     char **packetOut,            // OUT: outgoing packet
+                     size_t *packetSize,          // OUT: size of packet
+                     HgfsSessionInfo *session);   // IN: Session Info
 Bool
 HgfsUnpackSearchReadRequest(const char *packetIn,         // IN: request packet
                             size_t packetSize,            // IN: packet size
@@ -677,13 +677,15 @@ HgfsUnpackSearchReadRequest(const char *packetIn,         // IN: request packet
                             uint32 *offset);              // OUT: entry offset
 
 Bool
-HgfsPackSearchReadReply(char const *packetIn,      // IN: incoming packet
-                        HgfsInternalStatus status, // IN: reply status
-                        const char *utf8Name,      // IN: file name
-                        size_t utf8NameLen,        // IN: file name length
-                        HgfsFileAttrInfo *attr,    // IN: file attr struct
-                        char **packetOut,          // OUT: outgoing packet
-                        size_t *packetSize);       // OUT: size of packet
+HgfsPackSearchReadReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                        char const *packetIn,       // IN: incoming packet
+                        HgfsInternalStatus status,  // IN: reply status
+                        const char *utf8Name,       // IN: file name
+                        size_t utf8NameLen,         // IN: file name length
+                        HgfsFileAttrInfo *attr,     // IN: file attr struct
+                        char **packetOut,           // OUT: outgoing packet
+                        size_t *packetSize,         // OUT: size of packet
+                        HgfsSessionInfo *session);  // IN: Session Info
 
 Bool
 HgfsUnpackSetattrRequest(char const *packetIn,            // IN: request packet
@@ -696,12 +698,13 @@ HgfsUnpackSetattrRequest(char const *packetIn,            // IN: request packet
                          uint32 *caseFlags);              // OUT: case-sensitivity flags
 
 Bool
-HgfsPackSetattrReply(char const *packetIn,       // IN: setattrOp operation version
+HgfsPackSetattrReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                     char const *packetIn,       // IN: incoming packet
                      HgfsInternalStatus status,  // IN: reply status
                      HgfsOp op,                  // IN: request type
                      char **packetOut,           // OUT: outgoing packet
-                     size_t *packetSize);        // OUT: size of packet
-
+                     size_t *packetSize        // OUT: size of packet
+                     HgfsSessionInfo *session);  // IN: Session Info
 
 Bool
 HgfsUnpackCreateDirRequest(char const *packetIn,     // IN: incoming packet
@@ -709,11 +712,13 @@ HgfsUnpackCreateDirRequest(char const *packetIn,     // IN: incoming packet
                            HgfsCreateDirInfo *info); // IN/OUT: info struct
 
 Bool
-HgfsPackCreateDirReply(char const *packetIn,      // IN: incoming packet
-                       HgfsInternalStatus status, // IN: reply status
-                       HgfsOp op,                 // IN: request type
-                       char **packetOut,          // OUT: outgoing packet
-                       size_t *packetSize);       // OUT: size of packet
+HgfsPackCreateDirReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                       char const *packetIn,       // IN: create dir operation version
+                       HgfsInternalStatus status , // IN: reply status
+                       HgfsOp op,                  // IN: request type
+                       char **packetOut,           // OUT: outgoing packet
+                       size_t *packetSize,         // OUT: size of packet
+                       HgfsSessionInfo *session);  // IN: Session Info
 
 Bool
 HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
@@ -725,34 +730,44 @@ HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
                                   Bool *doSecurity);    // OUT: restore sec.str.
 
 Bool
-HgfsPackWriteWin32StreamReply(char const *packetIn,      // IN: incoming packet
-                              HgfsInternalStatus status, // IN: reply status
-                              HgfsOp op,                 // IN: request type
-                              uint32 actualSize,         // IN: amount written
-                              char **packetOut,          // OUT: outgoing packet
-                              size_t *packetSize);       // OUT: size of packet
+HgfsPackWriteWin32StreamReply(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                              char const *packetIn,       // IN: incoming packet
+                             HgfsInternalStatus status,  // IN: reply status
+                              HgfsOp op,                  // IN: request type
+                             uint32 actualSize,          // IN: amount written
+                             char **packetOut,           // OUT: outgoing packet
+                             size_t *packetSize,         // OUT: size of packet
+                              HgfsSessionInfo *session);  // IN:Session Info
+
 Bool
 HgfsUnpackCloseRequest(char const *packetIn,        // IN: request packet
                        size_t packetSize,           // IN: request packet size
                        HgfsOp *op,                  // OUT: request type
                        HgfsHandle *file);           // OUT: Handle to close
+
 Bool
-HgfsPackCloseReply(char const *packetIn,      // IN: incoming packet
-                  HgfsInternalStatus status,  // IN: reply status
-                  HgfsOp op,                  // IN: request type
-                  char **packetOut,           // OUT: outgoing packet
-                  size_t *packetSize);        // OUT: size of packet
+HgfsPackCloseReply(HgfsPacket *packet,          // IN/OUT: Hgfs Packet
+                   char const *packetIn,        // IN: incoming packet
+                   HgfsInternalStatus status,   // IN: reply status
+                   HgfsOp op,                   // IN: request type
+                   char **packetOut,            // OUT: outgoing packet
+                   size_t *packetSize,          // OUT: size of packet
+                   HgfsSessionInfo *session);   // IN: Session Info
+
 Bool
 HgfsUnpackSearchCloseRequest(char const *packetIn,        // IN: request packet
                              size_t packetSize,           // IN: request packet size
                              HgfsOp *op,                  // OUT: request type
                              HgfsHandle *file);           // OUT: Handle to close
+
 Bool
-HgfsPackSearchCloseReply(char const *packetIn,      // IN: incoming packet
-                         HgfsInternalStatus status,  // IN: reply status
-                         HgfsOp op,                  // IN: request type
-                         char **packetOut,           // OUT: outgoing packet
-                         size_t *packetSize);        // OUT: size of packet
+HgfsPackSearchCloseReply(HgfsPacket *packet,          // IN/OUT: Hgfs Packet
+                         char const *packetIn,        // IN: incoming packet
+                         HgfsInternalStatus status,   // IN: reply status
+                         HgfsOp op,                   // IN: request type
+                         char **packetOut,            // OUT: outgoing packet
+                         size_t *packetSize,          // OUT: size of packet
+                         HgfsSessionInfo *session);   // IN: Session Info
 
 /* Node cache functions. */
 
@@ -909,21 +924,83 @@ HgfsAckOplockBreak(ServerLockData *lockData,  // IN: server lock info
 
 /* Transport related functions. */
 Bool
-HgfsPackAndSendPacket(char *packet,               // IN: packet to send
-                      size_t packetSize,          // IN: packet size
-                      HgfsInternalStatus status,  // IN: status
-                      HgfsHandle id,              // IN: id of the request packet
-                      HgfsSessionInfo *session,   // IN: session info
-                      HgfsSendFlags flags);       // IN: flags how to send
+HgfsPackAndSendPacket(HgfsPacket *packet,           // IN/OUT: Hgfs Packet
+                      char *packetOut,              // IN: Output packet to send
+                      size_t packetOutLen,          // IN: Output packet size
+                      HgfsInternalStatus status,    // IN: status
+                      HgfsHandle id,                // IN: id of the request packet
+                      HgfsSessionInfo *session,     // IN: session info
+                      HgfsSendFlags flags);         // IN: flags how to send
 
 Bool
-HgfsPacketSend(char *packet,                // IN: packet buffer
-               size_t packetSize,           // IN: packet size
-               HgfsSessionInfo *session,    // IN: session info
-               HgfsSendFlags flags);        // IN: flags how to send
+HgfsPacketSend(HgfsPacket *packet,            // IN/OUT: Hgfs Packet
+               char *packetOut,               // IN: Output packet buffer
+               size_t packetOutLen,           // IN: Output packet size
+               HgfsSessionInfo *session,      // IN: session info
+               HgfsSendFlags flags);          // IN: flags how to send
 
 Bool
 HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo, // IN: Hgfs file handle
                                  HgfsOpenFlags *flags);      // IN/OUT: open mode
 
+
+void *
+HSPU_GetBuf(HgfsPacket *packet,           // IN/OUT: Hgfs Packet
+            uint32 startIndex,            // IN: start index of iov
+            void **buf,                   // OUT: Contigous buffer
+            size_t bufSize,               // IN: Size of buffer
+            Bool *isAllocated,            // OUT: Was buffer allocated ?
+            uint32 mappingType,           // IN: Readable/ Writeable ?
+            HgfsSessionInfo *session);    // IN: Session Info
+
+void *
+HSPU_GetMetaPacket(HgfsPacket *packet,          // IN/OUT: Hgfs Packet
+                   size_t *metaPacketSize,      // OUT: Size of metaPacket
+                   HgfsSessionInfo *session);   // IN: Session Info
+
+void *
+HSPU_GetDataPacketBuf(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                      uint32 mappingType,        // IN: Readable/ Writeable ?
+                      HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_PutPacket(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+              HgfsSessionInfo *session);  // IN: Session Info
+
+void
+HSPU_PutBuf(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+            uint32 startIndex,         // IN: Start of iov
+            void **buf,                // IN/OUT: Buffer to be freed
+            size_t *bufSize,           // IN: Size of the buffer
+           Bool *isAllocated,         // IN: Was buffer allocated ?
+            uint32 mappingType,        // IN: Readable/ Writeable ?
+           HgfsSessionInfo *session); // IN: Session info
+
+void
+HSPU_PutDataPacketBuf(HgfsPacket *packet,         // IN/OUT: Hgfs Packet
+                      HgfsSessionInfo *session);  // IN: Session Info
+
+void
+HSPU_PutMetaPacket(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                   HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_CopyBufToDataIovec(HgfsPacket *packet,       // IN/OUT: Hgfs packet
+                        void *buf,                // IN: Buffer to copy from
+                        uint32 bufSize,           // IN: Size of buffer
+                        HgfsSessionInfo *session);// IN: Session Info
+void
+HSPU_CopyBufToIovec(HgfsPacket *packet,       // IN/OUT: Hgfs Packet
+                    uint32 startIndex,        // IN: start index into iov
+                    void *buf,                // IN: Buffer
+                    size_t bufSize,           // IN: Size of buffer
+                    HgfsSessionInfo *session); // IN: Session Info
+void *
+HSPU_GetReplyPacket(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                    size_t *replyPacketSize,   //IN/OUT: Size of reply Packet
+                    HgfsSessionInfo *session); // IN: Session Info
+
+void
+HSPU_PutReplyPacket(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                    HgfsSessionInfo *session); // IN: Session Info
 #endif /* __HGFS_SERVER_INT_H__ */
index 095fb07df96a1bf718775a9648b0518f2161c651..b5eda9ff2b27d05890f6ef4a2b1d0e73abadd0b2 100644 (file)
@@ -3397,10 +3397,11 @@ HgfsServerScandir(char const *baseDir,      // IN: Directory to search in
  */
 
 HgfsInternalStatus
-HgfsServerOpen(char const *packetIn,     // IN: incoming packet
-               size_t packetSize,        // IN: size of packet
-               HgfsSessionInfo *session) // IN: session info
+HgfsServerOpen(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsNameStatus nameStatus;
    HgfsInternalStatus status;
    int newFd = -1;
@@ -3519,10 +3520,10 @@ HgfsServerOpen(char const *packetIn,     // IN: incoming packet
          goto exit;
       }
 
-      if (HgfsPackOpenReply(packetIn, status, &openInfo, &packetOut,
-                            &packetOutSize)) {
-         if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-            free(packetOut);
+      if (HgfsPackOpenReply(input->packet, packetIn, status, &openInfo, &packetOut,
+                            &packetOutSize, session)) {
+         if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+            HSPU_PutReplyPacket(input->packet, session);
          }
       } else {
          status = EPROTO;
@@ -3563,10 +3564,10 @@ HgfsServerOpen(char const *packetIn,     // IN: incoming packet
  */
 
 HgfsInternalStatus
-HgfsServerRead(char const *packetIn,     // IN: incoming packet
-               size_t packetSize,        // IN: size of packet
-               HgfsSessionInfo *session) // IN: session info
+HgfsServerRead(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   HgfsSessionInfo *session = input->session;
    HgfsRequest *header = (HgfsRequest *)packetIn;
    int fd;
    int error;
@@ -3579,12 +3580,38 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
    char *payload;
    uint32 *replyActualSize;
    size_t replySize;
+   size_t replyPacketSize;
    char *packetOut;
 
    ASSERT(packetIn);
    ASSERT(session);
 
-   if (header->op == HGFS_OP_READ_V3) {
+   if (header->op == HGFS_OP_READ_FAST_V3) {
+      HgfsRequestReadV3 *request =
+                        (HgfsRequestReadV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
+      HgfsReplyReadV3 *reply;
+
+      file = request->file;
+      offset = request->offset;
+      requiredSize = request->requiredSize;
+
+      replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply) - 1;
+      /* Get a data packet buffer that is writeable */
+      payload = HSPU_GetDataPacketBuf(input->packet, HGFS_BUF_WRITEABLE, session);
+      if (!payload) {
+         ASSERT_DEVEL(payload);
+         status = EPROTO;
+         goto error;
+      }
+      replyPacketSize = replySize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
+      reply = (HgfsReplyReadV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
+
+      replyActualSize = &reply->actualSize;
+      reply->reserved = 0;
+
+   } else if (header->op == HGFS_OP_READ_V3) {
       HgfsRequestReadV3 *request =
                         (HgfsRequestReadV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
       HgfsReplyReadV3 *reply;
@@ -3598,18 +3625,19 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
       extra = HGFS_LARGE_PACKET_MAX - replySize;
 
       /*
-       * requiredSize is user-provided, so this test must be carefully
-       * written to prevent wraparounds.
-       */
+      * requiredSize is user-provided, so this test must be carefully
+      * written to prevent wraparounds.
+      */
       if (requiredSize > extra) {
          /*
           * The client wants to read more bytes than our payload can handle.
           * Truncate the request
           */
-         requiredSize = extra;
+        requiredSize = extra;
       }
-
-      packetOut = Util_SafeMalloc(replySize + requiredSize);
+      replyPacketSize = replySize + requiredSize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize + requiredSize, replyPacketSize, status, error);
       reply = (HgfsReplyReadV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
       payload = reply->payload;
       replyActualSize = &reply->actualSize;
@@ -3638,7 +3666,9 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
          requiredSize = extra;
       }
 
-      packetOut = Util_SafeMalloc(replySize + requiredSize);
+      replyPacketSize = replySize + requiredSize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize + requiredSize, replyPacketSize, status, error);
       reply = (HgfsReplyRead *)packetOut;
       payload = reply->payload;
       replyActualSize = &reply->actualSize;
@@ -3652,14 +3682,13 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
 
    if (status != 0) {
       LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
-      free(packetOut);
-      return status;
+      goto error;
    }
 
    if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
       LOG(4, ("%s: Could not get sequenial open status\n", __FUNCTION__));
-      free(packetOut);
-      return EBADF;
+      status = EBADF;
+      goto error;
    }
 
 #if defined(GLIBC_VERSION_21) || defined(__APPLE__)
@@ -3712,17 +3741,23 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
 
    LOG(4, ("%s: read %d bytes\n", __FUNCTION__, error));
    *replyActualSize = error;
-   replySize += error;
+
+   if (header->op == HGFS_OP_READ_FAST_V3) {
+      HSPU_PutDataPacketBuf(input->packet, session);
+   } else {
+      replySize += error;
+   }
 
    /* Send the reply. */
-   if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id, session, 0)) {
+   if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize, 0,
+                              header->id, session, 0)) {
       status = 0;
       goto error;
    }
-   return 0;
 
+   return 0;
 error:
-   free(packetOut);
+   HSPU_PutReplyPacket(input->packet, session);
    return status;
 }
 
@@ -3745,12 +3780,12 @@ error:
  */
 
 HgfsInternalStatus
-HgfsServerWrite(char const *packetIn,     // IN: incoming packet
-                size_t packetSize,        // IN: size of packet
-                HgfsSessionInfo *session) // IN: session info
+HgfsServerWrite(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsRequest *header = (HgfsRequest *)packetIn;
-   uint32 extra;
    HgfsInternalStatus status;
    int fd;
    int error;
@@ -3762,38 +3797,84 @@ HgfsServerWrite(char const *packetIn,     // IN: incoming packet
    char *payload;
    uint32 *actualSize;
    size_t replySize;
+   size_t replyPacketSize;
    char *packetOut;
 
    ASSERT(packetIn);
    ASSERT(session);
 
-   if (header->op == HGFS_OP_WRITE_V3) {
+   if (header->op == HGFS_OP_WRITE_FAST_V3) {
       HgfsRequestWriteV3 *request;
       HgfsReplyWriteV3 *reply;
 
       replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
-      packetOut = Util_SafeMalloc(replySize);
+      replyPacketSize = replySize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
 
       request = (HgfsRequestWriteV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
       reply = (HgfsReplyWriteV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
 
       /* Enforced by the dispatch function */
       ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
-      extra = packetSize - (HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
 
       file = request->file;
       flags = request->flags;
       offset = request->offset;
-      payload = request->payload;
       requiredSize = request->requiredSize;
+      reply->reserved = 0;
       actualSize = &reply->actualSize;
+      /* Get a data packet buffer that is readable */
+      payload = HSPU_GetDataPacketBuf(input->packet, HGFS_BUF_READABLE, session);
+      if (!payload) {
+         ASSERT_DEVEL(payload);
+         status = EPROTO;
+         goto error;
+      }
+
+   } else if (header->op == HGFS_OP_WRITE_V3) {
+      HgfsRequestWriteV3 *request;
+      HgfsReplyWriteV3 *reply;
+      uint32 extra;
+
+      replySize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+      replyPacketSize = replySize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
+
+      request = (HgfsRequestWriteV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
+      reply = (HgfsReplyWriteV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
+
+      /* Enforced by the dispatch function */
+      ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
+      extra = packetSize - (HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
+
+      file = request->file;
+      flags = request->flags;
+      offset = request->offset;
+      requiredSize = request->requiredSize;
       reply->reserved = 0;
+      actualSize = &reply->actualSize;
+
+      payload = request->payload;
+
+      /*
+       * requiredSize is user-provided, so this test must be carefully
+       * written to prevent wraparounds.
+       */
+      if (requiredSize > extra) {
+         requiredSize = extra;
+      }
+
    } else {
       HgfsRequestWrite *request;
       HgfsReplyWrite *reply;
+      uint32 extra;
 
       replySize = sizeof *reply;
-      packetOut = Util_SafeMalloc(replySize);
+      replyPacketSize = replySize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, error);
 
       request = (HgfsRequestWrite *)packetIn;
       reply = (HgfsReplyWrite *)packetOut;
@@ -3808,10 +3889,18 @@ HgfsServerWrite(char const *packetIn,     // IN: incoming packet
       payload = request->payload;
       requiredSize = request->requiredSize;
       actualSize = &reply->actualSize;
+
+      /*
+       * requiredSize is user-provided, so this test must be carefully
+       * written to prevent wraparounds.
+       */
+      if (requiredSize > extra) {
+         requiredSize = extra;
+      }
    }
 
-   LOG(4, ("%s: write fh %u, offset %"FMT64"u, count %u, extra %u\n",
-           __FUNCTION__, file, offset, requiredSize, extra));
+   LOG(4, ("%s: write fh %u, offset %"FMT64"u, count %u\n",
+           __FUNCTION__, file, offset, requiredSize));
 
    /* Get the file desriptor from the cache */
    status = HgfsGetFd(file, session, ((flags & HGFS_WRITE_APPEND) ?
@@ -3820,26 +3909,13 @@ HgfsServerWrite(char const *packetIn,     // IN: incoming packet
 
    if (status != 0) {
       LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
-      free(packetOut);
-      return status;
+      goto error;
    }
 
    if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
       LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__));
-      free(packetOut);
-      return EBADF;
-   }
-
-   /*
-    * requiredSize is user-provided, so this test must be carefully
-    * written to prevent wraparounds.
-    */
-   if (requiredSize > extra) {
-      /*
-       * The driver wants to write more bytes than there is in its payload.
-       * Truncate the request
-       */
-      requiredSize = extra;
+      status = EBADF;
+      goto error;
    }
 
 #if defined(GLIBC_VERSION_21) || defined(__APPLE__)
@@ -3893,14 +3969,19 @@ HgfsServerWrite(char const *packetIn,     // IN: incoming packet
    *actualSize = error;
    status = 0;
 
-   if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id,
-                              session, 0)) {
+   if (header->op == HGFS_OP_WRITE_FAST_V3) {
+      HSPU_PutDataPacketBuf(input->packet, session);
+   }
+
+   if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize,
+                              0, header->id, session, 0)) {
       goto error;
    }
+
    return 0;
 
 error:
-   free(packetOut);
+   HSPU_PutReplyPacket(input->packet, session);
    return status;
 }
 
@@ -3923,10 +4004,11 @@ error:
  */
 
 HgfsInternalStatus
-HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
-                     size_t packetSize,        // IN: size of packet
-                     HgfsSessionInfo *session) // IN: session info
+HgfsServerSearchOpen(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsRequest *header;
    HgfsHandle *replySearch;
    uint32 extra;
@@ -3939,6 +4021,7 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
    uint32 dirNameLength;
    HgfsCaseType caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
    size_t replySize;
+   size_t replyPacketSize;
    char *packetOut;
    HgfsShareInfo shareInfo;
 
@@ -3951,7 +4034,9 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
       HgfsReplySearchOpenV3 *replyV3;
 
       replySize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
-      packetOut = Util_SafeMalloc(replySize);
+      replyPacketSize = replySize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, exit);
 
       requestV3 = (HgfsRequestSearchOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
       replyV3 = (HgfsReplySearchOpenV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
@@ -3970,7 +4055,9 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
       HgfsRequestSearchOpen *request = (HgfsRequestSearchOpen *)packetIn;
 
       replySize = sizeof (HgfsReplySearchOpen);
-      packetOut = Util_SafeMalloc(replySize);
+      replyPacketSize = replySize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, replySize, replyPacketSize, status, exit);
 
       /* Enforced by the dispatch function */
       ASSERT(packetSize >= sizeof *request);
@@ -4087,15 +4174,15 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
     */
    *replySearch = handle;
 
-   if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id,
-                              session, 0)) {
+   if (!HgfsPackAndSendPacket(input->packet, packetOut, replySize,
+                              0, header->id, session, 0)) {
       status = 0;
       goto exit;
    }
    return 0;
 
 exit:
-   free(packetOut);
+   HSPU_PutReplyPacket(input->packet, session);
    return status;
 }
 
@@ -4118,10 +4205,11 @@ exit:
  */
 
 HgfsInternalStatus
-HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
-                     size_t packetSize,        // IN: size of packet
-                     HgfsSessionInfo *session) // IN: session info
+HgfsServerSearchRead(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    uint32 requestedOffset;
    HgfsFileAttrInfo attr;
    HgfsInternalStatus status;
@@ -4319,8 +4407,8 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
        * since what filesystems allow dent lengths as high as 6144 bytes?
        */
       status = 0;
-      if (!HgfsPackSearchReadReply(packetIn, status, entryName, entryNameLen,
-                                   &attr, &packetOut, &packetOutSize)) {
+      if (!HgfsPackSearchReadReply(input->packet, packetIn, status, entryName, entryNameLen,
+                                   &attr, &packetOut, &packetOutSize, session)) {
          status = EPROTO;
       }
 
@@ -4330,8 +4418,9 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
       free(dent);
 
       if (status == 0 &&
-          !HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-         free(packetOut);
+          !HgfsPacketSend(input->packet,
+                          packetOut, packetOutSize, session, 0)) {
+         HSPU_PutReplyPacket(input->packet, session);
       }
       return status;
    }
@@ -4341,13 +4430,13 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
    free(search.utf8ShareName);
    LOG(4, ("%s: no entry\n", __FUNCTION__));
    status = 0;
-   if (!HgfsPackSearchReadReply(packetIn, status, NULL, 0, &attr,
-                                &packetOut, &packetOutSize)) {
+   if (!HgfsPackSearchReadReply(input->packet, packetIn, status, NULL, 0, &attr,
+                                &packetOut, &packetOutSize, session)) {
       status = EPROTO;
    }
    if (status == 0 &&
-       !HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-      free(packetOut);
+       !HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+      HSPU_PutReplyPacket(input->packet, session);
    }
    return status;
 }
@@ -4371,10 +4460,11 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
  */
 
 HgfsInternalStatus
-HgfsServerGetattr(char const *packetIn,     // IN: incoming packet
-                  size_t packetSize,        // IN: size of packet
-                  HgfsSessionInfo *session) // IN: session info
+HgfsServerGetattr(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    char *localName;
    HgfsAttrHint hints = 0;
    HgfsFileAttrInfo attr;
@@ -4479,13 +4569,13 @@ HgfsServerGetattr(char const *packetIn,     // IN: incoming packet
       }
       targetNameLen = targetName ? strlen(targetName) : 0;
    }
-   status = HgfsPackGetattrReply(packetIn, status, &attr, targetName,
-                                 targetNameLen, &packetOut, &packetOutSize) ? 0 : EPROTO;
+   status = HgfsPackGetattrReply(input->packet, packetIn, status, &attr, targetName,
+                                 targetNameLen, &packetOut, &packetOutSize, session) ? 0 : EPROTO;
    free(targetName);
 
    if (status == 0 &&
-       !HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-      free(packetOut);
+       !HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+      HSPU_PutReplyPacket(input->packet, session);
    }
 
 exit:
@@ -4511,10 +4601,11 @@ exit:
  */
 
 HgfsInternalStatus
-HgfsServerSetattr(char const *packetIn,     // IN: incoming packet
-                  size_t packetSize,        // IN: size of packet
-                  HgfsSessionInfo *session) // IN: session info
+HgfsServerSetattr(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsInternalStatus status;
    HgfsFileAttrInfo attr;
    char *cpName;
@@ -4542,12 +4633,13 @@ HgfsServerSetattr(char const *packetIn,     // IN: incoming packet
       status = HgfsSetattrFromName(cpName, cpNameSize, &attr, hints,
                                   caseFlags, session);
    }
-   if (!HgfsPackSetattrReply(packetIn, status, attr.requestType, &packetOut, &packetOutSize)) {
+   if (!HgfsPackSetattrReply(input->packet, packetIn, status, attr.requestType,
+                             &packetOut, &packetOutSize, session)) {
       status = EPROTO;
       goto exit;
    }
-   if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-      free(packetOut);
+   if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+      HSPU_PutReplyPacket(input->packet, session);
       /* We can't send the packet, ignore the error if any. */
    }
    status = 0;
@@ -4577,10 +4669,11 @@ exit:
  */
 
 HgfsInternalStatus
-HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
-                    size_t packetSize,        // IN: size of packet
-                    HgfsSessionInfo *session) // IN: session info
+HgfsServerCreateDir(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsNameStatus nameStatus;
    HgfsCreateDirInfo info;
    char *localName;
@@ -4670,12 +4763,12 @@ HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
       LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error)));
       return error;
    }
-   if (!HgfsPackCreateDirReply(packetIn, 0, info.requestType,
-                               &packetOut, &packetOutSize)) {
+   if (!HgfsPackCreateDirReply(input->packet, packetIn, 0, info.requestType,
+                               &packetOut, &packetOutSize, session)) {
       return EPROTO;
    }
-   if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-      free(packetOut);
+   if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+      HSPU_PutReplyPacket(input->packet, session);
    }
    return 0;
 }
@@ -4702,10 +4795,11 @@ HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
  */
 
 HgfsInternalStatus
-HgfsServerDeleteFile(char const *packetIn,     // IN: incoming packet
-                     size_t packetSize,        // IN: size of packet
-                     HgfsSessionInfo *session) // IN: session info
+HgfsServerDeleteFile(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsNameStatus nameStatus;
    char *localName;
    int error;
@@ -4777,11 +4871,12 @@ HgfsServerDeleteFile(char const *packetIn,     // IN: incoming packet
 
       return error;
    }
-   if (!HgfsPackDeleteReply(packetIn, 0, op, &packetOut, &packetOutSize)) {
+   if (!HgfsPackDeleteReply(input->packet, packetIn, 0, op, &packetOut,
+                            &packetOutSize, session)) {
       return EPROTO;
    }
-   if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-      free(packetOut);
+   if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+      HSPU_PutReplyPacket(input->packet, session);
    }
    return 0;
 }
@@ -4808,10 +4903,11 @@ HgfsServerDeleteFile(char const *packetIn,     // IN: incoming packet
  */
 
 HgfsInternalStatus
-HgfsServerDeleteDir(char const *packetIn,     // IN: incoming packet
-                    size_t packetSize,        // IN: size of packet
-                    HgfsSessionInfo *session) // IN: session info
+HgfsServerDeleteDir(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsNameStatus nameStatus;
    char *localName = NULL;
    int error;
@@ -4891,11 +4987,12 @@ HgfsServerDeleteDir(char const *packetIn,     // IN: incoming packet
       return error;
    }
 
-   if (!HgfsPackDeleteReply(packetIn, 0, op, &packetOut, &packetOutSize)) {
+   if (!HgfsPackDeleteReply(input->packet, packetIn, 0, op, &packetOut,
+                            &packetOutSize, session)) {
       return EPROTO;
    }
-   if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-      free(packetOut);
+   if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+      HSPU_PutReplyPacket(input->packet, session);
    }
    return 0;
 }
@@ -4922,10 +5019,11 @@ HgfsServerDeleteDir(char const *packetIn,     // IN: incoming packet
  */
 
 HgfsInternalStatus
-HgfsServerRename(char const *packetIn,     // IN: incoming packet
-                 size_t packetSize,        // IN: size of packet
-                 HgfsSessionInfo *session) // IN: session info
+HgfsServerRename(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsNameStatus nameStatus;
    char *localOldName = NULL;
    size_t localOldNameLen;
@@ -5109,12 +5207,13 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
     */
    status = 0;
    HgfsUpdateNodeNames(localOldName, localNewName, session);
-   if (!HgfsPackRenameReply(packetIn, status, op, &packetOut, &packetOutSize)) {
+   if (!HgfsPackRenameReply(input->packet, packetIn, status, op, &packetOut,
+                            &packetOutSize, session)) {
       status = EPROTO;
       goto exit;
    }
-   if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
-      free(packetOut);
+   if (!HgfsPacketSend(input->packet, packetOut, packetOutSize, session, 0)) {
+      HSPU_PutReplyPacket(input->packet, session);
    }
 
   exit:
@@ -5150,10 +5249,11 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
  */
 
 HgfsInternalStatus
-HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
-                      size_t packetSize,        // IN: size of packet
-                      HgfsSessionInfo *session) // IN: session info
+HgfsServerQueryVolume(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsRequest *header;
    uint32 extra;
    char *utf8Name = NULL;
@@ -5178,6 +5278,7 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
    uint64 *totalBytes;
    char *packetOut;
    size_t packetOutSize;
+   size_t replyPacketSize;
    HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
@@ -5191,7 +5292,10 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
       HgfsReplyQueryVolumeV3 *replyV3;
 
       packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
-      packetOut = Util_SafeMalloc(packetOutSize);
+      replyPacketSize = packetOutSize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+
       replyV3 = (HgfsReplyQueryVolumeV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
 
       /*
@@ -5221,7 +5325,10 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
       HgfsReplyQueryVolume *reply;
 
       packetOutSize = sizeof *reply;
-      packetOut = Util_SafeMalloc(packetOutSize);
+      replyPacketSize = packetOutSize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+
       reply = (HgfsReplyQueryVolume *)packetOut;
 
       freeBytes = &reply->freeBytes;
@@ -5230,7 +5337,6 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
       /* Enforced by the dispatch function. */
       ASSERT(packetSize >= sizeof *request);
       extra = packetSize - sizeof *request;
-
       fileName = request->fileName.name;
       fileNameLength = request->fileName.length;
    }
@@ -5401,14 +5507,14 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
    *totalBytes = outTotalBytes;
    status = 0;
 
-   if (!HgfsPackAndSendPacket(packetOut, packetOutSize, status, header->id,
-                              session, 0)) {
+   if (!HgfsPackAndSendPacket(input->packet, packetOut, packetOutSize,
+                              status, header->id, session, 0)) {
       goto exit;
    }
    return status;
 
 exit:
-   free(packetOut);
+   HSPU_PutReplyPacket(input->packet, session);
    return status;
 }
 
@@ -5431,10 +5537,11 @@ exit:
  */
 
 HgfsInternalStatus
-HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
-                        size_t packetSize,        // IN: size of packet
-                        HgfsSessionInfo *session) // IN: session info
+HgfsServerSymlinkCreate(HgfsInputParam *input)  // IN: Input params
 {
+   const char *packetIn = input->metaPacket;
+   size_t packetSize = input->metaPacketSize;
+   HgfsSessionInfo *session = input->session;
    HgfsRequest *header;
    uint32 extra;
    char *localSymlinkName = NULL;
@@ -5449,6 +5556,7 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
    HgfsShareOptions configOptions;
    char *packetOut = NULL;
    size_t packetOutSize;
+   size_t replyPacketSize;
    HgfsInternalStatus status = 0;
    size_t localSymlinkNameLen;
    HgfsShareInfo shareInfo;
@@ -5486,54 +5594,59 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
        */
       if (requestV3->symlinkName.flags & HGFS_FILE_NAME_USE_FILE_DESC ||
           targetNameP->flags & HGFS_FILE_NAME_USE_FILE_DESC) {
-                LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
-
-                return EPARAMETERNOTSUPPORTED;
-             }
-
-             packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
-             packetOut = Util_SafeMalloc(packetOutSize);
-             replyV3 = (HgfsReplySymlinkCreateV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
-             replyV3->reserved = 0;
-          } else {
-             HgfsRequestSymlinkCreate *request;
-             HgfsFileName *targetNameP;
-             request = (HgfsRequestSymlinkCreate *)packetIn;
-
-             /* Enforced by the dispatch function. */
-             ASSERT(packetSize >= sizeof *request);
-             extra = packetSize - sizeof *request;
-
-             symlinkName = request->symlinkName.name;
-             symlinkNameLength = request->symlinkName.length;
-
-             /*
-              * targetName starts after symlinkName + the variable length array
-              * in symlinkName.
-              */
-
-             targetNameP = (HgfsFileName *)(symlinkName + 1 + symlinkNameLength);
-             targetName = targetNameP->name;
-             targetNameLength = targetNameP->length;
-             packetOutSize = sizeof(struct HgfsReplySymlinkCreate);
-             packetOut = Util_SafeMalloc(packetOutSize);
-          }
-
-          /*
-           * request->symlinkName.length is user-provided, so this test must
-           * be carefully written to prevent wraparounds.
-           */
-
-          if (symlinkNameLength > extra) {
-             /* The input packet is smaller than the request */
-             status = EPROTO;
-             goto exit;
-          }
-
-          /*
-           * It is now safe to read the symlink file name and the
-           * "targetName" field
-           */
+         LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
+         return EPARAMETERNOTSUPPORTED;
+      }
+
+      packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
+      replyPacketSize = packetOutSize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+
+      replyV3 = (HgfsReplySymlinkCreateV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut);
+      replyV3->reserved = 0;
+
+   } else {
+      HgfsRequestSymlinkCreate *request;
+      HgfsFileName *targetNameP;
+      request = (HgfsRequestSymlinkCreate *)packetIn;
+
+      /* Enforced by the dispatch function. */
+      ASSERT(packetSize >= sizeof *request);
+      extra = packetSize - sizeof *request;
+
+      symlinkName = request->symlinkName.name;
+      symlinkNameLength = request->symlinkName.length;
+
+      /*
+       * targetName starts after symlinkName + the variable length array
+       * in symlinkName.
+       */
+
+      targetNameP = (HgfsFileName *)(symlinkName + 1 + symlinkNameLength);
+      targetName = targetNameP->name;
+      targetNameLength = targetNameP->length;
+      packetOutSize = sizeof(struct HgfsReplySymlinkCreate);
+      replyPacketSize = packetOutSize;
+      packetOut = HSPU_GetReplyPacket(input->packet, &replyPacketSize, session);
+      HGFS_REPLYPKT_CHECK(packetOut, packetOutSize, replyPacketSize, status, exit);
+   }
+
+   /*
+    * request->symlinkName.length is user-provided, so this test must
+    * be carefully written to prevent wraparounds.
+    */
+
+   if (symlinkNameLength > extra) {
+      /* The input packet is smaller than the request */
+      status = EPROTO;
+      goto exit;
+   }
+
+   /*
+    * It is now safe to read the symlink file name and the
+    * "targetName" field
+    */
 
    nameStatus = HgfsServerGetShareInfo(symlinkName,
                                        symlinkNameLength,
@@ -5609,7 +5722,8 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
    }
 
    status = 0;
-   if (!HgfsPackAndSendPacket(packetOut, packetOutSize, status, header->id,
+   if (!HgfsPackAndSendPacket(input->packet, packetOut, packetOutSize,
+                              status, header->id,
                               session, 0)) {
       goto exit;
    }
@@ -5618,7 +5732,7 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
 
 exit:
    free(localSymlinkName);
-   free(packetOut);
+   HSPU_PutReplyPacket(input->packet, session);
    return status;
 }
 
@@ -5775,9 +5889,7 @@ exit:
  */
 
 HgfsInternalStatus
-HgfsServerWriteWin32Stream(char const *packetIn,     // IN: incoming packet
-                           size_t packetSize,        // IN: size of packet
-                           HgfsSessionInfo *session) // IN: session info
+HgfsServerWriteWin32Stream(HgfsInputParam *input)  // IN: Input params
 {
    return EOPNOTSUPP;
 }
@@ -5802,9 +5914,7 @@ HgfsServerWriteWin32Stream(char const *packetIn,     // IN: incoming packet
  */
 
 HgfsInternalStatus
-HgfsServerServerLockChange(char const *packetIn,     // IN: incoming packet
-                           size_t packetSize,        // IN: size of packet
-                           HgfsSessionInfo *session) // IN: session info
+HgfsServerServerLockChange(HgfsInputParam *input) // IN: Input params
 {
    return EOPNOTSUPP;
 }
diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c b/open-vm-tools/lib/hgfsServer/hgfsServerPacketUtil.c
new file mode 100644 (file)
index 0000000..77ce074
--- /dev/null
@@ -0,0 +1,606 @@
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * hgfsServerPacketUtil.c --
+ *
+ * Utility functions for manipulating packet used by hgfs server code
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "vmware.h"
+#include "hgfsServer.h"
+#include "hgfsServerInt.h"
+#include "util.h"
+
+#define LOGLEVEL_MODULE hgfs
+#include "loglevel_user.h"
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetReplyPacket --
+ *
+ *    Get a reply packet given an hgfs packet.
+ *    Guest mappings may be established.
+ *
+ * Results:
+ *    Pointer to reply packet.
+ *
+ * Side effects:
+ *    Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetReplyPacket(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                    size_t *replyPacketSize,   // IN/OUT: Size of reply Packet
+                    HgfsSessionInfo *session)  // IN: Session Info
+{
+   ASSERT(session);
+   if (packet->replyPacket) {
+      /*
+       * When we are transferring packets over backdoor, reply packet
+       * is a static buffer. Backdoor should always return from here.
+       */
+      LOG(4, ("Exising reply packet %s %Zu %Zu\n", __FUNCTION__,
+              *replyPacketSize, packet->replyPacketSize));
+      /*
+       * HgfsServer_ProcessPacket does not tell us the real size of packetOut.
+       * It assumes that size of reply packet can never be bigger than size of
+       * the outgoing packet. I changed it to HGFS_LARGE_PACKET_MAX.
+       */
+      ASSERT_DEVEL(*replyPacketSize <= packet->replyPacketSize);
+      goto exit;
+   } else if (session->channelCbTable && session->channelCbTable->getWriteVa) {
+     /* Can we write directly into guest memory ? */
+      if (packet->metaPacket) {
+         LOG(10, ("%s Using meta packet for reply packet\n", __FUNCTION__));
+         ASSERT_DEVEL(*replyPacketSize <= packet->metaPacketSize);
+         packet->replyPacket = packet->metaPacket;
+         packet->replyPacketSize = packet->metaPacketSize;
+         goto exit;
+      }
+
+      /* This should really never happen in existing scenarios */
+      ASSERT_DEVEL(0);
+      LOG(10, ("%s Mapping meta packet for reply packet\n", __FUNCTION__));
+      packet->replyPacket = HSPU_GetBuf(packet, 0, &packet->metaPacket,
+                                        packet->metaPacketSize,
+                                        &packet->metaPacketIsAllocated,
+                                        HGFS_BUF_WRITEABLE,
+                                        session);
+      /*
+       * Really this can never happen, we would have caught bad physical address
+       * during getMetaPacket.
+       */
+      ASSERT(packet->replyPacket);
+      packet->replyPacketSize = packet->metaPacketSize;
+   } else {
+      /* For sockets channel we always need to allocate buffer */
+      LOG(10, ("%s Allocating reply packet\n", __FUNCTION__));
+      packet->replyPacket = Util_SafeMalloc(*replyPacketSize);
+      packet->replyPacketIsAllocated = TRUE;
+      packet->replyPacketSize = *replyPacketSize;
+   }
+
+exit:
+   *replyPacketSize = packet->replyPacketSize;
+   return packet->replyPacket;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutReplyPacket --
+ *
+ *    Free buffer if reply packet was allocated.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutReplyPacket(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                    HgfsSessionInfo *session)  // IN: Session Info
+{
+   if (packet->replyPacketIsAllocated) {
+      LOG(10, ("%s Freeing reply packet", __FUNCTION__));
+      free(packet->replyPacket);
+      packet->replyPacketIsAllocated = FALSE;
+      packet->replyPacket = NULL;
+      packet->replyPacketSize = 0;
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetMetaPacket --
+ *
+ *    Get a meta packet given an hgfs packet.
+ *    Guest mappings will be established.
+ *
+ * Results:
+ *    Pointer to meta packet.
+ *
+ * Side effects:
+ *    Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetMetaPacket(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                   size_t *metaPacketSize,    // OUT: Size of metaPacket
+                   HgfsSessionInfo *session)  // IN: Session Info
+{
+   *metaPacketSize = packet->metaPacketSize;
+   return HSPU_GetBuf(packet, 0, &packet->metaPacket,
+                      packet->metaPacketSize,
+                      &packet->metaPacketIsAllocated,
+                      HGFS_BUF_WRITEABLE, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetDataPacketIov --
+ *
+ *    Get a data packet in an iov form given an hgfs packet.
+ *    Guest mappings will be established.
+ *
+ * Results:
+ *    Pointer to data packet iov.
+ *
+ * Side effects:
+ *    Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetDataPacketIov(HgfsPacket *packet,       // IN/OUT: Hgfs Packet
+                      HgfsSessionInfo *session, // IN: Session Info
+                      HgfsVaIov iov)            // OUT: I/O vector
+{
+   NOT_IMPLEMENTED();
+   return NULL;
+
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetDataPacketBuf --
+ *
+ *    Get a data packet given an hgfs packet.
+ *    Guest mappings will be established.
+ *
+ * Results:
+ *    Pointer to data packet.
+ *
+ * Side effects:
+ *    Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetDataPacketBuf(HgfsPacket *packet,       // IN/OUT: Hgfs Packet
+                      uint32 mappingType,       // IN: Writeable/Readable
+                      HgfsSessionInfo *session) // IN: Session Info
+{
+   packet->dataMappingType = mappingType;
+   return HSPU_GetBuf(packet, packet->dataPacketIovIndex,
+                      &packet->dataPacket, packet->dataPacketSize,
+                      &packet->dataPacketIsAllocated, mappingType, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_GetBuf --
+ *
+ *    Get a {meta, data} packet given an hgfs packet.
+ *    Guest mappings will be established.
+ *
+ * Results:
+ *    Pointer to buffer.
+ *
+ * Side effects:
+ *    Buffer may be allocated.
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+HSPU_GetBuf(HgfsPacket *packet,           // IN/OUT: Hgfs Packet
+            uint32 startIndex,            // IN: start index of iov
+            void **buf,                   // OUT: Contigous buffer
+            size_t  bufSize,              // IN: Size of buffer
+            Bool *isAllocated,            // OUT: Was buffer allocated ?
+            uint32 mappingType,           // IN: Readable/Writeable ?
+            HgfsSessionInfo *session)     // IN: Session Info
+{
+   uint32 iovCount;
+   uint32 iovMapped = 0;
+   int32 size = bufSize;
+   int i;
+   void* (*func)(uint64, uint32, char **);
+   ASSERT(buf);
+
+   if (*buf) {
+      return *buf;
+   } else if (bufSize == 0) {
+      return NULL;
+   }
+
+   ASSERT_DEVEL(session->channelCbTable);
+   if (!session->channelCbTable) {
+      return NULL;
+   }
+
+   if (mappingType == HGFS_BUF_WRITEABLE) {
+      func = session->channelCbTable->getWriteVa;
+   } else {
+      ASSERT(mappingType == HGFS_BUF_READABLE);
+      func = session->channelCbTable->getReadVa;
+   }
+
+   ASSERT_DEVEL(func);
+   if (func == NULL) {
+      return NULL;
+   }
+
+   /* Establish guest memory mappings */
+   for (iovCount = startIndex; iovCount < packet->iovCount && size > 0;
+        iovCount++) {
+
+      packet->iov[iovCount].token = NULL;
+
+      /* Debugging check: Iov in VMCI should never cross page boundary */
+      ASSERT_DEVEL(packet->iov[iovCount].len <=
+      (4096 - (packet->iov[iovCount].pa & 0xfff)));
+
+      packet->iov[iovCount].va = func(packet->iov[iovCount].pa,
+                                      packet->iov[iovCount].len,
+                                      &packet->iov[iovCount].token);
+      ASSERT_DEVEL(packet->iov[iovCount].va);
+      if (packet->iov[iovCount].va == NULL) {
+         /* Guest probably passed us bad physical address */
+         *buf = NULL;
+         goto freeMem;
+      }
+      iovMapped++;
+      size -= packet->iov[iovCount].len;
+   }
+
+   if (iovMapped > 1) {
+      /* Seems like more than one page was requested. */
+      uint32 copiedAmount = 0;
+      uint32 copyAmount;
+      int32 remainingSize;
+      int i;
+      ASSERT_DEVEL(packet->iov[startIndex].len < bufSize);
+      *buf = Util_SafeMalloc(bufSize);
+      *isAllocated = TRUE;
+
+      LOG(10, ("%s: Hgfs Allocating buffer \n", __FUNCTION__));
+
+      /*
+       * Since we are allocating seperate buffer, it does not make sense
+       * to continue to hold on to mappings. Let's release it, we will
+       * reacquire mappings when we need in HSPU_CopyBufToIovec.
+       */
+      remainingSize = bufSize;
+      for (i = startIndex; i < packet->iovCount && remainingSize > 0; i++) {
+         copyAmount = remainingSize < packet->iov[i].len ?
+                      remainingSize : packet->iov[i].len;
+         memcpy((char *)*buf + copiedAmount, packet->iov[i].va, copyAmount);
+         copiedAmount += copyAmount;
+         remainingSize -= copyAmount;
+      }
+      ASSERT_DEVEL(copiedAmount == bufSize);
+   } else {
+      /* We will continue to hold on to guest mappings */
+      *buf = packet->iov[startIndex].va;
+      return *buf;
+   }
+
+freeMem:
+   for (i = 0; i < iovCount; i++) {
+      session->channelCbTable->putVa(&packet->iov[i].token);
+      packet->iov[i].va = NULL;
+   }
+
+   return *buf;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutMetaPacket --
+ *
+ *    Free meta packet buffer if allocated.
+ *    Guest mappings will be released.
+ *
+ * Results:
+ *    void.
+ *
+ * Side effects:
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutMetaPacket(HgfsPacket *packet,       // IN/OUT: Hgfs Packet
+                   HgfsSessionInfo *session) // IN: Session Info
+{
+   LOG(4, ("%s Hgfs Putting Meta packet\n", __FUNCTION__));
+   HSPU_PutBuf(packet, 0, &packet->metaPacket,
+               &packet->metaPacketSize,
+               &packet->metaPacketIsAllocated,
+               HGFS_BUF_WRITEABLE, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutDataPacketIov --
+ *
+ *    Free data packet Iov if allocated.
+ *
+ * Results:
+ *    void.
+ *
+ * Side effects:
+ *    Guest mappings will be released.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutDataPacketIov()
+{
+   NOT_IMPLEMENTED();
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutDataPacketBuf --
+ *
+ *    Free data packet buffer if allocated.
+ *    Guest mappings will be released.
+ *
+ * Results:
+ *    void.
+ *
+ * Side effects:
+ *    None.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutDataPacketBuf(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+                      HgfsSessionInfo *session)  // IN: Session Info
+{
+
+   LOG(4, ("%s Hgfs Putting Data packet\n", __FUNCTION__));
+   HSPU_PutBuf(packet, packet->dataPacketIovIndex,
+               &packet->dataPacket, &packet->dataPacketSize,
+               &packet->dataPacketIsAllocated,
+               packet->dataMappingType, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_PutBuf --
+ *
+ *    Free buffer if allocated and release guest mappings.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_PutBuf(HgfsPacket *packet,        // IN/OUT: Hgfs Packet
+            uint32 startIndex,         // IN: Start of iov
+            void **buf,                // IN/OUT: Buffer to be freed
+            size_t *bufSize,           // IN: Size of the buffer
+           Bool *isAllocated,         // IN: Was buffer allocated ?
+            uint32 mappingType,        // IN: Readable / Writeable ?
+           HgfsSessionInfo *session)  // IN: Session info
+{
+   uint32 iovCount = 0;
+   int size = *bufSize;
+   ASSERT(buf);
+
+   if (!session->channelCbTable) {
+      return;
+   }
+
+   if (!session->channelCbTable->putVa || *buf == NULL) {
+      return;
+   }
+
+   if (*isAllocated) {
+      if (mappingType == HGFS_BUF_WRITEABLE) {
+         HSPU_CopyBufToIovec(packet, startIndex, *buf, *bufSize, session);
+      }
+      LOG(10, ("%s: Hgfs Freeing buffer \n", __FUNCTION__));
+      free(*buf);
+      *isAllocated = FALSE;
+   } else {
+      for (iovCount = startIndex;
+           iovCount < packet->iovCount && size > 0;
+           iovCount++) {
+         ASSERT_DEVEL(packet->iov[iovCount].token);
+         session->channelCbTable->putVa(&packet->iov[iovCount].token);
+         size -= packet->iov[iovCount].len;
+      }
+      LOG(10, ("%s: Hgfs bufSize = %d \n", __FUNCTION__, size));
+      ASSERT(size <= 0);
+   }
+   *buf = NULL;
+   *bufSize = 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_CopyBufToMetaIovec --
+ *
+ *    Write out buffer to data Iovec.
+ *
+ * Results:
+ *    void
+ *
+ * Side effects:
+ *    @iov is populated with contents of @buf
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_CopyBufToMetaIovec(HgfsPacket *packet,      // IN/OUT: Hgfs packet
+                        void *buf,               // IN: Buffer to copy from
+                        size_t bufSize,          // IN: Size of buffer
+                        HgfsSessionInfo *session)// IN: Session Info
+{
+   HSPU_CopyBufToIovec(packet, 0, buf, bufSize, session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_CopyBufToDataIovec --
+ *
+ *    Write out buffer to data Iovec.
+ *
+ * Results:
+ *    void
+ *
+ * Side effects:
+ *    @iov is populated with contents of @buf
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_CopyBufToDataIovec(HgfsPacket *packet,   // IN: Hgfs packet
+                        void *buf,            // IN: Buffer to copy from
+                        uint32 bufSize,       // IN: Size of buffer
+                        HgfsSessionInfo *session)
+{
+   HSPU_CopyBufToIovec(packet, packet->dataPacketIovIndex, buf, bufSize,
+                       session);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HSPU_CopyBufToDataIovec --
+ *
+ *    Write out buffer to data Iovec.
+ *
+ * Results:
+ *    void
+ *
+ * Side effects:
+ *    @iov is populated with contents of @buf
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HSPU_CopyBufToIovec(HgfsPacket *packet,       // IN/OUT: Hgfs Packet
+                    uint32 startIndex,        // IN: start index into iov
+                    void *buf,                // IN: Contigous Buffer
+                    size_t bufSize,           // IN: Size of buffer
+                    HgfsSessionInfo *session) // IN: Session Info
+{
+   uint32 iovCount;
+   size_t remainingSize = bufSize;
+   size_t copyAmount;
+   size_t copiedAmount = 0;
+   int i;
+
+   ASSERT(packet);
+   ASSERT(buf);
+
+   if (!session->channelCbTable) {
+      return;
+   }
+
+   ASSERT_DEVEL(session->channelCbTable->getWriteVa);
+   if (!session->channelCbTable->getWriteVa) {
+      return;
+   }
+
+   for (iovCount = startIndex; iovCount < packet->iovCount
+        && remainingSize > 0; iovCount++) {
+      copyAmount = remainingSize < packet->iov[iovCount].len ?
+                   remainingSize: packet->iov[iovCount].len;
+
+      packet->iov[iovCount].token = NULL;
+
+      /* Debugging check: Iov in VMCI should never cross page boundary */
+      ASSERT_DEVEL(packet->iov[iovCount].len <=
+      (4096 - (packet->iov[iovCount].pa & 0xfff)));
+
+      packet->iov[iovCount].va = session->channelCbTable->getWriteVa(packet->iov[iovCount].pa,
+                                                     packet->iov[iovCount].len,
+                                                     &packet->iov[iovCount].token);
+      ASSERT_DEVEL(packet->iov[iovCount].va);
+      if (packet->iov[iovCount].va == NULL) {
+         goto freeMem;
+      }
+
+      memcpy(packet->iov[iovCount].va, (char *)buf + copiedAmount, copyAmount);
+      remainingSize -= copyAmount;
+      copiedAmount += copyAmount;
+   }
+
+   ASSERT(remainingSize == 0);
+   return;
+
+freeMem:
+   for (i = startIndex; i < iovCount; i++) {
+      session->channelCbTable->putVa(&packet->iov[i].token);
+   }
+}
+
+
index 6fe7c569db6b4a8943dea78b10d9306575ae32fa..02cf108ff8d24ff2ef293c099be258c2c1139a78 100644 (file)
@@ -47,5 +47,4 @@ typedef struct HgfsChannelCBTable {
 Bool HgfsChannel_Init(void *data);  /* Optional data, used in guest. */
 void HgfsChannel_Exit(void *data);  /* Optional data, used in guest. */
 void HgfsChannel_InvalidateObjects(DblLnkLst_Links *shares);
-
 #endif
index 077ba726c391ee2fee0f5301fee331fd181bb6ef..9fbe80ec678832e9e3e168000272719ee1d80b19 100644 (file)
@@ -118,7 +118,8 @@ typedef enum {
    HGFS_OP_CREATE_SYMLINK_V3,     /* Create a symlink */
    HGFS_OP_SERVER_LOCK_CHANGE_V3, /* Change the oplock on a file */
    HGFS_OP_WRITE_WIN32_STREAM_V3, /* Write WIN32_STREAM_ID format data to file */
-
+   HGFS_OP_READ_FAST_V3,          /* Read */
+   HGFS_OP_WRITE_FAST_V3,         /* Write */
    /*
     * Operations for version 4, deprecating version 3 operations.
     */
@@ -165,55 +166,6 @@ typedef enum {
 #define HGFS_REQ_GET_PAYLOAD_V3(hgfsReq) ((char *)(hgfsReq) + sizeof(HgfsRequest))
 #define HGFS_REP_GET_PAYLOAD_V3(hgfsRep) ((char *)(hgfsRep) + sizeof(HgfsReply))
 
-/* Some fudged values for TCP over sockets. */
-#define HGFS_HOST_PORT 2000
-
-/* Socket packet magic. */
-#define HGFS_SOCKET_VERSION1   1
-
-/*
- * Socket status codes.
- */
-
-typedef enum {
-   HGFS_SOCKET_STATUS_SUCCESS,                  /* Socket header is good. */
-   HGFS_SOCKET_STATUS_SIZE_MISMATCH,            /* Size and version are incompatible. */
-   HGFS_SOCKET_STATUS_VERSION_NOT_SUPPORTED,    /* Version not handled by remote. */
-   HGFS_SOCKET_STATUS_INVALID_PACKETLEN,        /* Message len exceeds maximum. */
-} HgfsSocketStatus;
-
-/*
- * Socket flags.
- */
-
-typedef uint32 HgfsSocketFlags;
-
-/* Used by backdoor proxy socket client to Hgfs server (out of VMX process). */
-#define HGFS_SOCKET_SYNC         (1 << 0)
-
-/* Socket packet header. */
-typedef
-#include "vmware_pack_begin.h"
-struct HgfsSocketHeader {
-   uint32 version;            /* Header version. */
-   uint32 size;               /* Header size, should match for the specified version. */
-   HgfsSocketStatus status;   /* Status: always success when sending (ignored) valid on replies. */
-   uint32 packetLen;          /* The length of the packet to follow. */
-   HgfsSocketFlags flags;     /* The flags to indicate how to deal with the packet. */
-}
-#include "vmware_pack_end.h"
-HgfsSocketHeader;
-
-#define HgfsSocketHeaderInit(hdr, _version, _size, _status, _pktLen, _flags) \
-   do {                                                                      \
-      (hdr)->version    = (_version);                                        \
-      (hdr)->size       = (_size);                                           \
-      (hdr)->status     = (_status);                                         \
-      (hdr)->packetLen  = (_pktLen);                                         \
-      (hdr)->flags      = (_flags);                                          \
-   } while (0)
-
-
 /*
  * File types, used in HgfsAttr. We support regular files,
  * directories, and symlinks.
index 9a7102ed14da4baa7dee3232d714afef3c6634f9..e8f01f7b9690d33ac84cd50505cbc28af7ba92b5 100644 (file)
@@ -35,6 +35,49 @@ typedef struct HgfsServerStateLogger {
    void                       *loggerData;   // logger callback private data
 } HgfsServerStateLogger;
 
+
+#define HGFS_MAX_IOV 3
+#define HGFS_BUF_READABLE  0x0000cafe
+#define HGFS_BUF_WRITEABLE 0x0000babe
+
+typedef
+struct HgfsVmxIov {
+   void *va;           /* Virtual addr */
+   uint64 pa;          /* Physical address passed by the guest */
+   uint32 len;         /* length of data; should be <= PAGE_SIZE for VMCI; arbitrary for backdoor */
+   char *token;        /* Token for physMem_ APIs */
+} HgfsVmxIov;
+
+typedef
+struct HgfsVaIov {
+   void *va;
+   uint32 len;
+} HgfsVaIov;
+
+typedef
+struct HgfsPacket {
+   /* For metapacket we always establish writeable mappings */
+   void *metaPacket;
+   size_t metaPacketSize;
+   Bool metaPacketIsAllocated;
+
+   void *dataPacket;
+   size_t dataPacketSize;
+   uint32 dataPacketIovIndex;
+   Bool dataPacketIsAllocated;
+   /* What type of mapping was established - readable/ writeable ? */
+   uint32 dataMappingType;
+
+   void *replyPacket;
+   size_t replyPacketSize;
+   Bool replyPacketIsAllocated;
+
+   uint32 iovCount;
+   HgfsVmxIov iov[1];
+
+} HgfsPacket;
+
+
 /*
  * Function used for sending replies to the client for a session.
  * Passed by the caller at session connect time.
@@ -75,13 +118,21 @@ HgfsSessionSendFunc(void *opaqueSession,  // IN
                     size_t bufferLen,     // IN
                     HgfsSendFlags flags); // IN
 
+typedef struct HgfsServerChannelCallbacks {
+    void* (*getReadVa)(uint64 pa, uint32 size, char **token);
+    void* (*getWriteVa)(uint64 pa, uint32 size, char **token);
+    void (*putVa)(char **token);
+    Bool (*send)(void *opaqueSession, HgfsPacket *packet, char *buffer,
+                 size_t bufferLen, HgfsSendFlags flags);
+}HgfsServerChannelCallbacks;
+
 typedef struct HgfsServerSessionCallbacks {
-   Bool (*connect)(void *, HgfsSessionSendFunc *, void **);
+   Bool (*connect)(void *, HgfsServerChannelCallbacks *, void **);
    void (*disconnect)(void *);
    void (*close)(void *);
-   void (*receive)(char const *,size_t, void *, HgfsReceiveFlags);
+   void (*receive)(HgfsPacket *packet, void *, HgfsReceiveFlags);
    void (*invalidateObjects)(void *, DblLnkLst_Links *);
-   void (*sendComplete)(void *, char *);
+   void (*sendComplete)(HgfsPacket *, void *);
 } HgfsServerSessionCallbacks;
 
 Bool HgfsServer_InitState(HgfsServerSessionCallbacks **, HgfsServerStateLogger *);
diff --git a/open-vm-tools/lib/include/hgfsTransport.h b/open-vm-tools/lib/include/hgfsTransport.h
new file mode 100644 (file)
index 0000000..2e68f85
--- /dev/null
@@ -0,0 +1,161 @@
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsTransport.h --
+ *
+ * Transport file shared between guest drivers and host.
+ */
+
+#ifndef _HGFS_TRANSPORT_H_
+# define _HGFS_TRANSPORT_H_
+
+#include "vmci_defs.h"
+#include "hgfsServer.h"   /* For HGFS_MAX_IOV */
+
+/****************************************
+ * Vsock, Tcp specific data structures  *
+ ****************************************/
+
+/* Some fudged values for TCP over sockets. */
+#define HGFS_HOST_PORT 2000
+
+/* Socket packet magic. */
+#define HGFS_SOCKET_VERSION1   1
+
+/*
+ * Socket status codes.
+ */
+
+typedef enum {
+   HGFS_SOCKET_STATUS_SUCCESS,                  /* Socket header is good. */
+   HGFS_SOCKET_STATUS_SIZE_MISMATCH,            /* Size and version are incompatible. */
+   HGFS_SOCKET_STATUS_VERSION_NOT_SUPPORTED,    /* Version not handled by remote. */
+   HGFS_SOCKET_STATUS_INVALID_PACKETLEN,        /* Message len exceeds maximum. */
+} HgfsSocketStatus;
+
+/*
+ * Socket flags.
+ */
+
+typedef uint32 HgfsSocketFlags;
+
+/* Used by backdoor proxy socket client to Hgfs server (out of VMX process). */
+#define HGFS_SOCKET_SYNC         (1 << 0)
+
+/* Socket packet header. */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsSocketHeader {
+   uint32 version;            /* Header version. */
+   uint32 size;               /* Header size, should match for the specified version. */
+   HgfsSocketStatus status;   /* Status: always success when sending (ignored) valid on replies. */
+   uint32 packetLen;          /* The length of the packet to follow. */
+   HgfsSocketFlags flags;     /* The flags to indicate how to deal with the packet. */
+}
+#include "vmware_pack_end.h"
+HgfsSocketHeader;
+
+#define HgfsSocketHeaderInit(hdr, _version, _size, _status, _pktLen, _flags) \
+   do {                                                                      \
+      (hdr)->version    = (_version);                                        \
+      (hdr)->size       = (_size);                                           \
+      (hdr)->status     = (_status);                                         \
+      (hdr)->packetLen  = (_pktLen);                                         \
+      (hdr)->flags      = (_flags);                                          \
+   } while (0)
+
+
+/************************************************
+ *    VMCI specific data structures, macros     *
+ ************************************************/
+
+#define HGFS_VMCI_VERSION_1          0xabcdabcd
+
+/* Helpful for debugging purposes */
+#define HGFS_VMCI_IO_PENDING         0xdeadbeef
+#define HGFS_VMCI_IO_COMPLETE        0xfaceb00c
+#define HGFS_VMCI_MORE_SPACE_NEEDED  0xc00becaf
+#define HGFS_VMCI_IO_FAILED          0xbeef0000
+
+#define HGFS_VMCI_TRANSPORT_ERROR   (VMCI_ERROR_CLIENT_MIN - 1)
+
+/*
+ * Used By : Guest and Host
+ * Lives in : Inside HgfsVmciTransportHeader
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsIov {
+   uint64 pa;                 /* Physical addr */
+   uint32 len;                /* length of data; should be <= PAGE_SIZE */
+}
+#include "vmware_pack_end.h"
+HgfsIov;
+
+/*
+ * Every VMCI request will have this transport Header sent over
+ * in the datagram by the Guest OS.
+ *
+ * Used By : Guest and Host
+ * Lives in : Sent by Guest inside VMCI datagram
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsVmciTransportHeader {
+   uint32 version;                          /* Version number */
+   uint32 iovCount;                         /* Number of iovs */
+   HgfsIov iov[1];                          /* (PA, len) */
+}
+#include "vmware_pack_end.h"
+HgfsVmciTransportHeader;
+
+/*
+ * Indicates status of VMCI requests. If the requests are processed sync
+ * by the hgfsServer then guest should see IO_COMPLETE otherwise IO_PENDING.
+ *
+ * Used By: Guest and Host
+ * Lives in: Guest Memory
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsVmciTransportStatus {
+   uint32 status;              /* IO_PENDING, COMPLETE, MORE SPACE NEEDED, FAILED etc */
+   uint32 flags;               /* ASYNC_PEND, VALID_ASYNC_PEND_REPLY */
+   uint32 size;                /* G->H: Size of the packet,H->G: How much more space is needed */
+}
+#include "vmware_pack_end.h"
+HgfsVmciTransportStatus;
+
+#endif /* _HGFS_TRANSPORT_H_ */
+
index d814b41f9fa532431289abd1133ebe05a6895289..e95894d80d5d4840080b519224eb2bcec554116d 100644 (file)
@@ -114,8 +114,8 @@ struct timespec {
 #define EPROTO (ELAST + 1)
 #endif
 
-#define HGFS_NAME_BUFFER_SIZE(request) (HGFS_PACKET_MAX - (sizeof *request - 1))
-#define HGFS_NAME_BUFFER_SIZET(sizet) (HGFS_PACKET_MAX - ((sizet) - 1))
+#define HGFS_NAME_BUFFER_SIZE(packetSize, request) (packetSize - (sizeof *request - 1))
+#define HGFS_NAME_BUFFER_SIZET(packetSize, sizet) (packetSize - ((sizet) - 1))
 
 #ifndef _WIN32
 /*
diff --git a/open-vm-tools/lib/include/vmci_defs.h b/open-vm-tools/lib/include/vmci_defs.h
new file mode 100644 (file)
index 0000000..76d1416
--- /dev/null
@@ -0,0 +1,790 @@
+/*********************************************************
+ * Copyright (C) 2005-2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+#ifndef _VMCI_DEF_H_
+#define _VMCI_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "vm_basic_types.h"
+#include "vm_atomic.h"
+#include "vm_assert.h"
+
+/* Register offsets. */
+#define VMCI_STATUS_ADDR      0x00
+#define VMCI_CONTROL_ADDR     0x04
+#define VMCI_ICR_ADDR        0x08
+#define VMCI_IMR_ADDR         0x0c
+#define VMCI_DATA_OUT_ADDR    0x10
+#define VMCI_DATA_IN_ADDR     0x14
+#define VMCI_CAPS_ADDR        0x18
+#define VMCI_RESULT_LOW_ADDR  0x1c
+#define VMCI_RESULT_HIGH_ADDR 0x20
+
+/* Max number of devices. */
+#define VMCI_MAX_DEVICES 1
+
+/* Status register bits. */
+#define VMCI_STATUS_INT_ON     0x1
+
+/* Control register bits. */
+#define VMCI_CONTROL_RESET        0x1
+#define VMCI_CONTROL_INT_ENABLE   0x2
+#define VMCI_CONTROL_INT_DISABLE  0x4
+
+/* Capabilities register bits. */
+#define VMCI_CAPS_HYPERCALL     0x1 
+#define VMCI_CAPS_GUESTCALL     0x2
+#define VMCI_CAPS_DATAGRAM      0x4
+#define VMCI_CAPS_NOTIFICATIONS 0x8
+
+/* Interrupt Cause register bits. */
+#define VMCI_ICR_DATAGRAM      0x1
+#define VMCI_ICR_NOTIFICATION  0x2
+
+/* Interrupt Mask register bits. */
+#define VMCI_IMR_DATAGRAM      0x1
+#define VMCI_IMR_NOTIFICATION  0x2
+
+/* 
+ * We have a fixed set of resource IDs available in the VMX. 
+ * This allows us to have a very simple implementation since we statically 
+ * know how many will create datagram handles. If a new caller arrives and
+ * we have run out of slots we can manually increment the maximum size of
+ * available resource IDs.
+ */
+
+typedef uint32 VMCI_Resource;
+
+/* VMCI reserved hypervisor datagram resource IDs. */
+#define VMCI_RESOURCES_QUERY      0
+#define VMCI_GET_CONTEXT_ID       1
+#define VMCI_SET_NOTIFY_BITMAP    2
+#define VMCI_DOORBELL_LINK        3
+#define VMCI_DOORBELL_UNLINK      4
+#define VMCI_DOORBELL_NOTIFY      5
+#define VMCI_DATAGRAM_REQUEST_MAP 6
+#define VMCI_DATAGRAM_REMOVE_MAP  7
+#define VMCI_EVENT_SUBSCRIBE      8
+#define VMCI_EVENT_UNSUBSCRIBE    9
+#define VMCI_QUEUEPAIR_ALLOC      10
+#define VMCI_QUEUEPAIR_DETACH     11
+#define VMCI_VSOCK_VMX_LOOKUP     12
+#define VMCI_HGFS_TRANSPORT       13
+#define VMCI_RESOURCE_MAX         14
+
+/* VMCI Ids. */
+typedef uint32 VMCIId;
+
+typedef struct VMCIHandle {
+   VMCIId context;
+   VMCIId resource;
+} VMCIHandle;
+
+static INLINE
+VMCIHandle VMCI_MAKE_HANDLE(VMCIId cid, 
+                           VMCIId rid)
+{
+   VMCIHandle h;
+   h.context = cid;
+   h.resource = rid;
+   return h;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCI_HANDLE_TO_UINT64 --
+ *
+ *     Helper for VMCI handle to uint64 conversion.
+ *
+ * Results:
+ *     The uint64 value.
+ * 
+ * Side effects:     
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCI_HANDLE_TO_UINT64(VMCIHandle handle) // IN:
+{
+   uint64 handle64;
+
+   handle64 = handle.context;
+   handle64 <<= 32;
+   handle64 |= handle.resource;
+   return handle64;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCI_UINT64_TO_HANDLE --
+ *
+ *     Helper for uint64 to VMCI handle conversion.
+ *
+ * Results:
+ *     The VMCI handle value.
+ * 
+ * Side effects:     
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE VMCIHandle
+VMCI_UINT64_TO_HANDLE(uint64 handle64) // IN:
+{
+   VMCIId context = (VMCIId)(handle64 >> 32);
+   VMCIId resource = (VMCIId)handle64;
+
+   return VMCI_MAKE_HANDLE(context, resource);
+}
+
+#define VMCI_HANDLE_TO_CONTEXT_ID(_handle) ((_handle).context)
+#define VMCI_HANDLE_TO_RESOURCE_ID(_handle) ((_handle).resource)
+#define VMCI_HANDLE_EQUAL(_h1, _h2) ((_h1).context == (_h2).context && \
+                                    (_h1).resource == (_h2).resource)
+
+#define VMCI_INVALID_ID 0xFFFFFFFF
+static const VMCIHandle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID, 
+                                              VMCI_INVALID_ID};
+
+#define VMCI_HANDLE_INVALID(_handle)   \
+   VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE)
+
+/*
+ * The below defines can be used to send anonymous requests.
+ * This also indicates that no response is expected.
+ */
+#define VMCI_ANON_SRC_CONTEXT_ID   VMCI_INVALID_ID
+#define VMCI_ANON_SRC_RESOURCE_ID  VMCI_INVALID_ID
+#define VMCI_ANON_SRC_HANDLE       VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID, \
+                                                   VMCI_ANON_SRC_RESOURCE_ID)
+
+/* The lowest 16 context ids are reserved for internal use. */
+#define VMCI_RESERVED_CID_LIMIT 16
+
+/*
+ * Hypervisor context id, used for calling into hypervisor
+ * supplied services from the VM. 
+ */
+#define VMCI_HYPERVISOR_CONTEXT_ID 0
+
+/* 
+ * Well-known context id, a logical context that contains 
+ * a set of well-known services.
+ */
+#define VMCI_WELL_KNOWN_CONTEXT_ID 1
+
+/* Todo: Change host context id to dynamic/random id. */
+#define VMCI_HOST_CONTEXT_ID  2
+
+/* 
+ * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make 
+ * handles that refer to a specific context.
+ */
+#define VMCI_CONTEXT_RESOURCE_ID 0
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCI error codes.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#define VMCI_SUCCESS_QUEUEPAIR_ATTACH     5
+#define VMCI_SUCCESS_QUEUEPAIR_CREATE     4
+#define VMCI_SUCCESS_LAST_DETACH          3
+#define VMCI_SUCCESS_ACCESS_GRANTED       2
+#define VMCI_SUCCESS_ENTRY_DEAD           1
+#define VMCI_SUCCESS                      0
+#define VMCI_ERROR_INVALID_RESOURCE      (-1)
+#define VMCI_ERROR_INVALID_ARGS          (-2)
+#define VMCI_ERROR_NO_MEM                (-3)
+#define VMCI_ERROR_DATAGRAM_FAILED       (-4)
+#define VMCI_ERROR_MORE_DATA             (-5)
+#define VMCI_ERROR_NO_MORE_DATAGRAMS     (-6)
+#define VMCI_ERROR_NO_ACCESS             (-7)
+#define VMCI_ERROR_NO_HANDLE             (-8)
+#define VMCI_ERROR_DUPLICATE_ENTRY       (-9)
+#define VMCI_ERROR_DST_UNREACHABLE       (-10)
+#define VMCI_ERROR_PAYLOAD_TOO_LARGE     (-11)
+#define VMCI_ERROR_INVALID_PRIV          (-12)
+#define VMCI_ERROR_GENERIC               (-13)
+#define VMCI_ERROR_PAGE_ALREADY_SHARED   (-14)
+#define VMCI_ERROR_CANNOT_SHARE_PAGE     (-15)
+#define VMCI_ERROR_CANNOT_UNSHARE_PAGE   (-16)
+#define VMCI_ERROR_NO_PROCESS            (-17)
+#define VMCI_ERROR_NO_DATAGRAM           (-18)
+#define VMCI_ERROR_NO_RESOURCES          (-19)
+#define VMCI_ERROR_UNAVAILABLE           (-20)
+#define VMCI_ERROR_NOT_FOUND             (-21)
+#define VMCI_ERROR_ALREADY_EXISTS        (-22)
+#define VMCI_ERROR_NOT_PAGE_ALIGNED      (-23)
+#define VMCI_ERROR_INVALID_SIZE          (-24)
+#define VMCI_ERROR_REGION_ALREADY_SHARED (-25)
+#define VMCI_ERROR_TIMEOUT               (-26)
+#define VMCI_ERROR_DATAGRAM_INCOMPLETE   (-27)
+#define VMCI_ERROR_INCORRECT_IRQL        (-28)
+#define VMCI_ERROR_EVENT_UNKNOWN         (-29)
+#define VMCI_ERROR_OBSOLETE              (-30)
+#define VMCI_ERROR_QUEUEPAIR_MISMATCH    (-31)
+#define VMCI_ERROR_QUEUEPAIR_NOTSET      (-32)
+#define VMCI_ERROR_QUEUEPAIR_NOTOWNER    (-33)
+#define VMCI_ERROR_QUEUEPAIR_NOTATTACHED (-34)
+#define VMCI_ERROR_QUEUEPAIR_NOSPACE     (-35)
+#define VMCI_ERROR_QUEUEPAIR_NODATA      (-36)
+#define VMCI_ERROR_BUSMEM_INVALIDATION   (-37)
+#define VMCI_ERROR_MODULE_NOT_LOADED     (-38)
+
+/* VMCI clients should return error code withing this range */
+#define VMCI_ERROR_CLIENT_MIN     (-500)
+#define VMCI_ERROR_CLIENT_MAX     (-550)
+
+/* Internal error codes. */
+#define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT (-1000)
+
+#define VMCI_PATH_MAX 256
+
+/* VMCI reserved events. */
+typedef uint32 VMCI_Event;
+
+#define VMCI_EVENT_CTX_ID_UPDATE  0
+#define VMCI_EVENT_CTX_REMOVED    1
+#define VMCI_EVENT_QP_RESUMED     2
+#define VMCI_EVENT_QP_PEER_ATTACH 3
+#define VMCI_EVENT_QP_PEER_DETACH 4
+#define VMCI_EVENT_MAX            5
+
+/* Reserved guest datagram resource ids. */
+#define VMCI_EVENT_HANDLER 0
+
+/* VMCI privileges. */
+typedef enum VMCIResourcePrivilegeType {
+   VMCI_PRIV_CH_PRIV,
+   VMCI_PRIV_DESTROY_RESOURCE,
+   VMCI_PRIV_ASSIGN_CLIENT,
+   VMCI_PRIV_DG_CREATE,
+   VMCI_PRIV_DG_SEND,
+   VMCI_PRIV_SM_CREATE,
+   VMCI_PRIV_SM_ATTACH,
+   VMCI_NUM_PRIVILEGES,
+} VMCIResourcePrivilegeType;
+
+/* 
+ * VMCI coarse-grained privileges (per context or host
+ * process/endpoint. An entity with the restricted flag is only
+ * allowed to interact with the hypervisor and trusted entities.
+ */
+typedef uint32 VMCIPrivilegeFlags;
+
+#define VMCI_PRIVILEGE_FLAG_RESTRICTED     0x01
+#define VMCI_PRIVILEGE_FLAG_TRUSTED        0x02
+#define VMCI_PRIVILEGE_ALL_FLAGS           (VMCI_PRIVILEGE_FLAG_RESTRICTED | \
+                                           VMCI_PRIVILEGE_FLAG_TRUSTED)
+#define VMCI_NO_PRIVILEGE_FLAGS            0x00
+#define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS  VMCI_NO_PRIVILEGE_FLAGS
+#define VMCI_LEAST_PRIVILEGE_FLAGS         VMCI_PRIVILEGE_FLAG_RESTRICTED
+#define VMCI_MAX_PRIVILEGE_FLAGS           VMCI_PRIVILEGE_FLAG_TRUSTED
+
+/* VMCI Discovery Service. */
+
+/* Well-known handle to the discovery service. */
+#define VMCI_DS_RESOURCE_ID 1 /* Reserved resource ID for discovery service. */
+#define VMCI_DS_HANDLE VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, \
+                                       VMCI_DS_RESOURCE_ID)
+#define VMCI_DS_CONTEXT VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, \
+                                        VMCI_CONTEXT_RESOURCE_ID)
+
+/* Maximum length of a DS message. */
+#define VMCI_DS_MAX_MSG_SIZE        300
+
+/* Command actions. */
+#define VMCI_DS_ACTION_LOOKUP         0
+#define VMCI_DS_ACTION_REGISTER       1
+#define VMCI_DS_ACTION_UNREGISTER     2
+
+/* Defines wire-protocol format for a request send to the DS from a context. */
+typedef struct VMCIDsRequestHeader {
+   int32       action;
+   int32       msgid;
+   VMCIHandle  handle;
+   int32       nameLen;
+   char        name[1];
+} VMCIDsRequestHeader;
+
+
+/* Defines the wire-protocol format for a request send from the DS to a context. */
+typedef struct VMCIDsReplyHeader {
+   int32       msgid;
+   int32       code;
+   VMCIHandle  handle;
+   int32       msgLen;
+   int8        msg[1];
+} VMCIDsReplyHeader;
+
+#define VMCI_PUBLIC_GROUP_NAME "vmci public group"
+/* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
+#define VMCI_RESERVED_RESOURCE_ID_MAX 1023
+
+#define VMCI_DOMAIN_NAME_MAXLEN  32
+
+#define VMCI_LGPFX "VMCI: "
+
+
+/*
+ * VMCIQueueHeader
+ *
+ * A Queue cannot stand by itself as designed.  Each Queue's header
+ * contains a pointer into itself (the producerTail) and into its peer
+ * (consumerHead).  The reason for the separation is one of
+ * accessibility: Each end-point can modify two things: where the next
+ * location to enqueue is within its produceQ (producerTail); and
+ * where the next dequeue location is in its consumeQ (consumerHead).
+ *
+ * An end-point cannot modify the pointers of its peer (guest to
+ * guest; NOTE that in the host both queue headers are mapped r/w).
+ * But, each end-point needs read access to both Queue header
+ * structures in order to determine how much space is used (or left)
+ * in the Queue.  This is because for an end-point to know how full
+ * its produceQ is, it needs to use the consumerHead that points into
+ * the produceQ but -that- consumerHead is in the Queue header for
+ * that end-points consumeQ.
+ *
+ * Thoroughly confused?  Sorry.
+ *
+ * producerTail: the point to enqueue new entrants.  When you approach
+ * a line in a store, for example, you walk up to the tail.
+ *
+ * consumerHead: the point in the queue from which the next element is
+ * dequeued.  In other words, who is next in line is he who is at the
+ * head of the line.
+ *
+ * Also, producerTail points to an empty byte in the Queue, whereas
+ * consumerHead points to a valid byte of data (unless producerTail ==
+ * consumerHead in which case consumerHead does not point to a valid
+ * byte of data).
+ *
+ * For a queue of buffer 'size' bytes, the tail and head pointers will be in
+ * the range [0, size-1].
+ *
+ * If produceQHeader->producerTail == consumeQHeader->consumerHead
+ * then the produceQ is empty.
+ */
+
+typedef struct VMCIQueueHeader {
+   /* All fields are 64bit and aligned. */
+   VMCIHandle    handle;       /* Identifier. */
+   Atomic_uint64 producerTail; /* Offset in this queue. */
+   Atomic_uint64 consumerHead; /* Offset in peer queue. */
+} VMCIQueueHeader;
+
+
+/*
+ * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
+ * size to be less than 4GB, and use 32bit atomic operations on the head and
+ * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
+ * is an atomic read-modify-write. This will cause traces to fire when a 32bit
+ * consumer tries to read the producer's tail pointer, for example, because the
+ * consumer has read-only access to the producer's tail pointer.
+ *
+ * We provide the following macros to invoke 32bit or 64bit atomic operations
+ * based on the architecture the code is being compiled on.
+ */
+
+/* Architecture independent maximum queue size. */
+#define QP_MAX_QUEUE_SIZE_ARCH_ANY   CONST64U(0xffffffff)
+
+#ifdef __x86_64__
+#  define QP_MAX_QUEUE_SIZE_ARCH     CONST64U(0xffffffffffffffff)
+#  define QPAtomic_ReadOffset(x)     Atomic_Read64(x)
+#  define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y)
+#else
+   /*
+    * Wrappers below are being used to call Atomic_Read32 because of the
+    * 'type punned' compilation warning received when Atomic_Read32 is
+    * called with a Atomic_uint64 pointer typecasted to Atomic_uint32
+    * pointer from QPAtomic_ReadOffset. Ditto with QPAtomic_WriteOffset.
+    */
+
+   static INLINE uint32
+   TypeSafe_Atomic_Read32(void *var) // IN:
+   {
+      return Atomic_Read32((Atomic_uint32 *)(var));
+   }
+
+   static INLINE void
+   TypeSafe_Atomic_Write32(void *var, uint32 val) // IN:
+   {
+      Atomic_Write32((Atomic_uint32 *)(var), (uint32)(val));
+   }
+
+#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffff)
+#  define QPAtomic_ReadOffset(x)  TypeSafe_Atomic_Read32((void *)(x))
+#  define QPAtomic_WriteOffset(x, y) \
+          TypeSafe_Atomic_Write32((void *)(x), (uint32)(y))
+#endif /* __x86_64__  */
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QPAddPointer --
+ *
+ *      Helper to add a given offset to a head or tail pointer. Wraps the value
+ *      of the pointer around the max size of the queue.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+QPAddPointer(Atomic_uint64 *var, // IN:
+             size_t add,         // IN:
+             uint64 size)        // IN:
+{
+   uint64 newVal = QPAtomic_ReadOffset(var);
+
+   if (newVal >= size - add) {
+      newVal -= size;
+   }
+   newVal += add;
+
+   QPAtomic_WriteOffset(var, newVal);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_ProducerTail() --
+ *
+ *      Helper routine to get the Producer Tail from the supplied queue.
+ *
+ * Results:
+ *      The contents of the queue's producer tail.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCIQueueHeader_ProducerTail(const VMCIQueueHeader *qHeader) // IN:
+{
+   VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader;
+   return QPAtomic_ReadOffset(&qh->producerTail);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_ConsumerHead() --
+ *
+ *      Helper routine to get the Consumer Head from the supplied queue.
+ *
+ * Results:
+ *      The contents of the queue's consumer tail.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCIQueueHeader_ConsumerHead(const VMCIQueueHeader *qHeader) // IN:
+{
+   VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader;
+   return QPAtomic_ReadOffset(&qh->consumerHead);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_AddProducerTail() --
+ *
+ *      Helper routine to increment the Producer Tail.  Fundamentally,
+ *      QPAddPointer() is used to manipulate the tail itself.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_AddProducerTail(VMCIQueueHeader *qHeader, // IN/OUT:
+                                size_t add,               // IN:
+                                uint64 queueSize)         // IN:
+{
+   QPAddPointer(&qHeader->producerTail, add, queueSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_AddConsumerHead() --
+ *
+ *      Helper routine to increment the Consumer Head.  Fundamentally,
+ *      QPAddPointer() is used to manipulate the head itself.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_AddConsumerHead(VMCIQueueHeader *qHeader, // IN/OUT:
+                                size_t add,               // IN:
+                                uint64 queueSize)         // IN:
+{
+   QPAddPointer(&qHeader->consumerHead, add, queueSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_CheckAlignment --
+ *
+ *      Checks if the given queue is aligned to page boundary.  Returns TRUE if
+ *      the alignment is good.
+ *
+ * Results:
+ *      TRUE or FALSE.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+VMCIQueueHeader_CheckAlignment(const VMCIQueueHeader *qHeader) // IN:
+{
+   uintptr_t hdr, offset;
+
+   hdr = (uintptr_t) qHeader;
+   offset = hdr & (PAGE_SIZE -1);
+
+   return offset == 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_GetPointers --
+ *
+ *      Helper routine for getting the head and the tail pointer for a queue.
+ *      Both the VMCIQueues are needed to get both the pointers for one queue.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_GetPointers(const VMCIQueueHeader *produceQHeader, // IN:
+                            const VMCIQueueHeader *consumeQHeader, // IN:
+                            uint64 *producerTail,                  // OUT:
+                            uint64 *consumerHead)                  // OUT:
+{
+   if (producerTail) {
+      *producerTail = VMCIQueueHeader_ProducerTail(produceQHeader);
+   }
+
+   if (consumerHead) {
+      *consumerHead = VMCIQueueHeader_ConsumerHead(consumeQHeader);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_ResetPointers --
+ *
+ *      Reset the tail pointer (of "this" queue) and the head pointer (of
+ *      "peer" queue).
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_ResetPointers(VMCIQueueHeader *qHeader) // IN/OUT:
+{
+   QPAtomic_WriteOffset(&qHeader->producerTail, CONST64U(0));
+   QPAtomic_WriteOffset(&qHeader->consumerHead, CONST64U(0));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_Init --
+ *
+ *      Initializes a queue's state (head & tail pointers).
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueueHeader_Init(VMCIQueueHeader *qHeader, // IN/OUT:
+                     const VMCIHandle handle)  // IN:
+{
+   qHeader->handle = handle;
+   VMCIQueueHeader_ResetPointers(qHeader);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_FreeSpace --
+ *
+ *      Finds available free space in a produce queue to enqueue more
+ *      data or reports an error if queue pair corruption is detected.
+ *
+ * Results:
+ *      Free space size in bytes or an error code.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE int64
+VMCIQueueHeader_FreeSpace(const VMCIQueueHeader *produceQHeader, // IN:
+                          const VMCIQueueHeader *consumeQHeader, // IN:
+                          const uint64 produceQSize)             // IN:
+{
+   uint64 tail;
+   uint64 head;
+   uint64 freeSpace;
+
+   tail = VMCIQueueHeader_ProducerTail(produceQHeader);
+   head = VMCIQueueHeader_ConsumerHead(consumeQHeader);
+
+   if (tail >= produceQSize || head >= produceQSize) {
+      return VMCI_ERROR_INVALID_SIZE;
+   }
+
+   /*
+    * Deduct 1 to avoid tail becoming equal to head which causes ambiguity. If
+    * head and tail are equal it means that the queue is empty.
+    */
+
+   if (tail >= head) {
+      freeSpace = produceQSize - (tail - head) - 1;
+   } else {
+      freeSpace = head - tail - 1;
+   }
+
+   return freeSpace;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueueHeader_BufReady --
+ *
+ *      VMCIQueueHeader_FreeSpace() does all the heavy lifting of
+ *      determing the number of free bytes in a Queue.  This routine,
+ *      then subtracts that size from the full size of the Queue so
+ *      the caller knows how many bytes are ready to be dequeued.
+ *
+ * Results:
+ *      On success, available data size in bytes (up to MAX_INT64).
+ *      On failure, appropriate error code.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE int64
+VMCIQueueHeader_BufReady(const VMCIQueueHeader *consumeQHeader, // IN:
+                         const VMCIQueueHeader *produceQHeader, // IN:
+                         const uint64 consumeQSize)             // IN:
+{
+   int64 freeSpace;
+
+   freeSpace = VMCIQueueHeader_FreeSpace(consumeQHeader,
+                                         produceQHeader,
+                                         consumeQSize);
+   if (freeSpace < VMCI_SUCCESS) {
+      return freeSpace;
+   } else {
+      return consumeQSize - freeSpace - 1;
+   }
+}
+
+
+#endif
+
index 3078e670a8ffc27be3abf5c837a8e1ace7e53aa3..4ea26674f7a7e1aa57f8b0e9a2faeb44d808bc2d 100644 (file)
@@ -90,7 +90,7 @@ HgfsSendOpenDirRequest(HgfsSuperInfo *sip,   // IN: Superinfo pointer
    request->reserved = 0;
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
 
    /*
     * Convert an input string to utf8 precomposed form, convert it to
@@ -190,7 +190,7 @@ HgfsSendOpenRequest(HgfsSuperInfo *sip,   // IN: Superinfo pointer
    request->reserved2 = 0;
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
    request->mode = openMode;
    request->flags = openFlags;
    DEBUG(VM_DEBUG_COMM, "open flags are %x\n", request->flags);
index 8b9b59c58347c4717813fc5c94e3a0227099e171..06064083e4d1d0861719b1cd3c1f6d9c4ba33d1a 100644 (file)
@@ -92,7 +92,7 @@ HgfsStatfsInt(struct vnode *vp,          // IN: vnode
    request->reserved = 0;
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
 
    fullPath = HGFS_VP_TO_FILENAME(vp);
    fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
index cfe4d1fbce04afa1a400996f65a89ee1f4c40613..79ede776428d331c3576862bdbf0046e5ba43666 100644 (file)
@@ -554,7 +554,7 @@ HgfsSetattrInt(struct vnode *vp,     // IN : vnode of the file
    fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
 
    /*
     * Convert an input string to utf8 precomposed form, convert it to
@@ -1431,7 +1431,7 @@ HgfsMkdirInt(struct vnode *dvp,         // IN : directory vnode
    request->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
 
    /*
     * Convert an input string to utf8 precomposed form, convert it to
@@ -2179,7 +2179,7 @@ HgfsDelete(HgfsSuperInfo *sip,          // IN: Superinfo
    request->reserved = 0;
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
 
    /*
     * Convert an input string to utf8 precomposed form, convert it to
@@ -2523,7 +2523,7 @@ HgfsSymlinkInt(struct vnode *dvp,         // IN : directory vnode
    request->symlinkName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
 
    /*
     * Convert an input string to utf8 precomposed form, convert it to
@@ -2781,7 +2781,7 @@ HgfsQueryAttrInt(const char *path,       // IN : Path to get attributes for
    request->reserved = 0;
 
    reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(HGFS_PACKET_MAX, reqSize);
 
    /*
     * Per the calling conventions of this function, if the path is NULL then
index 3ae90f1f6464f46700c43102aabf2ac4b67a0056..c58b6d8acc67350653d637aa3ebcd38a1e6e83fe 100644 (file)
@@ -93,7 +93,8 @@ typedef uint32 VMCI_Resource;
 #define VMCI_QUEUEPAIR_ALLOC      10
 #define VMCI_QUEUEPAIR_DETACH     11
 #define VMCI_VSOCK_VMX_LOOKUP     12
-#define VMCI_RESOURCE_MAX         13
+#define VMCI_HGFS_TRANSPORT       13
+#define VMCI_RESOURCE_MAX         14
 
 /* VMCI Ids. */
 typedef uint32 VMCIId;
@@ -107,7 +108,9 @@ static INLINE
 VMCIHandle VMCI_MAKE_HANDLE(VMCIId cid, 
                            VMCIId rid)
 {
-   VMCIHandle h = {cid, rid};
+   VMCIHandle h;
+   h.context = cid;
+   h.resource = rid;
    return h;
 }
 
@@ -263,6 +266,10 @@ static const VMCIHandle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID,
 #define VMCI_ERROR_BUSMEM_INVALIDATION   (-37)
 #define VMCI_ERROR_MODULE_NOT_LOADED     (-38)
 
+/* VMCI clients should return error code withing this range */
+#define VMCI_ERROR_CLIENT_MIN     (-500)
+#define VMCI_ERROR_CLIENT_MAX     (-550)
+
 /* Internal error codes. */
 #define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT (-1000)
 
index 935c8a92e61156112269500190e4dfdb329bb3fc..5bcac3f55e6d3453a45ba041f2a288585c50b607 100644 (file)
 
 #include <linux/errno.h>
 
-#include "bdhandler.h"
+#include "transport.h"
 #include "hgfsBd.h"
 #include "hgfsDevLinux.h"
 #include "hgfsProto.h"
 #include "module.h"
 #include "request.h"
 #include "rpcout.h"
-#include "transport.h"
 #include "vm_assert.h"
 
 
+static Bool HgfsBdChannelOpen(HgfsTransportChannel *channel);
+static void HgfsBdChannelClose(HgfsTransportChannel *channel);
+static HgfsReq * HgfsBdChannelAllocate(size_t payloadSize);
+void HgfsBdChannelFree(HgfsReq *req);
+static int HgfsBdChannelSend(HgfsTransportChannel *channel, HgfsReq *req);
+
+static HgfsTransportChannel channel = {
+   .name = "backdoor",
+   .ops.open = HgfsBdChannelOpen,
+   .ops.close = HgfsBdChannelClose,
+   .ops.allocate = HgfsBdChannelAllocate,
+   .ops.free = HgfsBdChannelFree,
+   .ops.send = HgfsBdChannelSend,
+   .priv = NULL,
+   .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -104,7 +121,7 @@ HgfsBdChannelClose(HgfsTransportChannel *channel) // IN: Channel
  *
  * HgfsBdChannelAllocate --
  *
- *      Allocate request uin the way that is suitable for sending through
+ *      Allocate request in a way that is suitable for sending through
  *      backdoor.
  *
  * Results:
@@ -129,12 +146,37 @@ HgfsBdChannelAllocate(size_t payloadSize) // IN: size of requests payload
              HGFS_SYNC_REQREP_CLIENT_CMD_LEN);
 
       req->payload = req->buffer + HGFS_SYNC_REQREP_CLIENT_CMD_LEN;
+      req->bufferSize = payloadSize;
    }
 
    return req;
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsBdChannelFree --
+ *
+ *     Free previously allocated request.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsBdChannelFree(HgfsReq *req)
+{
+   ASSERT(req);
+   kfree(req);
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -161,7 +203,7 @@ HgfsBdChannelSend(HgfsTransportChannel *channel, // IN: Channel
 
    ASSERT(req);
    ASSERT(req->state == HGFS_REQ_STATE_UNSENT);
-   ASSERT(req->payloadSize <= HGFS_PACKET_MAX);
+   ASSERT(req->payloadSize <= req->bufferSize);
 
    LOG(8, ("VMware hgfs: %s: backdoor sending.\n", __func__));
    payloadSize = req->payloadSize;
@@ -200,15 +242,5 @@ HgfsBdChannelSend(HgfsTransportChannel *channel, // IN: Channel
 HgfsTransportChannel*
 HgfsGetBdChannel(void)
 {
-   static HgfsTransportChannel channel;
-
-   channel.name = "backdoor";
-   channel.ops.open = HgfsBdChannelOpen;
-   channel.ops.close = HgfsBdChannelClose;
-   channel.ops.allocate = HgfsBdChannelAllocate;
-   channel.ops.send = HgfsBdChannelSend;
-   channel.priv = NULL;
-   channel.status = HGFS_CHANNEL_NOTCONNECTED;
-
    return &channel;
 }
diff --git a/open-vm-tools/modules/linux/vmhgfs/bdhandler.h b/open-vm-tools/modules/linux/vmhgfs/bdhandler.h
deleted file mode 100644 (file)
index 2689e9c..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*********************************************************
- * Copyright (C) 2006 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- *********************************************************/
-
-/*
- * bdhandler.h --
- *
- * Backdoor channel implementation.
- */
-
-#ifndef _HGFS_DRIVER_BDHANDLER_H_
-#define _HGFS_DRIVER_BDHANDLER_H_
-
-#include "transport.h"
-
-HgfsTransportChannel *HgfsGetBdChannel(void);
-
-#endif // _HGFS_DRIVER_BDHANDLER_H_
index b9f6ddbefd4143d97047699244582a4f444939f5..c94c9518fbc7f5b141b295d7bcd71f3d47f8b35d 100644 (file)
@@ -167,7 +167,7 @@ HgfsUnpackSearchReadReply(HgfsReq *req,        // IN: Reply packet
     * Make sure name length is legal.
     */
    if (fileNameLength > NAME_MAX ||
-       fileNameLength > HGFS_PACKET_MAX - replySize) {
+       fileNameLength > req->bufferSize - replySize) {
       return -ENAMETOOLONG;
    }
 
@@ -395,7 +395,7 @@ HgfsPackDirOpenRequest(struct file *file,   // IN: File pointer for this open
    }
 
    /* Build full name to send to server. */
-   if (HgfsBuildPath(name, HGFS_PACKET_MAX - (requestSize - 1),
+   if (HgfsBuildPath(name, req->bufferSize - (requestSize - 1),
                      file->f_dentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: build path failed\n"));
       return -EINVAL;
@@ -405,7 +405,7 @@ HgfsPackDirOpenRequest(struct file *file,   // IN: File pointer for this open
 
    /* Convert to CP name. */
    result = CPName_ConvertTo(name,
-                             HGFS_PACKET_MAX - (requestSize - 1),
+                             req->bufferSize - (requestSize - 1),
                              name);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackDirOpenRequest: CP conversion failed\n"));
index c7ab86ec91c9ef4edb7c6a0996ac8db30b87d0a7..f486f71d5bfab6ce03484585927d859cf0bff84d 100644 (file)
@@ -315,7 +315,7 @@ HgfsPackOpenRequest(struct inode *inode, // IN: Inode of the file to open
 
    /* Build full name to send to server. */
    if (HgfsBuildPath(name,
-                     HGFS_PACKET_MAX - (requestSize - 1),
+                     req->bufferSize - (requestSize - 1),
                      file->f_dentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: build path "
               "failed\n"));
@@ -327,7 +327,7 @@ HgfsPackOpenRequest(struct inode *inode, // IN: Inode of the file to open
 
    /* Convert to CP name. */
    result = CPName_ConvertTo(name,
-                             HGFS_PACKET_MAX - (requestSize - 1),
+                             req->bufferSize - (requestSize - 1),
                              name);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackOpenRequest: CP conversion "
index a1ae581f4ad58b06f480df501e58821b40796e7f..338ed552614436e65295543d44dfa9dd33f9e256 100644 (file)
@@ -117,6 +117,7 @@ static struct file_system_type hgfsType = {
    .kill_sb      = kill_anon_super,
 };
 
+extern int USE_VMCI;
 
 /*
  * Private functions implementations.
@@ -527,6 +528,12 @@ HgfsResetOps(void)
    hgfsVersionRename          = HGFS_OP_RENAME_V3;
    hgfsVersionQueryVolumeInfo = HGFS_OP_QUERY_VOLUME_INFO_V3;
    hgfsVersionCreateSymlink   = HGFS_OP_CREATE_SYMLINK_V3;
+
+   if (USE_VMCI) {
+      hgfsVersionRead = HGFS_OP_READ_FAST_V3;
+      hgfsVersionWrite = HGFS_OP_WRITE_FAST_V3;
+   }
+
 }
 
 
index 39fd8aa0cbdb75b160aac588d4f325811502eacb..4c0b9fdba2731b53874d45e0a94a5e53ed92d43e 100644 (file)
@@ -164,7 +164,7 @@ HgfsUnpackGetattrReply(HgfsReq *req,        // IN: Reply packet
       length = replyV3->symlinkTarget.length;
 
       /* Skip the symlinkTarget if it's too long. */
-      if (length > HGFS_NAME_BUFFER_SIZET(sizeof *replyV3 + sizeof(HgfsReply))) {
+      if (length > HGFS_NAME_BUFFER_SIZET(req->bufferSize, sizeof *replyV3 + sizeof(HgfsReply))) {
          LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: symlink "
                  "target name too long, ignoring\n"));
          return -ENAMETOOLONG;
@@ -176,7 +176,7 @@ HgfsUnpackGetattrReply(HgfsReq *req,        // IN: Reply packet
       length = replyV2->symlinkTarget.length;
 
       /* Skip the symlinkTarget if it's too long. */
-      if (length > HGFS_NAME_BUFFER_SIZE(replyV2)) {
+      if (length > HGFS_NAME_BUFFER_SIZE(req->bufferSize, replyV2)) {
          LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: symlink "
                  "target name too long, ignoring\n"));
          return -ENAMETOOLONG;
@@ -279,7 +279,7 @@ HgfsPackGetattrRequest(HgfsReq *req,            // IN/OUT: Request buffer
       }
       requestV3->reserved = 0;
       reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3);
-      reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+      reqBufferSize = HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize);
       break;
    }
 
@@ -308,7 +308,7 @@ HgfsPackGetattrRequest(HgfsReq *req,            // IN/OUT: Request buffer
          fileNameLength = &requestV2->fileName.length;
       }
       reqSize = sizeof *requestV2;
-      reqBufferSize = HGFS_NAME_BUFFER_SIZE(requestV2);
+      reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2);
       break;
    }
 
@@ -322,7 +322,7 @@ HgfsPackGetattrRequest(HgfsReq *req,            // IN/OUT: Request buffer
       fileName = requestV1->fileName.name;
       fileNameLength = &requestV1->fileName.length;
       reqSize = sizeof *requestV1;
-      reqBufferSize = HGFS_NAME_BUFFER_SIZE(requestV1);
+      reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV1);
       break;
    }
 
index 8361cbccf991d866a135fb6011926a9523c033b9..a9f57c8572990cdc1e6d3378cb9a400b9fb11b78 100644 (file)
@@ -238,7 +238,7 @@ HgfsDelete(struct inode *dir,      // IN: Parent dir of file/dir to delete
    }
 
    /* Build full name to send to server. */
-   if (HgfsBuildPath(fileName, HGFS_NAME_BUFFER_SIZET(reqSize),
+   if (HgfsBuildPath(fileName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
                      dentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: build path failed\n"));
       result = -EINVAL;
@@ -249,7 +249,7 @@ HgfsDelete(struct inode *dir,      // IN: Parent dir of file/dir to delete
 
    /* Convert to CP name. */
    result = CPName_ConvertTo(fileName,
-                             HGFS_NAME_BUFFER_SIZET(reqSize),
+                             HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
                              fileName);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDelete: CP conversion failed\n"));
@@ -449,7 +449,7 @@ HgfsPackSetattrRequest(struct iattr *iattr,   // IN: Inode attrs to update from
       }
       requestV3->reserved = 0;
       reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(requestV3);
-      reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+      reqBufferSize = HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize);
 
       /*
        * We only support changing these attributes:
@@ -552,7 +552,7 @@ HgfsPackSetattrRequest(struct iattr *iattr,   // IN: Inode attrs to update from
         fileNameLength = &requestV2->fileName.length;
       }
       reqSize = sizeof *requestV2;
-      reqBufferSize = HGFS_NAME_BUFFER_SIZE(requestV2);
+      reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, requestV2);
 
       /*
        * We only support changing these attributes:
@@ -626,7 +626,7 @@ HgfsPackSetattrRequest(struct iattr *iattr,   // IN: Inode attrs to update from
       fileName = request->fileName.name;
       fileNameLength = &request->fileName.length;
       reqSize = sizeof *request;
-      reqBufferSize = HGFS_NAME_BUFFER_SIZE(request);
+      reqBufferSize = HGFS_NAME_BUFFER_SIZE(req->bufferSize, request);
 
 
       /*
@@ -811,7 +811,7 @@ HgfsPackCreateDirRequest(struct dentry *dentry, // IN: Directory to create
 
    /* Build full name to send to server. */
    if (HgfsBuildPath(fileName,
-                     HGFS_PACKET_MAX - (requestSize - 1),
+                     req->bufferSize - (requestSize - 1),
                      dentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: build path "
               "failed\n"));
@@ -822,7 +822,7 @@ HgfsPackCreateDirRequest(struct dentry *dentry, // IN: Directory to create
 
    /* Convert to CP name. */
    result = CPName_ConvertTo(fileName,
-                             HGFS_PACKET_MAX - (requestSize - 1),
+                             req->bufferSize - (requestSize - 1),
                              fileName);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackCreateDirRequest: CP "
@@ -1364,7 +1364,7 @@ retry:
    }
 
    /* Build full old name to send to server. */
-   if (HgfsBuildPath(oldName, HGFS_NAME_BUFFER_SIZET(reqSize),
+   if (HgfsBuildPath(oldName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
                      oldDentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: build old path failed\n"));
       result = -EINVAL;
@@ -1375,7 +1375,7 @@ retry:
 
    /* Convert old name to CP format. */
    result = CPName_ConvertTo(oldName,
-                             HGFS_NAME_BUFFER_SIZET(reqSize),
+                             HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize),
                              oldName);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: oldName CP "
@@ -1413,7 +1413,7 @@ retry:
       newNameLength = &newNameP->length;
    }
 
-   if (HgfsBuildPath(newName, HGFS_NAME_BUFFER_SIZET(reqSize) - result,
+   if (HgfsBuildPath(newName, HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize) - result,
                      newDentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: build new path failed\n"));
       result = -EINVAL;
@@ -1424,7 +1424,7 @@ retry:
 
    /* Convert new name to CP format. */
    result = CPName_ConvertTo(newName,
-                             HGFS_NAME_BUFFER_SIZET(reqSize) - result,
+                             HGFS_NAME_BUFFER_SIZET(req->bufferSize, reqSize) - result,
                              newName);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: newName CP "
@@ -1545,7 +1545,7 @@ HgfsPackSymlinkCreateRequest(struct dentry *dentry,   // IN: File pointer for th
       return -EPROTO;
    }
 
-   if (HgfsBuildPath(symlinkName, HGFS_PACKET_MAX - (requestSize - 1),
+   if (HgfsBuildPath(symlinkName, req->bufferSize - (requestSize - 1),
                      dentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: build symlink path "
               "failed\n"));
@@ -1557,7 +1557,7 @@ HgfsPackSymlinkCreateRequest(struct dentry *dentry,   // IN: File pointer for th
 
    /* Convert symlink name to CP format. */
    result = CPName_ConvertTo(symlinkName,
-                             HGFS_PACKET_MAX - (requestSize - 1),
+                             req->bufferSize - (requestSize - 1),
                              symlinkName);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: symlinkName CP "
@@ -1597,7 +1597,7 @@ HgfsPackSymlinkCreateRequest(struct dentry *dentry,   // IN: File pointer for th
    targetNameBytes = strlen(symname) + 1;
 
    /* Copy target name into request packet. */
-   if (targetNameBytes > HGFS_PACKET_MAX - (requestSize - 1)) {
+   if (targetNameBytes > req->bufferSize - (requestSize - 1)) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackSymlinkCreateRequest: target name is too "
               "big\n"));
       return -EINVAL;
index 746165294dba07ec462fc23a152992d4e9f7638b..5ec0bf094c2405a7b342fe780f5e53f2d76f0b05 100644 (file)
 #include "inode.h"
 #include "vm_assert.h"
 #include "vm_basic_types.h"
+#include "hgfsTransport.h"
+
 
 /* Private functions. */
 static int HgfsDoWrite(HgfsHandle handle,
-                       const char *buf,
-                       size_t count,
+                       HgfsDataPacket dataPacket[],
+                       uint32 numEntries,
                        loff_t offset);
 static int HgfsDoRead(HgfsHandle handle,
-                      char *buf,
-                      size_t count,
+                      HgfsDataPacket dataPacket[],
+                      uint32 numEntries,
                       loff_t offset);
 static int HgfsDoReadpage(HgfsHandle handle,
                           struct page *page,
@@ -143,6 +145,8 @@ struct address_space_operations HgfsAddressSpaceOperations = {
  *    It is assumed that this function is never called with a larger read than
  *    what can be sent in one request.
  *
+ *    HgfsDataPacket is an array of pages into which data will be read.
+ *
  * Results:
  *    Returns the number of bytes read on success, or an error on failure.
  *
@@ -153,10 +157,10 @@ struct address_space_operations HgfsAddressSpaceOperations = {
  */
 
 static int
-HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
-           char *buf,          // OUT: Buffer to copy data into
-           size_t count,       // IN:  Number of bytes to read
-           loff_t offset)      // IN:  Offset at which to read
+HgfsDoRead(HgfsHandle handle,             // IN:  Handle for this file
+           HgfsDataPacket dataPacket[],   // IN/OUT: Data description
+           uint32 numEntries,             // IN: Number of entries in dataPacket
+           loff_t offset)                 // IN:  Offset at which to read
 {
    HgfsReq *req;
    HgfsOp opUsed;
@@ -164,8 +168,9 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
    uint32 actualSize = 0;
    char *payload = NULL;
    HgfsStatus replyStatus;
-
-   ASSERT(buf);
+   char *buf;
+   ASSERT(numEntries == 1);
+   uint32 count = dataPacket[0].len;
 
    req = HgfsGetNewRequest();
    if (!req) {
@@ -177,7 +182,31 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
 
  retry:
    opUsed = hgfsVersionRead;
-   if (opUsed == HGFS_OP_READ_V3) {
+   if (opUsed == HGFS_OP_READ_FAST_V3) {
+      HgfsRequest *header;
+      HgfsRequestReadV3 *request;
+
+      header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req));
+      header->id = req->id;
+      header->op = opUsed;
+
+      request = (HgfsRequestReadV3 *)(HGFS_REQ_PAYLOAD_V3(req));
+      request->file = handle;
+      request->offset = offset;
+      request->requiredSize = count;
+      request->reserved = 0;
+      req->dataPacket = kmalloc(numEntries * sizeof req->dataPacket[0],
+                                GFP_KERNEL);
+      if (!req->dataPacket) {
+         LOG(4, (KERN_DEBUG "%s: Failed to allocate mem\n", __func__));
+         result = -ENOMEM;
+         goto out;
+      }
+      memcpy(req->dataPacket, dataPacket, numEntries * sizeof req->dataPacket[0]);
+      req->numEntries = numEntries;
+
+      LOG(4, (KERN_DEBUG "VMware hgfs: Fast Read\n"));
+   } else if (opUsed == HGFS_OP_READ_V3) {
       HgfsRequest *header;
       HgfsRequestReadV3 *request;
 
@@ -190,6 +219,7 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
       request->offset = offset;
       request->requiredSize = count;
       request->reserved = 0;
+      req->dataPacket = NULL;
       req->payloadSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
    } else {
       HgfsRequestRead *request;
@@ -200,10 +230,10 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
       request->file = handle;
       request->offset = offset;
       request->requiredSize = count;
+      req->dataPacket = NULL;
       req->payloadSize = sizeof *request;
    }
 
-
    /* Send the request and process the reply. */
    result = HgfsSendRequest(req);
    if (result == 0) {
@@ -213,7 +243,9 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
 
       switch (result) {
       case 0:
-         if (opUsed == HGFS_OP_READ_V3) {
+         if (opUsed == HGFS_OP_READ_FAST_V3) {
+            actualSize = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize;
+         } else if (opUsed == HGFS_OP_READ_V3) {
             actualSize = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize;
             payload = ((HgfsReplyReadV3 *)HGFS_REP_PAYLOAD_V3(req))->payload;
          } else {
@@ -229,7 +261,7 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
          }
 
          if (!actualSize) {
-            /* We got no bytes, so don't need to copy to user. */
+            /* We got no bytes. */
             LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoRead: server returned "
                    "zero\n"));
             result = actualSize;
@@ -237,19 +269,34 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
          }
 
          /* Return result. */
-         memcpy(buf, payload, actualSize);
-         LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoRead: copied %u\n",
-                 actualSize));
+         if (opUsed == HGFS_OP_READ_V3 || opUsed == HGFS_OP_READ) {
+            buf = kmap(dataPacket[0].page) + dataPacket[0].offset;
+            ASSERT(buf);
+            memcpy(buf, payload, actualSize);
+            LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoRead: copied %u\n",
+                    actualSize));
+            kunmap(dataPacket[0].page);
+         }
          result = actualSize;
         break;
 
       case -EPROTO:
          /* Retry with older version(s). Set globally. */
-         if (opUsed == HGFS_OP_READ_V3) {
+         switch (opUsed) {
+         case HGFS_OP_READ_FAST_V3:
+            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoRead: Fast Read not "
+                    "supported. Falling back to V3 Read.\n"));
+            hgfsVersionRead = HGFS_OP_READ_V3;
+            goto retry;
+
+         case HGFS_OP_READ_V3:
             LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoRead: Version 3 not "
                     "supported. Falling back to version 1.\n"));
             hgfsVersionRead = HGFS_OP_READ;
             goto retry;
+
+         default:
+            break;
          }
         break;
 
@@ -267,6 +314,9 @@ HgfsDoRead(HgfsHandle handle,  // IN:  Handle for this file
    }
 
 out:
+   if (req->dataPacket) {
+      kfree(req->dataPacket);
+   }
    HgfsFreeRequest(req);
    return result;
 }
@@ -286,6 +336,9 @@ out:
  *    It is assumed that this function is never called with a larger write
  *    than what can be sent in one request.
  *
+ *    HgfsDataPacket is an array of pages from which data will be written
+ *    to file.
+ *
  * Results:
  *    Returns the number of bytes written on success, or an error on failure.
  *
@@ -296,10 +349,10 @@ out:
  */
 
 static int
-HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
-            const char *buf,         // IN: Buffer containing data
-            size_t count,            // IN: Number of bytes to write
-            loff_t offset)           // IN: Offset to begin writing at
+HgfsDoWrite(HgfsHandle handle,             // IN: Handle for this file
+            HgfsDataPacket dataPacket[],   // IN: Data description
+            uint32 numEntries,             // IN: Number of entries in dataPacket
+            loff_t offset)                 // IN: Offset to begin writing at
 {
    HgfsReq *req;
    int result = 0;
@@ -309,8 +362,9 @@ HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
    char *payload = NULL;
    uint32 reqSize;
    HgfsStatus replyStatus;
-
-   ASSERT(buf);
+   char *buf;
+   ASSERT(numEntries == 1);
+   uint32 count = dataPacket[0].len;
 
    req = HgfsGetNewRequest();
    if (!req) {
@@ -322,7 +376,7 @@ HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
 
  retry:
    opUsed = hgfsVersionWrite;
-   if (opUsed == HGFS_OP_WRITE_V3) {
+   if (opUsed == HGFS_OP_WRITE_FAST_V3) {
       HgfsRequest *header;
       HgfsRequestWriteV3 *request;
 
@@ -338,7 +392,42 @@ HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
       request->reserved = 0;
       payload = request->payload;
       requiredSize = request->requiredSize;
+
+      req->dataPacket = kmalloc(numEntries * sizeof req->dataPacket[0],
+                                GFP_KERNEL);
+      if (!req->dataPacket) {
+         LOG(4, (KERN_DEBUG "%s: Failed to allocate mem\n", __func__));
+         result = -ENOMEM;
+         goto out;
+      }
+      memcpy(req->dataPacket, dataPacket, numEntries * sizeof req->dataPacket[0]);
+      req->numEntries = numEntries;
       reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+      req->payloadSize = reqSize;
+      LOG(4, (KERN_DEBUG "VMware hgfs: Fast Write\n"));
+   } else if (opUsed == HGFS_OP_WRITE_V3) {
+      HgfsRequest *header;
+      HgfsRequestWriteV3 *request;
+
+      header = (HgfsRequest *)(HGFS_REQ_PAYLOAD(req));
+      header->id = req->id;
+      header->op = opUsed;
+
+      request = (HgfsRequestWriteV3 *)(HGFS_REQ_PAYLOAD_V3(req));
+      request->file = handle;
+      request->flags = 0;
+      request->offset = offset;
+      request->requiredSize = count;
+      request->reserved = 0;
+      payload = request->payload;
+      requiredSize = request->requiredSize;
+      reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+      req->dataPacket = NULL;
+      buf = kmap(dataPacket[0].page) + dataPacket[0].offset;
+      memcpy(payload, buf, requiredSize);
+      kunmap(dataPacket[0].page);
+
+      req->payloadSize = reqSize + requiredSize - 1;
    } else {
       HgfsRequestWrite *request;
 
@@ -352,10 +441,13 @@ HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
       payload = request->payload;
       requiredSize = request->requiredSize;
       reqSize = sizeof *request;
-   }
+      req->dataPacket = NULL;
+      buf = kmap(dataPacket[0].page) + dataPacket[0].offset;
+      memcpy(payload, buf, requiredSize);
+      kunmap(dataPacket[0].page);
 
-   memcpy(payload, buf, requiredSize);
-   req->payloadSize = reqSize + requiredSize - 1;
+      req->payloadSize = reqSize + requiredSize - 1;
+   }
 
    /* Send the request and process the reply. */
    result = HgfsSendRequest(req);
@@ -366,7 +458,7 @@ HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
 
       switch (result) {
       case 0:
-         if (opUsed == HGFS_OP_WRITE_V3) {
+         if (opUsed == HGFS_OP_WRITE_V3 || opUsed == HGFS_OP_WRITE_FAST_V3) {
             actualSize = ((HgfsReplyWriteV3 *)HGFS_REP_PAYLOAD_V3(req))->actualSize;
          } else {
             actualSize = ((HgfsReplyWrite *)HGFS_REQ_PAYLOAD(req))->actualSize;
@@ -380,11 +472,21 @@ HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
 
       case -EPROTO:
          /* Retry with older version(s). Set globally. */
-         if (opUsed == HGFS_OP_WRITE_V3) {
+         switch (opUsed) {
+         case HGFS_OP_WRITE_FAST_V3:
+            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoWrite: Fast Write not "
+                    "supported. Falling back to V3 write.\n"));
+            hgfsVersionRead = HGFS_OP_WRITE_V3;
+            goto retry;
+
+         case HGFS_OP_WRITE_V3:
             LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoWrite: Version 3 not "
                     "supported. Falling back to version 1.\n"));
             hgfsVersionWrite = HGFS_OP_WRITE;
             goto retry;
+
+         default:
+            break;
          }
          break;
 
@@ -404,6 +506,9 @@ HgfsDoWrite(HgfsHandle handle,       // IN: Handle for this file
    }
 
 out:
+   if (req->dataPacket) {
+      kfree(req->dataPacket);
+   }
    HgfsFreeRequest(req);
    return result;
 }
@@ -436,9 +541,9 @@ HgfsDoReadpage(HgfsHandle handle,  // IN:     Handle to use for reading
                unsigned pageTo)    // IN:     Where to stop reading
 {
    int result = 0;
-   char *buffer = kmap(page) + pageFrom;
    loff_t curOffset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageFrom;
    size_t nextCount, remainingCount = pageTo - pageFrom;
+   HgfsDataPacket dataPacket[1];
 
    LOG(6, (KERN_DEBUG "VMware hgfs: HgfsDoReadpage: read %Zu bytes from fh %u "
            "at offset %Lu\n", remainingCount, handle, curOffset));
@@ -452,7 +557,10 @@ HgfsDoReadpage(HgfsHandle handle,  // IN:     Handle to use for reading
    do {
       nextCount = (remainingCount > HGFS_IO_MAX) ?
          HGFS_IO_MAX : remainingCount;
-      result = HgfsDoRead(handle, buffer, nextCount, curOffset);
+      dataPacket[0].page = page;
+      dataPacket[0].offset = pageFrom;
+      dataPacket[0].len = nextCount;
+      result = HgfsDoRead(handle, dataPacket, 1, curOffset);
       if (result < 0) {
          LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoReadpage: read error %d\n",
                  result));
@@ -460,7 +568,7 @@ HgfsDoReadpage(HgfsHandle handle,  // IN:     Handle to use for reading
       }
       remainingCount -= result;
       curOffset += result;
-      buffer += result;
+      pageFrom += result;
    } while ((result > 0) && (remainingCount > 0));
 
    /*
@@ -468,7 +576,11 @@ HgfsDoReadpage(HgfsHandle handle,  // IN:     Handle to use for reading
     * than a page in the file from this offset, so we should zero the rest of
     * the page's memory.
     */
-   memset(buffer, 0, remainingCount);
+   if (remainingCount) {
+      char *buffer = kmap(page) + pageTo;
+      memset(buffer - remainingCount, 0, remainingCount);
+      kunmap(page);
+   }
 
    /*
     * We read a full page (or all of the page that actually belongs to the
@@ -480,7 +592,6 @@ HgfsDoReadpage(HgfsHandle handle,  // IN:     Handle to use for reading
    result = 0;
 
   out:
-   kunmap(page);
    return result;
 }
 
@@ -526,11 +637,11 @@ HgfsDoWritepage(HgfsHandle handle,  // IN: Handle to use for writing
                 unsigned pageTo)    // IN: Ending page offset
 {
    int result = 0;
-   char *buffer = kmap(page) + pageFrom;
    loff_t curOffset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageFrom;
    size_t nextCount;
    size_t remainingCount = pageTo - pageFrom;
    struct inode *inode;
+   HgfsDataPacket dataPacket[1];
 
    ASSERT(page->mapping);
    ASSERT(page->mapping->host);
@@ -545,7 +656,10 @@ HgfsDoWritepage(HgfsHandle handle,  // IN: Handle to use for writing
    do {
       nextCount = (remainingCount > HGFS_IO_MAX) ?
          HGFS_IO_MAX : remainingCount;
-      result = HgfsDoWrite(handle, buffer, nextCount, curOffset);
+      dataPacket[0].page = page;
+      dataPacket[0].offset = pageFrom;
+      dataPacket[0].len = nextCount;
+      result = HgfsDoWrite(handle, dataPacket, 1, curOffset);
       if (result < 0) {
          LOG(4, (KERN_DEBUG "VMware hgfs: HgfsDoWritepage: write error %d\n",
                  result));
@@ -553,7 +667,7 @@ HgfsDoWritepage(HgfsHandle handle,  // IN: Handle to use for writing
       }
       remainingCount -= result;
       curOffset += result;
-      buffer += result;
+      pageFrom += result;
 
       /* Update the inode's size now rather than waiting for a revalidate. */
       if (curOffset > compat_i_size_read(inode)) {
@@ -564,7 +678,6 @@ HgfsDoWritepage(HgfsHandle handle,  // IN: Handle to use for writing
    result = 0;
 
   out:
-   kunmap(page);
    return result;
 }
 
index 0bd6cb8806a09f6108d298941455c7e8410622dc..f0d3b7474f983beb92d605a13cd9a3c80a33ed83 100644 (file)
@@ -59,7 +59,6 @@
 
 static void
 HgfsRequestInit(HgfsReq *req,       // IN: request to initialize
-                size_t bufferSize,  // Size of the buffer allocated with request
                 int requestId)      // IN: ID assigned to the request
 {
    ASSERT(req);
@@ -69,8 +68,8 @@ HgfsRequestInit(HgfsReq *req,       // IN: request to initialize
    init_waitqueue_head(&req->queue);
    req->id = requestId;
    req->payloadSize = 0;
-   req->bufferSize = bufferSize;
    req->state = HGFS_REQ_STATE_ALLOCATED;
+   req->numEntries = 0;
 }
 
 /*
@@ -102,12 +101,12 @@ HgfsGetNewRequest(void)
       return NULL;
    }
 
-   HgfsRequestInit(req, HGFS_PACKET_MAX,
-                   atomic_inc_return(&hgfsIdCounter) - 1);
+   HgfsRequestInit(req, atomic_inc_return(&hgfsIdCounter) - 1);
 
    return req;
 }
 
+
 /*
  *----------------------------------------------------------------------
  *
@@ -139,9 +138,12 @@ HgfsCopyRequest(HgfsReq *req)   // IN: request to be copied
       return NULL;
    }
 
-   HgfsRequestInit(newReq, req->bufferSize, req->id);
+   HgfsRequestInit(newReq, req->id);
+
+   memcpy(newReq->dataPacket, req->dataPacket,
+          req->numEntries * sizeof (req->dataPacket[0]));
 
-   /* Copy payload from the original request. */
+   newReq->numEntries = req->numEntries;
    newReq->payloadSize = req->payloadSize;
    memcpy(newReq->payload, req->payload, req->payloadSize);
 
@@ -170,8 +172,8 @@ HgfsSendRequest(HgfsReq *req)       // IN/OUT: Outgoing request
    int ret;
 
    ASSERT(req);
-   ASSERT(req->payloadSize <= HGFS_PACKET_MAX);
-
+   ASSERT(req->payloadSize <= req->bufferSize);
+   LOG(4, (KERN_WARNING "Size of buffer %Zu\n", req->bufferSize));
    req->state = HGFS_REQ_STATE_UNSENT;
 
    LOG(8, (KERN_DEBUG "VMware hgfs: HgfsSendRequest: Sending request id %d\n",
@@ -205,7 +207,7 @@ static void HgfsRequestFreeMemory(struct kref *kref)
 
    LOG(10, (KERN_DEBUG "VMware hgfs: %s: freeing request %d\n",
             __func__, req->id));
-   kfree(req);
+   HgfsTransportFreeRequest(req);
 }
 
 /*
index e4a9bdebf8df694dcfdf7e4604fb1ae4fb5fcf10..29a5483f7d598d473f641663b9a64b1bfbcec6fa 100644 (file)
@@ -35,6 +35,7 @@
 #include "compat_wait.h"
 
 #include "hgfs.h" /* For common HGFS definitions. */
+#include "hgfsTransport.h"
 #include "vm_basic_types.h"
 
 /* Macros for accessing the payload portion of the HGFS request packet. */
@@ -44,6 +45,8 @@
 #define HGFS_REQ_PAYLOAD_V3(hgfsReq) (HGFS_REQ_PAYLOAD(hgfsReq) + sizeof(HgfsRequest))
 #define HGFS_REP_PAYLOAD_V3(hgfsRep) (HGFS_REQ_PAYLOAD(hgfsRep) + sizeof(HgfsReply))
 
+#define HGFS_MAX_PAGES 2
+
 /*
  * HGFS_REQ_STATE_ALLOCATED:
  *    The filesystem half has allocated the request from the slab
@@ -76,6 +79,16 @@ typedef enum {
    HGFS_REQ_STATE_COMPLETED,  /* Both header and payload were received. */
 } HgfsState;
 
+/*
+ * Each page that is sent from guest to host is described in the following
+ * format.
+ */
+typedef struct HgfsDataPacket {
+   struct page *page;
+   uint32 offset;
+   uint32 len;
+} HgfsDataPacket;
+
 /*
  * A request to be sent to the user process.
  */
@@ -111,10 +124,20 @@ typedef struct HgfsReq {
    /*
     * Size of the data buffer (below), not including size of chunk
     * used by transport. Must be enough to hold both request and
-    * reply (but not at the same time).
+    * reply (but not at the same time). Initialized in channels.
     */
    size_t bufferSize;
 
+  /*
+   * Used by read and write calls. Hgfs client passes in
+   * pages to the vmci channel using datapackets and vmci channel
+   * uses it to pass PA's to the host.
+   */
+   HgfsDataPacket *dataPacket;
+
+   /* Number of entries in data packet */
+   uint32 numEntries;
+
    /*
     * Packet of data, for both incoming and outgoing messages.
     * Include room for the command.
index 49460c2cf8142b1fdc1bd299ea799a8dd4808cfa..1502513b2c6776dbb897378f2ef1effd1bfe5c3d 100644 (file)
@@ -227,7 +227,7 @@ HgfsPackQueryVolumeRequest(struct dentry *dentry,   // IN: File pointer for this
    }
 
    /* Build full name to send to server. */
-   if (HgfsBuildPath(name, HGFS_PACKET_MAX - (requestSize - 1),
+   if (HgfsBuildPath(name, req->bufferSize - (requestSize - 1),
                      dentry) < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: build path failed\n"));
       return -EINVAL;
@@ -237,7 +237,7 @@ HgfsPackQueryVolumeRequest(struct dentry *dentry,   // IN: File pointer for this
 
    /* Convert to CP name. */
    result = CPName_ConvertTo(name,
-                             HGFS_PACKET_MAX - (requestSize - 1),
+                             req->bufferSize - (requestSize - 1),
                              name);
    if (result < 0) {
       LOG(4, (KERN_DEBUG "VMware hgfs: HgfsPackQueryVolumeRequest: CP conversion failed\n"));
index d2071d986716a01ef9f880e47ba9585c48740a90..0b6990efbdf8983b6c19cb62a52bfdf3edd5c9f0 100644 (file)
@@ -47,7 +47,7 @@
 #include "hgfsProto.h"
 #include "hgfsDevLinux.h"
 #include "module.h"
-#include "tcp.h"
+#include "transport.h"
 
 static char *HOST_IP;
 module_param(HOST_IP, charp, 0444);
@@ -113,6 +113,37 @@ static unsigned long hgfsRecvThreadFlags; /* Used to signal recv data availabili
 
 static void (*oldSocketDataReady)(struct sock *, int);
 
+static Bool HgfsVSocketChannelOpen(HgfsTransportChannel *channel);
+static int HgfsSocketChannelSend(HgfsTransportChannel *channel, HgfsReq *req);
+static void HgfsVSocketChannelClose(HgfsTransportChannel *channel);
+static Bool HgfsTcpChannelOpen(HgfsTransportChannel *channel);
+static void HgfsTcpChannelClose(HgfsTransportChannel *channel);
+static HgfsReq * HgfsSocketChannelAllocate(size_t payloadSize);
+void HgfsSocketChannelFree(HgfsReq *req);
+
+static HgfsTransportChannel vsockChannel = {
+   .name = "vsocket",
+   .ops.close = HgfsVSocketChannelClose,
+   .ops.send = HgfsSocketChannelSend,
+   .ops.open = HgfsVSocketChannelOpen,
+   .ops.allocate = NULL,
+   .ops.free = NULL,
+   .priv = NULL,
+   .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+static HgfsTransportChannel tcpChannel = {
+   .name = "tcp",
+   .ops.open = HgfsTcpChannelOpen,
+   .ops.close = HgfsTcpChannelClose,
+   .ops.allocate = HgfsSocketChannelAllocate,
+   .ops.free = HgfsSocketChannelFree,
+   .ops.send = HgfsSocketChannelSend,
+   .priv = NULL,
+   .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -855,12 +886,37 @@ HgfsSocketChannelAllocate(size_t payloadSize) // IN: size of the payload
                  GFP_KERNEL);
    if (likely(req)) {
       req->payload = req->buffer + sizeof(HgfsSocketHeader);
+      req->bufferSize = payloadSize;
    }
 
    return req;
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsSocketChannelFree --
+ *
+ *     Free previously allocated request.
+ *
+ * Results:
+ *      none
+ *
+ * Side effects:
+ *      Object is freed
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsSocketChannelFree(HgfsReq *req)
+{
+   ASSERT(req);
+   kfree(req);
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -880,21 +936,11 @@ HgfsSocketChannelAllocate(size_t payloadSize) // IN: size of the payload
 HgfsTransportChannel *
 HgfsGetTcpChannel(void)
 {
-   static HgfsTransportChannel channel;
-
-   channel.name = "tcp";
-   channel.ops.open = HgfsTcpChannelOpen;
-   channel.ops.close = HgfsTcpChannelClose;
-   channel.ops.allocate = HgfsSocketChannelAllocate;
-   channel.ops.send = HgfsSocketChannelSend;
-   channel.priv = NULL;
-   channel.status = HGFS_CHANNEL_NOTCONNECTED;
-
    if (!HOST_IP) {
       return NULL;
    }
 
-   return &channel;
+   return &tcpChannel;
 }
 
 
@@ -917,18 +963,10 @@ HgfsGetTcpChannel(void)
 HgfsTransportChannel *
 HgfsGetVSocketChannel(void)
 {
-   static HgfsTransportChannel channel;
-
-   channel.name = "vsocket";
-   channel.ops.open = HgfsVSocketChannelOpen;
-   channel.ops.close = HgfsVSocketChannelClose;
-   channel.ops.send = HgfsSocketChannelSend;
-   channel.priv = NULL;
-   channel.status = HGFS_CHANNEL_NOTCONNECTED;
-
    if (!HOST_VSOCKET_PORT) {
       return NULL;
    }
 
-   return &channel;
+   return &vsockChannel;
 }
+
diff --git a/open-vm-tools/modules/linux/vmhgfs/tcp.h b/open-vm-tools/modules/linux/vmhgfs/tcp.h
deleted file mode 100644 (file)
index b24f8a1..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*********************************************************
- * Copyright (C) 2006 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 and no later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- *********************************************************/
-
-/*
- * tcp.h --
- *
- * Tcp channel implementation.
- */
-
-#ifndef _HGFS_DRIVER_TCP_H_
-#define _HGFS_DRIVER_TCP_H_
-
-#include "transport.h"
-
-HgfsTransportChannel* HgfsGetTcpChannel(void);
-HgfsTransportChannel* HgfsGetVSocketChannel(void);
-
-#endif // _HGFS_DRIVER_TCP_H_
index 747e92c7d20a9b123e2daf53a49602ec99e8289e..735aa0bf27b0452a133bafac59d2c01e7427a90d 100644 (file)
 /* Must be included after sched.h. */
 #include <linux/smp_lock.h>
 
-#include "bdhandler.h"
 #include "hgfsDevLinux.h"
 #include "hgfsProto.h"
 #include "module.h"
 #include "request.h"
-#include "tcp.h"
 #include "transport.h"
 #include "vm_assert.h"
 
+extern int USE_VMCI;
+
 COMPAT_KTHREAD_DECLARE_STOP_INFO();
 static HgfsTransportChannel *hgfsChannel;     /* Current active channel. */
 static compat_mutex_t hgfsChannelLock;        /* Lock to protect hgfsChannel. */
@@ -157,10 +157,22 @@ HgfsTransportSetupNewChannel(void)
 {
    HgfsTransportChannel *newChannel;
 
+   newChannel = HgfsGetVmciChannel();
+   if (newChannel != NULL) {
+      if (HgfsTransportOpenChannel(newChannel)) {
+         hgfsChannel = newChannel;
+         LOG(10, ("CHANNEL: Vmci channel\n"));
+         return TRUE;
+      }
+   }
+
+   USE_VMCI = 0;
+
    newChannel = HgfsGetVSocketChannel();
    if (newChannel != NULL) {
       if (HgfsTransportOpenChannel(newChannel)) {
          hgfsChannel = newChannel;
+         LOG(10, ("CHANNEL: Vsocket channel\n"));
          return TRUE;
       }
    }
@@ -169,11 +181,13 @@ HgfsTransportSetupNewChannel(void)
    if (newChannel != NULL) {
       if (HgfsTransportOpenChannel(newChannel)) {
          hgfsChannel = newChannel;
+         LOG(10, ("CHANNEL: Tcp channel\n"));
          return TRUE;
       }
    }
 
    newChannel = HgfsGetBdChannel();
+   LOG(10, ("CHANNEL: Bd channel\n"));
    ASSERT(newChannel);
    hgfsChannel = newChannel;
    return HgfsTransportOpenChannel(newChannel);
@@ -345,6 +359,36 @@ HgfsTransportAllocateRequest(size_t bufferSize)   // IN: size of the buffer
    return req;
 }
 
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsTransportFreeRequest --
+ *
+ *     Free HGFS request structre using channel-specific free function.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+HgfsTransportFreeRequest(HgfsReq *req)   // IN: size of the buffer
+{
+   /*
+    * We cannot use hgfsChannel structre because global channel could
+    * changes in the meantime. We remember the channel when we do
+    * allocation and call the same channel for de-allocation. Smart.
+    */
+
+   HgfsTransportChannel *channel = (HgfsTransportChannel *)req->transportId;
+   channel->ops.free(req);
+   return;
+}
+
 
 /*
  *----------------------------------------------------------------------
@@ -370,7 +414,7 @@ HgfsTransportSendRequest(HgfsReq *req)   // IN: Request to send
 
    ASSERT(req);
    ASSERT(req->state == HGFS_REQ_STATE_UNSENT);
-   ASSERT(req->payloadSize <= HGFS_PACKET_MAX);
+   ASSERT(req->payloadSize <= req->bufferSize);
 
    compat_mutex_lock(&hgfsChannelLock);
 
@@ -393,7 +437,7 @@ HgfsTransportSendRequest(HgfsReq *req)   // IN: Request to send
       ASSERT(hgfsChannel->ops.send);
 
       /* If channel changed since we created request we need to adjust */
-      if (req->transportId != hgfsChannel) {
+     if (req->transportId != hgfsChannel) {
 
          HgfsTransportRemovePendingRequest(req);
 
index 478b59d116a0b72dbdb7ea0905b70bc65a12fd53..e4ce8e3bc7ee13572ac739fca437ae3d1af5bbc6 100644 (file)
@@ -36,6 +36,7 @@ typedef struct HgfsTransportChannelOps {
    void (*close)(struct HgfsTransportChannel *);
    HgfsReq* (*allocate)(size_t payloadSize);
    int (*send)(struct HgfsTransportChannel *, HgfsReq *);
+   void (*free)(HgfsReq *);
 } HgfsTransportChannelOps;
 
 typedef enum {
@@ -57,10 +58,16 @@ typedef struct HgfsTransportChannel {
 void HgfsTransportInit(void);
 void HgfsTransportExit(void);
 HgfsReq *HgfsTransportAllocateRequest(size_t payloadSize);
+void HgfsTransportFreeRequest(HgfsReq *req);
 int HgfsTransportSendRequest(HgfsReq *req);
 HgfsReq *HgfsTransportGetPendingRequest(HgfsHandle id);
 void HgfsTransportFinishRequest(HgfsReq *req, Bool success, Bool do_put);
 void HgfsTransportFlushRequests(void);
 void HgfsTransportMarkDead(void);
 
+HgfsTransportChannel* HgfsGetVmciChannel(void);
+HgfsTransportChannel* HgfsGetTcpChannel(void);
+HgfsTransportChannel* HgfsGetVSocketChannel(void);
+HgfsTransportChannel *HgfsGetBdChannel(void);
+
 #endif // _HGFS_DRIVER_TRANSPORT_H_
diff --git a/open-vm-tools/modules/linux/vmhgfs/vmci.c b/open-vm-tools/modules/linux/vmhgfs/vmci.c
new file mode 100644 (file)
index 0000000..b3c139d
--- /dev/null
@@ -0,0 +1,438 @@
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * vmci.c --
+ *
+ * Provides VMCI transport channel to the HGFS client.
+ */
+
+/* Must come before any kernel header file. */
+#include "driver-config.h"
+
+#include <linux/errno.h>
+#include <linux/moduleparam.h>
+#include <asm/io.h>
+
+#include "compat_mm.h"
+#include "hgfsProto.h"
+#include "hgfsTransport.h"
+#include "module.h"
+#include "request.h"
+#include "transport.h"
+#include "vm_assert.h"
+#include "vmci_call_defs.h"
+#include "vmci_defs.h"
+#include "vmciGuestKernelAPI.h"
+
+static Bool HgfsVmciChannelOpen(HgfsTransportChannel *channel);
+static void HgfsVmciChannelClose(HgfsTransportChannel *channel);
+static HgfsReq * HgfsVmciChannelAllocate(size_t payloadSize);
+void HgfsVmciChannelFree(HgfsReq *req);
+static int HgfsVmciChannelSend(HgfsTransportChannel *channel, HgfsReq *req);
+
+int USE_VMCI = 0;
+module_param(USE_VMCI, int, 0444);
+
+static HgfsTransportChannel channel = {
+   .name = "vmci",
+   .ops.open = HgfsVmciChannelOpen,
+   .ops.close = HgfsVmciChannelClose,
+   .ops.allocate = HgfsVmciChannelAllocate,
+   .ops.free = HgfsVmciChannelFree,
+   .ops.send = HgfsVmciChannelSend,
+   .priv = NULL,
+   .status = HGFS_CHANNEL_NOTCONNECTED
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelCallback --
+ *
+ *      Called when VMCI datagram is received.
+ *
+ * Results:
+ *      Always 0.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int HgfsVmciChannelCallback(void *data, VMCIDatagram *dg)
+{
+   return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelOpen --
+ *
+ *      Open VMCI channel.
+ *
+ * Results:
+ *      TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsVmciChannelOpen(HgfsTransportChannel *channel) // IN: Channel
+{
+   HgfsVmciTransportHeader transportHeader;
+   VMCIDatagram *dg;
+   int ret;
+
+   ASSERT(channel->status == HGFS_CHANNEL_NOTCONNECTED);
+   ASSERT(channel->priv == NULL);
+
+   if (USE_VMCI == 0) {
+      return FALSE;
+   }
+
+   channel->priv = kmalloc(sizeof(VMCIHandle), GFP_KERNEL);
+   if (NULL == channel->priv) {
+      return FALSE;
+   }
+
+   ret = VMCIDatagram_CreateHnd(VMCI_INVALID_ID,        /* Resource ID */
+                                VMCI_FLAG_DG_NONE,      /* Flags */
+                                HgfsVmciChannelCallback,/* Datagram Recv Callback*/
+                                NULL,                   /* Callback data */
+                                channel->priv);         /* VMCI outhandle */
+   if (ret != VMCI_SUCCESS) {
+      LOG(1, (KERN_WARNING "Failed to create VMCI handle %d\n", ret));
+      kfree(channel->priv);
+      return FALSE;
+   }
+
+   transportHeader.version = HGFS_VMCI_VERSION_1;
+   transportHeader.iovCount = 0;
+
+   /*
+    * Send a datagram to the VMX with the HgfsTransportHeader as the datagram
+    * payload
+    */
+   dg = kmalloc(sizeof *dg + sizeof transportHeader, GFP_KERNEL);
+   if (NULL == dg) {
+      LOG(4, (KERN_WARNING "%s failed to allocate\n", __func__));
+      VMCIDatagram_DestroyHnd(*(VMCIHandle *)channel->priv);
+      kfree(channel->priv);
+      return FALSE;
+   }
+
+   memcpy(VMCI_DG_PAYLOAD(dg), &transportHeader, sizeof transportHeader);
+
+   dg->src = *(VMCIHandle *)channel->priv;
+   dg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_HGFS_TRANSPORT);
+   dg->payloadSize = sizeof transportHeader;
+
+   if ((ret = VMCIDatagram_Send(dg)) < VMCI_SUCCESS) {
+      LOG(4, (KERN_WARNING "Failure with %d\n", ret));
+      VMCIDatagram_DestroyHnd(*(VMCIHandle *)channel->priv);
+      kfree(dg);
+      kfree(channel->priv);
+      return FALSE;
+   }
+
+   kfree(dg);
+   return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelClose --
+ *
+ *      Destroy vmci handle.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+HgfsVmciChannelClose(HgfsTransportChannel *channel) // IN: Channel
+{
+   ASSERT(channel->priv != NULL);
+
+   VMCIDatagram_DestroyHnd(*(VMCIHandle *)channel->priv);
+   kfree(channel->priv);
+   channel->priv = NULL;
+
+   LOG(8, ("VMware hgfs: %s: vmci closed.\n", __func__));
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelAllocate --
+ *
+ *      Allocate request in the way that is suitable for sending through
+ *      vmci. Today, we just allocate a page for the request and we ignore
+ *      payloadSize. We need this to support variable sized requests in future.
+ *
+ * Results:
+ *      NULL on failure; otherwise address of the new request.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static HgfsReq *
+HgfsVmciChannelAllocate(size_t payloadSize) // IN: Ignored
+{
+   HgfsReq *req = NULL;
+   const size_t size = PAGE_SIZE;
+
+   req = kmalloc(size, GFP_KERNEL);
+   if (likely(req)) {
+      req->payload = req->buffer + sizeof (HgfsVmciTransportStatus);
+      req->bufferSize = size - sizeof (HgfsVmciTransportStatus) - sizeof *req;
+   }
+
+   /* We asked for PAGE_SIZE, it should be page aligned */
+   ASSERT(((long)req & 0x00000fff) == 0);
+   LOG(10, (KERN_WARNING "%s: Allocated Request\n", __func__));
+   return req;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsVmciChannelFree --
+ *
+ *     Free previously allocated request.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsVmciChannelFree(HgfsReq *req)
+{
+   ASSERT(req);
+   kfree(req);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsVmciChannelSend --
+ *
+ *     Send a request via vmci.
+ *
+ * Results:
+ *     0 on success, negative error on failure.
+ *
+ * Side effects:
+ *     None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+HgfsVmciChannelSend(HgfsTransportChannel *channel, // IN: Channel
+                    HgfsReq *req)                  // IN: request to send
+{
+   int ret;
+   int iovCount = 0;
+   HgfsReply *reply;
+   VMCIDatagram *dg;
+   HgfsVmciTransportHeader *transportHeader;
+   HgfsVmciTransportStatus *transportStatus;
+   size_t transportHeaderSize;
+   size_t bufferSize;
+   size_t total;
+   uint64 pa;
+   uint64 len;
+   size_t va;
+   int j;
+
+   ASSERT(req);
+   ASSERT(req->state == HGFS_REQ_STATE_UNSENT || req->state == HGFS_REQ_STATE_ALLOCATED);
+   ASSERT(req->payloadSize <= req->bufferSize);
+
+   LOG(4, ("VMware hgfs: %s: VMCI sending.\n", __func__));
+
+   /*
+    +------------+
+    +   page 1   + <----- We can have request starting from here
+    +------------+
+    +   page 2   +
+    +------------+
+    +   page 3   + <----- ..and ending here
+    +------------+
+    */
+
+   /* Note that req->bufferSize does not include chunk used by the transport. */
+   total = req->bufferSize + sizeof (HgfsVmciTransportStatus);
+   bufferSize = 0;
+
+   /* Calculate number of entries for metaPacket */
+   iovCount = 1;
+   va = (size_t)req->buffer;
+   len = total < (PAGE_SIZE - va % PAGE_SIZE) ? total : (PAGE_SIZE - va % PAGE_SIZE);
+   total -= len;
+   iovCount += (total + PAGE_SIZE - 1)/ PAGE_SIZE;
+
+   ASSERT(iovCount >= 1);
+   transportHeaderSize = sizeof *transportHeader +
+                         (iovCount + req->numEntries - 1) * sizeof (HgfsIov);
+   dg = kmalloc(sizeof *dg + transportHeaderSize, GFP_KERNEL);
+   if (NULL == dg) {
+      LOG(4, (KERN_WARNING "%s failed to allocate\n", __func__));
+      return -ENOMEM;
+   }
+
+   /* Initialize datagram */
+   dg->src = *(VMCIHandle *)channel->priv;
+   dg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, VMCI_HGFS_TRANSPORT);
+   dg->payloadSize = transportHeaderSize;
+
+   transportHeader = VMCI_DG_PAYLOAD(dg);
+
+   /* Initialize transport header */
+   transportHeader->version = HGFS_VMCI_VERSION_1;
+
+   total = req->bufferSize + sizeof (HgfsVmciTransportStatus);
+   bufferSize = 0;
+   for (iovCount = 0; bufferSize < req->bufferSize; iovCount++) {
+      /*
+       * req->buffer should have been allocated by kmalloc()/ __get_free_pages().
+       * Specifically, it cannot be a buffer that is mapped from high memory.
+       * virt_to_phys() does not work for those.
+       */
+      pa = virt_to_phys(req->buffer + bufferSize);
+      len = total < (PAGE_SIZE - pa % PAGE_SIZE) ? total : (PAGE_SIZE - pa % PAGE_SIZE);
+      bufferSize += len;
+      total -= len;
+      transportHeader->iov[iovCount].pa = pa;
+      transportHeader->iov[iovCount].len = len;
+      LOG(8, ("iovCount = %u PA = %"FMT64"x len=%u\n", iovCount,
+              transportHeader->iov[iovCount].pa, transportHeader->iov[iovCount].len));
+   }
+
+   /* Right now we do not expect discontigous request packet */
+   ASSERT(iovCount == 1);
+   ASSERT(total == 0);
+   ASSERT(bufferSize == req->bufferSize + sizeof (HgfsVmciTransportStatus));
+
+   LOG(8, ("Size of request is %Zu %Zu\n", req->payloadSize, sizeof (HgfsRequest)));
+
+   for (j = 0; j < req->numEntries; j++, iovCount++) {
+      /* I will have to probably do page table walk here, haven't figured it out yet */
+      transportHeader->iov[iovCount].pa = page_to_phys(req->dataPacket[j].page);
+      transportHeader->iov[iovCount].pa += req->dataPacket[j].offset;
+      transportHeader->iov[iovCount].len = req->dataPacket[j].len;
+      LOG(8, ("iovCount = %u PA = %"FMT64"x len=%u\n", iovCount,
+              transportHeader->iov[iovCount].pa,
+              transportHeader->iov[iovCount].len));
+   }
+
+   transportHeader->iovCount = iovCount;
+
+   ASSERT(iovCount <= HGFS_MAX_IOV);
+
+   /* Initialize transport Status */
+   transportStatus = (HgfsVmciTransportStatus *)req->buffer;
+   transportStatus->status = HGFS_VMCI_IO_PENDING;
+   transportStatus->flags = 0;
+   transportStatus->size = req->bufferSize + sizeof (HgfsVmciTransportStatus);
+
+   LOG(8, (KERN_WARNING "Physical addr is %"FMT64"x len=%u iovCount=%u numEntries=%u\n",
+           transportHeader->iov[0].pa,
+           transportHeader->iov[0].len,
+           transportHeader->iovCount,
+           req->numEntries));
+   LOG(8, (KERN_WARNING "Id = %u op = %u\n",
+           ((HgfsRequest *)req->payload)->id,
+           ((HgfsRequest *)req->payload)->op));
+
+   if((ret = VMCIDatagram_Send(dg)) < VMCI_SUCCESS) {
+      if (ret == HGFS_VMCI_TRANSPORT_ERROR) {
+         LOG(0, (KERN_WARNING "HGFS Transport error occured. Don't blame VMCI\n"));
+      }
+      req->state = HGFS_REQ_STATE_UNSENT;
+      kfree(dg);
+      return -EIO;
+   }
+
+   LOG(8, (KERN_WARNING "VMware hgfs: %s: VMCI reply received.\n", __func__));
+
+   /* For HgfsVmciStage2 everything should complete sync. */
+   ASSERT(transportStatus->status == HGFS_VMCI_IO_COMPLETE);
+
+   if (transportStatus->status == HGFS_VMCI_IO_COMPLETE) {
+      reply = (HgfsReply *)req->payload;
+      req->payloadSize = transportStatus->size;
+      ASSERT(transportStatus->size <= (req->bufferSize + sizeof (HgfsVmciTransportStatus)));
+      HgfsCompleteReq(req);
+      LOG(8, (KERN_WARNING "IO_COMPLETE: id = %u status = %u\n",
+              (uint32)reply->id, (uint32)reply->status));
+   }
+
+   kfree(dg);
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsGetVmciChannel --
+ *
+ *     Initialize Vmci channel.
+ *
+ * Results:
+ *     Always return pointer to Vmci channel.
+ *
+ * Side effects:
+ *     None
+ *
+ *----------------------------------------------------------------------
+ */
+
+HgfsTransportChannel*
+HgfsGetVmciChannel(void)
+{
+   return &channel;
+}