]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Internal branch sync. Included in this change:
authorVMware, Inc <>
Mon, 21 May 2012 22:21:36 +0000 (15:21 -0700)
committerDmitry Torokhov <dtor@vmware.com>
Tue, 22 May 2012 18:03:29 +0000 (11:03 -0700)
. VMCI: increase pinned QP limit to support larger vPageChannel

. VMCI: Doxygen vPageChannel API

. VMCI: fix leaking shm pages in vPageChannel Destroy()

. fix foundry code to use the higher order bits of VixError correcly

. turn on VGAuth code in VIX

. changes in shared code that don't affect open-vm-tools functionality

Signed-off-by: Dmitry Torokhov <dtor@vmware.com>
14 files changed:
open-vm-tools/lib/foundryMsg/foundryMsg.c
open-vm-tools/lib/include/vixCommands.h
open-vm-tools/lib/include/vixOpenSource.h
open-vm-tools/lib/include/vm_atomic.h
open-vm-tools/lib/include/vm_basic_asm_x86_64.h
open-vm-tools/lib/include/vm_basic_types.h
open-vm-tools/lib/include/vmci_defs.h
open-vm-tools/modules/linux/shared/vmci_defs.h
open-vm-tools/modules/linux/vmci/common/vmciPageChannel.c
open-vm-tools/modules/linux/vmci/linux/vmci_version.h
open-vm-tools/modules/linux/vmci/shared/vmci_page_channel.h
open-vm-tools/services/plugins/vix/foundryToolsDaemon.c
open-vm-tools/services/plugins/vix/vixTools.c
open-vm-tools/services/plugins/vix/vixToolsInt.h

index 6969a208c973ad8a2ae678fe6f8e3041cb9574ab..f6308a76ad4bbf516ee7fcb4389ae7b923f44426 100644 (file)
@@ -655,7 +655,8 @@ VixMsg_AllocRequestMsg(size_t msgHeaderAndBodyLength,    // IN
       || (VIX_USER_CREDENTIAL_HOST_CONFIG_SECRET == credentialType)
       || (VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET == credentialType)
       || (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType)
-      || (VIX_USER_CREDENTIAL_SSPI == credentialType)) {
+      || (VIX_USER_CREDENTIAL_SSPI == credentialType)
+      || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType)) {
       /*
        * All of these are optional.
        */
@@ -707,7 +708,8 @@ VixMsg_AllocRequestMsg(size_t msgHeaderAndBodyLength,    // IN
          || (VIX_USER_CREDENTIAL_HOST_CONFIG_SECRET == credentialType)
          || (VIX_USER_CREDENTIAL_HOST_CONFIG_HASHED_SECRET == credentialType)
          || (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType)
-         || (VIX_USER_CREDENTIAL_SSPI == credentialType)) {
+         || (VIX_USER_CREDENTIAL_SSPI == credentialType)
+         || (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType)) {
       destPtr = (char *) commandRequest;
       destPtr += commandRequest->commonHeader.headerLength;
       destPtr += commandRequest->commonHeader.bodyLength;
index 156c85ac67eecd71b2981b7259a51dd8c77a4a1e..b386b6693399f5b8adb6bb8bfcf187220c19555f 100644 (file)
@@ -61,6 +61,7 @@
 #define VIX_USER_CREDENTIAL_NAMED_INTERACTIVE_USER    8
 #define VIX_USER_CREDENTIAL_TICKETED_SESSION          9
 #define VIX_USER_CREDENTIAL_SSPI                      10
+#define VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN         11
 
 #define VIX_SHARED_SECRET_CONFIG_USER_NAME          "__VMware_Vix_Shared_Secret_1__"
 
@@ -315,6 +316,20 @@ struct VixCommandSSPI {
 VixCommandSSPI;
 
 
+/*
+ * **********************************************************
+ * This is a SAML bearer token with optional userName to specify
+ * an IdProvider store.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct VixCommandSAMLToken {
+   uint32    tokenLength;
+   uint32    nameLength;
+}
+#include "vmware_pack_end.h"
+VixCommandSAMLToken;
+
 /*
  * **********************************************************
  * Basic power op request. The response is just a generic
index 9d5156f57e118859fadc63f260f6443c110fc080..1ff6b44f3f0ada6d9b5491c62943c6fc7dd44a03 100644 (file)
@@ -92,6 +92,88 @@ VixError Vix_TranslateGuestRegistryError(int systemError);
 
 #endif // VIX_HIDE_BORA_DEPENDENCIES
 
+
+/*
+ * This is an expanded view of a VixError
+ * Every VixError is a 64-bit int, so it can fit into this struct.
+ *
+ * The flags, extraErrorType, and extraError are all optional. They
+ * do not have to be set for any error. In fact, these are guaranteed
+ * to be all 0 when the error is VIX_OK. This means that any program
+ * that checks (VIX_OK == err) or (VIX_OK != err) will always work.
+ *
+ * The basic error field is a Vix error value, and it's the lsb
+ * of the new struct. This means that a 64-bit error can be assigned
+ * enum constant, like an integer. For example, err = VIX_E_FAIL; works.
+ * This just leaves the flags and extraError fields as 0.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct VixErrorFields {
+   uint16   error;
+
+   uint8    flags;
+
+   uint8    extraErrorType;
+   uint32   extraError;
+}
+#include "vmware_pack_end.h"
+VixErrorFields;
+
+/*
+ * These are the flags for a Vix error.
+ */
+enum {
+   VIX_ERRORFLAG_GUEST         = 0x0001,
+   VIX_ERRORFLAG_REMOTE        = 0x0002,
+};
+
+/*
+ * These are the types of extra error in a Vix error.
+ */
+enum {
+   VIX_ERROREXTRATYPE_NONE          = 0,
+   VIX_ERROREXTRATYPE_SNAPSHOT      = 1,
+   VIX_ERROREXTRATYPE_DISKLIB       = 2,
+   VIX_ERROREXTRATYPE_WINDOWS       = 3,
+   VIX_ERROREXTRATYPE_LINUX         = 4,
+   VIX_ERROREXTRATYPE_FILE          = 5,
+   VIX_ERROREXTRATYPE_VMDB          = 6,
+   VIX_ERROREXTRATYPE_AIO           = 7,
+   VIX_ERROREXTRATYPE_CRYPTO        = 8,
+   VIX_ERROREXTRATYPE_KEYSAFE       = 9,
+   VIX_ERROREXTRATYPE_BLOCKLIST     = 10,
+   VIX_ERROREXTRATYPE_V2I           = 11,
+   VIX_ERROREXTRATYPE_MSGPOST       = 12,
+};
+
+
+/*
+ * These are the types of extra error in a Vix error.
+ */
+#define VIX_ERROR_BASE_ERROR(err) ((VixErrorFields *) &err)->error
+#define VIX_ERROR_EXTRA_ERROR(err) ((VixErrorFields *) &err)->extraError
+#define VIX_ERROR_EXTRA_ERROR_TYPE(err) ((VixErrorFields *) &err)->extraErrorType
+#define VIX_ERROR_FROM_GUEST(err) (((VixErrorFields *) &err)->flags & VIX_ERRORFLAG_GUEST)
+#define VIX_ERROR_FROM_REMOTE(err) (((VixErrorFields *) &err)->flags & VIX_ERRORFLAG_REMOTE)
+#define VIX_ERROR_SET_FROM_GUEST(err) (((VixErrorFields *) &err)->flags |= VIX_ERRORFLAG_GUEST)
+#define VIX_ERROR_SET_FROM_REMOTE(err) (((VixErrorFields *) &err)->flags |= VIX_ERRORFLAG_REMOTE)
+
+#define VIX_SET_GUEST_WINDOWS_ERROR(err, vixError, winError)          \
+   do {                                                               \
+      err = 0;                                                        \
+      VIX_ERROR_BASE_ERROR(err) = vixError;                           \
+      VIX_ERROR_EXTRA_ERROR(err) = winError;                          \
+      VIX_ERROR_EXTRA_ERROR_TYPE(err) = VIX_ERROREXTRATYPE_WINDOWS;   \
+      VIX_ERROR_SET_FROM_GUEST(err);                                  \
+   } while (0)
+
+#define VIX_ERROR_SET_ADDITIONAL_ERROR(err, vixError, additionalError)   \
+   do {                                                                 \
+      err = additionalError;                                             \
+      err = (err << 32) | vixError;                                     \
+   } while (0)
+
 /*
  * This defines additional error codes.
  * The public error codes are defined in vix.h
@@ -112,6 +194,7 @@ enum {
    VIX_E_REG_KEY_INVALID                           = 20008,
    VIX_E_REG_KEY_HAS_SUBKEYS                       = 20009,
    VIX_E_REG_VALUE_NOT_FOUND                       = 20010,
+   VIX_E_REG_KEY_ALREADY_EXISTS                    = 20011,
 
    /* Reg Errors*/
    VIX_E_REG_INCORRECT_VALUE_TYPE                  = 25000
index 2c8be0906d4765eaf61739e7d29a75efb3d773c4..67a2c3925de8ef7a31595f5e2f52cac907abfb73 100644 (file)
@@ -1410,6 +1410,30 @@ Atomic_ReadAdd64(Atomic_uint64 *var, // IN
 #error No compiler defined for Atomic_ReadAdd64
 #endif
 }
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Atomic_ReadSub64 --
+ *
+ *      Atomic read (returned), sub a value, write.
+ *
+ * Results:
+ *      The value of the variable before the operation.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+Atomic_ReadSub64(Atomic_uint64 *var, // IN
+                 uint64 val)         // IN
+{
+   // Do an sub by an add and a overflow
+   return Atomic_ReadAdd64(var, -val);
+}
 #endif
 
 
index 64d95122c5001b8f6020fc93a147e9e346a42094..cd1f9e52a6ac18d7ea099a9730cfe6b24c7e1627 100644 (file)
@@ -322,7 +322,7 @@ Mul64x6464(uint64 multiplicand,
    uint64 result, dummy;
 
    __asm__("mulq    %3      \n\t"
-           "shrdq   %1, %0  \n\t"
+           "shrdq   %b4, %1, %0  \n\t"
            : "=a" (result),
              "=d" (dummy)
            : "0"  (multiplier),
@@ -380,7 +380,7 @@ Muls64x64s64(int64 multiplicand, int64 multiplier, uint32 shift)
    int64 result, dummy;
 
    __asm__("imulq   %3      \n\t"
-       "shrdq   %1, %0  \n\t"
+       "shrdq   %b4, %1, %0  \n\t"
        : "=a" (result),
          "=d" (dummy)
        : "0"  (multiplier),
index 75ecfbbb607f8c138e33fe843d517cde6a20a846..15ef0aba691e7759dd8eb10188e4c1e5d03bd3d8 100644 (file)
@@ -587,6 +587,7 @@ typedef void * UserVA;
 #define INVALID_LPN64     ((LPN64)-1)
 #define INVALID_PAGENUM   ((PageNum)-1)
 
+#define INVALID_MPN64     ((MPN64)-1)
 
 /*
  * Format modifier for printing VA, LA, and VPN.
index 6791b46cc3bcb3954770ad3c656def0ce1fac3cb..bbfb32e491d2915e12ba0599c687578085d59e42 100644 (file)
@@ -99,8 +99,12 @@ typedef enum VMCIIntrType {
  * Queues with pre-mapped data pages must be small, so that we don't pin
  * too much kernel memory (especially on vmkernel).  We limit a queuepair to
  * 32 KB, or 16 KB per queue for symmetrical pairs.
+ *
+ * XXX, we are raising this limit to 4MB to support high-throughput workloads
+ * with vioi-filter.  Once we switch to rings instead of queuepairs for the
+ * page channel, we will drop this limit again.  See PR 852983.
  */
-#define VMCI_MAX_PINNED_QP_MEMORY (32 * 1024)
+#define VMCI_MAX_PINNED_QP_MEMORY (4 * 1024 * 1024)
 
 /*
  * We have a fixed set of resource IDs available in the VMX.
@@ -149,6 +153,12 @@ typedef uint32 VMCI_Resource;
  */
 #define VMCI_CORE_DEVICE_RESOURCE_MAX  VMCI_QUEUEPAIR_DETACH
 
+/*
+ * VMCI reserved host datagram resource IDs.
+ * vsock control channel has resource id 1.
+ */
+#define VMCI_DVFILTER_DATA_PATH_DATAGRAM 2
+
 /* VMCI Ids. */
 typedef uint32 VMCIId;
 
index 8222af7261d71fd8e930ef13a165cf2a1576ebb8..e97c7e9a9a23d9f6ce3636d40bb179137f9c76a7 100644 (file)
@@ -99,8 +99,12 @@ typedef enum VMCIIntrType {
  * Queues with pre-mapped data pages must be small, so that we don't pin
  * too much kernel memory (especially on vmkernel).  We limit a queuepair to
  * 32 KB, or 16 KB per queue for symmetrical pairs.
+ *
+ * XXX, we are raising this limit to 4MB to support high-throughput workloads
+ * with vioi-filter.  Once we switch to rings instead of queuepairs for the
+ * page channel, we will drop this limit again.  See PR 852983.
  */
-#define VMCI_MAX_PINNED_QP_MEMORY (32 * 1024)
+#define VMCI_MAX_PINNED_QP_MEMORY (4 * 1024 * 1024)
 
 /*
  * We have a fixed set of resource IDs available in the VMX.
@@ -149,6 +153,12 @@ typedef uint32 VMCI_Resource;
  */
 #define VMCI_CORE_DEVICE_RESOURCE_MAX  VMCI_QUEUEPAIR_DETACH
 
+/*
+ * VMCI reserved host datagram resource IDs.
+ * vsock control channel has resource id 1.
+ */
+#define VMCI_DVFILTER_DATA_PATH_DATAGRAM 2
+
 /* VMCI Ids. */
 typedef uint32 VMCIId;
 
index 257750205a0d7326cc8f229f9e8a8600d1b2739b..ebdf47d7a313d278730d0ef8a119b947f0fa7838 100644 (file)
 
 #define VMCI_PACKET_RECV_THRESHOLD 150
 
+/*
+ * Maximum number of elements per DGRAM packet (for setting receive buffers).
+ */
+
+#define VMCI_PACKET_DGRAM_MAX_ELEMS \
+   ((VMCI_MAX_DG_PAYLOAD_SIZE - sizeof(VPageChannelPacket)) / \
+    sizeof(VPageChannelElem))
+
 /*
  * All flags.  We use this to check the validity of the flags, so put it here
  * instead of in the header, otherwise people might assume we mean for them
@@ -60,6 +68,8 @@
  */
 
 struct VPageChannel {
+   VPageChannelState state;
+
    VMCIHandle dgHandle;
    uint32 flags;
    VPageChannelRecvCB recvCB;
@@ -79,7 +89,6 @@ struct VPageChannel {
    uint64 consumeQSize;
    VMCIId attachSubId;
    VMCIId detachSubId;
-   Bool qpConnected;
    Bool useSpinLock;
    spinlock_t qpRecvLock;
    spinlock_t qpSendLock;
@@ -97,7 +106,7 @@ struct VPageChannel {
     * Receiving buffer.
     */
 
-   int curRecvBufs;
+   Atomic_Int curRecvBufs;
    int recvBufsTarget;
    int defaultRecvBufs;
    int maxRecvBufs;
@@ -110,9 +119,9 @@ struct VPageChannel {
 
 
 static int VPageChannelSendControl(VPageChannel *channel,
+                                   VPageChannelPacketType type,
                                    char *message,
                                    int len,
-                                   VPageChannelPacketType type,
                                    int numElems,
                                    VPageChannelElem *elems);
 
@@ -242,12 +251,15 @@ VPageChannelReleaseRecvLock(VPageChannel *channel, // IN
 /*
  *-----------------------------------------------------------------------------
  *
- * VPageChannelSetRecvBuffers --
+ * VPageChannelAddRecvBuffers --
  *
- *      Set the receiving buffers for the channel.
+ *      Add receiving buffers for the channel.  This will ask the client to
+ *      to allocate the required elements and then pass those to the peer.
+ *      If "byControl" is TRUE, then the DGRAM control channel will be used,
+ *      and multiple packets will be sent if necessary.
  *
  * Results:
- *      VMCI_SUCCESS if set, negative error code otherwise.
+ *      The number of buffers actually sent to the peer.
  *
  * Side effects:
  *      None.
@@ -256,74 +268,109 @@ VPageChannelReleaseRecvLock(VPageChannel *channel, // IN
  */
 
 static int
-VPageChannelSetRecvBuffers(VPageChannel *channel,     // IN
+VPageChannelAddRecvBuffers(VPageChannel *channel,     // IN
                            int numElems,              // IN
                            Bool byControl)            // IN
 {
-   int retval;
-   int allocNum;
-   size_t size = sizeof(VPageChannelPacket) +
-      numElems * sizeof(VPageChannelElem);
+   int n;
+   int sent;
+   size_t size;
    VPageChannelElem *elems;
    VPageChannelPacket *packet;
 
    ASSERT(channel);
 
-   packet = (VPageChannelPacket *)VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC);
-   if (packet == NULL) {
-      VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
-                    "(size=%"FMTSZ"u).\n",
-                    channel,
-                    size));
-      return VMCI_ERROR_NO_MEM;
-   }
+   sent = 0;
+   size = 0;
+   elems = NULL;
+   packet = NULL;
 
-   packet->type = VPCPacket_SetRecvBuffer;
-   packet->msgLen = 0;
-   packet->numElems = numElems;
+   n = min_t(int, VMCI_PACKET_DGRAM_MAX_ELEMS, numElems);
+   while (n > 0) {
+      int retval;
+      int allocNum;
 
-   elems = VPAGECHANNEL_PACKET_ELEMS(packet);
-   allocNum = channel->elemAllocFn(channel->allocClientData, elems, numElems);
-   if (allocNum != numElems) {
-      VMCI_WARNING((LGPFX"Failed to allocate receive buffer (channel=%p) "
-                    "(expected=%d) (actual=%d).\n",
-                    channel,
-                    numElems,
-                    allocNum));
-      retval = VMCI_ERROR_NO_MEM;
-      goto error;
-   }
+      /*
+       * First packet is always big enough to cover any remaining elements,
+       * so just allocate it once.
+       */
 
-   if (byControl || !channel->qpConnected) {
-      retval = VPageChannelSendControl(channel, NULL, 0,
-                                            VPCPacket_SetRecvBuffer,
-                                            numElems, elems);
-   } else {
-      retval = VPageChannel_SendPacket(channel, packet);
-   }
-   if (retval < VMCI_SUCCESS) {
-      VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) "
-                    "(err=%d).\n",
-                    channel,
-                    retval));
-      goto error;
-   }
+      if (NULL == packet) {
+         size = sizeof(VPageChannelPacket) + (n * sizeof(VPageChannelElem));
+         packet = (VPageChannelPacket *)
+            VMCI_AllocKernelMem(size, VMCI_MEMORY_ATOMIC);
+         if (packet == NULL) {
+            VMCI_WARNING((LGPFX"Failed to allocate packet (channel=%p) "
+                          "(size=%"FMTSZ"u).\n",
+                          channel,
+                          size));
+            goto exit;
+         }
+
+         packet->type = VPCPacket_SetRecvBuffer;
+         packet->msgLen = 0;
+         elems = VPAGECHANNEL_PACKET_ELEMS(packet);
+      }
 
-   channel->curRecvBufs += numElems;
+      allocNum = channel->elemAllocFn(channel->allocClientData, elems, n);
+      if (0 == allocNum) {
+         /*
+          * If the client failed to allocate any elements at all then just
+          * bail out and return whatever number we managed to send so far
+          * (if any).
+          */
 
-   VMCI_FreeKernelMem(packet, size);
+         VMCI_WARNING((LGPFX"Failed to allocate receive buffer (channel=%p) "
+                       "(expected=%d).\n",
+                       channel,
+                       n));
+         goto exit;
+      }
 
-   return VMCI_SUCCESS;
+      /*
+       * We wanted "n" elements, but we might only have "allocNum" because
+       * that's all the client could allocate.  Pass down whatever we got.
+       */
 
- error:
-   if (packet != NULL) {
-      if (allocNum) {
+      packet->numElems = allocNum;
+
+      if (byControl || VPCState_Connected != channel->state) {
+         retval = VPageChannelSendControl(channel, VPCPacket_SetRecvBuffer,
+                                          NULL, 0, allocNum, elems);
+      } else {
+         retval = VPageChannel_SendPacket(channel, packet);
+         /*
+          * XXX, what if this is a non-blocking queuepair and we fail to
+          * send because it's full and we can't wait?  Is it even worth it
+          * to loop?
+          */
+      }
+      if (retval < VMCI_SUCCESS) {
+         /*
+          * Failure to send is fatal.  Release the client's elements and
+          * bail out.
+          */
+
+         VMCI_WARNING((LGPFX"Failed to set receive buffers (channel=%p) "
+                       "(err=%d).\n",
+                       channel,
+                       retval));
          channel->elemFreeFn(channel->freeClientData, elems, allocNum);
+         goto exit;
       }
-      VMCI_FreeKernelMem(packet, size);
+
+      Atomic_Add32(&channel->curRecvBufs, allocNum);
+
+      sent += allocNum;
+      numElems -= allocNum;
+      n = min_t(int, VMCI_PACKET_DGRAM_MAX_ELEMS, numElems);
    }
 
-   return retval;
+exit:
+   if (NULL != packet) {
+      VMCI_FreeKernelMem(packet, size);
+   }
+   return sent;
 }
 
 
@@ -347,6 +394,7 @@ static int
 VPageChannelRecvPacket(VPageChannel *channel,         // IN
                        VPageChannelPacket *packet)    // IN
 {
+   int curRecvBufs;
    int recvBufsTarget;
 
    ASSERT(channel);
@@ -355,7 +403,8 @@ VPageChannelRecvPacket(VPageChannel *channel,         // IN
    if (packet->type != VPCPacket_Data &&
        packet->type != VPCPacket_Completion_Notify &&
        packet->type != VPCPacket_RequestBuffer &&
-       packet->type != VPCPacket_HyperConnect) {
+       packet->type != VPCPacket_HyperConnect &&
+       packet->type != VPCPacket_HyperDisconnect) {
       VMCI_WARNING((LGPFX"Received invalid packet (channel=%p) "
                     "(type=%d).\n",
                     channel,
@@ -408,7 +457,7 @@ VPageChannelRecvPacket(VPageChannel *channel,         // IN
                      (LGPFX"Requested more buffers (channel=%p) "
                       "(cur=%d) (target=%d) (max=%d).\n",
                       channel,
-                      channel->curRecvBufs,
+                      Atomic_Read32(&channel->curRecvBufs),
                       channel->recvBufsTarget,
                       channel->maxRecvBufs));
 
@@ -419,13 +468,32 @@ VPageChannelRecvPacket(VPageChannel *channel,         // IN
 
    case VPCPacket_Data:
       channel->recvCB(channel->clientRecvData, packet);
-      channel->curRecvBufs -= packet->numElems;
+      Atomic_Sub32(&channel->curRecvBufs, packet->numElems);
+      ASSERT(Atomic_Read32(&channel->curRecvBufs) > 0);
       break;
 
    case VPCPacket_Completion_Notify:
       channel->recvCB(channel->clientRecvData, packet);
       break;
 
+   case VPCPacket_HyperDisconnect:
+      VMCI_DEBUG_LOG(10,
+                     (LGPFX"Hypervisor requested disconnection "
+                      "(channel=%p) (numElems=%d).\n",
+                      channel,
+                      packet->numElems));
+      if (packet->numElems > 0) {
+         channel->elemFreeFn(channel->freeClientData,
+                             VPAGECHANNEL_PACKET_ELEMS(packet),
+                             packet->numElems);
+      }
+      (void)VPageChannelSendControl(channel, VPCPacket_GuestDisconnect,
+                                    NULL, 0, 0, NULL);
+      if (channel->state < VPCState_Disconnecting) {
+         channel->state = VPCState_Disconnecting;
+      }
+      return VMCI_SUCCESS;
+
    default:
       ASSERT_NOT_IMPLEMENTED(FALSE);
       break;
@@ -439,14 +507,12 @@ VPageChannelRecvPacket(VPageChannel *channel,         // IN
     * in the hope that we won't hit this again.
     */
 
-   if (channel->curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) {
-      int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD -
-         channel->curRecvBufs;
+   curRecvBufs = Atomic_Read32(&channel->curRecvBufs);
+   if (curRecvBufs < (recvBufsTarget - VMCI_PACKET_RECV_THRESHOLD)) {
+      int numElems = recvBufsTarget + VMCI_PACKET_RECV_THRESHOLD - curRecvBufs;
 
-      if (VPageChannelSetRecvBuffers(channel, numElems, FALSE) ==
-          VMCI_SUCCESS) {
-         channel->recvBufsTarget = recvBufsTarget;
-      }
+      (void)VPageChannelAddRecvBuffers(channel, numElems, FALSE);
+      channel->recvBufsTarget = recvBufsTarget;
    }
 
    return VMCI_SUCCESS;
@@ -531,7 +597,7 @@ VPageChannelDoDoorbellCallback(VPageChannel *channel) // IN/OUT
 
    ASSERT(channel);
 
-   if (!channel->qpConnected) {
+   if (VPCState_Connected != channel->state) {
       VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
                     channel));
       return;
@@ -696,6 +762,8 @@ VPageChannelSendConnectionMessage(VPageChannel *channel) // IN
 
    ASSERT(channel);
 
+   channel->state = VPCState_Connecting;
+
    memset(&message, 0, sizeof message);
    message.dgHandle = channel->dgHandle;
    message.qpHandle = channel->qpHandle;
@@ -710,9 +778,8 @@ VPageChannelSendConnectionMessage(VPageChannel *channel) // IN
                    channel->qpHandle.context,
                    channel->qpHandle.resource));
 
-   return VPageChannelSendControl(channel,
-                                  (char *)&message, sizeof message,
-                                  VPCPacket_GuestConnect, 0, NULL);
+   return VPageChannelSendControl(channel, VPCPacket_GuestConnect,
+                                  (char *)&message, sizeof message, 0, NULL);
 }
 
 
@@ -753,7 +820,7 @@ VPageChannelPeerAttachCB(VMCIId subId,             // IN
                       channel,
                       ePayload->handle.context,
                       ePayload->handle.resource));
-      channel->qpConnected = TRUE;
+      channel->state = VPCState_Connected;
    }
 }
 
@@ -795,7 +862,7 @@ VPageChannelPeerDetachCB(VMCIId subId,             // IN
                       channel,
                       ePayload->handle.context,
                       ePayload->handle.resource));
-      channel->qpConnected = FALSE;
+      channel->state = VPCState_Disconnected;
    }
 }
 
@@ -838,7 +905,7 @@ VPageChannelDestroyQueuePair(VPageChannel *channel) // IN/OUT
       channel->qpair = NULL;
    }
 
-   channel->qpConnected = FALSE;
+   channel->state = VPCState_Disconnected;
 }
 
 
@@ -995,6 +1062,7 @@ VPageChannel_CreateInVM(VPageChannel **channel,              // IN/OUT
     */
 
    memset(pageChannel, 0, sizeof *pageChannel);
+   pageChannel->state = VPCState_Unconnected;
    pageChannel->dgHandle = VMCI_INVALID_HANDLE;
    pageChannel->attachSubId = VMCI_INVALID_ID;
    pageChannel->detachSubId = VMCI_INVALID_ID;
@@ -1002,7 +1070,6 @@ VPageChannel_CreateInVM(VPageChannel **channel,              // IN/OUT
    pageChannel->qpair = NULL;
    pageChannel->doorbellHandle = VMCI_INVALID_HANDLE;
    pageChannel->peerDoorbellHandle = VMCI_INVALID_HANDLE;
-   pageChannel->qpConnected = FALSE;
    pageChannel->flags = channelFlags;
    pageChannel->recvCB = recvCB;
    pageChannel->clientRecvData = clientRecvData;
@@ -1013,7 +1080,7 @@ VPageChannel_CreateInVM(VPageChannel **channel,              // IN/OUT
    pageChannel->resourceId = resourceId;
    pageChannel->peerDgHandle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID,
                                                   peerResourceId);
-   pageChannel->curRecvBufs = 0;
+   Atomic_Write32(&pageChannel->curRecvBufs, 0);
    pageChannel->recvBufsTarget = defaultRecvBuffers;
    pageChannel->defaultRecvBufs = defaultRecvBuffers;
    pageChannel->maxRecvBufs = maxRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
@@ -1089,8 +1156,13 @@ VPageChannel_CreateInVM(VPageChannel **channel,              // IN/OUT
 
    if (defaultRecvBuffers) {
       int numElems = defaultRecvBuffers + VMCI_PACKET_RECV_THRESHOLD;
-      retval = VPageChannelSetRecvBuffers(pageChannel, numElems, TRUE);
-      if (retval < VMCI_SUCCESS) {
+      if (0 == VPageChannelAddRecvBuffers(pageChannel, numElems, TRUE)) {
+         /*
+          * AddRecvBuffers() returns the number of buffers actually added.  If
+          * we failed to add any at all, then fail.
+          */
+
+         retval = VMCI_ERROR_NO_MEM;
          goto error;
       }
    }
@@ -1148,6 +1220,7 @@ VPageChannel_Destroy(VPageChannel *channel) // IN/OUT
       VMCIDatagram_DestroyHnd(channel->dgHandle);
    }
 
+   channel->state = VPCState_Free;
    VMCI_FreeKernelMem(channel, sizeof *channel);
 
    VMCI_DEBUG_LOG(10,
@@ -1247,9 +1320,9 @@ VPageChannelAllocDatagram(VPageChannel *channel,       // IN
 
 static int
 VPageChannelSendControl(VPageChannel *channel,       // IN
+                        VPageChannelPacketType type, // IN
                         char *message,               // IN
                         int len,                     // IN
-                        VPageChannelPacketType type, // IN
                         int numElems,                // IN
                         VPageChannelElem *elems)     // IN
 {
@@ -1260,7 +1333,8 @@ VPageChannelSendControl(VPageChannel *channel,       // IN
    ASSERT(channel);
    ASSERT(type == VPCPacket_Data ||
           type == VPCPacket_GuestConnect ||
-          type == VPCPacket_SetRecvBuffer);
+          type == VPCPacket_SetRecvBuffer ||
+          type == VPCPacket_GuestDisconnect);
 
    dg = NULL;
    retval = VPageChannelAllocDatagram(channel, len, numElems, &dg);
@@ -1336,7 +1410,7 @@ VPageChannel_SendPacket(VPageChannel *channel,         // IN
 
    ASSERT(channel);
 
-   if (!channel->qpConnected) {
+   if (VPCState_Connected != channel->state) {
       VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
                     channel));
       return VMCI_ERROR_DST_UNREACHABLE;
@@ -1439,7 +1513,7 @@ VPageChannel_Send(VPageChannel *channel,       // IN/OUT
 
    ASSERT(channel);
 
-   if (!channel->qpConnected) {
+   if (VPCState_Connected != channel->state) {
       VMCI_WARNING((LGPFX"Not connected (channel=%p).\n",
                     channel));
       return VMCI_ERROR_DST_UNREACHABLE;
@@ -1507,7 +1581,7 @@ EXPORT_SYMBOL(VPageChannel_Send);
 void
 VPageChannel_PollRecvQ(VPageChannel *channel)     // IN
 {
-   if (channel->qpConnected) {
+   if (VPCState_Connected != channel->state) {
       VPageChannelDoDoorbellCallback(channel);
    }
 }
index 89365142799899e58cff03abb673f27a3be4d78c..5c8e8f24b9c45b5d795135dc702fa9dce562eccf 100644 (file)
@@ -25,8 +25,8 @@
 #ifndef _VMCI_VERSION_H_
 #define _VMCI_VERSION_H_
 
-#define VMCI_DRIVER_VERSION          9.5.5.0
-#define VMCI_DRIVER_VERSION_COMMAS   9,5,5,0
-#define VMCI_DRIVER_VERSION_STRING   "9.5.5.0"
+#define VMCI_DRIVER_VERSION          9.5.6.0
+#define VMCI_DRIVER_VERSION_COMMAS   9,5,6,0
+#define VMCI_DRIVER_VERSION_STRING   "9.5.6.0"
 
 #endif /* _VMCI_VERSION_H_ */
index 230120cff0d61dcb145da54b7c580143b3ec80a2..fdd47e782c49476685a7917bfe5233584f62de0e 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2011 VMware, Inc. All rights reserved.
+ * Copyright (C) 2011-2012 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
 #include "vmci_defs.h"
 #include "vmci_call_defs.h"
 
-/* Max size of a single tx buffer. */
+/** \cond PRIVATE */
 #define VPAGECHANNEL_MAX_TX_BUF_SIZE (1 << 14)
 #define VPAGECHANNEL_MAX_PAGES_PER_TX_BUFFER \
    (VPAGECHANNEL_MAX_TX_BUF_SIZE / PAGE_SIZE + 1)
+/** \endcond */
+
+/**
+ * \brief Get a pointer to the elements in a packet.
+ *
+ * Returns a pointer to the elements at the end of a page channel packet.
+ *
+ * \see VPageChannelElem
+ * \see VPageChannelPacket
+ */
 
 #define VPAGECHANNEL_PACKET_ELEMS(packet)             \
    (VPageChannelElem *)((char *)(packet) +            \
                          sizeof(VPageChannelPacket) + \
                          packet->msgLen)
+
+/**
+ * \brief Get a pointer to the message in a packet.
+ *
+ * Returns a pointer to the message embedded in a page channel packet.
+ *
+ * \see VPageChannelPacket
+ */
+
 #define VPAGECHANNEL_PACKET_MESSAGE(packet) \
    (char *)((char *)(packet) + sizeof(VPageChannelPacket))
 
-/*
- * Flags for channel creation.
- *
- * NOTIFY_ONLY means invoke the channel's receive callback directly when a
- * notification is received.  If not specified, then when a notification is
- * received, packets are read from the queuepair and the callback invoked for
- * each one separately.  Not applicable on VMKernel.
- *
- * DELAYED_CB means that all callbacks run in a delayed context, and the
- * caller is allowed to block.  If not specified, then callbacks run in
- * interrupt context and the channel will not block.  This can only be
- * specified on the guest side for now.
- *
- * SEND_WHILE_ATOMIC indicates that the client wishes to call Send() from
- * an atomic context and that the channel should not block.  If the channel
- * is not allowed to block, then the channel's pages are permanently mapped
- * and pinned.  Note that this will limit the total size of the channel to
+/**
+ * \brief Notify client directly, and do not read packets.
+ *
+ * This flag indicates that the channel should invoke the client's receive
+ * callback directly when any packets are available.  If not specified, then
+ * when a notification is received, packets are read from the channel and the
+ * callback invoked for each one separately.
+ *
+ * \note Not applicable to VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
+ */
+
+#define VPAGECHANNEL_FLAGS_NOTIFY_ONLY 0x1
+
+/**
+ * \brief Invoke client's receive callback in delayed context.
+ *
+ * This flag indicates that all callbacks run in a delayed context, and the
+ * caller and callback are allowed to block.  If not specified, then callbacks
+ * run in interrupt context and the channel will not block, and the caller
+ * is not allowed to block.
+ *
+ * \note Not applicable to VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
+ */
+
+#define VPAGECHANNEL_FLAGS_RECV_DELAYED 0x2
+
+/**
+ * \brief Send from an atomic context.
+ *
+ * This flag indicates that the client wishes to call Send() from an atomic
+ * context and that the channel should not block.  If the channel is not
+ * allowed to block, then the channel's pages are permanently mapped and
+ * pinned.  Note that this will limit the total size of the channel to
  * VMCI_MAX_PINNED_QP_MEMORY.
+ *
+ * \note Not applicable to VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
  */
 
-#define VPAGECHANNEL_FLAGS_NOTIFY_ONLY       0x1
-#define VPAGECHANNEL_FLAGS_RECV_DELAYED      0x2
 #define VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC 0x4
 
+/**
+ * \brief An element describing a data range.
+ *
+ * Describes a data range, starting at a base address and for a given
+ * length, i.e., an element of a scatter-gather list.  Indicates physical
+ * address for the guest and machine address for hypervisor.  Can be passed
+ * via packets or buffers.
+ *
+ * \note Structure is packed.
+ *
+ * \see VPageChannelPacket
+ * \see VPageChanelBuffer
+ */
 
 typedef
 #include "vmware_pack_begin.h"
 struct VPageChannelElem {
    union {
-      uint64 pa;     // For guest
-      uint64 ma;     // For hypervisor
+      /** \brief Physical address for guest. */
+      uint64 pa;
+
+      /** \brief Machine address for hypervisor. */
+      uint64 ma;
    };
+
+   /** \brief Length of range. */
    uint32 le;
 }
 #include "vmware_pack_end.h"
 VPageChannelElem;
 
+/**
+ * \brief Page channel page types.
+ *
+ * The various types of page channel packets.
+ *
+ * \see VPageChannelPacket
+ */
 typedef enum {
+   /** \brief Data packet. */
    VPCPacket_Data = 1,
-   VPCPacket_Completion_Notify, // Hypervisor to guest only.
-   VPCPacket_GuestConnect,      // Connect to hypervisor.  Internal use only.
-   VPCPacket_HyperConnect,      // Complete connection handshake.  Internal.
-   VPCPacket_RequestBuffer,     // Request buffers.  Internal use only.
-   VPCPacket_SetRecvBuffer,     // Set buffers.  Internal use only.
+
+   /** \brief Completion notification, from hypervisor to guest. */
+   VPCPacket_Completion_Notify,
+
+   /** \cond PRIVATE */
+   /** \brief Connect to hypervisor, internal. */
+   VPCPacket_GuestConnect,
+
+   /** \brief Complete connection handshake, internal. */
+   VPCPacket_HyperConnect,
+
+   /** \brief Request buffers, internal. */
+   VPCPacket_RequestBuffer,
+
+   /** \brief Set buffers, internal. */
+   VPCPacket_SetRecvBuffer,
+
+   /** \brief Hypervisor channel disconnect, internal. */
+   VPCPacket_HyperDisconnect,
+
+   /** \brief Guest channel ACK hypervisor disconnect, internal. */
+   VPCPacket_GuestDisconnect,
+   /** \endcond */
 } VPageChannelPacketType;
 
+/**
+ * \brief Page channel packet structure.
+ *
+ * A packet structure for passing control/data between guest and hypervisor.
+ * Can optionally contain a message and also a number of elements.
+ *
+ * \note Structure is packed.
+ *
+ * \see VPageChannelPacketType
+ */
 typedef
 #include "vmware_pack_begin.h"
 struct VPageChannelPacket {
+   /** \brief Type of packet. */
    VPageChannelPacketType type;
+
+   /** \brief Length of optional message. */
    uint32 msgLen;
+
+   /** \brief Number of optional elements in packet. */
    uint32 numElems;
-   /*
-    * Followed by msgLen of message and numElems of VPageChannelElem.
-    */
+
+   /** \brief Followed by msgLen of message and numElems VPageChannelElem. */
 }
 #include "vmware_pack_end.h"
 VPageChannelPacket;
 
+/**
+ * \brief Page channel buffer structure.
+ *
+ * A buffer of elements (a scatter-gather list).
+ *
+ * \note Structure is packed.
+ *
+ * \see VPageChannelElem
+ */
+
 typedef
 #include "vmware_pack_begin.h"
 struct VPageChannelBuffer {
+   /** \brief Number of elements. */
    uint32 numElems;
+
+   /** \brief First element. */
    VPageChannelElem elems[1];
-   /*
-    * Followed by numElems - 1 of VPageChannelElem.
-    */
+
+   /** \brief Followed by numElems - 1 of VPageChannelElem. */
 }
 #include "vmware_pack_end.h"
 VPageChannelBuffer;
 
+/** \cond PRIVATE */
 typedef
 #include "vmware_pack_begin.h"
 struct VPageChannelGuestConnectMessage {
+
+   /** \brief Guest channel's datagram handle for control channel. */
    VMCIHandle dgHandle;
+
+   /** \brief Guest channel's queuepair handle. */
    VMCIHandle qpHandle;
+
+   /** \brief Size of producer queue in queuepair in bytes. */
    uint64 produceQSize;
+
+   /** \brief Size of consumer queue in queuepair in bytes. */
    uint64 consumeQSize;
+
+   /** \brief Guest channel's doorbell handle. */
    VMCIHandle doorbellHandle;
 }
 #include "vmware_pack_end.h"
@@ -131,28 +253,129 @@ VPageChannelGuestConnectMessage;
 typedef
 #include "vmware_pack_begin.h"
 struct VPageChannelHyperConnectMessage {
+   /** \brief Hypervisor's doorbell handle. */
    VMCIHandle doorbellHandle;
 }
 #include "vmware_pack_end.h"
 VPageChannelHyperConnectMessage;
+/** \endcond PRIVATE */
+
+/** \cond PRIVATE */
+typedef enum VPageChannelState {
+   VPCState_Free = 0,
+   VPCState_Unconnected,
+   VPCState_Connecting,
+   VPCState_Connected,
+   VPCState_Disconnecting,
+   VPCState_Disconnected,
+} VPageChannelState;
+/** \endcond PRIVATE */
+
+/**
+ * \brief Opaque page channel type.
+ */
 
 struct VPageChannel;
 typedef struct VPageChannel VPageChannel;
 
+/**
+ * \brief Client receive callback type.
+ *
+ * Type of receive callback, invoked when there are data packets in the
+ * channel.  The client provides a callback with this type to
+ * VPageChannel_CreateInVM().  If VPAGECHANNEL_FLAGS_NOTIFY_ONLY is specified
+ * in the channel creation flags, then \c packet is \c NULL; otherwise,
+ * \c packet points to a channel packet.
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannelPacket
+ */
+
 typedef void (*VPageChannelRecvCB)(void *clientData,
                                    VPageChannelPacket *packet);
 
 
 #if !defined(VMKERNEL)
 
+/**
+ * \brief Client element allocation callback type.
+ *
+ * Type of element allocation callback, invoked when the channel needs
+ * elements.  The client provides a callback of this type to
+ * VPageChannel_CreateInVM().
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannelElem
+ * \see VPageChannelFreeElemFn
+ */
+
 typedef int (*VPageChannelAllocElemFn)(void *clientData,
                                        VPageChannelElem *elems,
                                        int numElems);
 
+/**
+ * \brief Client element release callback type.
+ *
+ * Type of element release callback, invoked when the channel releases
+ * elements.  The client provides a callback of this type to
+ * VPageChannel_CreateInVM().
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannelElem
+ * \see VPageChannelAllocElemFn
+ */
+
 typedef void (*VPageChannelFreeElemFn)(void *clientData,
                                        VPageChannelElem *elems,
                                        int numElems);
 
+/*
+ ************************************************************************
+ * VPageChannel_CreateInVM                                         */ /**
+ *
+ * \brief Create guest page channel.
+ *
+ * Creates a page channel in the guest.  The channel should be released
+ * with VPageChannel_Destroy().
+ *
+ * \note Only applicable in the guest.
+ *
+ * \see VPageChannel_CreateInVMK()
+ * \see VPageChannel_Destroy()
+ *
+ * \param[out] channel           Pointer to a newly constructed page
+ *                               channel if successful.
+ * \param[in]  resourceId        Resource ID on which the channel should
+ *                               register its control channel.
+ * \param[in]  peerResourceId    Resource ID of peer's control channel.
+ * \param[in]  produceQSize      Size of producer queue in queuepair in
+ *                               bytes.
+ * \param[in]  consumeQSize      Size of consumer queue in queuepair in
+ *                               bytes.
+ * \param[in]  flags             Channel flags.
+ * \param[in]  recvCB            Client's receive callback.
+ * \param[in]  clientRecvData    Client data for client's receive
+ *                               callback.
+ * \param[in]  elemAlloc         Element allocation callback for
+ *                               allocating page ranges (scatter-gather
+ *                               elements).
+ * \param[in]  allocClientData   Client data for element allocation
+ *                               callback.
+ * \param[in]  elemFree          Element release callback for elements.
+ * \param[in]  freeClientData    Client data for element release
+ *                               callback.
+ * \param[in]  defRecvBufs       Default number of elements sent to
+ *                               hypervisor channel.
+ * \param[in]  maxRecvBufs       Maximum number of elements that can be
+ *                               sent to the hypervisor channel.
+ *
+ * \retval     VMCI_SUCCESS      Creation succeeded, \c *channel contains
+ *                               a pointer to a valid channel.
+ * \retval     other             Failure.
+ *
+ ************************************************************************
+ */
+
 int VPageChannel_CreateInVM(VPageChannel **channel,
                             VMCIId resourceId,
                             VMCIId peerResourceId,
@@ -165,28 +388,128 @@ int VPageChannel_CreateInVM(VPageChannel **channel,
                             void *allocClientData,
                             VPageChannelFreeElemFn elemFree,
                             void *freeClientData,
-                            int defaultRecvBuffers,
-                            int maxRecvBuffers);
+                            int defRecvBufs,
+                            int maxRecvBufs);
 
 #else // VMKERNEL
 
+/*
+ ************************************************************************
+ * VPageChannel_CreateInVMK                                        */ /**
+ *
+ * \brief Create a page channel in VMKernel.
+ *
+ * Creates a page channel.  The channel should be released with
+ * VPageChannel_Destroy().
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_CreateInVM()
+ * \see VPageChannel_Destroy()
+ *
+ * \param[out] channel           Pointer to a newly constructed page
+ *                               channel if successful.
+ * \param[in]  resourceId        Resource ID on which to register
+ *                               control channel.
+ * \param[in]  recvCB            Client's receive callback.
+ * \param[in]  clientRecvData    Client data for receive callback.
+ *
+ * \retval     VMCI_SUCCESS      Creation succeeded, \c *channel
+ *                               contains a pointer to a valid channel.
+ * \retval     other             Failure.
+ *
+ ***********************************************************************
+ */
+
 int VPageChannel_CreateInVMK(VPageChannel **channel,
                              VMCIId resourceId,
                              VPageChannelRecvCB recvCB,
                              void *clientRecvData);
 
+/*
+ ************************************************************************
+ * VPageChannel_ReserveBuffers                                     */ /**
+ *
+ * \brief Reserve guest elements.
+ *
+ * Reserve sufficient guest elements to cover the given length.  The
+ * buffers can then be posted to the guest.  This allocates both the
+ * buffer and the elements within the buffer.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_ReleaseBuffers()
+ *
+ * \param[in]  channel  Page channel.
+ * \param[in]  dataLen  Length to reserve in bytes.
+ * \param[out] buffer   Pointer to a buffer containing elements to cover
+ *                      the given length if successful.
+ *
+ * \retval     VMCI_SUCCESS   Reservation succeeded, \c *buffer contains
+ *                            a pointer to a valid buffer.
+ * \retval     other          Failure.
+ *
+ ************************************************************************
+ */
+
 int VPageChannel_ReserveBuffers(VPageChannel *channel,
                                 size_t dataLen,
                                 VPageChannelBuffer **buffer);
+
+/*
+ ************************************************************************
+ * VPageChannel_ReleaseBuffers                                     */ /**
+ *
+ * \brief Release guest elements.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_ReserveBuffers()
+ *
+ * Release guest elements previous reserved with
+ * VPageChannel_ReserveBuffers().  If the buffers were sent to the guest,
+ * then only the buffer itself should be released, i.e.,
+ * \c returnToFreePool should be \c FALSE; the guest will release the
+ * buffers on completion.  Otherwise, if for some reason they are not
+ * sent after reserving them, then \c returnToFreePool should be set to
+ * \c TRUE.
+ *
+ * \param[in]  channel           Page channel.
+ * \param[in]  buffer            Buffer to be released.
+ * \param[in]  returnToFreePool  If \c TRUE, then release the elements
+ *                               of the buffer along with the buffer
+ *                               itself.  If \c FALSE, then release only
+ *                               the buffer pointer itself.
+ *
+ ************************************************************************
+ */
+
 void VPageChannel_ReleaseBuffers(VPageChannel *channel,
                                  VPageChannelBuffer *buffer,
                                  Bool returnToFreePool);
 
 /*
- * This function is called when the client is finished using the
- * scatter-gather list of a packet. This will generate a notification to the
- * guest to pass the ownership of buffers back to the guest. This can also be
- * used to read back the data from hypervisor and send it the to guest.
+ ************************************************************************
+ * VPageChannel_CompletionNotify                                   */ /**
+ *
+ * \brief Notify channel of completion.
+ *
+ * This function is called when the client is finished using the elements
+ * (scatter-gather list) of a packet.  This will generated a notification
+ * to the guest to pass ownership of the buffers back to the guest.  This
+ * can also be used to read back the data from the hypervisor and send
+ * it to the guest.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_ReserveBuffers
+ *
+ * \param[in]  channel  Channel on which I/O is complete.
+ * \param[in]  message  Optional message to send to guest.
+ * \param[in]  len      Length of optional message.
+ * \param[in]  buffer   Buffer used for I/O.
+ *
+ ************************************************************************
  */
 
 int VPageChannel_CompletionNotify(VPageChannel *channel,
@@ -194,10 +517,55 @@ int VPageChannel_CompletionNotify(VPageChannel *channel,
                                   int len,
                                   VPageChannelBuffer *buffer);
 
+/*
+ ************************************************************************
+ * VPageChannel_MapToMa                                           */ /**
+ *
+ * \brief Map guest PA in an element to a list of MAs.
+ *
+ * Map a guest physical address to a list of hypervisor machine
+ * addresses.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \param[in]     channel    Channel on which to map.
+ * \param[in]     paElem     Guest's physical address.
+ * \param[out]    maElems    Hypervisor machine addresses.
+ * \param[in]     numElems   Max number of hypervisor elements.
+ *
+ * \retval  elems    Number of mapped elements.
+ *
+ ************************************************************************
+ */
+
 int VPageChannel_MapToMa(VPageChannel *channel,
                          VPageChannelElem paElem,
                          VPageChannelElem *maElems,
                          uint32 numElems);
+
+/*
+ ************************************************************************
+ * VPageChannel_UnmapMa                                            */ /**
+ *
+ * \brief Unmap MA for a buffer.
+ *
+ * Unmap hypervisor machine addresses referring to a guest physical
+ * addresses.
+ *
+ * \note Only applicable on VMKernel.
+ *
+ * \see VPageChannel_MapToMa
+ *
+ * \param[in]  channel     Channel for which to unmap.
+ * \param[in]  buffer      Buffer containing elements to unmap.
+ * \param[in]  numElems    Number of elements to unmap.
+ *
+ * \retval  0     Unmap successful.
+ * \retval  -1    World not found for channel.
+ *
+ ************************************************************************
+ */
+
 int VPageChannel_UnmapMa(VPageChannel *channel,
                          VPageChannelBuffer *buffer,
                          int numElems);
@@ -205,34 +573,113 @@ int VPageChannel_UnmapMa(VPageChannel *channel,
 #endif // VMKERNEL
 
 /*
- * Common functions.
+ ************************************************************************
+ * VPageChannel_Destroy                                            */ /**
+ *
+ * \brief Destroy the given channel.
+ *
+ * Destroy the given channel.  This will disconnect from the peer
+ * channel (if connected) and release all resources.
+ *
+ * \see VPageChannel_CreateInVMK
+ * \see VPageChannel_CreateInVM
+ *
+ * \param[in]  channel  The channel to be destroyed.
+ *
+ ************************************************************************
  */
 
 void VPageChannel_Destroy(VPageChannel *channel);
+
+/*
+ ************************************************************************
+ * VPageChannel_Send                                               */ /**
+ *
+ * \brief Send a packet to the channel's peer.
+ *
+ * Send a packet to the channel's peer.  A message and a number of
+ * elements may optionally be sent.  If the send is successful, the
+ * elements are owned by the peer and only the buffer itself should
+ * be released, but not the elements within.  If the send fails, the
+ * client should release the buffer and the elements.
+ *
+ * \see VPageChannel_SendPacket
+ *
+ * \param[in]  channel     Channel on which to send.
+ * \param[in]  type        Type of packet to send.
+ * \param[in]  message     Optional message to send.
+ * \param[in]  len         Length of optional message.
+ * \param[in]  buffer      Buffer (of elements) to send.
+ *
+ * \retval  VMCI_SUCCESS   Packet successfully sent, buffer elements
+ *                         owned by peer.
+ * \retval  other          Failure to send, client should release
+ *                         elements.
+ *
+ ************************************************************************
+ */
+
 int VPageChannel_Send(VPageChannel *channel,
                       VPageChannelPacketType type,
                       char *message,
                       int len,
                       VPageChannelBuffer *buffer);
+
+/*
+ ************************************************************************
+ * VPageChannel_SendPacket                                         */ /**
+ *
+ * \brief Send the given packet to the channel's peer.
+ *
+ * Send a client-constructed packet to the channel's peer.  If the
+ * send is successful, any elements in the packet are owned by the
+ * peer.  Otherwise, the client retains ownership.
+ *
+ * \see VPageChannel_Send
+ *
+ * \param[in]  channel  Channel on which to send.
+ * \param[in]  packet   Packet to be sent.
+ *
+ * \retval  VMCI_SUCCESS   Packet successfully sent, buffer elements
+ *                         owned by peer.
+ * \retval  other          Failure to send, client should release
+ *                         elements.
+ *
+ ************************************************************************
+ */
+
 int VPageChannel_SendPacket(VPageChannel *channel,
                             VPageChannelPacket *packet);
-void VPageChannel_PollRecvQ(VPageChannel *channel);
 
+/*
+ ************************************************************************
+ * VPageChannel_PollRecvQ                                          */ /**
+ *
+ * \brief Poll the channel's receive queue for packets.
+ *
+ * Poll the channel's receive queue for packets from the peer.  If any
+ * packets are available, the channel's receive callback will be invoked.
+ *
+ * \param[in]  channel  Channel to poll.
+ *
+ ************************************************************************
+ */
+
+void VPageChannel_PollRecvQ(VPageChannel *channel);
 
 /*
- *-----------------------------------------------------------------------------
+ ************************************************************************
+ * VPageChannel_BufferLen                                          */ /**
  *
- * VPageChannelPacket_BufferLen --
+ * \brief Determine the length of a packet.
  *
- *      Calculate the length of the given packet.
+ * Determine the length of the given packet in bytes.
  *
- * Results:
- *      The length of the given packet in bytes.
+ * \param[in]  packet   Packet for which length is to be determined.
  *
- * Side effects:
- *      None.
+ * \retval     bytes    Size of the packet in bytes.
  *
- *-----------------------------------------------------------------------------
+ ************************************************************************
  */
 
 static INLINE size_t
@@ -252,7 +699,7 @@ VPageChannelPacket_BufferLen(VPageChannelPacket *packet) // IN
    return len;
 }
 
-
+/** \cond PRIVATE */
 #if defined(linux) && !defined(VMKERNEL)
 #include "compat_pci.h"
 #define vmci_pci_map_page(_pg, _off, _sz, _dir) \
@@ -260,5 +707,6 @@ VPageChannelPacket_BufferLen(VPageChannelPacket *packet) // IN
 #define vmci_pci_unmap_page(_dma, _sz, _dir) \
    pci_unmap_page(NULL, (_dma), (_sz), (_dir))
 #endif // linux && !VMKERNEL
+/** \endcond PRIVATE */
 
 #endif // _VMCI_PACKET_H_
index b721994e559685f92e742c3338ad7ca85e3725e9..0b700c279c5b857d83c1e20c15c9659dbcd88dd9 100644 (file)
@@ -1050,6 +1050,7 @@ gboolean
 ToolsDaemonTcloReceiveVixCommand(RpcInData *data) // IN
 {
    VixError err = VIX_OK;
+   uint32 additionalError;
    char *requestName = NULL;
    VixCommandRequestHeader *requestMsg = NULL;
    size_t maxResultBufferSize;
@@ -1117,12 +1118,22 @@ abort:
    /*
     * All Foundry tools commands return results that start with a foundry error
     * and a guest-OS-specific error.
+    *
+    * NOTE: We have always been returning an additional 32 bit error (errno,
+    * or GetLastError() for Windows) along with the 64 bit VixError. The VMX
+    * side has been dropping the higher order 32 bits of VixError (by copying
+    * it onto a 32 bit error). They do save the additional error but as far
+    * as we can tell, it was not getting used by foundry. So at this place,
+    * for certain guest commands that have extra error information tucked into
+    * the higher order 32 bits of the VixError, we use that extra error as the
+    * additional error to be sent back to VMX.
     */
+   additionalError = VixTools_GetAdditionalError(requestMsg->opCode, err);
    Str_Sprintf(tcloBuffer,
                sizeof tcloBuffer,
                "%"FMT64"d %d ",
                err,
-               Err_Errno());
+               additionalError);
    destPtr = tcloBuffer + strlen(tcloBuffer);
 
    /*
index e7365ca3898c67e10c48fd4b0c4ab5ed733dc959..fb5a71c800e17e7515327d83527b372b05ffad25 100644 (file)
 #include "impersonate.h"
 #include "vixOpenSource.h"
 #include "vixToolsInt.h"
+#include "vmware/tools/plugin.h"
 
 #ifdef _WIN32
 #include "registryWin32.h"
  * No support for open-vm-tools.
  */
 #if (defined(_WIN32) || defined(linux)) && !defined(OPEN_VM_TOOLS)
-// XXX Disabled until VGAuth API signature changes work through GoBuild
-#define SUPPORT_VGAUTH 0
+#define SUPPORT_VGAUTH 1
 #else
 #define SUPPORT_VGAUTH 0
 #endif
 #include "VGAuthIdProvider.h"
 
 #define VMTOOLSD_APP_NAME "vmtoolsd"
+
+#define VIXTOOLS_CONFIG_USE_VGAUTH_NAME "useVGAuth"
+/*
+ * XXX Leave this off by default until the VGAuth service is being
+ * officially installed.
+ */
+#define USE_VGAUTH_DEFAULT FALSE
+
+static gboolean gSupportVGAuth = USE_VGAUTH_DEFAULT;
+static gboolean QueryVGAuthConfig(GKeyFile *confDictRef);
+
 #endif
 
+
 #define SECONDS_BETWEEN_POLL_TEST_FINISHED     1
 
 /*
@@ -576,6 +588,10 @@ VixError GuestAuthPasswordAuthenticateImpersonate(
    char const *obfuscatedNamePassword,
    void **userToken);
 
+VixError GuestAuthSAMLAuthenticateAndImpersonate(
+   char const *obfuscatedNamePassword,
+   void **userToken);
+
 void GuestAuthUnimpersonate();
 
 #if SUPPORT_VGAUTH
@@ -607,6 +623,9 @@ VixTools_Initialize(Bool thisProcessRunsAsRootParam,
                     void *clientData)                                               // IN
 {
    VixError err = VIX_OK;
+#if SUPPORT_VGAUTH
+   ToolsAppCtx *ctx = (ToolsAppCtx *) clientData;
+#endif
 
    /*
     * Run unit tests on DEVEL builds.
@@ -640,6 +659,10 @@ VixTools_Initialize(Bool thisProcessRunsAsRootParam,
     */
 #endif
 
+#if SUPPORT_VGAUTH
+   gSupportVGAuth = QueryVGAuthConfig(ctx->config);
+#endif
+
 #ifdef _WIN32
    err = VixToolsInitializeWin32();
    if (VIX_FAILED(err)) {
@@ -2230,6 +2253,9 @@ VixToolsTranslateVGAuthError(VGAuthError vgErr)
               __FUNCTION__, vgErr);
       break;
    }
+   Debug("%s: translated VGAuth err "VGAUTHERR_FMT64X" to Vix err %"FMT64"d\n",
+         __FUNCTION__, vgErr, err);
+
 
    return err;
 }
@@ -7240,6 +7266,18 @@ VixToolsImpersonateUser(VixCommandRequestHeader *requestMsg,   // IN
       }
       break;
    }
+   case VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN:
+   {
+      VixCommandSAMLToken *samlStruct =
+         (VixCommandSAMLToken *) credentialField;
+      credentialField += sizeof(*samlStruct);
+
+      err = VixToolsImpersonateUserImplEx(NULL,
+                                          credentialType,
+                                          credentialField,
+                                          userToken);
+      break;
+   }
    case VIX_USER_CREDENTIAL_SSPI:
       /*
        * SSPI currently only supported in ticketed sessions
@@ -7424,11 +7462,16 @@ VixToolsImpersonateUserImplEx(char const *credentialTypeStr,         // IN
        */
       if ((VIX_USER_CREDENTIAL_NAME_PASSWORD != credentialType)
             && (VIX_USER_CREDENTIAL_NAME_PASSWORD_OBFUSCATED != credentialType)
-            && (VIX_USER_CREDENTIAL_TICKETED_SESSION != credentialType)) {
+            && (VIX_USER_CREDENTIAL_TICKETED_SESSION != credentialType)
+#if SUPPORT_VGAUTH
+            && (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN != credentialType)
+#endif
+            ) {
          err = VIX_E_NOT_SUPPORTED;
          goto abort;
       }
 
+
       /*
        * Use the GuestAuth library to do name-password authentication
        * and impersonation.
@@ -7444,6 +7487,16 @@ VixToolsImpersonateUserImplEx(char const *credentialTypeStr,         // IN
          goto abort;
       }
 
+      if (VIX_USER_CREDENTIAL_SAML_BEARER_TOKEN == credentialType) {
+         if (GuestAuthEnabled()) {
+            err = GuestAuthSAMLAuthenticateAndImpersonate(obfuscatedNamePassword,
+                                                          userToken);
+         } else {
+            err = VIX_E_NOT_SUPPORTED;
+         }
+         goto abort;
+      }
+
       /* Get the authToken and impersonate */
       if (VIX_USER_CREDENTIAL_TICKETED_SESSION == credentialType) {
 #ifdef _WIN32
@@ -8749,7 +8802,8 @@ VixToolsAddAuthPrincipal(VixCommandRequestHeader *requestMsg)    // IN
    si.subject.val.name = (char *) principalName;
    si.comment = (char *) principalComment;
 
-   vgErr = VGAuth_AddSubject(ctx, userName, req->addMapping, pemCert, &si);
+   vgErr = VGAuth_AddSubject(ctx, userName, req->addMapping, pemCert, &si,
+                             0, NULL);
    if (VGAUTH_FAILED(vgErr)) {
       err = VixToolsTranslateVGAuthError(vgErr);
    }
@@ -8860,13 +8914,13 @@ VixToolsRemoveAuthPrincipal(VixCommandRequestHeader *requestMsg)    // IN
    }
 
    if (VIX_GUEST_AUTH_PRINCIPAL_TYPE_NONE == req->principalType) {
-      vgErr = VGAuth_RemoveCert(ctx, userName, pemCert);
+      vgErr = VGAuth_RemoveCert(ctx, userName, pemCert, 0, NULL);
    } else {
       subj.type = (req->principalType == VIX_GUEST_AUTH_PRINCIPAL_TYPE_NAMED) ?
          VGAUTH_SUBJECT_NAMED : VGAUTH_SUBJECT_ANY;
       subj.val.name = (char *) principalName;
 
-      vgErr = VGAuth_RemoveSubject(ctx, userName, pemCert, &subj);
+      vgErr = VGAuth_RemoveSubject(ctx, userName, pemCert, &subj, 0, NULL);
    }
    if (VGAUTH_FAILED(vgErr)) {
       err = VixToolsTranslateVGAuthError(vgErr);
@@ -8966,7 +9020,7 @@ VixToolsListAuthPrincipals(VixCommandRequestHeader *requestMsg, // IN
       goto abort;
    }
 
-   vgErr = VGAuth_QueryIdProviders(ctx, userName, &num, &idList);
+   vgErr = VGAuth_QueryIdProviders(ctx, userName, 0, NULL, &num, &idList);
    if (VGAUTH_FAILED(vgErr)) {
       err = VixToolsTranslateVGAuthError(vgErr);
       goto abort;
@@ -9137,7 +9191,7 @@ VixToolsListMappedPrincipals(VixCommandRequestHeader *requestMsg, // IN
       goto abort;
    }
 
-   vgErr = VGAuth_QueryMappedIdentities(ctx, &num, &miList);
+   vgErr = VGAuth_QueryMappedIdentities(ctx, 0, NULL, &num, &miList);
    if (VGAUTH_FAILED(vgErr)) {
       err = VixToolsTranslateVGAuthError(vgErr);
       goto abort;
@@ -10300,8 +10354,6 @@ VixToolsRewriteError(uint32 opCode,          // IN
 {
    VixError newError = origError;
 
-   ASSERT(VIX_ERROR_CODE(origError) == origError);
-
    switch (opCode) {
       /*
        * This should include all non-VI guest operations.
@@ -10334,6 +10386,7 @@ VixToolsRewriteError(uint32 opCode,          // IN
    case VIX_COMMAND_LIST_FILESYSTEMS:
    case VIX_COMMAND_WAIT_FOR_TOOLS:
    case VIX_COMMAND_CAPTURE_SCREEN:
+      ASSERT(VIX_ERROR_CODE(origError) == origError);
       switch (origError) {
       case VIX_E_INVALID_LOGIN_CREDENTIALS:
          newError = VIX_E_GUEST_USER_PERMISSIONS;
@@ -10346,6 +10399,48 @@ VixToolsRewriteError(uint32 opCode,          // IN
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixTools_GetAdditionalError --
+ *
+ *    Gets the vix extra/additional error if any.
+ *
+ *    Some errors returned by tools may have extra error in
+ *    the higher order 32 bits. We need to pass that back.
+ *
+ * Results:
+ *      uint32
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint32
+VixTools_GetAdditionalError(uint32 opCode,    // IN
+                            VixError error)   // IN
+{
+   uint32 err;
+
+   switch (opCode) {
+      case VIX_COMMAND_CREATE_REGISTRY_KEY:
+      case VIX_COMMAND_LIST_REGISTRY_KEYS:
+      case VIX_COMMAND_DELETE_REGISTRY_KEY:
+      case VIX_COMMAND_SET_REGISTRY_VALUE:
+      case VIX_COMMAND_LIST_REGISTRY_VALUES:
+      case VIX_COMMAND_DELETE_REGISTRY_VALUE:
+         err = VIX_ERROR_EXTRA_ERROR(error);
+         break;
+      default:
+        err = Err_Errno();
+   }
+
+   return err;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -10631,7 +10726,7 @@ static Bool
 GuestAuthEnabled(void)
 {
 #if SUPPORT_VGAUTH
-   return TRUE;
+   return gSupportVGAuth;
 #else
    return FALSE;
 #endif
@@ -10684,13 +10779,94 @@ GuestAuthPasswordAuthenticateImpersonate(
    }
 
    vgErr = VGAuth_ValidateUsernamePassword(ctx, username, password,
+                                           0, NULL,
                                            &newHandle);
    if (VGAUTH_FAILED(vgErr)) {
       err = VixToolsTranslateVGAuthError(vgErr);
       goto done;
    }
 
-   vgErr = VGAuth_Impersonate(ctx, newHandle);
+   vgErr = VGAuth_Impersonate(ctx, newHandle, 0, NULL);
+   if (VGAUTH_FAILED(vgErr)) {
+      err = VixToolsTranslateVGAuthError(vgErr);
+      goto done;
+   }
+
+   *userToken = VGAUTH_GENERIC_USER_TOKEN;
+
+   err = VIX_OK;
+
+done:
+
+   if (newHandle) {
+      VGAuth_UserHandleFree(newHandle);
+   }
+
+   return err;
+#else
+   return VIX_E_NOT_SUPPORTED;
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * GuestAuthSAMLAuthenticateAndImpersonate
+ *
+ *      Do SAML bearer token authentication and impersonation using
+ *      the GuestAuth library.
+ *
+ * Results:
+ *      VIX_OK if successful.  Other VixError code otherwise.
+ *
+ * Side effects:
+ *      Current process impersonates.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VixError
+GuestAuthSAMLAuthenticateAndImpersonate(
+   char const *obfuscatedNamePassword, // IN
+   void **userToken)                   // OUT
+{
+#if SUPPORT_VGAUTH
+   VixError err;
+   char *token;
+   char *username;
+   VGAuthContext *ctx = NULL;
+   VGAuthError vgErr;
+   VGAuthUserHandle *newHandle = NULL;
+
+   Debug(">%s\n", __FUNCTION__);
+   err = VixMsg_DeObfuscateNamePassword(obfuscatedNamePassword,
+                                        &token,
+                                        &username);
+   if (err != VIX_OK) {
+      goto done;
+   }
+
+   err = VIX_E_INVALID_LOGIN_CREDENTIALS;
+
+   vgErr = TheVGAuthContext(&ctx);
+   if (VGAUTH_FAILED(vgErr)) {
+      err = VixToolsTranslateVGAuthError(vgErr);
+      goto done;
+   }
+
+   vgErr = VGAuth_ValidateSamlBearerToken(ctx,
+                                          token,
+                                          username,
+                                          0,
+                                          NULL,
+                                          &newHandle);
+   if (VGAUTH_FAILED(vgErr)) {
+      err = VixToolsTranslateVGAuthError(vgErr);
+      goto done;
+   }
+
+   vgErr = VGAuth_Impersonate(ctx, newHandle, 0, NULL);
    if (VGAUTH_FAILED(vgErr)) {
       err = VixToolsTranslateVGAuthError(vgErr);
       goto done;
@@ -10706,6 +10882,8 @@ done:
       VGAuth_UserHandleFree(newHandle);
    }
 
+   Debug("<%s\n", __FUNCTION__);
+
    return err;
 #else
    return VIX_E_NOT_SUPPORTED;
@@ -10746,6 +10924,54 @@ GuestAuthUnimpersonate(void)
 
 
 #if SUPPORT_VGAUTH
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueryVGAuthConfig
+ *
+ *      Check the tools configuration to see if VGAuth should be used.
+ *
+ * Results:
+ *      TRUE if vgauth should be used, FALSE if not.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gboolean
+QueryVGAuthConfig(GKeyFile *confDictRef)                       // IN
+{
+   gboolean useVGAuth;
+   gboolean retVal = USE_VGAUTH_DEFAULT;
+   GError *gErr = NULL;
+
+   if (confDictRef != NULL) {
+      useVGAuth = g_key_file_get_boolean(confDictRef,
+                                         VIX_TOOLS_CONFIG_API_GROUPNAME,
+                                         VIXTOOLS_CONFIG_USE_VGAUTH_NAME,
+                                         &gErr);
+
+      /*
+       * g_key_file_get_boolean() will return FALSE and set an error
+       * if the value isn't in config, so use the default in that
+       * case.
+       */
+      if (!useVGAuth && (NULL != gErr)) {
+         g_error_free(gErr);
+         retVal = USE_VGAUTH_DEFAULT;
+      } else {
+         retVal = useVGAuth;
+      }
+   }
+
+   Debug("%s: vgauth usage is: %d\n", __FUNCTION__, retVal);
+
+   return retVal;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -10772,8 +10998,16 @@ TheVGAuthContext(VGAuthContext **ctx) // OUT
    static VGAuthContext *vgaCtx = NULL;
    VGAuthError vgaCode = VGAUTH_E_OK;
 
+   /*
+    * XXX This needs to handle errors better -- if the service gets
+    * reset, the context will point to junk and anything using it will
+    * fail.
+    *
+    * Maybe add a no-op API here to poke it?  Or make the underlying
+    * VGAuth code smarter.
+    */
    if (vgaCtx == NULL) {
-      vgaCode = VGAuth_Init(VMTOOLSD_APP_NAME, 0, NULL, 0, &vgaCtx);
+      vgaCode = VGAuth_Init(VMTOOLSD_APP_NAME, 0, NULL, &vgaCtx);
    }
 
    *ctx = vgaCtx;
index fa5b9a6d28b3e3b1a942baae48f833d8fa2568bf..5b37c5c897111eb27eccbd8760da4e0020fd7eb8 100644 (file)
@@ -92,6 +92,8 @@ VixError VixTools_ProcessVixCommand(VixCommandRequestHeader *requestMsg,
                                     size_t *resultLen,
                                     Bool *deleteResultBufferResult);
 
+uint32 VixTools_GetAdditionalError(uint32 opCode,
+                                   VixError error);
 
 Bool VixToolsImpersonateUserImpl(char const *credentialTypeStr,
                                  int credentialType,