]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
2009.03.18-154848 2009.03.18-154848
authorMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Wed, 18 Mar 2009 23:41:37 +0000 (16:41 -0700)
committerMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Wed, 18 Mar 2009 23:41:37 +0000 (16:41 -0700)
196 files changed:
open-vm-tools/ChangeLog
open-vm-tools/Makefile.am
open-vm-tools/NEWS
open-vm-tools/configure.ac
open-vm-tools/guestd/Makefile.am
open-vm-tools/guestd/main.c
open-vm-tools/guestd/toolsDaemon.c
open-vm-tools/hgfsclient/Makefile.am
open-vm-tools/hgfsclient/hgfsclient.c
open-vm-tools/hgfsclient/stub-user-util.c [deleted file]
open-vm-tools/lib/Makefile.am
open-vm-tools/lib/appUtil/appUtilX11.c
open-vm-tools/lib/auth/authPosix.c
open-vm-tools/lib/dnd/dndFileContentsUtil.h [moved from open-vm-tools/lib/include/dndFileContentsUtil.h with 100% similarity]
open-vm-tools/lib/dnd/dndInt.h [moved from open-vm-tools/lib/include/dndInt.h with 100% similarity]
open-vm-tools/lib/dndGuest/copyPasteRpcV3.hh [moved from open-vm-tools/lib/include/copyPasteRpcV3.hh with 100% similarity]
open-vm-tools/lib/dndGuest/dnd.hh [moved from open-vm-tools/lib/include/dnd.hh with 100% similarity]
open-vm-tools/lib/dndGuest/dndRpc.hh [moved from open-vm-tools/lib/include/dndRpc.hh with 100% similarity]
open-vm-tools/lib/dndGuest/dndRpcV3.hh [moved from open-vm-tools/lib/include/dndRpcV3.hh with 100% similarity]
open-vm-tools/lib/dndGuest/dndTransport.hh [moved from open-vm-tools/lib/include/dndTransport.hh with 100% similarity]
open-vm-tools/lib/dndGuest/dndTransportGuestRpc.hh [moved from open-vm-tools/lib/include/dndTransportGuestRpc.hh with 100% similarity]
open-vm-tools/lib/file/file.c
open-vm-tools/lib/file/filePosix.c
open-vm-tools/lib/foundryMsg/foundryMsg.c
open-vm-tools/lib/ghIntegration/ghIntegration.c
open-vm-tools/lib/ghIntegration/ghIntegrationInt.h
open-vm-tools/lib/ghIntegration/ghIntegrationX11.c
open-vm-tools/lib/guestRpc/guestlibV3.x
open-vm-tools/lib/include/buildNumber.h
open-vm-tools/lib/include/conf.h
open-vm-tools/lib/include/guestInfo.h
open-vm-tools/lib/include/guestStats.h
open-vm-tools/lib/include/guest_os.h
open-vm-tools/lib/include/hostinfo.h
open-vm-tools/lib/include/log.h
open-vm-tools/lib/include/loglevel_user.h
open-vm-tools/lib/include/resolution.h
open-vm-tools/lib/include/str.h
open-vm-tools/lib/include/toolsLogger.h [deleted file]
open-vm-tools/lib/include/unicodeBase.h
open-vm-tools/lib/include/unityCommon.h
open-vm-tools/lib/include/vix.h
open-vm-tools/lib/include/vmGuestLib.h
open-vm-tools/lib/include/vm_basic_defs.h
open-vm-tools/lib/include/vm_basic_types.h
open-vm-tools/lib/include/vm_legal.h
open-vm-tools/lib/include/vm_product.h
open-vm-tools/lib/include/vm_tools_version.h
open-vm-tools/lib/include/vm_version.h
open-vm-tools/lib/include/vmtoolsApp.h
open-vm-tools/lib/include/x86cpuid.h
open-vm-tools/lib/misc/codeset.c
open-vm-tools/lib/misc/hostinfoPosix.c
open-vm-tools/lib/misc/posixPosix.c
open-vm-tools/lib/misc/timeutil.c
open-vm-tools/lib/misc/util_misc.c
open-vm-tools/lib/netUtil/netUtilLinux.c
open-vm-tools/lib/string/str.c
open-vm-tools/lib/toolsLogger/logger.c [deleted file]
open-vm-tools/lib/toolsLogger/toolsLoggerInt.h [deleted file]
open-vm-tools/lib/unicode/unicodeSimpleBase.c
open-vm-tools/lib/unicode/unicodeSimpleTypes.c
open-vm-tools/lib/unity/unity.c
open-vm-tools/lib/unity/unityPlatform.h
open-vm-tools/lib/unity/unityPlatformX11.c
open-vm-tools/lib/unity/unityPlatformX11Settings.c
open-vm-tools/lib/unity/unityPlatformX11Window.c
open-vm-tools/lib/unity/unityX11.h
open-vm-tools/lib/user/hostinfoPosix.c
open-vm-tools/lib/vixTools/vixTools.c
open-vm-tools/libguestlib/vmGuestLib.c
open-vm-tools/libvmtools/vmtools.c
open-vm-tools/libvmtools/vmtoolsLog.c
open-vm-tools/modules/Makefile.am
open-vm-tools/modules/freebsd/vmblock/compat_vop.h
open-vm-tools/modules/freebsd/vmblock/subr.c
open-vm-tools/modules/freebsd/vmblock/vm_basic_defs.h
open-vm-tools/modules/freebsd/vmblock/vm_basic_types.h
open-vm-tools/modules/freebsd/vmblock/vnops.c
open-vm-tools/modules/freebsd/vmhgfs/compat_vop.h
open-vm-tools/modules/freebsd/vmhgfs/vm_basic_defs.h
open-vm-tools/modules/freebsd/vmhgfs/vm_basic_types.h
open-vm-tools/modules/freebsd/vmhgfs/x86cpuid.h
open-vm-tools/modules/freebsd/vmmemctl/vm_basic_defs.h
open-vm-tools/modules/freebsd/vmmemctl/vm_basic_types.h
open-vm-tools/modules/freebsd/vmxnet/vm_basic_types.h
open-vm-tools/modules/freebsd/vmxnet/vm_device_version.h
open-vm-tools/modules/linux/dkms.conf
open-vm-tools/modules/linux/pvscsi/Makefile
open-vm-tools/modules/linux/pvscsi/pvscsi_defs.h
open-vm-tools/modules/linux/pvscsi/scsi_defs.h
open-vm-tools/modules/linux/pvscsi/vm_basic_defs.h
open-vm-tools/modules/linux/pvscsi/vm_basic_types.h
open-vm-tools/modules/linux/pvscsi/vm_device_version.h
open-vm-tools/modules/linux/vmblock/Makefile
open-vm-tools/modules/linux/vmblock/include/compat_wait.h
open-vm-tools/modules/linux/vmblock/include/vm_basic_defs.h
open-vm-tools/modules/linux/vmblock/include/vm_basic_types.h
open-vm-tools/modules/linux/vmci/Makefile
open-vm-tools/modules/linux/vmci/compat_wait.h
open-vm-tools/modules/linux/vmci/vm_basic_defs.h
open-vm-tools/modules/linux/vmci/vm_basic_types.h
open-vm-tools/modules/linux/vmci/vm_device_version.h
open-vm-tools/modules/linux/vmci/vmciGuestKernelAPI.h
open-vm-tools/modules/linux/vmhgfs/Makefile
open-vm-tools/modules/linux/vmhgfs/Makefile.normal
open-vm-tools/modules/linux/vmhgfs/compat_wait.h
open-vm-tools/modules/linux/vmhgfs/vm_basic_defs.h
open-vm-tools/modules/linux/vmhgfs/vm_basic_types.h
open-vm-tools/modules/linux/vmhgfs/x86cpuid.h
open-vm-tools/modules/linux/vmmemctl/Makefile
open-vm-tools/modules/linux/vmmemctl/compat_wait.h
open-vm-tools/modules/linux/vmmemctl/vm_basic_defs.h
open-vm-tools/modules/linux/vmmemctl/vm_basic_types.h
open-vm-tools/modules/linux/vmsync/Makefile
open-vm-tools/modules/linux/vmxnet/Makefile
open-vm-tools/modules/linux/vmxnet/compat_netdevice.h
open-vm-tools/modules/linux/vmxnet/vm_basic_types.h
open-vm-tools/modules/linux/vmxnet/vm_device_version.h
open-vm-tools/modules/linux/vmxnet/vmxnet.c
open-vm-tools/modules/linux/vmxnet3/Makefile
open-vm-tools/modules/linux/vmxnet3/Makefile.kernel
open-vm-tools/modules/linux/vmxnet3/Makefile.normal
open-vm-tools/modules/linux/vmxnet3/autoconf/netif_num_params.c [new file with mode: 0644]
open-vm-tools/modules/linux/vmxnet3/compat_netdevice.h
open-vm-tools/modules/linux/vmxnet3/vm_basic_types.h
open-vm-tools/modules/linux/vmxnet3/vm_device_version.h
open-vm-tools/modules/linux/vmxnet3/vmxnet3.c
open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h
open-vm-tools/modules/linux/vsock/Makefile
open-vm-tools/modules/linux/vsock/include/compat_wait.h
open-vm-tools/modules/linux/vsock/include/vm_basic_defs.h
open-vm-tools/modules/linux/vsock/include/vm_basic_types.h
open-vm-tools/modules/linux/vsock/include/vmciGuestKernelAPI.h
open-vm-tools/modules/linux/vsock/include/x86cpuid.h
open-vm-tools/modules/linux/vsock/linux/af_vsock.c
open-vm-tools/modules/linux/vsock/linux/vmci_sockets.h
open-vm-tools/modules/linux/vsock/linux/vsockPacket.h
open-vm-tools/modules/linux/vsock/linux/vsockSocketWrapper.h
open-vm-tools/modules/solaris/vmhgfs/Makefile
open-vm-tools/modules/solaris/vmhgfs/compat/compat_stdarg.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/str.h
open-vm-tools/modules/solaris/vmhgfs/vm_basic_defs.h
open-vm-tools/modules/solaris/vmhgfs/vm_basic_types.h
open-vm-tools/modules/solaris/vmhgfs/x86cpuid.h
open-vm-tools/modules/solaris/vmxnet/vm_basic_types.h
open-vm-tools/modules/solaris/vmxnet/vm_device_version.h
open-vm-tools/modules/solaris/vmxnet3/COPYING.CDDL [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/Makefile [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/includeCheck.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/net.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/net_sg.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/upt1_defs.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vm_basic_types.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vm_device_version.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmnet_def.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmware_pack_begin.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmware_pack_end.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet2_def.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3_defs.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3_main.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3_rx.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3_solaris.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3_solaris_compat.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3_tx.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3_utils.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet3s.conf [new file with mode: 0644]
open-vm-tools/modules/solaris/vmxnet3/vmxnet_def.h [new file with mode: 0644]
open-vm-tools/rpctool/COPYING [moved from open-vm-tools/services/plugins/COPYING with 100% similarity]
open-vm-tools/rpctool/Makefile.am [moved from open-vm-tools/lib/toolsLogger/Makefile.am with 68% similarity]
open-vm-tools/rpctool/rpctool.c [new file with mode: 0644]
open-vm-tools/scripts/linux/pam.d/vmtoolsd [moved from open-vm-tools/scripts/linux/pam.d/vmware-guestd with 100% similarity]
open-vm-tools/scripts/linux/pam.d/vmtoolsd-x64 [moved from open-vm-tools/scripts/linux/pam.d/vmware-guestd-x64 with 100% similarity]
open-vm-tools/services/plugins/guestInfo/guestInfoServer.c
open-vm-tools/services/plugins/guestInfo/perfMonLinux.c
open-vm-tools/services/plugins/powerOps/powerOps.c
open-vm-tools/services/plugins/vmbackup/stateMachine.c
open-vm-tools/services/vmtoolsd/Makefile.am
open-vm-tools/services/vmtoolsd/cmdLine.c
open-vm-tools/services/vmtoolsd/mainLoop.c
open-vm-tools/services/vmtoolsd/mainPosix.c
open-vm-tools/services/vmtoolsd/pluginMgr.c
open-vm-tools/services/vmtoolsd/serviceObj.c
open-vm-tools/services/vmtoolsd/toolsCoreInt.h
open-vm-tools/services/vmtoolsd/toolsRpc.c
open-vm-tools/toolbox/toolbox-gtk.c
open-vm-tools/toolbox/toolboxGtkInt.h
open-vm-tools/toolbox/toolboxScripts.c
open-vm-tools/vmware-user/Makefile.am
open-vm-tools/vmware-user/copyPaste.cpp [deleted file]
open-vm-tools/vmware-user/copyPasteDnDWrapper.cpp [moved from open-vm-tools/vmware-user/copyPasteWrapper.cpp with 73% similarity]
open-vm-tools/vmware-user/copyPasteDnDWrapper.h [moved from open-vm-tools/vmware-user/copyPasteWrapper.h with 75% similarity]
open-vm-tools/vmware-user/copyPasteUI.cpp
open-vm-tools/vmware-user/copyPasteUI.h
open-vm-tools/vmware-user/dnd.cpp [deleted file]
open-vm-tools/vmware-user/vmware-user.cpp

index 60bd98279618b7b4d136041d3a767c27414d3190..04ec6af007ba978c8fef14b3dbd91294493dc0f8 100644 (file)
@@ -1,5 +1,153 @@
+2009-03-18     Marcelo Vanzin   <mvanzin@vmware.com>
+       * Resync with internal trunk (2009.03.13)
+
+       * configure.ac: check for FreeBSD kernel tree when building modules; warn
+         about which version of make to use when building kernel modules on FreeBSD
+         and Solaris; add compiler defines for identifying Solaris 9 and 11.
+
+       * configure.ac, modules/Makefile.am: handle SYSDIR on FreeBSD.
+
+       * guestd/main.c, modules/solaris/vmhgfs/Makefile: remove HGFS-related that
+         is now obsolete with the recent changes to the HGFS module on Solaris.
+
+       * guestd/toolsDaemon.c: default to the configuration dir when the power
+         script path is not absolute.
+
+       * guestd/toolsDaemon.c, lib/include/guestInfo.h, lib/netUtil/netUtilLinux.c:
+         handle case when all network interfaces have been disabled and send an
+         "unknown" IP address to the host.
+
+       * guestd/toolsDaemon.c, services/vmtoolsd/toolsRpc.c: always send
+         TOOLS_VERSION_UNMANAGED from an open-vm-tools build, so there's no need for
+         a config file option anymore.
+
+       * hgfsclient/*: make it link to libvmtools to avoid code duplication.
+
+       * lib/appUtil/appUtil.c: update list of "skippable" apps when figuring out
+         an application's path.
+
+       * lib/auth/authPosix.c, scripts/linux/pam.d/*, guestd/Makefile.am,
+         services/vmtoolsd/Makefile.am : change the name of the PAM application to
+         "vmtoolsd" to reflect the new service name.
+
+       * lib/dnd/dndFileContentsUtil.h, lib/dnd/dndInt.h, lib/dndGuest/*.hh, and
+         corresponding files in lib/include: relocate private headers.
+
+       * lib/ghIntegration/ghIntegration.c, lib/ghIntegration/ghIntegrationInt.h,
+         lib/ghIntegration/ghIntegrationX11.c, lib/include/unityCommon.h: glue code
+         for Outlook mirrored folder, which does not affect open-vm-tools.
+
+       * lib/guestRpc/guestlibV3.x, lib/include/vmGuestLib.h,
+         libguestlib/vmGuestLib.c: add new guestlib counters.
+
+       * lib/include/conf.h, toolbox/toolbox-gtk.c: remove the need for the
+         "helpdir" config option; this doesn't really affect open-vm-tools since the
+         help files are not yet included.
+
+       * lib/include/guest_os.h, lib/misc/hostinfoPosix.c: more guest OS names; fix
+         name used to identify Solaris to match what VMware's host code expects.
+
+       * lib/include/guestStats.h: documentation changes.
+
+       * lib/include/hostinfo.h, lib/user/hostinfoPosix.c: add a new function that
+         behaves like daemon(3), but is more Mac OS-friendly.
+
+       * lib/include/toolsLogger.h, lib/Makefile.am, lib/toolsLogger/*: removed
+         library, which is not used anymore.
+
+       * lib/include/vm_basic_types.h, lib/misc/timeutil.c: fixes to compile under
+         (Open) Solaris 11.
+
+       * lib/include/vmtoolsApp.h, services/plugins/vmbackup/stateMachine.c,
+         services/vmtoolsd/mainLoop.c, services/vmtoolsd/mainPosix.c,
+         services/vmtoolsd/serviceObj.c, services/vmtoolsd/toolsCoreInt.h: add new
+         signal handler to gather debugging information from a running vmtoolsd
+         instance.
+
+       * lib/misc/posixPosix.c: fix off-by-one error.
+
+       * lib/unity/unity.c, lib/unity/unityPlatform.h, lib/unity/unityPlatformX11.c,
+         lib/unity/unityPlatformX11Settings.c: always send Unity updates using RPCI;
+         this avoids a possible race between replying to an incoming RPC and sending
+         an Unity update from a different thread; also, API documentation updates.
+
+       * lib/unity/unityPlatformX11.c: verify the DnD detection window was
+         initialized before actually using it.
+
+       * lib/unity/unityPlatformX11Settings.c, lib/unity/unityPlatformX11Window.c:
+         reset _NET_WM_DESKTOP as necessary before exiting Unity; this could cause
+         guest taskbars to disappear when in Unity mode.
+
+       * lib/unity/unityPlatformX11.c, lib/unity/unityPlatformX11Window.c,
+         lib/unity/unityX11.h: examine WM_CLIENT_LEADER when gathering application
+         information; certain applications use this property to define the window
+         where the WM_COMMAND property should be.
+
+       * lib/vixTools/vixTools.c: do not follow symlinks when deleting files in the
+         guest using the VIX API.
+
+       * libvmtools/vmtools.c, libvmtools/vmtoolsLog.c: allow the logging subsystem
+         to be re-configured, and clean up the logging data when unloading the
+         library; allow ${USER} and ${PID} to be used in log file paths.
+
+       * modules/freebsd/vmblock/subr.c, modules/freebsd/vmblock/vnops.c: fix kernel
+         panic on FreeBSD 7.
+
+       * modules/linux/*/Makefile: remove GCC version check.
+
+       * modules/linux/*/compat_wait.h: fix COMPAT_DEFINE_WAIT for "vanilla" 2.4
+         kernels.
+
+       * modules/linux/vmhgfs/Makefile.normal: fix build of HGFS module on 2.4
+         kernels.
+
+       * modules/linux/vmxnet/*, modules/linux/vmxnet3/*: avoid using compat
+         functions when they're not needed; add compatibility functions for
+         newer Linux kernels.
+
+       * modules/linux/vsock/linux/af_vsock.c: fix two races; one when the socket
+         state changed between calls to VSockVmciRecvStreamCB and
+         VSockVmciRecvPktWork, and another when trying to read from the socket after
+         a RST arrived after the socket got a detach notification.
+
+       * modules/solaris/vmxnet3/*: add Solaris vmxnet3 driver.
+
+       * rpctool/*: add "rpctool", a simple, stand-alone tool to send RPC commands
+         to the host software.
+
+       * services/plugins/guestInfo/guestInfoServer.c: don't cache configuration
+         data.
+
+       * services/plugins/guestInfo/perfMonLinux.c: fix problem with overwriting
+         flags after GuestInfoMonitorReadMeminfo() was called. (Same as fix to
+         lib/guestInfo on previous release.)
+
+       * services/plugins/powerOps/powerOps.c: handle power ops-related options
+         sent from the host.
+
+       * services/vmtoolsd/mainLoop.c: handle re-loading the configuration file.
+
+       * services/vmtoolsd/mainPosix.c: exec after forking on Mac OS, since
+         CoreFoundation classes don't work after a fork.
+
+       * services/vmtoolsd/pluginMgr.c: allow both 32 and 64 bit plugins to be
+         installed on Solaris by loading them from the appropriate directory;
+         add library loading code that is not really needed (nor used) in
+         open-vm-tools.
+
+       * services/vmtoolsd/toolsRpc.c: send another "capability" the host expects
+         from Tools.
+
+       * toolbox/toolbox-gtk.c: add F1 shortcut to invoke help.
+
+       * toolbox/toolboxScripts.c: fix issue with freeing data that should not be
+         freed.
+
+       * vmware-user/*: implement the new DnD protocol (V3).
+
+
 2009-02-18     Marcelo Vanzin   <mvanzin@vmware.com>
-       * Resync with internal trunk (2009.01.13)
+       * Resync with internal trunk (2009.02.13)
 
        * configure.ac, m4/vmtools.m4: clean up a lot of the library detection code.
 
index dc90b49685611b1255ad87af1b0a0a5cf8e0555f..c36b4cadab039ef4100e296d973f08e8d2f30682 100644 (file)
@@ -29,6 +29,7 @@ X11_SUBDIRS += vmware-user-suid-wrapper
 
 SUBDIRS =
 SUBDIRS += lib
+SUBDIRS += libvmtools
 SUBDIRS += guestd
 if HAVE_X11
    SUBDIRS += $(X11_SUBDIRS)
@@ -39,7 +40,7 @@ if BUILD_HGFSMOUNTER
 endif
 SUBDIRS += checkvm
 SUBDIRS += libguestlib
-SUBDIRS += libvmtools
+SUBDIRS += rpctool
 SUBDIRS += scripts
 SUBDIRS += services
 SUBDIRS += toolbox
index 822016ee8aec8625a647ec7b0cbe55f1ff5e7aff..345b84fd26944215175c08fb55f669e0fb0fbcdd 100644 (file)
@@ -1,3 +1,17 @@
+open-vm-tools 2009.03.18 changes:
+       * Mostly a bug fix release.
+
+       * Solaris vmxnet3 driver was added; open-vm-tools now should also compile on
+       OpenSolaris (tested on 08.11), as long as the --without-gtkmm option is used.
+
+       * The new DnD V3 protocol is now available in open-vm-tools.
+
+       * Added "rpctool", a simple, stand-alone tool to send RPC commands to the
+       host software.
+
+       * vmtoolsd is now preferred in lieu of vmware-guestd; vmware-guestd will
+       most probably be completely removed in the next release.
+
 open-vm-tools 2009.02.18 changes:
        * open-vm-tools now depend on glib 2.6.0 as a minimum requirement.
 
index c4e841b072cbec4ffbde2141711f0cc1b7f29928..825c8b2fff2442ee210eb0e0dbf2ce4dfcfe587e 100644 (file)
@@ -28,7 +28,7 @@
 #  RPCGENFLAGS: extra flags to pass to rpcgen
 #
 # The following libraries are currently tested: DNET, FUSE, GLIB2, GMODULE,
-# GOBJECT, GTHREAD, GTK, GTKMM, LIBPNG, PROCPS, URIPARSER, ZLIB
+# GOBJECT, GTHREAD, GTK, GTKMM, ICU, LIBPNG, PROCPS, URIPARSER, ZLIB
 ################################################################################
 
 ###
@@ -37,7 +37,7 @@
 
 AC_INIT(
    [open-vm-tools],
-   [2009.02.18-148847],
+   [2009.03.18],
    [open-vm-tools-devel@lists.sourceforge.net])
 
 # In order to make this configure script auto-detect situations where
@@ -133,12 +133,25 @@ case "$host_os" in
       ;;
 esac
 osVersion="`getOsVersion`"
-if test "$os" = "linux"; then
-   if test "$with_kernel_modules" = "yes"; then
-      if test ! -d "$LINUXDIR/kernel/"; then
-        AC_MSG_ERROR([$LINUXDIR/kernel does not exist])
-      fi
-   fi
+
+if test "$with_kernel_modules" = "yes"; then
+   case "$os" in
+      linux)
+         if test ! -d "$LINUXDIR/kernel/"; then
+             AC_MSG_ERROR([$LINUXDIR/kernel does not exist])
+         fi
+         ;;
+
+      freebsd)
+         freebsd_sysdir=/usr/src/sys
+         if test -n "$SYSDIR"; then
+            freebsd_sysdir="$SYSDIR"
+         fi
+         if test ! -f "$freebsd_sysdir/conf/kmod.mk"; then
+            AC_MSG_ERROR([FreeBSD kernel tree not found. Please install the kernel sources (or provide the location using SYSDIR) or configure using --without-kernel-modules.])
+         fi
+         ;;
+   esac
 fi
 
 # Arguments for disabling individual open-vm-tools features or libraries.
@@ -196,7 +209,7 @@ AM_INIT_AUTOMAKE
 # CPPFLAGS is intended for preprocessor options (-D and -I mainly)
 # CFLAGS is intended for compiler options (-O, -f, -W, and so forth)
 
-CPPFLAGS="$CPPFLAGS -DUSING_AUTOCONF=1"
+CPPFLAGS="$CPPFLAGS -DUSING_AUTOCONF=1 -DOPEN_VM_TOOLS"
 
 ###
 ### Programs
@@ -873,6 +886,13 @@ if test "$os" = "freebsd"; then
       MODULES="$MODULES vmblock vmhgfs"
       buildHgfsmounter=yes
    fi
+
+   if test "$with_kernel_modules" = "yes"; then
+      echo "****************************************************************"
+      echo "   You are building FreeBSD kernel modules. Make sure you use   "
+      echo "   'make' to build open-vm-tools, and not GNU make ('gmake').   "
+      echo "****************************************************************"
+   fi
 fi
 
 if test "$os" = "solaris"; then
@@ -890,9 +910,22 @@ if test "$os" = "solaris"; then
    VMWARE_USER_LDADD="$VMWARE_USER_LDADD -lnsl"
    VMWARE_USER_LDADD="$VMWARE_USER_LDADD -lrpcsvc"
 
-   # uname -r on Solaris 10 reports "5.10"
-   if test "$osVersion" -ge 510000; then
+   # Setup defines to identify the OS version.
+   if test "$osVersion" -eq 509000; then
+      CPPFLAGS="$CPPFLAGS -DSOL9"
+   fi
+   if test "$osVersion" -eq 510000; then
       CPPFLAGS="$CPPFLAGS -DSOL10"
+   fi
+   if test "$osVersion" -eq 511000; then
+      CPPFLAGS="$CPPFLAGS -DSOL11"
+   fi
+
+   # Choose which modules to compile
+   if test "$osVersion" -eq 510000; then
+      MODULES="$MODULES vmblock"
+   fi
+   if test "$osVersion" -ge 510000; then
       MODULES="$MODULES vmhgfs"
    fi
 
@@ -900,12 +933,28 @@ if test "$os" = "solaris"; then
    if test "$osVersion" -lt 511000 -a "$osVersion" -ge 509000; then
       MODULES="$MODULES vmxnet"
    fi
+
+   # Vmxnet3 is built on Solaris 10 only and only if GLDv3 is installed
+   if test "$osVersion" -eq 510000; then
+      AC_CHECK_HEADER(
+         [sys/mac.h],
+         [MODULES="$MODULES vmxnet3"],
+         [AC_MSG_WARN([GLDv3 (sys/mac.h) is not installed, vmxnet3 will not be compiled.])])
+   fi
+
+   if test "$with_kernel_modules" = "yes"; then
+      echo "****************************************************************"
+      echo "   You are building Solaris kernel modules. Make sure you use   "
+      echo "   GNU make to build open-vm-tools.                             "
+      echo "****************************************************************"
+   fi
 fi
 
 AM_CONDITIONAL(BUILD_HGFSMOUNTER, test "$buildHgfsmounter" = "yes")
 AM_CONDITIONAL(LINUX, test "$os" = "linux")
 AM_CONDITIONAL(SOLARIS, test "$os" = "solaris")
 AM_CONDITIONAL(FREEBSD, test "$os" = "freebsd")
+AM_CONDITIONAL(FREEBSD_CUSTOM_SYSDIR, test "$os" = "freebsd" -a -n "$SYSDIR")
 AM_CONDITIONAL(THIRTY_TWO_BIT_USERSPACE, test "$userSpaceBitness" = "32")
 AM_CONDITIONAL(HAVE_X11, test "$have_x" = "yes")
 AM_CONDITIONAL(HAVE_ICU, test "$with_icu" = "yes")
@@ -1008,6 +1057,12 @@ AC_SUBST([RPCGENFLAGS])
 AC_SUBST([XDR_LIBS])
 AC_SUBST([VMSVC_PLUGIN_INSTALLDIR])
 AC_SUBST([VMUSR_PLUGIN_INSTALLDIR])
+if test "$os" = "freebsd" -a -n "$SYSDIR"; then
+   # If SYSDIR is not defined, AC_SUBST expands to nothing, so we need something
+   # inside this block.
+   true
+   AC_SUBST([SYSDIR])
+fi
 
 ### Lib substs
 
@@ -1082,7 +1137,6 @@ AC_CONFIG_FILES([                      \
    lib/sync/Makefile                   \
    lib/syncDriver/Makefile             \
    lib/system/Makefile                 \
-   lib/toolsLogger/Makefile            \
    lib/unicode/Makefile                \
    lib/unity/Makefile                  \
    lib/unityStub/Makefile              \
@@ -1111,6 +1165,7 @@ AC_CONFIG_FILES([                      \
    hgfsclient/Makefile                 \
    hgfsmounter/Makefile                \
    checkvm/Makefile                    \
+   rpctool/Makefile                    \
    libguestlib/Makefile                \
    libvmtools/Makefile                 \
    xferlogs/Makefile                   \
index 23e7f4f1a27cceab5ab8306a241dd628f0d67f25..9ab7badc35a08931df1aec992462091b4f6f2f36 100644 (file)
@@ -16,7 +16,6 @@
 ################################################################################
 
 sbin_PROGRAMS = vmware-guestd
-pamdir = $(PAM_PREFIX)/pam.d
 
 AM_CFLAGS = -I$(top_builddir)/include
 AM_CFLAGS += -I$(top_srcdir)/services/plugins/vix
@@ -93,19 +92,3 @@ else
    vmware_guestd_LINK = $(LINK)
 endif
 
-if LINUX
-if PAMD
-if THIRTY_TWO_BIT_USERSPACE
-pam_SCRIPTS = ../scripts/linux/pam.d/vmware-guestd
-else
-pam_SCRIPTS = ../scripts/linux/pam.d/vmware-guestd-x64
-endif !THIRTY_TWO_BIT_USERSPACE
-endif PAMD
-endif LINUX
-
-install-exec-hook:
-       $(INSTALL) -d $(DESTDIR)/etc/vmware-tools
-       echo 'disable-tools-version = "true"' > $(DESTDIR)/etc/vmware-tools/tools.conf
-
-uninstall-hook:
-       rm -rf $(DESTDIR)/etc/vmware-tools
index fba65fb3ca6017e4f4444aca8657976d8a4ff444..6ea2b83f8e72c94f96ed8dd6e7d072e8832b2e73 100644 (file)
 #   include "miscSolaris.h"
 #endif
 
-/* XXX Refactor this.  Push VM_GUESTD_MOUNTS_HGFS to whomever builds this file. */
-#if defined(sun)
-#   define VM_GUESTD_MOUNTS_HGFS 1
-#   define VM_GUESTD_RUNS_HGFS_PSERVER 1
-#endif
-
-
-/* Headers needed by the hgfs pserver */
-#if defined(VM_GUESTD_MOUNTS_HGFS)
-#   if defined(sun)
-#      include <sys/param.h>
-#      include <sys/mount.h>
-#      include <sys/stat.h>
-#      include <fcntl.h>
-#   endif
-#endif
-#if defined(VM_GUESTD_RUNS_HGFS_PSERVER)
-#   include "hgfsDevLinux.h"
-#   include "hgfsBd.h"
-#   include "hgfsProto.h"
-#   include "hgfs.h"
-#endif
 #include "procMgr.h"
 #include "guestd_version.h"
 
@@ -109,21 +87,6 @@ VM_EMBED_VERSION(GUESTD_VERSION_STRING);
 #define EXEC_LOG                    "/var/log/vmware-tools-guestd"
 #define UPGRADER_FILENAME           "vmware-tools-upgrader"
 
-#if defined(VM_GUESTD_MOUNTS_HGFS)
- /*
-  * The Hgfs device is in /dev.  Solaris' umount program doesn't
-  * unmount filesystem's with name's longer than 8 characters, so we shorten
-  * it.  Solaris' mount(2) doesn't take NULL as the mount source, so we
-  * specify anything to get past the Kernel's VFS mount function.  We also
-  * need to specify MS_DATA so it looks for the optional data we pass in.
-  */
-#   define HGFS_FS_NAME           "vmhgfs"
-#   define HGFS_MOUNT_SRC         "/hgfs"
-#   if defined(sun)
-#      define HGFS_DEVICE            "/dev/vmware-hgfs"
-#      define HGFS_MOUNT_FLAGS       MS_DATA                   /* from <sys/mount.h> */
-#   endif
-#endif
 
 /*
  * All signals that:
@@ -152,442 +115,6 @@ static int const cSignals[] = {
 static int gDaemonSignal;
 static int gCommandLineRpciSignal;
 
-#ifdef VM_GUESTD_MOUNTS_HGFS
-typedef struct HgfsMountState {
-   const char *mountPoint; /* Mount point for hgfs filesystem */
-   Bool mounted;           /* TRUE if mounted, FALSE if not */
-} HgfsMountState;
-#endif
-
-#ifdef VM_GUESTD_RUNS_HGFS_PSERVER
-/* Hgfs state needed per mounted filesystem */
-typedef struct PserverState {
-   HgfsMountState mountState;
-   char *requestPacket;    /* Buffer for request packets */
-   RpcOut *out;            /* Backdoor communications channel */
-   int fd;                 /* Hgfs device fd (communication with kernel) */
-} PserverState;
-
-static PserverState globalHgfsState = {
-   {NULL, FALSE},  /* mountState */
-   NULL,           /* requestPacket */
-   NULL,           /* out */
-   -1              /* fd */
-};
-#elif defined(VM_GUESTD_MOUNTS_HGFS)
-static HgfsMountState globalHgfsState = {
-   NULL, /* mountPoint */
-   FALSE /* mounted */
-};
-#endif
-
-#ifdef VM_GUESTD_MOUNTS_HGFS
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsMountState_Cleanup --
- *
- *      Unmounts the hgfs filesystem
- *
- * Results:
- *      TRUE on success.
- *      FALSE if one or more steps failed.
- *
- * Side effects:
- *      Unmounts the filesystem and cleans up the HgfsMountState structure.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsMountState_Cleanup(HgfsMountState *state) // IN: Hgfs mount state
-{
-   Bool success = TRUE;
-   int result;
-
-   ASSERT(state);
-
-   /* Try to unmount hgfs */
-   if (state->mounted) {
-      Debug("HgfsMountState_Cleanup: attempting to unmount %s\n",
-            state->mountPoint);
-#if defined(sun)
-      result = umount(state->mountPoint);
-#endif
-      if (result < 0) {
-         int error = errno;
-         Debug("HgfsMountState_Cleanup: error %d (%s) unmounting filesystem\n",
-               error,
-               strerror(error));
-         success = FALSE;
-      } else {
-         state->mounted = FALSE;
-         Debug("HgfsMountState_Cleanup: unmount succeeded\n");
-      }
-   }
-   if (state->mountPoint) {
-      free((void *)state->mountPoint);
-      state->mountPoint = NULL;
-   }
-
-   return success;
-}
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsMountState_Init --
- *
- *      Mounts the hgfs filesystem
- *
- * Results:
- *      TRUE on success.
- *      FALSE if one or more steps failed.
- *
- * Side effects:
- *      Allocates a copy of the mount point string, updates the HgfsMountState structure,
- *      and mounts the filesystem.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsMountState_Init(HgfsMountState *state,   // IN: Hgfs mount state
-                    const char *pMountPoint, // IN: Shared folder mount target
-                    int fd)                  // IN: Pserver file descriptor, or -1
-{
-   int mntRes;
-
-   ASSERT(state);
-   ASSERT(pMountPoint);
-
-   state->mountPoint = strdup(pMountPoint);
-   state->mounted = FALSE;
-
-#if defined(sun)
-   {
-      HgfsMountInfo mntInfo;   /* Data to pass to kernel when mounting */
-
-      mntInfo.fd = fd;
-      mntInfo.version = HGFS_PROTOCOL_VERSION;
-      mntInfo.magicNumber = HGFS_SUPER_MAGIC;
-
-      Debug("HgfsMountState_Init: trying to mount %s...\n", state->mountPoint);
-      mntRes = mount(HGFS_MOUNT_SRC, state->mountPoint, HGFS_MOUNT_FLAGS,
-                     HGFS_FS_NAME, &mntInfo, sizeof mntInfo);
-   }
-#endif
-
-   if (mntRes == -1) {
-      int error = errno;
-      Debug("HgfsMountState_Init: mount failed: %s\n", strerror(error));
-      HgfsMountState_Cleanup(state);
-      return FALSE;
-   }
-   state->mounted = TRUE;
-   Debug("HgfsMountState_Init: mount succeeded\n");
-
-   return TRUE;
-}
-#endif
-
-/*
- * Hgfs pserver functions
- */
-
-#ifdef VM_GUESTD_RUNS_HGFS_PSERVER
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPserver_Cleanup --
- *
- *    Teardown the communication channel with the server, unmount this
- *    hgfs filesystem, and close the driver proc file.
- *
- * Results:
- *    TRUE on success.
- *    FALSE if one or more steps failed.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsPserver_Cleanup(PserverState *state) // IN: State for this mount
-{
-   Bool success = TRUE;
-   int result;
-
-   ASSERT(state);
-
-   /* Try to close the backdoor */
-   if (!HgfsBd_CloseBackdoor(&state->out)) {
-      Debug("HgfsPserver_Cleanup: failed to close backdoor\n");
-      success = FALSE;
-   }
-   state->out = NULL;
-
-   /* Release the request packet buffer */
-   if (state->requestPacket) {
-      HgfsBd_PutBuf(state->requestPacket);
-      state->requestPacket = NULL;
-   }
-
-   /*
-    * XXX The unmount should be done in the driver (NOT here), in case
-    * the pserver gets killed or is misbehaved.
-    */
-   if (!HgfsMountState_Cleanup(&state->mountState)) {
-      success = FALSE;
-   }
-
-   /* Try to close the hgfs device */
-   if (state->fd >= 0) {
-      result = close(state->fd);
-      if (result < 0) {
-         int error = errno;
-         Debug("HgfsPserver_Cleanup: failed to close file: %s\n",
-               strerror(error));
-         success = FALSE;
-      }
-      state->fd = -1;
-   }
-
-   return success;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPserver_Init --
- *
- *    Set up pserver communication state.
- *
- *    Specifically: open the proc file, try to mount the filesystem,
- *    get a request packet buffer from the backdoor layer and open the
- *    backdoor communication channel.
- *
- * Results:
- *    TRUE on success
- *    FALSE on failure
- *
- * Side effects:
- *    None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsPserver_Init(PserverState *state,     // IN/OUT: State for this mount
-                 const char *pMountPoint) // IN: Shared folder mount target
-{
-   ASSERT(state);
-   ASSERT(pMountPoint);
-
-   state->fd = -1;
-   state->out = NULL;
-   state->requestPacket = NULL;
-
-   state->fd = open(HGFS_DEVICE, O_RDWR | O_NONBLOCK);
-   if (state->fd < 0) {
-      int error = errno;
-      Debug("HgfsPserver_Init: error opening proc file: %s\n",
-            strerror(error));
-      HgfsPserver_Cleanup(state);
-      return FALSE;
-   }
-
-   /*
-    * We need to make sure children of guestd do not inherit
-    * this file descriptor, otherwise they'll keep references to
-    * the hgfs module.
-    */
-   if ((fcntl(state->fd, F_SETFD, FD_CLOEXEC)) < 0) {
-      int error = errno;
-      Debug("HgfsPserver_Init: error setting proc file flags: %s\n",
-            strerror(error));
-      HgfsPserver_Cleanup(state);
-      return FALSE;
-   }
-
-   if (HgfsMountState_Init(&state->mountState, pMountPoint, state->fd) == FALSE) {
-      HgfsPserver_Cleanup(state);
-      return FALSE;
-   }
-
-   /*
-    * Eventually we may want to frob /etc/mtab here to reflect the
-    * mount.
-    */
-
-   state->requestPacket = HgfsBd_GetBuf();
-   if (!state->requestPacket) {
-      Debug("HgfsPserver_Init: couldn't get bd buffer\n");
-      HgfsPserver_Cleanup(state);
-      return FALSE;
-   }
-
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsPserverHandleRequest --
- *
- *      Read a request from the driver, send it to the server, and
- *      pass the reply back to the driver.
- *
- * Results:
- *      TRUE on success
- *      FALSE on failure
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsPserverHandleRequest(PserverState *pState) // IN: Pserver state
-{
-   char const *replyPacket; // Buffer returned by HgfsBd_Dispatch
-   size_t packetSize;
-   int error;
-   int n;
-
-   ASSERT(pState);
-
-   /* Get the request from the driver. */
-   n = read(pState->fd, pState->requestPacket, HGFS_PACKET_MAX);
-   if (n < 0) {
-      error = errno;
-      Debug("HgfsPserverHandleRequest: Read error from hgfs fd: %s\n",
-            strerror(error));
-      return FALSE;
-   }
-
-   packetSize = n;
-
-   /*
-    * Ensure the backdoor is open and then attempt to send the request across it
-    * to the hgfs server. 
-    *
-    * Failure of either action may indicate that Shared Folders have been disabled,
-    * in which case we send an error response to the fs module and clean up the
-    * backdoor (so that it might be re-opened with a subsequent request).
-    *
-    * If both actions succeed, the replyPacket will have a valid reply and the
-    * packetSize will be set to the size of the replyPacket contents.
-    */
-   if (!HgfsBd_OpenBackdoor(&pState->out) ||
-       (HgfsBd_Dispatch(pState->out,
-                        pState->requestPacket,
-                        &packetSize,
-                        &replyPacket) < 0)) {
-      HgfsRequest *request = (HgfsRequest *)pState->requestPacket;
-      HgfsReply errorReply;
-
-      Debug("HgfsPserverHandleRequest: Problem sending request across backdoor\n");
-
-      errorReply.id = request->id;
-      errorReply.status = HGFS_STATUS_PROTOCOL_ERROR;
-
-      n = write(pState->fd, &errorReply, sizeof errorReply);
-      if (n < 0) {
-         error = errno;
-         Debug("HgfsPserverHandleRequest: Problem writing error reply: %s\n",
-               strerror(error));
-      }
-
-      if (!HgfsBd_CloseBackdoor(&pState->out)) {
-         Debug("HgfsPserverHandleRequest: Problem closing backdoor\n");
-      }
-
-      return FALSE;
-   }
-
-   ASSERT(replyPacket);
-   ASSERT(packetSize);
-
-   /* Send reply to driver */
-   n = write(pState->fd, replyPacket, packetSize);
-   if (n < 0) {
-      error = errno;
-      Debug("HgfsPserverHandleRequest: Write error to file: %s\n", strerror(error));
-      return FALSE;
-   }
-
-   return TRUE;
-}
-#endif
-
-#if defined(VM_GUESTD_MOUNTS_HGFS)
-/*
- *-----------------------------------------------------------------------------
- *
- * GuestdGetValidMountPt --
- *
- *    Return returns the shared folder mount point from the configuration
- *    dictionary with trailing /'s removed.  The caller is responsible for
- *    freeing the returned string.
- *
- * Return value:
- *    NULL on failure (No entry in configuration dictionary or the entry
- *    consisted of 0 or more consecutive /'s.
- *    non-NULL on success (Pointer to valid name, with trailing /'s
- *    removed).
- *
- * Side effects:
- *    None
- *
- *-----------------------------------------------------------------------------
- */
-
-static const char *
-GuestdGetValidMountPt(GuestApp_Dict *Dict) // IN: Configuration dictionary
-{
-   const char *pMount = GuestApp_GetDictEntry(Dict, CONFNAME_MOUNT_POINT);
-   const char *end;
-   char *p;
-   int len;
-
-   if (!pMount) {
-      return NULL;
-   }
-
-   len = strlen(pMount);
-   if (len <= 0) {
-      return NULL;
-   }
-
-   for (end = &pMount[len - 1]; end > pMount; end--) {
-      if (*end != '/') {
-        break;
-      }
-   }
-   if (end == pMount) {
-      /*
-       * Pathological case string consisting of all /'s
-       */
-      return NULL;
-   }
-
-   /*
-    * end points to the last non-/ (and non-'\0') character in pMount.
-    */
-   p = strdup(pMount);
-   if (p) {
-      p[end - pMount + 1] = '\0';
-   }
-   return p;
-}
-#endif /* VM_GUESTD_MOUNTS_HGFS */
-
 
 /*
  *-----------------------------------------------------------------------------
@@ -873,9 +400,6 @@ GuestdSleep(uint64 numUsecs,                 // IN
 #endif
    struct timeval tv;
    int status;
-#if defined(VM_GUESTD_RUNS_HGFS_PSERVER)
-   PserverState *pState = &globalHgfsState;
-#endif
 
    ASSERT(tdData);
 
@@ -901,16 +425,6 @@ GuestdSleep(uint64 numUsecs,                 // IN
       maxFd = asyncFd;
    }
 
-#if defined(VM_GUESTD_RUNS_HGFS_PSERVER)
-   /* If hgfs is enabled, add its fd */
-   if (pState->fd >= 0) {
-      FD_SET(pState->fd, &readFds);
-      if (pState->fd > maxFd) {
-         maxFd = pState->fd;
-      }
-   }
-#endif
-
 #if !defined(__FreeBSD__) && !defined(sun) && !defined(__APPLE__)
    SocketMgr_GetSelectables(SOCKETMGR_IN,
                             &sockReadFds,
@@ -943,13 +457,6 @@ GuestdSleep(uint64 numUsecs,                 // IN
    } else if (status > 0) {
       Debug("Select returned status > 0\n");
 
-#ifdef VM_GUESTD_RUNS_HGFS_PSERVER
-      if (pState->fd >= 0 && FD_ISSET(pState->fd, &readFds)) {
-         /* There is an hgfs request waiting in the driver. */
-         HgfsPserverHandleRequest(pState);
-      }
-#endif
-
       if (curAsyncProc && FD_ISSET(asyncFd, &readFds)) {
          /* The async proc fd was written to */
 
@@ -1017,37 +524,6 @@ GuestdDaemon(GuestApp_Dict **pConfDict,       // IN/OUT
    ToolsDaemon_Data *data = NULL;
    VmBackupSyncProvider *syncProvider = NULL;
 
-#if VM_GUESTD_MOUNTS_HGFS
-   const char *mountPoint = GuestdGetValidMountPt(*pConfDict);
-
-   if (!mountPoint) {
-      Warning("Could not determine shared folder mount point, %s occurred.\n",
-             strerror(errno));
-   } else if (!Util_MakeSureDirExistsAndAccessible(mountPoint, 0755)) {
-      Warning("Shared folder mount point %s is not an accessible directory.\n",
-             mountPoint);
-      /*
-       * free what GuestdGetValidMountPt allocated.
-       */
-      free((void *)mountPoint);
-      mountPoint = NULL;
-   } else {
-#   ifdef VM_GUESTD_RUNS_HGFS_PSERVER
-      /* Setup the hgfs pserver (guest can operate on host file name space) */
-      if (HgfsPserver_Init(&globalHgfsState, mountPoint) == FALSE) {
-        Warning("Unable to start hgfs.\n");
-      }
-#   else
-      /* Just mount the hgfs filesystem */
-      if (HgfsMountState_Init(&globalHgfsState, mountPoint, -1) == FALSE) {
-         Warning("Unable to mount hgfs.\n");
-      }
-#   endif
-
-      free((void *)mountPoint);
-   }
-#endif
-
    data = ToolsDaemon_Init(pConfDict, EXEC_LOG,
                            GuestdExecuteHalt, pConfDict,
                            GuestdExecuteReboot, pConfDict,
@@ -1083,7 +559,7 @@ GuestdDaemon(GuestApp_Dict **pConfDict,       // IN/OUT
    syncProvider = VmBackup_NewSyncDriverProvider();
    if (syncProvider != NULL) {
       Bool loggingEnabled = GuestApp_GetDictEntryBool(*pConfDict, CONFNAME_LOG);
-      VmBackup_Init(data->in, ToolsDaemonEventQueue, syncProvider, 
+      VmBackup_Init(data->in, ToolsDaemonEventQueue, syncProvider,
                     loggingEnabled);
    } else {
       Debug("No vmBackup implementation available!\n");
@@ -1137,11 +613,7 @@ out:
    if (guestInfoEnabled) {
       GuestInfoServer_Cleanup();
    }
-#if defined(VM_GUESTD_RUNS_HGFS_PSERVER)
-   HgfsPserver_Cleanup(&globalHgfsState);
-#elif defined(VM_GUESTD_MOUNTS_HGFS)
-   HgfsMountState_Cleanup(&globalHgfsState);
-#endif
+
    if (syncProvider != NULL) {
       VmBackup_Shutdown(data->in);
    }
@@ -1241,23 +713,23 @@ GuestdAlreadyRunning(char const *pidFileName) // IN
 
       /*
        * XXX There is an assumption that if the process with pid is alive,
-       * the process is just guestd. Actually the process name should be 
-       * also checked because it is possible that there is another process 
+       * the process is just guestd. Actually the process name should be
+       * also checked because it is possible that there is another process
        * with same pid. 2 reasons it is not checked. First we can not find
        * a cross-platform method to check the process name. Second is that
        * the possibility is very low in our case because the PID file should
        * always be with guestd process. Even user manually kills the guestd,
-       * the PID file will also be removed. Perhaps longer term we should 
-       * add a function like System_GetProcessName(pid_t) to 
-       * bora-vmsoft/lib/system that will hide the platform-specific 
-       * messiness. 
+       * the PID file will also be removed. Perhaps longer term we should
+       * add a function like System_GetProcessName(pid_t) to
+       * bora-vmsoft/lib/system that will hide the platform-specific
+       * messiness.
        */
-      if (pid != getpid() && kill(pid, 0) == 0) {  
+      if (pid != getpid() && kill(pid, 0) == 0) {
          return TRUE;
       }
       /*
        * If process with pid is dead, the PID file will be removed. If pid
-       * is same as getpid(), PID file will also be removed. 
+       * is same as getpid(), PID file will also be removed.
        */
       unlink(pidFileName);
    }
index 90d658d38524ae1d166a4c3c4204863d453de4ae..d1a2bab3c9923d189bdaf9e1da53bec650501545 100644 (file)
@@ -69,6 +69,7 @@ extern "C" {
 #include "foundryToolsDaemon.h"
 #include "util.h"
 #include "vmcheck.h"
+#include "guestInfo.h"
 
 #ifndef N_PLAT_NLM
 #include "vm_atomic.h"
@@ -921,7 +922,7 @@ ToolsDaemonTcloStateChange(char const **result,     // OUT
 
    for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
       if (strcmp(name, stateChangeCmdTable[i].tcloCmd) == 0) {
-         const char *script;
+         char *script;
          char *scriptCmd;
          unsigned int stateId;
 
@@ -935,13 +936,22 @@ ToolsDaemonTcloStateChange(char const **result,     // OUT
             return RpcIn_SetRetVals(result, resultLen, "", TRUE);
          }
 
-         script = GuestApp_GetDictEntry(*data->pConfDict,
-                                        stateChgConfNames[stateId]);
-         ASSERT(script);
+         script = Util_SafeStrdup(GuestApp_GetDictEntry(*data->pConfDict,
+                                                        stateChgConfNames[stateId]));
+         Debug("Script to execute is: %s\n", script);
          if (strlen(script) == 0) {
             ToolsDaemonStateChangeDone(TRUE, data);
             Debug("No script to run\n");
+            free(script);
             return RpcIn_SetRetVals(result, resultLen, "", TRUE);
+         } else if (!Util_IsAbsolutePath(script)) {
+            char *absScript;
+            char *installDir = GuestApp_GetInstallPath();
+            ASSERT_MEM_ALLOC(installDir);
+            absScript = Str_Asprintf(NULL, "%s%c%s", installDir, DIRSEPC, script);
+            ASSERT_MEM_ALLOC(absScript);
+            free(script);
+            script = absScript;
          }
 #ifdef N_PLAT_NLM
          procArgs = NULL;
@@ -983,10 +993,12 @@ ToolsDaemonTcloStateChange(char const **result,     // OUT
             goto startError;
          }
 
+         free(script);
          free(scriptCmd);
          return RpcIn_SetRetVals(result, resultLen, "", TRUE);
 
       startError:
+         free(script);
          free(scriptCmd);
          Debug("Error starting script\n");   
          return RpcIn_SetRetVals(result, resultLen, "Error starting script",
@@ -1031,6 +1043,7 @@ ToolsDaemonTcloCapReg(char const **result,     // OUT
    unsigned int minResolutionHeight;
 #endif
    ToolsDaemon_Data *data;
+   uint32 version;
 
    data = (ToolsDaemon_Data *)clientData;
    ASSERT(data);
@@ -1160,10 +1173,14 @@ ToolsDaemonTcloCapReg(char const **result,     // OUT
     * can override the Tools version such that the VMX treats the Tools as not
     * to be managed by the VMware platform.
     */
-   if (!RpcOut_sendOne(NULL, NULL, "tools.set.version %u",
-                       GuestApp_GetDictEntryBool(*data->pConfDict,
-                                                 CONFNAME_DISABLETOOLSVERSION) ?
-                       TOOLS_VERSION_UNMANAGED : TOOLS_VERSION_CURRENT)) {
+#if defined(OPEN_VM_TOOLS)
+   version = TOOLS_VERSION_UNMANAGED;
+#else
+   version = GuestApp_GetDictEntryBool(*data->pConfDict,
+                                       CONFNAME_DISABLETOOLSVERSION) ?
+               TOOLS_VERSION_UNMANAGED : TOOLS_VERSION_CURRENT;
+#endif
+   if (!RpcOut_sendOne(NULL, NULL, "tools.set.version %u", version)) {
       Debug("Daemon: Error setting tools version during 'Capabilities_Register'"
             "request.\n");
    }
@@ -1377,10 +1394,13 @@ ToolsDaemonTcloSetOption(char const **result,     // OUT
       if (ip == NULL) {
          RpcIn_SetRetVals(result, resultLen, "Error getting IP address of guest",
                           retVal = FALSE);
+         RpcOut_sendOne(NULL, NULL, "info-set guestinfo.ip %s",
+                        GUESTINFO_IP_UNKNOWN);
          goto exit;
       }
 
-      RpcOut_sendOne(NULL, NULL, "info-set guestinfo.ip %s", ip);
+      RpcOut_sendOne(NULL, NULL, "info-set guestinfo.ip %s",
+                     ip[0] == '\0' ? GUESTINFO_IP_UNKNOWN : ip);
       free(ip);
    } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERIOD) == 0) {
       uint32 period = atoi(value);
index f5b867ae44fb4e27c9fd55a5d4e90e0f2bd630f9..6f87a0f6bdb0ac869979f5291478a99ae892f9e8 100644 (file)
 bin_PROGRAMS = vmware-hgfsclient
 
 vmware_hgfsclient_LDADD =
-vmware_hgfsclient_LDADD += ../lib/conf/libConf.la
-vmware_hgfsclient_LDADD += ../lib/guestApp/libGuestApp.la
-vmware_hgfsclient_LDADD += ../lib/hgfs/libHgfs.la
 vmware_hgfsclient_LDADD += ../lib/hgfsBd/libHgfsBd.la
-vmware_hgfsclient_LDADD += ../lib/rpcOut/libRpcOut.la
-vmware_hgfsclient_LDADD += ../lib/string/libString.la
-vmware_hgfsclient_LDADD += ../lib/toolsLogger/libToolsLogger.la
-vmware_hgfsclient_LDADD += ../lib/vmCheck/libVmCheck.la
-vmware_hgfsclient_LDADD += ../lib/vmSignal/libVmSignal.la
-# In the absence of the linker options --start-group and --end-group (which can't
-# be put in LDADD), we need to bring the following libraries out of the alphebetical
-# order so their symbols are properly resolved.
-vmware_hgfsclient_LDADD += ../lib/backdoor/libBackdoor.la
-vmware_hgfsclient_LDADD += ../lib/dict/libDict.la
-vmware_hgfsclient_LDADD += ../lib/err/libErr.la
-vmware_hgfsclient_LDADD += ../lib/file/libFile.la
-vmware_hgfsclient_LDADD += ../lib/message/libMessage.la
-vmware_hgfsclient_LDADD += ../lib/rpcVmx/libRpcVmx.la
-vmware_hgfsclient_LDADD += ../lib/unicode/libUnicode.la
-vmware_hgfsclient_LDADD += ../lib/sync/libSync.la
-vmware_hgfsclient_LDADD += ../lib/misc/libMisc.la
-vmware_hgfsclient_LDADD += ../lib/stubs/libStubs.la
+vmware_hgfsclient_LDADD += @VMTOOLS_LIBS@
+
+vmware_hgfsclient_CPPFLAGS =
+vmware_hgfsclient_CPPFLAGS += @VMTOOLS_CPPFLAGS@
 
 vmware_hgfsclient_SOURCES =
 vmware_hgfsclient_SOURCES += hgfsclient.c
-vmware_hgfsclient_SOURCES += stub-user-util.c
 
 if HAVE_ICU
    vmware_hgfsclient_LDADD += @ICU_LIBS@
index b0c8c626d6eed1cf972091078af1f45f1b657e10..efc5fd2160d1e8ba281c759982095a01612355fd 100644 (file)
@@ -27,7 +27,6 @@
 #include "vmware.h"
 #include "guestApp.h"
 #include "vmcheck.h"
-#include "toolsLogger.h"
 #include "escBitvector.h"
 #include "hgfsEscape.h"
 #include "hgfs.h"
@@ -35,6 +34,7 @@
 #include "hgfsProto.h"
 #include "conf.h"
 #include "str.h"
+#include "vmtools.h"
 
 #include "hgfsclient_version.h"
 #include "embed_version.h"
@@ -48,7 +48,6 @@ VM_EMBED_VERSION(HGFSCLIENT_VERSION_STRING);
 
 RpcOut *gChannel = NULL;
 char *gPacketBuffer = NULL;
-static GuestApp_Dict *gConfDict = NULL;
 
 static Bool HgfsClient_Open(HgfsHandle *rootHandle);
 static HgfsFileName *HgfsClient_Read(HgfsHandle rootHandle,
@@ -59,124 +58,6 @@ static Bool HgfsClient_Init(void);
 static Bool HgfsClient_Cleanup(void);
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * Debug --
- *
- *    Debugging output. Useless to the end user.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void 
-Debug(const char *fmt, // IN: Duh
-      ...)             // IN: Variadic arguments to duh
-{
-#ifdef VMX86_DEVEL
-   va_list args;
-
-   va_start(args, fmt);
-   ToolsLogger_LogV(TOOLSLOG_TYPE_LOG, fmt, args);
-   va_end(args);
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Log --
- *
- *    Log something. Slightly more important than Debug, but less important
- *    than Warning.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void 
-Log(const char *fmt, // IN: Duh
-    ...)             // IN: Variadic arguments to duh
-{
-   va_list args;
-
-   va_start(args, fmt);
-   ToolsLogger_LogV(TOOLSLOG_TYPE_LOG, fmt, args);
-   va_end(args);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Warning --
- *
- *    Warn the user of something. Probably fairly important, but not as
- *    critical as Panic.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-Warning(const char *fmt, // IN: Duh
-        ...)             // IN: Variadic arguments to duh
-{
-   va_list args;
-
-   va_start(args, fmt);
-   ToolsLogger_LogV(TOOLSLOG_TYPE_WARNING, fmt, args);
-   va_end(args);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Panic --
- *
- *    Warn the user and quit the app. Something very bad must have happened.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-Panic(const char *fmt, // IN: Duh
-      ...)             // IN: Variadic arguments to duh
-{
-   va_list args;
-
-   va_start(args, fmt);
-   ToolsLogger_LogV(TOOLSLOG_TYPE_PANIC, fmt, args);
-   va_end(args);
-
-   exit(255);
-   NOT_REACHED();
-}
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -435,9 +316,20 @@ static Bool
 HgfsClient_Init(void)
 {
    Bool success = FALSE;
+   gchar *confFile;
+   GKeyFile *conf;
+
+   confFile = VMTools_GetToolsConfFile();
+   conf = VMTools_LoadConfig(confFile, G_KEY_FILE_NONE, FALSE);
 
-   gConfDict = Conf_Load();
-   ToolsLogger_Init("hgfsclient", gConfDict);
+   if (conf != NULL) {
+      VMTools_ConfigLogging(conf);
+      g_key_file_free(conf);
+      conf = NULL;
+   }
+
+   g_free(confFile);
+   confFile = NULL;
 
    if (!VmCheck_IsVirtualWorld()) {
       Warning("This application must be run in a Virtual Machine.\n");
@@ -501,10 +393,6 @@ HgfsClient_Cleanup(void)
          success = FALSE;
       }
    }
-   ToolsLogger_Cleanup();
-   if (gConfDict) {
-      GuestApp_FreeDict(gConfDict);
-   }
    return success;
 }
 
diff --git a/open-vm-tools/hgfsclient/stub-user-util.c b/open-vm-tools/hgfsclient/stub-user-util.c
deleted file mode 100644 (file)
index 76fddd7..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*********************************************************
- * Copyright (C) 2008 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.
- *
- *********************************************************/
-
-/*
- * stub-user-util.c --
- *
- *   Stubs for Util_* functions in lib/user.
- *
- */
-
-#if defined(_WIN32)
-#  include <windows.h>
-#endif
-
-#include <stdlib.h>
-#include "vm_assert.h"
-#include "util.h"
-
-void
-Util_Backtrace(int bugNr)
-{
-   NOT_IMPLEMENTED();
-}
-
-
-void
-Util_ExitProcessAbruptly(int code) // IN
-{
-#if defined(_WIN32)
-   TerminateProcess(GetCurrentProcess(),code);
-#else
-   exit(code);
-#endif
-}
-
-
-char *
-Util_ExpandString(const char *fileName)
-{
-   NOT_IMPLEMENTED();
-}
-
index 81bcdc48e0ec7946a8e3c970449ca488f413ff6b..d20d4b91a1adca4c6f9f65daa239e2f2f6027bce 100644 (file)
@@ -75,7 +75,6 @@ SUBDIRS += stubs
 SUBDIRS += sync
 SUBDIRS += syncDriver
 SUBDIRS += system
-SUBDIRS += toolsLogger
 SUBDIRS += unicode
 if ENABLE_UNITY
    SUBDIRS += unity
index b7139194dbac11c691b11bb0930d574fee87d88a..ace90bbc88181614d0b521545b923d25814df7d9 100644 (file)
@@ -689,7 +689,9 @@ AppUtil_AppIsSkippable(const char *appName)
       "python2.4",
       "python2.3",
       "python2.2",
-      "perl"
+      "perl",
+      "sh",
+      "bash",
    };
    char cbuf[PATH_MAX];
    int i;
index 3a9baedcc373ae5b818081526eb4fac1d49a60cd..91610e9f58a68ff5af64e268910a8b848b148ba9 100644 (file)
@@ -251,7 +251,7 @@ Auth_AuthenticateUser(const char *user,       //IN
       PAM_username = user;
       PAM_password = pass;
 #if defined(VMX86_TOOLS)
-      pam_error = dlpam_start("vmware-guestd", PAM_username, &PAM_conversation, &pamh);
+      pam_error = dlpam_start("vmtoolsd", PAM_username, &PAM_conversation, &pamh);
 #else
       pam_error = dlpam_start("vmware-authd", PAM_username, &PAM_conversation, &pamh);
 #endif
index f20cfae5e7484b3aa7effed177cc3b81ab72c6c8..39ac3ab1ce447cc886427852374354beaa739d5f 100644 (file)
@@ -1214,7 +1214,7 @@ File_CopyFromFdToFd(FileIODescriptor src,  // IN:
    FileIOResult fretR;
 
    do {
-      unsigned char buf[1024];
+      unsigned char buf[8 * 1024];
       size_t actual;
       FileIOResult fretW;
 
@@ -1293,6 +1293,11 @@ File_CopyFromFdToName(FileIODescriptor src,  // IN:
       result = FALSE;
    }
 
+   if (result == FALSE) {
+      /* The copy failed: ensure the destination file is removed */
+      File_Unlink(dstName);
+   }
+
    return result;
 }
 
@@ -1473,6 +1478,11 @@ File_CopyFromFd(FileIODescriptor src,     // IN:
       result = FALSE;
    }
 
+   if (result == FALSE) {
+      /* The copy failed: ensure the destination file is removed */
+      File_Unlink(dstName);
+   }
+
    return result;
 }
 
index 891b40b5dc3b13b6898b9ea060dab0ef1fa65285..1070c0fc6a339cca544bf740963c0dddd3733584 100644 (file)
@@ -164,14 +164,15 @@ FileRename(ConstUnicode oldName,  // IN:
  *----------------------------------------------------------------------
  *
  *  FileDeletion --
- *     Delete the specified file
+ *          Delete the specified file.  A NULL pathName will result in an error
+ *          and errno will be set to EFAULT.
  *
  * Results:
  *     0       success
  *     > 0     failure (errno)
  *
  * Side effects:
- *      May change the host file system.
+ *      May change the host file system.  errno may be set.
  *
  *----------------------------------------------------------------------
  */
@@ -182,13 +183,17 @@ FileDeletion(ConstUnicode pathName,   // IN:
 {
    int err;
    char *linkPath = NULL;
-   char *primaryPath = Unicode_GetAllocBytes(pathName,
-                                             STRING_ENCODING_DEFAULT);
+   char *primaryPath;
 
-   if (primaryPath == NULL && pathName != NULL) {
+   if (pathName == NULL) {
+      errno = EFAULT;
+      return errno;
+   } else if ((primaryPath = Unicode_GetAllocBytes(pathName,
+                               STRING_ENCODING_DEFAULT)) == NULL) {
       Log(LGPFX" %s: failed to convert \"%s\" to current encoding\n",
           __FUNCTION__, UTF8(pathName));
-      return UNICODE_CONVERSION_ERRNO;
+      errno = UNICODE_CONVERSION_ERRNO;
+      return errno;
    }
 
    if (handleLink) {
@@ -1799,13 +1804,14 @@ File_IsSameFile(ConstUnicode path1,  // IN:
  * File_Replace --
  *
  *      Replace old file with new file, and attempt to reproduce
- *      file permissions.
+ *      file permissions.  A NULL value for either the oldName or
+ *      newName will result in failure and errno will be set to EFAULT.
  *
  * Results:
  *      TRUE on success.
  *
  * Side effects:
- *      None.
+ *      errno may be set.
  *
  *-----------------------------------------------------------------------------
  */
@@ -1820,16 +1826,22 @@ File_Replace(ConstUnicode oldName,  // IN: old file
    char *oldPath = NULL;
    struct stat st;
 
-   newPath = Unicode_GetAllocBytes(newName, STRING_ENCODING_DEFAULT);
-   if (newPath == NULL && newName != NULL) {
+   if (newName == NULL) {
+      status = EFAULT;
+      goto bail;
+   } else if ((newPath = Unicode_GetAllocBytes(newName,
+                           STRING_ENCODING_DEFAULT)) == NULL) {
       status = UNICODE_CONVERSION_ERRNO;
       Msg_Append(MSGID(filePosix.replaceConversionFailed)
                  "Failed to convert file path \"%s\" to current encoding\n",
                  newName);
       goto bail;
    }
-   oldPath = Unicode_GetAllocBytes(oldName, STRING_ENCODING_DEFAULT);
-   if (oldPath == NULL && oldName != NULL) {
+   if (oldName == NULL) {
+      status = EFAULT;
+      goto bail;
+   } else if ((oldPath = Unicode_GetAllocBytes(oldName,
+                           STRING_ENCODING_DEFAULT)) == NULL) {
       status = UNICODE_CONVERSION_ERRNO;
       Msg_Append(MSGID(filePosix.replaceConversionFailed)
                  "Failed to convert file path \"%s\" to current encoding\n",
index 928b1bdcfb28f810ef931f7a9026a1540502935d..1851341b5882992b6fa190c024ef430dc6d2bf5e 100644 (file)
@@ -356,14 +356,12 @@ static const VixCommandInfo vixCommandInfoTable[] = {
                            VIX_COMMAND_CATEGORY_PRIVILEGED),
    VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_HOT_REMOVE_DEVICE,
                            VIX_COMMAND_CATEGORY_PRIVILEGED),
-   
-   /* The debugger stuff is also only available through VIX. */
    VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DEBUGGER_ATTACH,
-                           VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
+                           VIX_COMMAND_CATEGORY_PRIVILEGED),
    VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DEBUGGER_DETACH,
-                           VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
+                           VIX_COMMAND_CATEGORY_PRIVILEGED),
    VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_DEBUGGER_SEND_COMMAND,
-                           VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
+                           VIX_COMMAND_CATEGORY_PRIVILEGED),
 
    VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GET_RECORD_STATE,
                            VIX_COMMAND_CATEGORY_PRIVILEGED),
index 695918362176977b3b01acaf9ffde36416047bec..a1c87c184f79bcaf8da10e88de4f8c88858366cd 100644 (file)
@@ -81,6 +81,11 @@ static Bool GHITcloShellAction(char const **result,
 static Bool GHITcloSetGuestHandler(RpcInData *data);
 static Bool GHITcloRestoreDefaultGuestHandler(RpcInData *data);
 
+/*
+ * Wrapper function for the "ghi.guest.outlook.set.tempFolder" RPC.
+ */
+static Bool GHITcloSetOutlookTempFolder(RpcInData* data);
+
 static Bool GHIUpdateHost(GHIProtocolHandlerList *handlers);
 
 DynBuf gTcloUpdate;
@@ -258,6 +263,8 @@ GHI_InitBackdoor(struct RpcIn *rpcIn)   // IN
                                GHITcloSetGuestHandler, NULL);
       RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_RESTORE_DEFAULT_GUEST_HANDLER,
                                GHITcloRestoreDefaultGuestHandler, NULL);
+      RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_OUTLOOK_SET_TEMP_FOLDER,
+                               GHITcloSetOutlookTempFolder, NULL);
    }
 }
 
@@ -965,3 +972,76 @@ GHIUpdateHost(GHIProtocolHandlerList *handlers) // IN: type specific information
    }
    return status;
 }
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * GHITcloSetOutlookTempFolder --
+ *
+ *    Handler for the 'ghi.guest.outlook.set.tempFolder' RPC.
+ *
+ * Results:
+ *    If the RPC fails, return FALSE. Otherwise, returns TRUE.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+GHITcloSetOutlookTempFolder(RpcInData *data) // IN/OUT: RPC data
+{
+   Bool ret = FALSE;
+   XDR xdrs;
+
+   Debug("%s: Enter.\n", __FUNCTION__);
+
+   // Check our arguments.
+   ASSERT(data);
+   ASSERT(data->name);
+   ASSERT(data->argsSize > 0);
+
+   if (!(data && data->name && data->argsSize > 0)) {
+      Debug("%s: Invalid arguments.\n", __FUNCTION__);
+      goto exit;
+   }
+
+   Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
+         __FUNCTION__, data->name, data->argsSize);
+
+   /*
+    * Build an XDR Stream from the argument data.
+    *
+    * Note that the argument data begins with args + 1 since there is a space
+    * between the RPC name and the XDR serialization.
+    */
+   xdrmem_create(&xdrs, (char*) data->args + 1, data->argsSize - 1, XDR_DECODE);
+
+   // Call the platform implementation of our RPC.
+   ret = GHIPlatformSetOutlookTempFolder(ghiPlatformData, &xdrs);
+
+   // Destroy the XDR stream.
+   xdr_destroy(&xdrs);
+
+   if (ret == FALSE) {
+      Debug("%s: Failed to set Outlook temporary folder.\n", __FUNCTION__);
+      RPCIN_SETRETVALS(data, "Failed to set Outlook temporary folder", FALSE);
+      goto exit;
+   }
+
+   /*
+    * We don't have any out parameters, so we write empty values into the
+    * result fields of the RpcInData structure.
+    */
+   RPCIN_SETRETVALS(data, "", FALSE);
+
+   // Set our return value and return to the caller.
+   ret = TRUE;
+
+exit:
+   Debug("%s: Exit.\n", __FUNCTION__);
+   return ret;
+}
+
index 0250e15bb3146fbbc8382bc77a4e4e65578a4e30..b759a38c4fa2621e8c0fa1c5a2bb2bb9d05060f7 100644 (file)
@@ -64,6 +64,12 @@ void GHIPlatformUnregisterCaps(GHIPlatform *ghip);
 Bool GHIPlatformGetProtocolHandlers(GHIPlatform *ghip,
                                     GHIProtocolHandlerList *protocolHandlerList);
 
+/*
+ * Set the temporary folder used by Outlook to store attachments.
+ */
+Bool GHIPlatformSetOutlookTempFolder(GHIPlatform* ghip, const XDR* xdrs);
+
+
 /* Implemented by ghIntegration.c for use by the platform-specific code */
 Bool GHILaunchMenuChangeRPC(void);
 
index a3fff9a6e0d2be231b35b19df06eb221ae904bab..7688d7963c232f1510cf96d890def6825d5cf777 100644 (file)
@@ -2799,3 +2799,35 @@ GHISetVMwareEnviron(GHIPlatform *ghip)   // IN
    g_hash_table_foreach(ghip->vmwareEnv, GHISetVMwareVariable, NULL);
    return TRUE;
 }
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * GHIPlatformSetOutlookTempFolder --
+ *
+ *    Set the temporary folder used by Microsoft Outlook to store attachments
+ *    opened by the user.
+ *
+ *    XXX While we probably won't ever need to implement this for Linux, we
+ *        still the definition of this function in the X11 back-end.
+ *
+ * Results:
+ *    TRUE if successful, FALSE otherwise.
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+GHIPlatformSetOutlookTempFolder(GHIPlatform *ghip,  // IN: platform-specific state
+                                const XDR *xdrs)    // IN: XDR Serialized arguments
+{
+   ASSERT(ghip);
+   ASSERT(xdrs);
+
+   return FALSE;
+}
+
index 07bfd7c4e42a1974830ce6559fea1df4f3656670..d239181a5d0aa3e0955e32966069c8b85fbff679 100644 (file)
@@ -68,10 +68,22 @@ enum GuestLibV3TypeIds {
 
    GUESTLIB_CPU_STOLEN_MS         = 19,
    GUESTLIB_MEM_TARGET_SIZE_MB    = 20,
+
+   /* Host specific counters. */
+   GUESTLIB_HOST_CPU_NUM_CORES    = 21,
+   GUESTLIB_HOST_CPU_USED_MS      = 22,
+   GUESTLIB_HOST_MEM_SWAPPED_MB   = 23,
+   GUESTLIB_HOST_MEM_SHARED_MB    = 24,
+   GUESTLIB_HOST_MEM_USED_MB      = 25,
+   GUESTLIB_HOST_MEM_PHYS_MB      = 26,
+   GUESTLIB_HOST_MEM_PHYS_FREE_MB = 27,
+   GUESTLIB_HOST_MEM_KERN_OVHD_MB = 28,
+   GUESTLIB_HOST_MEM_MAPPED_MB    = 29,
+   GUESTLIB_HOST_MEM_UNMAPPED_MB  = 30,
    /*------ Add any new statistics above this line. ------- */
 
    /*------ Bump this when adding to this list. -------*/
-   GUESTLIB_MAX_STATISTIC_ID      = 21
+   GUESTLIB_MAX_STATISTIC_ID      = 31
 };
 
 union GuestLibV3Stat switch (GuestLibV3TypeIds d) {
@@ -120,5 +132,26 @@ union GuestLibV3Stat switch (GuestLibV3TypeIds d) {
       struct GuestLibV3StatUint64 cpuStolenMs;
    case GUESTLIB_MEM_TARGET_SIZE_MB:
       struct GuestLibV3StatUint64 memTargetSizeMB;
+
+   case GUESTLIB_HOST_CPU_NUM_CORES:
+      struct GuestLibV3StatUint32 hostCpuNumCores;
+   case GUESTLIB_HOST_CPU_USED_MS:
+      struct GuestLibV3StatUint64 hostCpuUsedMs;
+   case GUESTLIB_HOST_MEM_SWAPPED_MB:
+      struct GuestLibV3StatUint64 hostMemSwappedMB;
+   case GUESTLIB_HOST_MEM_SHARED_MB:
+      struct GuestLibV3StatUint64 hostMemSharedMB;
+   case GUESTLIB_HOST_MEM_USED_MB:
+      struct GuestLibV3StatUint64 hostMemUsedMB;
+   case GUESTLIB_HOST_MEM_PHYS_MB:
+      struct GuestLibV3StatUint64 hostMemPhysMB;
+   case GUESTLIB_HOST_MEM_PHYS_FREE_MB:
+      struct GuestLibV3StatUint64 hostMemPhysFreeMB;
+   case GUESTLIB_HOST_MEM_KERN_OVHD_MB:
+      struct GuestLibV3StatUint64 hostMemKernOvhdMB;
+   case GUESTLIB_HOST_MEM_MAPPED_MB:
+      struct GuestLibV3StatUint64 hostMemMappedMB;
+   case GUESTLIB_HOST_MEM_UNMAPPED_MB:
+      struct GuestLibV3StatUint64 hostMemUnmappedMB;
 };
 
index 7161abd07f0cf973fb900ac3234d9156499b3791..95c5dd0b2bce2332b9e6bd90244b25a81bf8ba06 100644 (file)
@@ -1,12 +1,12 @@
 #define BUILD_NUMBER \
-       "build-148847"
+       "build-154848"
 #define BUILD_NUMBER_NUMERIC \
-       148847
+       154848
 #define BUILD_NUMBER_NUMERIC_STRING \
-       "148847"
+       "154848"
 #define PRODUCT_BUILD_NUMBER \
-       "product-build-472"
+       "product-build-495"
 #define PRODUCT_BUILD_NUMBER_NUMERIC \
-       472
+       495
 #define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \
-       "472"
+       "495"
index a87732b860a15ed9a6276a087b7fc3a473cf9e62..e325351b3647ea021ace89bc2a3f4ccc219a707c 100644 (file)
 
 #define CONFNAME_SHOW_WIRELESS_ICON "wirelessIcon.enable"
 
-/*
- * Directory containing Help files accessed via the Toolbox's "Help"
- * button.  For now, intended only for toolbox-gtk.
- */
-#if !defined(_WIN32) && !defined(N_PLAT_NLM)
-#   define CONFNAME_HELPDIR                        "helpdir"
-#endif
-
 /*
  * Directory containing the tools library files.  Currently only intended
  * for vmware-user.
index 565162ddcd2535f2c9878cb2aad62bf4c3914057..669ad07d280f12e90020c6561c25a139c7074c2c 100644 (file)
  *
  *********************************************************/
 
-/*
- * guestInfo.h --
+/**
+ * @file guestInfo.h
+ *
+ * Common declarations that aid in sending guest information to the host.
+ */
+
+/**
+ * @defgroup vmtools_guestInfoAPI GuestInfo API Reference
+ * @{
+ *
+ * @brief APIs implementing the GuestInfo feature.
  *
- *    Common declarations that aid in sending guest information to the host.
+ * Definitions below are used for communication across the backdoor between
+ * the VMware Tools Service (running in the guest) and the VMX (running in
+ * the host).
+ *
+ * @sa @ref vmtools_guestInfo for a high level overview.
  */
 
 #ifndef _GUEST_INFO_H_
@@ -32,7 +45,9 @@
 
 #include "dbllnklst.h"
 #include "guestStats.h"
+#ifndef N_PLAT_NLM
 #include "guestrpc/nicinfo.h"
+#endif // #ifndef N_PLAT_NLM
 
 #define GUEST_INFO_COMMAND "SetGuestInfo"
 #define MAX_VALUE_LEN 100
@@ -43,6 +58,9 @@
 #define PARTITION_NAME_SIZE MAX_VALUE_LEN
 #define GUESTINFO_TIME_INTERVAL_MSEC 3000  /* time interval in msec */
 
+/* Value to be used when "primary" IP address is indeterminable. */
+#define GUESTINFO_IP_UNKNOWN "unknown"
+
 typedef enum {
    INFO_ERROR,       /* Zero is unused so that errors in atoi can be caught. */
    INFO_DNS_NAME,
@@ -94,6 +112,7 @@ typedef struct _DiskInfo {
  * Global functions
  */
 
+#ifndef N_PLAT_NLM
 extern Bool GuestInfo_GetFqdn(int outBufLen, char fqdn[]);
 extern Bool GuestInfo_GetNicInfo(GuestNicList *nicInfo);
 extern Bool GuestInfo_GetDiskInfo(PGuestDiskInfo di);
@@ -101,6 +120,10 @@ extern Bool GuestInfo_GetOSName(unsigned int outBufFullLen,
                                 unsigned int outBufLen, char *osNameFull,
                                 char *osName);
 extern int GuestInfo_GetSystemBitness(void);
+#endif // #ifndef N_PLAT_NLM
 
-#endif // _GUEST_INFO_H_
+/**
+ * @}
+ */
 
+#endif // _GUEST_INFO_H_
index 5fe308c699531f068ce3b701158e000d8daab764..11523c3428accb979f2b3144ccd851ba47f29af5 100644 (file)
@@ -16,8 +16,8 @@
  *
  *********************************************************/
 
-/*
- * guestStats.h --
+/**
+ * @file guestStats.h
  *
  *    Common declarations that aid in sending guest statistics to the vmx
  *    and may be further to vmkernel.
 typedef
 #include "vmware_pack_begin.h"
 struct GuestMemInfo {
-   uint32 version;            /* MemInfo structure version. */
-   uint32 flags;              /* Indicates which stats are valid. */
-   uint64 memTotal;           /* Total physical memory in Kb. */
-   uint64 memFree;            /* Physical memory available in Kb. */
-   uint64 memBuff;            /* Physical memory used as buffer cache in Kb. */
-   uint64 memCache;           /* Physical memory used as cache in Kb. */
-   uint64 memActive;          /* Physical memory actively in use in Kb (working set) */
-   uint64 memInactive;        /* Physical memory inactive in Kb (cold pages) */
-   uint64 swapInRate;         /* Memory swapped out in Kb / sec. */
-   uint64 swapOutRate;        /* Memory swapped out in Kb / sec. */
-   uint64 ioInRate;           /* Amount of I/O in Kb / sec. */
-   uint64 ioOutRate;          /* Amount of I/O out in Kb / sec. */
-   uint64 hugePagesTotal;     /* Total number of huge pages. */
-   uint64 hugePagesFree;      /* Available number of huge pages. */
-   uint64 memPinned;          /* Unreclaimable physical memory in 4K page size. */
+   uint32 version;            ///< MemInfo structure version. 
+   uint32 flags;              ///< Indicates which stats are valid. 
+   uint64 memTotal;           ///< Total physical memory in Kb. 
+   uint64 memFree;            ///< Physical memory available in Kb. 
+   uint64 memBuff;            ///< Physical memory used as buffer cache in Kb. 
+   uint64 memCache;           ///< Physical memory used as cache in Kb. 
+   uint64 memActive;          ///< Physical memory actively in use in Kb (working set) 
+   uint64 memInactive;        ///< Physical memory inactive in Kb (cold pages) 
+   uint64 swapInRate;         ///< Memory swapped out in Kb / sec. 
+   uint64 swapOutRate;        ///< Memory swapped out in Kb / sec. 
+   uint64 ioInRate;           ///< Amount of I/O in Kb / sec. 
+   uint64 ioOutRate;          ///< Amount of I/O out in Kb / sec. 
+   uint64 hugePagesTotal;     ///< Total number of huge pages. 
+   uint64 hugePagesFree;      ///< Available number of huge pages. 
+   uint64 memPinned;          ///< Unreclaimable physical memory in 4K page size. 
 }
 #include "vmware_pack_end.h"
 GuestMemInfo;
index e87ad991090ef82bda286bb74dbfb5690edfcb15..980c125831b222c5700b62e0d5c6123873248d6f 100644 (file)
@@ -186,13 +186,17 @@ typedef enum GuestOSFamilyType {
 #define STR_OS_RED_HAT_EN_4_FULL "Red Hat Enterprise Linux 4"
 #define STR_OS_RED_HAT_FULL "Red Hat Linux"  
 #define STR_OS_SLACKWARE "Slackware"    
+#define STR_OS_SLES_10                  "sles10"
+#define STR_OS_SLES_10_FULL             "SUSE Linux Enterprise Server 10"
+#define STR_OS_SLES_11                  "sles11"
+#define STR_OS_SLES_11_FULL             "SUSE Linux Enterprise Server 11"
 #define STR_OS_SMESERVER "SMEServer"    
 #define STR_OS_SUN_DESK "sjds"    
 #define STR_OS_SUN_DESK_FULL "Sun Java Desktop System" 
 #define STR_OS_SUSE "suse"    
 #define STR_OS_SUSE_EN "sles"    
 #define STR_OS_SUSE_EN_FULL "SUSE Linux Enterprise Server" 
-#define STR_OS_SUSE_FULL "SUSE Linux"   
+#define STR_OS_SUSE_FULL "SUSE Linux"
 #define STR_OS_TINYSOFA "Tiny Sofa"   
 #define STR_OS_TURBO "turbolinux"    
 #define STR_OS_TURBO_FULL "Turbolinux"    
@@ -337,7 +341,7 @@ typedef enum GuestOSFamilyType {
 #define STR_OS_FREEBSD "FreeBSD"
 
 /* Solaris */
-#define STR_OS_SOLARIS "Solaris"
+#define STR_OS_SOLARIS "solaris"
 
 /* All */
 #define STR_OS_64BIT_SUFFIX "-64"
index f641683f48a865c7a03bdd59c8225b878f5dc80b..1c89ca8c454462986f7ae9dc5e4949a7b4675ae9 100644 (file)
@@ -85,6 +85,16 @@ extern Unicode Hostinfo_GetModulePath(uint32 priv);
 extern void Hostinfo_ResetProcessState(const int *keepFds, size_t numKeepFds);
 extern int Hostinfo_Execute(const char *command, char * const *args,
                            Bool wait);
+typedef enum HostinfoDaemonizeFlags {
+   HOSTINFO_DAEMONIZE_DEFAULT = 0,
+   HOSTINFO_DAEMONIZE_NOCHDIR = (1 << 0),
+   HOSTINFO_DAEMONIZE_NOCLOSE = (1 << 1),
+   HOSTINFO_DAEMONIZE_EXIT    = (1 << 2),
+} HostinfoDaemonizeFlags;
+extern Bool Hostinfo_Daemonize(const char *path,
+                               char * const *args,
+                               HostinfoDaemonizeFlags flags,
+                               const char *pidPath);
 #endif
 
 extern Unicode Hostinfo_GetUser(void);
index e8e81b1db9bbc1d05f2ebe7187af317b8f0aebbf..c9d709f52e56937d2e8a854609c9a41d5e72ad5d 100644 (file)
@@ -48,7 +48,8 @@ typedef struct
 EXTERN void Log_GetInitDefaults(const char *fileName, const char *config,
                                 const char *suffix, LogInitParams *params);
 
-EXTERN Bool Log_Init(const char *fileName, const char *config, const char *suffix);
+EXTERN Bool Log_Init(const char *fileName, const char *config,
+                     const char *suffix);
 EXTERN Bool Log_InitForApp(const char *fileName, const char *config,
                            const char *suffix, const char *appName,
                            const char *appVersion);
index 63192d4edca97860e18421113513f7bebab0a052..172609a8590ed4944adefdaeee65e4eed541f6c5 100644 (file)
@@ -88,6 +88,7 @@
    LOGLEVEL_VAR(vmxnet3), \
    LOGLEVEL_VAR(pci_vmxnet3), \
    LOGLEVEL_VAR(vcpuhotplug), \
+   LOGLEVEL_VAR(heci), \
    \
    /* user/disk */ \
    LOGLEVEL_VAR(aioMgr), \
    LOGLEVEL_VAR(migrateVM), \
    LOGLEVEL_VAR(vmUpsellController), \
    LOGLEVEL_VAR(objc), /* lib/objc */ \
+   LOGLEVEL_VAR(blit), /* lib/blit */ \
+   LOGLEVEL_VAR(vmnetBridge), \
 
 LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER);
 
index 809c539683cf90d7fce606a5463bceb4f031ee74..fcff0c1b87b223818f7414541b0bdfd4eae1076c 100644 (file)
@@ -73,6 +73,16 @@ typedef void *          InitHandle;
 #   error Unknown display backend
 #endif
 
+/*
+ * Arguments to VMwareResolutionSet.exe
+ */
+#define RESOLUTION_SET_APP_NAME "VMwareResolutionSet.exe"
+typedef enum {
+   RESOLUTION_SET_NORESET   = 0,
+   RESOLUTION_SET_RESET     = 1,
+   RESOLUTION_SET_ARBITRARY = 2,
+} ResolutionSetDisplayReset;
+
 
 /*
  * Global functions
index 322753a6d623dc92e865d497856ccb1300b0e524..41bc91beb31efb4555f29d1578b0c64ab709de31 100644 (file)
@@ -37,7 +37,7 @@
 #elif __APPLE__
 #include <stdlib.h>
 #endif
-#include <stdarg.h>
+#include "compat/compat_stdarg.h" // Provides stdarg.h plus va_copy
 
 #include "vm_basic_types.h"
 
diff --git a/open-vm-tools/lib/include/toolsLogger.h b/open-vm-tools/lib/include/toolsLogger.h
deleted file mode 100644 (file)
index 9545c24..0000000
+++ /dev/null
@@ -1,86 +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 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.
- *
- *********************************************************/
-
-/*
- * toolsLogger.h --
- *
- *    All-purpose logging facility. The API is not intended to be
- *    called from the application code. Instead the application
- *    should re-implement DLWP with ToolsLogger_Log() (before, they
- *    use printf()/fprintf()/OutputDebugString()).
- *
- *    A sample:
- *
- *    #include "toolsLogger.h"
- *
- *    GuestApp_Dict *confDict = Conf_Load();
- *
- *    ToolsLogger_Init(progName, confDict);
- *
- *    Log("a log msg") // == ToolsLogger_Log(TOOLSLOG_TYPE_LOG, "a log msg");
- *    Warning("a warning msg"); // == ToolsLogger_Log(TOOLSLOG_TYPE_WARNING, 
- *                              //       "a warning msg");
- * 
- *    Panic("a panic msg");     // == ToolsLogger_Log(TOOLSLOG_TYPE_PANIC,
- *                              //       "a panic msg"); exit(1);
- *
- *    ToolsLogger_Cleanup();
- */
-
-
-#ifndef __TOOLSLOGGER_H__
-#   define __TOOLSLOGGER_H__
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdarg.h>
-
-/*
- * Log types
- */
-typedef enum {
-   TOOLSLOG_TYPE_PANIC,
-   TOOLSLOG_TYPE_WARNING,
-   TOOLSLOG_TYPE_LOG,
-   
-   TOOLSLOG_TYPE_LAST       /* Must be the last one */
-} ToolsLogType;
-
-
-Bool ToolsLogger_Init(const char *progName, GuestApp_Dict *conf);
-void ToolsLogger_Log(ToolsLogType type, 
-                     const char *fmt, 
-                     ...);
-
-void ToolsLogger_LogV(ToolsLogType type,
-                      const char *fmt,
-                      va_list args);
-
-void ToolsLogger_Cleanup(void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* __TOOLSLOGGER_H__ */
index 4ded269a57e659457ea3c3b852d8de6819ee01c6..df703b09ac8fda649a1020b2e1f5a992e29eeef0 100644 (file)
@@ -177,8 +177,8 @@ void Unicode_Free(Unicode str);
 Unicode *Unicode_AllocList(char **srcList, ssize_t length,
                            StringEncoding encoding);
 
-Unicode *Unicode_GetAllocList(Unicode const srcList[], ssize_t length, 
-                              StringEncoding encoding);
+char **Unicode_GetAllocList(Unicode const srcList[], ssize_t length,
+                            StringEncoding encoding);
 
 /*
  *-----------------------------------------------------------------------------
index 1194e9b4fc941f3df45b8993e440986ddf6d9722..3f51e071be261291ce60504e7aab941a760d95d3 100644 (file)
 #define GHI_RPC_GUEST_SHELL_ACTION                    "ghi.guest.shell.action"
 #define GHI_RPC_SET_GUEST_HANDLER                     "ghi.guest.handler.set"
 #define GHI_RPC_RESTORE_DEFAULT_GUEST_HANDLER         "ghi.guest.handler.restoreDefault"
+#define GHI_RPC_OUTLOOK_SET_TEMP_FOLDER               "ghi.guest.outlook.set.tempFolder"
 /* @} */
 
 
index 999c5d844477e644ba472ff7871973cb004589c0..e7b798914a3af1bf8be75ac407a42edbdb981ddb 100644 (file)
@@ -115,6 +115,7 @@ enum {
    VIX_E_OPERATION_ALREADY_IN_PROGRESS          = 31,
    VIX_E_UNFINISHED_JOB                         = 29,
    VIX_E_NEED_KEY                               = 30,
+   VIX_E_LICENSE                                = 32,
 
    /* Handle Errors */
    VIX_E_INVALID_HANDLE                         = 1000,
index 6766ed53bdaeba0c005e92c5761d42a39d8f9598..0bea8898a98743eb63934aff8b34902cca0ddf64 100644 (file)
@@ -380,7 +380,85 @@ VMGuestLibError VMGuestLib_GetCpuStolenMs(VMGuestLibHandle handle, // IN
 VMGuestLibError VMGuestLib_GetMemTargetSizeMB(VMGuestLibHandle handle,  // IN
                                               uint64 *memTargetSizeMB); // OUT
 
+/*
+ * Number of physical CPU cores on the host machine.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostNumCpuCores(VMGuestLibHandle handle,   // IN
+                              uint32 *hostNumCpuCores);  // OUT
+
+/*
+ * Total CPU time used by host.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostCpuUsedMs(VMGuestLibHandle handle,  // IN
+                            uint64 *hostCpuUsedMs);   // OUT
+
+/*
+ * Total memory swapped out on the host.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemSwappedMB(VMGuestLibHandle handle,     // IN
+                               uint64 *hostMemSwappedMB);   // OUT
+
+/*
+ * Total COW (Copy-On-Write) memory on host.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemSharedMB(VMGuestLibHandle handle,   // IN
+                              uint64 *hostMemSharedMB);  // OUT
+
+/*
+ * Total consumed memory on host.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemUsedMB(VMGuestLibHandle handle,  // IN
+                            uint64 *hostMemUsedMB);   // OUT
+
+/*
+ * Total memory available to host OS kernel.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemPhysMB(VMGuestLibHandle handle,  // IN
+                            uint64 *hostMemPhysMB);   // OUT
+
+/*
+ * Total physical memory free on host.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemPhysFreeMB(VMGuestLibHandle handle,    // IN
+                                uint64 *hostMemPhysFreeMB); // OUT
+
+/*
+ * Total host kernel memory overhead.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemKernOvhdMB(VMGuestLibHandle handle,     // IN
+                                uint64 *hostMemKernOvhdMB);  // OUT
+
+/*
+ * Total mapped memory on host.
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemMappedMB(VMGuestLibHandle handle,  // IN
+                              uint64 *hostMemMappedMB); // OUT
+
+/*
+ * Total unmapped memory on host.
+ */
 
+VMGuestLibError
+VMGuestLib_GetHostMemUnmappedMB(VMGuestLibHandle handle,    // IN
+                                uint64 *hostMemUnmappedMB); // OUT
 #ifdef __cplusplus
 }
 #endif
index e0d28d8e6524e0fa28c805efcfb653a2dfd44e80..0e730f680725b73621f58b4c87d6219e40d7a660 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index b1503b5d47a4d1f8824679f4494a2f46d6c943a0..a8bcda217e0b817b86cd843e294c874b8635cfce 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 317e25d20f60629e5e788016974f36af6bfa8121..666f04494324dc881afb616fc593689483caaac6 100644 (file)
  *
  * Deprecated.  Don't use these anymore.
  */
-#define PATENTS_LIST "6,075,938, 6,397,242, 6,496,847, 6,704,925, 6,711,672, 6,725,289,\n6,735,601, 6,785,886, 6,789,156, 6,795,966, 6,880,022, 6,944,699,\n6,961,806, 6,961,941, 7,069,413, 7,082,598, 7,089,377, 7,111,086,\n7,111,145, 7,117,481, 7,149,843, 7,155,558, 7,222,221, 7,260,815,\n7,260,820, 7,269,683, 7,275,136, 7,277,998, 7,277,999, 7,278,030,\n7,281,102, 7,290,253, 7,356,679, 7,409,487, 7,412,492, 7,412,702,\n7,424,710, 7,428,636, 7,433,951, 7,434,002, 7,447,854"
+#define PATENTS_LIST \
+   "6,075,938, 6,397,242, 6,496,847, 6,704,925, 6,711,672, 6,725,289,\n" \
+   "6,735,601, 6,785,886, 6,789,156, 6,795,966, 6,880,022, 6,944,699,\n" \
+   "6,961,806, 6,961,941, 7,069,413, 7,082,598, 7,089,377, 7,111,086,\n" \
+   "7,111,145, 7,117,481, 7,149,843, 7,155,558, 7,222,221, 7,260,815,\n" \
+   "7,260,820, 7,269,683, 7,275,136, 7,277,998, 7,277,999, 7,278,030,\n" \
+   "7,281,102, 7,290,253, 7,356,679, 7,409,487, 7,412,492, 7,412,702,\n" \
+   "7,424,710, 7,428,636, 7,433,951, 7,434,002, 7,447,854, 7,475,002,\n" \
+   "7,478,173, 7,478,180, 7,478,218, 7,478,388, 7,484,208, 7,487,313,\n" \
+   "7,487,314, 7,490,216"
+
 #define PATENTS_STRING_OLD "Protected by one or more U.S. Patent Nos.\n" PATENTS_LIST " and patents pending."
 
 /*
index 83b69eb201fb9772e68945a442ee1d898100ec0e..b29d015111e8e83eb2adaf4479d013b41d318abb 100644 (file)
       || defined(VMX86_P2V)      \
       || defined(VMX86_DDK)      \
       || defined(VMX86_VDDK))
-#   if defined(_WIN32)
+#   if defined(_WIN32) || defined(__APPLE__)
       /*
        * XXX Make the product be Workstation by default if none of the defines
        * XXX above are not defined in defs-globaldefs.mk -- Edward A. Waugh
index 41ccb668b0fe544ca6b05bd5045f00319635e572..655bd11ade07f2f75292642c3f070843b34fe192 100644 (file)
@@ -872,9 +872,17 @@ typedef uint32 ToolsVersion;
 #define   TOOLS_VERSION_ESX40_RC1_V_MNR      0
 #define   TOOLS_VERSION_ESX40_RC1_V_BASE     0
 
-#define   TOOLS_VERSION_CURRENT        TOOLS_VERSION_ESX40_RC1
-#define   TOOLS_VERSION_CURRENT_STR    TOOLS_VERSION_TO_STR(TOOLS_VERSION_ESX40_RC1)
-#define   TOOLS_VERSION_CURRENT_CSV    TOOLS_VERSION_TO_CSV(TOOLS_VERSION_ESX40_RC1)
+#ifndef RC_INVOKED
+#define   TOOLS_VERSION_ESX40_RELEASE  TOOLS_VERSION_TO_UINT(TOOLS_VERSION_ESX40_RELEASE_V)
+#endif /* RC_INVOKED */
+#define   TOOLS_VERSION_ESX40_RELEASE_V_MJR  8
+#define   TOOLS_VERSION_ESX40_RELEASE_V_MNR  0
+#define   TOOLS_VERSION_ESX40_RELEASE_V_BASE 1
+
+
+#define   TOOLS_VERSION_CURRENT        TOOLS_VERSION_ESX40_RELEASE
+#define   TOOLS_VERSION_CURRENT_STR    TOOLS_VERSION_TO_STR(TOOLS_VERSION_ESX40_RELEASE)
+#define   TOOLS_VERSION_CURRENT_CSV    TOOLS_VERSION_TO_CSV(TOOLS_VERSION_ESX40_RELEASE)
 
 
 /*
index 8b1a01621411ab70d4291af6205f168f86f4a455..6c4c06c330416a970207549ce91b7ec05aeca86b 100644 (file)
 /*
  * The current Tools version, derived from vm_tools_version.h. Do not modify this.
  */
-#define TOOLS_VERSION "2009.02.18"
+#define TOOLS_VERSION "2009.03.18"
 
 #ifdef VMX86_VPX
 #define VIM_API_TYPE "VirtualCenter"
index ddc193fbfce09ceb022d1a43eec03aea7ff03462..0cc94e67ed7176814ae9d81b91a8ee15fc508f8b 100644 (file)
  */
 #define TOOLS_CORE_SIG_CAPABILITIES "tcs_capabilities"
 
+/**
+ * Signal sent when the service receives a request to dump its internal
+ * state to the log. This is for debugging purposes, and plugins can
+ * respond to the signal by dumping their own state also.
+ *
+ * @param[in]  src      The source object.
+ * @param[in]  ctx      ToolsAppCtx *: The application context.
+ * @param[in]  data     Client data.
+ */
+#define TOOLS_CORE_SIG_DUMP_STATE  "tcs_dump_state"
+
 /**
  * Signal sent when a successful RpcChannel reset occurs.
  *
index 38c2058ac850cb4d8e33837e1020f899e34ebba1..66ca2590a664c8a2d42cd3f04a1d303c9f9ee813 100644 (file)
@@ -639,6 +639,7 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #define CPUID_MODEL_NEHALEM_1A 0x1a  // Nehalem / Gainestown
 #define CPUID_MODEL_ATOM_1C    0x1c  // Silverthorne / Diamondville
 #define CPUID_MODEL_CORE_1D    0x1d  // Dunnington
+#define CPUID_MODEL_NEHALEM_1E 0x1e  // Lynnfield
 
 #define CPUID_MODEL_PIII_07    7
 #define CPUID_MODEL_PIII_08    8
@@ -758,19 +759,18 @@ CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1.
            model == CPUID_MODEL_CORE_1D);
 }
 
-
 /*
- * Intel Nehalem processors are: Nehalem, Gainestown.
+ * Intel Nehalem processors are: Nehalem, Gainestown, Lynnfield.
  */
 static INLINE Bool
 CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
 {
    /* Assumes the CPU manufacturer is Intel. */
    return CPUID_FAMILY_IS_P6(v) &&
-          CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A;
+          (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A ||
+           CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1E);
 }
 
-
 static INLINE Bool
 CPUID_FAMILY_IS_K7(uint32 _eax)
 {
index e03250af68b02876a725b48f5aeaeee1ca5445b4..5488667ad73774a64e6c73c5611bc0aa83fb68bf 100644 (file)
@@ -75,6 +75,7 @@
 #include "vm_product.h"
 #include "vm_atomic.h"
 #include "unicode/ucnv.h"
+#include "unicode/udata.h"
 #include "unicode/putil.h"
 #include "file.h"
 #include "util.h"
 
 static Bool dontUseIcu = TRUE;
 
-#ifdef _WIN32
-static Bool initedIcu = FALSE;
-static Atomic_Ptr sCriticalSection;
-#else // Posix
-DEBUG_ONLY(static Bool initedIcu = FALSE;)
-#endif
-
 
 /*
  * Functions
@@ -186,73 +180,6 @@ CodeSetGetModulePath(HANDLE hModule) // IN
 }
 
 
-/*
- *----------------------------------------------------------------------------
- *
- * CodeSetEnterCriticalSection --
- *
- *      Initialize critical section atomically, and enter that critical section.
- *
- * Returns:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-CodeSetEnterCriticalSection(void)
-{
-   CRITICAL_SECTION *cs = Atomic_ReadPtr(&sCriticalSection);
-
-   // Initalize critical section atomically.
-   if (cs == NULL) {
-      CRITICAL_SECTION *newcs = Util_SafeMalloc(sizeof *newcs);
-      InitializeCriticalSection(newcs);
-
-      Atomic_Init();
-      cs = Atomic_ReadIfEqualWritePtr(&sCriticalSection, NULL, newcs);
-
-      if (cs == NULL) {
-        cs = newcs;
-      } else {
-         DeleteCriticalSection(newcs);
-        free(newcs);
-      }
-   }
-
-   ASSERT(cs);
-   EnterCriticalSection(cs);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CodeSetLeaveCriticalSection --
- *
- *      Leave critical section.
- *
- * Returns:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-CodeSetLeaveCriticalSection(void)
-{
-   CRITICAL_SECTION *cs = Atomic_ReadPtr(&sCriticalSection);
-
-   ASSERT(cs);
-   LeaveCriticalSection(cs);
-}
-
 #elif vmx86_devel // _WIN32
 
 /*
@@ -451,29 +378,18 @@ CodeSet_Init(const char *icuDataDir) // IN: ICU data file location in Current co
    DWORD attribs;
    utf16_t *modPath = NULL;
    utf16_t *lastSlash;
+   utf16_t *wpath;
+   HANDLE hFile;
+   HANDLE hMapping;
+   void *memMappedData = NULL;
 #else
    struct stat finfo;
 #endif
    char *path = NULL;
    Bool ret = FALSE;
 
-#ifdef _WIN32
-   CodeSetEnterCriticalSection();
-#endif
-
    DynBuf_Init(&dbpath);
 
-#ifdef _WIN32
-   if (initedIcu) {
-      // Nothing to be initialized.
-      ret = TRUE;
-      goto exit;
-   }
-#else // Posix
-   DEBUG_ONLY(ASSERT(!initedIcu);)
-   DEBUG_ONLY(initedIcu = TRUE;)
-#endif
-
 #ifdef USE_ICU
    /*
     * We're using system ICU, which finds its own data. So nothing to
@@ -575,29 +491,24 @@ CodeSet_Init(const char *icuDataDir) // IN: ICU data file location in Current co
       }
 
       /*
-       * Check for file existence.
+       * Since u_setDataDirectory can't handle UTF-16, we would have to
+       * now convert this path to local encoding. But that fails when
+       * the module is in a path containing characters not in the
+       * local encoding (see 282524). So we'll memory-map the file
+       * instead and call udata_setCommonData() below.
        */
-      attribs = GetFileAttributesW((LPCWSTR) DynBuf_Get(&dbpath));
-
-      if ((INVALID_FILE_ATTRIBUTES == attribs) ||
-          (attribs & FILE_ATTRIBUTE_DIRECTORY)) {
+      wpath = (utf16_t *) DynBuf_Get(&dbpath);
+      hFile = CreateFileW(wpath, GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL);
+      if (INVALID_HANDLE_VALUE == hFile) {
          goto exit;
       }
-
-      /*
-       * Convert path to local encoding using system APIs (old codeset).
-       */
-      if (!CodeSetOld_Utf16leToCurrent(DynBuf_Get(&dbpath),
-                                       DynBuf_GetSize(&dbpath),
-                                       &path, NULL)) {
-
-         /*
-          * The unicode path is not compatible in the current encoding.
-          */
-         path = CodeSet_GetAltPathName(DynBuf_Get(&dbpath));
-         if (!path) {
-            goto exit;
-         }
+      hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+      if (NULL == hMapping) {
+         goto exit;
+      }
+      memMappedData = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
+      if (NULL == memMappedData) {
+         goto exit;
       }
    }
 
@@ -676,10 +587,28 @@ CodeSet_Init(const char *icuDataDir) // IN: ICU data file location in Current co
 found:
 #endif
 
-   /*
-    * Tell ICU to use this directory.
-    */
-   u_setDataDirectory(path);
+#ifdef _WIN32
+   if (memMappedData) {
+      /*
+       * Tell ICU to use this mapped data.
+       */
+      UErrorCode uerr = U_ZERO_ERROR;
+      ASSERT(memMappedData);
+
+      udata_setCommonData(memMappedData, &uerr);
+      if (uerr != U_ZERO_ERROR) {
+         UnmapViewOfFile(memMappedData);
+         goto exit;
+      }
+   } else {
+#endif
+      /*
+       * Tell ICU to use this directory.
+       */
+      u_setDataDirectory(path);
+#ifdef _WIN32
+   }
+#endif
 
    dontUseIcu = FALSE;
    ret = TRUE;
@@ -702,15 +631,16 @@ found:
 
 #ifdef _WIN32
    free(modPath);
+   if (hMapping) {
+      CloseHandle(hMapping);
+   }
+   if (hFile) {
+      CloseHandle(hFile);
+   }
 #endif
    free(path);
    DynBuf_Destroy(&dbpath);
 
-#ifdef _WIN32
-   initedIcu = ret;
-   CodeSetLeaveCriticalSection();
-#endif
-
    return ret;
 }
 
index fc8931fb3715876ef86e1822679022fa7a768876..0a99d499080060fdf54fd461a8f2b1c22f7660fa 100644 (file)
@@ -392,7 +392,13 @@ HostinfoGetOSShortName(char *distro,         // IN: full distro name
       }
    } else if (strstr(distroLower, "suse")) {
       if (strstr(distroLower, "enterprise")) {
-         Str_Strcpy(distroShort, STR_OS_SUSE_EN, distroShortSize);
+         if (strstr(distroLower, "server 11")) {
+            Str_Strcpy(distroShort, STR_OS_SLES_11, distroShortSize);
+         } else if (strstr(distroLower, "server 10")) {
+            Str_Strcpy(distroShort, STR_OS_SLES_10, distroShortSize);
+         } else {
+            Str_Strcpy(distroShort, STR_OS_SUSE_EN, distroShortSize);
+         }
       } else if (strstr(distroLower, "sun")) {
          Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
       } else if (strstr(distroLower, "novell")) {
@@ -810,18 +816,16 @@ Hostinfo_GetOSName(uint32 outBufFullLen,  // IN: length of osNameFull buffer
    } else if (strstr(osNameFull, "SunOS")) {
       size_t nameLen = sizeof STR_OS_SOLARIS - 1;
       size_t releaseLen = 0;
-      char *periodPtr;
+      char solarisRelease[3] = "";
 
       /*
        * Solaris releases report their version as "x.y". For our supported
        * releases it seems that x is always "5", and is ignored in favor of
-       * y for the version number. We'll be naive and look for the first
-       * period, and use the entire string after that as the version number.
+       * y for the version number.
        */
 
-      periodPtr = Str_Strchr(buf.release, '.');
-      if (periodPtr != NULL) {
-         releaseLen = (buf.release + strlen(buf.release)) - periodPtr;
+      if (sscanf(buf.release, "5.%2[0-9]", solarisRelease) == 1) {
+         releaseLen = strlen(solarisRelease);
       }
 
       if (nameLen + releaseLen + 1 > outBufLen) {
@@ -829,7 +833,7 @@ Hostinfo_GetOSName(uint32 outBufFullLen,  // IN: length of osNameFull buffer
          return FALSE;
       }
 
-      Str_Strcpy(osName, STR_OS_SOLARIS, outBufLen);
+      Str_Snprintf(osName, outBufLen, "%s%s", STR_OS_SOLARIS, solarisRelease);
    }
 
    if (Hostinfo_GetSystemBitness() == 64) {
index 83383da5603e0cdf4ea833c8415b326bf43d2557..d94e62e45e65e1b6333272e6b2fc4c1e03dbb203 100644 (file)
@@ -1333,7 +1333,7 @@ Posix_ReadLink(ConstUnicode pathName)  // IN:
       return NULL;
    }
 
-   bytes = readlink(path, link, sizeof link);
+   bytes = readlink(path, link, sizeof link - 1);
    ASSERT_NOT_IMPLEMENTED(bytes < (ssize_t) sizeof link);
 
    free(path);
index 79cba7afbab3ce96e95b99e95fff5fbaefbac3af..4e28cb5cf7d4e9d57bde2af6e8061499a8cbe83d 100644 (file)
@@ -1011,7 +1011,7 @@ TimeUtil_GetLocalWindowsTimeZoneIndexAndName(char **ptzName)   // OUT: returning
       struct tm tim;
       localtime_r(&now, &tim);
 
-      #if defined SOL9 || defined SOL10 || defined N_PLAT_NLM
+      #if defined(sun) || defined N_PLAT_NLM
          /*
           * Offset is to standard (no need for DST adjustment).
           * Negative is east of prime meridian.
index 55f6c94cc631ada152447e8aad0d63bd5ed7c73a..75550a5e2b96f3d5393b68e226892c989857e8a0 100644 (file)
@@ -73,6 +73,7 @@
 #include "user_layout.h"
 #endif
 
+#if !defined(N_PLAT_NLM)
 /*
  *-----------------------------------------------------------------------------
  *
@@ -132,6 +133,7 @@ Util_GetCanonicalPath(const char *path) // IN
 #endif
    return canonicalPath;
 }
+#endif
 
 
 #if defined(_WIN32)
index 6803a161d8c44cc6a26308086332fe9bc2fc70e4..2b1816047245ca61664bdbec6a7228f3e4a8ff61 100644 (file)
 #include "str.h"
 
 #define MAX_IFACES      4
-#define LOOPBACK        "lo"
+#define LOOPBACK        "lo"    // XXX: We would have a problem with something like "loa0".
 #ifndef INET_ADDRSTRLEN
 #define INET_ADDRSTRLEN 16
 #endif
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ValidateConvertAddress --
+ *
+ *      Helper routine validates an address as a return value for
+ *      NetUtil_GetPrimaryIP.
+ *
+ * Results:
+ *      Returns TRUE with sufficient result stored in outputBuffer on success.
+ *      Returns FALSE with "" stored in outputBuffer on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+ValidateConvertAddress(const char *ifaceName,           // IN: interface name
+                       const struct sockaddr_in *addr,  // IN: network address to
+                                                        //     evaluate
+                       char ipstr[INET_ADDRSTRLEN])     // OUT: converted address
+                                                        //      stored here
+{
+   /*
+    * 1.  Ensure this isn't a loopback device.
+    * 2.  Ensure this is an (IPv4) internet address.
+    */
+   if (ifaceName[0] == '\0' ||
+       strncmp(ifaceName, LOOPBACK, sizeof LOOPBACK - 1) == 0 ||
+       addr->sin_family != AF_INET) {
+      goto invalid;
+   }
+
+   /*
+    * Branches separated because it just looked really silly to lump the
+    * initial argument checking and actual conversion logic together.
+    */
+
+   /*
+    * 3.  Attempt network to presentation conversion.
+    * 4.  Ensure the IP isn't all zeros.
+    */
+   if (inet_ntop(AF_INET, (void *)&addr->sin_addr, ipstr, INET_ADDRSTRLEN) != NULL &&
+       strcmp(ipstr, "0.0.0.0") != 0) {
+      return TRUE;
+   }
+
+invalid:
+   ipstr[0] = '\0';
+   return FALSE;
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
  *      Get the primary IP for this machine.
  *
  * Results:
- *      
- *      The IP or NULL if an error occurred.
+ *      If applicable address found, returns string of said IP address.
+ *      If applicable address not found, returns an empty string.
+ *      If an error occurred, returns NULL.
  *
  * Side effects:
- *
- *     None.
+ *     Caller is responsible for free()ing returned string.
  *
  *----------------------------------------------------------------------
  */
@@ -101,12 +156,12 @@ NetUtil_GetPrimaryIP(void)
    int sd, i;
    struct ifconf iflist;
    struct ifreq ifaces[MAX_IFACES];
-   char *ipstr;
+   char ipstr[INET_ADDRSTRLEN] = "";
 
    /* Get a socket descriptor to give to ioctl(). */
    sd = socket(PF_INET, SOCK_STREAM, 0);
    if (sd < 0) {
-      goto error;
+      return NULL;
    }
 
    memset(&iflist, 0, sizeof iflist);
@@ -118,54 +173,22 @@ NetUtil_GetPrimaryIP(void)
 
    if (ioctl(sd, SIOCGIFCONF, &iflist) < 0) {
       close(sd);
-      goto error;
+      return NULL;
    }
 
    close(sd);
 
    /* Loop through the list of interfaces provided by ioctl(). */
    for (i = 0; i < (sizeof ifaces/sizeof *ifaces); i++) {
-      /*
-       * Find the first interface whose name is not blank and isn't a
-       * loopback device.  This should be the primary interface.
-       */
-      if ((*ifaces[i].ifr_name != '\0') &&
-          (strncmp(ifaces[i].ifr_name, LOOPBACK, strlen(LOOPBACK)) != 0)) {
-         struct sockaddr_in *addr;
-
-         /*
-          * Allocate memory to return to caller; they must free this if we
-          * don't return error.
-          */
-         ipstr = calloc(1, INET_ADDRSTRLEN);
-         if (!ipstr) {
-            goto error;
-         }
-
-         addr = (struct sockaddr_in *)(&ifaces[i].ifr_addr);
-
-         /* Convert this address to dotted decimal */
-         if (inet_ntop(AF_INET, (void *)&addr->sin_addr,
-                       ipstr, INET_ADDRSTRLEN) == NULL) {
-            goto error_free;
-         }
-
-         /* We'd rather return NULL than an IP of zeros. */
-         if (strcmp(ipstr, "0.0.0.0") == 0) {
-            goto error_free;
-         }
-
-         return ipstr;
+      if (ValidateConvertAddress(ifaces[i].ifr_name,
+                                 (struct sockaddr_in *)&ifaces[i].ifr_addr,
+                                 ipstr)) {
+         break;
       }
    }
 
-   /* Making it through loop means no non-loopback devices were found. */
-   return NULL;
-
-error_free:
-   free(ipstr);
-error:
-   return NULL;
+   /* Success.  Here, caller, you can throw this away. */
+   return strdup(ipstr);
 }
 
 #else /* } FreeBSD || APPLE { */
@@ -175,7 +198,7 @@ NetUtil_GetPrimaryIP(void)
 {
    struct ifaddrs *ifaces;
    struct ifaddrs *curr;
-   char ipstr[INET_ADDRSTRLEN];
+   char ipstr[INET_ADDRSTRLEN] = "";
 
    /*
     * getifaddrs(3) creates a NULL terminated linked list of interfaces for us
@@ -185,45 +208,15 @@ NetUtil_GetPrimaryIP(void)
       return NULL;
    }
 
-   if (!ifaces) {
-      return NULL;
-   }
-
    /*
     * We traverse the list until there are no more interfaces or we have found
     * the primary interface.  This function defines the primary interface to be
     * the first non-loopback, internet interface in the interface list.
     */
    for(curr = ifaces; curr != NULL; curr = curr->ifa_next) {
-      struct sockaddr_in *addr;
-
-      /* Ensure this isn't a loopback device. */
-      if (strncmp(curr->ifa_name, LOOPBACK, strlen(LOOPBACK)) == 0) {
-         continue;
-      }
-
-      addr = (struct sockaddr_in *)(curr->ifa_addr);
-
-      /* Ensure this is an (IPv4) internet interface. */
-      if (addr->sin_family == AF_INET) {
-         memset(ipstr, 0, sizeof ipstr);
-
-         /* Attempt network to presentation conversion. */
-         if (inet_ntop(AF_INET, (void *)&addr->sin_addr, ipstr, sizeof ipstr) == NULL) {
-            continue;
-         }
-
-         /* If the IP is all zeros we'll try for another interface. */
-         if (strcmp(ipstr, "0.0.0.0") == 0) {
-            /* Empty the string so we never return "0.0.0.0". */
-            ipstr[0] = '\0';
-            continue;
-         }
-
-         /*
-          * We have found the primary interface and its dotted-decimal IP is
-          * in ipstr.
-          */
+      if (ValidateConvertAddress(curr->ifa_name,
+                                 (struct sockaddr_in *)curr->ifa_addr,
+                                 ipstr)) {
          break;
       }
    }
@@ -231,11 +224,8 @@ NetUtil_GetPrimaryIP(void)
    /* Tell FreeBSD to free our linked list. */
    freeifaddrs(ifaces);
 
-   /*
-    * If ipstr is blank, just return NULL.  Otherwise, we create a copy of the
-    * string and return the pointer; the caller must free this memory.
-    */
-   return (ipstr[0] == '\0') ? NULL : strdup(ipstr);
+   /* Success.  Here, caller, you can throw this away. */
+   return strdup(ipstr);
 }
 #endif /* } */
 
index b83b56881dfadb3ef389ca8871500a53f34cad3d..5b7439b49eb6b84a9cd2c671ac99d99593e32dbd 100644 (file)
@@ -136,9 +136,7 @@ Str_Vsnprintf(char *str,          // OUT
    ASSERT(str != NULL);
    ASSERT(format != NULL);
 
-#ifndef HAS_BSD_PRINTF
-   retval = vsnprintf(str, size, format, ap);
-#elif defined __linux__
+#ifdef HAS_BSD_PRINTF
    {
       va_list aq;
 
@@ -147,7 +145,7 @@ Str_Vsnprintf(char *str,          // OUT
       va_end(aq);
    }
 #else
-   retval = bsd_vsnprintf(&str, size, format, ap);
+   retval = vsnprintf(str, size, format, ap);
 #endif
 
    /*
@@ -529,16 +527,13 @@ StrVasprintf_Internal(size_t *length,       // OUT
    int ret;
 
 #ifdef HAS_BSD_PRINTF
-   #ifdef __linux__
-      {
-        va_list aq;
-        va_copy(aq, arguments);
-        ret = bsd_vsnprintf(&buf, 0, format, aq);
-        va_end(aq);
-      }
-   #else
-      ret = bsd_vsnprintf(&buf, 0, format, arguments);
-   #endif
+   {
+      va_list aq;
+
+      va_copy(aq, arguments);
+      ret = bsd_vsnprintf(&buf, 0, format, aq);
+      va_end(aq);
+   }
 
 #elif !defined sun && !defined STR_NO_WIN32_LIBS
    ret = vasprintf(&buf, format, arguments);
diff --git a/open-vm-tools/lib/toolsLogger/logger.c b/open-vm-tools/lib/toolsLogger/logger.c
deleted file mode 100644 (file)
index 361b685..0000000
+++ /dev/null
@@ -1,574 +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 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.
- *
- *********************************************************/
-
-/*
- * logger.c --
- *
- *    All purpose logging mechanism used by Tools user-level applications 
- */
-
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
-
-#if !defined(N_PLAT_NLM) && !defined(_WIN32)                                              
-#   include <syslog.h>                                                                       
-#endif                                                                                    
-
-#ifdef _MSC_VER
-#   include <io.h>
-#   include <windows.h>
-#endif
-
-#if defined(N_PLAT_NLM)                                                                   
-#   include "vmwtool.h"                                                                   
-#endif                              
-
-#include "vm_version.h"
-#include "vm_assert.h"
-#include "str.h"
-#include "vmware.h"
-#include "rpcvmx.h"
-#include "util.h"
-#include "fileIO.h"
-#include "system.h"
-#include "guestApp.h"
-#include "vmcheck.h"
-#include "toolsLogger.h"
-#include "toolsLoggerInt.h"
-
-
-/*
- * Internal function prototypes
- */
-static void ToolsLoggerToFile(const char *str);
-static void ToolsLoggerToHost(const char *str);
-static void ToolsLoggerToSyslog(int type, const char *str);
-static void ToolsLoggerToStderr(const char *str);
-static void ToolsLoggerToConsole(const char *str);
-static Bool ToolsLoggerGetDictEntryBool(ToolsLogType logType, 
-                                        ToolsLogSink logSink, 
-                                        Bool defaultVal);
-static Bool ToolsLoggerGetLogFilePath(char *path, int len);
-
-static char *logTypePrefix[] = {
-   "PANIC",
-   "WARNING",
-   "LOG"
-};
-
-#if !defined(N_PLAT_NLM) && !defined(_WIN32)
-static const int syslogFlag[TOOLSLOG_TYPE_LAST] = {
-   [TOOLSLOG_TYPE_PANIC]     = LOG_EMERG,
-   [TOOLSLOG_TYPE_WARNING]   = LOG_WARNING,
-   [TOOLSLOG_TYPE_LOG]       = LOG_INFO
-};
-#endif
-
-static Bool filterMatrix[TOOLSLOG_TYPE_LAST][TOOLSLOG_SINK_LAST] = {
-   /* file, console, syslog, host,  stderr */
-   {  TRUE, TRUE,    TRUE,   TRUE,  TRUE},  /* PANIC */
-   {  TRUE, FALSE,   TRUE,   TRUE,  TRUE},  /* WARNING */
-   {  TRUE, FALSE,   FALSE,  FALSE, FALSE}  /* LOG */
-};
-
-/* Map TOOLSLOG_TYPE_x to string */
-static const char *logTypeName[] = {
-   "panic",     /* PANIC */
-   "warning",   /* WARNING */
-   "log"        /* LOG */
-};
-
-/* Map TOOLSLOG_SINK_x to string */
-static const char *logSinkName[] = {
-   "file",      /* FILE */
-   "console",   /* CONSOLE */
-   "syslog",    /* SYSLOG */
-   "host",      /* HOST */
-   "stderr"     /* STDERR */
-};
-
-static GuestApp_Dict *gConfDict = NULL;
-static FileIODescriptor gFdLog;
-static const char *gProgName = NULL; 
-static Bool gInVirtualWorld = FALSE;
-
-#if !defined(N_PLAT_NLM) && !defined(_WIN32)
-static const char *gSyslogIdent = NULL;
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsLogger_Init --
- * 
- *    Init the logger. An application has to call ToolsLogger_init() before
- *    calls ToolsLogger_log.
- *
- * Results:
- *    TRUE/FALSE.
- *
- * Side effects:
- *    The log file is opened. gConfDict, gProgName, and gSyslogIdent are
- *    initialized with the passed-in parameters.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool 
-ToolsLogger_Init(const char *progName,      // IN
-                 GuestApp_Dict *confDict)   // IN
-{
-   FileIOResult rval;
-   ToolsLogType logType;
-   ToolsLogSink logSink;
-   char path[PATH_MAX];
-
-   ASSERT(progName);
-   ASSERT(confDict);
-
-   gProgName = progName;
-   gConfDict = confDict;
-
-   /* Initialize filterMatrix */
-   for (logType = TOOLSLOG_TYPE_PANIC; logType < TOOLSLOG_TYPE_LAST; logType++) {
-      for (logSink = TOOLSLOG_SINK_FILE; logSink < TOOLSLOG_SINK_LAST; logSink++) {
-         filterMatrix[logType][logSink] = ToolsLoggerGetDictEntryBool(logType, logSink,
-                                             filterMatrix[logType][logSink]);
-      }
-   }
-
-   /* Enable logging to host if possible. */
-   if (VmCheck_IsVirtualWorld()) {
-      gInVirtualWorld = TRUE;
-   }
-
-   /* Open syslog if it is unix */
-#if !defined(N_PLAT_NLM) && !defined(_WIN32)
-   gSyslogIdent = progName;
-   openlog(gSyslogIdent, 0, LOG_USER);
-#endif
-
-   /* Open (create if not exist) the log file */
-   if (!ToolsLoggerGetLogFilePath(path, sizeof path)) {
-      return FALSE;
-   }
-   
-   FileIO_Invalidate(&gFdLog); 
-   rval = FileIO_Open(&gFdLog, path, FILEIO_OPEN_ACCESS_WRITE, FILEIO_OPEN_CREATE);
-   if (rval != FILEIO_SUCCESS) {
-      return FALSE;
-   }
-
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * ToolsLogger_Log --
- *
- *    Wrapper for ToolsLogger_LogV.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-ToolsLogger_Log(ToolsLogType type,      // IN: message type
-                const char *fmt,        // IN: format string
-                ...)                    // IN: arguments
-{
-   va_list args;
-
-   va_start(args, fmt);
-   ToolsLogger_LogV(type, fmt, args);
-   va_end(args);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- * ToolsLogger_LogV --
- *
- *    Output a message to several logging destinations.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-ToolsLogger_LogV(ToolsLogType type,      // IN: message type
-                 const char *fmt,        // IN: format string
-                 va_list args)           // IN: arguments
-{
-   char msg[256];
-   char str[256];
-   const char *progName;
-
-   ASSERT(type >= 0 && type < TOOLSLOG_TYPE_LAST);
-   ASSERT(fmt);
-
-   /* 
-    * We need to be able to support some logging even without initialization.
-    * This is because the logger initialization routines make calls to
-    * Debug/Warning/Panic that most people will probably implement in terms
-    * of this function.
-    */
-
-   /* Format the message */
-   Str_Vsnprintf(msg, sizeof msg, fmt, args);
-
-   if (gProgName) {
-      progName = gProgName;
-   } else {
-      progName = "unknown";
-   }
-
-   Str_Snprintf(str, sizeof str, "[%s] %s: %s",
-                progName,
-                logTypePrefix[type],
-                msg);
-
-   /* Dispatch the message */
-   if (filterMatrix[type][TOOLSLOG_SINK_FILE]) {
-      ToolsLoggerToFile(str);
-   }
-
-   if (filterMatrix[type][TOOLSLOG_SINK_STDERR]) {
-      ToolsLoggerToStderr(str);
-   }
-
-   if (filterMatrix[type][TOOLSLOG_SINK_CONSOLE]) {
-      ToolsLoggerToConsole(str);
-   }
-
-   if (filterMatrix[type][TOOLSLOG_SINK_HOST]) {
-      ToolsLoggerToHost(str);
-   }
-
-   if (filterMatrix[type][TOOLSLOG_SINK_SYSLOG]) {
-      ToolsLoggerToSyslog(type, str);
-   }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsLogger_Cleanup --
- *
- *    Reclaim resource used by the tools logger. 
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    The log file and the syslog are closed. All global pointers are
- *    reset.
- *
- *
- *-----------------------------------------------------------------------------
- */
-
-void 
-ToolsLogger_Cleanup(void)
-{
-#if !defined(N_PLAT_NLM) && !defined(_WIN32)
-   if (gProgName != NULL) {
-      closelog();
-      gSyslogIdent = NULL;
-   }
-#endif
-   gProgName = NULL;
-   gConfDict = NULL;
-
-   FileIO_Close(&gFdLog);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsLoggerToFile --
- *
- *    Write the message to the log file. Does nothing if we haven't yet
- *    initialized the logging infrastructure.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-ToolsLoggerToFile(const char *str)              // IN: logging message
-{
-   size_t bytesWritten;                                                                   
-
-   /* When uninitialized, do not log to file. */
-   if (!gProgName) {
-      return;
-   }
-
-   if (FileIO_Seek(&gFdLog, 0, FILEIO_SEEK_END) != FILEIO_SUCCESS) {
-      return;
-   }
-
-   FileIO_Write(&gFdLog, str, strlen(str), &bytesWritten);                                
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsLoggerToStderr --
- *
- *    Write the message to STDERR. For WIN32, we write to STDOUT. 
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-ToolsLoggerToStderr(const char *str)            // IN: logging message
-{
-#ifdef _WIN32
-   printf("%s", str);
-   fflush(stdout);
-#else
-   fprintf(stderr, "%s", str);
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsLoggerToHost --
- *
- *    Write the message to vmx log file. Only do so if we've proven to
- *    ourselves that we're actually in a guest.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-ToolsLoggerToHost(const char *str)              // IN: logging message
-{
-   if (gInVirtualWorld) {
-      RpcVMX_Log("%s", str);
-   }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsLoggerToConsole --
- *
- *    Write the message to the system console. (NO WIN32 SUPPORT)
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-ToolsLoggerToConsole(const char *str)           // IN: logging message
-{
-#ifdef N_PLAT_NLM                                                                         
-   OutputToScreenWithAttribute(VMwareScreen, BOLD_RED, "%s", str);                        
-#else                                                                                     
-#ifndef _WIN32                                                                            
-   FileIOResult fr;                                                                       
-   FileIODescriptor fd;                                                                  
-   size_t bytesWritten;                                                                   
-                                                                                           
-   FileIO_Invalidate(&fd);                                                                 
-                                                                                           
-   fr = FileIO_Open(&fd, "/dev/console", FILEIO_OPEN_ACCESS_WRITE, 0);                     
-   if (fr != FILEIO_SUCCESS) {                                                            
-      goto done;                                                                          
-   }                                                                                      
-                                                                             
-   fr = FileIO_Write(&fd, str, strlen(str), &bytesWritten);                                
-   FileIO_Close(&fd);
-
-done:
-   return;
-#endif
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * ToolsLoggerToSyslog --
- *
- *    Write the message to the syslog daemon. Does nothing if we haven't yet
- *    initialized the logging infrastructure.
- *
- * Side effects:
- *
- *    None
- *
- *-----------------------------------------------------------------------------
- */
-static void
-ToolsLoggerToSyslog(int type,                   // IN: message type
-                    const char *str)            // IN: logging message
-{
-#ifdef _WIN32
-   OutputDebugString(str);
-#else
-#ifndef N_PLAT_NLM
-
-   /* When uninitialized, do not log to syslog. */
-   if (gProgName != NULL) {
-      syslog(LOG_USER|syslogFlag[type], "%s", str);
-   }
-#endif
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * ToolsLoggerGetDictEntryBool --
- *
- *    Get a logging dict entry's value & convert it to an Bool.
- *
- * Results:
- *    Returns TRUE is the dict entry is a case-insensitive match
- *    to "TRUE", FALSE otherwise. If there is no entry, for
- *    "name", return "defaultVal".
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------
- */
-
-static Bool
-ToolsLoggerGetDictEntryBool(ToolsLogType logType,   // IN: log type
-                            ToolsLogSink logSink,   // IN: log sink
-                            Bool defaultVal)        // IN: default value
-{
-   char name[64];
-   const char *value; 
-
-   Str_Snprintf(name, sizeof name, "log.%s.%s.enable",
-      logTypeName[logType], logSinkName[logSink]);
-
-   value = GuestApp_GetDictEntry(gConfDict, name);
-   if (!value) {
-      return defaultVal;
-   }
-
-#if  (defined N_PLAT_NLM || defined _WIN32)
-   return (stricmp(value, "TRUE") == 0);
-#else
-   return (strcasecmp(value, "TRUE") == 0);
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * ToolsLoggerGetLogFilePath --
- *
- *    Return the log file path. If the user specifies it in the config
- *    file, we load it from there. Otherwise, we use the default
- *    value defined by CONFVAL_LOGFILE_DEFAULT.
- *
- * Results:
- *    Return TRUE if the given buf 'path' is big enough to store the 
- *    path. Otherwise, return FALSE. 
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------
- */
-
-static Bool
-ToolsLoggerGetLogFilePath(char *path,   // OUT
-                          int size)     // IN
-{
-   const char *logFile;
-   char *logPath;
-
-   logFile = GuestApp_GetDictEntry(gConfDict, CONFNAME_LOGFILE);
-   if (logFile) {
-      Str_Strcpy(path, logFile, size);
-   } else {
-      char *defaultLogFile;
-
-      logPath = GuestApp_GetLogPath();
-      if (logPath == NULL) {
-         return FALSE;
-      }
-      defaultLogFile = Str_Asprintf(NULL, "%s%c%s", logPath, DIRSEPC, 
-                                    CONFVAL_LOGFILE_DEFAULT);
-      if (defaultLogFile == NULL) {
-         free(logPath);
-         return FALSE;
-      }
-
-      Str_Strcpy(path, defaultLogFile, size);
-
-      free(logPath);
-      free(defaultLogFile);
-   }
-
-   return TRUE;
-}
diff --git a/open-vm-tools/lib/toolsLogger/toolsLoggerInt.h b/open-vm-tools/lib/toolsLogger/toolsLoggerInt.h
deleted file mode 100644 (file)
index 258f41b..0000000
+++ /dev/null
@@ -1,53 +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 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.
- *
- *********************************************************/
-
-/*
- * toolsLoggerInt.h --
- *
- *    All-purpose logging facility. This header file contains 
- *    declarations that are intended just to be seen internally.
- *
- */
-
-
-#ifndef __TOOLSLOGGERINT_H__
-#   define __TOOLSLOGGERINT_H__
-
-
-/*
- * Log sinks
- */
-typedef enum {
-   TOOLSLOG_SINK_FILE,
-   TOOLSLOG_SINK_CONSOLE,
-   TOOLSLOG_SINK_SYSLOG,
-   TOOLSLOG_SINK_HOST,
-   TOOLSLOG_SINK_STDERR,
-
-   TOOLSLOG_SINK_LAST   /* Must be the last one */
-} ToolsLogSink;
-
-
-/*
- * Tools log file name 
- */
-#define CONFNAME_LOGFILE                          "log.file"
-#define CONFVAL_LOGFILE_DEFAULT                   "vmware-tools.log"
-
-
-#endif /* __TOOLSLOGGERINT_H__ */
index 84472e777382c08ef12548723070aedde0432bb5..8d7706037e69d2508917b541d7c57fe023b446d9 100644 (file)
@@ -319,13 +319,15 @@ Unicode_FreeList(Unicode *list,    // IN: the list to free
  *
  * Unicode_GetAllocList --
  *
- *      Allocates a list (actually a vector) of NUL terminated buffers from a 
- *      list (vector) of strings of specified encoding.
+ *      Given a list of Unicode strings, converts them to a list of
+ *      buffers in the specified encoding.
+ *
  *      The input list has a specified length or can be an argv-style
  *      NULL-terminated list (if length is negative).
  *
  * Results:
- *      An allocated list (vector) of NUL terminated buffers,
+ *      An allocated list (vector) of NUL terminated buffers in the specified
+ *      encoding
  *      or NULL on conversion failure.
  *      The caller is responsible to free the memory allocated by
  *      this routine.
@@ -336,12 +338,12 @@ Unicode_FreeList(Unicode *list,    // IN: the list to free
  *-----------------------------------------------------------------------------
  */
 
-Unicode *
+char **
 Unicode_GetAllocList(Unicode const srcList[], // IN: list of strings
-                    ssize_t length,          // IN: list 
-                    StringEncoding encoding) // IN:
+                    ssize_t length,          // IN: length (-1 for NULL term.)
+                    StringEncoding encoding) // IN: Encoding of returned list
 {
-   Unicode *dstList = NULL;
+   char **dstList = NULL;
    ssize_t i;
 
    ASSERT(srcList != NULL);
@@ -353,7 +355,7 @@ Unicode_GetAllocList(Unicode const srcList[], // IN: list of strings
       while (srcList[length] != NULL) {
          length++;
       }
-      
+
       /* Include the sentinel element. */
       length++;
    }
index 55732b0f2a0a33df776d6fc14f8247e3a60f5514..544662c4e401f5dc9ad7ec46223863526837fd02 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <ctype.h>
 #include <string.h>
+#include <stdio.h>
 
 #include "unicodeBase.h"
 #include "unicodeInt.h"
@@ -33,6 +34,7 @@
 #include "vm_assert.h"
 #include "util.h"
 #include "hashTable.h"
+#include "vm_atomic.h"
 
 static char *UnicodeNormalizeEncodingName(const char *encoding);
 
@@ -2429,155 +2431,174 @@ Unicode_IsEncodingValid(StringEncoding encoding)  // IN
       encoding < STRING_ENCODING_MAX_SPECIFIED;
 }
 
-
 /*
  *-----------------------------------------------------------------------------
  *
- * Unicode_InitEx --
+ * UnicodeInitInternal --
+ *
+ *      Convert argv and environment from default encoding into
+ *      unicode and initialize the cache of the native code set name
+ *      used to resolve STRING_ENCODING_DEFAULT.
  *
- *      Convert argv and environment from default encoding into unicode
- *     and initialize the cache of the native code set name used to
- *     resolve STRING_ENCODING_DEFAULT.
+ *      wargv takes precedence over argv as input if both are
+ *      specified, likewise with wenvp/envp.
  *
  * Results:
- *     returns on success
+ *      returns on success
  *      errors are terminal
  *
  * Side effects:
- *     Calling CodeSet_GetCurrentCodeSet() initializes the cache of the
+ *      Calling CodeSet_GetCurrentCodeSet() initializes the cache of the
  *      native code set name.  The cached name is used to resolve references
  *      to STRING_ENCODING_DEFAULT in unicode functions.
  *
  *-----------------------------------------------------------------------------
  */
-
-void
-Unicode_InitEx(int argc,                // IN
-               char ***argv,            // IN/OUT
-               char ***envp,            // IN/OUT
-               const char *icuDataDir)  // IN
+static void
+UnicodeInitInternal(int argc,               // IN
+                    const char *icuDataDir, // IN
+                    utf16_t **wargv,        // IN/OUT (OPT)
+                    utf16_t **wenvp,        // IN/OUT (OPT)
+                    char ***argv,           // IN/OUT (OPT)
+                    char ***envp)           // IN/OUT (OPT)
 {
 #if !defined(__APPLE__) && !defined(VMX86_SERVER)
    char **list;
    StringEncoding encoding;
 #endif
+   Bool success = FALSE;
+   char panicMsg[1024];
+   static volatile Bool inited = FALSE;
+   static Atomic_uint32 locked = {0};
+
+   panicMsg[0] = '\0';
 
    /*
-    * Always init the codeset module first.
+    * This function must be callable multiple times. We can't depend
+    * on lib/sync, so cheese it.
     */
+   while (1 == Atomic_ReadIfEqualWrite(&locked, 0, 1)) {
+#if !defined(N_PLAT_NLM) && !defined(__FreeBSD__)
+      usleep(250 * 1000);
+#endif
+   }
 
+   if (inited) {
+      success = TRUE;
+      goto exit;
+   }
+
+   /*
+    * Always init the codeset module first.
+    */
    if (!CodeSet_Init(icuDataDir)) {
-      Panic("Failed to initialize codeset.\n");
-      goto bail;
+#ifndef N_PLAT_NLM
+      snprintf(panicMsg, sizeof panicMsg, "Failed to initialize codeset.\n");
+#endif
+      goto exit;
    }
 
    encCache = HashTable_Alloc(128, HASH_ISTRING_KEY | HASH_FLAG_ATOMIC |
                               HASH_FLAG_COPYKEY, free);
    if (encCache == NULL) {
-      Panic("HashTable_Alloc failed.\n");
-      goto bail;
+#ifndef N_PLAT_NLM
+      snprintf(panicMsg, sizeof panicMsg, "HashTable_Alloc failed.\n");
+#endif
+      goto exit;
    }
 
    // UTF-8 native encoding for these two
 #if !defined(__APPLE__) && !defined(VMX86_SERVER)
-
    encoding = Unicode_EncodingNameToEnum(CodeSet_GetCurrentCodeSet());
    if (!Unicode_IsEncodingValid(encoding)) {
-      Panic("Unsupported local character encoding \"%s\".\n",
-            Unicode_EncodingEnumToName(STRING_ENCODING_DEFAULT));
-      goto bail;
+#ifndef N_PLAT_NLM
+      snprintf(panicMsg, sizeof panicMsg,
+         "Unsupported local character encoding \"%s\".\n",
+         Unicode_EncodingEnumToName(STRING_ENCODING_DEFAULT));
+#endif
+      goto exit;
    }
 
-   if (argv) {
+   if (wargv) {
+      list = Unicode_AllocList((char **)wargv, argc + 1, STRING_ENCODING_UTF16);
+      if (!list) {
+#ifndef N_PLAT_NLM
+         snprintf(panicMsg, sizeof panicMsg, "Unicode_AllocList1 failed.\n");
+#endif
+         goto exit;
+      }
+      *argv = list;
+   } else if (argv) {
       list = Unicode_AllocList(*argv, argc + 1, STRING_ENCODING_DEFAULT);
       if (!list) {
-         Panic("Unicode_AllocList1 failed.\n");
-         goto bail;
+#ifndef N_PLAT_NLM
+         snprintf(panicMsg, sizeof panicMsg, "Unicode_AllocList2 failed.\n");
+#endif
+         goto exit;
       }
       *argv = list;
    }
 
-   if (envp) {
+   if (wenvp) {
+      list = Unicode_AllocList((char **)wenvp, -1, STRING_ENCODING_UTF16);
+      if (!list) {
+#ifndef N_PLAT_NLM
+         snprintf(panicMsg, sizeof panicMsg, "Unicode_AllocList3 failed.\n");
+#endif
+         goto exit;
+      }
+      *envp = list;
+   } else if (envp) {
       list = Unicode_AllocList(*envp, -1, STRING_ENCODING_DEFAULT);
       if (!list) {
-         Panic("Unicode_AllocList2 failed.\n");
-         goto bail;
+#ifndef N_PLAT_NLM
+         snprintf(panicMsg, sizeof panicMsg, "Unicode_AllocList4 failed.\n");
+#endif
+         goto exit;
       }
       *envp = list;
    }
 #endif // !__APPLE__ && !VMX86_SERVER
 
-   return;
+   inited = TRUE;
+   success = TRUE;
+
+  exit:
+   Atomic_Write(&locked, 0);
 
-bail:
-   exit(1);
+   if (!success) {
+      panicMsg[sizeof panicMsg - 1] = '\0';
+      Panic("%s", panicMsg);
+      exit(1);
+   }
 }
 
+
 void
-Unicode_Init(int argc,        // IN
-             char ***argv,    // IN/OUT
-             char ***envp)    // IN/OUT
+Unicode_InitW(int argc,                // IN
+              utf16_t **wargv,         // IN/OUT (OPT)
+              utf16_t **wenvp,         // IN/OUT (OPT)
+              char ***argv,            // IN/OUT (OPT)
+              char ***envp)            // IN/OUT (OPT)
 {
-   Unicode_InitEx(argc, argv, envp, NULL);
+   UnicodeInitInternal(argc, NULL, wargv, wenvp, argv, envp);
 }
 
-#if defined(_WIN32)
+
 void
-Unicode_InitW(int argc,               // IN
-              utf16_t **wargv,        // IN
-              utf16_t **wenvp,        // IN
-              char ***argv,           // OUT
-              char ***envp)           // OUT
+Unicode_InitEx(int argc,                // IN
+               char ***argv,            // IN/OUT (OPT)
+               char ***envp,            // IN/OUT (OPT)
+               const char *icuDataDir)  // IN (OPT)
 {
-   char **list;
-   StringEncoding encoding;
-
-   /*
-    * Always init the codeset module first.
-    */
-
-   if (!CodeSet_Init(NULL)) {
-      Panic("Failed to initialize codeset.\n");
-      goto bail;
-   }
-
-   encCache = HashTable_Alloc(128, HASH_ISTRING_KEY | HASH_FLAG_ATOMIC |
-                              HASH_FLAG_COPYKEY, free);
-   if (encCache == NULL) {
-      Panic("HashTable_Alloc failed.\n");
-      goto bail;
-   }
-
-   encoding = Unicode_EncodingNameToEnum(CodeSet_GetCurrentCodeSet());
-   if (!Unicode_IsEncodingValid(encoding)) {
-      Panic("Unsupported character encoding \"%s\".\n",
-            Unicode_EncodingEnumToName(encoding));
-      goto bail;
-   }
-
-   encoding = STRING_ENCODING_UTF16;
-
-   if (wargv) {
-      list = Unicode_AllocList((char **)wargv, argc + 1, STRING_ENCODING_UTF16);
-      if (!list) {
-         Panic("Unicode_AllocList1 failed.\n");
-         goto bail;
-      }
-      *argv = list;
-   }
-
-   if (wenvp) {
-      list = Unicode_AllocList((char **)wenvp, -1, STRING_ENCODING_UTF16);
-      if (!list) {
-         Panic("Unicode_AllocList2 failed.\n");
-         goto bail;
-      }
-      *envp = list;
-   }
+   UnicodeInitInternal(argc, icuDataDir, NULL, NULL, argv, envp);
+}
 
-   return;
 
-bail:
-   exit(1);
+void
+Unicode_Init(int argc,        // IN
+             char ***argv,    // IN/OUT (OPT)
+             char ***envp)    // IN/OUT (OPT)
+{
+   UnicodeInitInternal(argc, NULL, NULL, NULL, argv, envp);
 }
-#endif // _WIN32
index b72922b99d31da892a54a05abe37bfe20662663d..597d3c5fa3a6c1070ed3400de6d0de5bea9c53ed 100644 (file)
@@ -23,7 +23,7 @@
  *
  * This file implements the guest-side Unity agent as part of the VMware Tools.
  * It contains entry points for embedding within the VMware Tools User Agent and
- * handles the GuestRpc (TCLO) interface.
+ * handles the GuestRpc (TCLO, RPCI) interface.
  *
  * UnityWindowTracker updates are sent to the MKS in two ways:
  *    @li @ref UNITY_RPC_GET_UPDATE GuestRpc (host-to-guest).
@@ -55,6 +55,7 @@
 #include "appUtil.h"
 #include <stdio.h>
 
+
 /*
  * Singleton object for tracking the state of the service.
  */
@@ -63,7 +64,7 @@ typedef struct UnityState {
    Bool forceEnable;
    Bool isEnabled;
    UnityVirtualDesktopArray virtDesktopArray;   // Virtual desktop configuration
-
+   UnityUpdateChannel updateChannel;            // Unity update transmission channel.
    UnityPlatform *up; // Platform-specific state
 } UnityState;
 
@@ -269,10 +270,18 @@ Unity_Init(GuestApp_Dict *conf, // IN
     */
    UnityWindowTracker_Init(&unity.tracker, UnityUpdateCallbackFn);
 
+   /*
+    * Initialize the update channel.
+    */
+   if (UnityUpdateChannelInit(&unity.updateChannel) == FALSE) {
+      Warning("%s: Unable to initialize Unity update channel.\n", __FUNCTION__);
+      return;
+   }
+
    /*
     * Initialize the host-specific portion of the unity service.
     */
-   unity.up = UnityPlatformInit(&unity.tracker, blockedWnd);
+   unity.up = UnityPlatformInit(&unity.tracker, &unity.updateChannel, blockedWnd);
 
    /*
     * Init our global dynbuf used to send results back.
@@ -323,20 +332,20 @@ Unity_Cleanup(void)
 
    Debug("%s\n", __FUNCTION__);
 
+
    /*
     * Exit Unity.
     */
-
    Unity_Exit();
 
    /*
     * Do one-time final platform-specific cleanup.
     */
-
    up = unity.up;
    unity.up = NULL;
    UnityPlatformCleanup(up);
 
+   UnityUpdateChannelCleanup(&unity.updateChannel);
    UnityWindowTracker_Cleanup(&unity.tracker);
    DynBuf_Destroy(&gTcloUpdate);
 }
@@ -973,31 +982,36 @@ UnityTcloGetUpdate(char const **result,     // OUT
                    size_t argsSize,         // ignored
                    void *clientData)        // ignored
 {
-   DynBuf *buf = &gTcloUpdate;
-   uint32 flags = 0;
+   Bool incremental = FALSE;
 
-   // Debug("UnityTcloGetUpdate name:%s args:'%s'", name, args);
+   Debug("UnityTcloGetUpdate name:%s args:'%s'", name, args);
 
    /*
     * Specify incremental or non-incremetal updates based on whether or
     * not the client set the "incremental" arg.
     */
    if (strstr(name, "incremental")) {
-      flags |= UNITY_UPDATE_INCREMENTAL;
+      incremental = TRUE;
    }
 
-   DynBuf_SetSize(buf, 0);
-
-   UnityGetUpdateCommon(flags, buf);
+   /*
+    * Call into platform-specific implementation to gather and send updates
+    * back via RPCI.  (This is done to ensure all updates are sent to the
+    * Unity server in sequence via the same channel.)
+    */
+   UnityPlatformDoUpdate(unity.up, incremental);
 
    /*
-    * Write the final result into the result out parameters.
+    * To maintain compatibility, we'll return a successful but empty response.
     */
-   *result = (char *)DynBuf_Get(buf);
-   *resultLen = DynBuf_GetSize(buf);
+   *result = "";
+   *resultLen = 0;
 
    /*
     * Give the debugger a crack to do something interesting at this point
+    *
+    * XXX Not sure if this is worth keeping around since this routine no
+    * longer returns updates directly.
     */
    UnityDebug_OnUpdate();
 
@@ -1219,7 +1233,7 @@ UnityUpdateCallbackFn(void *param,          // IN: dynbuf
 /*
  *-----------------------------------------------------------------------------
  *
- * UnityUpdateThreadInit --
+ * UnityUpdateChannelInit --
  *
  *      Initialize the state for the update thread.
  *
@@ -1235,34 +1249,33 @@ UnityUpdateCallbackFn(void *param,          // IN: dynbuf
  */
 
 Bool
-UnityUpdateThreadInit(UnityUpdateThreadData *updateData) // IN
+UnityUpdateChannelInit(UnityUpdateChannel *updateChannel) // IN
 {
-   ASSERT(updateData);
+   ASSERT(updateChannel);
 
-   updateData->flags = UNITY_UPDATE_INCREMENTAL;
-   updateData->rpcOut = NULL;
-   updateData->cmdSize = 0;
+   updateChannel->rpcOut = NULL;
+   updateChannel->cmdSize = 0;
 
-   DynBuf_Init(&updateData->updates);
-   DynBuf_AppendString(&updateData->updates, UNITY_RPC_PUSH_UPDATE_CMD " ");
+   DynBuf_Init(&updateChannel->updates);
+   DynBuf_AppendString(&updateChannel->updates, UNITY_RPC_PUSH_UPDATE_CMD " ");
 
    /* Exclude the null. */
-   updateData->cmdSize = DynBuf_GetSize(&updateData->updates) - 1;
+   updateChannel->cmdSize = DynBuf_GetSize(&updateChannel->updates) - 1;
 
-   updateData->rpcOut = RpcOut_Construct();
-   if (updateData->rpcOut == NULL) {
+   updateChannel->rpcOut = RpcOut_Construct();
+   if (updateChannel->rpcOut == NULL) {
       goto error;
    }
 
-   if (!RpcOut_start(updateData->rpcOut)) {
-      RpcOut_Destruct(updateData->rpcOut);
+   if (!RpcOut_start(updateChannel->rpcOut)) {
+      RpcOut_Destruct(updateChannel->rpcOut);
       goto error;
    }
 
    return TRUE;
 
 error:
-   DynBuf_Destroy(&updateData->updates);
+   DynBuf_Destroy(&updateChannel->updates);
 
    return FALSE;
 }
@@ -1271,7 +1284,7 @@ error:
 /*
  *-----------------------------------------------------------------------------
  *
- * UnityUpdateThreadCleanup --
+ * UnityUpdateChannelCleanup --
  *
  *      Cleanup the unity update thread state.
  *
@@ -1286,18 +1299,56 @@ error:
  */
 
 void
-UnityUpdateThreadCleanup(UnityUpdateThreadData *updateData) // IN
+UnityUpdateChannelCleanup(UnityUpdateChannel *updateChannel) // IN
 {
-   ASSERT(updateData);
+   if (updateChannel && updateChannel->rpcOut) {
+      RpcOut_stop(updateChannel->rpcOut);
+      RpcOut_Destruct(updateChannel->rpcOut);
+      updateChannel->rpcOut = NULL;
+
+      DynBuf_Destroy(&updateChannel->updates); // Avoid double-free by guarding this as well
+   }
+}
 
-   if (updateData->rpcOut) {
-      RpcOut_stop(updateData->rpcOut);
-      RpcOut_Destruct(updateData->rpcOut);
-      updateData->rpcOut = NULL;
 
-      DynBuf_Destroy(&updateData->updates); // Avoid double-free by guarding this as well
+#ifdef VMX86_DEVEL
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DumpUpdate --
+ *
+ *      Prints a Unity update via debug output.  NUL is represented as '!'.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+DumpUpdate(UnityUpdateChannel *updateChannel)   // IN
+{
+   int i, len;
+   char *buf = NULL;
+
+   len = updateChannel->updates.size;
+   buf = Util_SafeMalloc(len + 1);
+   memcpy(buf, updateChannel->updates.data, len);
+   buf[len] = '\0';
+   for (i = 0 ; i < len; i++) {
+      if (buf[i] == '\0') {
+         buf[i] = '!';
+      }
    }
+
+   Debug("%s: Sending update: %s\n", __FUNCTION__, buf);
+
+   free(buf);
 }
+#endif // ifdef VMX86_DEVEL
 
 
 /*
@@ -1306,7 +1357,7 @@ UnityUpdateThreadCleanup(UnityUpdateThreadData *updateData) // IN
  * UnitySendUpdates --
  *
  *      Gather and send a round of unity updates. The caller is responsible
- *      for gathering updates into updateData->updates buffer prior to the
+ *      for gathering updates into updateChannel->updates buffer prior to the
  *      function call. This function should only be called if there's data
  *      in the update buffer to avoid sending empty update string to the VMX.
  *
@@ -1321,21 +1372,25 @@ UnityUpdateThreadCleanup(UnityUpdateThreadData *updateData) // IN
  */
 
 Bool
-UnitySendUpdates(UnityUpdateThreadData *updateData) // IN
+UnitySendUpdates(UnityUpdateChannel *updateChannel) // IN
 {
    char const *myReply;
    size_t myRepLen;
    Bool retry = FALSE;
 
-   ASSERT(updateData);
-   ASSERT(updateData->rpcOut);
+   ASSERT(updateChannel);
+   ASSERT(updateChannel->rpcOut);
 
    /* Send 'tools.unity.push.update <updates>' to the VMX. */
 
+#ifdef VMX86_DEVEL
+   DumpUpdate(updateChannel);
+#endif
+
 retry_send:
-   if (!RpcOut_send(updateData->rpcOut,
-                    (char *)DynBuf_Get(&updateData->updates),
-                    DynBuf_GetSize(&updateData->updates),
+   if (!RpcOut_send(updateChannel->rpcOut,
+                    (char *)DynBuf_Get(&updateChannel->updates),
+                    DynBuf_GetSize(&updateChannel->updates),
                     &myReply, &myRepLen)) {
 
       /*
@@ -1348,8 +1403,8 @@ retry_send:
       if (!retry) {
          retry = TRUE;
          Debug("%s: could not send rpc. Reopening channel.\n", __FUNCTION__);
-         RpcOut_stop(updateData->rpcOut);
-         if (!RpcOut_start(updateData->rpcOut)) {
+         RpcOut_stop(updateChannel->rpcOut);
+         if (!RpcOut_start(updateChannel->rpcOut)) {
             Debug("%s: could not reopen rpc channel. Exiting...\n", __FUNCTION__);
             return FALSE;
          }
index 8a1e4d1f0b5ccde43cd20a2f874f88a9d0122a75..d983f10606e7c46dfbafe26926330f4cb115fcfa 100644 (file)
  *
  *********************************************************/
 
-/*
- * unityPlatform.h --
+/**
+ * @file unityPlatform.h
  *
- *    Implementation specific functionality
+ * Implementation specific functionality
  */
 
 #ifndef _UNITY_PLATFORM_H_
 #include "unityWindowTracker.h"
 #include "unity.h"
 
-/*
- * This data structure is used when gathering and sending
- * unity updates.
+
+/**
+ * Container used to store and send Unity updates.
  */
 
 typedef struct {
-   DynBuf updates;
-   size_t cmdSize;
+   DynBuf updates;      ///< See @ref vmtools_unity_uwtGuestRpc.
+   size_t cmdSize;      /**< @brief Size of RpcOut command prefix.
+                             Used as a convenient offset within #updates when
+                             resetting the update buffer. */
    RpcOut *rpcOut;
-   uint32 flags;
-} UnityUpdateThreadData;
+} UnityUpdateChannel;
 
 typedef struct {
    int x;
@@ -55,6 +56,7 @@ typedef struct _UnityPlatform UnityPlatform;
 
 Bool UnityPlatformIsSupported(void);
 UnityPlatform *UnityPlatformInit(UnityWindowTracker *tracker,
+                                 UnityUpdateChannel *updateChannel,
                                  int* blockedWnd);
 void UnityPlatformCleanup(UnityPlatform *up);
 void UnityPlatformRegisterCaps(UnityPlatform *up);
@@ -116,10 +118,12 @@ void UnityPlatformUpdateDnDDetWnd(UnityPlatform *up,
                                   Bool show);
 void UnityPlatformSetActiveDnDDetWnd(UnityPlatform *up, UnityDnD *detWnd);
 
+void UnityPlatformDoUpdate(UnityPlatform *up, Bool incremental);
+
 /* Functions implemented in unity.c for use by the platform-specific code. */
 void UnityGetUpdateCommon(int flags, DynBuf *buf);
-Bool UnityUpdateThreadInit(UnityUpdateThreadData *updateData);
-void UnityUpdateThreadCleanup(UnityUpdateThreadData *updateData);
-Bool UnitySendUpdates(UnityUpdateThreadData *updateData);
+Bool UnityUpdateChannelInit(UnityUpdateChannel *updateChannel);
+void UnityUpdateChannelCleanup(UnityUpdateChannel *updateChannel);
+Bool UnitySendUpdates(UnityUpdateChannel *updateChannel);
 
 #endif
index 27a71f7e416bd9a6d645285dd4e36da275abbc48..9afd21b748a74f36a771499f89de2dc23fe50576 100644 (file)
  *
  *********************************************************/
 
-/*
- * unityPlatformX11.c --
+/**
+ * @file unityPlatformX11.c
  *
- *    Implementation of Unity for guest operating systems that use the X11 windowing
- *    system. This file holds the basic things such as initialization/destruction of the
- *    UnityPlatform object, overall event handling, and handling of some Unity
- *    RPCs that are not window-centric.
+ * Implementation of Unity for guest operating systems that use the X11 windowing
+ * system. This file holds the basic things such as initialization/destruction of the
+ * UnityPlatform object, overall event handling, and handling of some Unity
+ * RPCs that are not window-centric.
  */
 
 #include "unityX11.h"
@@ -142,24 +142,24 @@ UnityPlatformIsSupported(void)
  */
 
 UnityPlatform *
-UnityPlatformInit(UnityWindowTracker *tracker, // IN
-                  int *blockedWnd)             // UNUSED
+UnityPlatformInit(UnityWindowTracker *tracker,          // IN
+                  UnityUpdateChannel *updateChannel,    // IN
+                  int *blockedWnd)                      // UNUSED
 {
    UnityPlatform *up;
    char *displayName;
 
+   ASSERT(tracker);
+   ASSERT(updateChannel);
+
    Debug("UnityPlatformInit: Running\n");
 
    up = Util_SafeCalloc(1, sizeof *up);
    up->tracker = tracker;
+   up->updateChannel = updateChannel;
 
    up->savedScreenSaverTimeout = -1;
 
-   if (!UnityUpdateThreadInit(&up->updateData)) {
-      free(up);
-      return NULL;
-   }
-
    /*
     * Because GDK filters events heavily, and we need to do a lot of low-level X work, we
     * just open another connection to the same display.
@@ -284,6 +284,7 @@ UnityPlatformInit(UnityWindowTracker *tracker, // IN
    INIT_ATOM(_NET_SUPPORTED);
    INIT_ATOM(_NET_FRAME_EXTENTS);
    INIT_ATOM(WM_CLASS);
+   INIT_ATOM(WM_CLIENT_LEADER);
    INIT_ATOM(WM_DELETE_WINDOW);
    INIT_ATOM(WM_ICON);
    INIT_ATOM(WM_NAME);
@@ -349,8 +350,6 @@ UnityPlatformCleanup(UnityPlatform *up) // IN
       up->display = NULL;
    }
 
-   UnityUpdateThreadCleanup(&up->updateData);
-
    free(up->desktopInfo.guestDesktopToUnity);
    up->desktopInfo.guestDesktopToUnity = NULL;
    free(up->desktopInfo.unityDesktopToGuest);
@@ -1183,41 +1182,6 @@ UnityPlatformUpdateWindowState(UnityPlatform *up,               // IN
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * UnityPlatformSendPendingUpdates --
- *
- *      Pushes any pending window tracker updates out to the host.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-UnityPlatformSendPendingUpdates(UnityPlatform *up, // IN
-                                int flags)         // IN
-{
-
-   DynBuf_SetSize(&up->updateData.updates, up->updateData.cmdSize);
-   UnityWindowTracker_RequestUpdates(up->tracker,
-                                     flags,
-                                     &up->updateData.updates);
-   DynBuf_AppendString(&up->updateData.updates, "");
-   if (DynBuf_GetSize(&up->updateData.updates) > (up->updateData.cmdSize + 1)) {
-      UnityPlatformDumpUpdate(up);
-      if (!UnitySendUpdates(&up->updateData)) {
-         Debug("UPDATE TRANSMISSION FAILED! --------------------\n");
-      }
-   }
-}
-
-
 #ifdef GTK2
 
 
@@ -1325,6 +1289,7 @@ UnityPlatformHandleEvents(gboolean errorOccurred,  // IN
    Bool restackDetWnd = FALSE;
 
    ASSERT(up);
+   ASSERT(up->isRunning);
 
    if (errorOccurred) {
       /*
@@ -1405,7 +1370,7 @@ UnityPlatformHandleEvents(gboolean errorOccurred,  // IN
          UnityPlatformStackDnDDetWnd(up);
       }
       UnityPlatformUpdateZOrder(up);
-      UnityPlatformSendPendingUpdates(up, UNITY_UPDATE_INCREMENTAL);
+      UnityPlatformDoUpdate(up, TRUE);
    }
 
    return TRUE;
@@ -1909,44 +1874,6 @@ UnityPlatformWMProtocolSupported(UnityPlatform *up,         // IN
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * UnityPlatformDumpUpdate --
- *
- *      Prints a Unity update via debug output...
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-UnityPlatformDumpUpdate(UnityPlatform *up) // IN
-{
-   int i, len;
-   char *buf;
-
-   return;
-
-   len = up->updateData.updates.size;
-   buf = alloca(len + 1);
-   memcpy(buf, up->updateData.updates.data, len);
-   buf[len] = '\0';
-   for (i = 0 ; i < len; i++) {
-      if (buf[i] == '\0') {
-         buf[i] = '!';
-      }
-   }
-
-   Debug("Sending update: %s\n", buf);
-}
-
-
 /*
  *----------------------------------------------------------------------------
  *
@@ -2198,6 +2125,11 @@ UnityPlatformStackDnDDetWnd(UnityPlatform *up)
 {
    static const Atom onDesktop[] = { 0xFFFFFFFF, 0, 0, 0, 0 };
 
+   if (!up->dnd.setMode || !up->dnd.detWnd) {
+      Debug("%s: DnD not yet initialized.\n", __func__);
+      return;
+   }
+
    if (!up->desktopWindow) {
       Debug("Desktop Window not cached. Tracker isn't populated.\n");
       return;
@@ -3043,3 +2975,47 @@ UnityPlatformSetDesktopActive(UnityPlatform *up,         // IN
 
    return TRUE;
 }
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * UnityPlatformDoUpdate --
+ *
+ *      This function is used to (possibly asynchronously) collect Unity window
+ *      updates and send them to the host via the RPCI update channel.
+ *
+ * Results:
+ *      Updates will be collected.  Updates may be sent.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+UnityPlatformDoUpdate(UnityPlatform *up,        // IN:
+                      Bool incremental)         // IN: Incremental vs. full update
+{
+   ASSERT(up);
+   ASSERT(up->updateChannel);
+
+   DynBuf_SetSize(&up->updateChannel->updates, up->updateChannel->cmdSize);
+
+   if (!incremental) {
+      UnityPlatformUpdateWindowState(up, up->tracker);
+   }
+
+   UnityWindowTracker_RequestUpdates(up->tracker,
+                                     incremental ? UNITY_UPDATE_INCREMENTAL : 0,
+                                     &up->updateChannel->updates);
+
+   DynBuf_AppendString(&up->updateChannel->updates, "");
+
+   if (DynBuf_GetSize(&up->updateChannel->updates) > (up->updateChannel->cmdSize + 1)) {
+      if (!UnitySendUpdates(up->updateChannel)) {
+         Debug("UPDATE TRANSMISSION FAILED! --------------------\n");
+      }
+   }
+}
index 96b2834f744678f56127b78aab8a6229ce6ddb87..4cbf39185c3c271bfeec4d7e3e1f3f83640a2035 100644 (file)
@@ -606,6 +606,17 @@ UnityPlatformSetTaskbarVisible(UnityPlatform *up,   // IN
          }
 
          if (currentSetting) {
+            /*
+             * If this flag is still set, that means that this window is being
+             * remapped -before- we received a _NET_WM_DESKTOP PropertyDelete
+             * notification.  (One such case may be if exiting Unity before the
+             * PropertyDelete is delivered.)  In that case, we'll go ahead and
+             * reset the property ourselves before remapping.
+             */
+            if (upw->wantSetDesktopNumberOnUnmap) {
+               UPWindow_SetEWMHDesktop(up, upw, upw->onUnmapDesktopNumber);
+               upw->wantSetDesktopNumberOnUnmap = FALSE;
+            }
             XMapWindow(up->display, dockWindow);
          } else {
             /* Preserve _NET_WM_DESKTOP across unmap. */
@@ -992,5 +1003,5 @@ UnityPlatformShowTaskbar(UnityPlatform *up,   // IN
             __FUNCTION__);
    }
 
-   UnityPlatformSendPendingUpdates(up, UNITY_UPDATE_INCREMENTAL);
+   UnityPlatformDoUpdate(up, TRUE);
 }
index 839f3f5705ea6cb7262004d88df7092ed0ae5874..38332fe71c7983a34b8e7e56ca2f2fc4510881c6 100644 (file)
@@ -77,10 +77,8 @@ static void UPWindowSetWindows(UnityPlatform *up,
                                UnityPlatformWindow *upw,
                                Window toplevelWindow,
                                Window clientWindow);
-static void UPWindowSetEWMHDesktop(UnityPlatform *up,
-                                   UnityPlatformWindow *upw,
-                                   uint32 ewmhDesktopId);
-
+static Window UPWindowLookupClientLeader(UnityPlatform *up,
+                                         UnityPlatformWindow *upw);
 
 #ifdef VMX86_DEVEL
 /*
@@ -1052,9 +1050,21 @@ UPWindow_CheckRelevance(UnityPlatform *up,        // IN
                   return;
                }
             } else if (event->atom == up->atoms._NET_WM_DESKTOP) {
-               if (upw->wantSetDesktopNumberOnUnmap &&
-                   event->state == PropertyDelete) {
-                  UPWindowSetEWMHDesktop(up, upw, upw->onUnmapDesktopNumber);
+               if (upw->wantSetDesktopNumberOnUnmap) {
+                  /*
+                   * We're to preserve _NET_WM_DESKTOP across unmapping and remapping a
+                   * window (most likely a taskbar).  If we see PropertyDelete, assume
+                   * it's ours and reset the _NET_WM_DESKTOP property.  If, however, we
+                   * instead see a PropertyNewValue (the only other possibility, hence
+                   * no "else" below), then we assume some other client wished to change
+                   * the property, and we forget about restoring _NET_WM_DESKTOP when
+                   * we remap the window later.
+                   */
+                  if (event->state == PropertyDelete) {
+                     Debug("%s: PropertyDelete: _NET_WM_DESKTOP: %#lx.  Resetting to %d.\n",
+                           __func__, upw->clientWindow, upw->onUnmapDesktopNumber);
+                     UPWindow_SetEWMHDesktop(up, upw, upw->onUnmapDesktopNumber);
+                  }
                   upw->wantSetDesktopNumberOnUnmap = FALSE;
                   return;
                }
@@ -1945,9 +1955,11 @@ UnityX11GetWindowPaths(UnityPlatform *up,        // IN
    int ret;
    Window checkWindow;
    Bool retval = FALSE;
+   Bool triedLeader = FALSE;
 
    checkWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
+tryLeader:
    UnityPlatformResetErrorCount(up);
    ret = XGetWindowProperty(up->display, checkWindow, up->atoms._NET_WM_PID, 0,
                             1024, False, AnyPropertyType,
@@ -1988,7 +2000,7 @@ UnityX11GetWindowPaths(UnityPlatform *up,        // IN
 
    if (!retval && XGetClassHint(up->display, checkWindow, &classHint)) {
       /*
-       * Last-ditch - try finding the WM_CLASS on $PATH.
+       * Try finding the WM_CLASS on $PATH.
        */
 
       char *fakeArgv[2] = {NULL, NULL};
@@ -2008,6 +2020,18 @@ UnityX11GetWindowPaths(UnityPlatform *up,        // IN
       XFree(classHint.res_class);
    }
 
+   if (!retval && !triedLeader) {
+      /*
+       * Last ditch - look for a client leader window and try all of the above
+       * again.
+       */
+      checkWindow = UPWindowLookupClientLeader(up, upw);
+      if (checkWindow != None) {
+         triedLeader = TRUE;
+         goto tryLeader;
+      }
+   }
+
    Debug("UnityX11GetWindowPath(%#lx) returning %s\n", upw->toplevelWindow,
          retval ? "TRUE" : "FALSE");
 
@@ -3781,7 +3805,7 @@ UnityPlatformSetWindowDesktop(UnityPlatform *up,         // IN
    ASSERT(desktopId < up->desktopInfo.numDesktops);
    guestDesktopId = up->desktopInfo.unityDesktopToGuest[desktopId];
 
-   UPWindowSetEWMHDesktop(up, upw, guestDesktopId);
+   UPWindow_SetEWMHDesktop(up, upw, guestDesktopId);
 
    return TRUE;
 }
@@ -3790,7 +3814,7 @@ UnityPlatformSetWindowDesktop(UnityPlatform *up,         // IN
 /*
  *------------------------------------------------------------------------------
  *
- * UPWindowSetEWMHDesktop --
+ * UPWindow_SetEWMHDesktop --
  *
  *     Move the window to the specified desktop.  ewmhDesktopId corresponds
  *     to a desktop index to be used with _NET_WM_DESKTOP.
@@ -3807,17 +3831,17 @@ UnityPlatformSetWindowDesktop(UnityPlatform *up,         // IN
  */
 
 
-static void
-UPWindowSetEWMHDesktop(UnityPlatform *up,               // IN
-                       UnityPlatformWindow *upw,        // IN
-                       uint32 ewmhDesktopId)            // IN
+void
+UPWindow_SetEWMHDesktop(UnityPlatform *up,               // IN
+                        UnityPlatformWindow *upw,        // IN
+                        uint32 ewmhDesktopId)            // IN
 {
    Atom data[5] = {0, 0, 0, 0, 0};
 
    ASSERT(up);
    ASSERT(upw);
 
-   if (!upw->isViewable) {
+   if (!upw->isViewable || upw->wantSetDesktopNumberOnUnmap) {
      Atom currentDesktop = ewmhDesktopId; // Cast for 64-bit correctness.
 
      /*
@@ -3826,6 +3850,13 @@ UPWindowSetEWMHDesktop(UnityPlatform *up,               // IN
       * eliminate race conditions, but if the window is not mapped, we
       * also need to set the property on the window so that it shows
       * up on the correct desktop when it is re-mapped.
+      *
+      * wantSetDesktopNumberOnUnmap implies that we unmapped the window
+      * in question.  We evaluate this here, in addition to isViewable,
+      * because it's totally possible that the window server processed
+      * our unmap request, but we just haven't received the notification
+      * yet.  (In other words, if that's the case, isViewable may still
+      * be TRUE.)
       */
 
      XChangeProperty(up->display, (Window)upw->clientWindow, up->atoms._NET_WM_DESKTOP,
@@ -3840,3 +3871,54 @@ UPWindowSetEWMHDesktop(UnityPlatform *up,               // IN
                                  up->atoms._NET_WM_DESKTOP,
                                  32, 5, data);
 }
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * UPWindowLookupClientLeader --
+ *
+ *      Given a UnityPlatformWindow, look up the associated "client leader"
+ *      window, identified by the WM_CLIENT_LEADER property, if it exists.
+ *
+ * Results:
+ *      A valid window ID if found, otherwise None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Window
+UPWindowLookupClientLeader(UnityPlatform *up,           // IN
+                           UnityPlatformWindow *upw)    // IN
+{
+   Atom propertyType;
+   int propertyFormat;
+   unsigned long itemsReturned;
+   unsigned long bytesRemaining;
+   unsigned char *valueReturned = NULL;
+
+   Window checkWindow;
+   Window leaderWindow = None;
+
+   ASSERT(up);
+   ASSERT(upw);
+
+   checkWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
+
+   UnityPlatformResetErrorCount(up);
+   XGetWindowProperty(up->display, checkWindow, up->atoms.WM_CLIENT_LEADER, 0,
+                      4, False, XA_WINDOW, &propertyType, &propertyFormat,
+                      &itemsReturned, &bytesRemaining, &valueReturned);
+
+   if (UnityPlatformGetErrorCount(up) == 0 && propertyFormat == 32 &&
+       itemsReturned == 1) {
+      leaderWindow = *(XID *)valueReturned;
+   }
+
+   XFree(valueReturned);
+
+   return leaderWindow;
+}
index 4808e10ea911ec631bca35f1258d74a3bd6080fd..7b6c49afcba04be2bc98ae321a05a298515a14ac 100644 (file)
@@ -205,6 +205,7 @@ struct _UnityPlatform {
       _NET_SUPPORTED,
       _NET_FRAME_EXTENTS,
       WM_CLASS,
+      WM_CLIENT_LEADER,
       WM_DELETE_WINDOW,
       WM_ICON,
       WM_NAME,
@@ -214,7 +215,7 @@ struct _UnityPlatform {
    } atoms;
 
    UnityWindowTracker *tracker;
-   UnityUpdateThreadData updateData;
+   UnityUpdateChannel *updateChannel;
 
    /*
     * This tracks all toplevel windows, whether or not they are showing through to the
@@ -384,13 +385,15 @@ Bool UPWindow_ProtocolSupported(const UnityPlatform *up,
 UnityPlatformWindow *UPWindow_Lookup(UnityPlatform *up, Window window);
 void UPWindow_SetUserTime(UnityPlatform *up,
                           UnityPlatformWindow *upw);
+void UPWindow_SetEWMHDesktop(UnityPlatform *up,
+                             UnityPlatformWindow *upw,
+                             uint32 ewmhDesktopId);
 
 /*
  * Implemented by unityPlatformX11.c
  */
 Bool UnityPlatformWMProtocolSupported(UnityPlatform *up, UnityX11WMProtocol proto);
 Bool UnityPlatformIsRootWindow(UnityPlatform *up, Window window);
-void UnityPlatformSendPendingUpdates(UnityPlatform *up, int flags);
 uint32 UnityX11GetCurrentDesktop(UnityPlatform *up);
 void UnityX11SetCurrentDesktop(UnityPlatform *up, uint32 currentDesktop);
 Time UnityPlatformGetServerTime(UnityPlatform *up);
@@ -403,7 +406,6 @@ Time UnityPlatformGetServerTime(UnityPlatform *up);
 
 int UnityPlatformGetErrorCount(UnityPlatform *up);
 void UnityPlatformResetErrorCount(UnityPlatform *up);
-void UnityPlatformDumpUpdate(UnityPlatform *up);
 Bool UnityPlatformSetTaskbarVisible(UnityPlatform *up, Bool currentSetting);
 void UnityPlatformSendClientMessage(UnityPlatform *up, Window destWindow,
                                    Window w, Atom messageType,
index b35ff8a65ad42bce56e1dfc7d7c936b8380d0b6d..fa21ee600289e298af535f1bccc88fedb5d19dd3 100644 (file)
 #endif
 #endif
 
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <paths.h>
+#endif
+
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
 #include "vmware.h"
 #include "hostType.h"
 #include "hostinfo.h"
@@ -1523,6 +1531,336 @@ Hostinfo_Execute(const char *command,
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Hostinfo_Daemonize --
+ *
+ *      Cross-platform daemon(3)-like wrapper.
+ *
+ *      Restarts the current process as a daemon, given the path to the
+ *      process (usually from Hostinfo_GetModulePath).  This means:
+ *
+ *         * You're detached from your parent.  (Your parent doesn't
+ *           need to wait for you to exit.)
+ *         * Your process no longer has a controlling terminal or
+ *           process group.
+ *         * Your stdin/stdout/stderr fds are redirected to /dev/null.
+ *         * Your main() function is called with the specified NULL-terminated
+ *           argument list.
+ *
+ *      (Don't forget that the first string in args is argv[0] -- the
+ *      name of the process).
+ *
+ *      Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCHDIR, then the
+ *      current directory of the daemon process is set to "/".
+ *
+ *      Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCLOSE, then all stdio
+ *      file descriptors of the daemon process are redirected to /dev/null.
+ *
+ *      If 'flags' contains HOSTINFO_DAEMONIZE_EXIT, then upon successful
+ *      launch of the daemon, the original process will exit.
+ *
+ *      If pidPath is non-NULL, then upon success, writes the PID
+ *      (as a US-ASCII string followed by a newline) of the daemon
+ *      process to that path.
+ *
+ * Results:
+ *      FALSE if the process could not be daemonized.  Err_Errno() contains
+ *      the error on failure.
+ *      TRUE if 'flags' does not contain HOSTINFO_DAEMONIZE_EXIT and
+ *      the process was daemonized.
+ *      Otherwise, if the process was daemonized, this function does
+ *      not return, and flow continues from your own main() function.
+ *
+ * Side effects:
+ *      The current process is restarted with the given arguments.
+ *      The process state is reset (see Hostinfo_ResetProcessState).
+ *      A new session is created (so the process has no controlling terminal).
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+Hostinfo_Daemonize(const char *path,             // IN: NUL-terminated UTF-8
+                                                 // path to exec
+                   char * const *args,           // IN: NULL-terminated UTF-8
+                                                 // argv list
+                   HostinfoDaemonizeFlags flags, // IN: flags
+                   const char *pidPath)          // IN/OPT: NUL-terminated
+                                                 // UTF-8 path to write PID
+{
+   /*
+    * We use the double-fork method to make a background process whose
+    * parent is init instead of the original process.
+    *
+    * We do this instead of calling daemon(), because daemon() is
+    * deprecated on Mac OS 10.5 hosts, and calling it causes a compiler
+    * warning.
+    *
+    * We must exec() after forking, because Mac OS library frameworks
+    * depend on internal Mach ports, which are not correctly propagated
+    * across fork calls.  exec'ing reinitializes the frameworks, which
+    * causes them to reopen their Mach ports.
+    */
+   int childPid;
+   int pipeFds[2] = { -1, -1 };
+   uint32 err = EINVAL;
+   char *pathLocalEncoding = NULL;
+   char *pidPathLocalEncoding = NULL;
+   char **argsLocalEncoding = NULL;
+
+   ASSERT_ON_COMPILE(sizeof (errno) <= sizeof err);
+
+   if (pipe(pipeFds) == -1) {
+      err = Err_Errno();
+      Warning("%s: Couldn't create pipe, error %u.\n",
+              __FUNCTION__, err);
+      goto cleanup;
+   }
+
+   if (fcntl(F_SETFD, pipeFds[1], 1) == -1) {
+      err = Err_Errno();
+      Warning("%s: Couldn't set close-on-exec for fd %d, error %u.\n",
+              __FUNCTION__, pipeFds[1], err);
+      goto cleanup;
+   }
+
+   // Convert the strings from UTF-8 before we fork.
+   pathLocalEncoding = Unicode_GetAllocBytes(path, STRING_ENCODING_DEFAULT);
+   if (!pathLocalEncoding) {
+      Warning("%s: Couldn't convert path [%s] to default encoding.\n",
+              __FUNCTION__, path);
+      goto cleanup;
+   }
+
+   if (pidPath) {
+      pidPathLocalEncoding =
+         Unicode_GetAllocBytes(pidPath, STRING_ENCODING_DEFAULT);
+      if (!pidPathLocalEncoding) {
+         Warning("%s: Couldn't convert path [%s] to default encoding.\n",
+                 __FUNCTION__, pidPath);
+         goto cleanup;
+      }
+   }
+
+   argsLocalEncoding = Unicode_GetAllocList(args, STRING_ENCODING_DEFAULT, -1);
+   if (!argsLocalEncoding) {
+      Warning("%s: Couldn't convert arguments to default encoding.\n",
+              __FUNCTION__);
+      goto cleanup;
+   }
+
+   childPid = fork();
+
+   switch (childPid) {
+   case -1:
+      err = Err_Errno();
+      Warning("%s: Couldn't fork first child, error %u.\n",
+              __FUNCTION__, err);
+      goto cleanup;
+   case 0:
+      // We're the first child.  Continue on.
+      break;
+   default:
+      {
+         // We're the original process.  Check if the first child exited.
+         int status;
+         FileIODescriptor pipeDesc;
+
+         close(pipeFds[1]);
+
+         pipeDesc = FileIO_CreateFDPosix(pipeFds[0], O_RDONLY);
+
+         waitpid(childPid, &status, 0);
+         if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) {
+            Warning("%s: Child %d exited with error %d.\n",
+                    __FUNCTION__, childPid, WEXITSTATUS(status));
+            goto cleanup;
+         } else if (WIFSIGNALED(status)) {
+            Warning("%s: Child %d exited with signal %d.\n",
+                    __FUNCTION__, childPid, WTERMSIG(status));
+            goto cleanup;
+         }
+
+         /*
+          * Check if the second child exec'ed successfully.  If it had
+          * an error, it will write a uint32 errno to this pipe before
+          * exiting.  Otherwise, its end of the pipe will be closed on
+          * exec and this call will fail as expected.
+          */
+         if (FileIO_Read(&pipeDesc, &err, sizeof err, NULL) == FILEIO_SUCCESS) {
+            Warning("%s: Child could not exec %s, error %u.\n",
+                    __FUNCTION__, path, err);
+            goto cleanup;
+         }
+
+         err = 0;
+         goto cleanup;
+      }
+   }
+
+   /*
+    * Close all fds except for the write end of the error pipe (which
+    * we've already set to close on successful exec).
+    */
+   Hostinfo_ResetProcessState(&pipeFds[1], 1);
+
+   if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE) && setsid() == -1) {
+      Warning("%s: Couldn't create new session, error %d.\n",
+              __FUNCTION__, Err_Errno());
+      _exit(EXIT_FAILURE);
+   }
+
+   switch (fork()) {
+   case -1:
+      {
+         Warning("%s: Couldn't fork second child, error %d.\n",
+                 __FUNCTION__, Err_Errno());
+         _exit(EXIT_FAILURE);
+      }
+   case 0:
+      // We're the second child.  Continue on.
+      break;
+   default:
+      /*
+       * We're the first child.  We don't need to exist any more.
+       *
+       * Exiting here causes the second child to be reparented to the
+       * init process, so the original process doesn't need to wait
+       * for the child we forked off.
+       */
+      _exit(EXIT_SUCCESS);
+   }
+
+   /*
+    * We can't use our i18n wrappers for file manipulation at this
+    * point, since we've forked; internal library mutexes might be
+    * invalid.
+    */
+   if (!(flags & HOSTINFO_DAEMONIZE_NOCHDIR) && chdir("/") == -1) {
+      uint32 err = Err_Errno();
+      Warning("%s: Couldn't chdir to /, error %u.\n",
+              __FUNCTION__, err);
+      // Let the original process know we failed to chdir.
+      if (write(pipeFds[1], &err, sizeof err) == -1) {
+         Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
+                 Err_Errno(), err);
+      }
+      _exit(EXIT_FAILURE);
+   }
+
+   if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE)) {
+      int fd;
+
+      fd = open(_PATH_DEVNULL, O_RDONLY);
+      if (fd != -1) {
+         dup2(fd, STDIN_FILENO);
+         close(fd);
+      }
+
+      fd = open(_PATH_DEVNULL, O_WRONLY);
+      if (fd != -1) {
+         dup2(fd, STDOUT_FILENO);
+         dup2(fd, STDERR_FILENO);
+         close(fd);
+      }
+   }
+
+   if (pidPath) {
+      int64 pid;
+      char pidString[32];
+      int pidStringLen;
+      int pidPathFd;
+      FileIODescriptor pidDesc;
+
+      ASSERT_ON_COMPILE(sizeof (pid_t) <= sizeof pid);
+      ASSERT(pidPathLocalEncoding);
+
+      // See above comment about how we can't use our i18n wrappers here.
+      pidPathFd = open(pidPathLocalEncoding, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+
+      if (pidPathFd == -1) {
+         err = Err_Errno();
+         Warning("%s: Couldn't open PID path [%s], error %d.\n",
+                 __FUNCTION__, pidPath, err);
+         if (write(pipeFds[1], &err, sizeof err) == -1) {
+            Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
+                    Err_Errno(), err);
+         }
+         _exit(EXIT_FAILURE);
+      }
+
+      pid = getpid();
+      pidStringLen = Str_Sprintf(pidString, sizeof pidString,
+                                 "%"FMT64"d\n", pid);
+      if (pidStringLen <= 0) {
+         err = EINVAL;
+         if (write(pipeFds[1], &err, sizeof err) == -1) {
+            Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
+                    Err_Errno(), err);
+         }
+         _exit(EXIT_FAILURE);
+      }
+
+      pidDesc = FileIO_CreateFDPosix(pidPathFd, O_WRONLY);
+
+      if (FileIO_Write(&pidDesc, pidString, pidStringLen, NULL) !=
+          FILEIO_SUCCESS) {
+         err = Err_Errno();
+         Warning("%s: Couldn't write PID to path [%s], error %d.\n",
+                 __FUNCTION__, pidPath, err);
+         if (write(pipeFds[1], &err, sizeof err) == -1) {
+            Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
+                    Err_Errno(), err);
+         }
+         _exit(EXIT_FAILURE);
+      }
+
+      close(pidPathFd);
+   }
+
+   if (execv(pathLocalEncoding, argsLocalEncoding) == -1) {
+      uint32 err = Err_Errno();
+      Warning("%s: Couldn't exec %s, error %u.\n",
+              __FUNCTION__, path, err);
+      // Let the original process know we failed to exec.
+      if (write(pipeFds[1], &err, sizeof err) == -1) {
+         Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
+                 Err_Errno(), err);
+      }
+      _exit(EXIT_FAILURE);
+   }
+
+   NOT_REACHED();
+
+  cleanup:
+   if (pipeFds[0] != -1) {
+      close(pipeFds[0]);
+   }
+   if (pipeFds[1] != -1) {
+      close(pipeFds[1]);
+   }
+   Util_FreeStringList(argsLocalEncoding, -1);
+   free(pidPathLocalEncoding);
+   free(pathLocalEncoding);
+
+   if (err == 0) {
+      if (flags & HOSTINFO_DAEMONIZE_EXIT) {
+         _exit(EXIT_SUCCESS);
+      }
+   } else {
+      Err_SetErrno(err);
+
+      if (pidPath) {
+         File_Unlink(pidPath);
+      }
+   }
+
+   return (err == 0);
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -1569,11 +1907,19 @@ Hostinfo_OSIsSMP(void)
  *
  *     Retrieve the full path to the executable. Not supported under VMvisor.
  *
+ *      Note: If your process is running with elevated privileges
+ *      (setuid/setgid), treat the path returned by this function as
+ *      untrusted (for example, do not pass it to exec or open).
+ *
+ *      This function returns a path that is under the control of the
+ *      user.  An attacker could manipulate the path returned by this
+ *      function to elevate privileges.
+ *
  * Results:
- *      On success: The allocated, NUL-terminated file path.  
+ *      On success: The allocated, NUL-terminated file path.
  *         Note: This path can be a symbolic or hard link; it's just one
  *         possible path to access the executable.
- *         
+ *
  *      On failure: NULL.
  *
  * Side effects:
index 8507f590ae13364e84f46b779ff43c530bec8efd..45745e255898b75b75f044f729c7a56606498a08 100644 (file)
@@ -1335,27 +1335,7 @@ VixToolsDeleteObject(VixCommandRequestHeader *requestMsg)  // IN
          }
       }
 
-#ifdef _WIN32
-      resultInt = File_UnlinkIfExists(pathName);
-#else
-      /*
-       * UnlinkIfExists() chases the symlink and tries to delete
-       * what it points to.  We don't want this, and rather than
-       * fight with bora/lib/file, just do it here ourselves.
-       */
-      {
-         char *primaryPath = Unicode_GetAllocBytes(pathName,
-                                                   STRING_ENCODING_DEFAULT);
-         if (NULL != primaryPath) {
-            resultInt = (unlink(primaryPath) == -1) ? errno : 0;
-            resultInt = (resultInt == ENOENT) ? 0 : resultInt;
-            free(primaryPath);
-         } else {
-            resultInt = UNICODE_CONVERSION_ERRNO;
-         }
-      }
-#endif
-
+      resultInt = File_UnlinkNoFollow(pathName);
       if (0 != resultInt) {
          err = FoundryToolsDaemon_TranslateSystemErr();
       }
@@ -3039,7 +3019,11 @@ VixToolsFreeRunProgramState(VixToolsRunProgramState *asyncState) // IN
    }
 
    if (NULL != asyncState->tempScriptFilePath) {
-      File_UnlinkIfExists(asyncState->tempScriptFilePath);
+      /*
+       * Use UnlinkNoFollow() since we created the file and we know it is not
+       * a symbolic link.
+       */
+      File_UnlinkNoFollow(asyncState->tempScriptFilePath);
    }
    if (NULL != asyncState->procState) {
       ProcMgr_Free(asyncState->procState);
index 0481b2584b366fe557d96a07b3784139e6919ce8..85cd1d1f409f820a8b9cee4c210efd4b55bac08f 100644 (file)
@@ -1310,3 +1310,282 @@ VMGuestLib_GetMemTargetSizeMB(VMGuestLibHandle handle, // IN
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostNumCpuCores --
+ *
+ *      Number of physical CPU cores on the host machine.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostNumCpuCores(VMGuestLibHandle handle, // IN
+                              uint32 *hostNumCpuCores) // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostNumCpuCores, hostCpuNumCores,
+                         GUESTLIB_HOST_CPU_NUM_CORES);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostCpuUsedMs --
+ *
+ *      Total CPU time used by host.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostCpuUsedMs(VMGuestLibHandle handle,  // IN
+                            uint64 *hostCpuUsedMs)    // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostCpuUsedMs, hostCpuUsedMs,
+                         GUESTLIB_HOST_CPU_USED_MS);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemSwappedMB --
+ *
+ *      Total swapped out memory on the host.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemSwappedMB(VMGuestLibHandle handle,  // IN
+                               uint64 *hostMemSwappedMB) // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemSwappedMB, hostMemSwappedMB,
+                         GUESTLIB_HOST_MEM_SWAPPED_MB);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemSharedMB --
+ *
+ *      Total COW (Copy-On-Write) memory on host.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemSharedMB(VMGuestLibHandle handle, // IN
+                              uint64 *hostMemSharedMB) // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemSharedMB, hostMemSharedMB,
+                         GUESTLIB_HOST_MEM_SHARED_MB);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemUsedMB --
+ *
+ *      Total consumed memory on host.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemUsedMB(VMGuestLibHandle handle,  // IN
+                            uint64 *hostMemUsedMB)    // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemUsedMB, hostMemUsedMB,
+                         GUESTLIB_HOST_MEM_USED_MB);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemPhysMB --
+ *
+ *      Total memory available to host OS kernel.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemPhysMB(VMGuestLibHandle handle,  // IN
+                            uint64 *hostMemPhysMB)    // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemPhysMB, hostMemPhysMB,
+                         GUESTLIB_HOST_MEM_PHYS_MB);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemPhysFreeMB --
+ *
+ *      Total phsyical memory free on host.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemPhysFreeMB(VMGuestLibHandle handle,    // IN
+                                uint64 *hostMemPhysFreeMB)  // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemPhysFreeMB, hostMemPhysFreeMB,
+                         GUESTLIB_HOST_MEM_PHYS_FREE_MB);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemUsedMB --
+ *
+ *      Total host kernel memory overhead.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemKernOvhdMB(VMGuestLibHandle handle,     // IN
+                                uint64 *hostMemKernOvhdMB)   // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemKernOvhdMB, hostMemKernOvhdMB,
+                         GUESTLIB_HOST_MEM_KERN_OVHD_MB);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemMappedMB --
+ *
+ *      Total mapped memory on host.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemMappedMB(VMGuestLibHandle handle,  // IN
+                              uint64 *hostMemMappedMB)  // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemMappedMB, hostMemMappedMB,
+                         GUESTLIB_HOST_MEM_MAPPED_MB);
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLib_GetHostMemUnmappedMB --
+ *
+ *      Total unmapped memory on host.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+VMGuestLibError
+VMGuestLib_GetHostMemUnmappedMB(VMGuestLibHandle handle,    // IN
+                                uint64 *hostMemUnmappedMB)  // OUT
+{
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETSTAT_V3(handle, error,
+                         hostMemUnmappedMB, hostMemUnmappedMB,
+                         GUESTLIB_HOST_MEM_UNMAPPED_MB);
+   return error;
+}
+
index eced935f299a2a0a5142a4ac9b41918294b3aff6..5b7e3e25c8a9f9caab6f14f8bd394a4bfcbd3be1 100644 (file)
@@ -33,6 +33,7 @@
 #  include "netutil.h"
 #endif
 
+#include "vm_assert.h"
 #include "vmtools.h"
 #include "wiper.h"
 
@@ -42,7 +43,7 @@
 VM_EMBED_VERSION(VMTOOLSLIB_VERSION_STRING);
 #endif
 
-extern void VMTools_InitLogging(void);
+extern void VMTools_ResetLogging(gboolean cleanDefault);
 
 
 /**
@@ -87,16 +88,16 @@ VMToolsDllInit(void *lib)
 #if defined(_WIN32)
    WiperInitData wiperData;
    CoreDump_SetUnhandledExceptionFilter();
-   VMTools_InitLogging();
+   VMTools_ResetLogging(FALSE);
    wiperData.resourceModule = lib;
    success = (NetUtil_LoadIpHlpApiDll() == ERROR_SUCCESS);
    g_assert(success);
    success = Wiper_Init(&wiperData.resourceModule);
    g_assert(success);
 #else
-   VMTools_InitLogging();
+   VMTools_ResetLogging(FALSE);
    success = Wiper_Init(NULL);
-   g_assert(success);
+   ASSERT(success);
 #endif
 }
 
@@ -114,6 +115,7 @@ VMToolsDllFini(void)
 #if defined(_WIN32)
    NetUtil_FreeIpHlpApiDll();
 #endif
+   VMTools_ResetLogging(TRUE);
 }
 
 
index 40dd1748a197ad7d51d3e02c3c146265c6065425..f378e11518a515b5b59d76cf98a4f5635cf4fdc9 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <glib/gstdio.h>
+#if defined(G_PLATFORM_WIN32)
+#  include <process.h>
+#else
+#  include <unistd.h>
+#endif
 
 #include "vmtools.h"
 #include "codeset.h"
@@ -38,6 +43,7 @@
 #  include "coreDump.h"
 #endif
 #include "file.h"
+#include "hostinfo.h"
 #include "str.h"
 #include "system.h"
 
@@ -90,10 +96,14 @@ VMToolsLogOutputDebugString(const gchar *domain,
                             gpointer _data);
 #endif
 
+void VMTools_ResetLogging(gboolean cleanDefault);
 
 typedef struct LogHandlerData {
+   gchar            *domain;
    GLogLevelFlags    mask;
    FILE             *file;
+   guint             handlerId;
+   gboolean          inherited;
 } LogHandlerData;
 
 static gchar *gLogDomain = NULL;
@@ -102,6 +112,7 @@ static gboolean gLogEnabled = FALSE;
 static guint gPanicCount = 0;
 static LogHandlerData *gDefaultData = NULL;
 static GLogFunc gDefaultLogFunc = DEFAULT_HANDLER;
+static GPtrArray *gDomains = NULL;
 
 /* Internal functions. */
 
@@ -118,6 +129,7 @@ static FILE *
 VMToolsLogOpenFile(const gchar *path)
 {
    FILE *logfile = NULL;
+   gchar *pathLocal;
 
    g_assert(path != NULL);
    if (File_Exists(path)) {
@@ -130,7 +142,10 @@ VMToolsLogOpenFile(const gchar *path)
       }
       free(bakFile);
    }
-   logfile = g_fopen(path, "w");
+
+   pathLocal = VMTOOLS_GET_FILENAME_LOCAL(path, NULL);
+   logfile = g_fopen(pathLocal, "w");
+   VMTOOLS_RELEASE_FILENAME_LOCAL(pathLocal);
    return logfile;
 }
 
@@ -310,25 +325,6 @@ VMToolsLogFile(const gchar *domain,
 }
 
 
-/**
- * Initializes the default log handler.
- */
-
-void
-VMTools_InitLogging(void)
-{
-   gDefaultData = g_malloc0(sizeof *gDefaultData);
-   gDefaultData->mask = G_LOG_LEVEL_ERROR |
-                        G_LOG_LEVEL_CRITICAL |
-                        G_LOG_LEVEL_WARNING;
-#if defined(VMX86_DEBUG)
-   gDefaultData->mask |= G_LOG_LEVEL_MESSAGE;
-#endif
-   gLogDomain = g_strdup("vmtools");
-   g_log_set_default_handler(DEFAULT_HANDLER, gDefaultData);
-}
-
-
 /**
  * Configures the given log domain based on the data provided in the given
  * dictionary. If the log domain being configured doesn't match the default
@@ -399,6 +395,38 @@ VMToolsConfigLogDomain(const gchar *domain,
          if (logpath == NULL) {
             g_warning("Missing log path for file handler (%s).\n", domain);
             goto exit;
+         } else {
+            /*
+             * Do some variable expansion in the input string. Currently only
+             * ${USER} and ${PID} are expanded.
+             */
+            gchar *vars[] = {
+               "${USER}",  NULL,
+               "${PID}",   NULL
+            };
+            size_t i;
+
+            vars[1] = Hostinfo_GetUser();
+            vars[3] = g_strdup_printf("%"FMTPID, getpid());
+
+            for (i = 0; i < ARRAYSIZE(vars); i += 2) {
+               char *last = logpath;
+               char *start;
+               while ((start = strstr(last, vars[i])) != NULL) {
+                  gchar *tmp;
+                  char *end = start + strlen(vars[i]);
+                  size_t offset = (start - last) + strlen(vars[i+1]);
+
+                  *start = '\0';
+                  tmp = g_strdup_printf("%s%s%s", logpath, vars[i+1], end);
+                  g_free(logpath);
+                  logpath = tmp;
+                  last = logpath + offset;
+               }
+            }
+
+            free(vars[1]);
+            g_free(vars[3]);
          }
       }
 #if defined(G_PLATFORM_WIN32)
@@ -450,19 +478,32 @@ VMToolsConfigLogDomain(const gchar *domain,
    }
 
    data = g_malloc0(sizeof *data);
+   data->domain = g_strdup(domain);
    data->mask = levelsMask;
    data->file = logfile;
 
    if (strcmp(domain, VMTools_GetDefaultLogDomain()) == 0) {
-      g_free(gDefaultData);
-      gDefaultData = data;
+      /* Replace the default log configuration before freeing the old data. */
+      LogHandlerData *old = gDefaultData;
+      LogHandlerData *gdata = g_malloc0(sizeof *gdata);
+
+      memcpy(gdata, data, sizeof *gdata);
+      g_log_set_default_handler(handlerFn, gdata);
+
+      gDefaultData = gdata;
       gDefaultLogFunc = handlerFn;
-      g_log_set_default_handler(handlerFn, data);
+      g_free(old);
    } else if (handler == NULL) {
+      ASSERT(data->file == NULL);
       data->file = gDefaultData->file;
+      data->inherited = TRUE;
    }
 
-   g_log_set_handler(domain, ALL_LOG_LEVELS, handlerFn, data);
+   if (gDomains == NULL) {
+      gDomains = g_ptr_array_new();
+   }
+   g_ptr_array_add(gDomains, data);
+   data->handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS, handlerFn, data);
 
 exit:
    g_free(handler);
@@ -517,6 +558,8 @@ VMTools_ConfigLogging(GKeyFile *cfg)
    gchar **list;
    gchar **curr;
 
+   VMTools_ResetLogging(FALSE);
+
    if (!g_key_file_has_group(cfg, LOGGING_GROUP)) {
       return;
    }
@@ -573,6 +616,70 @@ VMTools_EnableLogging(gboolean enable)
 }
 
 
+/**
+ * Resets the vmtools logging subsystem, freeing up data and optionally
+ * restoring the original glib configuration.
+ *
+ * @param[in]  cleanDefault   Whether to clean up the default handler and
+ *                            restore the original glib handler.
+ */
+
+void
+VMTools_ResetLogging(gboolean cleanDefault)
+{
+   gboolean oldLogEnabled = gLogEnabled;
+
+   /* Disable logging while we're playing with the configuration. */
+   gLogEnabled = FALSE;
+
+   if (cleanDefault) {
+      g_log_set_default_handler(g_log_default_handler, NULL);
+   }
+
+   if (gDomains != NULL) {
+      guint i;
+      for (i = 0; i < gDomains->len; i++) {
+         LogHandlerData *data = g_ptr_array_index(gDomains, i);
+         g_log_remove_handler(data->domain, data->handlerId);
+         if (data->file != NULL && !data->inherited) {
+            fclose(data->file);
+         }
+         g_free(data->domain);
+         g_free(data);
+      }
+      g_ptr_array_free(gDomains, TRUE);
+      gDomains = NULL;
+   }
+
+   if (gDefaultData != NULL) {
+      g_free(gDefaultData);
+      gDefaultData = NULL;
+   }
+
+   if (cleanDefault && gLogDomain != NULL) {
+      g_free(gLogDomain);
+      gLogDomain = NULL;
+   }
+
+   gDefaultLogFunc = DEFAULT_HANDLER;
+
+   if (!cleanDefault) {
+      if (gLogDomain == NULL) {
+         gLogDomain = g_strdup("vmtools");
+      }
+      gDefaultData = g_malloc0(sizeof *gDefaultData);
+      gDefaultData->mask = G_LOG_LEVEL_ERROR |
+                           G_LOG_LEVEL_CRITICAL |
+                           G_LOG_LEVEL_WARNING;
+#if defined(VMX86_DEBUG)
+      gDefaultData->mask |= G_LOG_LEVEL_MESSAGE;
+#endif
+      gLogEnabled = oldLogEnabled;
+      g_log_set_default_handler(gDefaultLogFunc, gDefaultData);
+   }
+}
+
+
 /* Wrappers for VMware's logging functions. */
 
 /**
index ab996be721418af616958c7c00713f204d5382f0..77e08b1d8ea3571a0a4ae2ad68275656e2969c8b 100644 (file)
@@ -9,6 +9,11 @@ $(MODULES):
        $(MAKE) VM_UNAME=$(KERNEL_RELEASE) MV=mv RM=rm $(EXTRA_ARGS) \
           -C "$(modulesrc)/$(MODULES_OS)/$@"
 
+if FREEBSD_CUSTOM_SYSDIR
+EXTRA_ARGS =
+EXTRA_ARGS += "SYSDIR=@SYSDIR@"
+endif
+
 if LINUX
 export pvscsidir := $(MODULES_DIR)/drivers/scsi
 export vmblockdir := $(MODULES_DIR)/fs/vmblock
index f4380e0f0dbef3331fe4eab8a56b1bbf0e571b22..066d908ea86d12f5dd07793ebd872b45b87ecc48 100644 (file)
@@ -51,7 +51,7 @@
  * We use defines rather than typedefs here to avoid causing problems for files that
  * don't have a vnode_if.h available.
  */
-#if __FreeBSD_version >= 700000
+#if __FreeBSD_version >= 700055
 #   define compat_vop_lock_t vop_lock1_t
 #   define compat_vop_lock_args struct vop_lock1_args
 #   define COMPAT_VOP_LOCK_OP_ELEMENT vop_lock1
index c6d2683550ae6b232355498fc1b493d254d96d69..3b427b3eb4e3a5eb65bc8af8a67e9f448d7988a9 100644 (file)
@@ -308,6 +308,39 @@ VMBlockHashRem(struct VMBlockNode *xp)  // IN: node to remove
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockInsMntQueDtr --
+ *
+ *      Do filesystem specific cleanup when recycling a vnode on a failed
+ *      insmntque1 call.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if __FreeBSD_version >= 700055
+static void
+VMBlockInsMntQueDtr(struct vnode *vp, // IN: node to cleanup
+                   void *xp)         // IN: FS private data
+{
+   vp->v_data = NULL;
+   vp->v_vnlock = &vp->v_lock;
+   FREE(xp, M_VMBLOCKFSNODE);
+   vp->v_op = &dead_vnodeops;
+   (void) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+   vgone(vp);
+   vput(vp);
+}
+#endif
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -381,6 +414,14 @@ VMBlockNodeGet(struct mount *mp,        // IN: VMBlock fs info
       panic("VMBlockNodeGet: Passed a NULL vnlock.\n");
    }
 
+   /* Before FreeBSD 7, insmntque was called by getnewvnode. */
+#if __FreeBSD_version >= 700055
+   error = insmntque1(vp, mp, VMBlockInsMntQueDtr, xp);
+   if (error != 0) {
+      return error;
+   }
+#endif
+
    /*
     * Atomically insert our new node into the hash or vget existing if
     * someone else has beaten us to it.
index 3fa1894d06ef0e96efbf5200d8a6b69ba838ac62..3a0919e4da11e30acfa9da3f75959035eb035889 100644 (file)
@@ -374,9 +374,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 54a3b44773c58163461ed8b1503c2616303764e9..a90e11055ded818187ed25b194d13ca4440a76e0 100644 (file)
@@ -895,11 +895,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 1f822c987780b81e7d34832577045032e96df32b..1f104efdacc68f5d049caa52fbef023e3e91abef 100644 (file)
 #include <sys/filedesc.h>
 #include <sys/kdb.h>
 #include "compat_freebsd.h"
-#if __FreeBSD_version >= 700000
+#if __FreeBSD_version >= 700055
 #include <sys/priv.h>
 #endif
 
@@ -698,7 +698,10 @@ struct vop_open_args {
    int fflag;           // IN: fdesc flags (see fcntl(2))
    struct ucred *cred;  // IN: caller's credentials (usually real uid vs euid)
    struct thread *td;   // IN: calling thread's context      
-   int fdidx;           // IN: file descriptor number alloc'd to this open()
+   FreeBSD <= 6 --
+      int fdidx;        // IN: file descriptor number alloc'd to this open()
+   FreeBSD >= 7 --
+      struct file *fp   // IN: struct associated with this particular open()
 };
 */
 {
@@ -724,7 +727,7 @@ struct vop_open_args {
        *      readdir() of the filesystem root for non-privileged users.
        */
       if ((retval = suser(ap->a_td)) == 0) {
-#if __FreeBSD_version >= 700000
+#if __FreeBSD_version >= 700055
          fp = ap->a_fp;
 #else
          fp = ap->a_td->td_proc->p_fd->fd_ofiles[ap->a_fdidx];
@@ -1082,7 +1085,7 @@ struct vop_rename_args {
       vrele(fvp);
       return EXDEV;
    }
-   
+
    return VMBlockVopBypass((struct vop_generic_args *)ap);
 }
 
@@ -1110,11 +1113,11 @@ struct vop_rename_args {
 static int
 VMBlockVopLock(compat_vop_lock_args *ap)
 /*
-struct {
-   struct vnode *a_vp;    // IN: vnode operand 
-   int a_flags;           // IN: lockmgr(9) flags
-   struct thread *a_td;   // IN: calling thread's context
-} *ap;
+struct vop_lock_args {
+   struct vnode *vp;    // IN: vnode operand
+   int flags;           // IN: lockmgr(9) flags
+   struct thread *td;   // IN: calling thread's context
+};
 */
 {
    struct vnode *vp = ap->a_vp;
index 521e046d691cc278a97f35cee017ec4463fc5f18..b5079d6a416a8e5158f55595ec656d72423fe69a 100644 (file)
@@ -39,7 +39,7 @@
  * We use defines rather than typedefs here to avoid causing problems for files that
  * don't have a vnode_if.h available.
  */
-#if __FreeBSD_version >= 700000
+#if __FreeBSD_version >= 700055
 #   define compat_vop_lock_t vop_lock1_t
 #   define compat_vop_lock_args struct vop_lock1_args
 #   define COMPAT_VOP_LOCK_OP_ELEMENT vop_lock1
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 337fd8cd9c82dbe09f8121f8a936bb4482a5a1f5..75bf8dd774111d34cb666b5567031aadd0c7c362 100644 (file)
@@ -639,6 +639,7 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #define CPUID_MODEL_NEHALEM_1A 0x1a  // Nehalem / Gainestown
 #define CPUID_MODEL_ATOM_1C    0x1c  // Silverthorne / Diamondville
 #define CPUID_MODEL_CORE_1D    0x1d  // Dunnington
+#define CPUID_MODEL_NEHALEM_1E 0x1e  // Lynnfield
 
 #define CPUID_MODEL_PIII_07    7
 #define CPUID_MODEL_PIII_08    8
@@ -758,19 +759,18 @@ CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1.
            model == CPUID_MODEL_CORE_1D);
 }
 
-
 /*
- * Intel Nehalem processors are: Nehalem, Gainestown.
+ * Intel Nehalem processors are: Nehalem, Gainestown, Lynnfield.
  */
 static INLINE Bool
 CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
 {
    /* Assumes the CPU manufacturer is Intel. */
    return CPUID_FAMILY_IS_P6(v) &&
-          CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A;
+          (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A ||
+           CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1E);
 }
 
-
 static INLINE Bool
 CPUID_FAMILY_IS_K7(uint32 _eax)
 {
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 5c6e8f06489118271c5e2837e02f5a41bbe7aa09..2cb9124e880e9e307410bff7c6a7a71956ca540c 100644 (file)
@@ -92,7 +92,8 @@
  *    Intel 82443BX (440 BX North Bridge and AGP Bridge)
  *    Intel 82545EM (e1000, server adapter, single port)
  *    Intel 82546EB (e1000, server adapter, dual port)
- *    Intel ICH7_16 (Hight Definition Audio controller)
+ *    Intel ICH7_16 (High Definition Audio controller)
+ *    Intel HECI (as embedded in ich9m)
  */
 #define PCI_VENDOR_ID_INTEL             0x8086
 #define PCI_DEVICE_ID_INTEL_82439TX     0x7100
 #define PCI_DEVICE_ID_INTEL_82545EM     0x100f
 #define PCI_DEVICE_ID_INTEL_82546EB     0x1010
 #define PCI_DEVICE_ID_INTEL_ICH7_16     0x27d8
+#define PCI_DEVICE_ID_INTEL_HECI        0x2a74
 
 
 /************* Strings for IDE Identity Fields **************************/
index b8dac81e50ddd4900e78e493f1472297dd260b0a..7d9af6a147e3f557375241fd17337be6b0b7c583 100644 (file)
@@ -1,5 +1,5 @@
 PACKAGE_NAME=open-vm-tools
-PACKAGE_VERSION=2009.02.18
+PACKAGE_VERSION=2009.03.18
 MAKE[0]="make -C pvscsi VM_UNAME=\$kernelver;   \
          make -C vmblock VM_UNAME=\$kernelver;  \
          make -C vmhgfs VM_UNAME=\$kernelver;   \
index 31103fbade99f02ff7ec01fd3a672ad6fddbbd42..b79d555584af49bd30070d2c196ba7b301175e04 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 5117d8dacef6c2e01b9ece716bdbdf636ce2b18c..095075a63085e30dd18e5b886ca3689a9c5b3c82 100644 (file)
@@ -178,10 +178,10 @@ enum PVSCSICommands {
  * Command descriptors.
  */
 
-struct CmdDescIssueSCSI {
+typedef struct CmdDescIssueSCSI {
    PA     reqAddr;
    PA     cmpAddr;
-};
+} CmdDescIssueSCSI;
 
 struct CmdDescResetDevice {
    uint32 target;
index 324674dfda77544edef8074bb4fa063058675156..a45c026fcdbbf95c715cb989b541058ac11d6508 100644 (file)
 #define SCSI_ASC_UNRECOVERED_READ_ERROR                         0x11  // Unrecovered read error
 #define SCSI_ASC_PARAM_LIST_LENGTH_ERROR                        0x1a  // parameter list length error
 #define SCSI_ASC_INVALID_COMMAND_OPERATION                     0x20  // invalid command operation code
+#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE             0x21  // Invalid LBA
 #define SCSI_ASC_INVALID_FIELD_IN_CDB                           0x24
 #define SCSI_ASC_LU_NOT_SUPPORTED                               0x25  // LU has been removed
 #define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST                0x26
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 5c6e8f06489118271c5e2837e02f5a41bbe7aa09..2cb9124e880e9e307410bff7c6a7a71956ca540c 100644 (file)
@@ -92,7 +92,8 @@
  *    Intel 82443BX (440 BX North Bridge and AGP Bridge)
  *    Intel 82545EM (e1000, server adapter, single port)
  *    Intel 82546EB (e1000, server adapter, dual port)
- *    Intel ICH7_16 (Hight Definition Audio controller)
+ *    Intel ICH7_16 (High Definition Audio controller)
+ *    Intel HECI (as embedded in ich9m)
  */
 #define PCI_VENDOR_ID_INTEL             0x8086
 #define PCI_DEVICE_ID_INTEL_82439TX     0x7100
 #define PCI_DEVICE_ID_INTEL_82545EM     0x100f
 #define PCI_DEVICE_ID_INTEL_82546EB     0x1010
 #define PCI_DEVICE_ID_INTEL_ICH7_16     0x27d8
+#define PCI_DEVICE_ID_INTEL_HECI        0x2a74
 
 
 /************* Strings for IDE Identity Fields **************************/
index 452e9a435b945165b05cad1f71d5a7bcbec0f162..cb1b6ed92cab997fa446f73254f8186b0b1a4411 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 7e2bcbed468139e64ec700b48e1fb6d7344e72bb..280d4522554f32cbde325e0e8d6aa8da1367064e 100644 (file)
@@ -193,10 +193,16 @@ do {                                                                      \
 
 /*
  * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28.
+ *
+ * Unfortunately it is not true. While some distros may have done it the
+ * change has never made it into vanilla 2.4 kernel. Instead of testing
+ * particular kernel versions let's just test for presence of DEFINE_WAIT
+ * when figuring out whether we need to provide replacement implementation
+ * or simply alias existing one.
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \
-   (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39))
+
+#ifndef DEFINE_WAIT
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DECLARE_WAITQUEUE(_wait, current)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -211,7 +217,9 @@ do {                                                                        \
       __set_current_state(_state);                              \
       remove_wait_queue(_sleep, _wait);                         \
    } while (0)
+
 #else
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DEFINE_WAIT(_wait)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -220,6 +228,7 @@ do {                                                                        \
    prepare_to_wait(_sleep, _wait, _state)
 # define compat_finish_wait(_sleep, _wait, _state)              \
    finish_wait(_sleep, _wait)
-#endif
+
+#endif /* #ifndef DEFINE_WAIT */
 
 #endif /* __COMPAT_WAIT_H__ */
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 90ee132165d27fb4da01a085e2d1e87b851288e9..3cc2a65401a08d1c99e407a03c588ac395489136 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 7e2bcbed468139e64ec700b48e1fb6d7344e72bb..280d4522554f32cbde325e0e8d6aa8da1367064e 100644 (file)
@@ -193,10 +193,16 @@ do {                                                                      \
 
 /*
  * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28.
+ *
+ * Unfortunately it is not true. While some distros may have done it the
+ * change has never made it into vanilla 2.4 kernel. Instead of testing
+ * particular kernel versions let's just test for presence of DEFINE_WAIT
+ * when figuring out whether we need to provide replacement implementation
+ * or simply alias existing one.
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \
-   (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39))
+
+#ifndef DEFINE_WAIT
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DECLARE_WAITQUEUE(_wait, current)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -211,7 +217,9 @@ do {                                                                        \
       __set_current_state(_state);                              \
       remove_wait_queue(_sleep, _wait);                         \
    } while (0)
+
 #else
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DEFINE_WAIT(_wait)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -220,6 +228,7 @@ do {                                                                        \
    prepare_to_wait(_sleep, _wait, _state)
 # define compat_finish_wait(_sleep, _wait, _state)              \
    finish_wait(_sleep, _wait)
-#endif
+
+#endif /* #ifndef DEFINE_WAIT */
 
 #endif /* __COMPAT_WAIT_H__ */
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 5c6e8f06489118271c5e2837e02f5a41bbe7aa09..2cb9124e880e9e307410bff7c6a7a71956ca540c 100644 (file)
@@ -92,7 +92,8 @@
  *    Intel 82443BX (440 BX North Bridge and AGP Bridge)
  *    Intel 82545EM (e1000, server adapter, single port)
  *    Intel 82546EB (e1000, server adapter, dual port)
- *    Intel ICH7_16 (Hight Definition Audio controller)
+ *    Intel ICH7_16 (High Definition Audio controller)
+ *    Intel HECI (as embedded in ich9m)
  */
 #define PCI_VENDOR_ID_INTEL             0x8086
 #define PCI_DEVICE_ID_INTEL_82439TX     0x7100
 #define PCI_DEVICE_ID_INTEL_82545EM     0x100f
 #define PCI_DEVICE_ID_INTEL_82546EB     0x1010
 #define PCI_DEVICE_ID_INTEL_ICH7_16     0x27d8
+#define PCI_DEVICE_ID_INTEL_HECI        0x2a74
 
 
 /************* Strings for IDE Identity Fields **************************/
index 5c36b1ede97a7b1ff508d731a981c45ed2923941..ca948a5775eda3dc4e0250246d21e1eba70bebbb 100644 (file)
@@ -16,7 +16,7 @@
  *
  *********************************************************/
 
-/* 
+/*
  * vmciGuestKernelAPI.h --
  *
  *    Kernel API exported from the VMCI guest driver.
 #include "vmci_defs.h"
 #include "vmci_call_defs.h"
 
-#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
-   /* XXX TODO for other guests. */
-#  include "vmci_queue_pair.h"
-#endif
+#include "vmci_queue_pair.h"
 
 /* VMCI Device Usage API. */
 Bool VMCI_DeviceGet(void);
@@ -63,19 +60,16 @@ uint32 VMCI_Version(void);
 typedef void (*VMCI_EventCB)(VMCIId subID, VMCI_EventData *ed,
                             void *clientData);
 
-int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback, 
+int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback,
                         void *callbackData, VMCIId *subID);
 int VMCIEvent_Unsubscribe(VMCIId subID);
 
 /* VMCI Discovery Service API. */
 int VMCIDs_Lookup(const char *name, VMCIHandle *out);
 
-#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
-/* VMCI QueuePair API.  XXX TODO for other guests. */
 int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
                         uint64 produceSize, VMCIQueue **consumeQ,
                         uint64 consumeSize, VMCIId peer, uint32 flags);
 int VMCIQueuePair_Detach(VMCIHandle handle);
-#endif
 
 #endif /* !__VMCI_GUESTKERNELAPI_H__ */
index 257fdfe1395ceade89f2e214869b5ed7d34e11d9..6aa3d1326150cc167cd5d2445de6c4b87efbe4c6 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 3c73fb532823059cfcf303251bf8ac48113ce70a..ae0e039ad4c4c59d3b65d1413520b272e5e2a291 100644 (file)
@@ -65,7 +65,7 @@ CC_OPTS += $(call vm_check_build, $(SRCROOT)/autoconf/maxbytes.c, -DVMW_SB_HAS_M
 CC_OPTS += -DVMW_KMEMCR_HAS_DTOR
 
 # Core driver components
-OBJS = bdhandler.o
+OBJS =  bdhandler.o
 OBJS += dentry.o
 OBJS += dir.o
 OBJS += file.o
@@ -83,15 +83,14 @@ OBJS += super.o
 OBJS +=        backdoor.o
 OBJS +=        cpName.o
 OBJS +=        cpNameLinux.o
-OBJS += cpNameLite.o
+OBJS +=        cpNameLite.o
 OBJS +=        hgfsBd.o
-OBJS +=        hgfsEscapeLinux.o
+OBJS +=        hgfsEscape.o
 OBJS +=        hgfsUtil.o
 OBJS +=        kernelStubsLinux.o
 OBJS +=        message.o
-OBJS +=  messageBackdoor.o
+OBJS +=        messageBackdoor.o
 OBJS +=        rpcout.o
-OBJS +=        hgfsEscape.o
 
 ifeq ($(MACHINE),x86_64)
 OBJS += backdoorGcc64.o
index 7e2bcbed468139e64ec700b48e1fb6d7344e72bb..280d4522554f32cbde325e0e8d6aa8da1367064e 100644 (file)
@@ -193,10 +193,16 @@ do {                                                                      \
 
 /*
  * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28.
+ *
+ * Unfortunately it is not true. While some distros may have done it the
+ * change has never made it into vanilla 2.4 kernel. Instead of testing
+ * particular kernel versions let's just test for presence of DEFINE_WAIT
+ * when figuring out whether we need to provide replacement implementation
+ * or simply alias existing one.
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \
-   (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39))
+
+#ifndef DEFINE_WAIT
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DECLARE_WAITQUEUE(_wait, current)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -211,7 +217,9 @@ do {                                                                        \
       __set_current_state(_state);                              \
       remove_wait_queue(_sleep, _wait);                         \
    } while (0)
+
 #else
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DEFINE_WAIT(_wait)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -220,6 +228,7 @@ do {                                                                        \
    prepare_to_wait(_sleep, _wait, _state)
 # define compat_finish_wait(_sleep, _wait, _state)              \
    finish_wait(_sleep, _wait)
-#endif
+
+#endif /* #ifndef DEFINE_WAIT */
 
 #endif /* __COMPAT_WAIT_H__ */
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 337fd8cd9c82dbe09f8121f8a936bb4482a5a1f5..75bf8dd774111d34cb666b5567031aadd0c7c362 100644 (file)
@@ -639,6 +639,7 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #define CPUID_MODEL_NEHALEM_1A 0x1a  // Nehalem / Gainestown
 #define CPUID_MODEL_ATOM_1C    0x1c  // Silverthorne / Diamondville
 #define CPUID_MODEL_CORE_1D    0x1d  // Dunnington
+#define CPUID_MODEL_NEHALEM_1E 0x1e  // Lynnfield
 
 #define CPUID_MODEL_PIII_07    7
 #define CPUID_MODEL_PIII_08    8
@@ -758,19 +759,18 @@ CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1.
            model == CPUID_MODEL_CORE_1D);
 }
 
-
 /*
- * Intel Nehalem processors are: Nehalem, Gainestown.
+ * Intel Nehalem processors are: Nehalem, Gainestown, Lynnfield.
  */
 static INLINE Bool
 CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
 {
    /* Assumes the CPU manufacturer is Intel. */
    return CPUID_FAMILY_IS_P6(v) &&
-          CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A;
+          (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A ||
+           CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1E);
 }
 
-
 static INLINE Bool
 CPUID_FAMILY_IS_K7(uint32 _eax)
 {
index 7da9af69ab29acf114e5f9e150c152b401364d72..dcae9b7cc756322d459bc00c45fb31e333ed4404 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 7e2bcbed468139e64ec700b48e1fb6d7344e72bb..280d4522554f32cbde325e0e8d6aa8da1367064e 100644 (file)
@@ -193,10 +193,16 @@ do {                                                                      \
 
 /*
  * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28.
+ *
+ * Unfortunately it is not true. While some distros may have done it the
+ * change has never made it into vanilla 2.4 kernel. Instead of testing
+ * particular kernel versions let's just test for presence of DEFINE_WAIT
+ * when figuring out whether we need to provide replacement implementation
+ * or simply alias existing one.
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \
-   (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39))
+
+#ifndef DEFINE_WAIT
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DECLARE_WAITQUEUE(_wait, current)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -211,7 +217,9 @@ do {                                                                        \
       __set_current_state(_state);                              \
       remove_wait_queue(_sleep, _wait);                         \
    } while (0)
+
 #else
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DEFINE_WAIT(_wait)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -220,6 +228,7 @@ do {                                                                        \
    prepare_to_wait(_sleep, _wait, _state)
 # define compat_finish_wait(_sleep, _wait, _state)              \
    finish_wait(_sleep, _wait)
-#endif
+
+#endif /* #ifndef DEFINE_WAIT */
 
 #endif /* __COMPAT_WAIT_H__ */
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 7c07608bcad556bd409b25dd8a8fd6c727d9ff1b..d9e0a42e82fc876ff4cc07c97eeaf029bff40516 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 9e55b7b83ac3961ea21668d7d1bc1dba588e0aff..add04de58f5524c82129f77f22c8e5018dcfb6b4 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 6117b1aee4a410fcea4d92ede7b56c7aa3904d68..de5e650c954481cc085d5c51f94dd9f1aeb1ae89 100644 (file)
@@ -178,6 +178,23 @@ compat_alloc_netdev(int priv_size,
 #   define compat_netdev_priv(netdev)   netdev_priv(netdev)
 #endif
 
+/*
+ * All compat_* business is good but when we can we should just provide
+ * missing implementation to ease upstreaming task.
+ */
+#ifndef HAVE_ALLOC_NETDEV
+#define alloc_netdev(sz, name, setup)  compat_alloc_netdev(sz, name, setup)
+#define alloc_etherdev(sz)             compat_alloc_etherdev(sz)
+#endif
+
+#ifndef HAVE_FREE_NETDEV
+#define free_netdev(dev)               kfree(dev)
+#endif
+
+#ifndef HAVE_NETDEV_PRIV
+#define netdev_priv(dev)               ((dev)->priv)
+#endif
+
 #if defined(NETDEV_TX_OK)
 #   define COMPAT_NETDEV_TX_OK    NETDEV_TX_OK
 #   define COMPAT_NETDEV_TX_BUSY  NETDEV_TX_BUSY
@@ -186,55 +203,56 @@ compat_alloc_netdev(int priv_size,
 #   define COMPAT_NETDEV_TX_BUSY  1
 #endif
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
+#ifndef HAVE_NETIF_QUEUE
 static inline void
-compat_netif_start_queue(struct device *dev)
+netif_start_queue(struct device *dev)
 {
    clear_bit(0, &dev->tbusy);
 }
 
 static inline void
-compat_netif_stop_queue(struct device *dev)
+netif_stop_queue(struct device *dev)
 {
    set_bit(0, &dev->tbusy);
 }
 
 static inline int
-compat_netif_queue_stopped(struct device *dev)
+netif_queue_stopped(struct device *dev)
 {
    return test_bit(0, &dev->tbusy);
 }
 
 static inline void
-compat_netif_wake_queue(struct device *dev)
+netif_wake_queue(struct device *dev)
 {
    clear_bit(0, &dev->tbusy);
    mark_bh(NET_BH);
 }
 
 static inline int
-compat_netif_running(struct device *dev)
+netif_running(struct device *dev)
 {
    return dev->start == 0;
 }
 
 static inline int
-compat_netif_carrier_ok(struct device *dev)
+netif_carrier_ok(struct device *dev)
 {
    return 1;
 }
 
 static inline void
-compat_netif_carrier_on(struct device *dev)
+netif_carrier_on(struct device *dev)
 {
 }
 
 static inline void
-compat_netif_carrier_off(struct device *dev)
+netif_carrier_off(struct device *dev)
 {
 }
+#endif
 
-#else
+/* Keep compat_* defines for now */
 #define compat_netif_start_queue(dev)   netif_start_queue(dev)
 #define compat_netif_stop_queue(dev)    netif_stop_queue(dev)
 #define compat_netif_queue_stopped(dev) netif_queue_stopped(dev)
@@ -243,7 +261,6 @@ compat_netif_carrier_off(struct device *dev)
 #define compat_netif_carrier_ok(dev)    netif_carrier_ok(dev)
 #define compat_netif_carrier_on(dev)    netif_carrier_on(dev)
 #define compat_netif_carrier_off(dev)   netif_carrier_off(dev)
-#endif
 
 /* unregister_netdevice_notifier was not safe prior to 2.6.17 */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) && \
@@ -266,7 +283,15 @@ static inline int compat_unregister_netdevice_notifier(struct notifier_block *nb
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
 #define compat_netif_napi_add(dev, napi, poll, quota) \
    netif_napi_add(dev, napi, poll, quota)
+
+#ifdef VMW_NETIF_SINGLE_NAPI_PARM
+#define compat_netif_rx_complete(dev, napi) netif_rx_complete(napi)
+#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(napi)
+#else
+#define compat_netif_rx_complete(dev, napi) netif_rx_complete(dev, napi)
 #define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev, napi)
+#endif
+
 #define compat_napi_enable(dev, napi)       napi_enable(napi)
 #define compat_napi_disable(dev, napi)      napi_disable(napi)
 #else
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 5c6e8f06489118271c5e2837e02f5a41bbe7aa09..2cb9124e880e9e307410bff7c6a7a71956ca540c 100644 (file)
@@ -92,7 +92,8 @@
  *    Intel 82443BX (440 BX North Bridge and AGP Bridge)
  *    Intel 82545EM (e1000, server adapter, single port)
  *    Intel 82546EB (e1000, server adapter, dual port)
- *    Intel ICH7_16 (Hight Definition Audio controller)
+ *    Intel ICH7_16 (High Definition Audio controller)
+ *    Intel HECI (as embedded in ich9m)
  */
 #define PCI_VENDOR_ID_INTEL             0x8086
 #define PCI_DEVICE_ID_INTEL_82439TX     0x7100
 #define PCI_DEVICE_ID_INTEL_82545EM     0x100f
 #define PCI_DEVICE_ID_INTEL_82546EB     0x1010
 #define PCI_DEVICE_ID_INTEL_ICH7_16     0x27d8
+#define PCI_DEVICE_ID_INTEL_HECI        0x2a74
 
 
 /************* Strings for IDE Identity Fields **************************/
index 3c6d95edaca360e58963c1506e2da87b342147d9..c907ed441a7a604d9374c0bf393ccc3c8c87b0ee 100644 (file)
 #include "compat_pci_mapping.h"
 #include "compat_init.h"
 #include "compat_timer.h"
-#include <asm/dma.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
 #include "compat_ethtool.h"
 #include "compat_netdevice.h"
 #include "compat_skbuff.h"
 #endif
 #include "compat_interrupt.h"
 
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+
 #include "vm_basic_types.h"
 #include "vmnet_def.h"
 #include "vmxnet_def.h"
@@ -198,7 +198,7 @@ static struct pci_driver vmxnet_driver = {
 static int
 vmxnet_change_mtu(struct net_device *dev, int new_mtu)
 {
-   struct Vmxnet_Private *lp = (struct Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
 
    if (new_mtu < VMXNET_MIN_MTU || new_mtu > VMXNET_MAX_MTU) {
       return -EINVAL;
@@ -272,7 +272,7 @@ static void
 vmxnet_get_drvinfo(struct net_device *dev,
                    struct ethtool_drvinfo *drvinfo)
 {
-   struct Vmxnet_Private *lp = dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
 
    strncpy(drvinfo->driver, vmxnet_driver.name, sizeof(drvinfo->driver));
    drvinfo->driver[sizeof(drvinfo->driver) - 1] = '\0';
@@ -310,7 +310,7 @@ static int
 vmxnet_set_tso(struct net_device *dev, u32 data)
 {
    if (data) {
-      struct Vmxnet_Private *lp = (struct Vmxnet_Private *)dev->priv;
+      struct Vmxnet_Private *lp = netdev_priv(dev);
 
       if (!lp->tso) {
          return -EINVAL;
@@ -462,7 +462,7 @@ vmxnet_set_tso(struct net_device *dev, void *addr)
    }
 
    if (value.data) {
-      struct Vmxnet_Private *lp = (struct Vmxnet_Private *)dev->priv;
+      struct Vmxnet_Private *lp = netdev_priv(dev);
 
       if (!lp->tso) {
          return -EINVAL;
@@ -634,7 +634,7 @@ vmxnet_exit(void)
 static void
 vmxnet_tx_timeout(struct net_device *dev)
 {
-   compat_netif_wake_queue(dev);
+   netif_wake_queue(dev);
 }
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) */
 
@@ -660,11 +660,10 @@ vmxnet_link_check(unsigned long data)   // IN: netdevice pointer
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43)
    struct net_device *dev = (struct net_device *)data;
-   struct Vmxnet_Private *lp;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
    uint32 status;
    int ok;
 
-   lp = dev->priv;
    status = inl(dev->base_addr + VMXNET_STATUS_ADDR);
    ok = (status & VMXNET_STATUS_CONNECTED) != 0;
    if (ok != netif_carrier_ok(dev)) {
@@ -839,13 +838,13 @@ vmxnet_probe_device(struct pci_dev             *pdev, // IN: vmxnet PCI device
       }
    }
 
-   dev = compat_alloc_etherdev(sizeof *lp);
+   dev = alloc_etherdev(sizeof *lp);
    if (!dev) {
       printk(KERN_ERR "Unable to allocate ethernet device\n");
       goto morph_back;
    }
 
-   lp = dev->priv;
+   lp = netdev_priv(dev);
    lp->pdev = pdev;
 
    dev->base_addr = ioaddr;
@@ -1099,14 +1098,14 @@ free_dev_dd:
 #endif
    compat_pci_unmap_single(lp->pdev, lp->ddPA, lp->ddSize, PCI_DMA_BIDIRECTIONAL);
    kfree(lp->dd);
-free_dev:;
-   compat_free_netdev(dev);
-morph_back:;
+free_dev:
+   free_netdev(dev);
+morph_back:
    if (morphed) {
       /* Morph back to LANCE hw. */
       outw(LANCE_CHIP, ioaddr - MORPH_PORT_SIZE);
    }
-release_reg:;
+release_reg:
    release_region(reqIOAddr, reqIOSize);
 pci_disable:;
    compat_pci_disable_device(pdev);
@@ -1133,7 +1132,7 @@ static void
 vmxnet_remove_device(struct pci_dev* pdev)
 {
    struct net_device *dev = pci_get_drvdata(pdev);
-   struct Vmxnet_Private *lp = dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
 
    /*
     * Do this before device is gone so we never call netif_carrier_* after
@@ -1184,7 +1183,7 @@ vmxnet_remove_device(struct pci_dev* pdev)
 
    compat_pci_unmap_single(lp->pdev, lp->ddPA, lp->ddSize, PCI_DMA_BIDIRECTIONAL);
    kfree(lp->dd);
-   compat_free_netdev(dev);
+   free_netdev(dev);
    compat_pci_disable_device(pdev);
 }
 
@@ -1207,7 +1206,7 @@ vmxnet_remove_device(struct pci_dev* pdev)
 static int
 vmxnet_init_ring(struct net_device *dev)
 {
-   struct Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
    Vmxnet2_DriverData *dd = lp->dd;
    unsigned int i;
    size_t offset;
@@ -1335,7 +1334,7 @@ vmxnet_init_ring(struct net_device *dev)
 static int
 vmxnet_open(struct net_device *dev)
 {
-   struct Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
    unsigned int ioaddr = dev->base_addr;
    uint32 ddPA;
 
@@ -1365,7 +1364,7 @@ vmxnet_open(struct net_device *dev)
 #endif
 
    lp->dd->txStopped = FALSE;
-   compat_netif_start_queue(dev);
+   netif_start_queue(dev);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
    dev->interrupt = 0;
@@ -1589,7 +1588,7 @@ vmxnet_map_pkt(struct sk_buff *skb,
 static void
 check_tx_queue(struct net_device *dev)
 {
-   Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
    Vmxnet2_DriverData *dd = lp->dd;
    int completed = 0;
 
@@ -1625,8 +1624,8 @@ check_tx_queue(struct net_device *dev)
       lp->numTxPending -= completed;
 
       // XXX conditionally wake up the queue based on the # of freed entries
-      if (compat_netif_queue_stopped(dev)) {
-        compat_netif_wake_queue(dev);
+      if (netif_queue_stopped(dev)) {
+         netif_wake_queue(dev);
          dd->txStopped = FALSE;
       }
    }
@@ -1657,7 +1656,7 @@ Vmxnet_TxStatus
 vmxnet_tx(struct sk_buff *skb, struct net_device *dev)
 {
    Vmxnet_TxStatus status = VMXNET_DEFER_TRANSMIT;
-   struct Vmxnet_Private *lp = (struct Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
    Vmxnet2_DriverData *dd = lp->dd;
    unsigned long flags;
    Vmxnet2_TxRingEntry *xre;
@@ -1698,7 +1697,7 @@ vmxnet_tx(struct sk_buff *skb, struct net_device *dev)
       /* check for the availability of tx ring entries */
       if (dd->txRingLength - lp->numTxPending < txEntries) {
          dd->txStopped = TRUE;
-         compat_netif_stop_queue(dev);
+         netif_stop_queue(dev);
          check_tx_queue(dev);
 
          spin_unlock_irqrestore(&lp->txLock, flags);
@@ -1828,7 +1827,7 @@ vmxnet_tx(struct sk_buff *skb, struct net_device *dev)
 
       if (lp->txBufInfo[dd->txDriverNext].skb != NULL) {
          dd->txStopped = TRUE;
-         compat_netif_stop_queue(dev);
+         netif_stop_queue(dev);
          check_tx_queue(dev);
 
          spin_unlock_irqrestore(&lp->txLock, flags);
@@ -2057,7 +2056,7 @@ vmxnet_rx_frags(Vmxnet_Private *lp, struct sk_buff *skb)
 static int
 vmxnet_rx(struct net_device *dev)
 {
-   Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
    Vmxnet2_DriverData *dd = lp->dd;
 
    if (!lp->devOpen) {
@@ -2187,7 +2186,7 @@ vmxnet_interrupt(int irq, void *dev_id)
    }
 
 
-   lp = (struct Vmxnet_Private *)dev->priv;
+   lp = netdev_priv(dev);
    outl(VMXNET_CMD_INTR_ACK, dev->base_addr + VMXNET_COMMAND_ADDR);
 
    dd = lp->dd;
@@ -2208,8 +2207,8 @@ vmxnet_interrupt(int irq, void *dev_id)
       spin_unlock(&lp->txLock);
    }
 
-   if (compat_netif_queue_stopped(dev) && !lp->dd->txStopped) {
-      compat_netif_wake_queue(dev);
+   if (netif_queue_stopped(dev) && !lp->dd->txStopped) {
+      netif_wake_queue(dev);
    }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)
@@ -2269,7 +2268,7 @@ static int
 vmxnet_close(struct net_device *dev)
 {
    unsigned int ioaddr = dev->base_addr;
-   Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
    int i;
    unsigned long flags;
 
@@ -2281,7 +2280,7 @@ vmxnet_close(struct net_device *dev)
    dev->start = 0;
 #endif
 
-   compat_netif_stop_queue(dev);
+   netif_stop_queue(dev);
 
    lp->devOpen = FALSE;
 
@@ -2362,7 +2361,7 @@ vmxnet_close(struct net_device *dev)
 static int
 vmxnet_load_multicast (struct net_device *dev)
 {
-    Vmxnet_Private *lp = (Vmxnet_Private *) dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
     volatile u16 *mcast_table = (u16 *)lp->dd->LADRF;
     struct dev_mc_list *dmi = dev->mc_list;
     char *addrs;
@@ -2423,7 +2422,7 @@ static void
 vmxnet_set_multicast_list(struct net_device *dev)
 {
    unsigned int ioaddr = dev->base_addr;
-   Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
+   struct Vmxnet_Private *lp = netdev_priv(dev);
 
    lp->dd->ifflags = ~(VMXNET_IFF_PROMISC
                       |VMXNET_IFF_BROADCAST
@@ -2473,7 +2472,7 @@ vmxnet_set_mac_address(struct net_device *dev, void *p)
    unsigned int ioaddr = dev->base_addr;
    int i;
 
-   if (compat_netif_running(dev))
+   if (netif_running(dev))
       return -EBUSY;
 
    memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -2503,7 +2502,7 @@ vmxnet_set_mac_address(struct net_device *dev, void *p)
 static struct net_device_stats *
 vmxnet_get_stats(struct net_device *dev)
 {
-   Vmxnet_Private *lp = (Vmxnet_Private *)dev->priv;
+   Vmxnet_Private *lp = netdev_priv(dev);
 
    return &lp->stats;
 }
index 81bb2b7c92ddcec103d27d37688683413fce6753..d340b243d03bbee6001f6347877c5d878ab2d01f 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 4680dcb9501fce5817bcc33b773a62278297ad85..a55d6c5f0c2a09e9be1f139c3cb83b62849ce052 100644 (file)
@@ -26,6 +26,7 @@ INCLUDE := -I.
 EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE)
 
 EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/autoconf/skblin.c, -DVMW_SKB_LINEARIZE_2618, )
+EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/autoconf/netif_num_params.c, -DVMW_NETIF_SINGLE_NAPI_PARM, )
 
 obj-m += $(DRIVER).o
 
index 31c3600dbb437f88c95b6e7f8a9eeffdf44f2cba..6210aadfe58cf810e8102130f845c1eb35bdee69 100644 (file)
@@ -61,6 +61,7 @@ INCLUDE += $(shell $(CC) $(CC_OPTS) $(INCLUDE) \
           | sed -n -e 's!^APATH!-I$(HEADER_DIR)/asm!p')
 
 CC_OPTS += $(call vm_check_build, $(SRCROOT)/autoconf/skblin.c, -DVMW_SKB_LINEARIZE_2618, )
+CC_OPTS += $(call vm_check_build, $(SRCROOT)/autoconf/netif_num_params.c, -DVMW_NETIF_SINGLE_NAPI_PARM, )
 
 OBJS := vmxnet3.o
 
diff --git a/open-vm-tools/modules/linux/vmxnet3/autoconf/netif_num_params.c b/open-vm-tools/modules/linux/vmxnet3/autoconf/netif_num_params.c
new file mode 100644 (file)
index 0000000..38b31ce
--- /dev/null
@@ -0,0 +1,37 @@
+/*********************************************************
+ * Copyright (C) 2009 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
+ *
+ *********************************************************/
+
+/*
+ * Detect whether netif_rx_complete (and netif_rx_schedule) take a single
+ * napi_struct argument. The foundation was laid whith introducing Generic
+ * Receive Offload infrastructure but sropping unneeded net_device argument
+ * did not happen till few commits later so we can't simply test for presence
+ * of NETIF_F_GRO.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/netdevice.h>
+
+#ifndef NETIF_F_GRO
+#   error This compile test intentionally fails.
+#endif
+
+void test_netif_rx_complete(struct napi_struct *napi)
+{
+   netif_rx_complete(napi);
+}
index 6117b1aee4a410fcea4d92ede7b56c7aa3904d68..de5e650c954481cc085d5c51f94dd9f1aeb1ae89 100644 (file)
@@ -178,6 +178,23 @@ compat_alloc_netdev(int priv_size,
 #   define compat_netdev_priv(netdev)   netdev_priv(netdev)
 #endif
 
+/*
+ * All compat_* business is good but when we can we should just provide
+ * missing implementation to ease upstreaming task.
+ */
+#ifndef HAVE_ALLOC_NETDEV
+#define alloc_netdev(sz, name, setup)  compat_alloc_netdev(sz, name, setup)
+#define alloc_etherdev(sz)             compat_alloc_etherdev(sz)
+#endif
+
+#ifndef HAVE_FREE_NETDEV
+#define free_netdev(dev)               kfree(dev)
+#endif
+
+#ifndef HAVE_NETDEV_PRIV
+#define netdev_priv(dev)               ((dev)->priv)
+#endif
+
 #if defined(NETDEV_TX_OK)
 #   define COMPAT_NETDEV_TX_OK    NETDEV_TX_OK
 #   define COMPAT_NETDEV_TX_BUSY  NETDEV_TX_BUSY
@@ -186,55 +203,56 @@ compat_alloc_netdev(int priv_size,
 #   define COMPAT_NETDEV_TX_BUSY  1
 #endif
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
+#ifndef HAVE_NETIF_QUEUE
 static inline void
-compat_netif_start_queue(struct device *dev)
+netif_start_queue(struct device *dev)
 {
    clear_bit(0, &dev->tbusy);
 }
 
 static inline void
-compat_netif_stop_queue(struct device *dev)
+netif_stop_queue(struct device *dev)
 {
    set_bit(0, &dev->tbusy);
 }
 
 static inline int
-compat_netif_queue_stopped(struct device *dev)
+netif_queue_stopped(struct device *dev)
 {
    return test_bit(0, &dev->tbusy);
 }
 
 static inline void
-compat_netif_wake_queue(struct device *dev)
+netif_wake_queue(struct device *dev)
 {
    clear_bit(0, &dev->tbusy);
    mark_bh(NET_BH);
 }
 
 static inline int
-compat_netif_running(struct device *dev)
+netif_running(struct device *dev)
 {
    return dev->start == 0;
 }
 
 static inline int
-compat_netif_carrier_ok(struct device *dev)
+netif_carrier_ok(struct device *dev)
 {
    return 1;
 }
 
 static inline void
-compat_netif_carrier_on(struct device *dev)
+netif_carrier_on(struct device *dev)
 {
 }
 
 static inline void
-compat_netif_carrier_off(struct device *dev)
+netif_carrier_off(struct device *dev)
 {
 }
+#endif
 
-#else
+/* Keep compat_* defines for now */
 #define compat_netif_start_queue(dev)   netif_start_queue(dev)
 #define compat_netif_stop_queue(dev)    netif_stop_queue(dev)
 #define compat_netif_queue_stopped(dev) netif_queue_stopped(dev)
@@ -243,7 +261,6 @@ compat_netif_carrier_off(struct device *dev)
 #define compat_netif_carrier_ok(dev)    netif_carrier_ok(dev)
 #define compat_netif_carrier_on(dev)    netif_carrier_on(dev)
 #define compat_netif_carrier_off(dev)   netif_carrier_off(dev)
-#endif
 
 /* unregister_netdevice_notifier was not safe prior to 2.6.17 */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) && \
@@ -266,7 +283,15 @@ static inline int compat_unregister_netdevice_notifier(struct notifier_block *nb
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
 #define compat_netif_napi_add(dev, napi, poll, quota) \
    netif_napi_add(dev, napi, poll, quota)
+
+#ifdef VMW_NETIF_SINGLE_NAPI_PARM
+#define compat_netif_rx_complete(dev, napi) netif_rx_complete(napi)
+#define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(napi)
+#else
+#define compat_netif_rx_complete(dev, napi) netif_rx_complete(dev, napi)
 #define compat_netif_rx_schedule(dev, napi) netif_rx_schedule(dev, napi)
+#endif
+
 #define compat_napi_enable(dev, napi)       napi_enable(napi)
 #define compat_napi_disable(dev, napi)      napi_disable(napi)
 #else
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 5c6e8f06489118271c5e2837e02f5a41bbe7aa09..2cb9124e880e9e307410bff7c6a7a71956ca540c 100644 (file)
@@ -92,7 +92,8 @@
  *    Intel 82443BX (440 BX North Bridge and AGP Bridge)
  *    Intel 82545EM (e1000, server adapter, single port)
  *    Intel 82546EB (e1000, server adapter, dual port)
- *    Intel ICH7_16 (Hight Definition Audio controller)
+ *    Intel ICH7_16 (High Definition Audio controller)
+ *    Intel HECI (as embedded in ich9m)
  */
 #define PCI_VENDOR_ID_INTEL             0x8086
 #define PCI_DEVICE_ID_INTEL_82439TX     0x7100
 #define PCI_DEVICE_ID_INTEL_82545EM     0x100f
 #define PCI_DEVICE_ID_INTEL_82546EB     0x1010
 #define PCI_DEVICE_ID_INTEL_ICH7_16     0x27d8
+#define PCI_DEVICE_ID_INTEL_HECI        0x2a74
 
 
 /************* Strings for IDE Identity Fields **************************/
index bbc9631addff0127f1b0e6f09f3c226f1772f0af..d413dc113f664bb03b5fd87b9c228766da70c6b7 100644 (file)
@@ -155,7 +155,7 @@ static struct pci_driver vmxnet3_driver = {
 #endif
 };
 
-static int disable_lro = 0;
+static int disable_lro;
 
 /*
  *----------------------------------------------------------------------------
@@ -381,12 +381,11 @@ vmxnet3_poll(struct napi_struct *napi, int budget)
 {
    struct vmxnet3_adapter *adapter = container_of(napi, struct vmxnet3_adapter, napi);
    int rxd_done, txd_done;
-   struct net_device *netdev = adapter->netdev;
 
    vmxnet3_do_poll(adapter, budget, &txd_done, &rxd_done);
 
    if (rxd_done < budget) {
-      netif_rx_complete(netdev, napi);
+      compat_netif_rx_complete(adapter->netdev, napi);
       vmxnet3_enable_intr(adapter, 0);
    }
    return rxd_done;
@@ -410,7 +409,7 @@ static int
 vmxnet3_poll(struct net_device *poll_dev, int *budget)
 {
    int rxd_done, txd_done, quota;
-   struct vmxnet3_adapter *adapter = poll_dev->priv;
+   struct vmxnet3_adapter *adapter = netdev_priv(poll_dev);
 
    quota = min(*budget, poll_dev->quota);
 
@@ -452,7 +451,7 @@ vmxnet3_intr(int irq, void *dev_id)
 #endif
 {
    struct net_device *dev = dev_id;
-   struct vmxnet3_adapter *adapter = dev->priv;
+   struct vmxnet3_adapter *adapter = netdev_priv(dev);
 
    if (UNLIKELY(adapter->intr.type == VMXNET3_IT_INTX)) {
       uint32 icr = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_ICR);
@@ -468,7 +467,7 @@ vmxnet3_intr(int irq, void *dev_id)
       vmxnet3_disable_intr(adapter, 0);
    }
 
-   compat_netif_rx_schedule(dev, &adapter->napi); 
+   compat_netif_rx_schedule(dev, &adapter->napi);
 
 #else
    vmxnet3_tq_tx_complete(&adapter->tx_queue, adapter);
index fb4334e6291af3af85daf59979f91e7ab3f39a60..27e7577ad67da80560641200c34245cb0692408a 100644 (file)
 #ifndef _VMXNET3_VERSION_H_
 #define _VMXNET3_VERSION_H_
 
-#define VMXNET3_DRIVER_VERSION          1.0.0.32
-#define VMXNET3_DRIVER_VERSION_COMMAS   1,0,0,32
-#define VMXNET3_DRIVER_VERSION_STRING   "1.0.0.32"
+#define VMXNET3_DRIVER_VERSION          1.0.0.33
+#define VMXNET3_DRIVER_VERSION_COMMAS   1,0,0,33
+#define VMXNET3_DRIVER_VERSION_STRING   "1.0.0.33"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01000020
+#define VMXNET3_DRIVER_VERSION_NUM      0x01000021
 
 #endif /* _VMXNET3_VERSION_H_ */
index e3f86640bbfb85bf2bb722084aae49e9e9444e42..b9f1b98673ff6b5543bf128cc13f5c8ad3b4a8fd 100644 (file)
@@ -108,16 +108,6 @@ postbuild:: ;
 $(DRIVER_KO): prebuild
        make -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) modules
        make -C $$PWD SRCROOT=$$PWD/$(SRCROOT) postbuild
-
-else
-
-ifneq ($(VM_CCVER), $(VMCCVER))
-$(warning *** Inappropriate build environment: you wanted to use gcc \
- version $(VM_CCVER) while kernel attempts to use gcc version $(VMCCVER).)
-$(error For proper build you'll have to replace $(CC) with symbolic \
- link to $(VM_CC))
-endif
-
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
index 7e2bcbed468139e64ec700b48e1fb6d7344e72bb..280d4522554f32cbde325e0e8d6aa8da1367064e 100644 (file)
@@ -193,10 +193,16 @@ do {                                                                      \
 
 /*
  * DEFINE_WAIT() and friends were added in 2.5.39 and backported to 2.4.28.
+ *
+ * Unfortunately it is not true. While some distros may have done it the
+ * change has never made it into vanilla 2.4 kernel. Instead of testing
+ * particular kernel versions let's just test for presence of DEFINE_WAIT
+ * when figuring out whether we need to provide replacement implementation
+ * or simply alias existing one.
  */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 28) || \
-   (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && \
-    LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 39))
+
+#ifndef DEFINE_WAIT
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DECLARE_WAITQUEUE(_wait, current)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -211,7 +217,9 @@ do {                                                                        \
       __set_current_state(_state);                              \
       remove_wait_queue(_sleep, _wait);                         \
    } while (0)
+
 #else
+
 # define COMPAT_DEFINE_WAIT(_wait)                              \
    DEFINE_WAIT(_wait)
 # define compat_init_prepare_to_wait(_sleep, _wait, _state)     \
@@ -220,6 +228,7 @@ do {                                                                        \
    prepare_to_wait(_sleep, _wait, _state)
 # define compat_finish_wait(_sleep, _wait, _state)              \
    finish_wait(_sleep, _wait)
-#endif
+
+#endif /* #ifndef DEFINE_WAIT */
 
 #endif /* __COMPAT_WAIT_H__ */
index c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592..7f4b4d645a6c1009318526f275cf6cbab902c0a4 100644 (file)
@@ -362,9 +362,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index 638e9ce6c95c9a90f80e430910819112e527b499..e2bbc89b933e4053af5b1d8a7496c9f22f604367 100644 (file)
@@ -883,11 +883,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 5c36b1ede97a7b1ff508d731a981c45ed2923941..ca948a5775eda3dc4e0250246d21e1eba70bebbb 100644 (file)
@@ -16,7 +16,7 @@
  *
  *********************************************************/
 
-/* 
+/*
  * vmciGuestKernelAPI.h --
  *
  *    Kernel API exported from the VMCI guest driver.
 #include "vmci_defs.h"
 #include "vmci_call_defs.h"
 
-#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
-   /* XXX TODO for other guests. */
-#  include "vmci_queue_pair.h"
-#endif
+#include "vmci_queue_pair.h"
 
 /* VMCI Device Usage API. */
 Bool VMCI_DeviceGet(void);
@@ -63,19 +60,16 @@ uint32 VMCI_Version(void);
 typedef void (*VMCI_EventCB)(VMCIId subID, VMCI_EventData *ed,
                             void *clientData);
 
-int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback, 
+int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback,
                         void *callbackData, VMCIId *subID);
 int VMCIEvent_Unsubscribe(VMCIId subID);
 
 /* VMCI Discovery Service API. */
 int VMCIDs_Lookup(const char *name, VMCIHandle *out);
 
-#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
-/* VMCI QueuePair API.  XXX TODO for other guests. */
 int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
                         uint64 produceSize, VMCIQueue **consumeQ,
                         uint64 consumeSize, VMCIId peer, uint32 flags);
 int VMCIQueuePair_Detach(VMCIHandle handle);
-#endif
 
 #endif /* !__VMCI_GUESTKERNELAPI_H__ */
index 337fd8cd9c82dbe09f8121f8a936bb4482a5a1f5..75bf8dd774111d34cb666b5567031aadd0c7c362 100644 (file)
@@ -639,6 +639,7 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #define CPUID_MODEL_NEHALEM_1A 0x1a  // Nehalem / Gainestown
 #define CPUID_MODEL_ATOM_1C    0x1c  // Silverthorne / Diamondville
 #define CPUID_MODEL_CORE_1D    0x1d  // Dunnington
+#define CPUID_MODEL_NEHALEM_1E 0x1e  // Lynnfield
 
 #define CPUID_MODEL_PIII_07    7
 #define CPUID_MODEL_PIII_08    8
@@ -758,19 +759,18 @@ CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1.
            model == CPUID_MODEL_CORE_1D);
 }
 
-
 /*
- * Intel Nehalem processors are: Nehalem, Gainestown.
+ * Intel Nehalem processors are: Nehalem, Gainestown, Lynnfield.
  */
 static INLINE Bool
 CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
 {
    /* Assumes the CPU manufacturer is Intel. */
    return CPUID_FAMILY_IS_P6(v) &&
-          CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A;
+          (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A ||
+           CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1E);
 }
 
-
 static INLINE Bool
 CPUID_FAMILY_IS_K7(uint32 _eax)
 {
index 4d0ee72e69a155662377da063afcd20cfc83c476..4f76b001a2277bfb6aa312b03f4719ade38cdee6 100644 (file)
@@ -201,6 +201,8 @@ static struct sock *__VSockVmciCreate(struct net *net,
 static void VSockVmciTestUnregister(void);
 static int VSockVmciRegisterAddressFamily(void);
 static void VSockVmciUnregisterAddressFamily(void);
+static int64 VSockVmciStreamHasData(VSockVmciSock *vsk);
+static int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk);
 
 
 /* Socket operations. */
@@ -1341,10 +1343,7 @@ VSockVmciHandleDetach(struct sock *sk) // IN
       ASSERT(vsk->produceQ);
       ASSERT(vsk->consumeQ);
 
-      if (sk->compat_sk_type == SOCK_STREAM &&
-          sk->compat_sk_state == SS_CONNECTED) {
-         compat_sock_set_done(sk);
-      }
+      compat_sock_set_done(sk);
 
       /* On a detach the peer will not be sending or receiving anymore. */
       vsk->peerShutdown = SHUTDOWN_MASK;
@@ -1355,8 +1354,7 @@ VSockVmciHandleDetach(struct sock *sk) // IN
        * queue.
        */
       sk->compat_sk_shutdown |= SEND_SHUTDOWN;
-      if (VMCIQueue_BufReady(vsk->consumeQ,
-                             vsk->produceQ, vsk->consumeSize) <= 0) {
+      if (VSockVmciStreamHasData(vsk) <= 0) {
          sk->compat_sk_shutdown |= RCV_SHUTDOWN;
          sk->compat_sk_state = SS_UNCONNECTED;
       }
@@ -1588,9 +1586,6 @@ VSockVmciRecvPktWork(compat_work_arg work)  // IN
    case SS_LISTEN:
       err = VSockVmciRecvListen(sk, pkt);
       break;
-   case SS_UNCONNECTED:
-      Log("packet received for socket in unconnected state; dropping.\n");
-      goto out;
    case SS_CONNECTING:
       /*
        * Processing of pending connections for servers goes through the
@@ -1601,14 +1596,15 @@ VSockVmciRecvPktWork(compat_work_arg work)  // IN
    case SS_CONNECTED:
       err = VSockVmciRecvConnected(sk, pkt);
       break;
-   case SS_DISCONNECTING:
-      Log("packet receieved for socket in disconnecting state; dropping.\n");
-      goto out;
-   case SS_FREE:
-      Log("packet receieved for socket in free state; dropping.\n");
-      goto out;
    default:
-      Log("socket is in invalid state; dropping packet.\n");
+      /*
+       * Because this function does not run in the same context as
+       * VSockVmciRecvStreamCB it is possible that the socket
+       * has closed. We need to let the other side know or it could
+       * be sitting in a connect and hang forever. Send a reset to prevent
+       * that.
+       */
+      VSOCK_SEND_RESET(sk, pkt);
       goto out;
    }
 
@@ -2215,6 +2211,8 @@ static int
 VSockVmciRecvConnected(struct sock *sk,      // IN
                        VSockPacket *pkt)     // IN
 {
+   VSockVmciSock *vsk;
+
    ASSERT(sk);
    ASSERT(pkt);
    ASSERT(sk->compat_sk_state == SS_CONNECTED);
@@ -2238,10 +2236,25 @@ VSockVmciRecvConnected(struct sock *sk,      // IN
       break;
 
    case VSOCK_PACKET_TYPE_RST:
-      sk->compat_sk_state = SS_DISCONNECTING;
-      sk->compat_sk_shutdown = SHUTDOWN_MASK;
-      sk->compat_sk_err = ECONNRESET;
-      sk->compat_sk_error_report(sk);
+      vsk = vsock_sk(sk);
+      /*
+       * It is possible that we sent our peer a message (e.g
+       * a WAITING_READ) right before we got notified that the peer
+       * had detached. If that happens then we can get a RST pkt back
+       * from our peer even though there is data available for us
+       * to read. In that case, don't shutdown the socket completely
+       * but instead allow the local client to finish reading data
+       * off the queuepair. Always treat a RST pkt in connected mode
+       * like a clean shutdown.
+       */
+      compat_sock_set_done(sk);
+      vsk->peerShutdown = SHUTDOWN_MASK;
+      sk->compat_sk_shutdown |= SEND_SHUTDOWN;
+      if (VSockVmciStreamHasData(vsk) <= 0) {
+        sk->compat_sk_state = SS_DISCONNECTING;
+        sk->compat_sk_shutdown = SHUTDOWN_MASK;
+      }
+      sk->compat_sk_state_change(sk);
       break;
 
    case VSOCK_PACKET_TYPE_WROTE:
@@ -3301,6 +3314,64 @@ VSockVmciUnregisterAddressFamily(void)
 }
 
 
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciStreamHasData --
+ *
+ *      Gets the amount of data available for a given stream socket's consume
+ *      queue.
+ *
+ *      Note that this assumes the socket lock is held.
+ *
+ * Results:
+ *      The amount of data available or a VMCI error code on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int64
+VSockVmciStreamHasData(VSockVmciSock *vsk) // IN
+{
+   ASSERT(vsk);
+
+   return VMCIQueue_BufReady(vsk->consumeQ,
+                            vsk->produceQ, vsk->consumeSize);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciStreamHasSpace --
+ *
+ *      Gets the amount of space available for a give stream socket's produce
+ *      queue.
+ *
+ *      Note that this assumes the socket lock is held.
+ *
+ * Results:
+ *      The amount of space available or a VMCI error code on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int64
+VSockVmciStreamHasSpace(VSockVmciSock *vsk) // IN
+{
+   ASSERT(vsk);
+
+   return VMCIQueue_FreeSpace(vsk->produceQ,
+                             vsk->consumeQ, vsk->produceSize);
+}
+
+
 /*
  * Socket operations.
  */
@@ -3831,8 +3902,7 @@ VSockVmciPoll(struct file *file,    // IN
        */
       if (!VMCI_HANDLE_INVALID(vsk->qpHandle) &&
          !(sk->compat_sk_shutdown & RCV_SHUTDOWN)) {
-        if (VMCIQueue_BufReady(vsk->consumeQ,
-                               vsk->produceQ, vsk->consumeSize)) {
+        if (VSockVmciStreamHasData(vsk)) {
            mask |= POLLIN | POLLRDNORM;
         } else {
            /*
@@ -3861,8 +3931,7 @@ VSockVmciPoll(struct file *file,    // IN
       if (sk->compat_sk_state == SS_CONNECTED) {
         if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) {
            int64 produceQFreeSpace =
-              VMCIQueue_FreeSpace(vsk->produceQ,
-                                  vsk->consumeQ, vsk->produceSize);
+              VSockVmciStreamHasSpace(vsk);
            if (produceQFreeSpace > 0) {
               mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
            } else if (produceQFreeSpace == 0) {
@@ -4406,8 +4475,7 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
       sentWrote = FALSE;
       retries = 0;
 
-      while (VMCIQueue_FreeSpace(vsk->produceQ,
-                                 vsk->consumeQ, vsk->produceSize) == 0 &&
+      while (VSockVmciStreamHasSpace(vsk) == 0 &&
              sk->compat_sk_err == 0 &&
              !(sk->compat_sk_shutdown & SEND_SHUTDOWN) &&
              !(vsk->peerShutdown & RCV_SHUTDOWN)) {
@@ -4783,9 +4851,7 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
 
    compat_init_prepare_to_wait(sk->compat_sk_sleep, &wait, TASK_INTERRUPTIBLE);
 
-   while ((ready = VMCIQueue_BufReady(vsk->consumeQ,
-                                      vsk->produceQ,
-                                      vsk->consumeSize)) < target &&
+   while ((ready = VSockVmciStreamHasData(vsk)) < target &&
           sk->compat_sk_err == 0 &&
           !(sk->compat_sk_shutdown & RCV_SHUTDOWN) &&
           !(vsk->peerShutdown & SEND_SHUTDOWN)) {
@@ -4844,8 +4910,7 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
       err = 0;
       goto outWait;
    } else if ((vsk->peerShutdown & SEND_SHUTDOWN) &&
-              VMCIQueue_BufReady(vsk->consumeQ,
-                                 vsk->produceQ, vsk->consumeSize) < target) {
+              VSockVmciStreamHasData(vsk) < target) {
       err = 0;
       goto outWait;
    }
@@ -4903,8 +4968,7 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
        * state.
        */
       if (vsk->peerShutdown & SEND_SHUTDOWN) {
-         if (VMCIQueue_BufReady(vsk->consumeQ,
-                                vsk->produceQ, vsk->consumeSize) <= 0) {
+         if (VSockVmciStreamHasData(vsk) <= 0) {
             sk->compat_sk_shutdown |= RCV_SHUTDOWN;
             sk->compat_sk_state = SS_UNCONNECTED;
             compat_sock_set_done(sk);
index 36256142699463f397798a2183aa215efc7261e3..aeab7d75cb6c0e574278d75549ca3748a5c3cd01 100644 (file)
 #  else
 #    include <sys/socket.h>
 #  endif // __KERNEL__
+#else // linux && !VMKERNEL
+#  if defined(__APPLE__)
+#    include <sys/socket.h>
+#    include <string.h>
+#  endif // __APPLE__
 #endif // linux && !VMKERNEL
 #endif
 
@@ -97,14 +102,14 @@ struct sockaddr_vm {
 #if defined(_WIN32)
 #  if !defined(WINNT_DDK)
 #  include <winioctl.h>
-#  define VMCI_SOCKETS_DEVICE          TEXT("\\\\.\\VMCI")
+#  define VMCI_SOCKETS_DEVICE          L"\\\\.\\VMCI"
 #  define VMCI_SOCKETS_GET_AF_VALUE    0x81032068
 #  define VMCI_SOCKETS_GET_LOCAL_CID   0x8103206c
 
    static __inline int VMCISock_GetAFValue(void)
    {
-      HANDLE device = CreateFile(VMCI_SOCKETS_DEVICE, GENERIC_READ, 0, NULL,
-                                 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+      HANDLE device = CreateFileW(VMCI_SOCKETS_DEVICE, GENERIC_READ, 0, NULL,
+                                  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
       if (INVALID_HANDLE_VALUE != device) {
          DWORD ioReturn;
          int afvalue;
@@ -123,8 +128,8 @@ struct sockaddr_vm {
 
    static __inline unsigned int VMCISock_GetLocalCID(void)
    {
-      HANDLE device = CreateFile(VMCI_SOCKETS_DEVICE, GENERIC_READ, 0, NULL,
-                                 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+      HANDLE device = CreateFileW(VMCI_SOCKETS_DEVICE, GENERIC_READ, 0, NULL,
+                                  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
       if (INVALID_HANDLE_VALUE != device) {
          DWORD ioReturn;
          unsigned int cid;
@@ -253,6 +258,11 @@ struct sockaddr_vm {
       return contextId;
    }
 #  endif // __KERNEL__
+#else
+#if defined(__APPLE__) && !defined(KERNEL)
+extern int VMCISock_GetAFValue(void);
+extern unsigned int VMCISock_GetLocalCID(void);
+#endif // __APPLE__ && !KERNEL
 #endif // linux && !VMKERNEL
 #endif // _WIN32
 
index 821a242db7a3c300ff5c674feee529de3ec895ad..2aa7f8be808f093255283e3ed9d761532e6a1582 100644 (file)
  *    Packet constants, types and functions.
  */
 
-#if defined(_WIN32) || defined(VMKERNEL)
+#ifndef _VSOCK_PACKET_H_
+#define _VSOCK_PACKET_H_
+
+#if defined(_WIN32) || defined(VMKERNEL) || defined(__APPLE__)
 # include "vsockOSInt.h"
 #else
 # define VSockOS_ClearMemory(_dst, _sz)   memset(_dst, 0, _sz)
 #endif
 
 
-#ifndef _VSOCK_PACKET_H_
-#define _VSOCK_PACKET_H_
-
-
 /* If the packet format changes in a release then this should change too. */
 #define VSOCK_PACKET_VERSION 1
 
index 5b85beae703ccf9970999766c383470572659005..cd1a34706e58093a0c45886bf722462df45b3e4b 100644 (file)
 #  define SHUTDOWN_MASK       3
 #endif // _WIN32 || VMKERNEL
 
+/*
+ * For signalling sockets.  These are defined as standard on Windows.  We do
+ * not use them on Linux.  So define them here only for VMKernel.
+ */
+#if defined(_WIN32)
+#  define SOCKET_EVENT_READ    FD_READ
+#  define SOCKET_EVENT_WRITE   FD_WRITE
+#  define SOCKET_EVENT_ACCEPT  FD_ACCEPT
+#  define SOCKET_EVENT_CONNECT FD_CONNECT
+#  define SOCKET_EVENT_CLOSE   FD_CLOSE
+#else
+#if defined(VMKERNEL)
+#  define SOCKET_EVENT_READ    0x1
+#  define SOCKET_EVENT_WRITE   0x2
+#  define SOCKET_EVENT_ACCEPT  0x8
+#  define SOCKET_EVENT_CONNECT 0x10
+#  define SOCKET_EVENT_CLOSE   0x20
+#endif // VMKERNEL
+#endif // _WIN32
+
+/*
+ * Custom socket control option values.  These are internal.  The public ones
+ * are in vmci_sockets.h.  As with the public options, use the address family
+ * as the option level.
+ */
+#define SO_VMCI_EVENT_ENUMERATE_SELECT 1000
 
 /*
  * Error codes.
index 58254a750a3c03dbde0c8536a646a8ef8b56fe07..42b2f95c1723896e9f4dc30437837d497ff03dcd 100644 (file)
@@ -45,6 +45,7 @@ CFLAGS   += -Wall -Werror
 CFLAGS   += $(GLOBAL_DEFS)
 CFLAGS   += $(CC_WARNINGS)
 CFLAGS   += -DVMX86_TOOLS
+CFLAGS   += -I.
 
 ifdef VMX86_DEVEL
 CFLAGS   += -DVMX86_DEVEL
@@ -159,10 +160,3 @@ install:
        chmod 755 /kernel/drv/$(MODULE)
        cp $(MODULE_64) /kernel/drv/amd64
        chmod 755 /kernel/drv/amd64/$(MODULE)
-       cp docs/hgfs.conf /kernel/drv/vmhgfs.conf
-       chmod 644 /kernel/drv/vmhgfs.conf
-       grep $(MODULE) /etc/name_to_major > /dev/null 2>&1; \
-       if [ ! $$? = 0 ]; then \
-          cat docs/append-to-devlink.tab >> /etc/devlink.tab; \
-          /usr/sbin/add_drv -m "* 0644 root sys" vmhgfs; \
-       fi
diff --git a/open-vm-tools/modules/solaris/vmhgfs/compat/compat_stdarg.h b/open-vm-tools/modules/solaris/vmhgfs/compat/compat_stdarg.h
new file mode 100644 (file)
index 0000000..8ed6091
--- /dev/null
@@ -0,0 +1,55 @@
+/*********************************************************
+ * Copyright (C) 2006 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * compat_stdarg.h --
+ *
+ *    Compatibility defines for systems that need the stdarg features. If your program
+ *    needs va_init, va_copy, va_end, etc. then include this file instead of including
+ *    stdarg.h directly.
+ */
+
+#ifndef _COMPAT_STDARG_H
+#define _COMPAT_STDARG_H 1
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+#include <stdarg.h>
+
+#if !defined(va_copy)
+#   if defined(__va_copy)
+#      define va_copy __va_copy
+#   elif defined(_WIN32)
+#      define va_copy(ap1, ap2) (*(ap1) = *(ap2))
+#   elif defined(VA_LIST_IS_ARRAY)
+#      define va_copy(ap1, ap2) memcpy(ap1, ap2, sizeof(va_list))
+#   else
+#      define va_copy(ap1, ap2) ((ap1) = (ap2))
+#   endif
+#endif
+
+#endif /* _COMPAT_STDARG_H */
index b79c313d14fd30a50c2613d8486c9030bb15d1e3..d452c7409f81d02ea0ef63719381976049b8ef7a 100644 (file)
@@ -35,7 +35,7 @@
 #elif __APPLE__
 #include <stdlib.h>
 #endif
-#include <stdarg.h>
+#include "compat/compat_stdarg.h" // Provides stdarg.h plus va_copy
 
 #include "vm_basic_types.h"
 
index 18b1156f883fe7e90ca2722de836bcd514eea8de..d6344b3b43269c9ea34e92d3bfb0761d309bad57 100644 (file)
@@ -360,9 +360,12 @@ GetCallerFrameAddr(void)
 #ifdef _WIN32 // {
 
 #define snprintf  _snprintf
-#define        vsnprintf _vsnprintf
 #define strtok_r  strtok_s
 
+#if (_MSC_VER < 1500)
+#define        vsnprintf _vsnprintf
+#endif
+
 typedef int uid_t;
 typedef int gid_t;
 
index dc0ad610841ae6390f3ff6bcd907f8c59af2b6f7..006f78baaff0459131615ac1d8c135c95bb28694 100644 (file)
@@ -881,11 +881,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index 31b6cdd241b78475284ffd76fd71794c6f32b476..7d31c8c4e8f5ec9a5a930ed0755a639b919fb9f7 100644 (file)
@@ -637,6 +637,7 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #define CPUID_MODEL_NEHALEM_1A 0x1a  // Nehalem / Gainestown
 #define CPUID_MODEL_ATOM_1C    0x1c  // Silverthorne / Diamondville
 #define CPUID_MODEL_CORE_1D    0x1d  // Dunnington
+#define CPUID_MODEL_NEHALEM_1E 0x1e  // Lynnfield
 
 #define CPUID_MODEL_PIII_07    7
 #define CPUID_MODEL_PIII_08    8
@@ -756,19 +757,18 @@ CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1.
            model == CPUID_MODEL_CORE_1D);
 }
 
-
 /*
- * Intel Nehalem processors are: Nehalem, Gainestown.
+ * Intel Nehalem processors are: Nehalem, Gainestown, Lynnfield.
  */
 static INLINE Bool
 CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
 {
    /* Assumes the CPU manufacturer is Intel. */
    return CPUID_FAMILY_IS_P6(v) &&
-          CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A;
+          (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A ||
+           CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1E);
 }
 
-
 static INLINE Bool
 CPUID_FAMILY_IS_K7(uint32 _eax)
 {
index dc0ad610841ae6390f3ff6bcd907f8c59af2b6f7..006f78baaff0459131615ac1d8c135c95bb28694 100644 (file)
@@ -881,11 +881,11 @@ typedef void * UserVA;
 #endif
 
 /*
- * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
- * Linux it's an int.
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
  * Use this like this: printf("The uid is %"FMTUID".\n", uid);
  */
-#ifdef sun
+#if defined(sun) && !defined(SOL11)
 #   ifdef VM_X86_64
 #      define FMTUID "u"
 #   else
index a27b23a3974b9a8905838057216b9bdecc3548d7..c35f7b051b931e98753a919092583a757d9059d1 100644 (file)
@@ -90,7 +90,8 @@
  *    Intel 82443BX (440 BX North Bridge and AGP Bridge)
  *    Intel 82545EM (e1000, server adapter, single port)
  *    Intel 82546EB (e1000, server adapter, dual port)
- *    Intel ICH7_16 (Hight Definition Audio controller)
+ *    Intel ICH7_16 (High Definition Audio controller)
+ *    Intel HECI (as embedded in ich9m)
  */
 #define PCI_VENDOR_ID_INTEL             0x8086
 #define PCI_DEVICE_ID_INTEL_82439TX     0x7100
 #define PCI_DEVICE_ID_INTEL_82545EM     0x100f
 #define PCI_DEVICE_ID_INTEL_82546EB     0x1010
 #define PCI_DEVICE_ID_INTEL_ICH7_16     0x27d8
+#define PCI_DEVICE_ID_INTEL_HECI        0x2a74
 
 
 /************* Strings for IDE Identity Fields **************************/
diff --git a/open-vm-tools/modules/solaris/vmxnet3/COPYING.CDDL b/open-vm-tools/modules/solaris/vmxnet3/COPYING.CDDL
new file mode 100644 (file)
index 0000000..883d599
--- /dev/null
@@ -0,0 +1,365 @@
+
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates
+         or contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+         Software, prior Modifications used by a Contributor (if any),
+         and the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+         Modifications, or (c) the combination of files containing
+         Original Software with files containing Modifications, in
+         each case including portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other
+         than Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+         makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+         portions thereof with code not governed by the terms of this
+         License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+         extent possible, whether at the time of the initial grant or
+         subsequently acquired, any and all of the rights conveyed
+         herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+         any of the following:
+
+        A. Any file that results from an addition to, deletion from or
+           modification of the contents of a file containing Original
+           Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original
+           Software or previous Modifications; or
+
+        C. Any new file that is contributed or otherwise made
+           available under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable
+          form of computer software code that is originally released
+          under this License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+          hereafter acquired, including without limitation, method,
+          process, and apparatus claims, in any patent Licensable by
+          grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+          code in which modifications are made and (b) associated
+          documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+          exercising rights under, and complying with all of the terms
+          of, this License.  For legal entities, "You" includes any
+          entity which controls, is controlled by, or is under common
+          control with You.  For purposes of this definition,
+          "control" means (a) the power, direct or indirect, to cause
+          the direction or management of such entity, whether by
+          contract or otherwise, or (b) ownership of more than fifty
+          percent (50%) of the outstanding shares or beneficial
+          ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, the Initial
+    Developer hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer, to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Software (or portions thereof),
+            with or without Modifications, and/or as part of a Larger
+            Work; and
+
+        (b) under Patent Claims infringed by the making, using or
+            selling of Original Software, to make, have made, use,
+            practice, sell, and offer for sale, and/or otherwise
+            dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            or otherwise makes the Original Software available to a
+            third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is
+            granted: (1) for code that You delete from the Original
+            Software, or (2) for infringements caused by: (i) the
+            modification of the Original Software, or (ii) the
+            combination of the Original Software with other software
+            or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, each
+    Contributor hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof), either on an unmodified basis, with other
+            Modifications, as Covered Software and/or as part of a
+            Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version
+            (or portions of such combination), to make, use, sell,
+            offer for sale, have made, and/or otherwise dispose of:
+            (1) Modifications made by that Contributor (or portions
+            thereof); and (2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first distributes or
+            otherwise makes the Modifications available to a third
+            party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is
+            granted: (1) for any code that Contributor has deleted
+            from the Contributor Version; (2) for infringements caused
+            by: (i) third party modifications of Contributor Version,
+            or (ii) the combination of Modifications made by that
+            Contributor with other software (except as part of the
+            Contributor Version) or other devices; or (3) under Patent
+            Claims infringed by Covered Software in the absence of
+            Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make
+    available in Executable form must also be made available in Source
+    Code form and that Source Code form must be distributed only under
+    the terms of this License.  You must include a copy of this
+    License with every copy of the Source Code form of the Covered
+    Software You distribute or otherwise make available.  You must
+    inform recipients of any such Covered Software in Executable form
+    as to how they can obtain such Covered Software in Source Code
+    form in a reasonable manner on or through a medium customarily
+    used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License.  You represent that You
+    believe Your Modifications are Your original creation(s) and/or
+    You have sufficient rights to grant the rights conveyed by this
+    License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification.  You may
+    not remove or alter any copyright, patent or trademark notices
+    contained within the Covered Software, or any notices of licensing
+    or any descriptive text giving attribution to any Contributor or
+    the Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version
+    of this License or the recipients' rights hereunder.  You may
+    choose to offer, and to charge a fee for, warranty, support,
+    indemnity or liability obligations to one or more recipients of
+    Covered Software.  However, you may do so only on Your own behalf,
+    and not on behalf of the Initial Developer or any Contributor.
+    You must make it absolutely clear that any such warranty, support,
+    indemnity or liability obligation is offered by You alone, and You
+    hereby agree to indemnify the Initial Developer and every
+    Contributor for any liability incurred by the Initial Developer or
+    such Contributor as a result of warranty, support, indemnity or
+    liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software
+    under the terms of this License or under the terms of a license of
+    Your choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License.  If You distribute the
+    Covered Software in Executable form under a different license, You
+    must make it absolutely clear that any terms which differ from
+    this License are offered by You alone, not by the Initial
+    Developer or Contributor.  You hereby agree to indemnify the
+    Initial Developer and every Contributor for any liability incurred
+    by the Initial Developer or such Contributor as a result of any
+    such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and
+    distribute the Larger Work as a single product.  In such a case,
+    You must make sure the requirements of this License are fulfilled
+    for the Covered Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Sun Microsystems, Inc. is the initial license steward and may
+    publish revised and/or new versions of this License from time to
+    time.  Each version will be given a distinguishing version number.
+    Except as provided in Section 4.3, no one other than the license
+    steward has the right to modify this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software.
+    If the Initial Developer includes a notice in the Original
+    Software prohibiting it from being distributed or otherwise made
+    available under any subsequent version of the License, You must
+    distribute and make the Covered Software available under the terms
+    of the version of the License under which You originally received
+    the Covered Software.  Otherwise, You may also choose to use,
+    distribute or otherwise make the Covered Software available under
+    the terms of any subsequent version of the License published by
+    the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license
+    and remove any references to the name of the license steward
+    (except to note that the license differs from this License); and
+    (b) otherwise make it clear that the license contains terms which
+    differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+    BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+    SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+    PURPOSE OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND
+    PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.  SHOULD ANY
+    COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+    INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+    NECESSARY SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF
+    WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.  NO USE OF
+    ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+    DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond
+    the termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that
+    the Participant Software (meaning the Contributor Version where
+    the Participant is a Contributor or the Original Software where
+    the Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if
+    the Initial Developer is not the Participant) and all Contributors
+    under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+    notice from Participant terminate prospectively and automatically
+    at the expiration of such 60 day notice period, unless if within
+    such 60 day period You withdraw Your claim with respect to the
+    Participant Software against such Participant either unilaterally
+    or pursuant to a written agreement with Participant.
+
+    6.3. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+    LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+    STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+    COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+    INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF
+    LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+    INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+    APPLICABLE LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO
+    NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+    CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+    APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is
+    defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+    computer software" (as that term is defined at 48
+    C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+    documentation" as such terms are used in 48 C.F.R. 12.212
+    (Sept. 1995).  Consistent with 48 C.F.R. 12.212 and 48
+    C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+    U.S. Government End Users acquire Covered Software with only those
+    rights set forth herein.  This U.S. Government Rights clause is in
+    lieu of, and supersedes, any other FAR, DFAR, or other clause or
+    provision that addresses Government rights in computer software
+    under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof.  If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable.  This License shall be governed
+    by the law of the jurisdiction specified in a notice contained
+    within the Original Software (except to the extent applicable law,
+    if any, provides otherwise), excluding such jurisdiction's
+    conflict-of-law provisions.  Any litigation relating to this
+    License shall be subject to the jurisdiction of the courts located
+    in the jurisdiction and venue specified in a notice contained
+    within the Original Software, with the losing party responsible
+    for costs, including, without limitation, court costs and
+    reasonable attorneys' fees and expenses.  The application of the
+    United Nations Convention on Contracts for the International Sale
+    of Goods is expressly excluded.  Any law or regulation which
+    provides that the language of a contract shall be construed
+    against the drafter shall not apply to this License.  You agree
+    that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use,
+    distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or
+    indirectly, out of its utilization of rights under this License
+    and You agree to work with Initial Developer and Contributors to
+    distribute such responsibility on an equitable basis.  Nothing
+    herein is intended or shall be deemed to constitute any admission
+    of liability.
+
diff --git a/open-vm-tools/modules/solaris/vmxnet3/Makefile b/open-vm-tools/modules/solaris/vmxnet3/Makefile
new file mode 100644 (file)
index 0000000..c62f363
--- /dev/null
@@ -0,0 +1,103 @@
+#!/usr/bin/make -f
+##########################################################
+# Copyright (C) 2009 VMware, Inc. All rights reserved.
+#
+# 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.
+#
+##########################################################
+
+ifneq ($(shell echo "$(VM_UNAME)" | cut -c-4),5.10)
+$(error "This makefile is only used for Solaris 10")
+endif
+
+##
+## General build locations and variables
+##
+
+MODULE    := vmxnet3
+CFLAGS    :=
+LDFLAGS   :=
+
+CFLAGS    += -O2
+CFLAGS    += -Wall -Werror -Wno-unknown-pragmas
+CFLAGS    += -U_NO_LONGLONG
+CFLAGS    += -D_KERNEL
+CFLAGS    += -I../../../lib/include    # for buildNumber.h
+
+CFLAGS    += -ffreestanding
+CFLAGS    += -nodefaultlibs
+
+CFLAGS_32  := $(CFLAGS)
+CFLAGS_32  += -m32
+LDFLAGS_32 := $(LDFLAGS)
+
+CFLAGS_64  := $(CFLAGS)
+CFLAGS_64  += -m64
+CFLAGS_64  += -mcmodel=kernel
+CFLAGS_64  += -mno-red-zone
+LDFLAGS_64 := $(LDFLAGS)
+ifdef HAVE_GNU_LD
+LDFLAGS_64 += -m elf_x86_64
+else
+LDFLAGS_64 += -64
+endif
+
+##
+## Objects needed to build the HGFS kernel module
+##
+VMXNET3_OBJS := vmxnet3_main.o
+VMXNET3_OBJS += vmxnet3_utils.o
+VMXNET3_OBJS += vmxnet3_tx.o
+VMXNET3_OBJS += vmxnet3_rx.o
+
+VMXNET3_32_OBJS := $(addprefix i386/, $(VMXNET3_OBJS))
+VMXNET3_64_OBJS := $(addprefix amd64/, $(VMXNET3_OBJS))
+
+MODULE_32 := i386/$(MODULE)
+MODULE_64 := amd64/$(MODULE)
+
+all: prepare_dirs $(MODULE_32) $(MODULE_64)
+
+prepare_dirs:
+       @echo "Creating build directories"
+       mkdir -p i386
+       mkdir -p amd64
+
+$(MODULE_32): $(VMXNET3_32_OBJS)
+       @echo "Linking          $@"
+       $(LD) $(LDFLAGS_32) -r $(VMXNET3_32_OBJS) -o $@
+
+$(VMXNET3_32_OBJS): i386/%.o: %.c
+       @echo "Compiling        $(<F)"
+       $(CC) $(CFLAGS_32) -c $< -o $@
+
+$(MODULE_64): $(VMXNET3_64_OBJS)
+       @echo "Linking          $@"
+       $(LD) $(LDFLAGS_64) -r $(VMXNET3_64_OBJS) -o $@
+
+$(VMXNET3_64_OBJS): amd64/%.o: %.c
+       @echo "Compiling        $(<F)"
+       $(CC) $(CFLAGS_64) -c $< -o $@
+
+clean:
+       @echo "Cleaning directories"
+       @rm -rf $(MODULE_32) $(VMXNET3_32_OBJS) i386
+       @rm -rf $(MODULE_64) $(VMXNET3_64_OBJS) amd64
+
+install:
+       @echo "Installing modules"
+       cp $(MODULE_32) /kernel/drv/
+       chmod 755 /kernel/drv/$(MODULE)
+       cp $(MODULE_64) /kernel/drv/amd64
+       chmod 755 /kernel/drv/amd64/$(MODULE)
+       cp docs/vmxnet3s.conf /kernel/drv/vmxnet3s.conf
+       chmod 644 /kernel/drv/vmxnet3s.conf
diff --git a/open-vm-tools/modules/solaris/vmxnet3/includeCheck.h b/open-vm-tools/modules/solaris/vmxnet3/includeCheck.h
new file mode 100644 (file)
index 0000000..3da2e00
--- /dev/null
@@ -0,0 +1,130 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * includeCheck.h --
+ *
+ *     Restrict include file use.
+ *
+ * In every .h file, define one or more of these
+ *
+ *     INCLUDE_ALLOW_VMX 
+ *     INCLUDE_ALLOW_USERLEVEL 
+ *     INCLUDE_ALLOW_VMMEXT
+ *     INCLUDE_ALLOW_VMCORE
+ *     INCLUDE_ALLOW_MODULE
+ *      INCLUDE_ALLOW_VMNIXMOD 
+ *     INCLUDE_ALLOW_VMKERNEL 
+ *     INCLUDE_ALLOW_DISTRIBUTE
+ *     INCLUDE_ALLOW_VMK_MODULE
+ *      INCLUDE_ALLOW_VMKDRIVERS
+ *      INCLUDE_ALLOW_VMIROM
+ *
+ * Then include this file.
+ *
+ * Any file that has INCLUDE_ALLOW_DISTRIBUTE defined will potentially
+ * be distributed in source form along with GPLed code.  Ensure
+ * that this is acceptable.
+ */
+
+
+/*
+ * Declare a VMCORE-only variable to help classify object
+ * files.  The variable goes in the common block and does
+ * not create multiple definition link-time conflicts.
+ */
+
+#if defined VMCORE && defined VMX86_DEVEL && defined VMX86_DEBUG && \
+    defined linux && !defined MODULE && \
+    !defined COMPILED_WITH_VMCORE
+#define COMPILED_WITH_VMCORE compiled_with_vmcore
+#ifdef ASM
+        .comm   compiled_with_vmcore, 0
+#else
+        asm(".comm compiled_with_vmcore, 0");
+#endif /* ASM */
+#endif
+
+
+#if defined VMCORE && \
+    !(defined VMX86_VMX || defined VMM || \
+      defined MONITOR_APP || defined VMMON)
+#error "Makefile problem: VMCORE without VMX86_VMX or \
+        VMM or MONITOR_APP or MODULE."
+#endif
+
+#if defined VMCORE && !defined INCLUDE_ALLOW_VMCORE
+#error "The surrounding include file is not allowed in vmcore."
+#endif
+#undef INCLUDE_ALLOW_VMCORE
+
+#if defined VMX86_VMX && !defined VMCORE && \
+    !(defined INCLUDE_ALLOW_VMX || defined INCLUDE_ALLOW_USERLEVEL)
+#error "The surrounding include file is not allowed in the VMX."
+#endif
+#undef INCLUDE_ALLOW_VMX
+
+#if defined USERLEVEL && !defined VMX86_VMX && !defined VMCORE && \
+    !defined INCLUDE_ALLOW_USERLEVEL
+#error "The surrounding include file is not allowed at userlevel."
+#endif
+#undef INCLUDE_ALLOW_USERLEVEL
+
+#if defined VMM && !defined VMCORE && \
+    !defined INCLUDE_ALLOW_VMMEXT
+#error "The surrounding include file is not allowed in the monitor."
+#endif
+#undef INCLUDE_ALLOW_VMMEXT
+
+#if defined MODULE && !defined VMKERNEL_MODULE && !defined VMNIXMOD && \
+    !defined VMMON && !defined INCLUDE_ALLOW_MODULE
+#error "The surrounding include file is not allowed in driver modules."
+#endif
+#undef INCLUDE_ALLOW_MODULE
+
+#if defined VMMON && !defined INCLUDE_ALLOW_VMMON
+#error "The surrounding include file is not allowed in vmmon."
+#endif
+#undef INCLUDE_ALLOW_VMMON
+
+#if defined VMKERNEL && !defined INCLUDE_ALLOW_VMKERNEL
+#error "The surrounding include file is not allowed in the vmkernel."
+#endif
+#undef INCLUDE_ALLOW_VMKERNEL
+
+#if defined GPLED_CODE && !defined INCLUDE_ALLOW_DISTRIBUTE
+#error "The surrounding include file is not allowed in GPL code."
+#endif
+#undef INCLUDE_ALLOW_DISTRIBUTE
+
+#if defined VMKERNEL_MODULE && !defined VMKERNEL && \
+    !defined INCLUDE_ALLOW_VMK_MODULE && !defined INCLUDE_ALLOW_VMKDRIVERS
+#error "The surrounding include file is not allowed in vmkernel modules."
+#endif
+#undef INCLUDE_ALLOW_VMK_MODULE
+#undef INCLUDE_ALLOW_VMKDRIVERS
+
+#if defined VMNIXMOD && !defined INCLUDE_ALLOW_VMNIXMOD
+#ifndef VMNIXMOD_VM
+#error "The surrounding include file is not allowed in vmnixmod."
+#endif
+#endif
+#undef INCLUDE_ALLOW_VMNIXMOD
+
+#if defined VMIROM && ! defined INCLUDE_ALLOW_VMIROM
+#error "The surrounding include file is not allowed in vmirom."
+#endif
+#undef INCLUDE_ALLOW_VMIROM
diff --git a/open-vm-tools/modules/solaris/vmxnet3/net.h b/open-vm-tools/modules/solaris/vmxnet3/net.h
new file mode 100644 (file)
index 0000000..ac71a38
--- /dev/null
@@ -0,0 +1,134 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/************************************************************
+ *
+ *   net.h
+ *
+ *   This file should contain all network global defines.
+ *   No vlance/vmxnet/vnet/vmknet specific stuff should be
+ *   put here only defines used/usable by all network code.
+ *   --gustav
+ *
+ ************************************************************/
+
+#ifndef VMWARE_DEVICES_NET_H
+#define VMWARE_DEVICES_NET_H
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMEXT
+#include "includeCheck.h"
+#include "vm_device_version.h"
+
+#define ETHERNET_MTU         1518
+#define ETH_MIN_FRAME_LEN      60
+
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN          6  /* length of MAC address */
+#endif
+#define ETH_HEADER_LEN        14  /* length of Ethernet header */
+#define IP_ADDR_LEN            4  /* length of IPv4 address */
+#define IP_HEADER_LEN         20  /* minimum length of IPv4 header */
+
+#define ETHER_MAX_QUEUED_PACKET 1600
+
+
+/*
+ * State's that a NIC can be in currently we only use this
+ * in VLance but if we implement/emulate new adapters that
+ * we also want to be able to morph a new corresponding
+ * state should be added.
+ */
+
+#define LANCE_CHIP  0x2934
+#define VMXNET_CHIP 0x4392
+
+/*
+ * Size of reserved IO space needed by the LANCE adapter and
+ * the VMXNET adapter. If you add more ports to Vmxnet than
+ * there is reserved space you must bump VMXNET_CHIP_IO_RESV_SIZE.
+ * The sizes must be powers of 2.
+ */
+
+#define LANCE_CHIP_IO_RESV_SIZE  0x20
+#define VMXNET_CHIP_IO_RESV_SIZE 0x40
+
+#define MORPH_PORT_SIZE 4
+
+
+#ifdef USERLEVEL
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Net_AddAddrToLADRF --
+ *
+ *      Given a MAC address, sets the corresponding bit in the LANCE style
+ *      Logical Address Filter 'ladrf'.
+ *      The caller should have initialized the ladrf to all 0's, as this
+ *      function only ORs on a bit in the array.
+ *      'addr' is presumed to be ETHER_ADDR_LEN in size;
+ *      'ladrf' is presumed to point to a 64-bit vector.
+ *
+ *      Derived from a long history of derivations, originally inspired by
+ *      sample code from the AMD "Network Products: Ethernet Controllers 1998
+ *      Data Book, Book 2", pages 1-53..1-55.
+ *
+ * Returns:
+ *      None.
+ *
+ * Side effects:
+ *      Updates 'ladrf'.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE void
+Net_AddAddrToLadrf(const uint8 *addr,  // IN: pointer to MAC address
+                   uint8 *ladrf)       // IN/OUT: pointer to ladrf
+{
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+
+   uint16 hashcode;
+   int32 crc = 0xffffffff;             /* init CRC for each address */
+   int32 j;
+   int32 bit;
+   int32 byte;
+
+   ASSERT(addr);
+   ASSERT(ladrf);
+
+   for (byte = 0; byte < ETHER_ADDR_LEN; byte++) {  /* for each address byte */
+      /* process each address bit */
+      for (bit = *addr++, j = 0;
+           j < 8;
+           j++, bit >>= 1) {
+        crc = (crc << 1) ^ ((((crc < 0 ? 1 : 0) ^ bit) & 0x01) ?
+               CRC_POLYNOMIAL_BE : 0);
+      }
+   }
+   hashcode = (crc & 1);              /* hashcode is 6 LSb of CRC ... */
+   for (j = 0; j < 5; j++) {          /* ... in reverse order. */
+      hashcode = (hashcode << 1) | ((crc>>=1) & 1);
+   }
+
+   ladrf[hashcode >> 3] |= 1 << (hashcode & 0x07);
+}
+
+#endif // USERLEVEL
+
+#endif // VMWARE_DEVICES_NET_H
diff --git a/open-vm-tools/modules/solaris/vmxnet3/net_sg.h b/open-vm-tools/modules/solaris/vmxnet3/net_sg.h
new file mode 100644 (file)
index 0000000..c90e376
--- /dev/null
@@ -0,0 +1,70 @@
+/*********************************************************
+ * Copyright (C) 2000 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * net_sg.h --
+ *
+ *     Network packet scatter gather structure.
+ */
+
+
+#ifndef _NET_SG_H
+#define _NET_SG_H
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#define NET_SG_DEFAULT_LENGTH  16
+
+/*
+ * A single scatter-gather element for a network packet.
+ * The address is split into low and high to save space.
+ * If we make it 64 bits then Windows pads things out such that
+ * we lose a lot of space for each scatter gather array.
+ * This adds up when you have embedded scatter-gather 
+ * arrays for transmit and receive ring buffers.
+ */
+typedef struct NetSG_Elem {
+   uint32      addrLow;
+   uint16      addrHi;
+   uint16      length;
+} NetSG_Elem;
+
+typedef enum NetSG_AddrType {
+   NET_SG_MACH_ADDR,
+   NET_SG_PHYS_ADDR,
+   NET_SG_VIRT_ADDR,
+   NET_SG_VMM_STACK_OFFSET,
+} NetSG_AddrType;
+
+typedef struct NetSG_Array {
+   uint16      addrType;
+   uint16      length;
+   NetSG_Elem  sg[NET_SG_DEFAULT_LENGTH];
+} NetSG_Array;
+
+#define NET_SG_SIZE(len) (sizeof(NetSG_Array) + (len - NET_SG_DEFAULT_LENGTH) * sizeof(NetSG_Elem))
+
+#define NET_SG_MAKE_PA(elem)                 (PA)QWORD(elem.addrHi, elem.addrLow)
+#define NET_SG_MAKE_PTR(elem) (char *)(uintptr_t)QWORD(elem.addrHi, elem.addrLow)
+
+#endif
diff --git a/open-vm-tools/modules/solaris/vmxnet3/upt1_defs.h b/open-vm-tools/modules/solaris/vmxnet3/upt1_defs.h
new file mode 100644 (file)
index 0000000..4b017a8
--- /dev/null
@@ -0,0 +1,106 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/* upt1_defs.h
+ *
+ *      Definitions for UPTv1
+ *
+ *      Some of the defs are duplicated in vmkapi_net_upt.h, because
+ *      vmkapi_net_upt.h cannot distribute with OSS yet and vmkapi headers can
+ *      only include vmkapi headers. Make sure they are kept in sync!
+ */
+
+#ifndef _UPT1_DEFS_H
+#define _UPT1_DEFS_H
+
+#define UPT1_MAX_TX_QUEUES  64
+#define UPT1_MAX_RX_QUEUES  64
+
+#define UPT1_MAX_INTRS  (UPT1_MAX_TX_QUEUES + UPT1_MAX_RX_QUEUES)
+
+typedef
+#include "vmware_pack_begin.h"
+struct UPT1_TxStats {
+   uint64 TSOPktsTxOK;  /* TSO pkts post-segmentation */
+   uint64 TSOBytesTxOK;
+   uint64 ucastPktsTxOK;
+   uint64 ucastBytesTxOK;
+   uint64 mcastPktsTxOK;
+   uint64 mcastBytesTxOK;
+   uint64 bcastPktsTxOK;
+   uint64 bcastBytesTxOK;
+   uint64 pktsTxError;
+   uint64 pktsTxDiscard;
+}
+#include "vmware_pack_end.h"
+UPT1_TxStats;
+
+typedef
+#include "vmware_pack_begin.h"
+struct UPT1_RxStats {
+   uint64 LROPktsRxOK;    /* LRO pkts */
+   uint64 LROBytesRxOK;   /* bytes from LRO pkts */
+   /* the following counters are for pkts from the wire, i.e., pre-LRO */
+   uint64 ucastPktsRxOK;
+   uint64 ucastBytesRxOK;
+   uint64 mcastPktsRxOK;
+   uint64 mcastBytesRxOK;
+   uint64 bcastPktsRxOK;
+   uint64 bcastBytesRxOK;
+   uint64 pktsRxOutOfBuf;
+   uint64 pktsRxError;
+}
+#include "vmware_pack_end.h"
+UPT1_RxStats;
+
+/* interrupt moderation level */
+#define UPT1_IML_NONE     0 /* no interrupt moderation */
+#define UPT1_IML_HIGHEST  7 /* least intr generated */
+#define UPT1_IML_ADAPTIVE 8 /* adpative intr moderation */
+
+/* values for UPT1_RSSConf.hashFunc */
+#define UPT1_RSS_HASH_TYPE_NONE      0x0
+#define UPT1_RSS_HASH_TYPE_IPV4      0x01
+#define UPT1_RSS_HASH_TYPE_TCP_IPV4  0x02
+#define UPT1_RSS_HASH_TYPE_IPV6      0x04
+#define UPT1_RSS_HASH_TYPE_TCP_IPV6  0x08
+
+#define UPT1_RSS_HASH_FUNC_NONE      0x0
+#define UPT1_RSS_HASH_FUNC_TOEPLITZ  0x01
+
+#define UPT1_RSS_MAX_KEY_SIZE        40
+#define UPT1_RSS_MAX_IND_TABLE_SIZE  128
+
+typedef 
+#include "vmware_pack_begin.h"
+struct UPT1_RSSConf {
+   uint16   hashType;
+   uint16   hashFunc;
+   uint16   hashKeySize;
+   uint16   indTableSize;
+   uint8    hashKey[UPT1_RSS_MAX_KEY_SIZE];
+   uint8    indTable[UPT1_RSS_MAX_IND_TABLE_SIZE];
+}
+#include "vmware_pack_end.h"
+UPT1_RSSConf;
+
+/* features */
+#define UPT1_F_RXCSUM      0x0001   /* rx csum verification */
+#define UPT1_F_RSS         0x0002
+#define UPT1_F_RXVLAN      0x0004   /* VLAN tag stripping */
+#define UPT1_F_LRO         0x0008
+
+#endif
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vm_basic_types.h b/open-vm-tools/modules/solaris/vmxnet3/vm_basic_types.h
new file mode 100644 (file)
index 0000000..006f78b
--- /dev/null
@@ -0,0 +1,956 @@
+/*********************************************************
+ * Copyright (C) 1998-2008 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ *
+ * vm_basic_types.h --
+ *
+ *    basic data types.
+ */
+
+
+#ifndef _VM_BASIC_TYPES_H_
+#define _VM_BASIC_TYPES_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+/* STRICT ANSI means the Xserver build and X defines Bool differently. */
+#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__)
+typedef char           Bool;
+#endif
+
+#ifndef FALSE
+#define FALSE          0
+#endif
+
+#ifndef TRUE
+#define TRUE           1
+#endif
+
+#define IsBool(x)      (((x) & ~1) == 0)
+#define IsBool2(x, y)  ((((x) | (y)) & ~1) == 0)
+
+/*
+ * Macros __i386__ and __ia64 are intrinsically defined by GCC
+ */
+#ifdef __i386__
+#define VM_I386
+#endif
+
+#ifdef _WIN64
+#define __x86_64__
+#endif
+
+#ifdef __x86_64__
+#define VM_X86_64
+#define VM_I386
+#define vm_x86_64 (1)
+#else
+#define vm_x86_64 (0)
+#endif
+
+
+
+#ifdef _WIN32
+/* safe assumption for a while */
+#define VM_I386
+#endif
+
+#ifdef _MSC_VER
+
+#pragma warning (3 :4505) // unreferenced local function
+#pragma warning (disable :4018) // signed/unsigned mismatch
+#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied
+#pragma warning (disable :4305) // truncation from 'const int' to 'short'
+#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char'
+#pragma warning (disable :4267) // truncation of 'size_t'
+#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned
+#pragma warning (disable :4142) // benign redefinition of type
+
+#endif
+
+#if defined(__APPLE__) || defined(HAVE_STDINT_H)
+
+/*
+ * TODO: This is a C99 standard header.  We should be able to test for
+ * #if __STDC_VERSION__ >= 199901L, but that breaks the Netware build
+ * (which doesn't have stdint.h).
+ */
+
+#include <stdint.h>
+
+typedef uint64_t uint64;
+typedef int64_t int64;
+typedef uint32_t uint32;
+typedef int32_t int32;
+typedef uint16_t uint16;
+typedef int16_t int16;
+typedef uint8_t uint8;
+
+/*
+ * XXX: int8_t is defined to be 'signed char' on Mac hosts.
+ *
+ * Unfortunately, GCC 4.0.1 warns when doing pointer assignment or
+ * comparison between signed char * and char * (even if char is
+ * signed).
+ *
+ * If we want to use int8_t to define int8, we need to go through and
+ * replace uses of char * with signed char * to prevent warnings.
+ */
+typedef char int8;
+
+#else /* !HAVE_STDINT_H */
+
+#ifdef _MSC_VER
+
+typedef unsigned __int64 uint64;
+typedef signed __int64 int64;
+
+#elif __GNUC__
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+#if defined(VM_X86_64)
+typedef unsigned long uint64;
+typedef long int64;
+#else
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#elif __FreeBSD__
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#else
+#error - Need compiler define for int64/uint64
+#endif /* _MSC_VER */
+
+typedef unsigned int       uint32;
+typedef unsigned short     uint16;
+typedef unsigned char      uint8;
+
+typedef int       int32;
+typedef short     int16;
+typedef char      int8;
+
+#endif /* HAVE_STDINT_H */
+
+/*
+ * FreeBSD (for the tools build) unconditionally defines these in
+ * sys/inttypes.h so don't redefine them if this file has already
+ * been included. [greg]
+ *
+ * This applies to Solaris as well.
+ */
+
+/*
+ * Before trying to do the includes based on OS defines, see if we can use
+ * feature-based defines to get as much functionality as possible
+ */
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_INTTYPES_H
+#include <sys/inttypes.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/param.h> /* For __FreeBSD_version */         
+#endif
+
+#if !defined(USING_AUTOCONF)
+#   if defined(__FreeBSD__) || defined(sun)
+#      ifdef KLD_MODULE
+#         include <sys/types.h>
+#      else
+#         if !defined(VMKERNEL) && (__FreeBSD_version >= 500043)
+#            include <inttypes.h>
+#            include <sys/types.h>
+#         else
+#            include <sys/inttypes.h>
+#         endif
+#      endif
+#   elif defined __APPLE__
+#      if KERNEL
+#         include <sys/unistd.h>
+#         include <sys/types.h> /* mostly for size_t */
+#         include <stdint.h>
+#      else
+#         include <unistd.h>
+#         include <inttypes.h>
+#         include <stdlib.h>
+#         include <stdint.h>
+#      endif
+#   else
+#      if !defined(__intptr_t_defined) && !defined(intptr_t)
+#         define __intptr_t_defined
+#         define intptr_t  intptr_t
+#         ifdef VM_I386
+#            ifdef VM_X86_64
+typedef int64     intptr_t;
+#            else
+typedef int32     intptr_t;
+#            endif
+#         endif
+#      endif
+
+#      ifndef _STDINT_H
+#         ifdef VM_I386
+#            ifdef VM_X86_64
+typedef uint64    uintptr_t;
+#            else
+typedef uint32    uintptr_t;
+#            endif
+#         endif
+#      endif
+#   endif
+#endif
+
+
+/*
+ * Time
+ * XXX These should be cleaned up.  -- edward
+ */
+
+typedef int64 VmTimeType;          /* Time in microseconds */
+typedef int64 VmTimeRealClock;     /* Real clock kept in microseconds */
+typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
+
+/*
+ * Printf format specifiers for size_t and 64-bit number.
+ * Use them like this:
+ *    printf("%"FMT64"d\n", big);
+ *
+ * FMTH is for handles/fds.
+ */
+
+#ifdef _MSC_VER
+   #define FMT64      "I64"
+   #ifdef VM_X86_64
+      #define FMTSZ      "I64"
+      #define FMTPD      "I64"
+      #define FMTH       "I64"
+   #else
+      #define FMTSZ      "I"
+      #define FMTPD      "I"
+      #define FMTH       "I"
+   #endif
+#elif defined __APPLE__
+   /* Mac OS hosts use the same formatters for 32- and 64-bit. */
+   #define FMT64 "ll"
+   #define FMTSZ "z"
+   #define FMTPD "l"
+   #define FMTH ""
+#elif __GNUC__
+   #define FMTH ""
+   #if defined(N_PLAT_NLM) || defined(sun) || \
+       (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5))
+      /*
+       * Why (__FreeBSD__ + 0)?  See bug 141008.
+       * Yes, we really need to test both (__FreeBSD__ + 0) and
+       * ((__FreeBSD__ + 0) < 5).  No, we can't remove "+ 0" from
+       * ((__FreeBSD__ + 0) < 5).
+       */
+      #ifdef VM_X86_64
+         #define FMTSZ  "l"
+         #define FMTPD  "l"
+      #else
+         #define FMTSZ  ""
+         #define FMTPD  ""
+      #endif
+   #elif defined(__linux__) \
+      || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
+      || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
+      || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L)
+      /* BSD, Linux */
+      #define FMTSZ     "z"
+
+      #if defined(VM_X86_64)
+         #define FMTPD  "l"
+      #else
+         #define FMTPD  ""
+      #endif
+   #else
+      /* Systems with a pre-C99 libc */
+      #define FMTSZ     "Z"
+      #ifdef VM_X86_64
+         #define FMTPD  "l"
+      #else
+         #define FMTPD  ""
+      #endif
+   #endif
+   #ifdef VM_X86_64
+      #define FMT64     "l"
+   #elif defined(sun) || defined(__FreeBSD__)
+      #define FMT64     "ll"
+   #else
+      #define FMT64     "L"
+   #endif
+#else
+   #error - Need compiler define for FMT64 and FMTSZ
+#endif
+
+/*
+ * Suffix for 64-bit constants.  Use it like this:
+ *    CONST64(0x7fffffffffffffff) for signed or
+ *    CONST64U(0x7fffffffffffffff) for unsigned.
+ *
+ * 2004.08.30(thutt):
+ *   The vmcore/asm64/gen* programs are compiled as 32-bit
+ *   applications, but must handle 64 bit constants.  If the
+ *   64-bit-constant defining macros are already defined, the
+ *   definition will not be overwritten.
+ */
+
+#if !defined(CONST64) || !defined(CONST64U)
+#ifdef _MSC_VER
+#define CONST64(c) c##I64
+#define CONST64U(c) c##uI64
+#elif defined __APPLE__
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
+#elif __GNUC__
+#ifdef VM_X86_64
+#define CONST64(c) c##L
+#define CONST64U(c) c##uL
+#else
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
+#endif
+#else
+#error - Need compiler define for CONST64
+#endif
+#endif
+
+/*
+ * Use CONST3264/CONST3264U if you want a constant to be
+ * treated as a 32-bit number on 32-bit compiles and
+ * a 64-bit number on 64-bit compiles. Useful in the case
+ * of shifts, like (CONST3264U(1) << x), where x could be
+ * more than 31 on a 64-bit compile.
+ */
+
+#ifdef VM_X86_64
+    #define CONST3264(a) CONST64(a)
+    #define CONST3264U(a) CONST64U(a)
+#else
+    #define CONST3264(a) (a)
+    #define CONST3264U(a) (a)
+#endif
+
+#define MIN_INT32  ((int32)0x80000000)
+#define MAX_INT32  ((int32)0x7fffffff)
+
+#define MIN_UINT32 ((uint32)0)
+#define MAX_UINT32 ((uint32)0xffffffff)
+
+#define MIN_INT64  (CONST64(0x8000000000000000))
+#define MAX_INT64  (CONST64(0x7fffffffffffffff))
+
+#define MIN_UINT64 (CONST64U(0))
+#define MAX_UINT64 (CONST64U(0xffffffffffffffff))
+
+typedef uint8 *TCA;  /* Pointer into TC (usually). */
+
+/*
+ * Type big enough to hold an integer between 0..100
+ */
+typedef uint8 Percent;
+#define AsPercent(v)   ((Percent)(v))
+#define CHOOSE_PERCENT  AsPercent(101)
+
+
+typedef uintptr_t VA;
+typedef uintptr_t VPN;
+
+typedef uint64    PA;
+typedef uint32    PPN;
+
+typedef uint64    PhysMemOff;
+typedef uint64    PhysMemSize;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64    BA;
+#endif
+typedef uint32    BPN;
+typedef uint32    PageNum;
+typedef unsigned  MemHandle;
+typedef int32     World_ID;
+
+#define INVALID_WORLD_ID ((World_ID)-1)
+
+typedef World_ID User_CartelID;
+#define INVALID_CARTEL_ID INVALID_WORLD_ID
+
+typedef User_CartelID User_SessionID;
+#define INVALID_SESSION_ID INVALID_CARTEL_ID
+
+typedef User_CartelID User_CartelGroupID;
+#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID
+
+typedef uint32 Worldlet_ID;
+#define INVALID_WORLDLET_ID ((Worldlet_ID)-1)
+
+/* world page number */
+typedef uint32    WPN;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64     MA;
+typedef uint32     MPN;
+#endif
+
+/*
+ * This type should be used for variables that contain sector
+ * position/quantity.
+ */
+typedef uint64 SectorType;
+
+/*
+ * Linear address
+ */
+
+typedef uintptr_t LA;
+typedef uintptr_t LPN;
+#define LA_2_LPN(_la)     ((_la) >> PAGE_SHIFT)
+#define LPN_2_LA(_lpn)    ((_lpn) << PAGE_SHIFT)
+
+#define LAST_LPN   ((((LA)  1) << (8 * sizeof(LA)   - PAGE_SHIFT)) - 1)
+#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1)
+#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1)
+
+/* Valid bits in a LPN. */
+#define LPN_MASK   LAST_LPN
+#define LPN_MASK32 LAST_LPN32
+#define LPN_MASK64 LAST_LPN64
+
+/*
+ * On 64 bit platform, address and page number types default
+ * to 64 bit. When we need to represent a 32 bit address, we use
+ * types defined below.
+ *
+ * On 32 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint32 VA32;
+typedef uint32 VPN32;
+typedef uint32 LA32;
+typedef uint32 LPN32;
+typedef uint32 PA32;
+typedef uint32 PPN32;
+typedef uint32 MA32;
+typedef uint32 MPN32;
+
+/*
+ * On 64 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint64 VA64;
+typedef uint64 VPN64;
+typedef uint64 LA64;
+typedef uint64 LPN64;
+typedef uint64 PA64;
+typedef uint64 PPN64;
+typedef uint64 MA64;
+typedef uint64 MPN64;
+
+/*
+ * VA typedefs for user world apps.
+ */
+typedef VA32 UserVA32;
+typedef VA64 UserVA64;
+typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
+#ifdef VMKERNEL
+typedef UserVA64 UserVA;
+#else
+typedef void * UserVA;
+#endif
+
+
+/*
+ * Maximal possible PPN value (errors too) that PhysMem can handle.
+ * Must be at least as large as MAX_PPN which is the maximum PPN
+ * for any region other than buserror.
+ */
+#define PHYSMEM_MAX_PPN ((PPN)0xffffffff)
+#define MAX_PPN         ((PPN)0x1fffffff)   /* Maximal observable PPN value. */
+#define INVALID_PPN     ((PPN)0xffffffff)
+
+#define INVALID_BPN  ((BPN) 0x1fffffff)
+
+#define INVALID_MPN  ((MPN)-1)
+#define MEMREF_MPN   ((MPN)-2)
+#define RESERVED_MPN ((MPN) 0)
+/* Support 43 bits of address space. */
+#define MAX_MPN      ((MPN)0x7fffffff)
+
+#define INVALID_LPN ((LPN)-1)
+#define INVALID_VPN ((VPN)-1)
+#define INVALID_LPN64 ((LPN64)-1)
+#define INVALID_PAGENUM ((PageNum)-1)
+#define INVALID_WPN ((WPN) -1)
+
+
+/*
+ * Format modifier for printing VA, LA, and VPN.
+ * Use them like this: Log("%#"FMTLA"x\n", laddr)
+ */
+
+#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__
+#   define FMTLA "l"
+#   define FMTVA "l"
+#   define FMTVPN "l"
+#else
+#   define FMTLA ""
+#   define FMTVA ""
+#   define FMTVPN ""
+#endif
+
+#ifndef EXTERN
+#define EXTERN        extern
+#endif
+#define CONST         const
+
+
+#ifndef INLINE
+#   ifdef _MSC_VER
+#      define INLINE        __inline
+#   else
+#      define INLINE        inline
+#   endif
+#endif
+
+
+/*
+ * Annotation for data that may be exported into a DLL and used by other
+ * apps that load that DLL and import the data.
+ */
+#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA)
+#  define VMX86_EXTERN_DATA       extern __declspec(dllimport)
+#else // !_WIN32
+#  define VMX86_EXTERN_DATA       extern
+#endif
+
+#if defined(_WIN32) && !defined(VMX86_NO_THREADS)
+#define THREADSPECIFIC __declspec(thread)
+#else
+#define THREADSPECIFIC
+#endif
+
+/*
+ * Due to the wonderful "registry redirection" feature introduced in
+ * 64-bit Windows, if you access any key under HKLM\Software in 64-bit
+ * code, you need to open/create/delete that key with
+ * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code.
+ */
+
+#ifdef _WIN32
+#ifdef _WIN64
+#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY
+#else
+#define VMW_KEY_WOW64_32KEY 0x0
+#endif
+#endif
+
+
+/*
+ * Consider the following reasons functions are inlined:
+ *
+ *  1) inlined for performance reasons
+ *  2) inlined because it's a single-use function
+ *
+ * Functions which meet only condition 2 should be marked with this
+ * inline macro; It is not critical to be inlined (but there is a
+ * code-space & runtime savings by doing so), so when other callers
+ * are added the inline-ness should be removed.
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+/*
+ * Starting at version 3.3, gcc does not always inline functions marked
+ * 'inline' (it depends on their size). To force gcc to do so, one must use the
+ * extra __always_inline__ attribute.
+ */
+#   define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__))
+#   if    defined(VMM) \
+       && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1))
+#      warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \
+             monitor size change?)
+#   endif
+#else
+#   define INLINE_SINGLE_CALLER INLINE
+#endif
+
+/*
+ * Used when a hard guaranteed of no inlining is needed. Very few
+ * instances need this since the absence of INLINE is a good hint
+ * that gcc will not do inlining.
+ */
+
+#if defined(__GNUC__) && defined(VMM)
+#define ABSOLUTELY_NOINLINE __attribute__((__noinline__))
+#endif
+
+/*
+ * Attributes placed on function declarations to tell the compiler
+ * that the function never returns.
+ */
+
+#ifdef _MSC_VER
+#define NORETURN __declspec(noreturn)
+#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9)
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#endif
+
+/*
+ * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands.
+ * Older GCCs don't know about it --hpreg
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+#   define VM_ASM_PLUS 1
+#else
+#   define VM_ASM_PLUS 0
+#endif
+
+/*
+ * Branch prediction hints:
+ *     LIKELY(exp)   - Expression exp is likely TRUE.
+ *     UNLIKELY(exp) - Expression exp is likely FALSE.
+ *   Usage example:
+ *        if (LIKELY(excCode == EXC_NONE)) {
+ *               or
+ *        if (UNLIKELY(REAL_MODE(vc))) {
+ *
+ * We know how to predict branches on gcc3 and later (hopefully),
+ * all others we don't so we do nothing.
+ */
+
+#if (__GNUC__ >= 3)
+/*
+ * gcc3 uses __builtin_expect() to inform the compiler of an expected value.
+ * We use this to inform the static branch predictor. The '!!' in LIKELY
+ * will convert any !=0 to a 1.
+ */
+#define LIKELY(_exp)     __builtin_expect(!!(_exp), 1)
+#define UNLIKELY(_exp)   __builtin_expect((_exp), 0)
+#else
+#define LIKELY(_exp)      (_exp)
+#define UNLIKELY(_exp)    (_exp)
+#endif
+
+/*
+ * GCC's argument checking for printf-like functions
+ * This is conditional until we have replaced all `"%x", void *'
+ * with `"0x%08x", (uint32) void *'. Note that %p prints different things
+ * on different platforms.  Argument checking is enabled for the
+ * vmkernel, which has already been cleansed.
+ *
+ * fmtPos is the position of the format string argument, beginning at 1
+ * varPos is the position of the variable argument, beginning at 1
+ */
+
+#if defined(__GNUC__)
+# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos)))
+#else
+# define PRINTF_DECL(fmtPos, varPos)
+#endif
+
+#if defined(__GNUC__)
+# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos)))
+#else
+# define SCANF_DECL(fmtPos, varPos)
+#endif
+
+/*
+ * UNUSED_PARAM should surround the parameter name and type declaration,
+ * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))"
+ *
+ */
+
+#ifndef UNUSED_PARAM
+# if defined(__GNUC__)
+#  define UNUSED_PARAM(_parm) _parm  __attribute__((__unused__))
+# else
+#  define UNUSED_PARAM(_parm) _parm
+# endif
+#endif
+
+/*
+ * REGPARM defaults to REGPARM3, i.e., a requent that gcc
+ * puts the first three arguments in registers.  (It is fine
+ * if the function has fewer than three args.)  Gcc only.
+ * Syntactically, put REGPARM where you'd put INLINE or NORETURN.
+ */
+
+#if defined(__GNUC__)
+# define REGPARM0 __attribute__((regparm(0)))
+# define REGPARM1 __attribute__((regparm(1)))
+# define REGPARM2 __attribute__((regparm(2)))
+# define REGPARM3 __attribute__((regparm(3)))
+# define REGPARM REGPARM3
+#else
+# define REGPARM0
+# define REGPARM1
+# define REGPARM2
+# define REGPARM3
+# define REGPARM
+#endif
+
+/*
+ * ALIGNED specifies minimum alignment in "n" bytes.
+ */
+
+#ifdef __GNUC__
+#define ALIGNED(n) __attribute__((__aligned__(n)))
+#else
+#define ALIGNED(n)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_OFFSET_CHECK --                                    */ /**
+ *
+ * \brief Check if the actual offsef of a member in a structure 
+ *        is what is expected
+ * 
+ *
+ * \param[in]  STRUCT       Structure the member is a part of.
+ * \param[in]  MEMBER       Member to check the offset of.
+ * \param[in]  OFFSET       Expected offset of MEMBER in STRUCTURE.
+ * \param[in]  DEBUG_EXTRA  Additional bytes to be added to OFFSET to
+ *                          compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == (OFFSET + DEBUG_EXTRA))
+#else
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == OFFSET)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_SIZE_CHECK --                                      */ /**
+ *
+ * \brief Check if the actual size of a structure is what is expected
+ * 
+ *
+ * \param[in]  STRUCT       Structure whose size is to be checked.
+ * \param[in]  SIZE         Expected size of STRUCT.
+ * \param[in]  DEBUG_EXTRA  Additional bytes to be added to SIZE to
+ *                          compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(sizeof(STRUCT) == (SIZE + DEBUG_EXTRA))
+#else
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(sizeof(STRUCT) == SIZE)
+#endif
+
+/*
+ * __func__ is a stringified function name that is part of the C99 standard. The block
+ * below defines __func__ on older systems where the compiler does not support that
+ * macro.
+ */
+#if defined(__GNUC__) \
+   && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \
+       || (__GNUC__ < 2))
+#   define __func__ __FUNCTION__
+#endif
+
+/*
+ * Once upon a time, this was used to silence compiler warnings that
+ * get generated when the compiler thinks that a function returns
+ * when it is marked noreturn.  Don't do it.  Use NOT_REACHED().
+ */
+
+#define INFINITE_LOOP()           do { } while (1)
+
+/*
+ * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_
+ * is defined. Use the same logic here so we don't define it twice. [greg]
+ */
+#ifdef __FreeBSD__
+#   ifdef _BSD_SIZE_T_
+#      undef _BSD_SIZE_T_
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef uint64 size_t;
+#         else
+             typedef uint32 size_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#   ifdef _BSD_SSIZE_T_
+#      undef _BSD_SSIZE_T_
+#      define _SSIZE_T
+#      define __ssize_t_defined
+#      define _SSIZE_T_DECLARED
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef int64 ssize_t;
+#         else
+             typedef int32 ssize_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#else
+#   ifndef _SIZE_T
+#      define _SIZE_T
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef uint64 size_t;
+#         else
+             typedef uint32 size_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#   if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \
+       !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED)
+#      define _SSIZE_T
+#      define __ssize_t_defined
+#      define _SSIZE_T_DECLARED
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef int64 ssize_t;
+#         else
+             typedef int32 ssize_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#endif
+
+/*
+ * Format modifier for printing pid_t.  On sun the pid_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The pid is %"FMTPID".\n", pid);
+ */
+#ifdef sun
+#   ifdef VM_X86_64
+#      define FMTPID "d"
+#   else
+#      define FMTPID "lu"
+#   endif
+#else
+# define FMTPID "d"
+#endif
+
+/*
+ * Format modifier for printing uid_t.  On Solaris 10 and earlier, uid_t
+ * is a ulong, but on other platforms it's an unsigned int.
+ * Use this like this: printf("The uid is %"FMTUID".\n", uid);
+ */
+#if defined(sun) && !defined(SOL11)
+#   ifdef VM_X86_64
+#      define FMTUID "u"
+#   else
+#      define FMTUID "lu"
+#   endif
+#else
+# define FMTUID "u"
+#endif
+
+/*
+ * Format modifier for printing mode_t.  On sun the mode_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The mode is %"FMTMODE".\n", mode);
+ */
+#ifdef sun
+#   ifdef VM_X86_64
+#      define FMTMODE "o"
+#   else
+#      define FMTMODE "lo"
+#   endif
+#else
+# define FMTMODE "o"
+#endif
+
+/*
+ * Format modifier for printing time_t. Most platforms define a time_t to be
+ * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed
+ * size quantity. Refer to the definition of FMTSZ to see why we need silly
+ * preprocessor arithmetic.
+ * Use this like this: printf("The mode is %"FMTTIME".\n", time);
+ */
+#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
+#   define FMTTIME FMTSZ"d"
+#else
+#   define FMTTIME "ld"
+#endif
+
+/*
+ * Define MXSemaHandle here so both vmmon and vmx see this definition.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t MXSemaHandle;
+#else
+typedef int MXSemaHandle;
+#endif
+
+/*
+ * Define type for poll device handles.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t PollDevHandle;
+#else
+typedef int PollDevHandle;
+#endif
+
+/*
+ * Define the utf16_t type.
+ */
+
+#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED)
+typedef wchar_t utf16_t;
+#else
+typedef uint16 utf16_t;
+#endif
+
+#endif  /* _VM_BASIC_TYPES_H_ */
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vm_device_version.h b/open-vm-tools/modules/solaris/vmxnet3/vm_device_version.h
new file mode 100644 (file)
index 0000000..c35f7b0
--- /dev/null
@@ -0,0 +1,195 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#ifndef VM_DEVICE_VERSION_H
+#define VM_DEVICE_VERSION_H
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMCORE
+#include "includeCheck.h"
+
+#ifdef _WIN32
+#include "guiddef.h"
+#endif
+
+/* LSILogic 53C1030 Parallel SCSI controller
+ * LSILogic SAS1068 SAS controller
+ */
+#define PCI_VENDOR_ID_LSILOGIC          0x1000
+#define PCI_DEVICE_ID_LSI53C1030        0x0030
+#define PCI_DEVICE_ID_LSISAS1068        0x0054
+
+/* Our own PCI IDs
+ *    VMware SVGA II (Unified VGA)
+ *    VMware SVGA (PCI Accelerator)
+ *    VMware vmxnet (Idealized NIC)
+ *    VMware vmxscsi (Abortive idealized SCSI controller)
+ *    VMware chipset (Subsystem ID for our motherboards)
+ *    VMware e1000 (Subsystem ID)
+ *    VMware vmxnet3 (Uniform Pass Through NIC)
+ */
+#define PCI_VENDOR_ID_VMWARE            0x15AD
+#define PCI_DEVICE_ID_VMWARE_SVGA2      0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA       0x0710
+#define PCI_DEVICE_ID_VMWARE_NET        0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI       0x0730
+#define PCI_DEVICE_ID_VMWARE_VMCI       0x0740
+#define PCI_DEVICE_ID_VMWARE_CHIPSET    0x1976
+#define PCI_DEVICE_ID_VMWARE_82545EM    0x0750 /* single port */
+#define PCI_DEVICE_ID_VMWARE_82546EB    0x0760 /* dual port   */
+#define PCI_DEVICE_ID_VMWARE_EHCI       0x0770
+#define PCI_DEVICE_ID_VMWARE_1394       0x0780
+#define PCI_DEVICE_ID_VMWARE_BRIDGE     0x0790
+#define PCI_DEVICE_ID_VMWARE_ROOTPORT   0x07A0
+#define PCI_DEVICE_ID_VMWARE_VMXNET3    0x07B0
+#define PCI_DEVICE_ID_VMWARE_PVSCSI     0x07C0
+
+/* The hypervisor device might grow.  Please leave room
+ * for 7 more subfunctions.
+ */
+#define PCI_DEVICE_ID_VMWARE_HYPER      0x0800
+#define PCI_DEVICE_ID_VMWARE_VMI        0x0801
+
+#define PCI_DEVICE_VMI_CLASS            0x05
+#define PCI_DEVICE_VMI_SUBCLASS         0x80
+#define PCI_DEVICE_VMI_INTERFACE        0x00
+#define PCI_DEVICE_VMI_REVISION         0x01
+
+/* From linux/pci_ids.h:
+ *   AMD Lance Ethernet controller
+ *   BusLogic SCSI controller
+ *   Ensoniq ES1371 sound controller
+ */
+#define PCI_VENDOR_ID_AMD               0x1022
+#define PCI_DEVICE_ID_AMD_VLANCE        0x2000
+#define PCI_VENDOR_ID_BUSLOGIC                 0x104B
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC  0x0140
+#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER     0x1040
+#define PCI_VENDOR_ID_ENSONIQ           0x1274
+#define PCI_DEVICE_ID_ENSONIQ_ES1371    0x1371
+
+/* From linux/pci_ids.h:
+ *    Intel 82439TX (430 HX North Bridge)
+ *    Intel 82371AB (PIIX4 South Bridge)
+ *    Intel 82443BX (440 BX North Bridge and AGP Bridge)
+ *    Intel 82545EM (e1000, server adapter, single port)
+ *    Intel 82546EB (e1000, server adapter, dual port)
+ *    Intel ICH7_16 (High Definition Audio controller)
+ *    Intel HECI (as embedded in ich9m)
+ */
+#define PCI_VENDOR_ID_INTEL             0x8086
+#define PCI_DEVICE_ID_INTEL_82439TX     0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0   0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB_2   0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3   0x7113
+#define PCI_DEVICE_ID_INTEL_82371AB     0x7111
+#define PCI_DEVICE_ID_INTEL_82443BX     0x7190
+#define PCI_DEVICE_ID_INTEL_82443BX_1   0x7191
+#define PCI_DEVICE_ID_INTEL_82443BX_2   0x7192 /* Used when no AGP support */
+#define PCI_DEVICE_ID_INTEL_82545EM     0x100f
+#define PCI_DEVICE_ID_INTEL_82546EB     0x1010
+#define PCI_DEVICE_ID_INTEL_ICH7_16     0x27d8
+#define PCI_DEVICE_ID_INTEL_HECI        0x2a74
+
+
+/************* Strings for IDE Identity Fields **************************/
+#define VIDE_ID_SERIAL_STR     "00000000000000000001"  /* Must be 20 Bytes */
+#define VIDE_ID_FIRMWARE_STR   "00000001"              /* Must be 8 Bytes */
+
+/* No longer than 40 Bytes */
+#define VIDE_ATA_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE Hard Drive"
+#define VIDE_ATAPI_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE CDROM Drive"
+
+#define ATAPI_VENDOR_ID        "NECVMWar"              /* Must be 8 Bytes */
+#define ATAPI_PRODUCT_ID PRODUCT_GENERIC_NAME " IDE CDROM"     /* Must be 16 Bytes */
+#define ATAPI_REV_LEVEL        "1.00"                  /* Must be 4 Bytes */
+
+#define IDE_NUM_INTERFACES   2 /* support for two interfaces */
+#define IDE_DRIVES_PER_IF    2
+
+/************* Strings for SCSI Identity Fields **************************/
+#define SCSI_DISK_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI Hard Drive"
+#define SCSI_DISK_VENDOR_NAME COMPANY_NAME
+#define SCSI_DISK_REV_LEVEL "1.0"
+#define SCSI_CDROM_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI CDROM Drive"
+#define SCSI_CDROM_VENDOR_NAME COMPANY_NAME
+#define SCSI_CDROM_REV_LEVEL "1.0"
+
+/************* SCSI implementation limits ********************************/
+#define SCSI_MAX_CONTROLLERS    4        // Need more than 1 for MSCS clustering
+#define        SCSI_MAX_DEVICES         16       // BT-958 emulates only 16
+#define SCSI_IDE_CHANNEL         SCSI_MAX_CONTROLLERS
+#define SCSI_IDE_HOSTED_CHANNEL  (SCSI_MAX_CONTROLLERS + 1)
+#define SCSI_MAX_CHANNELS        (SCSI_MAX_CONTROLLERS + 2)
+
+/************* Strings for the VESA BIOS Identity Fields *****************/
+#define VBE_OEM_STRING COMPANY_NAME " SVGA"
+#define VBE_VENDOR_NAME COMPANY_NAME
+#define VBE_PRODUCT_NAME PRODUCT_GENERIC_NAME
+
+/************* PCI implementation limits ********************************/
+#define PCI_MAX_BRIDGES         15
+
+/************* Ethernet implementation limits ***************************/
+#define MAX_ETHERNET_CARDS      10
+
+/************* PCI Passthrough implementation limits ********************/
+#define MAX_PCI_PASSTHRU_DEVICES 2
+
+/************* USB implementation limits ********************************/
+#define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127
+
+/************* Strings for Host USB Driver *******************************/
+
+#ifdef _WIN32
+
+/*
+ * Globally unique ID for the VMware device interface. Define INITGUID before including
+ * this header file to instantiate the variable.
+ */
+DEFINE_GUID(GUID_DEVICE_INTERFACE_VMWARE_USB_DEVICES, 
+0x2da1fe75, 0xaab3, 0x4d2c, 0xac, 0xdf, 0x39, 0x8, 0x8c, 0xad, 0xa6, 0x65);
+
+/*
+ * Globally unique ID for the VMware device setup class.
+ */
+DEFINE_GUID(GUID_CLASS_VMWARE_USB_DEVICES, 
+0x3b3e62a5, 0x3556, 0x4d7e, 0xad, 0xad, 0xf5, 0xfa, 0x3a, 0x71, 0x2b, 0x56);
+
+/*
+ * This string defines the device ID string of a VMware USB device.
+ * The format is USB\Vid_XXXX&Pid_YYYY, where XXXX and YYYY are the
+ * hexadecimal representations of the vendor and product ids, respectively.
+ *
+ * The official vendor ID for VMware, Inc. is 0x0E0F.
+ * The product id for USB generic devices is 0x0001.
+ */
+#define USB_VMWARE_DEVICE_ID_WIDE L"USB\\Vid_0E0F&Pid_0001"
+#define USB_DEVICE_ID_LENGTH (sizeof(USB_VMWARE_DEVICE_ID_WIDE) / sizeof(WCHAR))
+
+#ifdef UNICODE
+#define USB_PNP_SETUP_CLASS_NAME L"VMwareUSBDevices"
+#define USB_PNP_DRIVER_NAME L"vmusb"
+#else
+#define USB_PNP_SETUP_CLASS_NAME "VMwareUSBDevices"
+#define USB_PNP_DRIVER_NAME "vmusb"
+#endif
+#endif
+
+#endif /* VM_DEVICE_VERSION_H */
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmnet_def.h b/open-vm-tools/modules/solaris/vmxnet3/vmnet_def.h
new file mode 100644 (file)
index 0000000..c02c5fe
--- /dev/null
@@ -0,0 +1,62 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * vmnet_def.h 
+ *
+ *     - definitions which are (mostly) not vmxnet or vlance specific
+ */
+
+#ifndef _VMNET_DEF_H_
+#define _VMNET_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMNIXMOD
+#include "includeCheck.h"
+
+/*
+ * capabilities - not all of these are implemented in the virtual HW
+ *                (eg VLAN support is in the virtual switch)  so even vlance 
+ *                can use them
+ */
+#define VMNET_CAP_SG           0x0001  /* Can do scatter-gather transmits. */
+#define VMNET_CAP_IP4_CSUM      0x0002 /* Can checksum only TCP/UDP over IPv4. */
+#define VMNET_CAP_HW_CSUM       0x0004 /* Can checksum all packets. */
+#define VMNET_CAP_HIGH_DMA      0x0008 /* Can DMA to high memory. */
+#define VMNET_CAP_TOE          0x0010  /* Supports TCP/IP offload. */
+#define VMNET_CAP_TSO          0x0020  /* Supports TCP Segmentation offload */
+#define VMNET_CAP_SW_TSO        0x0040 /* Supports SW TCP Segmentation */
+#define VMNET_CAP_VMXNET_APROM  0x0080 /* Vmxnet APROM support */
+#define VMNET_CAP_HW_TX_VLAN    0x0100  /* Can we do VLAN tagging in HW */
+#define VMNET_CAP_HW_RX_VLAN    0x0200  /* Can we do VLAN untagging in HW */
+#define VMNET_CAP_SW_VLAN       0x0400  /* Can we do VLAN tagging/untagging in SW */
+#define VMNET_CAP_WAKE_PCKT_RCV 0x0800  /* Can wake on network packet recv? */
+#define VMNET_CAP_ENABLE_INT_INLINE 0x1000  /* Enable Interrupt Inline */
+#define VMNET_CAP_ENABLE_HEADER_COPY 0x2000  /* copy header for vmkernel */
+#define VMNET_CAP_TX_CHAIN      0x4000  /* Guest can use multiple tx entries for a pkt */
+#define VMNET_CAP_RX_CHAIN      0x8000  /* a pkt can span multiple rx entries */
+#define VMNET_CAP_LPD           0x10000 /* large pkt delivery */
+#define VMNET_CAP_BPF           0x20000 /* BPF Support in VMXNET Virtual Hardware */
+#define VMNET_CAP_SG_SPAN_PAGES 0x40000        /* Can do scatter-gather span multiple pages transmits. */
+#define VMNET_CAP_IP6_CSUM      0x80000        /* Can do IPv6 csum offload. */
+#define VMNET_CAP_TSO6         0x100000        /* Can do TSO segmentation offload for IPv6 pkts. */
+#define VMNET_CAP_TSO256k      0x200000        /* Can do TSO segmentation offload for pkts up to 256kB. */
+#endif // _VMNET_DEF_H_
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmware_pack_begin.h b/open-vm-tools/modules/solaris/vmxnet3/vmware_pack_begin.h
new file mode 100644 (file)
index 0000000..7dd9b05
--- /dev/null
@@ -0,0 +1,41 @@
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * vmware_pack_begin.h --
+ *
+ *    Begin of structure packing. See vmware_pack_init.h for details.
+ *
+ *    Note that we do not use the following construct in this include file,
+ *    because we want to emit the code every time the file is included --hpreg
+ *
+ *    #ifndef foo
+ *    #   define foo
+ *    ...
+ *    #endif
+ *
+ */
+
+
+#include "vmware_pack_init.h"
+
+
+#ifdef _MSC_VER
+#   pragma pack(push, 1)
+#elif __GNUC__
+#else
+#   error Compiler packing...
+#endif
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmware_pack_end.h b/open-vm-tools/modules/solaris/vmxnet3/vmware_pack_end.h
new file mode 100644 (file)
index 0000000..0959b26
--- /dev/null
@@ -0,0 +1,42 @@
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * vmware_pack_end.h --
+ *
+ *    End of structure packing. See vmware_pack_init.h for details.
+ *
+ *    Note that we do not use the following construct in this include file,
+ *    because we want to emit the code every time the file is included --hpreg
+ *
+ *    #ifndef foo
+ *    #   define foo
+ *    ...
+ *    #endif
+ *
+ */
+
+
+#include "vmware_pack_init.h"
+
+
+#ifdef _MSC_VER
+#   pragma pack(pop)
+#elif __GNUC__
+__attribute__((__packed__))
+#else
+#   error Compiler packing...
+#endif
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet2_def.h b/open-vm-tools/modules/solaris/vmxnet3/vmxnet2_def.h
new file mode 100644 (file)
index 0000000..5fede92
--- /dev/null
@@ -0,0 +1,414 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#ifndef _VMXNET2_DEF_H_
+#define _VMXNET2_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "net_sg.h"
+#include "vmxnet_def.h"
+
+
+/*
+ * Magic number that identifies this version of the vmxnet protocol.
+ */
+#define VMXNET2_MAGIC                  0xbabe864f
+
+/* size of the rx ring */
+#define VMXNET2_MAX_NUM_RX_BUFFERS             128
+#define VMXNET2_DEFAULT_NUM_RX_BUFFERS         100
+
+
+/* size of the rx ring when enhanced vmxnet is used */
+#define ENHANCED_VMXNET2_MAX_NUM_RX_BUFFERS     512 
+#define ENHANCED_VMXNET2_DEFAULT_NUM_RX_BUFFERS 150 
+
+/* size of the 2nd rx ring */
+#define VMXNET2_MAX_NUM_RX_BUFFERS2             2048 
+#define VMXNET2_DEFAULT_NUM_RX_BUFFERS2                512
+
+/* size of the tx ring */
+#define VMXNET2_MAX_NUM_TX_BUFFERS             128
+#define VMXNET2_DEFAULT_NUM_TX_BUFFERS         100
+
+/* size of the tx ring when tso/jf is used */
+#define VMXNET2_MAX_NUM_TX_BUFFERS_TSO          512
+#define VMXNET2_DEFAULT_NUM_TX_BUFFERS_TSO     256
+
+enum {
+   VMXNET2_OWNERSHIP_DRIVER,
+   VMXNET2_OWNERSHIP_DRIVER_PENDING,
+   VMXNET2_OWNERSHIP_NIC,
+   VMXNET2_OWNERSHIP_NIC_PENDING,
+   VMXNET2_OWNERSHIP_NIC_FRAG,
+   VMXNET2_OWNERSHIP_DRIVER_FRAG,
+};
+
+#define VMXNET2_SG_DEFAULT_LENGTH      6
+
+typedef struct Vmxnet2_SG_Array {
+   uint16      addrType;
+   uint16      length;
+   NetSG_Elem  sg[VMXNET2_SG_DEFAULT_LENGTH];
+} Vmxnet2_SG_Array;
+
+typedef struct Vmxnet2_RxRingEntry {
+   uint64              paddr;          /* Physical address of the packet data. */
+   uint32              bufferLength;   /* The length of the data at paddr. */
+   uint32              actualLength;   /* The actual length of the received data. */
+   uint16               ownership;     /* Who owns the packet. */
+   uint16              flags;          /* Flags as defined below. */
+   uint32               index;          /* 
+                                         * Currently:
+                                         *
+                                         * This is being used as an packet index to
+                                         * rx buffers.
+                                         *
+                                         * Originally: 
+                                         *
+                                        * was void* driverData ("Driver specific data.")
+                                        * which was used for sk_buf**s in Linux and
+                                         * VmxnetRxBuff*s in Windows.  It could not be
+                                        * here because the structure needs to be the
+                                        * same size between architectures, and it was
+                                        * not used on the device side, anyway.  Look
+                                        * for its replacement in
+                                        * Vmxnet_Private.rxRingBuffPtr on Linux and
+                                        * VmxnetAdapter.rxRingBuffPtr on Windows.
+                                        */
+} Vmxnet2_RxRingEntry;
+
+/*
+ * Vmxnet2_RxRingEntry flags:
+ * 
+ * VMXNET2_RX_HW_XSUM_OK       The hardware verified the TCP/UDP checksum.
+ * VMXNET2_RX_WITH_FRAG        More data is in the 2nd ring
+ * VMXNET2_RX_FRAG_EOP         This is the last frag, the only valid flag for
+ *                             2nd ring entry
+ *
+ */
+#define VMXNET2_RX_HW_XSUM_OK  0x01
+#define VMXNET2_RX_WITH_FRAG   0x02
+#define VMXNET2_RX_FRAG_EOP    0x04
+
+typedef struct Vmxnet2_TxRingEntry {
+   uint16              flags;          /* Flags as defined below. */
+   uint16              ownership;      /* Who owns this packet. */
+   uint32               extra;          /*
+                                        * was void* driverData ("Driver specific data.")
+                                        * which was used for sk_buf*s in Linux and
+                                         * VmxnetTxInfo*s in Windows.  It could not be
+                                        * here because the structure needs to be the
+                                        * same size between architectures, and it was
+                                        * not used on the device side, anyway.  Look
+                                        * for its replacement in
+                                        * Vmxnet_Private.txRingBuffPtr on Linux and
+                                        * VmxnetAdapter.txRingBuffPtr on Windows.
+                                        */
+   uint32               tsoMss;         /* TSO pkt MSS */
+   Vmxnet2_SG_Array    sg;             /* Packet data. */
+} Vmxnet2_TxRingEntry;
+
+/*
+ * Vmxnet2_TxRingEntry flags:
+ *
+ *   VMXNET2_TX_CAN_KEEP       The implementation can return the tx ring entry 
+ *                             to the driver when it is ready as opposed to 
+ *                             before the transmit call from the driver completes.
+ *   VMXNET2_TX_RING_LOW       The driver's transmit ring buffer is low on free
+ *                             slots.
+ *   VMXNET2_TX_HW_XSUM         The hardware should perform the TCP/UDP checksum
+ *   VMXNET2_TX_TSO             The hardware should do TCP segmentation.
+ *   VMXNET2_TX_PINNED_BUFFER   The driver used one of the preallocated vmkernel
+ *                              buffers *and* it has been pinned with Net_PinTxBuffers.
+ *   VMXNET2_TX_MORE            This is *not* the last tx entry for the pkt.
+ *                              All flags except VMXNET2_TX_MORE are ignored
+ *                              for the subsequent tx entries.
+ */
+#define VMXNET2_TX_CAN_KEEP         0x0001
+#define VMXNET2_TX_RING_LOW         0x0002
+#define VMXNET2_TX_HW_XSUM           0x0004
+#define VMXNET2_TX_TSO              0x0008
+#define VMXNET2_TX_PINNED_BUFFER     0x0010
+#define VMXNET2_TX_MORE              0x0020
+
+/*
+ * Structure used by implementations.  This structure allows the inline
+ * functions below to be used.
+ */
+typedef struct Vmxnet2_RxRingInfo {
+   Vmxnet2_RxRingEntry    *base;       /* starting addr of the ring */
+   uint32                  nicNext;    /* next entry to use in the ring */
+   uint32                  ringLength; /* # of entries in the ring */
+   PA                      startPA;    /* PA of the starting addr of the ring */
+#ifdef VMX86_DEBUG
+   const char             *name;
+#endif
+} Vmxnet2_RxRingInfo;
+
+typedef struct Vmxnet2_TxRingInfo {
+   Vmxnet2_TxRingEntry    *base;       /* starting addr of the ring */
+   uint32                  nicNext;    /* next entry to use in the ring */
+   uint32                  ringLength; /* # of entries in the ring */
+   PA                      startPA;    /* PA of the starting addr of the ring */
+#ifdef VMX86_DEBUG
+   const char             *name;
+#endif
+} Vmxnet2_TxRingInfo;
+
+typedef struct Vmxnet2_ImplData {
+   Vmxnet2_RxRingInfo    rxRing;
+   Vmxnet2_RxRingInfo    rxRing2;
+   Vmxnet2_TxRingInfo    txRing;
+
+   struct PhysMem_Token          *ddPhysMemToken;
+} Vmxnet2_ImplData;
+
+/* 
+ * Used internally for performance studies. By default this will be off so there 
+ * should be no compatibilty or other interferences.
+ */
+
+/* #define ENABLE_VMXNET2_PROFILING    */
+
+
+#ifdef ENABLE_VMXNET2_PROFILING
+typedef struct Vmxnet2_VmmStats {
+   uint64      vIntTSC;             /* the time that virtual int was posted */
+   uint64      actionsCount;        /* Number of actions received */
+   uint64      numWasteActions;     /* Number of non-productive actions */
+}  Vmxnet2_VmmStats;
+#endif
+
+typedef struct Vmxnet2_DriverStats {
+   uint32      transmits;         /* # of times that the drivers transmit function */
+                                  /*   is called. The driver could transmit more */
+                                  /*   than one packet per call. */
+   uint32      pktsTransmitted;   /* # of packets transmitted. */
+   uint32      noCopyTransmits;   /* # of packets that are transmitted without */
+                                  /*   copying any data. */
+   uint32      copyTransmits;     /* # of packets that are transmittted by copying */
+                                  /*   the data into a buffer. */
+   uint32      maxTxsPending;     /* Max # of transmits outstanding. */
+   uint32      txStopped;         /* # of times that transmits got stopped because */
+                                  /*   the tx ring was full. */
+   uint32      txRingOverflow;    /* # of times that transmits got deferred bc */
+                                  /*   the tx ring was full.  This must be >= */
+                                  /*   txStopped since there will be one */
+                                  /*   txStopped when the ring fills up and then */
+                                  /*   one txsRingOverflow for each packet that */
+                                  /*   that gets deferred until there is space. */
+   uint32      interrupts;        /* # of times interrupted. */
+   uint32      pktsReceived;      /* # of packets received. */
+   uint32      rxBuffersLow;      /* # of times that the driver was low on */
+                                  /*   receive buffers. */
+#ifdef ENABLE_VMXNET2_PROFILING
+    Vmxnet2_VmmStats  vmmStats;     /* vmm related stats for perf study */
+#endif
+} Vmxnet2_DriverStats;
+
+/*
+ * Shared data structure between the vm, the vmm, and the vmkernel.
+ * This structure was originally arranged to try to group common data 
+ * on 32-byte cache lines, but bit rot and the fact that we no longer
+ * run on many CPUs with that cacheline size killed that optimization.
+ * vmxnet3 should target 128 byte sizes and alignments to optimize for
+ * the 64 byte cacheline pairs on P4.
+ */
+typedef struct Vmxnet2_DriverData {
+   /*
+    * Magic must be first.
+    */
+   Vmxnet_DDMagic       magic;
+
+   /*
+    * Receive fields. 
+    */
+   uint32              rxRingLength;           /* Length of the receive ring. */
+   uint32              rxDriverNext;           /* Index of the next packet that will */
+                                               /*   be filled in by the impl */
+
+   uint32              rxRingLength2;          /* Length of the 2nd receive ring. */
+   uint32              rxDriverNext2;          /* Index of the next packet that will */
+                                               /*   be filled in by the impl */
+
+   uint32              notUsed1;               /* was "irq" */
+
+   /*
+    * Interface flags and multicast filter.
+    */
+   uint32              ifflags;
+   uint32              LADRF[VMXNET_MAX_LADRF];
+
+   /*
+    * Transmit fields
+    */
+   uint32               txDontClusterSize;      /* All packets <= this will be transmitted */
+                                                /* immediately, regardless of clustering */
+                                                /* settings [was fill[1]] */
+   uint32              txRingLength;           /* Length of the transmit ring. */
+   uint32              txDriverCur;            /* Index of the next packet to be */
+                                               /*   returned by the implementation.*/
+   uint32              txDriverNext;           /* Index of the entry in the ring */
+                                               /*   buffer to use for the next packet.*/
+   uint32              txStopped;              /* The driver has stopped transmitting */
+                                               /*   because its ring buffer is full.*/
+   uint32              txClusterLength;        /* Maximum number of packets to */
+                                               /*   put in the ring buffer before */
+                                               /*   asking the implementation to */
+                                               /*   transmit the packets in the buffer.*/
+   uint32              txNumDeferred;          /* Number of packets that have been */
+                                               /*   queued in the ring buffer since */
+                                               /*   the last time the implementation */
+                                               /*   was asked to transmit. */
+   uint32              notUsed3;               /* This field is deprecated but still used */
+                                                /* as minXmitPhysLength on the escher branch. */
+                                                /* It cannot be used for other purposes */
+                                                /* until escher vms no longer are allowed */
+                                                /* to install this driver. */
+
+   uint32              totalRxBuffers;          /* used by esx for max rx buffers */
+   uint64              rxBufferPhysStart;       /* used by esx for pinng rx buffers */
+   /*
+    * Extra fields for future expansion.
+    */
+   uint32              extra[2];
+
+   uint16               maxFrags;               /* # of frags the driver can handle */
+   uint16               featureCtl;             /* for driver to enable some feature */
+
+   /*
+    * The following fields are used to save the nicNext indexes part
+    * of implData in the vmkernel when disconnecting the adapter, we
+    * need them when we reconnect.  This mechanism is used for
+    * checkpointing as well.
+    */
+   uint32               savedRxNICNext;
+   uint32               savedRxNICNext2;
+   uint32               savedTxNICNext;
+
+   /*
+    * Fields used during initialization or debugging.
+    */
+   uint32              length;
+   uint32              rxRingOffset;
+   uint32              rxRingOffset2;
+   uint32              txRingOffset;   
+   uint32              debugLevel;
+   uint32              txBufferPhysStart;
+   uint32              txBufferPhysLength;
+   uint32              txPktMaxSize;
+
+   /*
+    * Driver statistics.
+    */
+   Vmxnet2_DriverStats stats;
+} Vmxnet2_DriverData;
+
+/* 
+ * Shared between VMM and Vmkernel part of vmxnet2 to optimize action posting
+ * VMM writes 1 (don't post) or 0 (okay to post) and vmk reads this.
+ */
+typedef struct VmxnetVMKShared {
+   uint32  dontPostActions;  
+} VmxnetVMKShared;
+
+/*
+ * Inline functions used to assist the implementation of the vmxnet interface.
+ */
+
+/*
+ * Get the next empty packet out of the receive ring and move to 
+ * the next packet.
+ */
+static INLINE Vmxnet2_RxRingEntry *
+Vmxnet2_GetNextRx(Vmxnet2_RxRingInfo *ri, uint16 ownership)
+{
+   Vmxnet2_RxRingEntry *rre = ri->base + ri->nicNext;
+   if (rre->ownership == ownership) {
+      VMXNET_INC(ri->nicNext, ri->ringLength);
+   } else {
+      rre = NULL;
+   }
+
+   return rre;
+}
+
+/*
+ * Return ownership of a packet in the receive ring to the driver.
+ */
+static INLINE void
+Vmxnet2_PutRx(Vmxnet2_RxRingEntry *rre, uint32 pktLength, uint16 ownership)
+{
+   rre->actualLength = pktLength;
+   rre->ownership = ownership;
+}
+
+/*
+ * Get the next pending packet out of the transmit ring.
+ */
+static INLINE Vmxnet2_TxRingEntry *
+Vmxnet2_GetNextTx(Vmxnet2_TxRingInfo *ri)
+{
+   Vmxnet2_TxRingEntry *txre = ri->base + ri->nicNext;
+   if (txre->ownership == VMXNET2_OWNERSHIP_NIC) {
+      return txre;
+   } else {
+      return NULL;
+   }
+}
+
+/*
+ * Move to the next entry in the transmit ring.
+ */
+static INLINE unsigned int
+Vmxnet2_IncNextTx(Vmxnet2_TxRingInfo *ri)
+{
+   unsigned int prev = ri->nicNext;
+   Vmxnet2_TxRingEntry *txre = ri->base + ri->nicNext;
+   
+   txre->ownership = VMXNET2_OWNERSHIP_NIC_PENDING;
+
+   VMXNET_INC(ri->nicNext, ri->ringLength);
+   return prev;
+}
+
+/*
+ * Get the indicated entry from transmit ring.
+ */
+static INLINE Vmxnet2_TxRingEntry *
+Vmxnet2_GetTxEntry(Vmxnet2_TxRingInfo *ri, unsigned int idx)
+{
+   return ri->base + idx;
+}
+
+/*
+ * Get the indicated entry from the given rx ring
+ */
+static INLINE Vmxnet2_RxRingEntry *
+Vmxnet2_GetRxEntry(Vmxnet2_RxRingInfo *ri, unsigned int idx)
+{
+   return ri->base + idx;
+}
+#endif
+
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_defs.h b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_defs.h
new file mode 100644 (file)
index 0000000..c1ea9d4
--- /dev/null
@@ -0,0 +1,589 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * vmxnet3_defs.h --
+ *
+ *      Definitions shared by device emulation and guest drivers for
+ *      VMXNET3 NIC
+ */
+
+#ifndef _VMXNET3_DEFS_H_
+#define _VMXNET3_DEFS_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_MODULE
+#include "includeCheck.h"
+
+#include "upt1_defs.h"
+
+/* all registers are 32 bit wide */
+/* BAR 1 */
+#define VMXNET3_REG_VRRS  0x0    /* Vmxnet3 Revision Report Selection */
+#define VMXNET3_REG_UVRS  0x8    /* UPT Version Report Selection */
+#define VMXNET3_REG_DSAL  0x10   /* Driver Shared Address Low */
+#define VMXNET3_REG_DSAH  0x18   /* Driver Shared Address High */
+#define VMXNET3_REG_CMD   0x20   /* Command */
+#define VMXNET3_REG_MACL  0x28   /* MAC Address Low */
+#define VMXNET3_REG_MACH  0x30   /* MAC Address High */
+#define VMXNET3_REG_ICR   0x38   /* Interrupt Cause Register */
+#define VMXNET3_REG_ECR   0x40   /* Event Cause Register */
+
+/* BAR 0 */
+#define VMXNET3_REG_IMR      0x0   /* Interrupt Mask Register */
+#define VMXNET3_REG_TXPROD   0x600 /* Tx Producer Index */
+#define VMXNET3_REG_RXPROD   0x800 /* Rx Producer Index for ring 1 */
+#define VMXNET3_REG_RXPROD2  0xA00 /* Rx Producer Index for ring 2 */
+
+#define VMXNET3_PT_REG_SIZE     4096    /* BAR 0 */
+#define VMXNET3_VD_REG_SIZE     4096    /* BAR 1 */
+
+#define VMXNET3_REG_ALIGN       8  /* All registers are 8-byte aligned. */
+#define VMXNET3_REG_ALIGN_MASK  0x7
+
+/* I/O Mapped access to registers */
+#define VMXNET3_IO_TYPE_PT              0
+#define VMXNET3_IO_TYPE_VD              1
+#define VMXNET3_IO_ADDR(type, reg)      (((type) << 24) | ((reg) & 0xFFFFFF))
+#define VMXNET3_IO_TYPE(addr)           ((addr) >> 24)
+#define VMXNET3_IO_REG(addr)            ((addr) & 0xFFFFFF)
+
+typedef enum {
+   VMXNET3_CMD_FIRST_SET = 0xCAFE0000,
+   VMXNET3_CMD_ACTIVATE_DEV = VMXNET3_CMD_FIRST_SET,
+   VMXNET3_CMD_QUIESCE_DEV,
+   VMXNET3_CMD_RESET_DEV,
+   VMXNET3_CMD_UPDATE_RX_MODE,
+   VMXNET3_CMD_UPDATE_MAC_FILTERS,
+   VMXNET3_CMD_UPDATE_VLAN_FILTERS,
+   VMXNET3_CMD_UPDATE_RSSIDT,
+   VMXNET3_CMD_UPDATE_IML,
+   VMXNET3_CMD_UPDATE_PMCFG,
+   VMXNET3_CMD_UPDATE_FEATURE,
+
+   VMXNET3_CMD_FIRST_GET = 0xF00D0000,
+   VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET,
+   VMXNET3_CMD_GET_STATS,
+   VMXNET3_CMD_GET_LINK,
+   VMXNET3_CMD_GET_PERM_MAC_LO,
+   VMXNET3_CMD_GET_PERM_MAC_HI,
+   VMXNET3_CMD_GET_DID_LO,
+   VMXNET3_CMD_GET_DID_HI,
+   VMXNET3_CMD_GET_DEV_EXTRA_INFO,
+   VMXNET3_CMD_GET_CONF_INTR
+} Vmxnet3_Cmd;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_TxDesc {
+   uint64 addr;
+
+   uint32 len:14;
+   uint32 gen:1;      /* generation bit */
+   uint32 rsvd:1;
+   uint32 dtype:1;    /* descriptor type */
+   uint32 ext1:1;
+   uint32 msscof:14;  /* MSS, checksum offset, flags */
+
+   uint32 hlen:10;    /* header len */
+   uint32 om:2;       /* offload mode */
+   uint32 eop:1;      /* End Of Packet */
+   uint32 cq:1;       /* completion request */
+   uint32 ext2:1;
+   uint32 ti:1;       /* VLAN Tag Insertion */
+   uint32 tci:16;     /* Tag to Insert */
+}
+#include "vmware_pack_end.h"
+Vmxnet3_TxDesc;
+
+/* TxDesc.OM values */
+#define VMXNET3_OM_NONE  0
+#define VMXNET3_OM_CSUM  2
+#define VMXNET3_OM_TSO   3
+
+/* fields in TxDesc we access w/o using bit fields */
+#define VMXNET3_TXD_EOP_SHIFT 12
+#define VMXNET3_TXD_CQ_SHIFT  13
+#define VMXNET3_TXD_GEN_SHIFT 14
+
+#define VMXNET3_TXD_CQ  (1 << VMXNET3_TXD_CQ_SHIFT)
+#define VMXNET3_TXD_EOP (1 << VMXNET3_TXD_EOP_SHIFT)
+#define VMXNET3_TXD_GEN (1 << VMXNET3_TXD_GEN_SHIFT)
+
+#define VMXNET3_HDR_COPY_SIZE   128
+
+typedef
+#include "vmware_pack_begin.h"
+struct vmxnet3_TxDataDesc {
+   uint8 data[VMXNET3_HDR_COPY_SIZE];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_TxDataDesc;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_TxCompDesc {
+   uint32 txdIdx:12;    /* Index of the EOP TxDesc */
+   uint32 ext1:20;
+
+   uint32 ext2;
+   uint32 ext3;
+
+   uint32 rsvd:24;
+   uint32 type:7;       /* completion type */
+   uint32 gen:1;        /* generation bit */
+}
+#include "vmware_pack_end.h"
+Vmxnet3_TxCompDesc;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_RxDesc {
+   uint64 addr;
+
+   uint32 len:14;
+   uint32 btype:1;      /* Buffer Type */
+   uint32 dtype:1;      /* Descriptor type */
+   uint32 rsvd:15;
+   uint32 gen:1;        /* Generation bit */
+
+   uint32 ext1;
+}
+#include "vmware_pack_end.h"
+Vmxnet3_RxDesc;
+
+/* values of RXD.BTYPE */
+#define VMXNET3_RXD_BTYPE_HEAD   0    /* head only */
+#define VMXNET3_RXD_BTYPE_BODY   1    /* body only */
+
+/* fields in RxDesc we access w/o using bit fields */
+#define VMXNET3_RXD_BTYPE_SHIFT  14
+#define VMXNET3_RXD_GEN_SHIFT    31
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_RxCompDesc {
+   uint32 rxdIdx:12;    /* Index of the RxDesc */
+   uint32 ext1:2;
+   uint32 eop:1;        /* End of Packet */
+   uint32 sop:1;        /* Start of Packet */
+   uint32 rqID:10;      /* rx queue/ring ID */
+   uint32 rssType:4;    /* RSS hash type used */
+   uint32 cnc:1;        /* Checksum Not Calculated */
+   uint32 ext2:1;
+
+   uint32 rssHash;      /* RSS hash value */
+
+   uint32 len:14;       /* data length */
+   uint32 err:1;        /* Error */
+   uint32 ts:1;         /* Tag is stripped */
+   uint32 tci:16;       /* Tag stripped */
+
+   uint32 csum:16;
+   uint32 tuc:1;        /* TCP/UDP Checksum Correct */
+   uint32 udp:1;        /* UDP packet */
+   uint32 tcp:1;        /* TCP packet */
+   uint32 ipc:1;        /* IP Checksum Correct */
+   uint32 v6:1;         /* IPv6 */
+   uint32 v4:1;         /* IPv4 */
+   uint32 frg:1;        /* IP Fragment */
+   uint32 fcs:1;        /* Frame CRC correct */
+   uint32 type:7;       /* completion type */
+   uint32 gen:1;        /* generation bit */
+}
+#include "vmware_pack_end.h"
+Vmxnet3_RxCompDesc;
+
+/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
+#define VMXNET3_RCD_TUC_SHIFT  16
+#define VMXNET3_RCD_IPC_SHIFT  19
+
+/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.qword[1] */
+#define VMXNET3_RCD_TYPE_SHIFT 56
+#define VMXNET3_RCD_GEN_SHIFT  63
+
+/* csum OK for TCP/UDP pkts over IP */
+#define VMXNET3_RCD_CSUM_OK (1 << VMXNET3_RCD_TUC_SHIFT | 1 << VMXNET3_RCD_IPC_SHIFT)
+
+/* value of RxCompDesc.rssType */
+#define VMXNET3_RCD_RSS_TYPE_NONE     0
+#define VMXNET3_RCD_RSS_TYPE_IPV4     1
+#define VMXNET3_RCD_RSS_TYPE_TCPIPV4  2
+#define VMXNET3_RCD_RSS_TYPE_IPV6     3
+#define VMXNET3_RCD_RSS_TYPE_TCPIPV6  4
+
+/* a union for accessing all cmd/completion descriptors */
+typedef union Vmxnet3_GenericDesc {
+   uint64             qword[2];
+   uint32             dword[4];
+   uint16             word[8];
+   Vmxnet3_TxDesc     txd;
+   Vmxnet3_RxDesc     rxd;
+   Vmxnet3_TxCompDesc tcd;
+   Vmxnet3_RxCompDesc rcd;
+} Vmxnet3_GenericDesc;
+
+#define VMXNET3_INIT_GEN       1
+
+/* Max size of a single tx buffer */
+#define VMXNET3_MAX_TX_BUF_SIZE  (1 << 14)
+
+/* # of tx desc needed for a tx buffer size */
+#define VMXNET3_TXD_NEEDED(size) (((size) + VMXNET3_MAX_TX_BUF_SIZE - 1) / VMXNET3_MAX_TX_BUF_SIZE)
+
+/* max # of tx descs for a non-tso pkt */
+#define VMXNET3_MAX_TXD_PER_PKT 16
+
+/* Max size of a single rx buffer */
+#define VMXNET3_MAX_RX_BUF_SIZE  ((1 << 14) - 1)
+/* Minimum size of a type 0 buffer */
+#define VMXNET3_MIN_T0_BUF_SIZE  128
+#define VMXNET3_MAX_CSUM_OFFSET  1024
+
+/* Ring base address alignment */
+#define VMXNET3_RING_BA_ALIGN   512
+#define VMXNET3_RING_BA_MASK    (VMXNET3_RING_BA_ALIGN - 1)
+
+/* Ring size must be a multiple of 32 */
+#define VMXNET3_RING_SIZE_ALIGN 32
+#define VMXNET3_RING_SIZE_MASK  (VMXNET3_RING_SIZE_ALIGN - 1)
+
+/* Max ring size */
+#define VMXNET3_TX_RING_MAX_SIZE   4096
+#define VMXNET3_TC_RING_MAX_SIZE   4096
+#define VMXNET3_RX_RING_MAX_SIZE   4096
+#define VMXNET3_RC_RING_MAX_SIZE   8192
+
+/* a list of reasons for queue stop */
+
+#define VMXNET3_ERR_NOEOP        0x80000000  /* cannot find the EOP desc of a pkt */
+#define VMXNET3_ERR_TXD_REUSE    0x80000001  /* reuse a TxDesc before tx completion */
+#define VMXNET3_ERR_BIG_PKT      0x80000002  /* too many TxDesc for a pkt */
+#define VMXNET3_ERR_DESC_NOT_SPT 0x80000003  /* descriptor type not supported */
+#define VMXNET3_ERR_SMALL_BUF    0x80000004  /* type 0 buffer too small */
+#define VMXNET3_ERR_STRESS       0x80000005  /* stress option firing in vmkernel */
+#define VMXNET3_ERR_SWITCH       0x80000006  /* mode switch failure */
+#define VMXNET3_ERR_TXD_INVALID  0x80000007  /* invalid TxDesc */
+
+/* completion descriptor types */
+#define VMXNET3_CDTYPE_TXCOMP      0    /* Tx Completion Descriptor */
+#define VMXNET3_CDTYPE_RXCOMP      3    /* Rx Completion Descriptor */
+
+#define VMXNET3_GOS_BITS_UNK    0   /* unknown */
+#define VMXNET3_GOS_BITS_32     1
+#define VMXNET3_GOS_BITS_64     2
+
+#define VMXNET3_GOS_TYPE_UNK        0 /* unknown */
+#define VMXNET3_GOS_TYPE_LINUX      1
+#define VMXNET3_GOS_TYPE_WIN        2
+#define VMXNET3_GOS_TYPE_SOLARIS    3
+#define VMXNET3_GOS_TYPE_FREEBSD    4
+#define VMXNET3_GOS_TYPE_PXE        5
+
+/* All structures in DriverShared are padded to multiples of 8 bytes */
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_GOSInfo {
+   uint32   gosBits: 2;     /* 32-bit or 64-bit? */
+   uint32   gosType: 4;     /* which guest */
+   uint32   gosVer:  16;    /* gos version */
+   uint32   gosMisc: 10;    /* other info about gos */
+} 
+#include "vmware_pack_end.h"
+Vmxnet3_GOSInfo;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_DriverInfo {
+   uint32          version;        /* driver version */
+   Vmxnet3_GOSInfo gos;
+   uint32          vmxnet3RevSpt;  /* vmxnet3 revision supported */
+   uint32          uptVerSpt;      /* upt version supported */
+}
+#include "vmware_pack_end.h"
+Vmxnet3_DriverInfo;
+
+#define VMXNET3_REV1_MAGIC  0xbabefee1
+
+/* 
+ * QueueDescPA must be 128 bytes aligned. It points to an array of
+ * Vmxnet3_TxQueueDesc followed by an array of Vmxnet3_RxQueueDesc.
+ * The number of Vmxnet3_TxQueueDesc/Vmxnet3_RxQueueDesc are specified by
+ * Vmxnet3_MiscConf.numTxQueues/numRxQueues, respectively.
+ */
+#define VMXNET3_QUEUE_DESC_ALIGN  128
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_MiscConf {
+   Vmxnet3_DriverInfo driverInfo;
+   uint64             uptFeatures;
+   uint64             ddPA;         /* driver data PA */
+   uint64             queueDescPA;  /* queue descriptor table PA */
+   uint32             ddLen;        /* driver data len */
+   uint32             queueDescLen; /* queue descriptor table len, in bytes */
+   uint32             mtu;
+   uint16             maxNumRxSG;
+   uint8              numTxQueues;
+   uint8              numRxQueues;
+   uint32             reserved[4];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_MiscConf;
+
+typedef
+#include "vmware_pack_begin.h"
+struct vmxnet3_TxQueueConf {
+   uint64    txRingBasePA;
+   uint64    dataRingBasePA;
+   uint64    compRingBasePA;
+   uint64    ddPA;         /* driver data */
+   uint64    reserved;
+   uint32    txRingSize;   /* # of tx desc */
+   uint32    dataRingSize; /* # of data desc */
+   uint32    compRingSize; /* # of comp desc */
+   uint32    ddLen;        /* size of driver data */
+   uint8     intrIdx;
+   uint8     _pad[7];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_TxQueueConf;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_RxQueueConf {
+   uint64    rxRingBasePA[2];
+   uint64    compRingBasePA;
+   uint64    ddPA;            /* driver data */
+   uint64    reserved;
+   uint32    rxRingSize[2];   /* # of rx desc */
+   uint32    compRingSize;    /* # of rx comp desc */
+   uint32    ddLen;           /* size of driver data */
+   uint8     intrIdx;
+   uint8     _pad[7];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_RxQueueConf;
+
+enum vmxnet3_intr_mask_mode {
+   VMXNET3_IMM_AUTO   = 0,
+   VMXNET3_IMM_ACTIVE = 1,
+   VMXNET3_IMM_LAZY   = 2
+};
+
+enum vmxnet3_intr_type {
+   VMXNET3_IT_AUTO = 0,
+   VMXNET3_IT_INTX = 1,
+   VMXNET3_IT_MSI  = 2,
+   VMXNET3_IT_MSIX = 3
+};
+
+#define VMXNET3_MAX_TX_QUEUES  8
+#define VMXNET3_MAX_RX_QUEUES  16
+/* addition 1 for events */
+#define VMXNET3_MAX_INTRS      25
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_IntrConf {
+   Bool   autoMask;
+   uint8  numIntrs;      /* # of interrupts */
+   uint8  eventIntrIdx;
+   uint8  modLevels[VMXNET3_MAX_INTRS]; /* moderation level for each intr */
+   uint32 reserved[3];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_IntrConf;
+
+/* one bit per VLAN ID, the size is in the units of uint32 */
+#define VMXNET3_VFT_SIZE  (4096 / (sizeof(uint32) * 8))
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_QueueStatus {
+   Bool    stopped;
+   uint8   _pad[3];
+   uint32  error;
+}
+#include "vmware_pack_end.h"
+Vmxnet3_QueueStatus;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_TxQueueCtrl {
+   uint32  txNumDeferred;
+   uint32  txThreshold;
+   uint64  reserved;
+}
+#include "vmware_pack_end.h"
+Vmxnet3_TxQueueCtrl;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_RxQueueCtrl {
+   Bool    updateRxProd;
+   uint8   _pad[7];
+   uint64  reserved;
+}
+#include "vmware_pack_end.h"
+Vmxnet3_RxQueueCtrl;
+
+#define VMXNET3_RXM_UCAST     0x01  /* unicast only */
+#define VMXNET3_RXM_MCAST     0x02  /* multicast passing the filters */
+#define VMXNET3_RXM_BCAST     0x04  /* broadcast only */
+#define VMXNET3_RXM_ALL_MULTI 0x08  /* all multicast */
+#define VMXNET3_RXM_PROMISC   0x10  /* promiscuous */
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_RxFilterConf {
+   uint32   rxMode;       /* VMXNET3_RXM_xxx */
+   uint16   mfTableLen;   /* size of the multicast filter table */
+   uint16   _pad1;
+   uint64   mfTablePA;    /* PA of the multicast filters table */
+   uint32   vfTable[VMXNET3_VFT_SIZE]; /* vlan filter */
+}
+#include "vmware_pack_end.h"
+Vmxnet3_RxFilterConf;
+
+#define VMXNET3_PM_MAX_FILTERS        6
+#define VMXNET3_PM_MAX_PATTERN_SIZE   128
+#define VMXNET3_PM_MAX_MASK_SIZE      (VMXNET3_PM_MAX_PATTERN_SIZE / 8)
+
+#define VMXNET3_PM_WAKEUP_MAGIC       0x01  /* wake up on magic pkts */
+#define VMXNET3_PM_WAKEUP_FILTER      0x02  /* wake up on pkts matching filters */
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_PM_PktFilter {
+   uint8 maskSize;
+   uint8 patternSize;
+   uint8 mask[VMXNET3_PM_MAX_MASK_SIZE];
+   uint8 pattern[VMXNET3_PM_MAX_PATTERN_SIZE];
+   uint8 pad[6];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_PM_PktFilter;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_PMConf {
+   uint16               wakeUpEvents;  /* VMXNET3_PM_WAKEUP_xxx */
+   uint8                numFilters;
+   uint8                pad[5];
+   Vmxnet3_PM_PktFilter filters[VMXNET3_PM_MAX_FILTERS];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_PMConf;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_VariableLenConfDesc {
+   uint32              confVer;
+   uint32              confLen;
+   uint64              confPA;
+}
+#include "vmware_pack_end.h"
+Vmxnet3_VariableLenConfDesc;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_DSDevRead {
+   /* read-only region for device, read by dev in response to a SET cmd */
+   Vmxnet3_MiscConf     misc;
+   Vmxnet3_IntrConf     intrConf;
+   Vmxnet3_RxFilterConf rxFilterConf;
+   Vmxnet3_VariableLenConfDesc  rssConfDesc;
+   Vmxnet3_VariableLenConfDesc  pmConfDesc;
+   uint64               reserved[2];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_DSDevRead;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_TxQueueDesc {
+   Vmxnet3_TxQueueCtrl ctrl;
+   Vmxnet3_TxQueueConf conf;
+   /* Driver read after a GET command */
+   Vmxnet3_QueueStatus status;
+   UPT1_TxStats        stats;
+   uint8               _pad[88]; /* 128 aligned */
+}
+#include "vmware_pack_end.h"
+Vmxnet3_TxQueueDesc;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_RxQueueDesc {
+   Vmxnet3_RxQueueCtrl ctrl;
+   Vmxnet3_RxQueueConf conf;
+   /* Driver read after a GET command */
+   Vmxnet3_QueueStatus status;
+   UPT1_RxStats        stats;
+   uint8               _pad[88]; /* 128 aligned */
+}
+#include "vmware_pack_end.h"
+Vmxnet3_RxQueueDesc;
+
+typedef
+#include "vmware_pack_begin.h"
+struct Vmxnet3_DriverShared {
+   uint32               magic;
+   uint32               pad; /* make devRead start at 64-bit boundaries */
+   Vmxnet3_DSDevRead    devRead;
+   uint32               ecr;
+   uint32               reserved[5];
+}
+#include "vmware_pack_end.h"
+Vmxnet3_DriverShared;
+
+#define VMXNET3_ECR_RQERR       (1 << 0)
+#define VMXNET3_ECR_TQERR       (1 << 1)
+#define VMXNET3_ECR_LINK        (1 << 2)
+#define VMXNET3_ECR_DIC         (1 << 3)
+#define VMXNET3_ECR_DEBUG       (1 << 4)
+
+/* flip the gen bit of a ring */
+#define VMXNET3_FLIP_RING_GEN(gen) ((gen) = (gen) ^ 0x1)
+
+/* only use this if moving the idx won't affect the gen bit */
+#define VMXNET3_INC_RING_IDX_ONLY(idx, ring_size) \
+do {\
+   (idx)++;\
+   if (UNLIKELY((idx) == (ring_size))) {\
+      (idx) = 0;\
+   }\
+} while (0)
+
+#define VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid) \
+   vfTable[vid >> 5] |= (1 << (vid & 31))
+#define VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid) \
+   vfTable[vid >> 5] &= ~(1 << (vid & 31))
+
+#define VMXNET3_VFTABLE_ENTRY_IS_SET(vfTable, vid) \
+   ((vfTable[vid >> 5] & (1 << (vid & 31))) != 0)
+
+#define VMXNET3_MAX_MTU     9000
+#define VMXNET3_MIN_MTU     60
+
+#define VMXNET3_LINK_UP         (10000 << 16 | 1)    // 10 Gbps, up
+#define VMXNET3_LINK_DOWN       0
+#endif /* _VMXNET3_DEFS_H_ */
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_main.c b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_main.c
new file mode 100644 (file)
index 0000000..164c72e
--- /dev/null
@@ -0,0 +1,1501 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#include "vmxnet3_solaris.h"
+
+/*
+ * TODO:
+ *    - Tx data ring
+ *    - MAC_CAPAB_POLL support
+ *    - JF support
+ *    - Dynamic RX pool
+ */
+
+/*
+ * Forward declarations
+ */
+static int       vmxnet3_getstat(void *, uint_t, uint64_t *);
+static int       vmxnet3_start(void *);
+static void      vmxnet3_stop(void *);
+static int       vmxnet3_setpromisc(void *, boolean_t);
+static int       vmxnet3_multicst(void *, boolean_t, const uint8_t *);
+static int       vmxnet3_unicst(void *, const uint8_t *);
+static boolean_t vmxnet3_getcapab(void *, mac_capab_t, void *);
+
+/* MAC callbacks */
+static mac_callbacks_t vmxnet3_mac_callbacks = {
+   MC_GETCAPAB,        /* mc_callbacks */
+   vmxnet3_getstat,    /* mc_getstat */
+   vmxnet3_start,      /* mc_start */
+   vmxnet3_stop,       /* mc_stop */
+   vmxnet3_setpromisc, /* mc_setpromisc */
+   vmxnet3_multicst,   /* mc_multicst */
+   vmxnet3_unicst,     /* mc_unicst */
+   vmxnet3_tx,         /* mc_tx */
+   NULL,               /* mc_resources */
+   NULL,               /* mc_ioctl */
+   vmxnet3_getcapab    /* mc_getcapab */
+};
+
+/* Tx DMA engine description */
+static ddi_dma_attr_t vmxnet3_dma_attrs_tx = {
+   DMA_ATTR_V0,           /* dma_attr_version */
+   0x0000000000000000ull, /* dma_attr_addr_lo */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_count_max */
+   0x0000000000000001ull, /* dma_attr_align */
+   0x0000000000000001ull, /* dma_attr_burstsizes */
+   0x00000001,            /* dma_attr_minxfer */
+   0x000000000000FFFFull, /* dma_attr_maxxfer */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
+   -1,                    /* dma_attr_sgllen */
+   0x00000001,            /* dma_attr_granular */
+   0                      /* dma_attr_flags */
+};
+
+/* --- */
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_getstat --
+ *
+ *    Fetch the statistics of a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_getstat(void *data, uint_t stat, uint64_t *val)
+{
+   vmxnet3_softc_t *dp = data;
+   UPT1_TxStats *txStats;
+   UPT1_RxStats *rxStats;
+
+   VMXNET3_DEBUG(dp, 2, "getstat(%u)\n", stat);
+
+   if (!dp->devEnabled) {
+      return DDI_FAILURE;
+   }
+
+   txStats = &VMXNET3_TQDESC(dp)->stats;
+   rxStats = &VMXNET3_RQDESC(dp)->stats;
+
+   /*
+    * First touch the related register
+    */
+   switch (stat) {
+      case MAC_STAT_MULTIRCV:
+      case MAC_STAT_BRDCSTRCV:
+      case MAC_STAT_MULTIXMT:
+      case MAC_STAT_BRDCSTXMT:
+      case MAC_STAT_NORCVBUF:
+      case MAC_STAT_IERRORS:
+      case MAC_STAT_NOXMTBUF:
+      case MAC_STAT_OERRORS:
+      case MAC_STAT_RBYTES:
+      case MAC_STAT_IPACKETS:
+      case MAC_STAT_OBYTES:
+      case MAC_STAT_OPACKETS:
+         VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
+         break;
+      case MAC_STAT_IFSPEED:
+      case MAC_STAT_COLLISIONS:
+      case ETHER_STAT_LINK_DUPLEX:
+         /* nothing */
+         break;
+      default:
+         return DDI_FAILURE;
+   }
+
+   /*
+    * Then fetch the corresponding stat
+    */
+   switch (stat) {
+      case MAC_STAT_IFSPEED:
+         *val = dp->linkSpeed;
+         break;
+      case MAC_STAT_MULTIRCV:
+         *val = rxStats->mcastPktsRxOK;
+         break;
+      case MAC_STAT_BRDCSTRCV:
+         *val = rxStats->bcastPktsRxOK;
+         break;
+      case MAC_STAT_MULTIXMT:
+         *val = txStats->mcastPktsTxOK;
+         break;
+      case MAC_STAT_BRDCSTXMT:
+         *val = txStats->bcastPktsTxOK;
+         break;
+      case MAC_STAT_NORCVBUF:
+         *val = rxStats->pktsRxOutOfBuf;
+         break;
+      case MAC_STAT_IERRORS:
+         *val = rxStats->pktsRxError;
+         break;
+      case MAC_STAT_NOXMTBUF:
+         *val = txStats->pktsTxDiscard;
+         break;
+      case MAC_STAT_OERRORS:
+         *val = txStats->pktsTxError;
+         break;
+      case MAC_STAT_COLLISIONS:
+         *val = 0;
+         break;
+      case MAC_STAT_RBYTES:
+         *val = rxStats->LROBytesRxOK +
+                rxStats->ucastBytesRxOK +
+                rxStats->mcastBytesRxOK +
+                rxStats->bcastBytesRxOK;
+         break;
+      case MAC_STAT_IPACKETS:
+         *val = rxStats->LROPktsRxOK +
+                rxStats->ucastPktsRxOK +
+                rxStats->mcastPktsRxOK +
+                rxStats->bcastPktsRxOK;
+         break;
+      case MAC_STAT_OBYTES:
+         *val = txStats->TSOBytesTxOK +
+                txStats->ucastBytesTxOK +
+                txStats->mcastBytesTxOK +
+                txStats->bcastBytesTxOK;
+         break;
+      case MAC_STAT_OPACKETS:
+         *val = txStats->TSOPktsTxOK +
+                txStats->ucastPktsTxOK +
+                txStats->mcastPktsTxOK +
+                txStats->bcastPktsTxOK;
+         break;
+      case ETHER_STAT_LINK_DUPLEX:
+         *val = LINK_DUPLEX_FULL;
+         break;
+      default:
+         ASSERT(B_FALSE);
+   }
+
+   return DDI_SUCCESS;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_prepare_drivershared --
+ *
+ *    Allocate and initialize the shared data structures
+ *    of a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_prepare_drivershared(vmxnet3_softc_t *dp)
+{
+   Vmxnet3_DriverShared *ds;
+   size_t allocSize = sizeof(Vmxnet3_DriverShared);
+
+   if (vmxnet3_alloc_dma_mem_1(dp, &dp->sharedData, allocSize,
+                               B_TRUE) != DDI_SUCCESS) {
+      return DDI_FAILURE;
+   }
+   ds = VMXNET3_DS(dp);
+   memset(ds, 0, allocSize);
+
+   allocSize = sizeof(Vmxnet3_TxQueueDesc) + sizeof(Vmxnet3_RxQueueDesc);
+   if (vmxnet3_alloc_dma_mem_128(dp, &dp->queueDescs, allocSize,
+                                 B_TRUE) != DDI_SUCCESS) {
+      vmxnet3_free_dma_mem(&dp->sharedData);
+      return DDI_FAILURE;
+   }
+   memset(dp->queueDescs.buf, 0, allocSize);
+
+   ds->magic = VMXNET3_REV1_MAGIC;
+
+   /* Take care of most of devRead */
+   ds->devRead.misc.driverInfo.version = BUILD_NUMBER_NUMERIC;
+   if (sizeof(void *) == 4) {
+      ds->devRead.misc.driverInfo.gos.gosBits = VMXNET3_GOS_BITS_32;
+   } else if (sizeof(void *) == 8) {
+      ds->devRead.misc.driverInfo.gos.gosBits = VMXNET3_GOS_BITS_64;
+   } else {
+      ASSERT(B_FALSE);
+   }
+   ds->devRead.misc.driverInfo.gos.gosType = VMXNET3_GOS_TYPE_SOLARIS;
+   ds->devRead.misc.driverInfo.gos.gosVer = 10;
+   ds->devRead.misc.driverInfo.vmxnet3RevSpt = 1;
+   ds->devRead.misc.driverInfo.uptVerSpt = 1;
+
+   ds->devRead.misc.uptFeatures = UPT1_F_RXCSUM;
+   ds->devRead.misc.mtu = ETHERMTU;
+   // XXX: ds->devRead.misc.maxNumRxSG
+   ds->devRead.misc.numTxQueues = 1;
+   ds->devRead.misc.numRxQueues = 1;
+   ds->devRead.misc.queueDescPA = dp->queueDescs.bufPA;
+   ds->devRead.misc.queueDescLen = allocSize;
+
+   /* TxQueue and RxQueue information is filled in other functions */
+
+   ds->devRead.intrConf.autoMask = (dp->intrMaskMode == VMXNET3_IMM_AUTO);
+   ds->devRead.intrConf.numIntrs = 1;
+   // XXX: ds->intr.modLevels
+   ds->devRead.intrConf.eventIntrIdx = 0;
+
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_DSAL, VMXNET3_ADDR_LO(dp->sharedData.bufPA));
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_DSAH, VMXNET3_ADDR_HI(dp->sharedData.bufPA));
+
+   return DDI_SUCCESS;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_destroy_drivershared --
+ *
+ *    Destroy the shared data structures of a vmxnet3 device.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_destroy_drivershared(vmxnet3_softc_t *dp)
+{
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_DSAL, 0);
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_DSAH, 0);
+
+   vmxnet3_free_dma_mem(&dp->queueDescs);
+   vmxnet3_free_dma_mem(&dp->sharedData);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_alloc_cmdring --
+ *
+ *    Allocate and initialize the command ring of a queue.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_alloc_cmdring(vmxnet3_softc_t *dp, vmxnet3_cmdring_t *cmdRing)
+{
+   size_t ringSize = cmdRing->size * sizeof(Vmxnet3_TxDesc);
+
+   if (vmxnet3_alloc_dma_mem_512(dp, &cmdRing->dma, ringSize,
+                                 B_TRUE) != DDI_SUCCESS) {
+      return DDI_FAILURE;
+   }
+   memset(cmdRing->dma.buf, 0, ringSize);
+   cmdRing->avail = cmdRing->size;
+   cmdRing->next2fill = 0;
+   cmdRing->gen = VMXNET3_INIT_GEN;
+
+   return DDI_SUCCESS;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_alloc_compring --
+ *
+ *    Allocate and initialize the completion ring of a queue.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_alloc_compring(vmxnet3_softc_t *dp, vmxnet3_compring_t *compRing)
+{
+   size_t ringSize = compRing->size * sizeof(Vmxnet3_TxCompDesc);
+
+   if (vmxnet3_alloc_dma_mem_512(dp, &compRing->dma, ringSize,
+                                 B_TRUE) != DDI_SUCCESS) {
+      return DDI_FAILURE;
+   }
+   memset(compRing->dma.buf, 0, ringSize);
+   compRing->next2comp = 0;
+   compRing->gen = VMXNET3_INIT_GEN;
+
+   return DDI_SUCCESS;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_prepare_txqueue --
+ *
+ *    Initialize the tx queue of a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_prepare_txqueue(vmxnet3_softc_t *dp)
+{
+   Vmxnet3_TxQueueDesc *tqdesc = VMXNET3_TQDESC(dp);
+   vmxnet3_txqueue_t *txq = &dp->txQueue;
+
+   ASSERT(!(txq->cmdRing.size & VMXNET3_RING_SIZE_MASK));
+   ASSERT(!(txq->compRing.size & VMXNET3_RING_SIZE_MASK));
+   ASSERT(!txq->cmdRing.dma.buf && !txq->compRing.dma.buf);
+
+   if (vmxnet3_alloc_cmdring(dp, &txq->cmdRing) != DDI_SUCCESS) {
+      goto error;
+   }
+   tqdesc->conf.txRingBasePA = txq->cmdRing.dma.bufPA;
+   tqdesc->conf.txRingSize = txq->cmdRing.size;
+   tqdesc->conf.dataRingBasePA = 0;
+   tqdesc->conf.dataRingSize = 0;
+
+   if (vmxnet3_alloc_compring(dp, &txq->compRing) != DDI_SUCCESS) {
+      goto error_cmdring;
+   }
+   tqdesc->conf.compRingBasePA = txq->compRing.dma.bufPA;
+   tqdesc->conf.compRingSize = txq->compRing.size;
+
+   txq->metaRing = kmem_zalloc(txq->cmdRing.size*sizeof(vmxnet3_metatx_t),
+                               KM_SLEEP);
+   ASSERT(txq->metaRing);
+
+   if (vmxnet3_txqueue_init(dp, txq) != DDI_SUCCESS) {
+      goto error_mpring;
+   }
+
+   return DDI_SUCCESS;
+
+error_mpring:
+   kmem_free(txq->metaRing, txq->cmdRing.size*sizeof(vmxnet3_metatx_t));
+   vmxnet3_free_dma_mem(&txq->compRing.dma);
+error_cmdring:
+   vmxnet3_free_dma_mem(&txq->cmdRing.dma);
+error:
+   return DDI_FAILURE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_prepare_rxqueue --
+ *
+ *    Initialize the rx queue of a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_prepare_rxqueue(vmxnet3_softc_t *dp)
+{
+   Vmxnet3_RxQueueDesc *rqdesc = VMXNET3_RQDESC(dp);
+   vmxnet3_rxqueue_t *rxq = &dp->rxQueue;
+
+   ASSERT(!(rxq->cmdRing.size & VMXNET3_RING_SIZE_MASK));
+   ASSERT(!(rxq->compRing.size & VMXNET3_RING_SIZE_MASK));
+   ASSERT(!rxq->cmdRing.dma.buf && !rxq->compRing.dma.buf);
+
+   if (vmxnet3_alloc_cmdring(dp, &rxq->cmdRing) != DDI_SUCCESS) {
+      goto error;
+   }
+   rqdesc->conf.rxRingBasePA[0] = rxq->cmdRing.dma.bufPA;
+   rqdesc->conf.rxRingSize[0] = rxq->cmdRing.size;
+   rqdesc->conf.rxRingBasePA[1] = 0;
+   rqdesc->conf.rxRingSize[1] = 0;
+
+   if (vmxnet3_alloc_compring(dp, &rxq->compRing) != DDI_SUCCESS) {
+      goto error_cmdring;
+   }
+   rqdesc->conf.compRingBasePA = rxq->compRing.dma.bufPA;
+   rqdesc->conf.compRingSize = rxq->compRing.size;
+
+   rxq->bufRing = kmem_zalloc(rxq->cmdRing.size*sizeof(vmxnet3_bufdesc_t),
+                              KM_SLEEP);
+   ASSERT(rxq->bufRing);
+
+   if (vmxnet3_rxqueue_init(dp, rxq) != DDI_SUCCESS) {
+      goto error_bufring;
+   }
+
+   return DDI_SUCCESS;
+
+error_bufring:
+   kmem_free(rxq->bufRing, rxq->cmdRing.size*sizeof(vmxnet3_bufdesc_t));
+   vmxnet3_free_dma_mem(&rxq->compRing.dma);
+error_cmdring:
+   vmxnet3_free_dma_mem(&rxq->cmdRing.dma);
+error:
+   return DDI_FAILURE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_destroy_txqueue --
+ *
+ *    Destroy the tx queue of a vmxnet3 device.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_destroy_txqueue(vmxnet3_softc_t *dp)
+{
+   vmxnet3_txqueue_t *txq = &dp->txQueue;
+
+   ASSERT(txq->metaRing);
+   ASSERT(txq->cmdRing.dma.buf && txq->compRing.dma.buf);
+
+   vmxnet3_txqueue_fini(dp, txq);
+
+   kmem_free(txq->metaRing, txq->cmdRing.size*sizeof(vmxnet3_metatx_t));
+
+   vmxnet3_free_dma_mem(&txq->cmdRing.dma);
+   vmxnet3_free_dma_mem(&txq->compRing.dma);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_destroy_rxqueue --
+ *
+ *    Destroy the rx queue of a vmxnet3 device.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_destroy_rxqueue(vmxnet3_softc_t *dp)
+{
+   vmxnet3_rxqueue_t *rxq = &dp->rxQueue;
+
+   ASSERT(rxq->bufRing);
+   ASSERT(rxq->cmdRing.dma.buf && rxq->compRing.dma.buf);
+
+   vmxnet3_rxqueue_fini(dp, rxq);
+
+   kmem_free(rxq->bufRing, rxq->cmdRing.size*sizeof(vmxnet3_bufdesc_t));
+
+   vmxnet3_free_dma_mem(&rxq->cmdRing.dma);
+   vmxnet3_free_dma_mem(&rxq->compRing.dma);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_refresh_rxfilter --
+ *
+ *    Apply new RX filters settings to a vmxnet3 device.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_refresh_rxfilter(vmxnet3_softc_t *dp)
+{
+   Vmxnet3_DriverShared *ds = VMXNET3_DS(dp);
+
+   ds->devRead.rxFilterConf.rxMode = dp->rxMode;
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_RX_MODE);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_refresh_linkstate --
+ *
+ *    Fetch the link state of a vmxnet3 device.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_refresh_linkstate(vmxnet3_softc_t *dp)
+{
+   uint32_t ret32;
+
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
+   ret32 = VMXNET3_BAR1_GET32(dp, VMXNET3_REG_CMD);
+   if (ret32 & 1) {
+      dp->linkState = LINK_STATE_UP;
+      dp->linkSpeed = (ret32 >> 16) * 1000000ULL;
+   } else {
+      dp->linkState = LINK_STATE_DOWN;
+      dp->linkSpeed = 0;
+   }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_start --
+ *
+ *    Start a vmxnet3 device: allocate and initialize the shared data
+ *    structures and send a start command to the device.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_start(void *data)
+{
+   vmxnet3_softc_t *dp = data;
+   Vmxnet3_TxQueueDesc *tqdesc;
+   Vmxnet3_RxQueueDesc *rqdesc;
+   int txQueueSize, rxQueueSize;
+   uint32_t ret32;
+
+   VMXNET3_DEBUG(dp, 1, "start()\n");
+
+   /*
+    * Allocate vmxnet3's shared data and advertise its PA
+    */
+   if (vmxnet3_prepare_drivershared(dp) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "vmxnet3_prepare_drivershared() failed\n");
+      goto error;
+   }
+   tqdesc = VMXNET3_TQDESC(dp);
+   rqdesc = VMXNET3_RQDESC(dp);
+
+   /*
+    * Create and initialize the tx queue
+    */
+   txQueueSize = vmxnet3_getprop(dp, "TxRingSize", 32, 4096,
+                                 VMXNET3_DEF_TX_RING_SIZE);
+   if (!(txQueueSize & VMXNET3_RING_SIZE_MASK)) {
+      dp->txQueue.cmdRing.size = txQueueSize;
+      dp->txQueue.compRing.size = txQueueSize;
+      dp->txQueue.sharedCtrl = &tqdesc->ctrl;
+      if (vmxnet3_prepare_txqueue(dp) != DDI_SUCCESS) {
+         VMXNET3_WARN(dp, "vmxnet3_prepare_txqueue() failed\n");
+         goto error_shared_data;
+      }
+   } else {
+      VMXNET3_WARN(dp, "invalid tx ring size (%d)\n", txQueueSize);
+      goto error_shared_data;
+   }
+
+   /*
+    * Create and initialize the rx queue
+    */
+   rxQueueSize = vmxnet3_getprop(dp, "RxRingSize", 32, 4096,
+                                 VMXNET3_DEF_RX_RING_SIZE);
+   if (!(txQueueSize & VMXNET3_RING_SIZE_MASK)) {
+      dp->rxQueue.cmdRing.size = rxQueueSize;
+      dp->rxQueue.compRing.size = rxQueueSize;
+      dp->rxQueue.sharedCtrl = &rqdesc->ctrl;
+      if (vmxnet3_prepare_rxqueue(dp) != DDI_SUCCESS) {
+         VMXNET3_WARN(dp, "vmxnet3_prepare_rxqueue() failed\n");
+         goto error_tx_queue;
+      }
+   } else {
+      VMXNET3_WARN(dp, "invalid rx ring size (%d)\n", rxQueueSize);
+      goto error_tx_queue;
+   }
+
+   /*
+    * Allocate the Tx DMA handle
+    */
+   if (ddi_dma_alloc_handle(dp->dip, &vmxnet3_dma_attrs_tx, DDI_DMA_SLEEP,
+                            NULL, &dp->txDmaHandle) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_dma_alloc_handle() failed\n");
+      goto error_rx_queue;
+   }
+
+   /*
+    * Activate the device
+    */
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_ACTIVATE_DEV);
+   ret32 = VMXNET3_BAR1_GET32(dp, VMXNET3_REG_CMD);
+   if (ret32) {
+      VMXNET3_WARN(dp, "ACTIVATE_DEV failed: 0x%x\n", ret32);
+      goto error_txhandle;
+   }
+   dp->devEnabled = B_TRUE;
+
+   VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_RXPROD, dp->txQueue.cmdRing.size - 1);
+
+   /*
+    * Update the RX filters, must be done after ACTIVATE_DEV
+    */
+   dp->rxMode = VMXNET3_RXM_UCAST | VMXNET3_RXM_BCAST;
+   vmxnet3_refresh_rxfilter(dp);
+
+   /*
+    * Get the link state now because no events will be generated
+    */
+   vmxnet3_refresh_linkstate(dp);
+   mac_link_update(dp->mac, dp->linkState);
+
+   /*
+    * Finally, unmask the interrupt
+    */
+   VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_IMR, 0);
+
+   return DDI_SUCCESS;
+
+error_txhandle:
+   ddi_dma_free_handle(&dp->txDmaHandle);
+error_rx_queue:
+   vmxnet3_destroy_rxqueue(dp);
+error_tx_queue:
+   vmxnet3_destroy_txqueue(dp);
+error_shared_data:
+   vmxnet3_destroy_drivershared(dp);
+error:
+   return DDI_FAILURE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_stop --
+ *
+ *    Stop a vmxnet3 device: send a stop command to the device and
+ *    de-allocate the shared data structures.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_stop(void *data)
+{
+   vmxnet3_softc_t *dp = data;
+
+   VMXNET3_DEBUG(dp, 1, "stop()\n");
+
+   /*
+    * Take the 2 locks related to asynchronous events.
+    * These events should always check dp->devEnabled before poking dp.
+    */
+   mutex_enter(&dp->intrLock);
+   mutex_enter(&dp->rxPoolLock);
+   VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_IMR, 1);
+   dp->devEnabled = B_FALSE;
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV);
+   mutex_exit(&dp->rxPoolLock);
+   mutex_exit(&dp->intrLock);
+
+   ddi_dma_free_handle(&dp->txDmaHandle);
+
+   vmxnet3_destroy_rxqueue(dp);
+   vmxnet3_destroy_txqueue(dp);
+
+   vmxnet3_destroy_drivershared(dp);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_setpromisc --
+ *
+ *    Set or unset promiscuous mode on a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_SUCCESS.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_setpromisc(void *data, boolean_t promisc)
+{
+   vmxnet3_softc_t *dp = data;
+
+   VMXNET3_DEBUG(dp, 2, "setpromisc(%s)\n", promisc ? "TRUE" : "FALSE");
+
+   if (promisc) {
+      dp->rxMode |= VMXNET3_RXM_PROMISC;
+   } else {
+      dp->rxMode &= ~VMXNET3_RXM_PROMISC;
+   }
+
+   vmxnet3_refresh_rxfilter(dp);
+
+   return DDI_SUCCESS;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_multicst --
+ *
+ *    Add or remove a multicast address from/to a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_multicst(void *data, boolean_t add, const uint8_t *macaddr)
+{
+   vmxnet3_softc_t *dp = data;
+   vmxnet3_dmabuf_t newMfTable;
+   int ret = DDI_SUCCESS;
+   uint16_t macIdx;
+
+   VMXNET3_DEBUG(dp, 2, "multicst(%s, "MACADDR_FMT")\n",
+                 add ? "add" : "remove",
+                 MACADDR_FMT_ARGS(macaddr));
+
+   /*
+    * First lookup the position of the given MAC to check if it is
+    * present in the existing MF table.
+    */
+   for (macIdx = 0; macIdx < dp->mfTable.bufLen; macIdx += 6) {
+      if (memcmp(&dp->mfTable.buf[macIdx], macaddr, 6) == 0) {
+         break;
+      }
+   }
+
+   /*
+    * Check for 2 situations we can handle gracefully by bailing out:
+    * Adding an already existing filter or removing a non-existing one.
+    */
+   if (add && macIdx < dp->mfTable.bufLen) {
+      VMXNET3_WARN(dp, MACADDR_FMT " already in MC filter list @ %u\n",
+                   MACADDR_FMT_ARGS(macaddr), macIdx / 6);
+      ASSERT(B_FALSE);
+      goto done;
+   }
+   if (!add && macIdx == dp->mfTable.bufLen) {
+      VMXNET3_WARN(dp, MACADDR_FMT " not in MC filter list @ %u\n",
+                   MACADDR_FMT_ARGS(macaddr), macIdx / 6);
+      ASSERT(B_FALSE);
+      goto done;
+   }
+
+   /*
+    * Create the new MF table
+    */
+   {
+      size_t allocSize = dp->mfTable.bufLen + (add ? 6 : -6);
+      if (allocSize) {
+         ret = vmxnet3_alloc_dma_mem_1(dp, &newMfTable, allocSize, B_TRUE);
+         ASSERT(ret == DDI_SUCCESS);
+         if (add) {
+            memcpy(newMfTable.buf, dp->mfTable.buf, dp->mfTable.bufLen);
+            memcpy(newMfTable.buf + dp->mfTable.bufLen, macaddr, 6);
+         } else {
+            memcpy(newMfTable.buf, dp->mfTable.buf, macIdx);
+            memcpy(newMfTable.buf + macIdx,
+                   dp->mfTable.buf + macIdx + 6,
+                   dp->mfTable.bufLen - macIdx - 6);
+         }
+      } else {
+         newMfTable.buf = NULL;
+         newMfTable.bufPA = 0;
+         newMfTable.bufLen = 0;
+      }
+   }
+
+   /*
+    * Now handle 2 corner cases: if we're creating the first filter or
+    * removing the last one, we have to update rxMode accordingly.
+    */
+   if (add && newMfTable.bufLen == 6) {
+      ASSERT(!(dp->rxMode & VMXNET3_RXM_MCAST));
+      dp->rxMode |= VMXNET3_RXM_MCAST;
+      vmxnet3_refresh_rxfilter(dp);
+   }
+   if (!add && dp->mfTable.bufLen == 6) {
+      ASSERT(newMfTable.buf == NULL);
+      ASSERT(dp->rxMode & VMXNET3_RXM_MCAST);
+      dp->rxMode &= ~VMXNET3_RXM_MCAST;
+      vmxnet3_refresh_rxfilter(dp);
+   }
+
+   /*
+    * Now replace the old MF table with the new one
+    */
+   if (dp->mfTable.buf) {
+      vmxnet3_free_dma_mem(&dp->mfTable);
+   }
+   dp->mfTable = newMfTable;
+   VMXNET3_DS(dp)->devRead.rxFilterConf.mfTablePA = newMfTable.bufPA;
+   VMXNET3_DS(dp)->devRead.rxFilterConf.mfTableLen = newMfTable.bufLen;
+
+done:
+   /* Always update the filters */
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_MAC_FILTERS);
+
+   return ret;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_unicst --
+ *
+ *    Set the mac address of a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_unicst(void *data, const uint8_t *macaddr)
+{
+   vmxnet3_softc_t *dp = data;
+   uint32_t val32;
+
+   VMXNET3_DEBUG(dp, 2, "unicst("MACADDR_FMT")\n",
+                 MACADDR_FMT_ARGS(macaddr));
+
+   val32 = *((uint32_t *) (macaddr + 0));
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_MACL, val32);
+   val32 = *((uint16_t *) (macaddr + 4));
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_MACH, val32);
+
+   memcpy(dp->macaddr, macaddr, 6);
+
+   return DDI_SUCCESS;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_getcapab --
+ *
+ *    Get the capabilities of a vmxnet3 device.
+ *
+ * Results:
+ *    B_TRUE or B_FALSE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static boolean_t
+vmxnet3_getcapab(void *data, mac_capab_t capab, void *arg)
+{
+   vmxnet3_softc_t *dp = data;
+   boolean_t ret;
+
+   switch (capab) {
+      case MAC_CAPAB_HCKSUM: {
+         uint32_t *txflags = arg;
+         *txflags = HCKSUM_INET_PARTIAL;
+         ret = B_TRUE;
+         break;
+      }
+      case MAC_CAPAB_LSO: {
+         mac_capab_lso_t *lso = arg;
+         lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
+         lso->lso_basic_tcp_ipv4.lso_max = IP_MAXPACKET;
+         ret = vmxnet3_getprop(dp, "EnableLSO", 0, 1, 1);
+         break;
+      }
+      default:
+         ret = B_FALSE;
+   }
+
+   VMXNET3_DEBUG(dp, 2, "getcapab(0x%x) -> %s\n", capab, ret ? "yes" : "no");
+
+   return ret;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_reset --
+ *
+ *    Reset a vmxnet3 device. Only to be used when the device is wedged.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    The device is reset.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_reset(void *data)
+{
+   vmxnet3_softc_t *dp = data;
+
+   VMXNET3_DEBUG(dp, 1, "vmxnet3_reset()\n");
+
+   vmxnet3_stop(dp);
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
+   vmxnet3_start(dp);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_intr_events --
+ *
+ *    Process pending events on a vmxnet3 device.
+ *
+ * Results:
+ *    B_TRUE if the link state changed, B_FALSE otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static boolean_t
+vmxnet3_intr_events(vmxnet3_softc_t *dp)
+{
+   Vmxnet3_DriverShared *ds = VMXNET3_DS(dp);
+   boolean_t linkStateChanged = B_FALSE;
+   uint32_t events = ds->ecr;
+
+   if (events) {
+      VMXNET3_DEBUG(dp, 2, "events(0x%x)\n", events);
+      if (events & (VMXNET3_ECR_RQERR | VMXNET3_ECR_TQERR)) {
+         Vmxnet3_TxQueueDesc *tqdesc = VMXNET3_TQDESC(dp);
+         Vmxnet3_RxQueueDesc *rqdesc = VMXNET3_RQDESC(dp);
+
+         VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_GET_QUEUE_STATUS);
+         if (tqdesc->status.stopped) {
+            VMXNET3_WARN(dp, "tq error 0x%x\n", tqdesc->status.error);
+         }
+         if (rqdesc->status.stopped) {
+            VMXNET3_WARN(dp, "rq error 0x%x\n", rqdesc->status.error);
+         }
+
+         if (ddi_taskq_dispatch(dp->resetTask, vmxnet3_reset,
+                                dp, DDI_NOSLEEP) == DDI_SUCCESS) {
+            VMXNET3_WARN(dp, "reset scheduled\n");
+         } else {
+            VMXNET3_WARN(dp, "ddi_taskq_dispatch() failed()\n");
+         }
+      }
+      if (events & VMXNET3_ECR_LINK) {
+         vmxnet3_refresh_linkstate(dp);
+         linkStateChanged = B_TRUE;
+      }
+      if (events & VMXNET3_ECR_DIC) {
+         VMXNET3_DEBUG(dp, 1, "device implementation change\n");
+      }
+      VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_ECR, events);
+   }
+
+   return linkStateChanged;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_intr --
+ *
+ *    Interrupt handler of a vmxnet3 device.
+ *
+ * Results:
+ *    DDI_INTR_CLAIMED or DDI_INTR_UNCLAIMED.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static u_int
+vmxnet3_intr(caddr_t data1, caddr_t data2)
+{
+   vmxnet3_softc_t *dp = (void *) data1;
+
+   VMXNET3_DEBUG(dp, 3, "intr()\n");
+
+   mutex_enter(&dp->intrLock);
+
+   if (dp->devEnabled) {
+      boolean_t linkStateChanged;
+      boolean_t mustUpdateTx;
+      mblk_t *mps;
+
+      if (dp->intrType == DDI_INTR_TYPE_FIXED &&
+          !VMXNET3_BAR1_GET32(dp, VMXNET3_REG_ICR)) {
+         goto intr_unclaimed;
+      }
+
+      if (dp->intrMaskMode == VMXNET3_IMM_ACTIVE) {
+         VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_IMR, 1);
+      }
+
+      linkStateChanged = vmxnet3_intr_events(dp);
+      mustUpdateTx = vmxnet3_tx_complete(dp, &dp->txQueue);
+      mps = vmxnet3_rx_intr(dp, &dp->rxQueue);
+
+      mutex_exit(&dp->intrLock);
+      VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_IMR, 0);
+
+      if (linkStateChanged) {
+         mac_link_update(dp->mac, dp->linkState);
+      }
+      if (mustUpdateTx) {
+         mac_tx_update(dp->mac);
+      }
+      if (mps) {
+         mac_rx(dp->mac, NULL, mps);
+      }
+
+      return DDI_INTR_CLAIMED;
+   }
+
+intr_unclaimed:
+   mutex_exit(&dp->intrLock);
+   return DDI_INTR_UNCLAIMED;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_attach --
+ *
+ *    Probe and attach a vmxnet3 instance to the stack.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+   vmxnet3_softc_t *dp;
+   mac_register_t *macr;
+   uint16_t vendorId, devId, ret16;
+   uint32_t ret32;
+   int ret;
+   uint_t uret;
+
+   if (cmd != DDI_ATTACH) {
+      goto error;
+   }
+
+   /*
+    * Allocate the soft state
+    */
+   dp = kmem_zalloc(sizeof(vmxnet3_softc_t), KM_SLEEP);
+   ASSERT(dp);
+
+   dp->dip = dip;
+   dp->instance = ddi_get_instance(dip);
+
+   VMXNET3_DEBUG(dp, 1, "attach()\n");
+
+   ddi_set_driver_private(dip, dp);
+
+   /*
+    * Get access to the PCI bus configuration space
+    */
+   if (pci_config_setup(dip, &dp->pciHandle) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "pci_config_setup() failed\n");
+      goto error_soft_state;
+   }
+
+   /*
+    * Make sure the chip is a vmxnet3 device
+    */
+   vendorId = pci_config_get16(dp->pciHandle, PCI_CONF_VENID);
+   devId = pci_config_get16(dp->pciHandle, PCI_CONF_DEVID);
+   if (vendorId != PCI_VENDOR_ID_VMWARE ||
+       devId != PCI_DEVICE_ID_VMWARE_VMXNET3) {
+      VMXNET3_WARN(dp, "wrong PCI venid/devid (0x%x, 0x%x)\n",
+                   vendorId, devId);
+      goto error_pci_config;
+   }
+
+   /*
+    * Make sure we can access the registers through the I/O space
+    */
+   ret16 = pci_config_get16(dp->pciHandle, PCI_CONF_COMM);
+   ret16 |= PCI_COMM_IO | PCI_COMM_ME;
+   pci_config_put16(dp->pciHandle, PCI_CONF_COMM, ret16);
+
+   /*
+    * Map the I/O space in memory
+    */
+   if (ddi_regs_map_setup(dip, 1, &dp->bar0, 0, 0, &vmxnet3_dev_attr,
+                          &dp->bar0Handle) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_regs_map_setup() for BAR0 failed\n");
+      goto error_pci_config;
+   }
+
+   if (ddi_regs_map_setup(dip, 2, &dp->bar1, 0, 0, &vmxnet3_dev_attr,
+                          &dp->bar1Handle) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_regs_map_setup() for BAR1 failed\n");
+      goto error_regs_map_0;
+   }
+
+   /*
+    * Check the version number of the virtual device
+    */
+   if (VMXNET3_BAR1_GET32(dp, VMXNET3_REG_VRRS) & 1) {
+      VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_VRRS, 1);
+   } else {
+      VMXNET3_WARN(dp, "incompatible h/w version\n");
+      goto error_regs_map_1;
+   }
+
+   if (VMXNET3_BAR1_GET32(dp, VMXNET3_REG_UVRS) & 1) {
+      VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_UVRS, 1);
+   } else {
+      VMXNET3_WARN(dp, "incompatible upt version\n");
+      goto error_regs_map_1;
+   }
+
+   /*
+    * Read the MAC address from the device
+    */
+   ret32 = VMXNET3_BAR1_GET32(dp, VMXNET3_REG_MACL);
+   *((uint32_t *) (dp->macaddr + 0)) = ret32;
+   ret32 = VMXNET3_BAR1_GET32(dp, VMXNET3_REG_MACH);
+   *((uint16_t *) (dp->macaddr + 4)) = ret32;
+
+   /*
+    * Register with the MAC framework
+    */
+   macr = mac_alloc(MAC_VERSION);
+   if (!macr) {
+      VMXNET3_WARN(dp, "mac_alloc() failed\n");
+      goto error_regs_map_1;
+   }
+
+   macr->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
+   macr->m_driver = dp;
+   macr->m_dip = dip;
+   macr->m_instance = 0;
+   macr->m_src_addr = dp->macaddr;
+   macr->m_dst_addr = NULL;
+   macr->m_callbacks = &vmxnet3_mac_callbacks;
+   macr->m_min_sdu = 0;
+   macr->m_max_sdu = ETHERMTU;
+   macr->m_pdata = NULL;
+   macr->m_pdata_size = 0;
+
+   ret = mac_register(macr, &dp->mac);
+   mac_free(macr);
+   if (ret != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "mac_register() failed\n");
+      goto error_regs_map_1;
+   }
+
+   /*
+    * Register the interrupt(s) in this order of preference:
+    * MSI-X, MSI, INTx
+    */
+   VMXNET3_BAR1_PUT32(dp, VMXNET3_REG_CMD, VMXNET3_CMD_GET_CONF_INTR);
+   ret32 = VMXNET3_BAR1_GET32(dp, VMXNET3_REG_CMD);
+   switch (ret32 & 0x3) {
+      case VMXNET3_IT_AUTO:
+      case VMXNET3_IT_MSIX:
+         dp->intrType = DDI_INTR_TYPE_MSIX;
+         if (ddi_intr_alloc(dip, &dp->intrHandle, dp->intrType, 0, 1,
+                            &ret, DDI_INTR_ALLOC_STRICT) == DDI_SUCCESS) {
+            break;
+         }
+         VMXNET3_DEBUG(dp, 2, "DDI_INTR_TYPE_MSIX failed\n");
+      case VMXNET3_IT_MSI:
+         dp->intrType = DDI_INTR_TYPE_MSI;
+         if (ddi_intr_alloc(dip, &dp->intrHandle, dp->intrType, 0, 1,
+                            &ret, DDI_INTR_ALLOC_STRICT) == DDI_SUCCESS) {
+            break;
+         }
+         VMXNET3_DEBUG(dp, 2, "DDI_INTR_TYPE_MSI failed\n");
+      case VMXNET3_IT_INTX:
+         dp->intrType = DDI_INTR_TYPE_FIXED;
+         if (ddi_intr_alloc(dip, &dp->intrHandle, dp->intrType, 0, 1,
+                            &ret, DDI_INTR_ALLOC_STRICT) == DDI_SUCCESS) {
+            break;
+         }
+         VMXNET3_DEBUG(dp, 2, "DDI_INTR_TYPE_INTX failed\n");
+      default:
+         VMXNET3_WARN(dp, "ddi_intr_alloc() failed\n");
+         goto error_mac;
+   }
+   dp->intrMaskMode = (ret32 >> 2) & 0x3;
+   if (dp->intrMaskMode == VMXNET3_IMM_LAZY) {
+      VMXNET3_WARN(dp, "Lazy masking is not supported\n");
+      goto error_intr;
+   }
+
+   if (ddi_intr_get_pri(dp->intrHandle, &uret) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_intr_get_pri() failed\n");
+      goto error_intr;
+   }
+
+   VMXNET3_DEBUG(dp, 2, "intrType=0x%x, intrMaskMode=0x%x, intrPrio=%u\n",
+           dp->intrType, dp->intrMaskMode, uret);
+
+   /*
+    * Create a task queue to reset the device if it wedges.
+    */
+   dp->resetTask = ddi_taskq_create(dip, "vmxnet3_reset_task", 1,
+                                    TASKQ_DEFAULTPRI, 0);
+   if (!dp->resetTask) {
+      VMXNET3_WARN(dp, "ddi_taskq_create() failed()\n");
+      goto error_intr;
+   }
+
+   /*
+    * Initialize our mutexes now that we know the interrupt priority
+    * This _must_ be done before ddi_intr_enable()
+    */
+   mutex_init(&dp->intrLock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(uret));
+   mutex_init(&dp->txLock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(uret));
+   mutex_init(&dp->rxPoolLock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(uret));
+
+   if (ddi_intr_add_handler(dp->intrHandle, vmxnet3_intr,
+                            dp, NULL) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_intr_add_handler() failed\n");
+      goto error_mutexes;
+   }
+
+   if (ddi_intr_enable(dp->intrHandle) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_intr_enable() failed\n");
+      goto error_intr_handler;
+   }
+
+   return DDI_SUCCESS;
+
+error_intr_handler:
+   ddi_intr_remove_handler(dp->intrHandle);
+error_mutexes:
+   mutex_destroy(&dp->rxPoolLock);
+   mutex_destroy(&dp->txLock);
+   mutex_destroy(&dp->intrLock);
+   ddi_taskq_destroy(dp->resetTask);
+error_intr:
+   ddi_intr_free(dp->intrHandle);
+error_mac:
+   mac_unregister(dp->mac);
+error_regs_map_1:
+   ddi_regs_map_free(&dp->bar1Handle);
+error_regs_map_0:
+   ddi_regs_map_free(&dp->bar0Handle);
+error_pci_config:
+   pci_config_teardown(&dp->pciHandle);
+error_soft_state:
+   kmem_free(dp, sizeof(vmxnet3_softc_t));
+error:
+   return DDI_FAILURE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_detach --
+ *
+ *    Detach a vmxnet3 instance from the stack.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+   vmxnet3_softc_t *dp = ddi_get_driver_private(dip);
+   unsigned int retries = 0;
+
+   VMXNET3_DEBUG(dp, 1, "detach()\n");
+
+   if (cmd != DDI_DETACH) {
+      return DDI_FAILURE;
+   }
+
+   while (dp->rxNumBufs) {
+      if (retries++ < 10) {
+         VMXNET3_WARN(dp, "rx pending (%u), waiting 1 second...\n",
+                      dp->rxNumBufs);
+         delay(drv_usectohz(1000000));
+      } else {
+         VMXNET3_WARN(dp, "giving up...\n");
+         return DDI_FAILURE;
+      }
+   }
+
+   ddi_intr_disable(dp->intrHandle);
+   ddi_intr_remove_handler(dp->intrHandle);
+   ddi_intr_free(dp->intrHandle);
+
+   mac_unregister(dp->mac);
+
+   if (dp->mfTable.buf) {
+      vmxnet3_free_dma_mem(&dp->mfTable);
+   }
+
+   mutex_destroy(&dp->rxPoolLock);
+   mutex_destroy(&dp->txLock);
+   mutex_destroy(&dp->intrLock);
+   ddi_taskq_destroy(dp->resetTask);
+
+   ddi_regs_map_free(&dp->bar1Handle);
+   ddi_regs_map_free(&dp->bar0Handle);
+   pci_config_teardown(&dp->pciHandle);
+
+   kmem_free(dp, sizeof(vmxnet3_softc_t));
+
+   return DDI_SUCCESS;
+}
+
+/* --- */
+
+/*
+ * Structures used by the Solaris module loader
+ */
+
+#define VMXNET3_IDENT "VMware EtherAdapter v3 b" BUILD_NUMBER_NUMERIC_STRING
+
+DDI_DEFINE_STREAM_OPS(vmxnet3_dev_ops,
+                      nulldev,
+                      nulldev,
+                      vmxnet3_attach,
+                      vmxnet3_detach,
+                      nodev,
+                      NULL,
+                      D_NEW | D_MP,
+                      NULL);
+
+static struct modldrv vmxnet3_modldrv = {
+   &mod_driverops,             /* drv_modops */
+   VMXNET3_IDENT,              /* drv_linkinfo */
+   &vmxnet3_dev_ops            /* drv_dev_ops */
+};
+
+static struct modlinkage vmxnet3_modlinkage = {
+    MODREV_1,                  /* ml_rev */
+    { &vmxnet3_modldrv, NULL } /* ml_linkage */
+};
+
+/* Module load entry point */
+int _init(void)
+{
+   int ret;
+
+#ifdef DEBUG
+   cmn_err(CE_CONT, "_init()\n");
+#endif
+
+   mac_init_ops(&vmxnet3_dev_ops, VMXNET3_MODNAME);
+   ret = mod_install(&vmxnet3_modlinkage);
+   if (ret != DDI_SUCCESS) {
+      mac_fini_ops(&vmxnet3_dev_ops);
+   }
+
+   return ret;
+}
+
+/* Module unload entry point */
+int _fini(void)
+{
+   int ret;
+
+#ifdef DEBUG
+   cmn_err(CE_CONT, "_fini()\n");
+#endif
+
+   ret = mod_remove(&vmxnet3_modlinkage);
+   if (ret == DDI_SUCCESS) {
+      mac_fini_ops(&vmxnet3_dev_ops);
+   }
+
+   return ret;
+}
+
+/* Module info entry point */
+int _info(struct modinfo *modinfop)
+{
+#ifdef DEBUG
+   cmn_err(CE_CONT, "_info()\n");
+#endif
+
+   return mod_info(&vmxnet3_modlinkage, modinfop);
+}
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_rx.c b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_rx.c
new file mode 100644 (file)
index 0000000..9756d4e
--- /dev/null
@@ -0,0 +1,468 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#include "vmxnet3_solaris.h"
+
+#define VMXNET3_RXBUF_SIZE (ETHERMTU + 18)
+
+static void vmxnet3_put_rxbuf(vmxnet3_rxbuf_t *rxBuf);
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_alloc_rxbuf --
+ *
+ *    Allocate a new rxBuf from memory. All its fields are set except
+ *    for its associated mblk which has to be allocated later.
+ *
+ * Results:
+ *    A new rxBuf or NULL.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static vmxnet3_rxbuf_t *
+vmxnet3_alloc_rxbuf(vmxnet3_softc_t *dp, boolean_t canSleep)
+{
+   vmxnet3_rxbuf_t *rxBuf;
+   int flag = canSleep ? KM_SLEEP : KM_NOSLEEP;
+
+   rxBuf = kmem_zalloc(sizeof(vmxnet3_rxbuf_t), flag);
+   if (!rxBuf) {
+      return NULL;
+   }
+
+   if (vmxnet3_alloc_dma_mem_1(dp, &rxBuf->dma, VMXNET3_RXBUF_SIZE,
+                               canSleep) != DDI_SUCCESS) {
+      kmem_free(rxBuf, sizeof(vmxnet3_rxbuf_t));
+      return NULL;
+   }
+
+   rxBuf->freeCB.free_func = vmxnet3_put_rxbuf;
+   rxBuf->freeCB.free_arg = (caddr_t) rxBuf;
+   rxBuf->dp = dp;
+
+   atomic_inc_32(&dp->rxNumBufs);
+
+   return rxBuf;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_free_rxbuf --
+ *
+ *    Free a rxBuf.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_free_rxbuf(vmxnet3_softc_t *dp, vmxnet3_rxbuf_t *rxBuf)
+{
+   vmxnet3_free_dma_mem(&rxBuf->dma);
+   kmem_free(rxBuf, sizeof(vmxnet3_rxbuf_t));
+
+#ifndef DEBUG
+   atomic_dec_32(&dp->rxNumBufs);
+#else
+   {
+      uint32_t nv = atomic_dec_32_nv(&dp->rxNumBufs);
+      ASSERT(nv != -1);
+   }
+#endif
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_put_rxbuf --
+ *
+ *    Return a rxBuf to the pool or free it.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_put_rxbuf(vmxnet3_rxbuf_t *rxBuf)
+{
+   vmxnet3_softc_t *dp = rxBuf->dp;
+   vmxnet3_rxpool_t *rxPool = &dp->rxPool;
+
+   VMXNET3_DEBUG(dp, 5, "free 0x%p\n", rxBuf);
+
+   mutex_enter(&dp->rxPoolLock);
+   if (dp->devEnabled && rxPool->nBufs < rxPool->nBufsLimit) {
+      rxBuf->next = rxPool->listHead;
+      rxPool->listHead = rxBuf;
+      mutex_exit(&dp->rxPoolLock);
+   } else {
+      mutex_exit(&dp->rxPoolLock);
+      vmxnet3_free_rxbuf(dp, rxBuf);
+   }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_get_rxbuf --
+ *
+ *    Get an unused rxBuf from either the pool or from memory.
+ *    The returned rxBuf has a mblk associated with it.
+ *
+ * Results:
+ *    A rxBuf or NULL.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static vmxnet3_rxbuf_t *
+vmxnet3_get_rxbuf(vmxnet3_softc_t *dp, boolean_t canSleep)
+{
+   vmxnet3_rxbuf_t *rxBuf;
+   vmxnet3_rxpool_t *rxPool = &dp->rxPool;
+
+   mutex_enter(&dp->rxPoolLock);
+   if (rxPool->listHead) {
+      rxBuf = rxPool->listHead;
+      rxPool->listHead = rxBuf->next;
+      mutex_exit(&dp->rxPoolLock);
+      VMXNET3_DEBUG(dp, 5, "alloc 0x%p from pool\n", rxBuf);
+   } else {
+      mutex_exit(&dp->rxPoolLock);
+      rxBuf = vmxnet3_alloc_rxbuf(dp, canSleep);
+      if (!rxBuf) {
+         goto done;
+      }
+      VMXNET3_DEBUG(dp, 5, "alloc 0x%p from mem\n", rxBuf);
+   }
+
+   ASSERT(rxBuf);
+
+   rxBuf->mblk = desballoc((uchar_t *) rxBuf->dma.buf,
+                           rxBuf->dma.bufLen, BPRI_MED,
+                           &rxBuf->freeCB);
+   if (!rxBuf->mblk) {
+      vmxnet3_put_rxbuf(rxBuf);
+      rxBuf = NULL;
+   }
+
+done:
+   return rxBuf;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_rx_populate --
+ *
+ *    Populate a Rx descriptor with a new rxBuf.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_rx_populate(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq,
+                    uint16_t idx, boolean_t canSleep)
+{
+   int ret = DDI_SUCCESS;
+   vmxnet3_rxbuf_t *rxBuf = vmxnet3_get_rxbuf(dp, canSleep);
+
+   if (rxBuf) {
+      vmxnet3_cmdring_t *cmdRing = &rxq->cmdRing;
+      Vmxnet3_GenericDesc *rxDesc = VMXNET3_GET_DESC(cmdRing, idx);;
+
+      rxq->bufRing[idx].rxBuf = rxBuf;
+      rxDesc->rxd.addr = rxBuf->dma.bufPA;
+      rxDesc->rxd.len = rxBuf->dma.bufLen;
+      // rxDesc->rxd.btype = 0;
+      membar_producer();
+      rxDesc->rxd.gen = cmdRing->gen;
+   } else {
+      ret = DDI_FAILURE;
+   }
+
+   return ret;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_rxqueue_init --
+ *
+ *    Initialize a RxQueue by populating the whole Rx ring with rxBufs.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+int
+vmxnet3_rxqueue_init(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq)
+{
+   vmxnet3_cmdring_t *cmdRing = &rxq->cmdRing;
+
+   do {
+      if (vmxnet3_rx_populate(dp, rxq, cmdRing->next2fill,
+                              B_TRUE) != DDI_SUCCESS) {
+         goto error;
+      }
+      VMXNET3_INC_RING_IDX(cmdRing, cmdRing->next2fill);
+   } while (cmdRing->next2fill);
+
+   dp->rxPool.nBufsLimit = vmxnet3_getprop(dp, "RxBufPoolLimit",
+                                           0, cmdRing->size * 10,
+                                           cmdRing->size * 2);
+
+   return DDI_SUCCESS;
+
+error:
+   while (cmdRing->next2fill) {
+      VMXNET3_DEC_RING_IDX(cmdRing, cmdRing->next2fill);
+      vmxnet3_free_rxbuf(dp, rxq->bufRing[cmdRing->next2fill].rxBuf);
+   }
+
+   return DDI_FAILURE;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_rxqueue_fini --
+ *
+ *    Finish a RxQueue by freeing all the related rxBufs.
+ *
+ * Results:
+ *    DDI_SUCCESS.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+vmxnet3_rxqueue_fini(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq)
+{
+   vmxnet3_rxpool_t *rxPool = &dp->rxPool;
+   vmxnet3_rxbuf_t *rxBuf;
+   unsigned int i;
+
+   ASSERT(!dp->devEnabled);
+
+   /* First the rxPool */
+   while (rxPool->listHead) {
+      rxBuf = rxPool->listHead;
+      rxPool->listHead = rxBuf->next;
+      vmxnet3_free_rxbuf(dp, rxBuf);
+   }
+
+   /* Then the ring */
+   for (i = 0; i < rxq->cmdRing.size; i++) {
+      rxBuf = rxq->bufRing[i].rxBuf;
+      ASSERT(rxBuf);
+      ASSERT(rxBuf->mblk);
+      /*
+       * Here, freemsg() will trigger a call to vmxnet3_put_rxbuf() which
+       * will then call vmxnet3_free_rxbuf() because the underlying
+       * device is disabled.
+       */
+      freemsg(rxBuf->mblk);
+   }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_rx_hwcksum --
+ *
+ *    Determine if a received packet was checksummed by the Vmxnet3
+ *    device and tag the mp appropriately.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    The mp may get tagged.
+ *
+ *---------------------------------------------------------------------------
+ */
+static void
+vmxnet3_rx_hwcksum(vmxnet3_softc_t *dp, mblk_t *mp,
+                   Vmxnet3_GenericDesc *compDesc)
+{
+   uint32_t flags = 0;
+
+   if (!compDesc->rcd.cnc) {
+      if (compDesc->rcd.v4 && compDesc->rcd.ipc) {
+         flags |= HCK_IPV4_HDRCKSUM;
+         if ((compDesc->rcd.tcp || compDesc->rcd.udp) &&
+              compDesc->rcd.tuc) {
+            flags |= HCK_FULLCKSUM | HCK_FULLCKSUM_OK;
+         }
+      }
+
+      VMXNET3_DEBUG(dp, 3, "rx cksum flags = 0x%x\n", flags);
+
+      hcksum_assoc(mp, NULL, NULL, 0, 0, 0, 0, flags, 0);
+   }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_rx_intr --
+ *
+ *    Interrupt handler for Rx. Look if there are any pending Rx and
+ *    put them in mplist.
+ *
+ * Results:
+ *    A list of messages to pass to the MAC subystem.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+mblk_t *
+vmxnet3_rx_intr(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq)
+{
+   vmxnet3_compring_t *compRing = &rxq->compRing;
+   vmxnet3_cmdring_t *cmdRing = &rxq->cmdRing;
+   Vmxnet3_RxQueueCtrl *rxqCtrl = rxq->sharedCtrl;
+   Vmxnet3_GenericDesc *compDesc;
+   mblk_t *mplist = NULL, **mplistTail = &mplist;
+
+   ASSERT(mutex_owned(&dp->intrLock));
+
+   compDesc = VMXNET3_GET_DESC(compRing, compRing->next2comp);
+   while (compDesc->rcd.gen == compRing->gen) {
+      mblk_t *mp = NULL, **mpTail = &mp;
+      boolean_t mpValid = B_TRUE;
+      boolean_t eop;
+
+      ASSERT(compDesc->rcd.sop);
+
+      do {
+         uint16_t rxdIdx = compDesc->rcd.rxdIdx;
+         vmxnet3_rxbuf_t *rxBuf = rxq->bufRing[rxdIdx].rxBuf;
+         mblk_t *mblk = rxBuf->mblk;
+         Vmxnet3_GenericDesc *rxDesc;
+
+         while (compDesc->rcd.gen != compRing->gen) {
+            /*
+             * H/W may be still be in the middle of generating this entry,
+             * so hold on until the gen bit is flipped.
+             */
+            membar_consumer();
+         }
+         ASSERT(compDesc->rcd.gen == compRing->gen);
+         ASSERT(rxBuf);
+         ASSERT(mblk);
+
+         /* Some Rx descriptors may have been skipped */
+         while (cmdRing->next2fill != rxdIdx) {
+            rxDesc = VMXNET3_GET_DESC(cmdRing, cmdRing->next2fill);
+            rxDesc->rxd.gen = cmdRing->gen;
+            VMXNET3_INC_RING_IDX(cmdRing, cmdRing->next2fill);
+         }
+
+         eop = compDesc->rcd.eop;
+
+         /*
+          * Now we have a piece of the packet in the rxdIdx descriptor.
+          * Grab it only if we achieve to replace it with a fresh buffer.
+          */
+         if (vmxnet3_rx_populate(dp, rxq, rxdIdx, B_FALSE) == DDI_SUCCESS) {
+            /* Success, we can chain the mblk with the mp */
+            mblk->b_wptr = mblk->b_rptr + compDesc->rcd.len;
+            *mpTail = mblk;
+            mpTail = &mblk->b_cont;
+            ASSERT(*mpTail == NULL);
+
+            VMXNET3_DEBUG(dp, 3, "rx 0x%p on [%u]\n", mblk, rxdIdx);
+
+            if (eop) {
+               if (!compDesc->rcd.err) {
+                  /* Tag the mp if it was checksummed by the H/W */
+                  vmxnet3_rx_hwcksum(dp, mp, compDesc);
+               } else {
+                  mpValid = B_FALSE;
+               }
+            }
+         } else {
+            /* Keep the same buffer, we still need to flip the gen bit */
+            rxDesc = VMXNET3_GET_DESC(cmdRing, rxdIdx);
+            rxDesc->rxd.gen = cmdRing->gen;
+            mpValid = B_FALSE;
+         }
+
+         VMXNET3_INC_RING_IDX(compRing, compRing->next2comp);
+         VMXNET3_INC_RING_IDX(cmdRing, cmdRing->next2fill);
+         compDesc = VMXNET3_GET_DESC(compRing, compRing->next2comp);
+      } while (!eop);
+
+      if (mp) {
+         if (mpValid) {
+            *mplistTail = mp;
+            mplistTail = &mp->b_next;
+            ASSERT(*mplistTail == NULL);
+         } else {
+            /* This message got holes, drop it */
+            freemsg(mp);
+         }
+      }
+   }
+
+   if (rxqCtrl->updateRxProd) {
+      uint32_t rxprod;
+
+      /*
+       * All buffers are actually available, but we can't tell that to
+       * the device because it may interpret that as an empty ring.
+       * So skip one buffer.
+       */
+      if (cmdRing->next2fill) {
+         rxprod = cmdRing->next2fill - 1;
+      } else {
+         rxprod = cmdRing->size - 1;
+      }
+      VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_RXPROD, rxprod);
+   }
+
+   return mplist;
+}
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_solaris.h b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_solaris.h
new file mode 100644 (file)
index 0000000..a5a87b1
--- /dev/null
@@ -0,0 +1,244 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#ifndef _VMXNET3_SOLARIS_H_
+#define _VMXNET3_SOLARIS_H_
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/debug.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/strlog.h>
+#include <sys/kmem.h>
+#include <sys/stat.h>
+#include <sys/kstat.h>
+#include <sys/vtrace.h>
+#include <sys/dlpi.h>
+#include <sys/strsun.h>
+#include <sys/ethernet.h>
+#include <sys/modctl.h>
+#include <sys/errno.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/pci.h>
+#include <sys/strsubr.h>
+#include <sys/pattr.h>
+#include <sys/mac.h>
+#include <sys/mac_ether.h>
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/tcp.h>
+
+#include "vm_basic_types.h"
+#include "vm_device_version.h"
+#include "buildNumber.h"
+
+#include "vmxnet3_defs.h"
+#include "vmxnet3_solaris_compat.h"
+
+typedef struct vmxnet3_dmabuf_t {
+   caddr_t              buf;
+   uint64_t             bufPA;
+   size_t               bufLen;
+   ddi_dma_handle_t     dmaHandle;
+   ddi_acc_handle_t     dataHandle;
+} vmxnet3_dmabuf_t;
+
+typedef struct vmxnet3_cmdring_t {
+   vmxnet3_dmabuf_t     dma;
+   uint16_t             size;
+   uint16_t             next2fill;
+   uint16_t             avail;
+   uint8_t              gen;
+} vmxnet3_cmdring_t;
+
+typedef struct vmxnet3_compring_t {
+   vmxnet3_dmabuf_t     dma;
+   uint16_t             size;
+   uint16_t             next2comp;
+   uint8_t              gen;
+} vmxnet3_compring_t;
+
+typedef struct vmxnet3_metatx_t {
+   mblk_t              *mp;
+   uint16_t             sopIdx;
+   uint16_t             frags;
+} vmxnet3_metatx_t;
+
+typedef struct vmxnet3_txqueue_t {
+   vmxnet3_cmdring_t    cmdRing;
+   vmxnet3_compring_t   compRing;
+   vmxnet3_metatx_t    *metaRing;
+   Vmxnet3_TxQueueCtrl *sharedCtrl;
+} vmxnet3_txqueue_t;
+
+typedef struct vmxnet3_rxbuf_t {
+   vmxnet3_dmabuf_t        dma;
+   mblk_t                 *mblk;
+   frtn_t                  freeCB;
+   struct vmxnet3_softc_t *dp;
+   struct vmxnet3_rxbuf_t *next;
+} vmxnet3_rxbuf_t;
+
+typedef struct vmxnet3_bufdesc_t {
+   vmxnet3_rxbuf_t     *rxBuf;
+} vmxnet3_bufdesc_t;
+
+typedef struct vmxnet3_rxpool_t {
+   vmxnet3_rxbuf_t     *listHead;
+   unsigned int         nBufs;
+   unsigned int         nBufsLimit;
+} vmxnet3_rxpool_t;
+
+typedef struct vmxnet3_rxqueue_t {
+   vmxnet3_cmdring_t    cmdRing;
+   vmxnet3_compring_t   compRing;
+   vmxnet3_bufdesc_t   *bufRing;
+   Vmxnet3_RxQueueCtrl *sharedCtrl;
+} vmxnet3_rxqueue_t;
+
+typedef struct vmxnet3_softc_t {
+   dev_info_t          *dip;
+   int                  instance;
+   mac_handle_t         mac;
+
+   ddi_acc_handle_t     pciHandle;
+   ddi_acc_handle_t     bar0Handle, bar1Handle;
+   caddr_t              bar0, bar1;
+
+   boolean_t            devEnabled;
+   uint8_t              macaddr[6];
+   link_state_t         linkState;
+   uint64_t             linkSpeed;
+   vmxnet3_dmabuf_t     sharedData;
+   vmxnet3_dmabuf_t     queueDescs;
+
+   kmutex_t             intrLock;
+   int                  intrType;
+   int                  intrMaskMode;
+   ddi_intr_handle_t    intrHandle;
+   ddi_taskq_t         *resetTask;
+
+   kmutex_t             txLock;
+   vmxnet3_txqueue_t    txQueue;
+   ddi_dma_handle_t     txDmaHandle;
+   boolean_t            txMustResched;
+
+   vmxnet3_rxqueue_t    rxQueue;
+   kmutex_t             rxPoolLock;
+   vmxnet3_rxpool_t     rxPool;
+   volatile uint32_t    rxNumBufs;
+   uint32_t             rxMode;
+
+   vmxnet3_dmabuf_t     mfTable;
+} vmxnet3_softc_t;
+
+int       vmxnet3_alloc_dma_mem_1(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
+                                  size_t size, boolean_t canSleep);
+int       vmxnet3_alloc_dma_mem_128(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
+                                    size_t size, boolean_t canSleep);
+int       vmxnet3_alloc_dma_mem_512(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
+                                    size_t size, boolean_t canSleep);
+void      vmxnet3_free_dma_mem(vmxnet3_dmabuf_t *dma);
+int       vmxnet3_getprop(vmxnet3_softc_t *dp, char *name,
+                          int min, int max, int def);
+
+int       vmxnet3_txqueue_init(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq);
+mblk_t   *vmxnet3_tx(void *data, mblk_t *mps);
+boolean_t vmxnet3_tx_complete(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq);
+void      vmxnet3_txqueue_fini(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq);
+
+int       vmxnet3_rxqueue_init(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq);
+mblk_t   *vmxnet3_rx_intr(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq);
+void      vmxnet3_rxqueue_fini(vmxnet3_softc_t *dp, vmxnet3_rxqueue_t *rxq);
+
+extern ddi_device_acc_attr_t vmxnet3_dev_attr;
+
+#define VMXNET3_MODNAME "vmxnet3s"
+
+/* Logging stuff */
+#define VMXNET3_LOG(Level, Device, Format, Args...)   \
+   cmn_err(Level, VMXNET3_MODNAME "%d: " Format,      \
+           Device->instance, ##Args);
+
+#define VMXNET3_WARN(Device, Format, Args...)         \
+   VMXNET3_LOG(CE_WARN, Device, Format, ##Args)
+
+#ifdef VMXNET3_DEBUG_LEVEL
+#define VMXNET3_DEBUG(Device, Level, Format, Args...) \
+   do {                                               \
+      if (Level <= VMXNET3_DEBUG_LEVEL) {             \
+         VMXNET3_LOG(CE_CONT, Device, Format, ##Args) \
+      }                                               \
+   } while (0)
+#else
+#define VMXNET3_DEBUG(Device, Level, Format, Args...)
+#endif
+
+#define MACADDR_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MACADDR_FMT_ARGS(mac) \
+   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
+
+/* Default ring size */
+#define VMXNET3_DEF_TX_RING_SIZE 256
+#define VMXNET3_DEF_RX_RING_SIZE 256
+
+/* Register access helpers */
+#define VMXNET3_BAR0_GET32(Device, Reg) \
+   ddi_get32((Device)->bar0Handle, (uint32_t *) ((Device)->bar0 + (Reg)))
+#define VMXNET3_BAR0_PUT32(Device, Reg, Value) \
+   ddi_put32((Device)->bar0Handle, (uint32_t *) ((Device)->bar0 + (Reg)), (Value))
+#define VMXNET3_BAR1_GET32(Device, Reg) \
+   ddi_get32((Device)->bar1Handle, (uint32_t *) ((Device)->bar1 + (Reg)))
+#define VMXNET3_BAR1_PUT32(Device, Reg, Value) \
+   ddi_put32((Device)->bar1Handle, (uint32_t *) ((Device)->bar1 + (Reg)), (Value))
+
+/* Misc helpers */
+#define VMXNET3_DS(Device) \
+   ((Vmxnet3_DriverShared *) (Device)->sharedData.buf)
+#define VMXNET3_TQDESC(Device) \
+   ((Vmxnet3_TxQueueDesc *) (Device)->queueDescs.buf)
+#define VMXNET3_RQDESC(Device) \
+   ((Vmxnet3_RxQueueDesc *) ((Device)->queueDescs.buf + sizeof(Vmxnet3_TxQueueDesc)))
+
+#define VMXNET3_ADDR_LO(addr) ((uint32_t) (addr))
+#define VMXNET3_ADDR_HI(addr) ((uint32_t) (((uint64_t) (addr)) >> 32))
+
+#define VMXNET3_GET_DESC(Ring, Idx) \
+   (((Vmxnet3_GenericDesc *) (Ring)->dma.buf) + Idx)
+
+/* Rings handling */
+#define VMXNET3_INC_RING_IDX(Ring, Idx) \
+   do {                                 \
+      (Idx)++;                          \
+      if ((Idx) == (Ring)->size) {      \
+         (Idx) = 0;                     \
+         (Ring)->gen ^= 1;              \
+      }                                 \
+   } while (0)
+
+#define VMXNET3_DEC_RING_IDX(Ring, Idx) \
+   do {                                 \
+      if ((Idx) == 0) {                 \
+         (Idx) = (Ring)->size;          \
+         (Ring)->gen ^= 1;              \
+      }                                 \
+      (Idx)--;                          \
+   } while (0)
+
+#endif /* _VMXNET3_SOLARIS_H_ */
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_solaris_compat.h b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_solaris_compat.h
new file mode 100644 (file)
index 0000000..38ea543
--- /dev/null
@@ -0,0 +1,36 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#ifndef _VMXNET3_SOLARIS_COMPAT_H_
+#define _VMXNET3_SOLARIS_COMPAT_H_
+
+/*
+ * In this file are stored all the definitions/helpers that the
+ * DDI/DDK provides but that our toolchain currently lacks.
+ * Nuke them the day the toolchain is refreshed.
+ */
+
+#define DDI_INTR_PRI(pri) (void *)((uintptr_t)(pri))
+
+#define LSO_TX_BASIC_TCP_IPV4 0x02
+
+#define HW_LSO 0x10
+
+#define DB_LSOMSS(mp) ((mp)->b_datap->db_struioun.cksum.pad)
+
+#define ETHERTYPE_VLAN (0x8100)
+
+#endif /* _VMXNET3_SOLARIS_COMPAT_H_ */
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_tx.c b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_tx.c
new file mode 100644 (file)
index 0000000..a0e4c5b
--- /dev/null
@@ -0,0 +1,516 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#include "vmxnet3_solaris.h"
+
+typedef enum vmxnet3_txstatus {
+   VMXNET3_TX_OK,
+   VMXNET3_TX_FAILURE,
+   VMXNET3_TX_PULLUP,
+   VMXNET3_TX_RINGFULL
+} vmxnet3_txstatus;
+
+typedef struct vmxnet3_offload_t {
+   uint16_t om;
+   uint16_t hlen;
+   uint16_t msscof;
+} vmxnet3_offload_t;
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_txqueue_init --
+ *
+ *    Initialize a TxQueue. Currently nothing needs to be done.
+ *
+ * Results:
+ *    DDI_SUCCESS.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+int
+vmxnet3_txqueue_init(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq)
+{
+   return DDI_SUCCESS;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_txqueue_fini --
+ *
+ *    Finish a TxQueue by freeing all pending Tx.
+ *
+ * Results:
+ *    DDI_SUCCESS.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+vmxnet3_txqueue_fini(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq)
+{
+   unsigned int i;
+
+   ASSERT(!dp->devEnabled);
+
+   for (i = 0; i < txq->cmdRing.size; i++) {
+      mblk_t *mp = txq->metaRing[i].mp;
+      if (mp) {
+         freemsg(mp);
+      }
+   }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_tx_prepare_offload --
+ *
+ *    Build the offload context of a msg.
+ *
+ * Results:
+ *    0 if everything went well.
+ *    +n if n bytes need to be pulled up.
+ *    -1 in case of error (not used).
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_tx_prepare_offload(vmxnet3_softc_t *dp,
+                           vmxnet3_offload_t *ol,
+                           mblk_t *mp)
+{
+   int ret = 0;
+   uint32_t start, stuff, value, flags;
+
+   ol->om = VMXNET3_OM_NONE;
+   ol->hlen = 0;
+   ol->msscof = 0;
+
+   hcksum_retrieve(mp, NULL, NULL, &start, &stuff, NULL, &value, &flags);
+   if (flags) {
+      struct ether_vlan_header *eth = (void *) mp->b_rptr;
+      uint8_t ethLen;
+
+      if (eth->ether_tpid == htons(ETHERTYPE_VLAN)) {
+         ethLen = sizeof(struct ether_vlan_header);
+      } else {
+         ethLen = sizeof(struct ether_header);
+      }
+
+      VMXNET3_DEBUG(dp, 4, "flags=0x%x, ethLen=%u, start=%u, stuff=%u, value=%u\n",
+                            flags,      ethLen,    start,    stuff,    value);
+
+      if (flags & HCK_PARTIALCKSUM) {
+         ol->om = VMXNET3_OM_CSUM;
+         ol->hlen = start + ethLen;
+         ol->msscof = stuff + ethLen;
+      }
+      if (flags & HW_LSO) {
+         mblk_t *mblk = mp;
+         uint8_t *ip, *tcp;
+         uint8_t ipLen, tcpLen;
+
+         /*
+          * Copy e1000g's behavior:
+          * - Do not assume all the headers are in the same mblk.
+          * - Assume each header is always within one mblk.
+          * - Assume the ethernet header is in the first mblk.
+          */
+         ip = mblk->b_rptr + ethLen;
+         if (ip >= mblk->b_wptr) {
+            mblk = mblk->b_cont;
+            ip = mblk->b_rptr;
+         }
+         ipLen = IPH_HDR_LENGTH((ipha_t *) ip);
+         tcp = ip + ipLen;
+         if (tcp >= mblk->b_wptr) {
+            mblk = mblk->b_cont;
+            tcp = mblk->b_rptr;
+         }
+         tcpLen = TCP_HDR_LENGTH((tcph_t *) tcp);
+         if (tcp + tcpLen > mblk->b_wptr) { // careful, '>' instead of '>=' here
+            mblk = mblk->b_cont;
+         }
+
+         ol->om = VMXNET3_OM_TSO;
+         ol->hlen = ethLen + ipLen + tcpLen;
+         /* OpenSolaris fills 'value' with the MSS but Solaris doesn't. */
+         ol->msscof = DB_LSOMSS(mp);
+
+         if (mblk != mp) {
+            ret = ol->hlen;
+         }
+      }
+   }
+
+   return ret;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_tx_one --
+ *
+ *    Map a msg into the Tx command ring of a vmxnet3 device.
+ *
+ * Results:
+ *    VMXNET3_TX_OK if everything went well.
+ *    VMXNET3_TX_RINGFULL if the ring is nearly full.
+ *    VMXNET3_TX_PULLUP if the msg is overfragmented.
+ *    VMXNET3_TX_FAILURE if there was a DMA or offload error.
+ *
+ * Side effects:
+ *    The ring is filled if VMXNET3_TX_OK is returned.
+ *
+ *---------------------------------------------------------------------------
+ */
+static vmxnet3_txstatus
+vmxnet3_tx_one(vmxnet3_softc_t *dp,
+               vmxnet3_txqueue_t *txq,
+               vmxnet3_offload_t *ol,
+               mblk_t *mp)
+{
+   int ret = VMXNET3_TX_OK;
+   unsigned int frags = 0, totLen = 0;
+   vmxnet3_cmdring_t *cmdRing = &txq->cmdRing;
+   Vmxnet3_TxQueueCtrl *txqCtrl = txq->sharedCtrl;
+   Vmxnet3_GenericDesc *txDesc;
+   uint16_t sopIdx, eopIdx;
+   uint8_t sopGen, curGen;
+   mblk_t *mblk;
+
+   mutex_enter(&dp->txLock);
+
+   sopIdx = eopIdx = cmdRing->next2fill;
+   sopGen = cmdRing->gen;
+   curGen = !cmdRing->gen;
+
+   for (mblk = mp; mblk != NULL; mblk = mblk->b_cont) {
+      unsigned int len = MBLKL(mblk);
+      ddi_dma_cookie_t cookie;
+      uint_t cookieCount;
+
+      if (len) {
+         totLen += len;
+      } else {
+         continue;
+      }
+
+      if (ddi_dma_addr_bind_handle(dp->txDmaHandle, NULL,
+                                   (caddr_t) mblk->b_rptr, len,
+                                   DDI_DMA_RDWR | DDI_DMA_STREAMING,
+                                   DDI_DMA_DONTWAIT, NULL,
+                                   &cookie, &cookieCount) != DDI_DMA_MAPPED) {
+         VMXNET3_WARN(dp, "ddi_dma_addr_bind_handle() failed\n");
+         ret = VMXNET3_TX_FAILURE;
+         goto error;
+      }
+
+      ASSERT(cookieCount);
+
+      do {
+         uint64_t addr = cookie.dmac_laddress;
+         size_t len = cookie.dmac_size;
+
+         do {
+            uint32_t dw2, dw3;
+            size_t chunkLen;
+
+            ASSERT(!txq->metaRing[eopIdx].mp);
+            ASSERT(cmdRing->avail - frags);
+
+            if (frags >= cmdRing->size - 1 ||
+                (ol->om != VMXNET3_OM_TSO && frags >= VMXNET3_MAX_TXD_PER_PKT)) {
+               VMXNET3_DEBUG(dp, 2, "overfragmented mp (%u)\n", frags);
+               ddi_dma_unbind_handle(dp->txDmaHandle);
+               ret = VMXNET3_TX_PULLUP;
+               goto error;
+            }
+            if (cmdRing->avail - frags <= 1) {
+               dp->txMustResched = B_TRUE;
+               ddi_dma_unbind_handle(dp->txDmaHandle);
+               ret = VMXNET3_TX_RINGFULL;
+               goto error;
+            }
+
+            if (len > VMXNET3_MAX_TX_BUF_SIZE) {
+               chunkLen = VMXNET3_MAX_TX_BUF_SIZE;
+            } else {
+               chunkLen = len;
+            }
+
+            frags++;
+            eopIdx = cmdRing->next2fill;
+
+            txDesc = VMXNET3_GET_DESC(cmdRing, eopIdx);
+            ASSERT(txDesc->txd.gen != cmdRing->gen);
+
+            // txd.addr
+            txDesc->txd.addr = addr;
+            // txd.dw2
+            dw2 = chunkLen == VMXNET3_MAX_TX_BUF_SIZE ? 0 : chunkLen;
+            dw2 |= curGen << VMXNET3_TXD_GEN_SHIFT;
+            txDesc->dword[2] = dw2;
+            ASSERT(txDesc->txd.len == len || txDesc->txd.len == 0);
+            // txd.dw3
+            dw3 = 0;
+            txDesc->dword[3] = dw3;
+
+            VMXNET3_INC_RING_IDX(cmdRing, cmdRing->next2fill);
+            curGen = cmdRing->gen;
+
+            addr += chunkLen;
+            len -= chunkLen;
+         } while (len);
+
+         if (--cookieCount) {
+            ddi_dma_nextcookie(dp->txDmaHandle, &cookie);
+         }
+      } while (cookieCount);
+
+      ddi_dma_unbind_handle(dp->txDmaHandle);
+   }
+
+   /* Update the EOP descriptor */
+   txDesc = VMXNET3_GET_DESC(cmdRing, eopIdx);
+   txDesc->dword[3] |= VMXNET3_TXD_CQ | VMXNET3_TXD_EOP;
+
+   /* Update the SOP descriptor. Must be done last */
+   txDesc = VMXNET3_GET_DESC(cmdRing, sopIdx);
+   if (ol->om == VMXNET3_OM_TSO &&
+       txDesc->txd.len != 0 &&
+       txDesc->txd.len < ol->hlen) {
+      ret = VMXNET3_TX_FAILURE;
+      goto error;
+   }
+   txDesc->txd.om = ol->om;
+   txDesc->txd.hlen = ol->hlen;
+   txDesc->txd.msscof = ol->msscof;
+   membar_producer();
+   txDesc->txd.gen = sopGen;
+
+   /* Update the meta ring & metadata */
+   txq->metaRing[sopIdx].mp = mp;
+   txq->metaRing[eopIdx].sopIdx = sopIdx;
+   txq->metaRing[eopIdx].frags = frags;
+   cmdRing->avail -= frags;
+   if (ol->om == VMXNET3_OM_TSO) {
+      txqCtrl->txNumDeferred +=
+         (totLen - ol->hlen + ol->msscof - 1) / ol->msscof;
+   } else {
+      txqCtrl->txNumDeferred++;
+   }
+
+   VMXNET3_DEBUG(dp, 3, "tx 0x%p on [%u;%u]\n", mp, sopIdx, eopIdx);
+
+   goto done;
+
+error:
+   /* Reverse the generation bits */
+   while (sopIdx != cmdRing->next2fill) {
+      VMXNET3_DEC_RING_IDX(cmdRing, cmdRing->next2fill);
+      txDesc = VMXNET3_GET_DESC(cmdRing, cmdRing->next2fill);
+      txDesc->txd.gen = !cmdRing->gen;
+   }
+
+done:
+   mutex_exit(&dp->txLock);
+
+   return ret;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_tx --
+ *
+ *    Send packets on a vmxnet3 device.
+ *
+ * Results:
+ *    NULL in case of success or failure.
+ *    The mps to be retransmitted later if the ring is full.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+mblk_t *
+vmxnet3_tx(void *data, mblk_t *mps)
+{
+   vmxnet3_softc_t *dp = data;
+   vmxnet3_txqueue_t *txq = &dp->txQueue;
+   vmxnet3_cmdring_t *cmdRing = &txq->cmdRing;
+   Vmxnet3_TxQueueCtrl *txqCtrl = txq->sharedCtrl;
+   vmxnet3_txstatus status = VMXNET3_TX_OK;
+   mblk_t *mp;
+
+   ASSERT(mps != NULL);
+
+   do {
+      vmxnet3_offload_t ol;
+      int pullup;
+
+      mp = mps;
+      mps = mp->b_next;
+      mp->b_next = NULL;
+
+      if (DB_TYPE(mp) != M_DATA) {
+         /*
+          * PR #315560: Solaris might pass M_PROTO mblks for some reason.
+          * Drop them because we don't understand them and because their
+          * contents are not Ethernet frames anyway.
+          */
+         ASSERT(B_FALSE);
+         freemsg(mp);
+         continue;
+      }
+
+      /*
+       * Prepare the offload while we're still handling the original
+       * message -- msgpullup() discards the metadata afterwards.
+       */
+      pullup = vmxnet3_tx_prepare_offload(dp, &ol, mp);
+      if (pullup) {
+         mblk_t *new_mp = msgpullup(mp, pullup);
+         freemsg(mp);
+         if (new_mp) {
+            mp = new_mp;
+         } else {
+            continue;
+         }
+      }
+
+      /*
+       * Try to map the message in the Tx ring.
+       * This call might fail for non-fatal reasons.
+       */
+      status = vmxnet3_tx_one(dp, txq, &ol, mp);
+      if (status == VMXNET3_TX_PULLUP) {
+         /*
+          * Try one more time after flattening
+          * the message with msgpullup().
+          */
+         if (mp->b_cont != NULL) {
+            mblk_t *new_mp = msgpullup(mp, -1);
+            freemsg(mp);
+            if (new_mp) {
+               mp = new_mp;
+               status = vmxnet3_tx_one(dp, txq, &ol, mp);
+            } else {
+               continue;
+            }
+         }
+      }
+      if (status != VMXNET3_TX_OK && status != VMXNET3_TX_RINGFULL) {
+         /* Fatal failure, drop it */
+         freemsg(mp);
+      }
+   } while (mps && status != VMXNET3_TX_RINGFULL);
+
+   if (status == VMXNET3_TX_RINGFULL) {
+      mp->b_next = mps;
+      mps = mp;
+   } else {
+      ASSERT(!mps);
+   }
+
+   /* Notify the device */
+   mutex_enter(&dp->txLock);
+   if (txqCtrl->txNumDeferred >= txqCtrl->txThreshold) {
+      VMXNET3_BAR0_PUT32(dp, VMXNET3_REG_TXPROD, cmdRing->next2fill);
+      txqCtrl->txNumDeferred = 0;
+   }
+   mutex_exit(&dp->txLock);
+
+   return mps;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_tx_complete --
+ *
+ *    Parse a transmit queue and complete packets.
+ *
+ * Results:
+ *    B_TRUE if Tx must be updated or B_FALSE if no action is required.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+boolean_t
+vmxnet3_tx_complete(vmxnet3_softc_t *dp, vmxnet3_txqueue_t *txq)
+{
+   vmxnet3_cmdring_t *cmdRing = &txq->cmdRing;
+   vmxnet3_compring_t *compRing = &txq->compRing;
+   Vmxnet3_GenericDesc *compDesc;
+   boolean_t completedTx = B_FALSE;
+   boolean_t ret = B_FALSE;
+
+   mutex_enter(&dp->txLock);
+
+   compDesc = VMXNET3_GET_DESC(compRing, compRing->next2comp);
+   while (compDesc->tcd.gen == compRing->gen) {
+      vmxnet3_metatx_t *sopMetaDesc, *eopMetaDesc;
+      uint16_t sopIdx, eopIdx;
+      mblk_t *mp;
+
+      eopIdx = compDesc->tcd.txdIdx;
+      eopMetaDesc = &txq->metaRing[eopIdx];
+      sopIdx = eopMetaDesc->sopIdx;
+      sopMetaDesc = &txq->metaRing[sopIdx];
+
+      ASSERT(eopMetaDesc->frags);
+      cmdRing->avail += eopMetaDesc->frags;
+
+      ASSERT(sopMetaDesc->mp);
+      mp = sopMetaDesc->mp;
+      freemsg(mp);
+
+      eopMetaDesc->sopIdx = 0;
+      eopMetaDesc->frags = 0;
+      sopMetaDesc->mp = NULL;
+
+      completedTx = B_TRUE;
+
+      VMXNET3_DEBUG(dp, 3, "cp 0x%p on [%u;%u]\n", mp, sopIdx, eopIdx);
+
+      VMXNET3_INC_RING_IDX(compRing, compRing->next2comp);
+      compDesc = VMXNET3_GET_DESC(compRing, compRing->next2comp);
+   }
+
+   if (dp->txMustResched && completedTx) {
+      dp->txMustResched = B_FALSE;
+      ret = B_TRUE;
+   }
+
+   mutex_exit(&dp->txLock);
+
+   return ret;
+}
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_utils.c b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3_utils.c
new file mode 100644 (file)
index 0000000..665215b
--- /dev/null
@@ -0,0 +1,248 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+#include "vmxnet3_solaris.h"
+
+/* This symbol is needed by the Solaris dynamic loader */
+char _depends_on[] = {"misc/mac"};
+
+/* Used by ddi_regs_map_setup() and ddi_dma_mem_alloc() */
+ddi_device_acc_attr_t vmxnet3_dev_attr = {
+   DDI_DEVICE_ATTR_V0,
+   DDI_STRUCTURE_LE_ACC,
+   DDI_STRICTORDER_ACC
+};
+
+/* Buffers with no alignment constraint DMA description */
+static ddi_dma_attr_t vmxnet3_dma_attrs_1 = {
+   DMA_ATTR_V0,           /* dma_attr_version */
+   0x0000000000000000ull, /* dma_attr_addr_lo */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_count_max */
+   0x0000000000000001ull, /* dma_attr_align */
+   0x0000000000000001ull, /* dma_attr_burstsizes */
+   0x00000001,            /* dma_attr_minxfer */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_maxxfer */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
+   1,                     /* dma_attr_sgllen */
+   0x00000001,            /* dma_attr_granular */
+   0                      /* dma_attr_flags */
+};
+
+/* Buffers with a 128-bytes alignment constraint DMA description */
+static ddi_dma_attr_t vmxnet3_dma_attrs_128 = {
+   DMA_ATTR_V0,           /* dma_attr_version */
+   0x0000000000000000ull, /* dma_attr_addr_lo */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_count_max */
+   0x0000000000000080ull, /* dma_attr_align */
+   0x0000000000000001ull, /* dma_attr_burstsizes */
+   0x00000001,            /* dma_attr_minxfer */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_maxxfer */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
+   1,                     /* dma_attr_sgllen */
+   0x00000001,            /* dma_attr_granular */
+   0                      /* dma_attr_flags */
+};
+
+/* Buffers with a 512-bytes alignment constraint DMA description */
+static ddi_dma_attr_t vmxnet3_dma_attrs_512 = {
+   DMA_ATTR_V0,           /* dma_attr_version */
+   0x0000000000000000ull, /* dma_attr_addr_lo */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_count_max */
+   0x0000000000000200ull, /* dma_attr_align */
+   0x0000000000000001ull, /* dma_attr_burstsizes */
+   0x00000001,            /* dma_attr_minxfer */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_maxxfer */
+   0xFFFFFFFFFFFFFFFFull, /* dma_attr_seg */
+   1,                     /* dma_attr_sgllen */
+   0x00000001,            /* dma_attr_granular */
+   0                      /* dma_attr_flags */
+};
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_alloc_dma_mem --
+ *
+ *    Allocate /size/ bytes of contiguous DMA-ble memory.
+ *
+ * Results:
+ *    DDI_SUCCESS or DDI_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+vmxnet3_alloc_dma_mem(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
+                      size_t size, boolean_t canSleep,
+                      ddi_dma_attr_t *dma_attrs)
+{
+   ddi_dma_cookie_t cookie;
+   uint_t cookieCount;
+   int (*cb) (caddr_t) = canSleep ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT;
+
+   ASSERT(size != 0);
+
+   /*
+    * Allocate a DMA handle
+    */
+   if (ddi_dma_alloc_handle(dp->dip, dma_attrs, cb, NULL,
+                            &dma->dmaHandle) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_dma_alloc_handle() failed\n");
+      goto error;
+   }
+
+   /*
+    * Allocate memory
+    */
+   if (ddi_dma_mem_alloc(dma->dmaHandle, size, &vmxnet3_dev_attr,
+                         DDI_DMA_CONSISTENT, cb, NULL, &dma->buf,
+                         &dma->bufLen, &dma->dataHandle) != DDI_SUCCESS) {
+      VMXNET3_WARN(dp, "ddi_dma_mem_alloc() failed\n");
+      goto error_dma_handle;
+   }
+
+   /*
+    * Map the memory
+    */
+   if (ddi_dma_addr_bind_handle(dma->dmaHandle, NULL,
+                                dma->buf, dma->bufLen,
+                                DDI_DMA_RDWR | DDI_DMA_STREAMING,
+                                cb, NULL, &cookie,
+                                &cookieCount) != DDI_DMA_MAPPED) {
+      VMXNET3_WARN(dp, "ddi_dma_addr_bind_handle() failed\n");
+      goto error_dma_mem;
+   }
+
+   ASSERT(cookieCount == 1);
+   dma->bufPA = cookie.dmac_laddress;
+
+   return DDI_SUCCESS;
+
+error_dma_mem:
+   ddi_dma_mem_free(&dma->dataHandle);
+error_dma_handle:
+   ddi_dma_free_handle(&dma->dmaHandle);
+error:
+   dma->buf = NULL;
+   dma->bufPA = NULL;
+   dma->bufLen = 0;
+   return DDI_FAILURE;
+}
+
+int
+vmxnet3_alloc_dma_mem_1(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
+                        size_t size, boolean_t canSleep)
+{
+   return vmxnet3_alloc_dma_mem(dp, dma, size, canSleep,
+                                &vmxnet3_dma_attrs_1);
+}
+
+int
+vmxnet3_alloc_dma_mem_512(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
+                          size_t size, boolean_t canSleep)
+{
+   return vmxnet3_alloc_dma_mem(dp, dma, size, canSleep,
+                                &vmxnet3_dma_attrs_512);
+}
+
+int
+vmxnet3_alloc_dma_mem_128(vmxnet3_softc_t *dp, vmxnet3_dmabuf_t *dma,
+                          size_t size, boolean_t canSleep)
+{
+   return vmxnet3_alloc_dma_mem(dp, dma, size, canSleep,
+                                &vmxnet3_dma_attrs_128);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_free_dma_mem --
+ *
+ *    Free DMA-ble memory.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+vmxnet3_free_dma_mem(vmxnet3_dmabuf_t *dma)
+{
+   ddi_dma_unbind_handle(dma->dmaHandle);
+   ddi_dma_mem_free(&dma->dataHandle);
+   ddi_dma_free_handle(&dma->dmaHandle);
+
+   dma->buf = NULL;
+   dma->bufPA = NULL;
+   dma->bufLen = 0;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * vmxnet3_getprop --
+ *
+ *    Get the numeric value of the property "name" in vmxnet3s.conf for
+ *    the corresponding device instance.
+ *    If the property isn't found or if it doesn't satisfy the conditions,
+ *    "def" is returned.
+ *
+ * Results:
+ *    The value of the property or "def".
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------------
+ */
+int
+vmxnet3_getprop(vmxnet3_softc_t *dp, char *name,
+                int min, int max, int def)
+{
+   int ret = def;
+   int *props;
+   uint_t nprops;
+
+   if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dp->dip, DDI_PROP_DONTPASS,
+                                 name, &props, &nprops) == DDI_PROP_SUCCESS) {
+      if (dp->instance < nprops) {
+         ret = props[dp->instance];
+      } else {
+         VMXNET3_WARN(dp, "property %s not available for this device\n",
+                      name);
+      }
+      ddi_prop_free(props);
+   }
+
+   if (ret < min || ret > max) {
+      ASSERT(def >= min && def <= max);
+      VMXNET3_WARN(dp, "property %s invalid (%d <= %d <= %d)\n",
+                   name, min, ret, max);
+      ret = def;
+   }
+
+   VMXNET3_DEBUG(dp, 2, "getprop(%s) -> %d\n", name, ret);
+
+   return ret;
+}
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet3s.conf b/open-vm-tools/modules/solaris/vmxnet3/vmxnet3s.conf
new file mode 100644 (file)
index 0000000..4bfaf56
--- /dev/null
@@ -0,0 +1,39 @@
+# Driver.conf(4) file for VMware Vmxnet Generation 3 adapters.
+
+# TxRingSize --
+#
+#    Tx ring size for each vmxnet3s# adapter. Must be a multiple of 32.
+#
+#    Minimum value: 32
+#    Maximum value: 4096
+#
+TxRingSize=256,256,256,256,256,256,256,256,256,256;
+
+# RxRingSize --
+#
+#    Rx ring size for each vmxnet3s# adapter. Must be a multiple of 32.
+#
+#    Minimum value: 32
+#    Maximum value: 4096
+#
+RxRingSize=256,256,256,256,256,256,256,256,256,256;
+
+# RxBufPoolLimit --
+#
+#    Limit the number of Rx buffers cached for each vmxnet3s# adapter.
+#    Increasing the limit might improve performance but increases the
+#    memory footprint.
+#
+#    Minimum value: 0
+#    Maximum value: RxRingSize * 10
+#
+RxBufPoolLimit=512,512,512,512,512,512,512,512,512,512;
+
+# EnableLSO --
+#
+#    Enable or disable LSO for each vmxnet3s# adapter.
+#
+#    Minimum value: 0
+#    Maximum value: 1
+#
+EnableLSO=1,1,1,1,1,1,1,1,1,1;
diff --git a/open-vm-tools/modules/solaris/vmxnet3/vmxnet_def.h b/open-vm-tools/modules/solaris/vmxnet3/vmxnet_def.h
new file mode 100644 (file)
index 0000000..841a250
--- /dev/null
@@ -0,0 +1,168 @@
+/*********************************************************
+ * Copyright (C) 1999 VMware, Inc. All rights reserved.
+ *
+ * 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.
+ *
+ *********************************************************/
+
+#ifndef _VMXNET_DEF_H_
+#define _VMXNET_DEF_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "net_sg.h"
+#include "vmnet_def.h"
+
+
+/*
+ *   Vmxnet I/O ports, used by both the vmxnet driver and 
+ *   the device emulation code.
+ */
+
+#define VMXNET_INIT_ADDR               0x00
+#define VMXNET_INIT_LENGTH             0x04
+#define VMXNET_TX_ADDR                 0x08
+#define VMXNET_COMMAND_ADDR            0x0c
+#define VMXNET_MAC_ADDR                        0x10
+#define VMXNET_LOW_VERSION             0x18
+#define VMXNET_HIGH_VERSION            0x1c
+#define VMXNET_STATUS_ADDR             0x20
+#define VMXNET_TOE_INIT_ADDR            0x24
+#define VMXNET_APROM_ADDR               0x28
+#define VMXNET_INT_ENABLE_ADDR          0x30
+#define VMXNET_WAKE_PKT_PATTERNS        0x34
+
+/*
+ * Vmxnet command register values.
+ */
+#define VMXNET_CMD_INTR_ACK            0x0001
+#define VMXNET_CMD_UPDATE_LADRF                0x0002
+#define VMXNET_CMD_UPDATE_IFF          0x0004
+#define VMXNET_CMD_UNUSED 1            0x0008
+#define VMXNET_CMD_UNUSED_2            0x0010
+#define VMXNET_CMD_INTR_DISABLE        0x0020
+#define VMXNET_CMD_INTR_ENABLE         0x0040
+#define VMXNET_CMD_UNUSED_3            0x0080
+#define VMXNET_CMD_CHECK_TX_DONE       0x0100
+#define VMXNET_CMD_GET_NUM_RX_BUFFERS  0x0200
+#define VMXNET_CMD_GET_NUM_TX_BUFFERS  0x0400
+#define VMXNET_CMD_PIN_TX_BUFFERS      0x0800
+#define VMXNET_CMD_GET_CAPABILITIES    0x1000
+#define VMXNET_CMD_GET_FEATURES                0x2000
+#define VMXNET_CMD_SET_POWER_FULL       0x4000
+#define VMXNET_CMD_SET_POWER_LOW        0x8000
+
+/*
+ * Vmxnet status register values.
+ */
+#define VMXNET_STATUS_CONNECTED                0x0001
+#define VMXNET_STATUS_ENABLED          0x0002
+#define VMXNET_STATUS_TX_PINNED         0x0004
+
+/*
+ * Values for the interface flags.
+ */
+#define VMXNET_IFF_PROMISC             0x01
+#define VMXNET_IFF_BROADCAST           0x02
+#define VMXNET_IFF_MULTICAST           0x04
+#define VMXNET_IFF_DIRECTED             0x08
+
+/*
+ * Length of the multicast address filter.
+ */
+#define VMXNET_MAX_LADRF               2
+
+/*
+ * Size of Vmxnet APROM. 
+ */
+#define VMXNET_APROM_SIZE 6
+
+/*
+ * An invalid ring index.
+ */
+#define VMXNET_INVALID_RING_INDEX      (-1)
+
+/*
+ * Features that are implemented by the driver.  These are driver
+ * specific so not all features will be listed here.  In addition not all
+ * drivers have to pay attention to these feature flags.
+ *
+ *  VMXNET_FEATURE_ZERO_COPY_TX        The driver won't do any copies as long as
+ *                                     the packet length is > 
+ *                                     Vmxnet_DriverData.minTxPhysLength.
+ * 
+ *  VMXNET_FEATURE_TSO                  The driver will use the TSO capabilities
+ *                                      of the underlying hardware if available 
+ *                                      and enabled.
+ *
+ *  VMXNET_FEATURE_JUMBO_FRAME          The driver can send/rcv jumbo frame 
+ *
+ *  VMXNET_FEATURE_LPD                  The backend can deliver large pkts
+ */
+#define VMXNET_FEATURE_ZERO_COPY_TX             0x01
+#define VMXNET_FEATURE_TSO                      0x02
+#define VMXNET_FEATURE_JUMBO_FRAME              0x04
+#define VMXNET_FEATURE_LPD                      0x08
+
+/*
+ * Define the set of capabilities required by each feature above
+ */
+#define VMXNET_FEATURE_ZERO_COPY_TX_CAPS        VMXNET_CAP_SG
+#define VMXNET_FEATURE_TSO_CAPS                 VMXNET_CAP_TSO
+#define VMXNET_HIGHEST_FEATURE_BIT              VMXNET_FEATURE_TSO
+
+#define VMXNET_INC(val, max)     \
+   val++;                        \
+   if (UNLIKELY(val == max)) {   \
+      val = 0;                   \
+   }
+
+/*
+ * code that just wants to switch on the different versions of the
+ * guest<->implementation protocol can cast driver data to this.
+ */
+typedef uint32 Vmxnet_DDMagic;
+
+/*
+ * Wake packet pattern commands sent through VMXNET_WAKE_PKT_PATTERNS port
+ */
+
+#define VMXNET_PM_OPCODE_START 3 /* args: cnt of wake packet patterns */
+#define VMXNET_PM_OPCODE_LEN   2 /* args: index of wake packet pattern */
+                                 /*       number of pattern byte values */
+#define VMXNET_PM_OPCODE_DATA  1 /* args: index of wake packet pattern */
+                                 /*       offset in pattern byte values list */
+                                 /*       packet byte offset */
+                                 /*       packet byte value */
+#define VMXNET_PM_OPCODE_END   0 /* args: <none> */
+
+typedef union Vmxnet_WakePktCmd {
+   uint32 pktData : 32;
+   struct {
+      unsigned cmd : 2; /* wake packet pattern cmd [from list above] */
+      unsigned cnt : 3; /* cnt wk pkt pttrns 1..MAX_NUM_FILTER_PTTRNS */
+      unsigned ind : 3; /* ind wk pkt pttrn 0..MAX_NUM_FILTER_PTTRNS-1 */
+      unsigned lenOff : 8; /* num pttrn byte vals 1..MAX_PKT_FILTER_SIZE */
+                           /* OR offset in pattern byte values list */
+                           /* 0..MAX_PKT_FILTER_SIZE-1 */
+      unsigned byteOff : 8; /* pkt byte offset 0..MAX_PKT_FILTER_SIZE-1 */
+      unsigned byteVal : 8; /* packet byte value 0..255 */
+   } pktPttrn;
+} Vmxnet_WakePktCmd;
+
+#endif /* _VMXNET_DEF_H_ */
similarity index 68%
rename from open-vm-tools/lib/toolsLogger/Makefile.am
rename to open-vm-tools/rpctool/Makefile.am
index 41f9615d35771368334765dfa99d683d4a7fb882..9b806a38b54399b56818794eb948fbfb58ab00df 100644 (file)
@@ -1,5 +1,5 @@
 ################################################################################
-### Copyright 2007 VMware, Inc.  All rights reserved.
+### Copyright 2009 VMware, Inc.  All rights reserved.
 ###
 ### This program is free software; you can redistribute it and/or modify
 ### it under the terms of version 2 of the GNU General Public License as
 ### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 ################################################################################
 
-noinst_LTLIBRARIES = libToolsLogger.la
+bin_PROGRAMS = vmware-rpctool
+
+vmware_rpctool_SOURCES =
+vmware_rpctool_SOURCES += rpctool.c
+
+vmware_rpctool_LDADD =
+vmware_rpctool_LDADD += ../lib/rpcOut/libRpcOut.la
+vmware_rpctool_LDADD += ../lib/message/libMessage.la
+vmware_rpctool_LDADD += ../lib/backdoor/libBackdoor.la
+vmware_rpctool_LDADD += ../lib/string/libString.la
 
-libToolsLogger_la_SOURCES =
-libToolsLogger_la_SOURCES += logger.c
diff --git a/open-vm-tools/rpctool/rpctool.c b/open-vm-tools/rpctool/rpctool.c
new file mode 100644 (file)
index 0000000..b93fd28
--- /dev/null
@@ -0,0 +1,106 @@
+/*********************************************************
+ * Copyright (C) 2002 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.
+ *
+ *********************************************************/
+
+/*
+ * rpcTool.c --
+ *
+ *      Simple program to drive the guest RPC library.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vmware.h"
+#include "rpcout.h"
+#include "str.h"
+
+int RpcToolCommand(int argc, char *argv[]);
+
+void
+PrintUsage(void)
+{
+   fprintf(stderr, "rpctool syntax:\n\n");
+   fprintf(stderr, "  rpctool <text>\n\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   if (argc <= 1) {
+      PrintUsage();
+      return 1;
+   }
+
+   argc--;
+   argv++;
+
+   return RpcToolCommand(argc, argv);
+}
+
+int
+RpcToolCommand(int argc, char *argv[])
+{
+   char *result = NULL;
+   Bool status = FALSE;
+
+   status = RpcOut_sendOne(&result, NULL, "%s", argv[0]);
+   if (!status) {
+      fprintf(stderr, "%s\n", result ? result : "NULL");
+   } else {
+      printf("%s\n", result);
+   }
+   free(result);
+   return (status == TRUE ? 0 : 1);
+}
+
+void
+Panic(const char *fmt, ...)
+{
+   va_list args;
+   static char buf[1024];
+
+   va_start(args, fmt);
+   Str_Vsnprintf(buf, sizeof buf, fmt, args);
+   va_end(args);
+
+   fputs(buf, stderr);
+   abort();
+}
+
+
+void
+Debug(char *fmt, ...)
+{
+#if defined(VMX86_DEBUG) || defined(VMX86_DEVEL)
+   va_list args;
+   char *buf;
+
+   va_start(args, fmt);
+   buf = Str_Vasprintf(NULL, fmt, args);
+   va_end(args);
+
+   fprintf(stderr, "rpctool: %s\n", buf);
+   fflush(stderr);
+#else
+   /* No output in non-debug/non-developer builds */
+#endif
+}
+
+
index c82b2e98e4833b2e4d7068eb07b510cd3b897cde..a2428f86721a3c87c2e09abc7990380d2680b75c 100644 (file)
@@ -72,11 +72,6 @@ typedef struct _GuestInfoCache{
 } GuestInfoCache;
 
 
-/*
- * Local variables.
- */
-static gboolean gDisableQueryDiskInfo = FALSE;
-
 /* Local cache of the guest information that was last sent to vmx. */
 static GuestInfoCache gInfoCache;
 
@@ -221,6 +216,7 @@ GuestInfoGather(gpointer data)
    char name[255];
    char osNameFull[MAX_VALUE_LEN];
    char osName[MAX_VALUE_LEN];
+   gboolean disableQueryDiskInfo;
    GuestNicList nicInfo;
    GuestDiskInfo diskInfo;
 #if defined(_WIN32) || defined(linux)
@@ -255,7 +251,11 @@ GuestInfoGather(gpointer data)
       }
    }
 
-   if (!gDisableQueryDiskInfo) {
+   disableQueryDiskInfo = g_key_file_get_boolean(ctx->config,
+                                                 "guestinfo",
+                                                 CONFNAME_DISABLEQUERYDISKINFO,
+                                                 NULL);
+   if (!disableQueryDiskInfo) {
       if (!GuestInfo_GetDiskInfo(&diskInfo)) {
          g_warning("Failed to get disk info.\n");
       } else {
@@ -1028,11 +1028,6 @@ ToolsOnLoad(ToolsAppCtx *ctx)
    memset(&gInfoCache, 0, sizeof gInfoCache);
    vmResumed = FALSE;
 
-   gDisableQueryDiskInfo = g_key_file_get_boolean(ctx->config,
-                                                  "guestinfo",
-                                                  CONFNAME_DISABLEQUERYDISKINFO,
-                                                  NULL);
-
    /* Add the first timer event. */
    src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10);
    VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL);
index dc7afc299eb30cbf049d498b02115d3fb1e7fac6..838b610486e03051133f07a44e9d0cf4b08dc123 100644 (file)
@@ -65,9 +65,10 @@ GuestInfo_PerfMon(GuestMemInfo *vmStats)   // OUT: filled vmstats
 {
 #ifndef NO_PROCPS
    ASSERT(vmStats);
+   vmStats->flags = 0;
    GuestInfoMonitorGetStat(vmStats);
    if (GuestInfoMonitorReadMeminfo(vmStats)) {
-      vmStats->flags = LINUX_MEMINFO_FLAGS;
+      vmStats->flags |= LINUX_MEMINFO_FLAGS;
       return TRUE;
    }
 #endif
@@ -133,16 +134,6 @@ GuestInfoMonitorGetStat(GuestMemInfo *vmStats)   // OUT: filled vmstats
    vmStats->swapOutRate = (uint64)((*swapOut * kb_per_page * hz + cpuHalf) / cpuTotal);
    vmStats->ioInRate = (uint64)((*pageIn * kb_per_page * hz + cpuHalf) / cpuTotal);
    vmStats->ioOutRate = (uint64)((*pageOut * kb_per_page * hz + cpuHalf) / cpuTotal);
-
-
-   Debug("GuestInfoMonitorGetStat: GuestMemInfo: total: %"FMT64"u free: %"FMT64"u"\
-         "buff: %"FMT64"u cache: %"FMT64"u swapin: %"FMT64"u swapout: %"FMT64"u ioin:"\
-         "%"FMT64"u ioout: %"FMT64"u inactive: %"FMT64"u active: %"FMT64"u"\
-         "hugetotal: %"FMT64"u hugefree: %"FMT64"u\n", vmStats->memTotal,
-         vmStats->memFree, vmStats->memBuff, vmStats->memCache, vmStats->swapInRate,
-         vmStats->swapOutRate, vmStats->ioInRate, vmStats->ioOutRate,
-         vmStats->memInactive, vmStats->memActive, vmStats->hugePagesTotal,
-         vmStats->hugePagesFree);
 }
 
 
@@ -194,16 +185,6 @@ GuestInfoMonitorReadMeminfo(GuestMemInfo *vmStats)   // OUT: filled vmstats
       }
    }
    fclose(fp);
-
-   Debug("GuestInfoMonitorReadMeminfo: GuestMemInfo: total: %"FMT64"u free: %"FMT64"u"\
-         "buff: %"FMT64"u cache: %"FMT64"u swapin: %"FMT64"u swapout: %"FMT64"u ioin:"\
-         "%"FMT64"u ioout: %"FMT64"u inactive: %"FMT64"u active: %"FMT64"u"\
-         "hugetotal: %"FMT64"u hugefree: %"FMT64"u\n", vmStats->memTotal,
-         vmStats->memFree, vmStats->memBuff, vmStats->memCache, vmStats->swapInRate,
-         vmStats->swapOutRate, vmStats->ioInRate, vmStats->ioOutRate,
-         vmStats->memInactive, vmStats->memActive, vmStats->hugePagesTotal,
-         vmStats->hugePagesFree);
-
    return TRUE;
 }
 #endif
index 8540cf0bded37b7ca31bac9e79496ac58515bdb6..f5397024852a23ee8fa42db88a259b439ed2eaff 100644 (file)
@@ -66,6 +66,7 @@ typedef struct PowerOpState {
    GPid                 pid;
 #endif
    ToolsAppCtx         *ctx;
+   gboolean             scriptEnabled[GUESTOS_STATECHANGE_LAST];
 } PowerOpState;
 
 
@@ -95,6 +96,51 @@ PowerOpsCapabilityCb(gpointer src,
 }
 
 
+/**
+ * Handles power ops-related options.
+ *
+ * @param[in]  src      The source object.
+ * @param[in]  ctx      The app context.
+ * @param[in]  option   Option being set.
+ * @param[in]  value    Option value.
+ * @param[in]  plugin   Plugin registration data.
+ *
+ * @return TRUE on success.
+ */
+
+static gboolean
+PowerOpsSetOption(gpointer src,
+                  ToolsAppCtx *ctx,
+                  const gchar *option,
+                  const gchar *value,
+                  ToolsPluginData *plugin)
+{
+   gboolean enabled;
+   PowerOpState *state = plugin->_private;
+
+   if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
+      return FALSE;
+   }
+
+   enabled = (strcmp(value, "1") == 0);
+
+   if (strcmp(option, TOOLSOPTION_SCRIPTS_POWERON) == 0) {
+      state->scriptEnabled[GUESTOS_STATECHANGE_POWERON] = enabled;
+   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_POWEROFF) == 0) {
+      state->scriptEnabled[GUESTOS_STATECHANGE_HALT] =
+         state->scriptEnabled[GUESTOS_STATECHANGE_REBOOT] = enabled;
+   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_SUSPEND) == 0) {
+      state->scriptEnabled[GUESTOS_STATECHANGE_SUSPEND] = enabled;
+   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_RESUME) == 0) {
+      state->scriptEnabled[GUESTOS_STATECHANGE_RESUME] = enabled;
+   } else {
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+
 /**
  * Clean up internal state on shutdown.
  *
@@ -365,6 +411,14 @@ PowerOpsStateChange(RpcInData *data)
 
          state->stateChgInProgress = stateChangeCmdTable[i].id;
 
+         /* Check for the toolScripts option. */
+         if (!state->scriptEnabled[stateChangeCmdTable[i].id]) {
+            PowerOpsStateChangeDone(state, TRUE);
+            g_debug("Script for %s not configured to run\n",
+                    stateChangeCmdTable[i].tcloCmd);
+            return RPCIN_SETRETVALS(data, "", TRUE);
+         }
+
          script = g_key_file_get_string(state->ctx->config,
                                         "powerops",
                                         stateChgConfNames[stateChangeCmdTable[i].id],
@@ -435,6 +489,7 @@ ToolsOnLoad(ToolsAppCtx *ctx)
 
    ToolsPluginSignalCb sigs[] = {
       { TOOLS_CORE_SIG_CAPABILITIES, PowerOpsCapabilityCb, NULL },
+      { TOOLS_CORE_SIG_SET_OPTION, PowerOpsSetOption, &regData },
       { TOOLS_CORE_SIG_SHUTDOWN, PowerOpsShutdown, &regData }
    };
    ToolsAppReg regs[] = {
@@ -446,16 +501,20 @@ ToolsOnLoad(ToolsAppCtx *ctx)
    state->ctx = ctx;
    state->pid = INVALID_PID;
 
+   for (i = 0; i < GUESTOS_STATECHANGE_LAST; i++) {
+      state->scriptEnabled[i] = TRUE;
+   }
+
    regs[0].data = g_array_sized_new(FALSE,
                                     TRUE,
                                     sizeof (RpcChannelCallback),
                                     ARRAYSIZE(stateChangeCmdTable));
 
    for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
-      RpcChannelCallback *cb = &g_array_index(regs[0].data, RpcChannelCallback, i);
-      cb->name = stateChangeCmdTable[i].tcloCmd;
-      cb->callback = PowerOpsStateChange;
-      cb->clientData = state;
+      RpcChannelCallback cb = { stateChangeCmdTable[i].tcloCmd,
+                                PowerOpsStateChange,
+                                state, NULL, NULL, 0 };
+      g_array_append_val(regs[0].data, cb);
    }
 
    regData.regs = VMTools_WrapArray(regs, sizeof *regs, ARRAYSIZE(regs));
index c18ab245a5e4f655b82a4dc62a33317cb5d672c1..3334752a8d2425f12c171580cca14fd34e58241d 100644 (file)
@@ -65,6 +65,45 @@ static Bool
 VmBackupEnableSync(void);
 
 
+/**
+ * Returns a string representation of the given state machine state.
+ *
+ * @param[in]  state    State of interest.
+ *
+ * @return A string representation of the state.
+ */
+
+static const char *
+VmBackupGetStateName(VmBackupMState state)
+{
+   switch (state) {
+   case VMBACKUP_MSTATE_IDLE:
+      return "IDLE";
+
+   case VMBACKUP_MSTATE_SCRIPT_FREEZE:
+      return "SCRIPT_FREEZE";
+
+   case VMBACKUP_MSTATE_SYNC_FREEZE:
+      return "SYNC_FREEZE";
+
+   case VMBACKUP_MSTATE_SYNC_THAW:
+      return "SYNC_THAW";
+
+   case VMBACKUP_MSTATE_SCRIPT_THAW:
+      return "SCRIPT_THAW";
+
+   case VMBACKUP_MSTATE_SCRIPT_ERROR:
+      return "SCRIPT_ERROR";
+
+   case VMBACKUP_MSTATE_SYNC_ERROR:
+      return "SYNC_ERROR";
+
+   default:
+      NOT_IMPLEMENTED();
+   }
+}
+
+
 /**
  * Sends a keep alive backup event to the VMX.
  *
@@ -246,7 +285,8 @@ VmBackupOnError(void)
       break;
 
    default:
-      g_error("Unexpected machine state on error: %d\n", gBackupState->machineState);
+      g_error("Unexpected machine state on error: %s\n",
+              VmBackupGetStateName(gBackupState->machineState));
    }
 
    return (gBackupState->machineState == VMBACKUP_MSTATE_IDLE);
@@ -370,7 +410,8 @@ VmBackupAsyncCallback(void *clientData)
       break;
 
    default:
-      g_error("Unexpected machine state: %d\n", gBackupState->machineState);
+      g_error("Unexpected machine state: %s\n",
+              VmBackupGetStateName(gBackupState->machineState));
    }
 
 exit:
@@ -530,6 +571,8 @@ VmBackupSnapshotDone(RpcInData *data)
    if (gBackupState == NULL) {
       return RPCIN_SETRETVALS(data, "Error: no backup in progress", FALSE);
    } else if (gBackupState->machineState != VMBACKUP_MSTATE_SYNC_FREEZE) {
+      g_warning("Error: unexpected state for snapshot done message: %s",
+                VmBackupGetStateName(gBackupState->machineState));
       return RPCIN_SETRETVALS(data,
                               "Error: unexpected state for snapshot done message.",
                               FALSE);
@@ -549,6 +592,28 @@ VmBackupSnapshotDone(RpcInData *data)
 }
 
 
+/**
+ * Prints some information about the plugin's state to the log.
+ *
+ * @param[in]  src      The source object.
+ * @param[in]  ctx      Unused.
+ * @param[in]  data     Unused.
+ */
+
+static void
+VmBackupDumpState(gpointer src,
+                  ToolsAppCtx *ctx,
+                  gpointer data)
+{
+   if (gBackupState == NULL) {
+      g_message("Backup is idle.\n");
+   } else {
+      g_message("Backup is in state: %s\n",
+                VmBackupGetStateName(gBackupState->machineState));
+   }
+}
+
+
 /**
  * Reset callback. Currently does nothing.
  *
@@ -631,6 +696,7 @@ ToolsOnLoad(ToolsAppCtx *ctx)
          { VMBACKUP_PROTOCOL_SNAPSHOT_DONE, VmBackupSnapshotDone, NULL, NULL, NULL, 0 }
       };
       ToolsPluginSignalCb sigs[] = {
+         { TOOLS_CORE_SIG_DUMP_STATE, VmBackupDumpState, NULL },
          { TOOLS_CORE_SIG_RESET, VmBackupReset, NULL },
          { TOOLS_CORE_SIG_SHUTDOWN, VmBackupShutdown, NULL },
       };
index 661e992632b87ebf3d3d7dc20627c960321919c6..3e13c818c80b10cb9fa28f699d1b1e023662aa3d 100644 (file)
@@ -16,6 +16,8 @@
 ################################################################################
 
 bin_PROGRAMS = vmtoolsd
+pamdir = $(PAM_PREFIX)/pam.d
+
 
 vmtoolsd_CPPFLAGS =
 vmtoolsd_CPPFLAGS += @VMTOOLS_CPPFLAGS@
@@ -67,3 +69,19 @@ if HAVE_ICU
 else
    vmtoolsd_LINK = $(LINK)
 endif
+
+if LINUX
+if PAMD
+if THIRTY_TWO_BIT_USERSPACE
+pam_SCRIPTS = $(top_srcdir)/scripts/linux/pam.d/vmtoolsd
+else
+pam_SCRIPTS = $(top_srcdir)/scripts/linux/pam.d/vmtoolsd-x64
+endif !THIRTY_TWO_BIT_USERSPACE
+endif PAMD
+endif LINUX
+
+install-exec-hook:
+       $(INSTALL) -d $(DESTDIR)/etc/vmware-tools
+
+uninstall-hook:
+       rm -rf $(DESTDIR)/etc/vmware-tools
index a1c74eec65361b57483352946e621feca80d818d..9b693a8ff2eb425e5422c4572ab1057ca180104a 100644 (file)
@@ -98,24 +98,27 @@ ToolsCoreIgnoreArg(const gchar *option,
 
 
 /**
- * Asks a running instance of a service to stop running.
+ * Signals a specific event in a running service instance.
  *
- * @param[in]  svcname     Name of the service to be killed.
+ * @param[in]  svcname     Name of the service to be signaled.
+ * @param[in]  evtFmt      Format string for the event name. It should expect
+ *                         a single string parameter.
  *
- * @return Whether killing the service was successful.
+ * @return Whether successfully signaled the running service.
  */
 
 static gboolean
-ToolsCoreKillService(const gchar *svcname)
+ToolsCoreSignalEvent(const gchar *svcname,
+                     const wchar_t *evtFmt)
 {
    gboolean ret = FALSE;
    gchar *msg;
    wchar_t *evt;
    HANDLE h = NULL;
 
-   g_assert(svcname != NULL);
+   ASSERT(svcname != NULL);
 
-   evt = Str_Aswprintf(NULL, QUIT_EVENT_NAME_FMT, svcname);
+   evt = Str_Aswprintf(NULL, evtFmt, svcname);
    if (evt == NULL) {
       g_printerr("Out of memory!\n");
       goto exit;
@@ -135,7 +138,7 @@ ToolsCoreKillService(const gchar *svcname)
 
 error:
    msg = g_win32_error_message(GetLastError());
-   g_printerr("Cannot open quit event: %s\n", msg);
+   g_printerr("Cannot open event: %s\n", msg);
    g_free(msg);
 
 exit:
@@ -166,6 +169,7 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
    gboolean ret = FALSE;
    gboolean version = FALSE;
 #if defined(G_PLATFORM_WIN32)
+   gboolean dumpState = FALSE;
    gboolean kill = FALSE;
 #endif
    GOptionEntry clOptions[] = {
@@ -176,6 +180,8 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
       { "cmd", '\0', 0, G_OPTION_ARG_CALLBACK, ToolsCoreRunCommand,
          N_("Sends an RPC command to the host and exits."), N_("command") },
 #if defined(G_PLATFORM_WIN32)
+      { "dump-state", 's', 0, G_OPTION_ARG_NONE, &dumpState,
+         N_("Dumps the internal state of a running service instance to the logs."), 0 },
       { "kill", 'k', 0, G_OPTION_ARG_NONE, &kill,
          N_("Stops a running instance of a tools service."), 0 },
       { "install", 'i', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, ToolsCoreIgnoreArg,
@@ -233,7 +239,10 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
 
 #if defined(G_PLATFORM_WIN32)
    if (kill) {
-      exit(ToolsCoreKillService(state->name) ? 0 : 1);
+      exit(ToolsCoreSignalEvent(state->name, QUIT_EVENT_NAME_FMT) ? 0 : 1);
+   }
+   if (dumpState) {
+      exit(ToolsCoreSignalEvent(state->name, DUMP_STATE_EVENT_NAME_FMT) ? 0 : 1);
    }
 #else
    /* If not running the "vmusr" service, ignore the blockFd parameter. */
index 9b3364d0d2ce1fa5930eefd3303a0cdb60ab6464..bb30d46926c3d507d9a98bb7221a94c66cf241f9 100644 (file)
@@ -73,6 +73,60 @@ ToolsCoreInitializeDebug(ToolsServiceState *state)
 }
 
 
+/**
+ * Reloads the config file and re-configure the logging subsystem if the
+ * log file was updated. If the config file is being loaded for the first
+ * time, try to upgrade it to the new version if an old version is
+ * detected.
+ *
+ * @param[in]  clientData  Service state.
+ *
+ * @return TRUE.
+ */
+
+static gboolean
+ToolsCoreReloadConfig(gpointer clientData)
+{
+   ToolsServiceState *state = clientData;
+   char *confFile = state->configFile;
+   gboolean loaded = TRUE;
+
+   if (confFile == NULL) {
+      confFile = VMTools_GetToolsConfFile();
+   }
+
+   if (state->ctx.config == NULL) {
+      state->ctx.config = VMTools_LoadConfig(confFile,
+                                             G_KEY_FILE_NONE,
+                                             state->mainService);
+      state->configMtime = time(NULL);
+      if (state->ctx.config == NULL) {
+         /* Couldn't load the config file. Just create an empty dictionary. */
+         state->ctx.config = g_key_file_new();
+      }
+   } else if (VMTools_ReloadConfig(confFile,
+                                   G_KEY_FILE_NONE,
+                                   &state->ctx.config,
+                                   &state->configMtime)) {
+      g_debug("Config file reloaded.\n");
+   } else {
+      loaded = FALSE;
+   }
+
+   if (loaded) {
+      VMTools_ConfigLogging(state->ctx.config);
+      if (state->log) {
+         VMTools_EnableLogging(state->log);
+      }
+   }
+
+   if (state->configFile == NULL) {
+      g_free(confFile);
+   }
+   return TRUE;
+}
+
+
 /**
  * Cleans up the main loop after it has executed. After this function
  * returns, the fields of the state object shouldn't be used anymore.
@@ -112,6 +166,70 @@ ToolsCore_Cleanup(ToolsServiceState *state)
 }
 
 
+/**
+ * Logs some information about the runtime state of the service: loaded
+ * plugins, registered GuestRPC callbacks, etc. Also fires a signal so
+ * that plugins can log their state if they want to.
+ *
+ * @param[in]  state    The service state.
+ */
+
+void
+ToolsCore_DumpState(ToolsServiceState *state)
+{
+   guint i;
+
+   g_message("VM Tools Service '%s':\n", state->name);
+   g_message("   Plugin path: %s\n", state->pluginPath);
+
+   if (state->plugins != NULL) {
+      for (i = 0; i < state->plugins->len; i++) {
+         ToolsPlugin *plugin = g_ptr_array_index(state->plugins, i);
+         GArray *regs = (plugin->data != NULL) ? plugin->data->regs : NULL;
+         guint j;
+
+         g_message("   Plugin: %s\n", plugin->data->name);
+
+         if (regs == NULL) {
+            g_message("      No registrations.\n");
+            continue;
+         }
+
+         for (j = 0; j < regs->len; j++) {
+            guint k;
+            ToolsAppReg *reg = &g_array_index(regs, ToolsAppReg, j);
+
+            switch (reg->type) {
+            case TOOLS_APP_GUESTRPC:
+               for (k = 0; k < reg->data->len; k++) {
+                  RpcChannelCallback *cb = &g_array_index(reg->data,
+                                                          RpcChannelCallback,
+                                                          k);
+                  g_message("      RPC callback: %s\n", cb->name);
+               }
+               break;
+
+            case TOOLS_APP_SIGNALS:
+               for (k = 0; k < reg->data->len; k++) {
+                  ToolsPluginSignalCb *sig = &g_array_index(reg->data,
+                                                            ToolsPluginSignalCb,
+                                                            k);
+                  g_message("      Signal callback: %s\n", sig->signame);
+               }
+               break;
+            }
+         }
+      }
+   } else {
+      g_message("   No plugins loaded.");
+   }
+
+   g_signal_emit_by_name(state->ctx.serviceObj,
+                         TOOLS_CORE_SIG_DUMP_STATE,
+                         &state->ctx);
+}
+
+
 /**
  * Returns the name of the TCLO app name. This will only return non-NULL
  * if the service is either the tools "guestd" or "userd" service.
@@ -146,33 +264,13 @@ gboolean
 ToolsCore_Setup(ToolsServiceState *state)
 {
    GMainContext *gctx;
-   char *confFile = state->configFile;
-
-   if (confFile == NULL) {
-      confFile = VMTools_GetToolsConfFile();
-   }
 
    if (!g_thread_supported()) {
       g_thread_init(NULL);
    }
 
    VMTools_SetDefaultLogDomain(state->name);
-
-   /* Load the tools config file. */
-   if (confFile != NULL) {
-      state->ctx.config = VMTools_LoadConfig(confFile,
-                                             G_KEY_FILE_NONE,
-                                             state->mainService);
-      if (state->ctx.config == NULL) {
-         /* Couldn't load the config file. Just create an empty dictionary. */
-         state->ctx.config = g_key_file_new();
-      }
-   }
-
-   VMTools_ConfigLogging(state->ctx.config);
-   if (state->log) {
-      VMTools_EnableLogging(state->log);
-   }
+   ToolsCoreReloadConfig(state);
 
    /* Initializes the app context. */
    gctx = g_main_context_default();
@@ -217,9 +315,6 @@ error:
    }
 
 exit:
-   if (state->configFile == NULL) {
-      g_free(confFile);
-   }
    return (state->ctx.mainLoop != NULL);
 }
 
@@ -235,6 +330,7 @@ exit:
 int
 ToolsCore_Run(ToolsServiceState *state)
 {
+   g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreReloadConfig, state);
 #if defined(__APPLE__)
    ToolsCore_CFRunLoop(state);
 #else
index 1d3e2964ff2f0b2743d7c76c73fd339416895e40..7dda158d0f8cf90e96d98eb19fa74259317e6ee4 100644 (file)
 #include <string.h>
 #include <unistd.h>
 #include <glib/gstdio.h>
+#include "file.h"
 #include "system.h"
 #include "unicode.h"
+#include "util.h"
 #include "vmtools.h"
 
 #if !defined(__APPLE__)
@@ -59,6 +61,24 @@ ToolsCoreSigHandler(const siginfo_t *info,
 }
 
 
+/**
+ * Handles a USR1 signal; logs the current service state.
+ *
+ * @param[in]  info     Unused.
+ * @param[in]  data     Unused.
+ *
+ * @return TRUE
+ */
+
+gboolean
+ToolsCoreSigUsrHandler(const siginfo_t *info,
+                       gpointer data)
+{
+   ToolsCore_DumpState(&gState);
+   return TRUE;
+}
+
+
 /**
  * Tools daemon entry function.
  *
@@ -72,14 +92,79 @@ int
 main(int argc,
      char *argv[])
 {
+   int i;
    int ret = EXIT_FAILURE;
+   char **argvCopy;
    GSource *src;
 
    Unicode_Init(argc, &argv, NULL);
 
-   if (!ToolsCore_ParseCommandLine(&gState, argc, argv)) {
+   /*
+    * ToolsCore_ParseCommandLine() uses g_option_context_parse(), which modifies
+    * argv. We don't want that to happen, so we make a copy of the array and
+    * use that as the argument instead.
+    */
+   argvCopy = g_malloc(argc * sizeof *argvCopy);
+   for (i = 0; i < argc; i++) {
+      argvCopy[i] = argv[i];
+   }
+
+   if (!ToolsCore_ParseCommandLine(&gState, argc, argvCopy)) {
+      g_free(argvCopy);
       goto exit;
    }
+   g_free(argvCopy);
+   argvCopy = NULL;
+
+   if (gState.pidFile != NULL) {
+#if defined(__APPLE__)
+      /*
+       * The Mac OS main loop uses CoreFoundation classes, and that does not
+       * work with fork(). So we must exec() after the fork or the daemon
+       * will crash.
+       *
+       * We at least make sure that argv[0] is an absolute path before
+       * exec'ing; but all other path arguments should have been given
+       * as absolute paths if '--background' was used, or things may not
+       * work as expected.
+       */
+      if (!g_path_is_absolute(argv[0])) {
+         char *cwd = File_Cwd(NULL);
+         char *abs = g_strdup_printf("%s%c%s", cwd, DIRSEPC, argv[0]);
+         vm_free(cwd);
+         argv[0] = abs;
+      }
+
+      /*
+       * Need to remove --background from the command line or we'll get
+       * into an infinite loop. ToolsCore_ParseCommandLine() already
+       * validated that "-b" has an argument, so it's safe to assume the
+       * data is there.
+       */
+      for (i = 1; i < argc; i++) {
+         if (strcmp(argv[i], "--background") == 0 ||
+             strcmp(argv[i], "-b") == 0) {
+            int j;
+            for (j = i + 2; j < argc; j++) {
+               argv[j - 2] = argv[j];
+            }
+            argv[j - 2] = NULL;
+            break;
+         }
+      }
+
+      if (System_Daemon(FALSE, FALSE, gState.pidFile)) {
+         execv(argv[0], argv);
+         _exit(1);
+      } else {
+         goto exit;
+      }
+#else
+      if (!System_Daemon(FALSE, FALSE, gState.pidFile)) {
+         goto exit;
+      }
+#endif
+   }
 
    if (!ToolsCore_Setup(&gState)) {
       goto exit;
@@ -105,10 +190,9 @@ main(int argc,
                             ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
    g_source_unref(src);
 
-   if (gState.pidFile != NULL &&
-       !System_Daemon(FALSE, FALSE, gState.pidFile)) {
-      goto exit;
-   }
+   src = VMTools_NewSignalSource(SIGUSR1);
+   VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src, ToolsCoreSigUsrHandler, NULL, NULL);
+   g_source_unref(src);
 
    ret = ToolsCore_Run(&gState);
 
index 46a065a8ed526d67f309425c56d56764ee69fada..cd9506faffcca7e598dd7a78825f3b8a48518c1c 100644 (file)
 #include "vmtools.h"
 
 
+#ifdef USE_APPLOADER
+static Bool (*LoadDependencies)(char *libName);
+#endif
+
+
 /**
  * Compares two strings. To be used with g_ptr_array_sort.
  *
@@ -75,10 +80,15 @@ ToolsCore_LoadPlugins(ToolsServiceState *state)
       if (state->mainService ||
           strcmp(state->name, VMTOOLS_USER_SERVICE) == 0) {
          char *instPath;
+         char *subdir = "";
+#if defined(sun) && defined(__x86_64__)
+         subdir = "/amd64";
+#endif
          instPath = GuestApp_GetInstallPath();
-         state->pluginPath = g_strdup_printf("%s%cplugins%c%s",
+         state->pluginPath = g_strdup_printf("%s%cplugins%s%c%s",
                                              instPath,
                                              DIRSEPC,
+                                             subdir,
                                              DIRSEPC,
                                              state->name);
          vm_free(instPath);
@@ -112,6 +122,24 @@ ToolsCore_LoadPlugins(ToolsServiceState *state)
    g_ptr_array_sort(plugins, ToolsCoreStrPtrCompare);
 
    state->plugins = g_ptr_array_new();
+
+#ifdef USE_APPLOADER
+   {
+      Bool ret = FALSE;
+      GModule *mainModule = g_module_open(NULL, G_MODULE_BIND_LAZY);
+      ASSERT(mainModule);
+
+      ret = g_module_symbol(mainModule, "AppLoader_LoadLibraryDependencies",
+                            (gpointer *)&LoadDependencies);
+      g_module_close(mainModule);
+
+      if (!ret) {
+         g_critical("Unable to locate library dependency loading function.\n");
+         goto exit;
+      }
+   }
+#endif
+
    for (i = 0; i < plugins->len; i++) {
       gchar *entry;
       gchar *path;
@@ -128,6 +156,13 @@ ToolsCore_LoadPlugins(ToolsServiceState *state)
          goto next;
       }
 
+#ifdef USE_APPLOADER
+      if (!LoadDependencies(path)) {
+         g_warning("Loading of library dependencies for %s failed.\n", entry);
+         goto next;
+      }
+#endif
+
       module = g_module_open(path, G_MODULE_BIND_LOCAL);
       if (module == NULL) {
          g_warning("Opening plugin '%s' failed.\n", entry);
@@ -306,4 +341,3 @@ ToolsCore_UnloadPlugins(ToolsServiceState *state)
    g_ptr_array_free(state->plugins, TRUE);
    state->plugins = NULL;
 }
-
index 1e1a9946f183c601a08f8cd6512fcad00e8cc02f..0b75b6fd2b29b7da3da470e489f62e02e53000e5 100644 (file)
@@ -116,6 +116,16 @@ ToolsCore_Service_class_init(gpointer _klass,
                 2,
                 G_TYPE_POINTER,
                 G_TYPE_BOOLEAN);
+   g_signal_new(TOOLS_CORE_SIG_DUMP_STATE,
+                G_OBJECT_CLASS_TYPE(klass),
+                G_SIGNAL_RUN_LAST,
+                0,
+                NULL,
+                NULL,
+                g_cclosure_marshal_VOID__POINTER,
+                G_TYPE_NONE,
+                1,
+                G_TYPE_POINTER);
    g_signal_new(TOOLS_CORE_SIG_RESET,
                 G_OBJECT_CLASS_TYPE(klass),
                 G_SIGNAL_RUN_LAST,
index bb8408a0e44f89350f2da11211d9ed3bc108fcbd..631824f9af90dca50af323aa48a340d4db46f518 100644 (file)
 
 #include <glib-object.h>
 #include <gmodule.h>
+#include <time.h>
 #include "vmrpcdbg.h"
 #include "vmtoolsApp.h"
 
 /* Used by the Windows implementation to communicate with other processes. */
 #if defined(G_PLATFORM_WIN32)
 #  define QUIT_EVENT_NAME_FMT         L"Global\\VMwareToolsQuitEvent_%s"
+#  define DUMP_STATE_EVENT_NAME_FMT   L"Global\\VMwareToolsDumpStateEvent_%s"
 #endif
 
 /** Defines the internal data about a plugin. */
@@ -47,6 +49,7 @@ typedef struct ToolsPlugin {
 typedef struct ToolsServiceState {
    gchar         *name;
    gchar         *configFile;
+   time_t         configMtime;
    gboolean       log;
    gboolean       mainService;
    gchar         *pluginPath;
@@ -71,6 +74,9 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
 void
 ToolsCore_Cleanup(ToolsServiceState *state);
 
+void
+ToolsCore_DumpState(ToolsServiceState *state);
+
 const char *
 ToolsCore_GetTcloName(ToolsServiceState *state);
 
index daaf1f1cd16ba93114cde1f103ce7c6567bd2393..8dce4169b3edeef9e1ce17e493440d90d09fd2f6 100644 (file)
@@ -89,6 +89,8 @@ ToolsCoreCheckReset(struct RpcChannel *chan,
 static Bool
 ToolsCoreRpcCapReg(RpcInData *data)
 {
+   char *confPath = GuestApp_GetConfPath();
+   gchar *msg;
    GArray *pcaps = NULL;
    ToolsServiceState *state = data->clientData;
 
@@ -103,22 +105,34 @@ ToolsCoreRpcCapReg(RpcInData *data)
       g_array_free(pcaps, TRUE);
    }
 
+   /* Tell the host the location of the conf directory. */
+   msg = g_strdup_printf("tools.capability.guest_conf_directory %s", confPath);
+   if (!RpcChannel_Send(state->ctx.rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+      g_debug("Unable to register guest conf directory capability.\n");
+   }
+   free(msg);
+   msg = NULL;
+
    /* Send the tools version to the VMX. */
    if (state->mainService) {
+      uint32 version;
       char *result = NULL;
       size_t resultLen;
-      gboolean disableVersion;
       gchar *toolsVersion;
-      GError *err = NULL;
+
+#if defined(OPEN_VM_TOOLS)
+      version = TOOLS_VERSION_UNMANAGED;
+#else
+      gboolean disableVersion;
 
       disableVersion = g_key_file_get_boolean(state->ctx.config,
                                               "vmtools",
                                               CONFNAME_DISABLETOOLSVERSION,
-                                              &err);
-      g_clear_error(&err);
-      toolsVersion = g_strdup_printf("tools.set.version %u",
-                                     disableVersion ? TOOLS_VERSION_UNMANAGED
-                                                    : TOOLS_VERSION_CURRENT);
+                                              NULL);
+      version = disableVersion ? TOOLS_VERSION_UNMANAGED : TOOLS_VERSION_CURRENT;
+#endif
+
+      toolsVersion = g_strdup_printf("tools.set.version %u", version);
 
       if (!RpcChannel_Send(state->ctx.rpc, toolsVersion, strlen(toolsVersion) + 1,
                            &result, &resultLen)) {
@@ -128,6 +142,7 @@ ToolsCoreRpcCapReg(RpcInData *data)
       g_free(toolsVersion);
    }
 
+   free(confPath);
    return RPCIN_SETRETVALS(data, "", TRUE);
 }
 
index 69f14976f4033a9527be12570f0f82418164578b..e7df9911027ba9f143a2d353f7167ef9b3237604 100644 (file)
 
 #include <stdlib.h>
 #include <string.h>
+#include <gdk/gdkkeysyms.h>
 
 #include "toolboxGtkInt.h"
 #include "vm_assert.h"
 #include "vm_app.h"
 #include "eventManager.h"
 #include "guestApp.h"
+#if !defined(OPEN_VM_TOOLS)
+#  include "installerdb.h"
+#endif
 #include "vmcheck.h"
 #include "debug.h"
 #include "strutil.h"
@@ -108,25 +112,29 @@ GtkWidget *optionsTimeSync;
 GtkWidget *scriptsApply;
 DblLnkLst_Links *gEventQueue;
 
-void ToolsMainCleanupRpc(void);
-void ToolsMainSignalHandler(int sig);
-void ToolsMain_OnDestroy(GtkWidget *widget, gpointer data);
-void ToolsMain_YesNoBoxOnClicked(GtkButton *btn, gpointer user_data);
-void ToolsMain_OnHelp(gpointer btn, gpointer data);
-void ToolsMain_OpenHelp(const char *help);
+static void ToolsMainCleanupRpc(void);
+static void ToolsMainSignalHandler(int sig);
+static void ToolsMain_OnDestroy(GtkWidget *widget, gpointer data);
+static void ToolsMain_YesNoBoxOnClicked(GtkButton *btn, gpointer user_data);
+static void ToolsMain_OnHelp(gpointer btn, gpointer data);
+static void ToolsMain_OpenHelp(const char *help);
+static gint ToolsMain_CheckF1Help(GtkWidget *widget, GdkEventKey *event,
+                                  gpointer data);
 
-GtkWidget* ToolsMain_Create(void);
+static GtkWidget* ToolsMain_Create(void);
 
 
-Bool RpcInResetCB(RpcInData *data);
-Bool RpcInSetOptionCB(char const **result, size_t *resultLen, const char *name,
-                      const char *args, size_t argsSize, void *clientData);
-Bool RpcInCapRegCB(char const **result, size_t *resultLen, const char *name,
-                   const char *args, size_t argsSize, void *clientData);
-void RpcInErrorCB(void *clientdata, char const *status);
-gint EventQueuePump(gpointer data);
+static Bool RpcInResetCB(RpcInData *data);
+static Bool RpcInSetOptionCB(char const **result, size_t *resultLen,
+                             const char *name, const char *args,
+                             size_t argsSize, void *clientData);
+static Bool RpcInCapRegCB(char const **result, size_t *resultLen,
+                          const char *name, const char *args,
+                          size_t argsSize, void *clientData);
+static void RpcInErrorCB(void *clientdata, char const *status);
+static gint EventQueuePump(gpointer data);
 
-void ShowUsage(char const *prog);
+static void ShowUsage(char const *prog);
 
 
 /*
@@ -145,7 +153,7 @@ void ShowUsage(char const *prog);
  *-----------------------------------------------------------------------------
  */
 
-void
+static void
 ToolsMainCleanupRpc(void)
 {
    if (gRpcInCtlPanel) {
@@ -181,7 +189,8 @@ ToolsMainCleanupRpc(void)
  *-----------------------------------------------------------------------------
  */
 
-void ToolsMainSignalHandler(int sig) // IN
+static void
+ToolsMainSignalHandler(int sig) // IN
 {
    /* We want to kill the event manager before gtk_main_quit. */
    ToolsMainCleanupRpc();
@@ -205,7 +214,7 @@ void ToolsMainSignalHandler(int sig) // IN
  *-----------------------------------------------------------------------------
  */
 
-void
+static void
 ToolsMain_OpenHelp(const char *help) // IN
 {
    char helpPage[1000];
@@ -252,7 +261,7 @@ ToolsMain_OpenHelp(const char *help) // IN
  *-----------------------------------------------------------------------------
  */
 
-void
+static void
 ToolsMain_OnHelp(gpointer btn,  // IN: Unused
                  gpointer data) // IN: notebook containing all tabs
 {
@@ -280,6 +289,37 @@ ToolsMain_OnHelp(gpointer btn,  // IN: Unused
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ToolsMain_CheckF1Help --
+ *
+ *      Snooper function to detect F1 key press and display appropriate help
+ *      page to the user.
+ *
+ * Results:
+ *      TRUE if user pressed F1.
+ *      FALSE if user pressed any other key and it should be processed further.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static gint
+ToolsMain_CheckF1Help(GtkWidget *widget,    // IN: Unused
+                      GdkEventKey *event,   // IN: event that was snooped
+                      gpointer data)        // IN: notebook containing all tabs
+{
+   if (event->type != GDK_KEY_PRESS || event->keyval != GDK_F1) {
+      return FALSE; /* pass event further */
+   }
+
+   ToolsMain_OnHelp(NULL, data);
+   return TRUE;
+}
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -427,7 +467,7 @@ ToolsMain_YesNoBox(gchar *title, gchar *msg)
  *-----------------------------------------------------------------------------
  */
 
-void
+static void
 ToolsMain_YesNoBoxOnClicked(GtkButton *btn,     // IN: clicked button
                            gpointer user_data) // OUT: pointer to result value
 {
@@ -461,7 +501,7 @@ ToolsMain_YesNoBoxOnClicked(GtkButton *btn,     // IN: clicked button
  *-----------------------------------------------------------------------------
  */
 
-void
+static void
 ToolsMain_OnDestroy(GtkWidget *widget, // IN: Unused
                     gpointer data)     // IN: Unused
 {
@@ -496,7 +536,7 @@ ToolsMain_OnDestroy(GtkWidget *widget, // IN: Unused
  *-----------------------------------------------------------------------------
  */
 
-gint
+static gint
 EventQueuePump(gpointer data) // IN: Unused
 {
    int ret;
@@ -533,7 +573,7 @@ EventQueuePump(gpointer data) // IN: Unused
  *-----------------------------------------------------------------------------
  */
 
-GtkWidget*
+static GtkWidget*
 ToolsMain_Create(void)
 {
    GtkWidget *ToolsMain;
@@ -639,6 +679,9 @@ ToolsMain_Create(void)
 #else
    btn = gtk_button_new_with_label("Close");
 #endif
+
+   gtk_key_snooper_install(ToolsMain_CheckF1Help, notebookMain);
+
    gtk_widget_show(btn);
    gtk_box_pack_start(GTK_BOX(hbox), btn, FALSE, FALSE, 0);
    gtk_signal_connect_object(GTK_OBJECT(btn), "clicked",
@@ -667,7 +710,7 @@ ToolsMain_Create(void)
  *-----------------------------------------------------------------------------
  */
 
-Bool
+static Bool
 RpcInResetCB(RpcInData *data) // IN/OUT
 {
    Debug("----------toolbox: Received 'reset' from vmware\n");
@@ -692,7 +735,7 @@ RpcInResetCB(RpcInData *data) // IN/OUT
  *-----------------------------------------------------------------------------
  */
 
-void
+static void
 RpcInErrorCB(void *clientdata, char const *status)
 {
    Warning("Error in the RPC recieve loop: %s\n", status);
@@ -720,7 +763,7 @@ RpcInErrorCB(void *clientdata, char const *status)
  *-----------------------------------------------------------------------------
  */
 
-Bool
+static Bool
 RpcInSetOptionCB(char const **result,     // OUT
                  size_t *resultLen,       // OUT
                  const char *name,        // IN
@@ -812,7 +855,7 @@ RpcInSetOptionCB(char const **result,     // OUT
  *-----------------------------------------------------------------------------
  */
 
-Bool
+static Bool
 RpcInCapRegCB(char const **result,     // OUT
               size_t *resultLen,       // OUT
               const char *name,        // IN
@@ -882,8 +925,8 @@ OnViewportSizeRequest(GtkWidget *widget,           // IN
  *
  * InitHelpDir --
  *
- *      Queries the Tools config dictionary for the location of the Toolbox
- *      Help docs.  If not found, will try to fall back to semi-safe defaults.
+ *      Queries the location db for the location of the Toolbox Help docs.
+ *      If not found, will try to fall back to semi-safe defaults.
  *
  * Results:
  *      None.
@@ -895,14 +938,27 @@ OnViewportSizeRequest(GtkWidget *widget,           // IN
  *-----------------------------------------------------------------------------
  */
 
-void
-InitHelpDir(GKeyFile *pConfDict) // IN
+static void
+InitHelpDir(void)
 {
    gchar *tmpDir = NULL;
 
    ASSERT(hlpDir == NULL);
 
-   tmpDir = g_key_file_get_string(pConfDict, "toolbox", CONFNAME_HELPDIR, NULL);
+   /*
+    * XXX: open-vm-tools doesn't have an installer db, nor does it have help
+    * files yet IIRC.
+    */
+#if !defined(OPEN_VM_TOOLS)
+   if (InstallerDB_Init("/etc/vmware-tools", TRUE)) {
+      const char *libdir = InstallerDB_GetLibDir();
+      if (libdir != NULL) {
+         tmpDir = g_strdup_printf("%s/hlp", libdir);
+      }
+      InstallerDB_DeInit();
+   }
+#endif
+
    if (!tmpDir || !File_Exists(tmpDir)) {
       unsigned int i;
 
@@ -941,7 +997,7 @@ InitHelpDir(GKeyFile *pConfDict) // IN
  *-----------------------------------------------------------------------------
  */
 
-void
+static void
 ShowUsage(char const *prog)
 {
    fprintf(stderr,
@@ -1004,7 +1060,7 @@ main(int argc,                  // IN: ARRAY_SIZEOF(argv)
    Debug_EnableToFile(g_key_file_get_string(pConfDict, "logging",
                                             CONFNAME_LOGFILE, NULL),
                       FALSE);
-   InitHelpDir(pConfDict);
+   InitHelpDir();
    g_key_file_free(pConfDict);
 
    optionAutoHide = FALSE;
index 29ac2bdf26d5a04a23f54e0f32a54670099c583c..9b15d6620e6bc964780c2685892d679565b9ca17 100644 (file)
@@ -62,7 +62,6 @@ void OnViewportSizeRequest(GtkWidget *widget, GtkRequisition *requisition,
 
 Bool ToolsMain_YesNoBox(gchar* title, gchar *msg);
 void ToolsMain_MsgBox(gchar* title, gchar *msg);
-void ToolsMain_OnDestroy(GtkWidget *widget, gpointer data);
 
 GtkWidget* About_Create(GtkWidget* mainWnd);
 GtkWidget* Devices_Create(GtkWidget* mainWnd);
index d0a7470cffc7b981c443b249ba1d323936eaa985..04e0faa5f490e1ebb56cc117024cd63de4978c8f 100644 (file)
@@ -567,12 +567,11 @@ Scripts_OnEdit(gpointer btn,  // IN: unused
    editor = Posix_Getenv("EDITOR");
    if (editor == NULL || strlen(editor) == 0) {
       Debug("EDITOR not set, defaulting to vi.\n");
-      free(editor);
       editor = g_find_program_in_path("vi");
       if (editor == NULL) {
          ToolsMain_MsgBox("Error",
                           "Cannot edit script because the an editor was not found.");
-         goto exit;
+         return;
       } else {
          /*
           * Make sure "editor" is allocated with malloc(), so that the call to
@@ -582,6 +581,13 @@ Scripts_OnEdit(gpointer btn,  // IN: unused
          editor = Util_SafeStrdup(tmp);
          g_free(tmp);
       }
+   } else {
+      /*
+       * Strings retuned by Posix_Getenv should not be freed
+       * so we make a duplicate that can be freed so we can
+       * have a common code path below.
+       */
+      editor = Util_SafeStrdup(editor);
    }
 
    scriptName = gtk_entry_get_text(GTK_ENTRY(scriptsPath));
@@ -602,7 +608,6 @@ Scripts_OnEdit(gpointer btn,  // IN: unused
       g_free(msg);
    }
 
-exit:
    free(editor);
 }
 
index 814386bffe67dd53a10b74f545c5a974d5128d96..e36a10f993becb1c7bbe8f536ca26c6e273fa7b5 100644 (file)
@@ -117,7 +117,7 @@ vmware_user_SOURCES += copyPaste.c
 if HAVE_GTKMM
    vmware_user_SOURCES += copyPasteUI.cpp
 endif
-vmware_user_SOURCES += copyPasteWrapper.cpp
+vmware_user_SOURCES += copyPasteDnDWrapper.cpp
 vmware_user_SOURCES += debugStdio.c
 vmware_user_SOURCES += dnd.c
 vmware_user_SOURCES += foreignVMToolsDaemon.c
diff --git a/open-vm-tools/vmware-user/copyPaste.cpp b/open-vm-tools/vmware-user/copyPaste.cpp
deleted file mode 100644 (file)
index 75ba686..0000000
+++ /dev/null
@@ -1,2088 +0,0 @@
-/*********************************************************
- * Copyright (C) 2005 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.
- *
- *********************************************************/
-
-/*
- * copyPaste.c --
- *
- *    Set of functions in guest side for copy/paste (both file and text).
- *    Currently there are 2 versions copy/paste. Version 1 only supports
- *    text copy/paste, and based on backdoor cmd. Version 2 supports both
- *    text and file copy/paste, and based on guestRPC.
- *
- *    G->H Text Copy/Paste (version 1)
- *    --------------------
- *    When Ungrab, CopyPaste_RequestSelection got called, which try to get
- *    selection text and send to backdoor.
- *
- *    H->G Text Copy/Paste (version 1)
- *    --------------------
- *    When grab, CopyPaste_GetBackdoorSelections got called, which first
- *    get host selection text, then claim as selection owner. If some app
- *    asks for selection, CopyPasteSelectionGetCB will reply with host
- *    selection text.
- *
- *    G->H Copy/Paste (version 2)
- *    --------------------
- *    When Ungrab, host vmx will send out rpc command "copypaste.gh.data.get",
- *    which handler is CopyPasteRpcInGHSetDataCB. It first tries to get selection
- *    contents and sends it back as rpc result. For file transfer, host vmx
- *    will transfer files with hgFileCopy lib. Function CopyPasteGHFileListGetNext
- *    will handle the file list during transfer.
- *
- *    H->G Copy/Paste (version 2)
- *    --------------------
- *    When grab, host vmx will send host selection content to guest with
- *    out rpc command "copypaste.hg.data.set", which handler is
- *    CopyPasteRpcInHGSetDataCB. It first keeps a copy then claim as selection
- *    owner. If some app asks for files, CopyPasteSelectionGetCB will ask host
- *    vmx to transfer files into a temp dir with rpc "copypaste.hgCopyFiles",
- *    then reply with host selection file list. For KDE and gnome the file list
- *    format is different. If someapp asks for text, CopyPasteSelectionGetCB
- *    will provide the data.
- */
-
-#include "vmwareuserInt.h"
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "vm_assert.h"
-#include "debug.h"
-#include "str.h"
-#include "strutil.h"
-#include "vm_app.h"
-#include "eventManager.h"
-#include "guestApp.h"
-#include "dnd.h"
-#include "util.h"
-#include "cpName.h"
-#include "cpNameUtil.h"
-#include "guestInfoServer.h"
-#include "vmblock.h"
-#include "file.h"
-#include "codeset.h"
-#include "escape.h"
-#include "hostinfo.h"
-#include "wiper.h"
-
-
-/*
- * Gtk 1.2 doesn't know about the CLIPBOARD selection, but that doesn't matter, we
- * just create the atom we need directly in main().
- */
-#ifndef GDK_SELECTION_CLIPBOARD
-GdkAtom GDK_SELECTION_CLIPBOARD;
-#endif
-
-#ifndef GDK_SELECTION_TYPE_TIMESTAMP
-GdkAtom GDK_SELECTION_TYPE_TIMESTAMP;
-#endif
-
-#ifndef GDK_SELECTION_TYPE_UTF8_STRING
-GdkAtom GDK_SELECTION_TYPE_UTF8_STRING;
-#endif
-
-typedef struct FCPGHState {
-   char *fileList;
-   char *fileListNext;
-   size_t fileListSize;
-} FCPGHState;
-
-/*
- * Currently there are 2 versions copy/paste.
- * Key points in copy/paste version 1:
- * 1. Only text copy/paste
- * 2. copy/paste is based on backdoor directly
- *
- * Key points in copy/paste version 2:
- * 1. Support both file/text copy/paste
- * 2. Both file/text copy/paste are based on guestRPC
- */
-static int32 gVmxCopyPasteVersion = 1;
-
-/*
- * Getting a selection is an asyncronous event, so we have to keep track of both
- * selections globablly in order to decide which one to use.
- */
-static Bool gWaitingOnGuestSelection = FALSE;
-static char gGuestSelPrimaryBuf[MAX_SELECTION_BUFFER_LENGTH];
-static char gGuestSelClipboardBuf[MAX_SELECTION_BUFFER_LENGTH];
-static uint64 gGuestSelPrimaryTime = 0;
-static uint64 gGuestSelClipboardTime = 0;
-static char gHostClipboardBuf[MAX_SELECTION_BUFFER_LENGTH];
-
-/* Guest->Host state. */
-FCPGHState gFcpGHState;
-/* RPC buffer for Guest->Host FCP. */
-static char *gGHFCPRpcResultBuffer;
-/* File list size for Guest->Host FCP. */
-static size_t gGHFCPListSize;
-static Bool gHGFCPPending;
-/* Current selection is text or file list (for FCP). */
-static Bool gHGIsClipboardFCP;
-/* 
- * Total file size in selection list. This is used to check if there is enough
- * space in guest OS for host->guest file transfer.
- */
-static uint64 gHGFCPTotalSize;
-
-static GdkAtom gFCPAtom[NR_FCP_TARGETS];
-
-/* Host->guest file transfer status, used for sync between transfer and paste. */
-int gHGFCPFileTransferStatus;
-
-static char gFileRoot[DND_MAX_PATH];
-static size_t gFileRootSize;
-static Bool gIsOwner;
-static VmTimeType gHGGetListTime;
-
-/*
- * Forward Declarations
- */
-static INLINE void CopyPasteStateInit(void);
-static void CopyPasteSelectionReceivedCB(GtkWidget *widget,
-                                         GtkSelectionData *selection_data,
-                                         gpointer data);
-static void CopyPasteSelectionGetCB(GtkWidget *widget,
-                                    GtkSelectionData *selection_data,
-                                    guint info,
-                                    guint time_stamp,
-                                    gpointer data);
-static gint CopyPasteSelectionClearCB(GtkWidget *widget,
-                                      GdkEventSelection *event,
-                                      gpointer data);
-
-static void CopyPasteSetBackdoorSelections(void);
-static Bool CopyPasteRpcInGHSetDataCB(char const **result, size_t *resultLen,
-                                      const char *name, const char *args,
-                                      size_t argsSize,void *clientData);
-static Bool CopyPasteRpcInHGSetDataCB(char const **result, size_t *resultLen,
-                                      const char *name, const char *args,
-                                      size_t argsSize,void *clientData);
-
-static INLINE void CopyPasteGHFileListClear(void);
-static INLINE void CopyPasteGHFileListSet(char *fileList, size_t fileListSize);
-
-/* This struct is only used by CopyPasteSelectionRemoveTarget. */
-struct SelectionTargetList {
-  GdkAtom selection;
-  GtkTargetList *list;
-};
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteSelectionRemoveTarget --
- *
- *      To remove a target from a selection target list. The reason to develop
- *      this function is that in gtk there is only gtk_selection_add_target to
- *      add supported target to selection list, but no function to remove one.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      If no more target, the selection list will be removed too.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-CopyPasteSelectionRemoveTarget(GtkWidget *widget,
-                               GdkAtom selection,
-                               GdkAtom target)
-{
-   const char *selection_handler_key = "gtk-selection-handlers";
-   struct SelectionTargetList *targetList;
-   GList *tempList;
-   GList *selectionLists;
-
-   /* Get selection list. */
-   selectionLists = gtk_object_get_data(GTK_OBJECT (widget), selection_handler_key);
-   tempList = selectionLists;
-   while (tempList) {
-      /* Enumerate the list to find the selection. */
-      targetList = tempList->data;
-      if (targetList->selection == selection) {
-         /* Remove target. */
-         gtk_target_list_remove(targetList->list, target);
-         /* If no more target, remove selection from list. */
-         if (!targetList->list->list) {
-            /* Free target list. */
-            gtk_target_list_unref(targetList->list);
-            g_free(targetList);
-            /* Remove and free selection node. */
-            selectionLists = g_list_remove_link(selectionLists, tempList);
-            g_list_free_1(tempList);
-         }
-         break;
-      }
-      tempList = tempList->next;
-   }
-   /* Put new selection list back. */
-   gtk_object_set_data (GTK_OBJECT (widget), selection_handler_key, selectionLists);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPaste_RequestSelection --
- *
- *      Request the guest's text clipboard (asynchronously), we'll give it to 
- *      the host when the request completes. For version 1 guest->host text
- *      copy/paste.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      The owner of the clipboard will get a request from our application.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-CopyPaste_RequestSelection(void)
-{
-   if (gVmxCopyPasteVersion > 1) {
-      return;
-   }
-
-   /*
-    * Ask for both the PRIMARY and CLIPBOARD selections.
-    */
-   gGuestSelPrimaryBuf[0] = '\0';
-   gGuestSelClipboardBuf[0] = '\0';
-
-   /* Only send out request if we are not the owner. */
-   if (!gIsOwner) {
-      /* Try to get utf8 text from primary and clipboard. */
-      gWaitingOnGuestSelection = TRUE;
-      gtk_selection_convert(gUserMainWidget,
-                            GDK_SELECTION_PRIMARY,
-                            GDK_SELECTION_TYPE_UTF8_STRING,
-                            GDK_CURRENT_TIME);
-      while (gWaitingOnGuestSelection) gtk_main_iteration();
-
-      gWaitingOnGuestSelection = TRUE;
-      gtk_selection_convert(gUserMainWidget,
-                            GDK_SELECTION_CLIPBOARD,
-                            GDK_SELECTION_TYPE_UTF8_STRING,
-                            GDK_CURRENT_TIME);
-      while (gWaitingOnGuestSelection) gtk_main_iteration();
-
-      if (gGuestSelPrimaryBuf[0] == '\0' && gGuestSelClipboardBuf[0] == '\0') {
-         /*
-          * If we cannot get utf8 text, try to get localized text from primary
-          * and clipboard.
-          */
-         gWaitingOnGuestSelection = TRUE;
-         gtk_selection_convert(gUserMainWidget,
-                               GDK_SELECTION_PRIMARY,
-                               GDK_SELECTION_TYPE_STRING,
-                               GDK_CURRENT_TIME);
-         while (gWaitingOnGuestSelection) gtk_main_iteration();
-
-         gWaitingOnGuestSelection = TRUE;
-         gtk_selection_convert(gUserMainWidget,
-                               GDK_SELECTION_CLIPBOARD,
-                               GDK_SELECTION_TYPE_STRING,
-                               GDK_CURRENT_TIME);
-         while (gWaitingOnGuestSelection) gtk_main_iteration();
-      }
-   }
-   /* Send text to host. */
-   Debug("CopyPaste_RequestSelection: Prim is [%s], Clip is [%s]\n",
-         gGuestSelPrimaryBuf, gGuestSelClipboardBuf);
-   CopyPasteSetBackdoorSelections();
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteSelectionReceivedCB --
- *
- *      Callback for the gtk signal "selection_recieved".
- *      Called because we previously requested a copy/paste selection and
- *      finally got results of that asynchronous operation. After some basic
- *      sanity checks, send the result (in selection_data) thru the backdoor 
- *      (version 1) or guestRPC (version 2) so the vmx can copy it to host
- *      clipboard.
- *
- *      We made several requests for selections, the string (actual data) and
- *      file list for each of PRIMARY and CLIPBOARD selections. So this funtion
- *      will get called several times, once for each request.
- *
- *      For guest->host copy/paste (both text and file).
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-CopyPasteSelectionReceivedCB(GtkWidget *widget,                // IN: unused
-                             GtkSelectionData *selection_data, // IN: requested data
-                             gpointer data)                    // IN: unused
-{
-   char *target;
-   char *utf8Str = NULL;
-   size_t len;
-   size_t aligned_len;
-
-   if ((widget == NULL) || (selection_data == NULL)) {
-      Debug("CopyPasteSelectionReceivedCB: Error, widget or selection_data is invalid\n");
-      goto exit;
-   }
-
-   if (selection_data->length < 0) {
-      Debug("CopyPasteSelectionReceivedCB: Error, length less than 0\n");
-      goto exit;
-   }
-
-   /* Try to get clipboard or selection timestamp. */
-   if (selection_data->target == GDK_SELECTION_TYPE_TIMESTAMP) {
-      if (selection_data->selection == GDK_SELECTION_PRIMARY) {
-         if (selection_data->length == 4) {
-            gGuestSelPrimaryTime = *(uint32 *)selection_data->data;
-            Debug("CopyPasteSelectionReceivedCB: Got pri time [%"FMT64"u]\n",
-                  gGuestSelPrimaryTime);
-         } else if (selection_data->length == 8) {
-            gGuestSelPrimaryTime = *(uint64 *)selection_data->data;
-            Debug("CopyPasteSelectionReceivedCB: Got pri time [%"FMT64"u]\n",
-                  gGuestSelPrimaryTime);
-         } else {
-            Debug("CopyPasteSelectionReceivedCB: Unknown pri time. Size %d\n",
-                  selection_data->length);
-         }
-      }
-      if (selection_data->selection == GDK_SELECTION_CLIPBOARD) {
-         if (selection_data->length == 4) {
-            gGuestSelClipboardTime = *(uint32 *)selection_data->data;
-            Debug("CopyPasteSelectionReceivedCB: Got clip time [%"FMT64"u]\n",
-                  gGuestSelClipboardTime);
-         } else if (selection_data->length == 8) {
-            gGuestSelClipboardTime = *(uint64 *)selection_data->data;
-            Debug("CopyPasteSelectionReceivedCB: Got clip time [%"FMT64"u]\n",
-                  gGuestSelClipboardTime);
-         } else {
-            Debug("CopyPasteSelectionReceivedCB: Unknown clip time. Size %d\n",
-                  selection_data->length);
-         }
-      }
-      goto exit;
-   }
-
-   if (selection_data->selection == GDK_SELECTION_PRIMARY) {
-      target = gGuestSelPrimaryBuf;
-   } else if (selection_data->selection == GDK_SELECTION_CLIPBOARD) {
-      target = gGuestSelClipboardBuf;
-   } else {
-      goto exit;
-   }
-
-   utf8Str = selection_data->data;
-   len = strlen(selection_data->data);
-
-   if (selection_data->target != GDK_SELECTION_TYPE_STRING &&
-       selection_data->target != GDK_SELECTION_TYPE_UTF8_STRING) {
-      /* It is a file list. */
-      if (len >= MAX_SELECTION_BUFFER_LENGTH - 1) {
-         Warning("CopyPasteSelectionReceivedCB file list too long\n");
-      } else {
-         memcpy(target, selection_data->data, len + 1);
-      }
-      goto exit;
-   }
-
-   /*
-    * If target is GDK_SELECTION_TYPE_STRING, assume encoding is local code
-    * set. Convert to utf8 before send to vmx.
-    */
-   if (selection_data->target == GDK_SELECTION_TYPE_STRING &&
-       !CodeSet_CurrentToUtf8(selection_data->data,
-                              selection_data->length,
-                              &utf8Str,
-                              &len)) {
-      Debug("CopyPasteSelectionReceivedCB: Couldn't convert to utf8 code set\n");
-      gWaitingOnGuestSelection = FALSE;
-      return;
-   }
-
-   /*
-    * String in backdoor communication is 4 bytes by 4 bytes, so the len
-    * should be aligned to 4;
-    */
-   aligned_len = (len + 4) & ~3;
-   if (aligned_len >= MAX_SELECTION_BUFFER_LENGTH) {
-      /* With alignment, len is still possible to be less than max. */
-      if (len < (MAX_SELECTION_BUFFER_LENGTH - 1)) {
-         memcpy(target, utf8Str, len + 1);
-      } else {
-         memcpy(target, utf8Str, MAX_SELECTION_BUFFER_LENGTH - 1);
-         target[MAX_SELECTION_BUFFER_LENGTH - 1] ='\0';
-      }
-   } else {
-      memcpy(target, utf8Str, len + 1);
-   }
-
-exit:
-   if (selection_data->target == GDK_SELECTION_TYPE_STRING) {
-      free(utf8Str);
-   }
-   gWaitingOnGuestSelection = FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteSelectionGetCB --
- *
- *      Callback for the gtk signal "selection_get".
- *      This is called when some other app requests the copy/paste selection,
- *      probably because we declare oursleves the selection owner on mouse
- *      grab. In text copy/paste case, we simply respond with contents of 
- *      gHostClipboardBuf, which should have been set on mouse grab. In file
- *      copy/paste case, send file transfer request to host vmx, then return
- *      file list with right format according to different request.
- *      For host->guest copy/paste (both text and file).
- *
- * Results:
- *      None
- *
- * Side effects:
- *      An X message is sent to the requesting app containing the data, it
- *      will likely act on it in some way. In FCP case, may first start a 
- *      host->guest file transfer. Add block if blocking driver is available,
- *      otherwise wait till file copy done.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-CopyPasteSelectionGetCB(GtkWidget        *widget,         // IN: unused
-                        GtkSelectionData *selection_data, // IN: requested type
-                                                          // OUT:the data to be sent
-                        guint            info,            // IN: unused
-                        guint            time_stamp,      // IN: unsued
-                        gpointer         data)            // IN: unused
-{
-   const char *begin = NULL;
-   const char *end = NULL;
-   const char *next = NULL;
-   const char *pre = NULL;
-   const char *post = NULL;
-   size_t preLen = 0;
-   size_t postLen = 0;
-   size_t len = 0;
-   char *text = NULL;
-   size_t textLen = 1;
-   Bool blockAdded = FALSE;
-   Bool gnomeFCP = FALSE;
-   VmTimeType curTime;
-
-   if ((widget == NULL) || (selection_data == NULL)) {
-      Debug("CopyPasteSelectionGetCB: Error, widget or selection_data is invalid\n");
-      return;
-   }
-
-   /* If it is text copy paste, return gHostClipboardBuf. */
-   if (GDK_SELECTION_TYPE_STRING == selection_data->target ||
-       GDK_SELECTION_TYPE_UTF8_STRING == selection_data->target) {
-      char *outBuf = gHostClipboardBuf;
-      size_t len = strlen(gHostClipboardBuf);
-
-      /*
-       * If target is GDK_SELECTION_TYPE_STRING, assume encoding is local code
-       * set. Convert from utf8 to local one.
-       */
-      if (GDK_SELECTION_TYPE_STRING == selection_data->target &&
-          !CodeSet_Utf8ToCurrent(gHostClipboardBuf,
-                                 strlen(gHostClipboardBuf),
-                                 &outBuf,
-                                 &len)) {
-         Debug("CopyPasteSelectionGetCB: can not convert to current codeset\n");
-         return;
-      }
-
-      gtk_selection_data_set(selection_data, selection_data->target, 8,
-                             outBuf, len);
-      Debug("CopyPasteSelectionGetCB: Set text [%s]\n", outBuf);
-
-      if (GDK_SELECTION_TYPE_STRING == selection_data->target) {
-         free(outBuf);
-      }
-
-      return;
-   }
-   
-   if (selection_data->target != gFCPAtom[FCP_TARGET_INFO_URI_LIST] &&
-       selection_data->target != gFCPAtom[FCP_TARGET_INFO_GNOME_COPIED_FILES]) {
-      Debug("CopyPasteSelectionGetCB: Got unknown target\n");
-      return;
-   }
-
-   if (!gHGIsClipboardFCP) {
-      Debug("CopyPasteSelectionGetCB: no file list available\n");
-      return;
-   }
-
-   /*
-    * KDE may ask for clipboard content right after clipboard owner changed,
-    * and cause unexpected HG file copy. So HG FCP will return nothing for 1
-    * second after switch from host OS to guest OS. Please refer to bug 301971.
-    */
-   Hostinfo_GetTimeOfDay(&curTime);
-   if (curTime - gHGGetListTime < FCP_COPY_DELAY) {
-      Debug("%s: waiting for delay\n", __FUNCTION__);
-      return;
-   }
-
-   if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFER_NOT_YET) {
-      if (GuestInfo_GetAvailableDiskSpace(gFileRoot) < gHGFCPTotalSize) {
-         Debug("CopyPasteSelectionGetCB no enough space to copy file from host.\n");
-         return;
-      }
-      /* Send host a rpc to start file transfer. */
-      if (!GuestApp_RpcSendOneCPName("copypaste.hg.copy.files", ' ',
-                                     gFileRoot, gFileRootSize)) {
-         Debug("CopyPasteSelectionGetCB: failed sending copypaste.hg.copy.files "
-               "with CPName");
-         return;
-      }
-      gHGFCPFileTransferStatus = FCP_FILE_TRANSFERRING;
-   }
-
-   if (gBlockFd > 0) {
-      /* Add a block on the staging directory for this command. */
-      if (DnD_AddBlock(gBlockFd, gFileRoot)) {
-         Debug("CopyPasteSelectionGetCB: add block [%s].\n", gFileRoot);
-         blockAdded = TRUE;
-      } else {
-         Warning("CopyPasteSelectionGetCB: Unable to add block [%s].\n", gFileRoot);
-      }
-   }
-   
-   if (!blockAdded) {
-      /*
-       * If there is no blocking driver, wait here till file copy is done.
-       * 2 reasons to keep this:
-       * 1. If run vmware-user stand-alone as non-root, blocking driver can not
-       *    be opened. Debug purpose only.
-       * 2. Other platforms (Solaris, FreeBSD, etc) may also use this code, and there
-       *    is no blocking driver yet.
-       */
-      Debug("CopyPasteSelectionGetCB no blocking driver, waiting for "
-            "HG file copy done ...\n");
-      while (gHGFCPFileTransferStatus != FCP_FILE_TRANSFERRED) {
-         struct timeval tv;
-         int nr;
-
-         tv.tv_sec = 0;
-         nr = EventManager_ProcessNext(gEventQueue, (uint64 *)&tv.tv_usec);
-         if (nr != 1) {
-            Debug("CopyPasteSelectionGetCB unexpected end of loop: returned "
-                  "value is %d.\n", nr);
-            return;
-         }
-         if (select(0, NULL, NULL, NULL, &tv) == -1) {
-            Debug("CopyPasteSelectionGetCB error in select (%s).\n", 
-                  strerror(errno));
-            return;         
-         }
-      }
-
-      Debug("CopyPasteSelectionGetCB file transfer done!\n");
-   }
-
-   /* Setup the format string components */
-   if (selection_data->target == gFCPAtom[FCP_TARGET_INFO_URI_LIST]) {
-      Debug("CopyPasteSelectionGetCB Got uri_list request!\n");
-      pre = DND_URI_LIST_PRE_KDE;
-      preLen = sizeof DND_URI_LIST_PRE_KDE - 1;
-      post = DND_URI_LIST_POST;
-      postLen = sizeof DND_URI_LIST_POST - 1;
-   }
-   if (selection_data->target == gFCPAtom[FCP_TARGET_INFO_GNOME_COPIED_FILES]) {
-      Debug("CopyPasteSelectionGetCB Got gnome_copied request!\n");
-      pre = FCP_GNOME_LIST_PRE;
-      preLen = sizeof FCP_GNOME_LIST_PRE - 1;
-      post = FCP_GNOME_LIST_POST;
-      postLen = sizeof FCP_GNOME_LIST_POST - 1;
-      gnomeFCP = TRUE;
-
-      textLen += 5;
-      text = Util_SafeRealloc(text, textLen);
-      Str_Snprintf(text, 6, "copy\n");
-   }
-
-   if (!pre) {
-      Debug("CopyPasteSelectionGetCB: invalid drag target info\n");
-      return;
-   }
-
-
-   /*
-    * Set begin to first non-NUL character and end to last NUL character to
-    * prevent errors in calling CPName_GetComponent().
-    */
-   for(begin = gHostClipboardBuf; *begin == '\0'; begin++)
-      ;
-   end = CPNameUtil_Strrchr(gHostClipboardBuf, gGHFCPListSize + 1, '\0');
-   ASSERT(end);
-
-   /* Build up selection data */
-   while ((len = CPName_GetComponent(begin, end, &next)) != 0) {
-      const size_t origTextLen = textLen;
-      Bool freeBegin = FALSE;
-
-      if (len < 0) {
-         Debug("CopyPasteSelectionGetCB: error getting next component\n");
-         if (text) {
-            free(text);
-         }
-         return;
-      }
-
-      /*
-       * A URI list will expect the provided path to be escaped.  If we cannot
-       * escape the path for some reason we just use the unescaped version and
-       * hope that it works.
-       */
-      if (selection_data->target == gFCPAtom[FCP_TARGET_INFO_URI_LIST]) {
-         size_t newLen;
-         char *escapedComponent;
-         int escIndex;
-         int bytesToEsc[256] = { 0, };
-
-         /* We escape the following characters based on RFC 1630. */
-         bytesToEsc['#'] = 1;
-         bytesToEsc['?'] = 1;
-         bytesToEsc['*'] = 1;
-         bytesToEsc['!'] = 1;
-         bytesToEsc['%'] = 1;  /* Escape character */
-
-         /* Escape non-ASCII characters so we can pass UTF-8 filenames */
-         for (escIndex = 0x80; escIndex < 0x100; escIndex++) {
-            bytesToEsc[escIndex] = 1;
-         }
-
-         escapedComponent = Escape_Do('%', bytesToEsc, begin, len, &newLen);
-         if (escapedComponent) {
-            begin = escapedComponent;
-            len = newLen;
-            freeBegin = TRUE;
-         }
-      }
-
-      /*
-       * Append component.  NUL terminator was accounted for by initializing
-       * textLen to one above.
-       */
-      textLen += preLen + len + postLen;
-      text = Util_SafeRealloc(text, textLen);
-
-      /* 
-       * Bug 143147: Gnome FCP does not like the trailing newlines. We don't
-       * have this problem for targets that ask for URI lists. So we don't see
-       * this problem on:
-       * - KDE which asks for URI lists during FCP
-       * - DnD in both Gnome and KDE since they ask for URI lists.
-       *
-       * This is a problem only for Gnome FCP which expects a specially
-       * formatted 'copy' command string containing the file list which it then
-       * converts into a URI list internally.
-       */
-      Str_Snprintf(text + origTextLen - 1,
-                   textLen - origTextLen + 1,
-                   "%s%s%s", pre, begin, gnomeFCP && next == end ? "" : post);
-
-      if (freeBegin) {
-         free((void *)begin);
-      }
-
-      /* Iterate to next component */
-      begin = next;
-   }
-
-   /*
-    * Send out the data using the selection system. When sending a string, GTK will
-    * ensure that a null terminating byte is added to the end so we do not need to
-    * add it. GTK also copies the data so the original will never be modified.
-    */
-   Debug("CopyPasteSelectionGetCB: set file list [%s]\n", text);
-   gtk_selection_data_set(selection_data, selection_data->target,
-                          8, /* 8 bits per character. */
-                          text, textLen);
-   free(text);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteSelectionClearCB --
- *
- *      Callback for the gtk signal "selection_clear".
- *
- * Results:
- *      Always TRUE.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static gint
-CopyPasteSelectionClearCB(GtkWidget          *widget,         // IN: unused
-                          GdkEventSelection  *event,          // IN: unused
-                          gpointer           data)            // IN: unused
-{
-   Debug("CopyPasteSelectionClearCB got clear signal\n");
-   gIsOwner = FALSE;
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteSetBackdoorSelections --
- *
- *      Set the clipboard one of two ways, the old way or the new way.
- *      The old way uses GuestApp_SetSel and there's only one selection.
- *      Set backdoor selection with either primary selection or clipboard.
- *      The primary selection is the first priority, then clipboard.
- *      If both unavailable, set backdoor selection length to be 0.
- *      This will be used by older VMXs or VMXs on Windows hosts (which
- *      has only one clipboard). Doing this gives us backwards
- *      compatibility.
- *
- *      The new way uses new sets both PRIMARY and CLIPBOARD. Newer Linux
- *      VMXs will use these rather than the above method and have the two
- *      selections set separately.
- *
- *      XXX: The "new way" doesn't exist yet, the vmx has no support for it.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      The VMX probably changes some string buffers.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-CopyPasteSetBackdoorSelections(void)
-{
-   uint32 const *p;
-   size_t len;
-   size_t aligned_len;
-   size_t primaryLen;
-   size_t clipboardLen;
-   unsigned int i;
-
-   primaryLen = strlen(gGuestSelPrimaryBuf);
-   clipboardLen = strlen(gGuestSelClipboardBuf);
-
-   if (primaryLen) {
-      /*
-       * Send primary selection to backdoor if it exists.
-       */
-      p = (uint32 const *)gGuestSelPrimaryBuf;
-   } else if (clipboardLen) {
-      /*
-       * Otherwise send clipboard to backdoor if it exists.
-       */
-      p = (uint32 const *)gGuestSelClipboardBuf;
-   } else {
-      /*
-       * Neither selection is set
-       */
-      p = NULL;
-   }
-
-   if (p == NULL) {
-      GuestApp_SetSelLength(0);
-      Debug("CopyPasteSetBackdoorSelections Set empty text.\n");
-   } else {
-      len = strlen((char *)p);
-      Debug("CopyPasteSetBackdoorSelections Set text [%s].\n", (char *)p);
-      aligned_len = (len + 4) & ~3;
-
-      /* Here long string should already be truncated. */
-      ASSERT(aligned_len <= MAX_SELECTION_BUFFER_LENGTH);
-
-      GuestApp_SetSelLength(len);
-      for (i = 0; i < len; i += 4, p++) {
-         GuestApp_SetNextPiece(*p);
-      }
-   }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPaste_GetBackdoorSelections --
- *
- *      Get the clipboard "the old way".
- *      The old way uses GuestApp_SetSel and there's only one selection.
- *      We don't have to do anything for the "new way", since the host
- *      will just push PRIMARY and/or CLIPBOARD when they are available
- *      on the host.
- *
- *      XXX: the "new way" isn't availble yet because the vmx doesn't
- *           implement separate clipboards. Even when it does this
- *           function will still exist for backward compatibility
- *
- * Results:
- *      TRUE if selection length>=0, FLASE otherwise.
- *
- * Side effects:
- *      This application becomes the selection owner for PRIMARY and/or
-        CLIPBOARD selections.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-CopyPaste_GetBackdoorSelections(void)
-{
-   int selLength;
-   int iAtom;
-
-   if (gVmxCopyPasteVersion > 1) {
-      return TRUE;
-   }
-
-   selLength = GuestApp_GetHostSelectionLen();
-   if (selLength < 0) {
-      return FALSE;
-   } else if (selLength > 0) {
-      memset(gHostClipboardBuf, 0, sizeof (gHostClipboardBuf));
-      GuestApp_GetHostSelection(selLength, gHostClipboardBuf);
-      Debug("CopyPaste_GetBackdoorSelections Get text [%s].\n", gHostClipboardBuf);
-      gtk_selection_owner_set(gUserMainWidget,
-                              GDK_SELECTION_CLIPBOARD,
-                              GDK_CURRENT_TIME);
-      gtk_selection_owner_set(gUserMainWidget,
-                              GDK_SELECTION_PRIMARY,
-                              GDK_CURRENT_TIME);
-      gIsOwner = TRUE;
-      gHGIsClipboardFCP = FALSE;
-      for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
-         CopyPasteSelectionRemoveTarget(gUserMainWidget,
-                                        GDK_SELECTION_PRIMARY,
-                                        gFCPAtom[iAtom]);
-         CopyPasteSelectionRemoveTarget(gUserMainWidget,
-                                        GDK_SELECTION_CLIPBOARD,
-                                        gFCPAtom[iAtom]);
-      }
-   }
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteRpcInGHSetDataCB --
- *
- *    Handler function for the "copypaste.gh.data.get" RPC command. Host is
- *    asking for clipboard contents for guest->host copy/paste. If both primary
- *    selection and clipboard are empty, the empty list should also be sent back
- *    because Host should release clipboard owner.
- *
- *    For Guest->Host copy/paste operations only.
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    The owner of the clipboard will get requests from our application.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-CopyPasteRpcInGHSetDataCB(char const **result,  // OUT
-                          size_t *resultLen,    // OUT
-                          const char *name,     // IN
-                          const char *args,     // IN
-                          size_t argsSize,      // Ignored
-                          void *clientData)     // Ignored
-{
-   int iAtom;
-   GdkAtom activeSelection = GDK_SELECTION_PRIMARY;
-   char *source = gGuestSelPrimaryBuf;
-   char format[256];
-   char *rpcBody = NULL;
-   size_t rpcBodySize = 0;
-
-   gGuestSelPrimaryBuf[0] = '\0';
-   gGuestSelClipboardBuf[0] = '\0';
-
-   if (gIsOwner) {
-      Debug("CopyPasteRpcInGHSetDataCB Send empty buf to host\n");
-      return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-   }
-
-   /* First check which one is newer, primary selection or clipboard. */
-   gGuestSelPrimaryTime = 0;
-   gGuestSelClipboardTime = 0;
-
-   gWaitingOnGuestSelection = TRUE;
-   gtk_selection_convert(gUserMainWidget,
-                         GDK_SELECTION_PRIMARY,
-                         GDK_SELECTION_TYPE_TIMESTAMP,
-                         GDK_CURRENT_TIME);
-   while (gWaitingOnGuestSelection) gtk_main_iteration();
-
-   gWaitingOnGuestSelection = TRUE;
-   gtk_selection_convert(gUserMainWidget,
-                         GDK_SELECTION_CLIPBOARD,
-                         GDK_SELECTION_TYPE_TIMESTAMP,
-                         GDK_CURRENT_TIME);
-   while (gWaitingOnGuestSelection) gtk_main_iteration();
-
-   if (gGuestSelPrimaryTime < gGuestSelClipboardTime) {
-      activeSelection = GDK_SELECTION_CLIPBOARD;
-      source = gGuestSelClipboardBuf;
-   }
-
-try_again:
-   /* Check if it is file list in the active selection. */
-   for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
-      gWaitingOnGuestSelection = TRUE;
-      gtk_selection_convert(gUserMainWidget,
-                            activeSelection,
-                            gFCPAtom[iAtom],
-                            GDK_CURRENT_TIME);
-      while (gWaitingOnGuestSelection) gtk_main_iteration();
-      if (source[0] != '\0') {
-         if (gVmxCopyPasteVersion < 2) {
-            /* Only vmx version greater than 2 support file copy/paste. */
-            Debug("CopyPasteRpcInGHSetDataCB invalid operation\n");
-            return RpcIn_SetRetVals(result, resultLen,
-                                    "invalid operation", FALSE);
-         }
-         break;
-      }
-   }
-
-   if (source[0] != '\0') {
-      char *currName;
-      size_t currSize;
-      size_t index = 0;
-      char *ghFileList = NULL;
-      size_t ghFileListSize = 0;
-
-      /*
-       * In gnome, before file list there may be a extra line indicating it
-       * is a copy or cut.
-       */
-      if (strncmp(source, "copy", 4) == 0) {
-         source += 4;
-      }
-      if (strncmp(source, "cut", 3) == 0) {
-         source += 3;
-      }
-
-      while (*source == '\n' || *source == '\r' || *source == ' ') {
-         source++;
-      }
-
-      /*
-       * Get the the full filenames and last components from the URI list.  The
-       * body of the RPC message will be these last components delimited with
-       * NUL characters; the Guest->Host file list will be the full paths
-       * delimited by NUL characters.
-       */
-      while ((currName = DnD_UriListGetNextFile(source,
-                                                &index,
-                                                &currSize))) {
-         size_t lastComponentSize;
-         char *lastComponentStart;
-
-         /* Append current filename to Guest->Host list */
-         ghFileList = Util_SafeRealloc(ghFileList,
-                                       ghFileListSize + currSize + 1);
-         memcpy(ghFileList + ghFileListSize, currName, currSize);
-         ghFileListSize += currSize;
-         ghFileList[ghFileListSize] = '\0';
-         ghFileListSize++;
-
-         /* Append last component to RPC body */
-         lastComponentStart = CPNameUtil_Strrchr(currName, currSize, DIRSEPC);
-         if (!lastComponentStart) {
-            /*
-             * This shouldn't happen since filenames are absolute, but handle
-             * it as if the file name is the last component
-             */
-            lastComponentStart = currName;
-         } else {
-            /* Skip the last directory separator */
-            lastComponentStart++;
-         }
-
-         lastComponentSize = currName + currSize - lastComponentStart;
-         rpcBody = Util_SafeRealloc(rpcBody, rpcBodySize + lastComponentSize + 1);
-         memcpy(rpcBody + rpcBodySize, lastComponentStart, lastComponentSize);
-         rpcBodySize += lastComponentSize;
-         rpcBody[rpcBodySize] = '\0';
-         rpcBodySize++;
-
-         free(currName);
-      }
-
-      if (!ghFileList || !rpcBody) {
-         Warning("CopyPasteRpcInGHSetDataCB: no filenames retrieved "
-                 "from URI list\n");
-         free(ghFileList);
-         free(rpcBody);
-         return RpcIn_SetRetVals(result, resultLen,
-                                 "error retrieving file name", FALSE);
-      }
-
-      /* Set the list of full paths */
-      CopyPasteGHFileListSet(ghFileList, ghFileListSize);
-
-      /* rpcBody (and its size) will always contain a trailing NUL character */
-      rpcBodySize--;
-      Debug("CopyPasteRpcInGHSetDataCB: Sending: [%s] (%zu)\n",
-            CPName_Print(rpcBody, rpcBodySize), rpcBodySize);
-
-      Str_Sprintf(format, sizeof format, "%d ", CPFORMAT_FILELIST);
-      *resultLen = rpcBodySize + strlen(format);
-
-      free(gGHFCPRpcResultBuffer);
-      gGHFCPRpcResultBuffer = Util_SafeCalloc(1, rpcBodySize + strlen(format));
-
-      memcpy(gGHFCPRpcResultBuffer, format, strlen(format));
-      memcpy(gGHFCPRpcResultBuffer + strlen(format), rpcBody, rpcBodySize);
-      free(rpcBody);
-      *result = gGHFCPRpcResultBuffer;
-      return TRUE;
-   } else {
-      /* Try to get utf8 text from active selection. */
-      gWaitingOnGuestSelection = TRUE;
-      gtk_selection_convert(gUserMainWidget,
-                            activeSelection,
-                            GDK_SELECTION_TYPE_UTF8_STRING,
-                            GDK_CURRENT_TIME);
-      while (gWaitingOnGuestSelection) gtk_main_iteration();
-
-      if (source[0] == '\0') {
-         /* Try to get text from active selection. */
-         gWaitingOnGuestSelection = TRUE;
-         gtk_selection_convert(gUserMainWidget,
-                              activeSelection,
-                              GDK_SELECTION_TYPE_STRING,
-                              GDK_CURRENT_TIME);
-         while (gWaitingOnGuestSelection) gtk_main_iteration();
-      }
-
-      /*
-       * With 'cut' operation OpenOffice will put data into clipboard but
-       * set same timestamp for both clipboard and primary selection.
-       * If primary timestamp is same as clipboard timestamp, we should try
-       * clipboard again if primary selection is empty. For details please
-       * refer to bug 300780.
-       */
-      if (source[0] == '\0' &&
-          gGuestSelPrimaryTime == gGuestSelClipboardTime &&
-          gGuestSelPrimaryTime != 0) {
-         gGuestSelPrimaryTime = 0;
-         gGuestSelClipboardTime = 0;
-         activeSelection = GDK_SELECTION_CLIPBOARD;
-         source = gGuestSelClipboardBuf;
-         goto try_again;
-      }
-
-      if (source[0] != '\0') {
-         free(gGHFCPRpcResultBuffer);
-
-         gGHFCPRpcResultBuffer =
-            Str_Asprintf(NULL, "%d %s", CPFORMAT_TEXT, source);
-
-         if (!gGHFCPRpcResultBuffer) {
-            Debug("CopyPasteRpcInGHSetDataCB failed to alloc memory.\n");
-            return RpcIn_SetRetVals(result, resultLen,
-                                    "error allocating memory", FALSE);
-         }
-
-         *result = gGHFCPRpcResultBuffer;
-         *resultLen = strlen(gGHFCPRpcResultBuffer);
-
-         Debug("CopyPasteRpcInGHSetDataCB creating text: %s\n", source);
-
-         return TRUE;
-      }
-      /* Neither file list nor text is available, send empty list back. */
-      Debug("CopyPasteRpcInGHSetDataCB Send empty buf to host\n");
-      return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-   }
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPasteRpcInGHFinishCB --
- *
- *    For Guest->Host operations only.
- *
- *    Invoked when host side of copyPaste operation has finished.
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-CopyPasteRpcInGHFinishCB(char const **result,      // OUT
-                         size_t *resultLen,        // OUT
-                         const char *name,         // IN
-                         const char *args,         // IN
-                         size_t argsSize,          // Ignored
-                         void *clientData)         // IN
-{
-   char *effect = NULL;
-   unsigned int index = 0;
-
-   gFcpGHState.fileListNext = gFcpGHState.fileList;
-
-   effect = StrUtil_GetNextToken(&index, args, " ");
-   if (!effect) {
-      Warning("CopyPasteRpcInGHFinishCB: no drop effect provided\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "drop effect not provided", FALSE);
-   }
-
-   Debug("CopyPasteRpcInGHFinishCB got effect %s\n", effect);
-
-   free(effect);
-   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPasteGHFileListClear --
- *
- *    Clears existing Guest->Host file list, releasing any used resources.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-CopyPasteGHFileListClear(void)
-{
-   Debug("CopyPasteGHFileListClear: clearing G->H file list\n");
-   if (gFcpGHState.fileList) {
-      free(gFcpGHState.fileList);
-      gFcpGHState.fileList = NULL;
-   }
-   gFcpGHState.fileListSize = 0;
-   gFcpGHState.fileListNext = NULL;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPasteGHFileListSet --
- *
- *    Sets the Guest->Host file list that is accessed through
- *    CopyPasteGHFileListGetNext().
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    Clears the existing Guest->Host file list if it exists.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-CopyPasteGHFileListSet(char *fileList,      // IN: new Guest->Host file list
-                       size_t fileListSize) // IN: size of the provided list
-{
-   CopyPasteGHFileListClear();
-   gFcpGHState.fileList = fileList;
-   gFcpGHState.fileListSize = fileListSize;
-   gFcpGHState.fileListNext = fileList;
-
-   Debug("CopyPasteGHFileListSet: [%s] (%"FMTSZ"u)\n",
-         CPName_Print(gFcpGHState.fileList, gFcpGHState.fileListSize),
-         gFcpGHState.fileListSize);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPasteGHFileListGetNext --
- *
- *    Retrieves the next file in the Guest->Host file list.
- *
- *    Note that this function may only be called after calling
- *    CopyPasteGHFileListSet() and before calling CopyPasteGHFileListClear().
- *
- * Results:
- *    TRUE on success, FALSE on failure.  If TRUE is returned, fileName is
- *    given a pointer to the filename's location or NULL if there are no more
- *    files, and fileNameSize is given the length of fileName.
- *
- * Side effects:
- *    The fileListNext value of the Guest->Host global state is updated.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-CopyPasteGHFileListGetNext(char **fileName,       // OUT: fill with filename location
-                           size_t *fileNameSize)  // OUT: fill with filename length
-{
-   char const *end;
-   char const *next;
-   int len;
-
-   ASSERT(gFcpGHState.fileList);
-   ASSERT(gFcpGHState.fileListNext);
-   ASSERT(gFcpGHState.fileListSize > 0);
-
-   /* Ensure end is the last NUL character */
-   end = CPNameUtil_Strrchr(gFcpGHState.fileList,
-                            gFcpGHState.fileListSize,
-                            '\0');
-   ASSERT(end);
-
-   /* Get the length of this filename and a pointer to the next one */
-   len = CPName_GetComponent(gFcpGHState.fileListNext, end, &next);
-   if (len < 0) {
-      Warning("CopyPasteGHFileListGetNext: error retrieving next component\n");
-      return FALSE;
-   }
-
-   /* No more entries in the list */
-   if (len == 0) {
-      Debug("CopyPasteGHFileListGetNext: no more entries\n");
-      *fileName = NULL;
-      *fileNameSize = 0;
-      gFcpGHState.fileListNext = gFcpGHState.fileList;
-      return TRUE;
-   }
-
-   Debug("CopyPasteGHFileListGetNext: returning [%s] (%d)\n",
-         gFcpGHState.fileListNext, len);
-
-   *fileName = gFcpGHState.fileListNext;
-   *fileNameSize = len;
-   gFcpGHState.fileListNext = (char *)next;
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteHGSetData --
- *
- *    Host is sending text for copy/paste.
- *
- *    RPC command format:
- *    1. Format
- *    2. Size of text
- *    3. If text size > 0, then followed by text, otherwise nothing
- *
- *    For Host->Guest operations only.
- *
- * Results:
- *    TRUE on success, FALSE otherwise.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-CopyPasteHGSetData(char const **result,     // OUT
-                   size_t *resultLen,       // OUT
-                   const char *args)        // IN
-{
-   char *format = NULL;
-   char *sSize = NULL;
-   uint32 textSize;
-   unsigned int index = 0;
-   Bool ret = FALSE;
-   int iAtom;
-
-   /* Parse value string. */
-   format = StrUtil_GetNextToken(&index, args, " ");
-   index++; /* Ignore leading space before data. */
-   sSize = StrUtil_GetNextToken(&index, args, " ");
-   index++;
-   if (!format || !sSize) {
-      Debug("CopyPasteHGSetData failed to parse format & size\n");
-      ret = RpcIn_SetRetVals(result, resultLen,
-                             "format and size is not completed", FALSE);
-      goto exit;
-   }
-
-   textSize = atoi(sSize);
-   gHostClipboardBuf[0] = '\0';
-
-   if (textSize > 0) {
-      if (textSize >= MAX_SELECTION_BUFFER_LENGTH) {
-         textSize = MAX_SELECTION_BUFFER_LENGTH - 1;
-      }
-      memcpy(gHostClipboardBuf, args + index, textSize);
-      gHostClipboardBuf[textSize] = '\0';
-      Debug("CopyPasteHGSetData: Set text [%s]\n", gHostClipboardBuf);
-   }
-      
-   gtk_selection_owner_set(gUserMainWidget,
-                           GDK_SELECTION_CLIPBOARD,
-                           GDK_CURRENT_TIME);
-   gtk_selection_owner_set(gUserMainWidget,
-                           GDK_SELECTION_PRIMARY,
-                           GDK_CURRENT_TIME);
-   gIsOwner = TRUE;
-   gHGIsClipboardFCP = FALSE;
-
-   /* We put text into selection, so remove file target types from list. */
-   for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
-      CopyPasteSelectionRemoveTarget(gUserMainWidget,
-                                     GDK_SELECTION_PRIMARY,
-                                     gFCPAtom[iAtom]);
-      CopyPasteSelectionRemoveTarget(gUserMainWidget,
-                                     GDK_SELECTION_CLIPBOARD,
-                                     gFCPAtom[iAtom]);
-   }
-
-   ret = RpcIn_SetRetVals(result, resultLen, "", TRUE);
-
-exit:
-   free(format);
-   free(sSize);
-   return ret;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteRpcInHGDataFinishCB --
- *
- *       For Host->Guest operations only.
- *       Host has finished transferring copyPaste data to the guest. We do any
- *       post H->G operation cleanup here, like picking a new file root.
- *
- * Results:
- *       TRUE on success, FALSE otherwise
- *
- * Side effects:
- *       Copied files will be deleted in error or cancel case.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-CopyPasteRpcInHGDataFinishCB(char const **result,   // OUT
-                             size_t *resultLen,     // OUT
-                             const char *name,      // IN
-                             const char *args,      // IN
-                             size_t argsSize,       // Ignored
-                             void *clientData)      // IN: pointer to mainWnd
-{
-   unsigned int index = 0;
-   char *state;
-
-   Debug("CopyPasteRpcInHGDataFinishCB received copypaste data finish\n");
-
-   state = StrUtil_GetNextToken(&index, args, " ");
-
-   if (!state) {
-      Debug("CopyPasteRpcInHGDataFinishCB failed to parse data state\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "must specify data finish state", FALSE);
-   }
-
-   if (strcmp(state, "success") != 0) {
-      Debug("CopyPasteRpcInHGDataFinishCB data transfer error\n");
-      /*
-       * Delete staging directory in error or cancel case, otherwise
-       * target application may still try to get copied files because
-       * the file list is provided right after adding block to staging
-       * directory.
-       */
-      File_DeleteDirectoryTree(gFileRoot);
-   }
-
-   free(state);
-
-   ASSERT(gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING);
-   gHGFCPFileTransferStatus = FCP_FILE_TRANSFERRED;
-
-   if (gBlockFd > 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
-      Warning("CopyPasteRpcInHGDataFinishCB: Unable to remove block [%s].\n",
-              gFileRoot);
-   }
-
-   /* get new root dir for next FCP operation. */
-   gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
-
-   Debug("CopyPasteRpcInHGDataFinishCB create staging dir [%s]\n", gFileRoot);
-
-   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteHGSetFileList --
- *
- *    Host is sending file list for FCP (file copy/paste).
- *
- *    RPC command format:
- *    1. Format
- *    2. Total size of all files in the list
- *    3. Size of file list string
- *    4. If list size > 0, then followed by file list, otherwise nothing
- *
- *    For Host->Guest FCP operations only.
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-CopyPasteHGSetFileList(char const **result,     // OUT
-                       size_t *resultLen,       // OUT
-                       const char *args)        // IN
-{
-   char *format = NULL;
-   char *data = NULL;
-   char *sListSize = NULL;
-   size_t listSize;
-   char *sTotalSize = NULL;
-   char *stagingDirName = NULL;
-   char mountDirName[DND_MAX_PATH];
-   unsigned int index = 0;
-   Bool ret = FALSE;
-   char *retStr;
-   int iAtom;
-
-   gHGFCPFileTransferStatus = FCP_FILE_TRANSFER_NOT_YET;
-   /* Parse value string. */
-   format = StrUtil_GetNextToken(&index, args, " ");
-   index++; /* Ignore leading space before data. */
-   sTotalSize = StrUtil_GetNextToken(&index, args, " ");
-   index++;
-   sListSize = StrUtil_GetNextToken(&index, args, " ");
-   index++;
-   if (!format || !sTotalSize || !sListSize) {
-      Debug("CopyPasteHGSetFileList failed to parse format & size\n");
-      retStr = "format or size is not completed";
-      goto exit;
-   }
-
-   listSize = atoi(sListSize);
-   /* 
-    * Total file size in selection list. This is used to check if there is enough
-    * space in guest OS for host->guest file transfer.
-    */
-   gHGFCPTotalSize = atol(sTotalSize);
-
-   if (listSize <= 0) {
-      Debug("CopyPasteHGSetFileList: got empty list\n");
-      gHostClipboardBuf[0] = '\0';
-      retStr = "";
-      ret = TRUE;
-      goto exit;
-   }
-
-   /*
-    * XXX Should do code set convertion here from utf8 to current for file list,
-    * but right now should not do that. The reason is that the hgfs server
-    * always puts utf8 file name into guest, which is not right if local guest
-    * encoding is non-utf8. DnD has same problem.
-    */
-
-   data = (char *)Util_SafeCalloc(1, listSize + 1);
-   memcpy(data, args + index, listSize);
-   data[listSize] = '\0';
-
-   if (gBlockFd > 0) {
-      /*
-       * Here we take the last component of the actual file root, which is
-       * a temporary directory for this DnD operation, and append it to the
-       * mount point for vmblock.  This is where we want the target application
-       * to access the file since it will enable vmblock to block that
-       * application's progress if necessary.
-       */
-      stagingDirName = DnD_GetLastDirName(gFileRoot);
-      if (!stagingDirName) {
-         Debug("CopyPasteHGSetFileList: error construct stagingDirName\n");
-         retStr = "error construct stagingDirName";
-         goto exit;
-      }
-      if (sizeof VMBLOCK_MOUNT_POINT - 1 +
-          (sizeof DIRSEPS - 1) * 2 + strlen(stagingDirName) >= sizeof mountDirName) {
-         Debug("CopyPasteHGSetFileList: directory name too large.\n");
-         retStr = "directory name too large";
-         goto exit;
-      }
-      Str_Sprintf(mountDirName, sizeof mountDirName,
-                  VMBLOCK_MOUNT_POINT DIRSEPS"%s"DIRSEPS, stagingDirName);
-   }
-
-   /* Add the file root to the relative paths received from host */
-   if (!DnD_PrependFileRoot(gBlockFd > 0 ? mountDirName : gFileRoot,
-                            &data, &listSize)) {
-      Debug("CopyPasteHGSetFileList: error prepending guest file root\n");
-      retStr = "error prepending file root";
-      goto exit;
-   }
-
-   if (listSize + 1 > sizeof gHostClipboardBuf) {
-      Debug("CopyPasteHGSetFileList: data too large\n");
-      retStr = "data too large";
-      goto exit;
-   }
-
-   memcpy(gHostClipboardBuf, data, listSize + 1);
-   gGHFCPListSize = listSize;
-   gHGIsClipboardFCP = TRUE;
-   Debug("CopyPasteHGSetFileList: get file list [%s] (%zu)\n",
-         CPName_Print(gHostClipboardBuf, gGHFCPListSize), gGHFCPListSize);
-
-   for (iAtom = 0; iAtom < NR_FCP_TARGETS; iAtom++) {
-      gtk_selection_add_target(gUserMainWidget, GDK_SELECTION_PRIMARY,
-                               gFCPAtom[iAtom], 0);
-      gtk_selection_add_target(gUserMainWidget, GDK_SELECTION_CLIPBOARD,
-                               gFCPAtom[iAtom], 0);
-   }
-
-   Debug("CopyPasteHGSetFileList: added targets\n");
-   gtk_selection_owner_set(gUserMainWidget,
-                           GDK_SELECTION_CLIPBOARD,
-                           GDK_CURRENT_TIME);
-   gtk_selection_owner_set(gUserMainWidget,
-                           GDK_SELECTION_PRIMARY,
-                           GDK_CURRENT_TIME);
-   gIsOwner = TRUE;
-
-   retStr = "";
-   ret = TRUE;
-
-exit:
-   free(format);
-   free(data);
-   free(sTotalSize);
-   free(sListSize);
-   free(stagingDirName);
-   Hostinfo_GetTimeOfDay(&gHGGetListTime);
-   return RpcIn_SetRetVals(result, resultLen, retStr, ret);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteRpcInHGSetDataCB --
- *
- *    Host is sending data for copy/paste. The data can be text, file list, etc.
- *
- *    For Host->Guest operations only.
- *
- * Results:
- *    TRUE if success, FALSE otherwise.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-CopyPasteRpcInHGSetDataCB(char const **result,  // OUT
-                          size_t *resultLen,    // OUT
-                          const char *name,     // IN
-                          const char *args,     // IN
-                          size_t argsSize,      // Ignored
-                          void *clientData)     // IN: ignored
-{
-   char *formatStr = NULL;
-   DND_CPFORMAT format;
-   Bool ret = FALSE;
-
-   unsigned int index = 0;
-
-   if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING) {
-      return RpcIn_SetRetVals(result, resultLen,
-                              "", TRUE);
-   }
-
-   /* Parse value string. */
-   formatStr = StrUtil_GetNextToken(&index, args, " ");
-   index++; /* Ignore leading space before data. */
-
-   if (!formatStr) {
-      Debug("CopyPasteTcloHGDataSet failed to parse format\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "format and size is not completed", FALSE);
-   }
-
-   format = (DND_CPFORMAT)atoi(formatStr);
-   free(formatStr);
-
-   switch (format) {
-   case CPFORMAT_TEXT:
-      ret = CopyPasteHGSetData(result, resultLen, args);
-      break;
-   case CPFORMAT_FILELIST:
-      /* Only vmx version greater than 2 support file copy/paste. */
-      if (gVmxCopyPasteVersion < 2) {
-         Debug("CopyPasteRpcInHGSetDataCB invalid operation\n");
-         return RpcIn_SetRetVals(result, resultLen,
-                                 "invalid operation", FALSE);
-      }
-      ret = CopyPasteHGSetFileList(result, resultLen, args);
-      break;
-   default:
-      Debug("CopyPasteTcloHGDataSet unknown format\n");
-      ret = RpcIn_SetRetVals(result, resultLen,
-                             "unknown format", FALSE);
-      break;
-   }
-
-   return ret;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPasteRpcInGHGetNextFileCB --
- *
- *    For Guest->Host operations only.
- *
- *    Invoked when the host is compiling its list of files to copy from the
- *    guest.  Here we provide the path of the next file in our Guest->Host file
- *    list in guest path format (for display purposes) and CPName format (for
- *    file copy operation).
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    Iterator pointer within file list of GH state is iterated to next list
- *    entry (through call to CopyPasteGHFileListGetNext()).
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-CopyPasteRpcInGHGetNextFileCB(char const **result,      // OUT
-                              size_t *resultLen,        // OUT
-                              const char *name,         // IN
-                              const char *args,         // IN
-                              size_t argsSize,          // Ignored
-                              void *clientData)         // IN
-{
-   static char resultBuffer[DND_MAX_PATH];
-   char *fileName;
-   size_t fileNameSize;
-   uint32 cpNameSize;
-   Bool res;
-
-   /*
-    * Retrieve a pointer to the next filename and its size from the list stored
-    * in the G->H DnD state.  Note that fileName should not be free(3)d here
-    * since an additional copy is not allocated.
-    */
-   res = CopyPasteGHFileListGetNext(&fileName, &fileNameSize);
-
-   if (!res) {
-      Warning("CopyPasteRpcInGHGetNextFileCB: error retrieving file name\n");
-      return RpcIn_SetRetVals(result, resultLen, "error getting file", FALSE);
-   }
-
-   if (!fileName) {
-      /* There are no more files to send */
-      Debug("CopyPasteRpcInGHGetNextFileCB: reached end of Guest->Host file list\n");
-      return RpcIn_SetRetVals(result, resultLen, "|end|", TRUE);
-   }
-
-   if (fileNameSize + 1 + fileNameSize > sizeof resultBuffer) {
-      Warning("CopyPasteRpcInGHGetNextFileCB: filename too large (%"FMTSZ"u)\n", fileNameSize);
-      return RpcIn_SetRetVals(result, resultLen, "filename too large", FALSE);
-   }
-
-   /*
-    * Construct a reply message of the form:
-    * <file name in guest format><NUL><filename in CPName format>
-    */
-   memcpy(resultBuffer, fileName, fileNameSize);
-   resultBuffer[fileNameSize] = '\0';
-
-   cpNameSize = CPNameUtil_ConvertToRoot(fileName,
-                                         sizeof resultBuffer - (fileNameSize + 1),
-                                         resultBuffer + fileNameSize + 1);
-   if (cpNameSize < 0) {
-      Warning("CopyPasteRpcInGHGetNextFileCB: could not convert to CPName\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "error on CPName conversion", FALSE);
-   }
-
-   /* Set manually because RpcIn_SetRetVals() assumes no NUL characters */
-   *result = resultBuffer;
-   *resultLen = fileNameSize + 1 + cpNameSize;
-
-   Debug("CopyPasteRpcInGHGetNextFileCB: [%s] (%"FMTSZ"u)\n",
-         CPName_Print(*result, *resultLen), *resultLen);
-
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPaste_GetVmxCopyPasteVersion --
- *
- *      Ask the vmx for it's copy/paste version.
- *
- * Results:
- *      The copy/paste version the vmx supports, 1 if the vmx doesn't know
- *      what we're talking about.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-int32
-CopyPaste_GetVmxCopyPasteVersion(void)
-{
-   char *reply = NULL;
-   size_t replyLen;
-
-   if (!RpcOut_sendOne(&reply, &replyLen, "vmx.capability.copypaste_version")) {
-      Debug("CopyPaste_GetVmxCopyPasteVersion: could not get VMX copyPaste "
-            "version capability: %s\n", reply ? reply : "NULL");
-      gVmxCopyPasteVersion = 1;
-   } else {
-      gVmxCopyPasteVersion = atoi(reply);
-   }
-
-   free(reply);
-   Debug("CopyPaste_GetVmxCopyPasteVersion: got version %d\n", gVmxCopyPasteVersion);
-   return gVmxCopyPasteVersion;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPaste_RegisterCapability --
- *
- *      Register the "copypaste" capability. Sometimes this needs to be done
- *      separately from the rest of copy/paste registration, so we provide it
- *      separately here.
- *
- * Results:
- *      TRUE on success
- *      FALSE on failure
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-CopyPaste_RegisterCapability(void)
-{
-   /* Tell the VMX about the copyPaste version we support. */
-   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.copypaste_version 2")) {
-      Debug("CopyPaste_RegisterCapability: could not set guest copypaste "
-            "version capability\n");
-      gVmxCopyPasteVersion = 1;
-      return FALSE;
-   }
-   Debug("CopyPaste_RegisterCapability: set copypaste version 2\n");
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPaste_Register --
- *
- *      Setup callbacks, initialize.
- *
- * Results:
- *      Always TRUE.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-CopyPaste_Register(GtkWidget* mainWnd)
-{
-   /* Text copy/paste initialization for all versions. */
-#ifndef GDK_SELECTION_CLIPBOARD
-   GDK_SELECTION_CLIPBOARD = gdk_atom_intern("CLIPBOARD", FALSE);
-#endif
-
-#ifndef GDK_SELECTION_TYPE_TIMESTAMP
-   GDK_SELECTION_TYPE_TIMESTAMP = gdk_atom_intern("TIMESTAMP", FALSE);
-#endif
-
-#ifndef GDK_SELECTION_TYPE_UTF8_STRING
-   GDK_SELECTION_TYPE_UTF8_STRING = gdk_atom_intern("UTF8_STRING", FALSE);
-#endif
-
-   gFCPAtom[FCP_TARGET_INFO_GNOME_COPIED_FILES] = 
-      gdk_atom_intern(FCP_TARGET_NAME_GNOME_COPIED_FILES, FALSE);
-   gFCPAtom[FCP_TARGET_INFO_URI_LIST] = 
-      gdk_atom_intern(FCP_TARGET_NAME_URI_LIST, FALSE);
-
-   /* 
-    * String is always in supported list. FCP atoms will dynamically be 
-    * added and removed.
-    */
-   gtk_selection_add_target(mainWnd, GDK_SELECTION_PRIMARY,
-                            GDK_SELECTION_TYPE_STRING, 0);
-   gtk_selection_add_target(mainWnd, GDK_SELECTION_CLIPBOARD,
-                            GDK_SELECTION_TYPE_STRING, 0);
-   gtk_selection_add_target(mainWnd, GDK_SELECTION_PRIMARY,
-                            GDK_SELECTION_TYPE_UTF8_STRING, 0);
-   gtk_selection_add_target(mainWnd, GDK_SELECTION_CLIPBOARD,
-                            GDK_SELECTION_TYPE_UTF8_STRING, 0);
-
-   gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_received",
-                      GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB), mainWnd);
-   gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_get",
-                      GTK_SIGNAL_FUNC(CopyPasteSelectionGetCB), mainWnd);
-   gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_clear_event",
-                      GTK_SIGNAL_FUNC(CopyPasteSelectionClearCB), mainWnd);
-
-   RpcIn_RegisterCallback(gRpcIn, "copypaste.hg.data.set",
-                          CopyPasteRpcInHGSetDataCB, NULL);
-   RpcIn_RegisterCallback(gRpcIn, "copypaste.hg.data.finish",
-                          CopyPasteRpcInHGDataFinishCB, NULL);
-   RpcIn_RegisterCallback(gRpcIn, "copypaste.gh.data.get",
-                          CopyPasteRpcInGHSetDataCB, NULL);
-   RpcIn_RegisterCallback(gRpcIn, "copypaste.gh.get.next.file",
-                          CopyPasteRpcInGHGetNextFileCB, NULL);
-   RpcIn_RegisterCallback(gRpcIn, "copypaste.gh.finish",
-                          CopyPasteRpcInGHFinishCB, NULL);
-
-   CopyPasteStateInit();
-   Wiper_Init(NULL);
-
-   return CopyPaste_RegisterCapability();
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPaste_Unregister --
- *
- *      Cleanup copy/paste related things.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      copy/paste is stopped, the rpc channel to the vmx is closed.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-CopyPaste_Unregister(GtkWidget* mainWnd)
-{
-   gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
-                                 GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB),
-                                 mainWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
-                                 GTK_SIGNAL_FUNC(CopyPasteSelectionGetCB),
-                                 mainWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
-                                 GTK_SIGNAL_FUNC(CopyPasteSelectionClearCB),
-                                 mainWnd);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPaste_OnReset --
- *
- *    Handles reinitializing Copy Paste state on a reset.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-CopyPaste_OnReset(void)
-{
-   if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING) {
-      File_DeleteDirectoryTree(gFileRoot);
-      if (gBlockFd > 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
-         Warning("CopyPasteRpcInHGDataFinishCB: Unable to remove block [%s].\n",
-                 gFileRoot);
-      }
-      gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
-   }
-
-   CopyPasteStateInit();
-}
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPaste_InProgress --
- *
- *    Indicates whether a copy/paste data transfer is currently in progress.
- *
- * Results:
- *    TRUE if in progress, FALSE otherwise.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-CopyPaste_InProgress(void)
-{
-   /* XXX We currently have no way to determine if a G->H FCP is ongoing. */
-   return gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPaste_IsRpcCPSupported --
- *
- *    Check if RPC copy/paste is supported by vmx or not.
- *
- * Results:
- *    TRUE if RPC copy/paste is supported, FALSE otherwise.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-CopyPaste_IsRpcCPSupported(void)
-{
-   return gVmxCopyPasteVersion > 1;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * CopyPasteStateInit --
- *
- *    Initalialize CopyPaste State.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-CopyPasteStateInit(void)
-{
-   gHostClipboardBuf[0] = '\0';
-   gGuestSelPrimaryBuf[0] = '\0';
-   gGuestSelClipboardBuf[0] = '\0';
-   gIsOwner = FALSE;
-   gGHFCPRpcResultBuffer = NULL;
-   gHGFCPPending = FALSE;
-   gHGFCPFileTransferStatus = FCP_FILE_TRANSFER_NOT_YET;
-
-   if (CopyPaste_GetVmxCopyPasteVersion() >= 2) {
-      /*
-       * Create staging directory for file copy/paste. This is for vmx with version 2
-       * or greater.
-       */
-      gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
-      Debug("CopyPaste_Register create file root [%s]\n", gFileRoot);
-   }
-}
similarity index 73%
rename from open-vm-tools/vmware-user/copyPasteWrapper.cpp
rename to open-vm-tools/vmware-user/copyPasteDnDWrapper.cpp
index 61b49244803eb558f271d156901c04d05f955294..b6247d3bee0e12e305edce6a4caa41cd0abd33a9 100644 (file)
  *********************************************************/
 
 /**
- * @file copyPasteWrapper.cpp
+ * @file copyPasteDnDWrapper.cpp
  * 
  * This singleton class implements a wrapper around various versions of
  * copy and paste protocols, and provides some convenience functions that
  * help to make VMwareUser a bit cleaner. 
  */
 
-#include "copyPasteWrapper.h"
+#include "copyPasteDnDWrapper.h"
 extern "C" {
 #include "vmwareuserInt.h"
 #include "debug.h"
@@ -32,23 +32,23 @@ extern "C" {
 
 
 /**
- * CopyPasteWrapper is a singleton, here is a pointer to its only instance.
+ * CopyPasteDnDWrapper is a singleton, here is a pointer to its only instance.
  */
-CopyPasteWrapper *CopyPasteWrapper::m_instance = 0;
+CopyPasteDnDWrapper *CopyPasteDnDWrapper::m_instance = 0;
 
 /**
  *
- * Get an instance of CopyPasteWrapper, which is an application singleton.  
+ * Get an instance of CopyPasteDnDWrapper, which is an application singleton.  
  *
- * @return a pointer to the singleton CopyPasteWrapper object, or NULL if
+ * @return a pointer to the singleton CopyPasteDnDWrapper object, or NULL if
  * for some reason it could not be allocated.
  */
 
-CopyPasteWrapper *
-CopyPasteWrapper::GetInstance()
+CopyPasteDnDWrapper *
+CopyPasteDnDWrapper::GetInstance()
 {
    if (!m_instance) {
-      m_instance = new CopyPasteWrapper;
+      m_instance = new CopyPasteDnDWrapper;
    }
    return m_instance;
 }
@@ -59,7 +59,7 @@ CopyPasteWrapper::GetInstance()
  * Constructor.
  */
 
-CopyPasteWrapper::CopyPasteWrapper() :
+CopyPasteDnDWrapper::CopyPasteDnDWrapper() :
 #if defined(HAVE_GTKMM)
    m_copyPasteUI(NULL),
 #endif
@@ -75,7 +75,7 @@ CopyPasteWrapper::CopyPasteWrapper() :
  * Destructor.
  */
 
-CopyPasteWrapper::~CopyPasteWrapper()
+CopyPasteDnDWrapper::~CopyPasteDnDWrapper()
 {
    if (IsRegistered()) {
       Unregister();
@@ -95,12 +95,28 @@ CopyPasteWrapper::~CopyPasteWrapper()
  */
 
 void
-CopyPasteWrapper::SetUserData(const void *userData)
+CopyPasteDnDWrapper::SetUserData(const void *userData)
 {
+   Debug("%s: enter %lx\n", __FUNCTION__, (unsigned long) userData);
    m_userData = userData;
 }
 
 
+/**
+ *
+ * Set block fd.
+ *
+ * @param[in] blockFd blockFd specified as command line arg by VMwareUser.
+ */
+
+void
+CopyPasteDnDWrapper::SetBlockFd(int blockFd)
+{
+   Debug("%s: enter %d\n", __FUNCTION__, blockFd);
+   mBlockFd = blockFd;
+}
+
+
 /**
  *
  * Register copy and paste capabilities with the VMX. Try newest version
@@ -110,8 +126,9 @@ CopyPasteWrapper::SetUserData(const void *userData)
  */
 
 bool
-CopyPasteWrapper::Register()
+CopyPasteDnDWrapper::Register()
 {
+   Debug("%s: mBlockFd %d\n", __FUNCTION__, mBlockFd);
    if (IsRegistered()) {
       return TRUE;
    }
@@ -125,6 +142,9 @@ CopyPasteWrapper::Register()
    Debug("%s: enter\n", __FUNCTION__);
    m_copyPasteUI = new CopyPasteUI();
    if (m_copyPasteUI) {
+      Debug("%s: Setting block fd to %d\n", __FUNCTION__, mBlockFd);
+      m_copyPasteUI->SetBlockFd(mBlockFd);
+      m_copyPasteUI->Init();
       SetIsRegistered(TRUE);
       int version = GetVersion();
       Debug("%s: version is %d\n", __FUNCTION__, version);
@@ -138,8 +158,10 @@ CopyPasteWrapper::Register()
    }
 #endif
    if (!IsRegistered()) {
+      Debug("%s: Registering legacy m_userData %lx\n", __FUNCTION__, (long unsigned int) m_userData);
       SetIsRegistered(CopyPaste_Register((GtkWidget *)m_userData));
       if (IsRegistered()) {
+      Debug("%s: Registering capability\n", __FUNCTION__);
          if (!CopyPaste_RegisterCapability()) {
             Unregister();
          }
@@ -154,7 +176,7 @@ CopyPasteWrapper::Register()
  */
 
 void
-CopyPasteWrapper::Unregister()
+CopyPasteDnDWrapper::Unregister()
 {
    if (!IsRegistered()) {
       return;
@@ -182,7 +204,7 @@ CopyPasteWrapper::Unregister()
  */
 
 int
-CopyPasteWrapper::GetVersion()
+CopyPasteDnDWrapper::GetVersion()
 {
    if (IsRegistered()) {
       m_version = CopyPaste_GetVmxCopyPasteVersion();
@@ -200,7 +222,7 @@ CopyPasteWrapper::GetVersion()
  */
 
 void
-CopyPasteWrapper::SetIsRegistered(bool isRegistered)
+CopyPasteDnDWrapper::SetIsRegistered(bool isRegistered)
 {
    m_isRegistered = isRegistered;
 }
@@ -214,7 +236,7 @@ CopyPasteWrapper::SetIsRegistered(bool isRegistered)
  */
 
 bool
-CopyPasteWrapper::IsRegistered()
+CopyPasteDnDWrapper::IsRegistered()
 {
    return m_isRegistered;
 }
@@ -222,11 +244,11 @@ CopyPasteWrapper::IsRegistered()
 
 /**
  *
- * Handle reset by calling protocol dependent handlers. 
+ * Handle reset by calling protocol dependent handlers.
  */
 
 void
-CopyPasteWrapper::OnReset()
+CopyPasteDnDWrapper::OnReset()
 {
    Debug("%s: enter\n", __FUNCTION__);
    if (IsRegistered()) {
similarity index 75%
rename from open-vm-tools/vmware-user/copyPasteWrapper.h
rename to open-vm-tools/vmware-user/copyPasteDnDWrapper.h
index 95b1e3f3a6626e4aca96ff2a3f68db11e65b20b6..e0b3c52c2f4d4de8c809d74099c27b722d91fb39 100644 (file)
  *********************************************************/
 
 /**
- * @file copyPasteWrapper.h
+ * @file copyPasteDnDWrapper.h
  * 
  * This singleton class implements a wrapper around various versions of
  * copy and paste.
  *
  */
 
-#ifndef COPYPASTEWRAPPER_H
-#define COPYPASTEWRAPPER_H
+#ifndef COPYPASTEDNDWRAPPER_H
+#define COPYPASTEDNDWRAPPER_H
 
 #if defined(HAVE_GTKMM)
 #include "copyPasteUI.h"
 #endif
 
-class CopyPasteWrapper
+class CopyPasteDnDWrapper
 {
 public:
-   ~CopyPasteWrapper();
-   void SetUserData(const void *userData);
+   ~CopyPasteDnDWrapper();
+   static CopyPasteDnDWrapper *GetInstance();
    bool Register();
    void Unregister();
-   static CopyPasteWrapper *GetInstance();
    int GetVersion();
    void SetIsRegistered(bool isRegistered);
    bool IsRegistered();
    void OnReset();
+   void SetBlockFd(int blockFd);
+   void SetUserData(const void *userData);
 private:
    /*
     * We're a singleton, so it is a compile time error to call these.
     */
-   CopyPasteWrapper();
-   CopyPasteWrapper(const CopyPasteWrapper &wrapper);
-   CopyPasteWrapper& operator=(const CopyPasteWrapper &wrapper);
+   CopyPasteDnDWrapper();
+   CopyPasteDnDWrapper(const CopyPasteDnDWrapper &wrapper);
+   CopyPasteDnDWrapper& operator=(const CopyPasteDnDWrapper &wrapper);
 private:
 #if defined(HAVE_GTKMM)
    CopyPasteUI *m_copyPasteUI;
@@ -57,7 +58,8 @@ private:
    bool m_isRegistered;
    const void *m_userData;
    int m_version;
-   static CopyPasteWrapper *m_instance;
+   static CopyPasteDnDWrapper *m_instance;
+   int mBlockFd;
 };
 
-#endif // COPYPASTEWRAPPER_H
+#endif // COPYPASTEDNDWRAPPER_H
index bba97811da775bb14d843d2a8aac735b7b456040..4f0dafb5d24bec89659cd3299902a474f446809f 100644 (file)
@@ -32,6 +32,7 @@
 #include "dndFileList.hh"
 
 extern "C" {
+   #include "vmwareuserInt.h"
    #include "vmblock.h"
    #include "vm_app.h"
    #include "file.h"
@@ -42,6 +43,7 @@ extern "C" {
    #include "debug.h"
    #include "cpNameUtil.h"
    #include "rpcout.h"
+   #include "eventManager.h"
 }
 
 /*
@@ -65,8 +67,44 @@ CopyPasteUI::CopyPasteUI()
    mHGStagingDir(""),
    mIsClipboardOwner(false),
    mClipTimePrev(0),
-   mPrimTimePrev(0)
+   mPrimTimePrev(0),
+   mHGGetFilesInitiated(false),
+   mFileTransferDone(false),
+   mBlockAdded(false),
+   mBlockFd(-1),
+   mInited(false)
 {
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CopyPasteUI::Init --
+ *
+ *    Initialize copy paste UI class and register for V3 or greater copy
+ *    paste.
+ *
+ * Results:
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+CopyPasteUI::Init()
+{
+
+   if (mInited) {
+      return;
+   }
+
+   mInited = true;
+   CPClipboard_Init(&mClipboard);
+
    Gtk::TargetEntry gnome(FCP_TARGET_NAME_GNOME_COPIED_FILES);
    Gtk::TargetEntry kde(FCP_TARGET_NAME_URI_LIST);
    gnome.set_info(FCP_TARGET_INFO_GNOME_COPIED_FILES);
@@ -75,8 +113,6 @@ CopyPasteUI::CopyPasteUI()
    mListTargets.push_back(gnome);
    mListTargets.push_back(kde);
 
-   CPClipboard_Init(&mClipboard);
-
    /* Tell the VMX about the copyPaste version we support. */
    if (!RpcOut_sendOne(NULL, NULL, "tools.capability.copypaste_version 3")) {
       Debug("%s: could not set guest copypaste version capability\n",
@@ -224,8 +260,8 @@ CopyPasteUI::GetCurrentTime(void)
  *
  * CopyPasteUI::LocalGetFileRequestCB --
  *
- *      Callback from a file paste request from another host application.
- *      Begins copying the files from guest to host and return the file list.
+ *      Callback from a file paste request from another guest application.
+ *      Begins copying the files from host to guest and return the file list.
  *
  * Results:
  *      None.
@@ -243,19 +279,24 @@ CopyPasteUI::LocalGetFileRequestCB(Gtk::SelectionData& sd,        // IN:
    Debug("%s: enter.\n", __FUNCTION__);
    mHGCopiedUriList = "";
    VmTimeType curTime;
+   mBlockAdded = false;
 
    curTime = GetCurrentTime();
 
    /*
     * Some applications may ask for clipboard contents right after clipboard
-    * owner changed. So GH FCP will return nothing for some time after switch
+    * owner changed. So HG FCP will return nothing for some time after switch
     * from guest OS to host OS.
     */
    if ((curTime - mHGGetListTime) < FCP_COPY_DELAY) {
+      Debug("%s: time delta less than FCP_COPY_DELAY, returning.\n",
+            __FUNCTION__);
       return;
    }
 
    if (!mIsClipboardOwner || !mCP.IsCopyPasteAllowed()) {
+      Debug("%s: not clipboard ownder, or copy paste not allowed, returning.\n",
+            __FUNCTION__);
       return;
    }
 
@@ -263,13 +304,14 @@ CopyPasteUI::LocalGetFileRequestCB(Gtk::SelectionData& sd,        // IN:
          sd.get_target().c_str());
 
    /* Copy the files. */
-   if (!mHGGetFilesInitated) {
+   if (!mHGGetFilesInitiated) {
       utf::string str;
       utf::string hgStagingDir;
       utf::string stagingDirName;
       utf::string pre;
       utf::string post;
       size_t index = 0;
+      mFileTransferDone = false;
 
       hgStagingDir = static_cast<utf::string>(mCP.GetFiles());
       Debug("%s: Getting files. Staging dir: %s", __FUNCTION__,
@@ -279,7 +321,16 @@ CopyPasteUI::LocalGetFileRequestCB(Gtk::SelectionData& sd,        // IN:
          Debug("%s: Can not create staging directory\n", __FUNCTION__);
          return;
       }
-      mHGGetFilesInitated = true;
+      mHGGetFilesInitiated = true;
+
+      if (DnD_AddBlock(mBlockFd, hgStagingDir.c_str())) {
+         Debug("%s: add block mBlockFd %d.\n", __FUNCTION__, mBlockFd);
+         mHGStagingDir = hgStagingDir;
+         mBlockAdded = true;
+      } else {
+         Debug("%s: unable to add block fd %d dir %s.\n",
+                __FUNCTION__, mBlockFd, hgStagingDir.c_str());
+      }
 
       /* Provide URIs for each path in the guest's file list. */
       if (FCP_TARGET_INFO_GNOME_COPIED_FILES == info) {
@@ -320,6 +371,44 @@ CopyPasteUI::LocalGetFileRequestCB(Gtk::SelectionData& sd,        // IN:
       return;
    }
 
+   if (!mBlockAdded) {
+      /*
+       * If there is no blocking driver, wait here till file copy is done.
+       * 2 reasons to keep this:
+       * 1. If run vmware-user stand-alone as non-root, blocking driver can
+       *    not be opened. Debug purpose only.
+       * 2. Other platforms (Solaris, etc) may also use this code,
+       *    and there is no blocking driver yet.
+       *
+       * Polling here will not be sufficient for large files (experiments
+       * showed it was sufficient for a 256MB file, and failed for a 1GB
+       * file, but those numbers are of course context-sensitive and so YMMV).
+       * The reason is we are executing in the context of gtkmm callback, and
+       * apparently it only has so much patience regarding how quickly we
+       * return.
+       */
+      Debug("%s no blocking driver, waiting for "
+            "HG file copy done ...\n", __FUNCTION__);
+      while (mFileTransferDone == false) {
+         struct timeval tv;
+         int nr;
+
+         tv.tv_sec = 0;
+         nr = EventManager_ProcessNext(gEventQueue, (uint64 *)&tv.tv_usec);
+         if (nr != 1) {
+            Debug("%s: unexpected end of loop: returned "
+                  "value is %d.\n", __FUNCTION__, nr);
+            return;
+         }
+         if (select(0, NULL, NULL, NULL, &tv) == -1) {
+            Debug("%s: error in select (%s).\n", __FUNCTION__,
+                  strerror(errno));
+            return;
+         }
+      }
+      Debug("%s: file transfer done!\n", __FUNCTION__);
+   }
+
    Debug("%s: providing file list [%s]\n", __FUNCTION__,
          mHGCopiedUriList.c_str());
 
@@ -510,7 +599,7 @@ CopyPasteUI::LocalReceivedTargetsCB(const Glib::StringArrayHandle& targetsArray)
  * CopyPasteUI::LocalReceivedFileListCB --
  *
  *      Got clipboard or primary selection file list. Parse it and add
- *      it to the crossplaform clipboard. Send clipboard to the guest.
+ *      it to the crossplaform clipboard. Send clipboard to the host.
  *
  * Results:
  *      None.
@@ -541,7 +630,7 @@ CopyPasteUI::LocalReceivedFileListCB(const Gtk::SelectionData& sd)        // IN
  * CopyPasteUI::LocalReceivedTextCB --
  *
  *      Got clipboard (or primary selection) text, add to local clipboard
- *      cache and send clipboard to guest.
+ *      cache and send clipboard to host.
  *
  * Results:
  *      None.
@@ -595,7 +684,7 @@ CopyPasteUI::LocalReceivedTextCB(const Glib::ustring& text)        // IN
  *
  * CopyPasteUI::LocalGetSelectionFileList --
  *
- *      Contruct local file list and remote file list from selection data.
+ *      Construct local file list and remote file list from selection data.
  *      Called by both DnD and FCP.
  *
  * Results:
@@ -617,6 +706,8 @@ CopyPasteUI::LocalGetSelectionFileList(const Gtk::SelectionData& sd)      // IN
    size_t index = 0;
    DnDFileList fileList;
    DynBuf buf;
+   uint64 totalSize = 0;
+   int64 size;
 
    /*
     * Turn the uri list into two \0  delimited lists. One for full paths and
@@ -651,12 +742,26 @@ CopyPasteUI::LocalGetSelectionFileList(const Gtk::SelectionData& sd)      // IN
        */
       newRelPath = Str_Strrchr(newPath, DIRSEPC) + 1; // Point to char after '/'
 
+      /*
+       * XXX For directory, value is -1, so if there is any directory,
+       * total size is not accurate.
+       */
+      if ((size = File_GetSize(newPath)) >= 0) {
+         totalSize += size;
+      } else {
+         Debug("%s: Unable to get file size for %s\n", __FUNCTION__, newPath);
+      }
+
+      Debug("%s: Adding newPath '%s' newRelPath '%s'\n", __FUNCTION__,
+            newPath, newRelPath);
       fileList.AddFile(newPath, newRelPath);
       free(newPath);
    }
 
    DynBuf_Init(&buf);
-   fileList.ToCPClipboard(&buf, true);
+   fileList.SetFileSize(totalSize);
+   Debug("%s: totalSize is %"FMT64"u\n", __FUNCTION__, totalSize);
+   fileList.ToCPClipboard(&buf, false);
    CPClipboard_SetItem(&mClipboard, CPFORMAT_FILELIST, DynBuf_Get(&buf),
                        DynBuf_GetSize(&buf));
    DynBuf_Destroy(&buf);
@@ -794,6 +899,7 @@ CopyPasteUI::GetRemoteClipboardCB(const CPClipboard *clip) // IN
    void *buf;
    size_t sz;
 
+   Debug("%s: enter\n", __FUNCTION__);
    if (!clip) {
       Debug("%s: No clipboard contents.", __FUNCTION__);
       return;
@@ -827,49 +933,12 @@ CopyPasteUI::GetRemoteClipboardCB(const CPClipboard *clip) // IN
 
       mIsClipboardOwner = TRUE;
       mHGGetListTime = GetCurrentTime();
-      mHGGetFilesInitated = FALSE;
+      mHGGetFilesInitiated = false;
       mHGCopiedUriList = "";
    }
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * CopyPasteUI::GetLocalFiles --
- *
- *    Invoke the copy files from host to guest.
- *
- * Results:
- *    true if the request was sent. false otherwise.
- *
- * Side effects:
- *    None.
- *
- *-----------------------------------------------------------------------------
- */
-
-bool
-CopyPasteUI::GetLocalFiles(void)
-{
-   Debug("%s: enter try to start HG file copy.\n", __FUNCTION__);
-#if defined(NOT_YET)
-   ASSERT_IN_SAFE_CONTEXT(mSyncWnd);
-#endif
-
-   mHGStagingDir = mCP.GetFiles();
-
-#if defined(NOT_YET)
-   if (mHGStagingDir.empty()) {
-      mDataObject->NotifyGetFilesDone(false);
-      return false;
-   }
-   mDataObject->SetStagingDir(mHGStagingDir);
-#endif
-   return true;
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -893,20 +962,26 @@ void
 CopyPasteUI::GetLocalFilesDone(bool success)
 {
    Debug("%s: enter success %d\n", __FUNCTION__, success);
+
+   if (mBlockAdded) {
+      Debug("%s: removing block mBlockFd %d\n", __FUNCTION__, mBlockFd);
+      DnD_RemoveBlock(mBlockFd, mHGStagingDir.c_str());
+      mBlockAdded = false;
+   }
+
+   mFileTransferDone = true;
    if (success) {
       /*
        * Mark current staging dir to be deleted on next reboot for FCP. The
        * file will not be deleted after reboot if it is moved to another
-       * location by target application. 
+       * location by target application.
        */
       DnD_DeleteStagingFiles(mHGStagingDir.c_str(), TRUE);
    } else {
       /* Copied files are already removed in common layer. */
       mHGStagingDir.clear();
    }
-#if defined(NOT_YET)
-   mDataObject->NotifyGetFilesDone(success);
-#endif
+   mHGGetFilesInitiated = false;
 }
 
 
index efc3a0b0d193b767b45773176a616851a893bfd4..f6feb7927a6b6c7d58e739c7cb31c614a223f58b 100644 (file)
@@ -47,13 +47,13 @@ class CopyPasteUI : public sigc::trackable
 public:
    CopyPasteUI();
    virtual ~CopyPasteUI();
+   void Init();
    void VmxCopyPasteVersionChanged(struct RpcIn *rpcIn,
                                    uint32 version);
    void SetCopyPasteAllowed(bool isCopyPasteAllowed)
       { mCP.SetCopyPasteAllowed(isCopyPasteAllowed); }
    void Reset(void);
-   bool GetLocalFiles(void);
-
+   void SetBlockFd(int fd) {Debug("Setting mBlockFd to %d\n", fd); mBlockFd = fd;};
 private:
 
    /* hg */
@@ -81,7 +81,7 @@ private:
    // Member variables
    CopyPaste mCP;
    bool mClipboardEmpty;
-   std::string mHGStagingDir;
+   utf::string mHGStagingDir;
    std::list<Gtk::TargetEntry> mListTargets;
    bool mIsClipboardOwner;
    uint64 mClipTime;
@@ -92,10 +92,14 @@ private:
    CPClipboard mClipboard;
 
    /* File vars. */
-   bool mHGGetFilesInitated;
+   bool mHGGetFilesInitiated;
    VmTimeType mHGGetListTime;
    utf::string mHGCopiedUriList;
    utf::utf8string mHGFCPData;
+   bool mFileTransferDone;
+   bool mBlockAdded;
+   int mBlockFd;
+   bool mInited;
 };
 
 #endif // COPYPASTE_UI_H
diff --git a/open-vm-tools/vmware-user/dnd.cpp b/open-vm-tools/vmware-user/dnd.cpp
deleted file mode 100644 (file)
index 926a85f..0000000
+++ /dev/null
@@ -1,2698 +0,0 @@
-/*********************************************************
- * Copyright (C) 2005 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.
- *
- *********************************************************/
-
-/*
- * dnd.c --
- *
- *  Handles the guest side of host<->guest DnD operations.
- *
- *  Guest->Host DnD
- *  ---------------
- *
- *  The DnD process within the guest starts when we receive a "dnd.ungrab" RPC
- *  message from the host, which invokes DnDRpcInMouseUngrabCB().  The MKS
- *  sends this RPC when it sees the mouse stray outside of the clip (guest's
- *  viewable area).  RpcInMouseUngrabCB() will determine whether a DnD is
- *  pending by calling DnDDragPending():
- *   o if a DnD is not pending, it replies with a "dnd.notpending" RPC and we
- *     are done,
- *   o if a DnD is pending, we send fake X events to the X server that place
- *     our invisible window at the location of the mouse pointer and generate
- *     mouse movements over the window.
- *
- *  Faking mouse movement over our window causes Gtk to send us a "drag_motion"
- *  signal, which invokes DnDGtkDragMotionCB().  Here we find a common target
- *  (drop type) and request the data from the drag source via
- *  gtk_drag_get_data().
- *
- *  When the data is ready, Gtk signals us with a "data_received" signal.  We
- *  parse the provided data and send the file names to the host with
- *  a "dnd.data.set" RPC.  Then we start the DnD operation with a "dnd.enter"
- *  RPC.  Upon receiving the "dnd.enter", the MKS will allow the ungrab of the
- *  mouse from the guest window and the user will be able to select a location
- *  to drop the files.
- *
- *  (Note that it is important that the guest reply to the "dnd.ungrab" with
- *   either a "dnd.notpending" or a "dnd.enter" in a timely manner, since the
- *   MKS will delay mouse packets until it has received a reply from the
- *   guest.)
- *
- *  When the user drops the files, the host will send us a "dnd.data.get.file"
- *  for each file, which invokes DnDRpcInGetNextFileCB().  On each invocation,
- *  we reply with the next file from the Guest->Host file list (obtained from
- *  DnDGHFileListGetNext()), and "|end|" when there are no more files.  With
- *  this information, the host copies the files from the guest using HGFS.
- *
- *  When the host has finished copying the files, it sends us a "dnd.finish"
- *  RPC, which invokes DnDRpcInFinishCB().  At this point, we fake X events
- *  that cause a mouse button release over our window.
- *
- *  This button release causes Gtk to send us a "drag_drop" signal, which
- *  invokes DnDGtkDragDropCB().  Here we simply clean up our state and
- *  indicate that the drag finished successfully by calling gtk_drag_finish().
- *
- *  If an error occurs at any point, the host sends us a "dnd.finish cancel"
- *  RPC.  We will fake an ESC key press and release to cancel the pending DnD
- *  in the guest.
- *
- *
- *  Host->Guest DnD
- *  ---------------
- *
- *  A host->guest DnD begins with a "dnd.data.set" from the vmx to provide the
- *  list of files being dragged into the guest, then a "dnd.enter" to begin the
- *  DnD operation.  When the "dnd.enter" is received, this process will send
- *  a fake mouse button press and mouse movement on its window, starting the
- *  DnD operation within the guest.  At this point the mouse still has not been
- *  grabbed by the guest and all mouse movements go only to the host.
- *
- *  As part of the normal DnD protocol on the host, the UI in the host will
- *  receive updates on the location of the mouse within its target window.
- *  This location is translated to guest coordinates and sent to us via the
- *  "dnd.move" RPC, at which point we fake additional mouse movements to that
- *  location.  When the user releases the mouse, the host UI is again notified
- *  and sends us a "dnd.drop" RPC.
- *
- *  When the drop occurs, we add a block (via vmblock) on the directory
- *  containing the files to be given to the target application, then fake
- *  a mouse release at the location of the drop.  This will cause the target
- *  application to request the data, which we provide through our
- *  "drag_data_get" handler (DnDGtkDataRequestCB()).  When the application
- *  attempts to access these files it will be blocked by vmblock.
- *
- *  After the drop is sent, the host will send the files to the hgfs server
- *  running inside this process, and will notify us when that transfer is
- *  complete via the "dnd.data.finish" RPC.  If the transfer is successful, we
- *  remove the block to allow the target application to access the files.  If
- *  the transfer is unsuccessful, we remove any partially copied files then
- *  remove the block; this has the effect of failing the DnD operation since
- *  the target cannot access the necessary files.  Once this is done, we
- *  generate a new file root within the staging directory and send that to the
- *  host for the next DnD operation.
- *
- *  Note that we used to fake the mouse release only after the data transfer
- *  completed (and Windows guests still behave that way), but this was changed
- *  since the Linux UI was modified to allow guest interaction while the
- *  progress dialog (for the file transfer) was displayed and updating.  This
- *  caused a lot of instability since the mouse was no longer in a predictable
- *  state when the fake release was sent.  vmblock let us work around this by
- *  changing where the block occurred.
- */
-
-
-#include <string.h>
-#include <stdlib.h>
-#include <X11/extensions/XTest.h>       /* for XTest*() */
-#include <X11/keysym.h>                 /* for XK_Escape */
-#include <X11/Xatom.h>                  /* for XA_WINDOW */
-
-#include "vmwareuserInt.h"
-#include "vm_app.h"
-#include "vm_assert.h"
-#include "vm_basic_defs.h"
-#include "eventManager.h"
-#include "debug.h"
-#include "strutil.h"
-#include "str.h"
-#include "file.h"
-#include "guestApp.h"
-#include "cpName.h"
-#include "cpNameUtil.h"
-#include "dnd.h"
-#include "util.h"
-#include "hgfsVirtualDir.h"
-#include "hgfsServerPolicy.h"
-#include "vmblock.h"
-#include "escape.h"
-
-
-#define DND_MAX_PATH                    6144
-#define DRAG_TARGET_NAME_URI_LIST       "text/uri-list"
-#define DRAG_TARGET_INFO_URI_LIST       0
-#define DRAG_TARGET_NAME_TEXT_PLAIN     "text/plain"
-#define DRAG_TARGET_INFO_TEXT_PLAIN     1
-#define DRAG_TARGET_NAME_STRING         "STRING"
-#define DRAG_TARGET_INFO_STRING         2
-/*
- * We support all three drag targets from Host->Guest since we can present
- * filenames in any of these forms if an application requests.  However, we
- * only support file drag targets (text/uri-list) from Guest->Host since we
- * can only DnD files across the backdoor.
- */
-#define NR_DRAG_TARGETS                 3
-#define NR_GH_DRAG_TARGETS              1
-
-#define DROPEFFECT_NONE 0
-#define DROPEFFECT_COPY 1
-#define DROPEFFECT_MOVE 2
-#define DROPEFFECT_LINK 4
-
-/*
- * More friendly names for calling DnDFakeXEvents().  This is really ugly but
- * it allows us to keep all of the X fake event code in one place.
- *
- * Operation | showWidget | buttonEvent | buttonPress | moveWindow | coordsProvided
- * ----------+------------+-------------+-------------+------------+---------------
- * G->H Drag |    Yes     |      No     |     n/a     |    Yes     |       No
- * G->H Drop |     No     |     Yes     |   Release   |    Yes     |       No
- * H->G Drag |    Yes     |     Yes     |    Press    |    Yes     |       No
- * H->G Move |     No     |      No     |     n/a     |     No     |      Yes
- * H->G Drop |     No     |     Yes     |   Release   |     No     |      Yes
- * ----------+------------+-------------+-------------+------------+---------------
- */
-#define DnDGHFakeDrag(widget) \
-    DnDFakeXEvents(widget, TRUE, FALSE, FALSE, TRUE, FALSE, 0, 0)
-#define DnDGHFakeDrop(widget) \
-    DnDFakeXEvents(widget, FALSE, TRUE, FALSE, TRUE, FALSE, 0, 0)
-#define DnDHGFakeDrag(widget) \
-    DnDFakeXEvents(widget, TRUE, TRUE, TRUE, TRUE, FALSE, 0, 0)
-#define DnDHGFakeMove(widget, x, y) \
-    DnDFakeXEvents(widget, FALSE, FALSE, FALSE, FALSE, TRUE, x, y)
-#define DnDHGFakeDrop(widget, x, y) \
-    DnDFakeXEvents(widget, FALSE, TRUE, FALSE, FALSE, TRUE, x, y)
-
-#ifdef GTK2
-# define GDKATOM_TO_ATOM(gdkAtom) gdk_x11_atom_to_xatom(gdkAtom)
-#else
-# define GDKATOM_TO_ATOM(gdkAtom) gdkAtom
-#endif
-
-/*
- * Forward Declarations
- */
-static Bool DnDRpcInEnterCB      (char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-static Bool DnDRpcInDataSetCB    (char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-static Bool DnDRpcInMoveCB       (char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-static Bool DnDRpcInDataFinishCB (char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-static Bool DnDRpcInDropCB       (char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-static Bool DnDRpcInMouseUngrabCB(char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-static Bool DnDRpcInGetNextFileCB(char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-static Bool DnDRpcInFinishCB     (char const **result, size_t *resultLen,
-                                  const char *name, const char *args,
-                                  size_t argsSize,void *clientData);
-
-/*
- * Gtk DnD specific event/signal callbacks.
- */
-/* For Host->Guest DnD */
-static void DnDGtkBeginCB(GtkWidget *widget, GdkDragContext *dc, gpointer data);
-static void DnDGtkEndCB(GtkWidget *widget, GdkDragContext *dc, gpointer data);
-static void DnDGtkDataRequestCB(GtkWidget *widget, GdkDragContext *dc,
-                                GtkSelectionData *selection_data,
-                                guint info, guint time, gpointer data);
-
-/* For Guest->Host DnD */
-static gboolean DnDGtkDragMotionCB(GtkWidget *widget, GdkDragContext *dc, gint x,
-                                   gint y, guint time, gpointer data);
-static void DnDGtkDragDataReceivedCB(GtkWidget *widget, GdkDragContext *dc,
-                                     gint x, gint y, GtkSelectionData *dragData,
-                                     guint info, guint time, gpointer data);
-static gboolean DnDGtkDragDropCB(GtkWidget *widget, GdkDragContext *dc,
-                                 gint x, gint y, guint time, gpointer data);
-
-/*
- * Utility
- */
-static Bool DnDSendVmxNewFileRoot(char *rpcCmd);
-static Bool DnDFakeXEvents(GtkWidget *widget, Bool showWidget,
-                           Bool buttonEvent, Bool buttonPress,
-                           Bool moveWindow,
-                           Bool coordsProvided, int x, int y);
-static void DnDSendEscapeKey(GtkWidget *mainWnd);
-static INLINE Bool DnDGHDragPending(GtkWidget *widget);
-static INLINE Bool DnDGHXdndDragPending(GtkWidget *widget);
-static INLINE void DnDGHXdndClearPending(GtkWidget *widget);
-static INLINE Bool DnDGHMotifDragPending(GtkWidget *widget);
-static INLINE void DnDGHFileListClear(void);
-static INLINE void DnDGHFileListSet(char *fileList, size_t fileListSize);
-static INLINE Bool DnDGHFileListGetNext(char **fileName, size_t *fileNameSize);
-static INLINE void DnDGHStateInit(GtkWidget *widget);
-static INLINE void DnDHGStateInit(void);
-static INLINE Bool DnDGHCancel(GtkWidget *widget);
-static Bool DnDGHXEventTimeout(void *clientData);
-
-/*
- * Globals
- */
-struct ghState {
-   Bool dragInProgress;
-   Bool ungrabReceived;
-   char *dndFileList;
-   char *dndFileListNext;
-   size_t dndFileListSize;
-   GdkDragContext *dragContext;
-   guint time;
-   Event *event;
-} gGHState;
-static Bool gHGDnDInProgress;
-static Bool gDoneDragging;
-static Bool gHGDataPending;
-static char gDnDData[1024];
-static GdkDragContext *gDragCtx;
-static GtkTargetEntry gTargetEntry[NR_DRAG_TARGETS];
-static GdkAtom gTargetEntryAtom[NR_GH_DRAG_TARGETS];
-static char gFileRoot[DND_MAX_PATH];
-static size_t gFileRootSize;
-static size_t gDnDDataSize;
-static Bool gUnity;
-
-/*
- * From vmwareuserInt.h
- */
-RpcIn     *gRpcIn;
-Display   *gXDisplay;
-Window     gXRoot;
-
-
-/*
- * Host->Guest RPC callback implementations
- */
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDRpcInEnterCB --
- *
- *       For Host->Guest operations only.
- *       User has dragged something over this guest's MKS window
- *
- * Results:
- *       TRUE on success, FALSE otherwise
- *
- * Side effects:
- *      Some GdkEvents are generated which will "drag" the mouse. A directory
- *       is created.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInEnterCB(char const **result,     // OUT
-                size_t *resultLen,       // OUT
-                const char *name,        // IN
-                const char *args,        // IN
-                size_t argsSize,         // Ignored
-                void *clientData)        // IN
-{
-   char *numFormats;
-   char *pFormat;
-   unsigned int index = 0;
-   int nFormats;
-   int i;
-   GtkWidget *mainWnd;
-
-   Debug("Got DnDRpcInEnterCB\n");
-   mainWnd = GTK_WIDGET(clientData);
-   if (mainWnd == NULL) {
-      return RpcIn_SetRetVals(result, resultLen,
-                              "bad clientData passed to callback", FALSE);
-   }
-
-   if (gBlockFd < 0) {
-      Debug("DnDRpcInEnterCB: cannot allow H->G DnD without vmblock.\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "blocking file system unavailable", FALSE);
-   }
-
-   numFormats = StrUtil_GetNextToken(&index, args, " ");
-   if (!numFormats) {
-      Debug("DnDRpcInEnterCB: Failed to parse numformats\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "must specify number of formats", FALSE);
-   }
-
-   /* Skip whitespace character. */
-   index++;
-
-   nFormats = atoi(numFormats);
-   free(numFormats);
-
-   for (i = 0; i < nFormats; i++) {
-      pFormat = StrUtil_GetNextToken(&index, args, ",");
-
-      if (!pFormat) {
-         Debug("DnDRpcInEnterCB: Failed to parse format list\n");
-         return RpcIn_SetRetVals(result, resultLen,
-                                 "Failed to read format list", FALSE);
-      } else {
-         /*
-          * TODO: check that formats are ok for us to handle. For now, this is
-          * ok since there should only be a CF_HDROP. But, we really should figure
-          * out a much more cross-platform format scheme
-          */
-         free(pFormat);
-      }
-   }
-
-   if (!DnDHGFakeDrag(mainWnd)) {
-      Debug("DnDRpcInEnterCB: Failed to fake X events\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "failed to fake drag", FALSE);
-   }
-
-   RpcIn_SetRetVals(result, resultLen, "", TRUE);
-   RpcOut_sendOne(NULL, NULL, "dnd.feedback copy");
-   Debug("DnDRpcInEnterCB finished\n");
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDRpcInDataSetCB --
- *
- *       For Host->Guest operations only.
- *       Host is sending data from a DnD operation.
- *
- * Results:
- *       TRUE on success, FALSE otherwise.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInDataSetCB(char const **result,  // OUT
-                  size_t *resultLen,    // OUT
-                  const char *name,     // IN
-                  const char *args,     // IN
-                  size_t argsSize,      // IN: Size of args
-                  void *clientData)     // Ignored
-{
-   char blockDir[DND_MAX_PATH];
-   char *perDnDDir = NULL;
-   char *format;
-   char  *data;
-   unsigned int index = 0;
-   size_t dataSize;
-   char *retStr;
-   Bool ret = FALSE;
-
-   Debug("DnDRpcInDataSetCB: enter\n");
-
-   if (gBlockFd < 0) {
-      Debug("DnDRpcInDataSetCB: blocking file system not available.\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "blocking file system not available", FALSE);
-   }
-
-   /* Parse the data type & value string. */
-   format = StrUtil_GetNextToken(&index, args, " ");
-   if (!format) {
-      Debug("DnDRpcInDataSetCB: Failed to parse format\n");
-      return RpcIn_SetRetVals(result, resultLen, "need format", FALSE);
-   }
-
-   index++; /* Ignore leading space before data. */
-   dataSize = argsSize - index;
-   data = Util_SafeMalloc(dataSize);
-   memcpy(data, args + index, dataSize);
-
-   Debug("DnDRpcInDataSetCB: Received data from host: (%s) [%s] (%"FMTSZ"u)\n",
-         format, CPName_Print(data, dataSize), dataSize);
-
-   /*
-    * Here we take the last component of the actual file root, which is
-    * a temporary directory for this DnD operation, and append it to the mount
-    * point for vmblock.  This is where we want the target application to
-    * access the file since it will enable vmblock to block that application's
-    * progress if necessary.
-    */
-   perDnDDir = DnD_GetLastDirName(gFileRoot);
-   if (!perDnDDir) {
-      Debug("DnDRpcInDataSetCB: cannot obtain dirname of root.\n");
-      retStr = "error obtaining dirname of root";
-      goto out;
-   }
-
-   if (sizeof VMBLOCK_MOUNT_POINT - 1 +
-       (sizeof DIRSEPS - 1) * 2 + strlen(perDnDDir) >= sizeof blockDir) {
-      Debug("DnDRpcInDataSetCB: blocking directory path too large.\n");
-      retStr = "blocking directory path too large";
-      goto out;
-   }
-
-   Str_Sprintf(blockDir, sizeof blockDir,
-               VMBLOCK_MOUNT_POINT DIRSEPS "%s" DIRSEPS, perDnDDir);
-
-   /* Add the file root to the relative paths received from host */
-   if (!DnD_PrependFileRoot(blockDir, &data, &dataSize)) {
-      Debug("DnDRpcInDataSsetCB: error prepending guest file root\n");
-      retStr = "error prepending file root";
-      goto out;
-   }
-   if (dataSize + 1 > sizeof gDnDData) {
-      Debug("DnDRpcInDataSetCB: data too large\n");
-      retStr = "data too large";
-      goto out;
-   }
-
-   memcpy(gDnDData, data, dataSize + 1);
-   gDnDDataSize = dataSize;
-   Debug("DnDRpcInDataSetCB: prepended file root [%s] (%"FMTSZ"u)\n",
-         CPName_Print(gDnDData, gDnDDataSize), gDnDDataSize);
-
-   retStr = "";
-   ret = TRUE;
-
-out:
-   free(format);
-   free(data);
-   free(perDnDDir);
-   return RpcIn_SetRetVals(result, resultLen, retStr, ret);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDRpcInMoveCB --
- *
- *       For Host->Guest operations only.
- *       Host user is dragging data over this guest's MKS window
- *
- * Results:
- *       TRUE on success, FALSE otherwise.
- *
- * Side effects:
- *      Send a gdk event that "moves" the mouse.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInMoveCB(char const **result,     // OUT
-               size_t *resultLen,       // OUT
-               const char *name,        // IN
-               const char *args,        // IN
-               size_t argsSize,         // Ignored
-               void *clientData)        // IN: pointer to mainWnd
-{
-   GtkWidget *mainWnd;
-   char *sXCoord;
-   char *sYCoord;
-   unsigned int index = 0;
-   int xCoord, yCoord;
-
-   mainWnd = GTK_WIDGET(clientData);
-   if (mainWnd == NULL) {
-      return RpcIn_SetRetVals(result, resultLen,
-                              "bad clientData passed to callback", FALSE);
-   }
-
-   sXCoord = StrUtil_GetNextToken(&index, args, " ");
-   sYCoord = StrUtil_GetNextToken(&index, args, " ");
-
-   if (!sXCoord || !sYCoord) {
-      Debug("DnDRpcInMove: Failed to parse coords\n");
-      free(sXCoord);
-      free(sYCoord);
-      return RpcIn_SetRetVals(result, resultLen,
-                              "error reading mouse move data", FALSE);
-   }
-
-   xCoord = atoi(sXCoord);
-   yCoord = atoi(sYCoord);
-
-   free(sXCoord);
-   free(sYCoord);
-
-   /* Fake a mouse move */
-   if (!DnDHGFakeMove(mainWnd, xCoord, yCoord)) {
-      Debug("DnDRpcInMove: Failed to fake mouse movement\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "failed to move mouse", FALSE);
-   }
-
-   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDRpcInDataFinishCB --
- *
- *       For Host->Guest operations only.
- *       Host has finished transferring DnD data to the guest. We do any post
- *       H->G operation cleanup here, like removing the block on the staging
- *       directory, picking a new file root, and informing the host of the new
- *       root.
- *
- * Results:
- *       TRUE on success, FALSE otherwise
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInDataFinishCB(char const **result,   // OUT
-                     size_t *resultLen,     // OUT
-                     const char *name,      // IN
-                     const char *args,      // IN
-                     size_t argsSize,       // Ignored
-                     void *clientData)      // Ignored
-{
-   unsigned int index = 0;
-   char *state;
-
-   Debug("DnDRpcInDataFinishCB: enter\n");
-
-   state = StrUtil_GetNextToken(&index, args, " ");
-   if (!state) {
-      Debug("DnDRpcInDataFinishCB: could not get dnd finish state.\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "could not get dnd finish state", FALSE);
-   }
-
-   /* 
-    * If the guest doesn't support vmblock, we'll have bailed out of 
-    * DndRpcInDropCB before setting gHGDataPending. Thus, it doesn't make sense
-    * to pop a warning here, but let's keep the message around just in case 
-    * there can be a failure worth hearing about.
-    */
-   if (!gHGDataPending) {
-      Debug("DnDRpcInDataFinishCB: expected gHGDataPending to be set.\n");
-   }
-
-   gHGDataPending = FALSE;
-
-   /*
-    * The host will send us "success" or "error", depending on whether the
-    * transfer finished successfully.  In either case we remove the pending
-    * block, but in the "error" case we also need to delete all the files so
-    * the destination application doesn't access the partially copied files and
-    * mistake them for a successful drop.
-    */
-   if (strcmp(state, "success") != 0) {
-      /* On any non-success input, delete the files. */
-      DnD_DeleteStagingFiles(gFileRoot, FALSE);
-   }
-
-   free(state);
-
-   if (gBlockFd >= 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
-      Warning("DnDRpcInDataFinishCB: could not remove block on %s\n",
-              gFileRoot);
-   }
-
-   /* Pick a new file root and send that to the host for the next DnD. */
-   if (!DnDSendVmxNewFileRoot("dnd.setGuestFileRoot")) {
-      Debug("DnDRpcInDataFinishCB: Failed to send dnd.setGuestFileRoot "
-            "message to host\n");
-      return RpcIn_SetRetVals(result, resultLen, "could not send guest root", FALSE);
-   }
-
-   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDRpcInDropCB --
- *
- *       For Host->Guest operations only.
- *       Host user has dropped data over this guest's MKS window.  We add
- *       a block on the staging directory then send a fake mouse release to
- *       invoke the drop completion (from Gtk's point of view).
- *
- * Results:
- *       TRUE on success, FALSE otherwise.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInDropCB(char const **result,   // OUT
-               size_t *resultLen,     // OUT
-               const char *name,      // IN
-               const char *args,      // IN
-               size_t argsSize,       // Ignored
-               void *clientData)      // IN: Gtk window widget
-{
-   GtkWidget *mainWnd;
-   char *sXCoord;
-   char *sYCoord;
-   unsigned int index = 0;
-   int xCoord, yCoord;
-
-   Debug("DnDRpcInDropCB: enter\n");
-
-   gDoneDragging = TRUE;
-
-   mainWnd = GTK_WIDGET(clientData);
-   if (mainWnd == NULL) {
-      return RpcIn_SetRetVals(result, resultLen,
-                              "bad clientData passed to callback", FALSE);
-   }
-
-   sXCoord = StrUtil_GetNextToken(&index, args, " ");
-   sYCoord = StrUtil_GetNextToken(&index, args, " ");
-
-   if (!sXCoord || !sYCoord) {
-      Debug("DnDRpcInDropCB: Failed to parse coords\n");
-      free(sXCoord);
-      free(sYCoord);
-      return RpcIn_SetRetVals(result, resultLen,
-                              "must specify drop coordinates", FALSE);
-   }
-
-   xCoord = atoi(sXCoord);
-   yCoord = atoi(sYCoord);
-
-   free(sXCoord);
-   free(sYCoord);
-
-   Debug("DnDRpcInDropCB: Received drop notification at (%d,%d)\n",
-         xCoord, yCoord);
-
-   /*
-    * Add a block on the guest file root, warp the pointer, then fake the mouse
-    * release.  Make sure we'll succeed before modifying any mouse state in the
-    * guest.
-    */
-   if (gBlockFd < 0) {
-      /*
-       * We shouldn't get here since DnDRpcInEnterCB() checks this, but we'll
-       * check rather than ASSERT just in case.
-       */
-      return RpcIn_SetRetVals(result, resultLen,
-                              "blocking file system unavailable", FALSE);
-   }
-
-   if (!DnD_AddBlock(gBlockFd, gFileRoot)) {
-      return RpcIn_SetRetVals(result, resultLen, "could not add block", FALSE);
-   }
-
-   /* Update state before causing faking any mouse or keyboard changes. */
-   gHGDataPending = TRUE;
-
-
-   if (!DnDHGFakeDrop(mainWnd, xCoord, yCoord)) {
-      Debug("DnDRpcInDropCB: failed to fake drop\n");
-      return RpcIn_SetRetVals(result, resultLen, "failed to fake drop", FALSE);
-   }
-
-   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-}
-
-
-/*
- * Guest->Host RPC callback implementations
- */
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDRpcInMouseUngrabCB --
- *
- *    For Guest->Host operations only.
- *
- *    Called when a mouse ungrab is attempted with the mouse button down.  When
- *    the MKS sees mouse movements outside of the clip (the viewable portion of
- *    the guest's display) while a mouse button is down, this function is
- *    called so we can inform the MKS whether to allow the ungrab (and start
- *    a DnD if one is pending).
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    The GDK window is moved and resized, and the mouse is moved over it.
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInMouseUngrabCB(char const **result,      // OUT
-                      size_t *resultLen,        // OUT
-                      const char *name,         // IN
-                      const char *args,         // IN
-                      size_t argsSize,          // Ignored
-                      void *clientData)         // IN
-{
-   unsigned int index = 0;
-   GtkWidget *mainWnd;
-   int32 xPos;
-   int32 yPos;
-
-   Debug("Got DnDRpcInMouseUngrabCB\n");
-   mainWnd = GTK_WIDGET(clientData);
-   if (mainWnd == NULL) {
-      Warning("DnDRpcInMouseUngrabCB: invalid clientData\n");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "bad clientData passed to callback", FALSE);
-   }
-
-   /*
-    * If there is already a DnD or copy/paste in progress (including the file
-    * transfer), don't allow another.
-    */
-   if (gHGDataPending || gGHState.dragInProgress || CopyPaste_InProgress()) {
-      RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "dnd already in progress", FALSE);
-   }
-
-   if (!StrUtil_GetNextIntToken(&xPos, &index, args, " ")) {
-      Warning("DnDRpcInMouseUngrabCB: could not parse x coordinate\n");
-      RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "Failed to parse x coordinate", FALSE);
-   }
-
-   if (!StrUtil_GetNextIntToken(&yPos, &index, args, " ")) {
-      Warning("DnDRpcInMouseUngrabCB: could not parse y coordinate\n");
-      RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "Failed to parse y coordinate", FALSE);
-   }
-
-   Debug("DnDRpcInMouseUngrabCB: Received (%d,%d)\n", xPos, yPos);
-
-   /*
-    * If there is no DnD pending, inform the host so the MKS can start sending
-    * mouse packets again.
-    */
-   if (!DnDGHDragPending(mainWnd)) {
-      RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-      return RpcIn_SetRetVals(result, resultLen, "DnD not pending", TRUE);
-   }
-
-   /* The host only gives us coordinates within our screen */
-   ASSERT(xPos >= 0);
-   ASSERT(yPos >= 0);
-
-   /*
-    * Fake mouse movements over the window to try and generate a "drag_motion"
-    * signal from GTK.  If a drag is pending, that signal will be sent to our
-    * widget and DnDGtkDragMotionCB will be invoked to start the DnD
-    * operation.
-    */
-   if (!DnDGHFakeDrag(mainWnd)) {
-      Warning("DnDRpcInMouseUngrabCB: could not fake X events\n");
-      RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "error faking X events", FALSE);
-   }
-
-   /*
-    * Add event to fire and hide our widget if a DnD is not pending.  Note that
-    * this is here in case our drag pending heuristic for Xdnd and Motif does
-    * not encompass all cases, or if the X events we generate don't cause the
-    * "drag_motion" for some other reason.
-    */
-   gGHState.event = EventManager_Add(gEventQueue, RPCIN_POLL_TIME * 100,
-                                     DnDGHXEventTimeout, mainWnd);
-   if (!gGHState.event) {
-      Warning("DnDRpcInMouseUngrabCB: could not create event\n");
-      RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-      return RpcIn_SetRetVals(result, resultLen,
-                              "could not create timeout event", FALSE);
-   }
-
-   gGHState.dragInProgress = FALSE;
-   gGHState.ungrabReceived = TRUE;
-
-   Debug("DnDRpcInMouseUngrabCB finished\n");
-   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDRpcInGetNextFileCB --
- *
- *    For Guest->Host operations only.
- *
- *    Invoked when the host is compiling its list of files to copy from the
- *    guest.  Here we provide the path of the next file in our Guest->Host file
- *    list in guest path format (for display purposes) and CPName format (for
- *    file copy operation).
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    Iterator pointer within file list of GH state is iterated to next list
- *    entry (through call to DnDGHFileListGetNext()).
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInGetNextFileCB(char const **result,      // OUT
-                      size_t *resultLen,        // OUT
-                      const char *name,         // IN
-                      const char *args,         // IN
-                      size_t argsSize,          // Ignored
-                      void *clientData)         // IN
-{
-   static char resultBuffer[DND_MAX_PATH];
-   char *fileName;
-   size_t fileNameSize;
-   uint32 cpNameSize;
-   GtkWidget *mainWnd;
-   Bool res;
-
-   mainWnd = GTK_WIDGET(clientData);
-   if (mainWnd == NULL) {
-      DnDGHCancel(NULL);
-      return RpcIn_SetRetVals(result, resultLen,
-                              "bad clientData passed to callback", FALSE);
-   }
-
-   /*
-    * Retrieve a pointer to the next filename and its size from the list stored
-    * in the G->H DnD state.  Note that fileName should not be free(3)d here
-    * since an additional copy is not allocated.
-    */
-   res = DnDGHFileListGetNext(&fileName, &fileNameSize);
-
-   if (!res) {
-      Warning("DnDRpcInGetNextFileCB: error retrieving file name\n");
-      DnDGHCancel(mainWnd);
-      return RpcIn_SetRetVals(result, resultLen, "error getting file", FALSE);
-   }
-
-   if (!fileName) {
-      /* There are no more files to send */
-      Debug("DnDRpcInGetNextFileCB: reached end of Guest->Host file list\n");
-      return RpcIn_SetRetVals(result, resultLen, "|end|", TRUE);
-   }
-
-   if (fileNameSize + 1 + fileNameSize > sizeof resultBuffer) {
-      Warning("DnDRpcInGetNextFileCB: filename too large (%"FMTSZ"u)\n", fileNameSize);
-      DnDGHCancel(mainWnd);
-      return RpcIn_SetRetVals(result, resultLen, "filename too large", FALSE);
-   }
-
-   /*
-    * Construct a reply message of the form:
-    * <file name in guest format><NUL><filename in CPName format>
-    */
-   memcpy(resultBuffer, fileName, fileNameSize);
-   resultBuffer[fileNameSize] = '\0';
-
-   cpNameSize = CPNameUtil_ConvertToRoot(fileName,
-                                         sizeof resultBuffer - (fileNameSize + 1),
-                                         resultBuffer + fileNameSize + 1);
-   if (cpNameSize < 0) {
-      Warning("DnDRpcInGetNextFileCB: could not convert to CPName\n");
-      DnDGHCancel(mainWnd);
-      return RpcIn_SetRetVals(result, resultLen,
-                              "error on CPName conversion", FALSE);
-   }
-
-   /* Set manually because RpcIn_SetRetVals() assumes no NUL characters */
-   *result = resultBuffer;
-   *resultLen = fileNameSize + 1 + cpNameSize;
-
-   Debug("DnDRpcInGetNextFileCB: [%s] (%"FMTSZ"u)\n",
-         CPName_Print(*result, *resultLen), *resultLen);
-
-   return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDRpcInFinishCB --
- *
- *    For Guest->Host operations only.
- *
- *    Invoked when host side of DnD operation has finished.
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-DnDRpcInFinishCB(char const **result,      // OUT
-                 size_t *resultLen,        // OUT
-                 const char *name,         // IN
-                 const char *args,         // IN
-                 size_t argsSize,          // Ignored
-                 void *clientData)         // IN
-{
-   GtkWidget *mainWnd;
-   char *effect = NULL;
-   unsigned int index = 0;
-   char *retStr;
-   Bool ret = FALSE;
-
-   mainWnd = GTK_WIDGET(clientData);
-   if (mainWnd == NULL) {
-      retStr = "bad clientData passed to callback";
-      goto exit;
-   }
-
-   effect = StrUtil_GetNextToken(&index, args, " ");
-   if (!effect) {
-      Warning("DnDRpcInFinishCB: no drop effect provided\n");
-      retStr = "drop effect not provided";
-      goto exit;
-   }
-
-   if (strcmp(effect, "cancel") == 0) {
-      DnDSendEscapeKey(mainWnd);
-      DnDGHCancel(mainWnd);
-   } else {
-      /*
-       * The drop happened on the host.  Fake X events such that our window is
-       * placed at the mouse's coordinates and raised, then fake a button
-       * release on the window.  This causes us to get a "drag_drop" signal
-       * from GTK on our widget.
-       */
-      if (!DnDGHFakeDrop(mainWnd)) {
-         Warning("DnDRpcInFinishCB: could not fake X events\n");
-         retStr = "error faking X events";
-         goto exit;
-      }
-
-      gGHState.event = EventManager_Add(gEventQueue, RPCIN_POLL_TIME * 10,
-                                           DnDGHXEventTimeout, mainWnd);
-      if (!gGHState.event) {
-         Warning("DnDRpcInFinishCB: could not create event\n");
-         retStr = "could not create timeout event";
-         goto exit;
-      }
-   }
-
-   retStr = "";
-   ret = TRUE;
-
-exit:
-   if (!ret) {
-      DnDGHCancel(mainWnd);
-   }
-
-   free(effect);
-   gGHState.dragInProgress = FALSE;
-   return RpcIn_SetRetVals(result, resultLen, retStr, ret);
-}
-
-
-/*
- * Host->Guest (drop source) Gtk callback implementations
- */
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDGtkBeginCB --
- *
- *       "drag_begin" signal handler for GTK.  This signal will be received
- *       after the fake mouse press sent in DnDRpcInEnterCB() is performed.
- *       Here we simply initialize our state variables.
- *
- * Results:
- *       None
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-DnDGtkBeginCB(GtkWidget *widget,   // IN: the widget under the drag
-              GdkDragContext *dc,  // IN: the drag context maintained by gdk
-              gpointer data)       // IN: unused
-{
-   GtkWidget *mainWnd = GTK_WIDGET(data);
-
-   Debug("DnDGtkBeginCB: entry\n");
-
-   if ((widget == NULL) || (mainWnd == NULL) || (dc == NULL)) {
-      return;
-   }
-
-   gHGDnDInProgress = TRUE;
-   gDoneDragging = FALSE;
-   gHGDataPending = FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDGtkEndCB --
- *
- *       "drag_end" signal handler for GTK. This is called when a drag and drop has
- *       completed. So this function is the last one to be called in any given DnD
- *       operation.
- *
- * Results:
- *       None
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-DnDGtkEndCB(GtkWidget *widget,   // IN: the widget under the drag
-            GdkDragContext *dc,  // IN: the drag context maintained by gdk
-            gpointer data)       // IN: unused
-{
-
-   GtkWidget *mainWnd = GTK_WIDGET(data);
-
-   Debug("DnDGtkEndCB: enter\n");
-
-   if (mainWnd == NULL || dc == NULL) {
-      return;
-   }
-
-   /*
-    * Do not set gHGDataPending to FALSE since DnD operation completes before
-    * the data transfer.
-    */
-   gDoneDragging = FALSE;
-   gHGDnDInProgress = FALSE;
-
-   RpcOut_sendOne(NULL, NULL, "dnd.finish %d", DROPEFFECT_COPY);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnDGtkDataRequestCB --
- *       DnD "drag_data_get" handler, for handling requests for DnD data on the
- *       specified widget. This function is called when there is need for DnD data
- *       on thesource, so this function is responsible for setting up the dynamic
- *       data exchange buffer and sending it out.
- *
- * Results:
- *       None
- *
- * Side effects:
- *      Data is avaiable to drop target.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-DnDGtkDataRequestCB(GtkWidget *widget,                // IN
-                    GdkDragContext *dc,               // IN
-                    GtkSelectionData *selection_data, // IN/OUT: buffer for the data
-                    guint info,                       // IN: the requested fo the data
-                    guint time,                       // IN: unused
-                    gpointer data)                    // IN: unused
-{
-   const char *begin;
-   const char *end;
-   const char *next;
-   const char *pre;
-   const char *post;
-   size_t preLen;
-   size_t postLen;
-   size_t len;
-   Bool insertSpace;
-   char *text = NULL;
-   size_t textLen = 1;
-
-   Debug("DnDGtkDataRequestCB: enter\n");
-
-   if ((widget == NULL) || (dc == NULL) || (selection_data == NULL)) {
-      Debug("DnDGtkDataRequestCB: Error, widget or dc or selection_data is invalid\n");
-      return;
-   }
-
-   /* Do nothing if we have not finished dragging yet */
-   if (!gDoneDragging) {
-      Debug("DnDGtkDataRequestCB: not done dragging yet\n");
-      return;
-   }
-
-   /* Setup the format string components */
-   switch (info) {
-   case DRAG_TARGET_INFO_URI_LIST:      /* text/uri-list */
-      pre = DND_URI_LIST_PRE;
-      preLen = sizeof DND_URI_LIST_PRE - 1;
-      post = DND_URI_LIST_POST;
-      postLen = sizeof DND_URI_LIST_POST - 1;
-      insertSpace = FALSE;
-      break;
-   case DRAG_TARGET_INFO_TEXT_PLAIN:    /* text/plain */
-      pre = DND_TEXT_PLAIN_PRE;
-      preLen = sizeof DND_TEXT_PLAIN_PRE - 1;
-      post = DND_TEXT_PLAIN_POST;
-      postLen = sizeof DND_TEXT_PLAIN_POST - 1;
-      insertSpace = TRUE;
-      break;
-   case DRAG_TARGET_INFO_STRING:        /* STRING */
-      pre = DND_STRING_PRE;
-      preLen = sizeof DND_STRING_PRE - 1;
-      post = DND_STRING_POST;
-      postLen = sizeof DND_STRING_POST - 1;
-      insertSpace = TRUE;
-      break;
-   default:
-      Log("DnDGtkDataRequestCB: invalid drag target info\n");
-      return;
-   }
-
-
-   /*
-    * Set begin to first non-NUL character and end to last NUL character to
-    * prevent errors in calling CPName_GetComponent().
-    */
-   for(begin = gDnDData; *begin == '\0'; begin++)
-      ;
-   end = CPNameUtil_Strrchr(gDnDData, gDnDDataSize + 1, '\0');
-   ASSERT(end);
-
-   /* Build up selection data */
-   while ((len = CPName_GetComponent(begin, end, &next)) != 0) {
-      const size_t origTextLen = textLen;
-      Bool freeBegin = FALSE;
-
-      if (len < 0) {
-         Log("DnDGtkDataRequestCB: error getting next component\n");
-         if (text) {
-            free(text);
-         }
-         return;
-      }
-
-      /*
-       * A URI list will expect the provided path to be escaped.  If we cannot
-       * escape the path for some reason we just use the unescaped version and
-       * hope that it works.
-       */
-      if (info == DRAG_TARGET_INFO_URI_LIST) {
-         size_t newLen;
-         char *escapedComponent;
-         int escIndex;
-         int bytesToEsc[256] = { 0, };
-
-         /* We escape the following characters based on RFC 1630. */
-         bytesToEsc['#'] = 1;
-         bytesToEsc['?'] = 1;
-         bytesToEsc['*'] = 1;
-         bytesToEsc['!'] = 1;
-         bytesToEsc['%'] = 1;  /* Escape character */
-
-         /* Escape non-ASCII characters so we can pass UTF-8 filenames */
-         for (escIndex = 0x80; escIndex < 0x100; escIndex++) {
-            bytesToEsc[escIndex] = 1;
-         }
-
-         escapedComponent = Escape_Do('%', bytesToEsc, begin, len, &newLen);
-         if (escapedComponent) {
-            begin = escapedComponent;
-            len = newLen;
-            freeBegin = TRUE;
-         }
-      }
-
-      /*
-       * Append component.  NUL terminator was accounted for by initializing
-       * textLen to one above.
-       */
-      textLen += preLen + len + postLen + (insertSpace ? 1 : 0);
-      text = Util_SafeRealloc(text, textLen);
-      Str_Snprintf(text + origTextLen - 1,
-                   textLen - origTextLen + 1,
-                   "%s%s%s", pre, begin, post);
-
-      if (insertSpace && next != end) {
-         ASSERT(textLen - 2 >= 0);
-         text[textLen - 2] = ' ';
-         text[textLen - 1] = '\0';
-      }
-
-      if (freeBegin) {
-         free((void *)begin);
-      }
-
-      /* Iterate to next component */
-      begin = next;
-   }
-
-   /*
-    * Send out the data using the selection system. When sending a string, GTK will
-    * ensure that a null terminating byte is added to the end so we do not need to
-    * add it. GTK also copies the data so the original will never be modified.
-    */
-   Debug("DnDGtkDataRequestCB: calling gtk_selection_data_set with [%s]\n", text);
-   gtk_selection_data_set(selection_data, selection_data->target,
-                          8, /* 8 bits per character. */
-                          text, textLen);
-   free(text);
-}
-
-
-/*
- * Guest->Host (drop target) Gtk callback implementations
- */
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGtkDragMotionCB --
- *
- *    "drag_motion" signal handler for GTK.  This is invoked each time the
- *    mouse moves over the drag target (destination) window when a DnD is
- *    pending.
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    RPC messages are sent to the host to proxy the DnD over.
- *
- *----------------------------------------------------------------------------
- */
-
-static gboolean
-DnDGtkDragMotionCB(GtkWidget *widget,    // IN: target widget
-                   GdkDragContext *dc,   // IN: the GDK drag context
-                   gint x,               // IN: x position of mouse
-                   gint y,               // IN: y position of mouse
-                   guint time,           // IN: time of event
-                   gpointer data)        // IN: our private data
-{
-   GdkAtom commonTarget = 0;
-   Bool found = FALSE;
-   uint32 i;
-
-   ASSERT(widget);
-   ASSERT(widget == data);
-   ASSERT(dc);
-
-   Debug("DnDGtkDragMotionCB: entry (x=%d, y=%d, time=%d)\n", x, y, time);
-
-   /*
-    * We'll get a number of these and should only carry on these operations on
-    * the first one.
-    *
-    * XXX Unity mode needs to know if there is a g->h->g dnd operation by
-    * detecting if the mouse has left the detection window. This code is
-    * currently not in the guest and should be ported from the host.
-    */
-   if (gGHState.dragInProgress && !gUnity) {
-      Debug("DnDGtkDragMotionCB: drag already in progress\n");
-      return FALSE;
-   }
-
-   /*
-    * Sometimes (rarely) real user mouse movements will trigger "drag_motion"
-    * signals after we have already handled them.  Prevent resetting the data
-    * and trying to start a new DnD operation.
-    */
-   if (!gGHState.ungrabReceived && !gUnity) {
-      Debug("DnDGtkDragMotionCB: extra drag motion without ungrab\n");
-      return FALSE;
-   }
-
-   gGHState.ungrabReceived = FALSE;
-
-   /* Remove event that hides our widget out of band from the DnD protocol. */
-   if (gGHState.event) {
-      Debug("DnDGtkDragMotionCB: removed pending event\n");
-      EventManager_Remove(gGHState.event);
-      gGHState.event = NULL;
-   }
-
-   /*
-    * Note that gdk_drag_status() is called for us by GTK since we passed in
-    * GTK_DEST_DEFAULT_MOTION to gtk_drag_dest_set().  We'd handle it
-    * ourselves, but GTK 1.2.10 has a "bug" that requires us to provide this
-    * flag to get drag_leave and drag_drop signals.
-    */
-
-   /*
-    * We need to try and find a common target format with the list of formats
-    * offered by the drag source.  This list is stored in the drag context's
-    * targets field, and each list member's data variable is a GdkAtom.  We
-    * translated our supported targets into GdkAtoms in gTargetEntryAtom at
-    * initialization.  Note that the GdkAtom value is an index into a table of
-    * strings maintained by the X server, so if they are equivalent then
-    * a common mime type is found.
-    */
-   for (i = 0; i < ARRAYSIZE(gTargetEntryAtom) && !found; i++) {
-      GList *currContextTarget = dc->targets;
-
-      while (currContextTarget) {
-         if (gTargetEntryAtom[i] == (GdkAtom)currContextTarget->data) {
-            commonTarget = gTargetEntryAtom[i];
-            found = TRUE;
-            break;
-         }
-         currContextTarget = currContextTarget->next;
-      }
-   }
-
-   if (!found) {
-      Warning("DnDGtkDragMotionCB: could not find a common target format\n");
-      DnDGHCancel(widget);
-      return FALSE;
-   }
-
-   /*
-    * Request the data.  A "drag_data_received" signal will be sent to widget
-    * (that's us) upon completion.
-    */
-   gtk_drag_get_data(widget, dc, commonTarget, time);
-
-
-   gGHState.dragInProgress = TRUE;
-   return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGtkDragDataReceivedCB --
- *
- *    "drag_data_received" signal handler for GTK.  Invoked when the data
- *    requested by a gtk_drag_get_data() call is ready.
- *
- *    This function actually begins the drag operation with the host by first
- *    setting the data ("dnd.data.set" RPC command) and then starting the DnD
- *    ("dnd.enter" RPC command).
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-DnDGtkDragDataReceivedCB(GtkWidget *widget,          // IN
-                         GdkDragContext *dc,         // IN
-                         gint x,                     // IN
-                         gint y,                     // IN
-                         GtkSelectionData *dragData, // IN
-                         guint info,                 // IN
-                         guint time,                 // IN
-                         gpointer data)              // IN
-{
-   const char rpcHeader[] = "dnd.data.set CF_HDROP ";
-   const size_t rpcHeaderSize = sizeof rpcHeader - 1;
-   char *rpcBody = NULL;
-   size_t rpcBodySize = 0;
-   char *rpc;
-   size_t rpcSize;
-
-
-   Debug("DnDGtkDragDataReceivedCB: entry\n");
-
-   if (dragData->length < 0) {
-      Warning("DnDGtkDragDataReceivedCB: received length < 0 error\n");
-      goto error;
-   }
-
-   gGHState.dragContext = dc;
-   gGHState.time = time;
-
-   /*
-    * Construct the body of the RPC message and our Guest->Host file list.
-    */
-   if (dragData->target == gTargetEntryAtom[DRAG_TARGET_INFO_URI_LIST]) {
-      char *currName;
-      size_t currSize;
-      size_t index = 0;
-      char *ghFileList = NULL;
-      size_t ghFileListSize = 0;
-
-      Debug("DnDGtkDragDataReceivedCB: uri-list [%s]\n", dragData->data);
-
-      /*
-       * Get the the full filenames and last components from the URI list.  The
-       * body of the RPC message will be these last components delimited with
-       * NUL characters; the Guest->Host file list will be the full paths
-       * delimited by NUL characters.
-       */
-      while ((currName = DnD_UriListGetNextFile(dragData->data,
-                                                &index,
-                                                &currSize))) {
-         size_t lastComponentSize;
-         char *lastComponentStart;
-
-         /* Append current filename to Guest->Host list */
-         ghFileList = Util_SafeRealloc(ghFileList,
-                                       ghFileListSize + currSize + 1);
-         memcpy(ghFileList + ghFileListSize, currName, currSize);
-         ghFileListSize += currSize;
-         ghFileList[ghFileListSize] = '\0';
-         ghFileListSize++;
-
-         /* Append last component to RPC body */
-         lastComponentStart = CPNameUtil_Strrchr(currName, currSize, DIRSEPC);
-         if (!lastComponentStart) {
-            /*
-             * This shouldn't happen since filenames are absolute, but handle
-             * it as if the file name is the last component
-             */
-            lastComponentStart = currName;
-         } else {
-            /* Skip the last directory separator */
-            lastComponentStart++;
-         }
-
-         lastComponentSize = currName + currSize - lastComponentStart;
-         rpcBody = Util_SafeRealloc(rpcBody, rpcBodySize + lastComponentSize + 1);
-         memcpy(rpcBody + rpcBodySize, lastComponentStart, lastComponentSize);
-         rpcBodySize += lastComponentSize;
-         rpcBody[rpcBodySize] = '\0';
-         rpcBodySize++;
-
-         free(currName);
-      }
-
-      if (!ghFileList || !rpcBody) {
-         Warning("DnDGtkDragDataReceivedCB: no filenames retrieved "
-                 "from URI list\n");
-         free(ghFileList);
-         free(rpcBody);
-         goto error;
-      }
-
-      /* Set the list of full paths for use in the "dnd.data.get.file" callback */
-      DnDGHFileListSet(ghFileList, ghFileListSize);
-
-      /* rpcBody (and its size) will always contain a trailing NUL character */
-      rpcBodySize--;
-   } else {
-      Warning("DnDGtkDragDataReceivedCB: unknown target format used [%s]\n",
-              dragData->data);
-      goto error;
-   }
-
-   /*
-    * Set the drag data on the host, followed by sending the drag enter
-    */
-   rpcSize = rpcHeaderSize + rpcBodySize;
-   rpc = Util_SafeMalloc(rpcSize);
-   memcpy(rpc, rpcHeader, rpcHeaderSize);
-   memcpy(rpc + rpcHeaderSize, rpcBody, rpcBodySize);
-   free(rpcBody);
-
-   Debug("DnDGtkDragMotionCB: Sending: [%s] (%"FMTSZ"u)\n",
-         CPName_Print(rpc, rpcSize), rpcSize);
-   if (!RpcOut_SendOneRaw(rpc, rpcSize, NULL, NULL)) {
-      Warning("DnDGtkDragMotionCB: failed to send dnd.data.set message\n");
-      free(rpc);
-      goto error;
-   }
-
-   free(rpc);
-
-   if (!RpcOut_sendOne(NULL, NULL, "dnd.enter 1 CF_HDROP")) {
-      Warning("DnDGtkDragMotionCB: failed to send dnd.enter message\n");
-      goto error;
-   }
-
-   return;
-
-error:
-   RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-   DnDGHCancel(widget);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGtkDragDropCB --
- *
- *    "drag_drop" signal handler for GTK.  This is invoked when a mouse button
- *    release occurs on our widget.  We generate that mouse button release in
- *    DnDRpcInFinishCB() when the host indicates that the drop has occurred and
- *    the files have been successfully transferred to the guest.
- *
- * Results:
- *    TRUE indicates to GTK that it need not run other handlers, FALSE
- *    otherwise.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static gboolean
-DnDGtkDragDropCB(GtkWidget *widget,  // IN: widget event occurred on
-                 GdkDragContext *dc, // IN: Destination drag context
-                 gint x,             // IN: x coordinate of drop
-                 gint y,             // IN: y coordinate of drop
-                 guint time,         // IN: time of event
-                 gpointer data)      // IN: our private data
-{
-   ASSERT(widget);
-   ASSERT(widget == data);
-
-   Debug("DnDGtkDragDropCB: entry (%d, %d)\n", x, y);
-
-   /* Remove timeout callback that was set in case we didn't get here */
-   if (gGHState.event) {
-      Debug("DnDGtkDragDropCB: removed pending event\n");
-      EventManager_Remove(gGHState.event);
-      gGHState.event = NULL;
-   }
-
-   /* Hide our window so we don't receive stray signals */
-   if (!gUnity) {
-      gtk_widget_hide(widget);
-   }
-
-   gtk_drag_finish(dc, TRUE, FALSE, time);
-
-   /* Reset all Guest->Host state */
-   DnDGHStateInit(widget);
-
-   return FALSE;
-}
-
-
-/*
- * Utility functions
- */
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnD_GetNewFileRoot --
- *
- *    Convenience function that gets a new file root for use on a single DnD
- *    operation and sets the global file root variable accordingly.
- *
- * Results:
- *    Size of root string (not including NUL terminator).
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-DnD_GetNewFileRoot(char *fileRoot,         // IN/OUT
-                   int bufSize)            // IN: sizeof fileRoot
-{
-   char *newDir = NULL;
-   size_t fileRootSize;
-
-   newDir = DnD_CreateStagingDirectory();
-   if (newDir == NULL) {
-      /*
-       * Fallback on base of file root if we couldn't create a staging
-       * directory for this DnD operation.  This is what Windows DnD does.
-       */
-      Str_Strcpy(fileRoot, DnD_GetFileRoot(), bufSize);
-      return strlen(fileRoot);
-   } else {
-      fileRootSize = strlen(newDir);
-      ASSERT(fileRootSize < bufSize);
-      memcpy(fileRoot, newDir, fileRootSize);
-      fileRoot[fileRootSize] = '\0';
-      free(newDir);
-      return fileRootSize;
-   }
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDSendVmxNewFileRoot --
- *
- *    Sends the VMX a new file root with the provided RPC command.
- *
- * Results:
- *    TRUE on success, FALSE on failure
- *
- * Side effects:
- *    gFileRoot is repopulated.
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-DnDSendVmxNewFileRoot(char *rpcCmd)     // IN: RPC command
-{
-   int32 rpcCommandSize;
-   int32 cpNameSize;
-   int32 rpcMessageSize;
-   char *rpcMessage;
-   char *cur;
-
-   /* Repopulate gFileRoot */
-   gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot);
-
-   /*
-    * Here we must convert the file root before sending it across the
-    * backdoor.  We can only communicate with new VMXs (v2 DnD), so we only
-    * need to handle that case here.
-    *
-    * <rpcCmd> <file root in local format><NUL><file root in CPName>
-    */
-   rpcCommandSize = strlen(rpcCmd);
-
-   /*
-    * ConvertToRoot below will append the root share name, so we need to
-    * make room for it in our buffer.
-    */
-   rpcMessageSize = rpcCommandSize + 1 +
-                    gFileRootSize + 1 +
-                    HGFS_STR_LEN(HGFS_SERVER_POLICY_ROOT_SHARE_NAME) + 1 +
-                    gFileRootSize + 1;
-
-   rpcMessage = Util_SafeCalloc(1, rpcMessageSize);
-   memcpy(rpcMessage, rpcCmd, rpcCommandSize);
-   rpcMessage[rpcCommandSize] = ' ';
-   cur = rpcMessage + rpcCommandSize + 1;
-
-   memcpy(cur, gFileRoot, gFileRootSize);
-   cur += gFileRootSize;
-   *cur = '\0';
-   cur++;
-
-   Debug("DnDSendVmxNewFileRoot: calling CPNameUtil_ConvertToRoot(%s, %"FMTSZ"u, %p)\n",
-         gFileRoot, rpcMessageSize - (cur - rpcMessage), cur);
-   cpNameSize = CPNameUtil_ConvertToRoot(gFileRoot,
-                                         rpcMessageSize - (cur - rpcMessage),
-                                         cur);
-   if (cpNameSize < 0) {
-      Debug("DnDSendVmxNewFileRoot: Could not convert file root to CPName\n");
-      free(rpcMessage);
-      return FALSE;
-   }
-
-   /* Readjust message size for actual length */
-   rpcMessageSize = rpcCommandSize + 1 +
-                    gFileRootSize + 1 +
-                    cpNameSize + 1;
-
-   Debug("DnDSendVmxNewFileRoot: sending root [%s] (%d)\n",
-         CPName_Print(rpcMessage, rpcMessageSize), rpcMessageSize);
-
-   /*
-    * We must use RpcOut_SendOneRaw() here since RpcOut_sendOne() assumes a
-    * string and we are using CPName format.
-    */
-   if (!RpcOut_SendOneRaw(rpcMessage, rpcMessageSize, NULL, NULL)) {
-      Debug("DnDSendVmxNewFileRoot: Failed to send %s message to host\n", rpcCmd);
-      free(rpcMessage);
-      return FALSE;
-   }
-
-   free(rpcMessage);
-   return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDFakeXEvents --
- *
- *    Fake X mouse events and window movement for the provided Gtk widget.
- *
- *    This function will optionally show the widget, move the provided widget
- *    to either the provided location or the current mouse position if no
- *    coordinates are provided, and cause a button press or release event.
- *
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    Other X events should be generated from those faked here.
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-DnDFakeXEvents(GtkWidget *widget,  // IN: the Gtk widget
-               Bool showWidget,    // IN: whether to show Gtk widget
-               Bool buttonEvent,   // IN: whether to send a button event
-               Bool buttonPress,   // IN: whether to press or release mouse
-               Bool moveWindow,    // IN: whether to move our window too
-               Bool coordsProvided,// IN: whether coordinates provided
-               int xCoord,         // IN: x coordinate
-               int yCoord)         // IN: y coordinate
-{
-   Window rootWnd;
-   Bool ret;
-   Display *dndXDisplay;
-   Window dndXWindow;
-
-   ASSERT(widget);
-
-   dndXDisplay = GDK_WINDOW_XDISPLAY(widget->window);
-   dndXWindow = GDK_WINDOW_XWINDOW(widget->window);
-
-   /*
-    * Turn on X synchronization in order to ensure that our X events occur in
-    * the order called.  In particular, we want the window movement to occur
-    * before the mouse movement so that the events we are coercing do in fact
-    * happen.
-    */
-   XSynchronize(dndXDisplay, True);
-
-   if (showWidget) {
-      Debug("DnDFakeXEvents: showing Gtk widget\n");
-      gtk_widget_show(widget);
-      gdk_window_show(widget->window);
-   }
-
-   /* Get the current location of the mouse if coordinates weren't provided. */
-   if (!coordsProvided) {
-      Window rootReturn;
-      Window childReturn;
-      int rootXReturn;
-      int rootYReturn;
-      int winXReturn;
-      int winYReturn;
-      unsigned int maskReturn;
-
-      rootWnd = RootWindow(dndXDisplay, DefaultScreen(dndXDisplay));
-      ret = XQueryPointer(dndXDisplay, rootWnd, &rootReturn, &childReturn,
-                          &rootXReturn, &rootYReturn, &winXReturn, &winYReturn,
-                          &maskReturn);
-      if (ret == False) {
-         Warning("DnDFakeXEvents: XQueryPointer() returned False.\n");
-         XSynchronize(dndXDisplay, False);
-         return FALSE;
-      }
-
-      Debug("DnDFakeXEvents: mouse is at (%d, %d)\n", rootXReturn, rootYReturn);
-
-      xCoord = rootXReturn;
-      yCoord = rootYReturn;
-   }
-
-   if (moveWindow) {
-      /*
-       * Make sure the window is at this point and at the top (raised).  The
-       * window is resized to be a bit larger than we would like to increase
-       * the likelihood that mouse events are attributed to our window -- this
-       * is okay since the window is invisible and hidden on cancels and DnD
-       * finish.
-       */
-      XMoveResizeWindow(dndXDisplay, dndXWindow, xCoord, yCoord, 25, 25);
-      XRaiseWindow(dndXDisplay, dndXWindow);
-   }
-
-   /*
-    * Generate mouse movements over the window.  The second one makes ungrabs
-    * happen more reliably on KDE, but isn't necessary on GNOME.
-    */
-   XTestFakeMotionEvent(dndXDisplay, -1, xCoord, yCoord, CurrentTime);
-   XTestFakeMotionEvent(dndXDisplay, -1, xCoord + 1, yCoord + 1, CurrentTime);
-
-   if (buttonEvent) {
-      Debug("DnDFakeXEvents: faking left mouse button %s\n",
-            buttonPress ? "press" : "release");
-      XTestFakeButtonEvent(dndXDisplay, 1, buttonPress, CurrentTime);
-   }
-
-   XSynchronize(dndXDisplay, False);
-
-   return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDSendEscapeKey --
- *
- *    Sends the escape key, canceling any pending drag and drop on the guest.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-DnDSendEscapeKey(GtkWidget *mainWnd)  // IN
-{
-   Display *dndXDisplay;
-   uint32 escKeycode;
-
-   Debug("DnDRpcInFinishCB: faking ESC key press/release\n");
-
-   dndXDisplay = GDK_WINDOW_XDISPLAY(mainWnd->window);
-   escKeycode = XKeysymToKeycode(dndXDisplay, XK_Escape);
-
-   XTestFakeKeyEvent(dndXDisplay, escKeycode, TRUE, CurrentTime);
-   XTestFakeKeyEvent(dndXDisplay, escKeycode, FALSE, CurrentTime);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHDragPending --
- *
- *    Determine whether a drag is currently pending within the guest by
- *    inspecting the internal state of the X server.  Note that Gtk supports
- *    both the Xdnd and Motif protocols, so we check each one of those.
- *
- * Results:
- *    TRUE if a Drag operation is pending (waiting for a drop), FALSE
- *    otherwise.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE Bool
-DnDGHDragPending(GtkWidget *widget) // IN: our widget
-{
-   /* Xdnd is much more prevalent, so call it first */
-   return DnDGHXdndDragPending(widget) || DnDGHMotifDragPending(widget);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHXdndDragPending --
- *
- *    Determines whether an Xdnd protocol drag is pending.
- *
- * Results:
- *    TRUE is a drag is pending, FALSE otherwise.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE Bool
-DnDGHXdndDragPending(GtkWidget *widget) // IN: our widget
-{
-   GdkAtom xDnDSelection;
-   Window owner;
-
-   xDnDSelection = gdk_atom_intern("XdndSelection", TRUE);
-   if (xDnDSelection == None) {
-      Warning("DnDGHXdndDragPending: could not obtain Xdnd selection atom\n");
-      return FALSE;
-   }
-
-   /*
-    * The XdndSelection atom will only have an owner if there is a drag in
-    * progress.
-    */
-   owner = XGetSelectionOwner(GDK_WINDOW_XDISPLAY(widget->window),
-                              GDKATOM_TO_ATOM(xDnDSelection));
-
-   Debug("DnDGHXdndDragPending: an Xdnd drag is %spending\n",
-         owner != None ? "" : "not ");
-
-   return owner != None;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHXdndClearPending --
- *
- *    Clear the ownership of the XdndSelection selection atom that we use to
- *    determine if a Xdnd drag is pending.
- *
- *    Note that this function should only be called when a DnD is not in
- *    progress.
- *
- *    Also note that this is function is only necessary to handle desktop
- *    environments that don't clear the selection owner themselves (read KDE).
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-DnDGHXdndClearPending(GtkWidget *widget) // IN: program's widget
-{
-   GdkAtom xDnDSelection;
-
-   ASSERT(!gGHState.dragInProgress);
-
-   xDnDSelection = gdk_atom_intern("XdndSelection", TRUE);
-   if (xDnDSelection == None) {
-      return;
-   }
-
-   /* Clear current owner by setting owner to None */
-   XSetSelectionOwner(GDK_WINDOW_XDISPLAY(widget->window),
-                      GDKATOM_TO_ATOM(xDnDSelection), None, CurrentTime);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDMotifDragPending --
- *
- *    Determines whether a Motif protocol drag is pending.
- *
- *    XXX This has not yet been tested (looking for an app that actually uses
- *    the Motif protocol)
- *
- * Results:
- *    TRUE if a drag is pending, FALSE otherwise.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE Bool
-DnDGHMotifDragPending(GtkWidget *widget) // IN: our widget
-{
-   GdkAtom motifDragWindow;
-   Display *dndXDisplay;
-   int ret;
-   Window rootXWindow;
-   Atom type;
-   int format;
-   unsigned long nitems;
-   unsigned long bytesAfter;
-   unsigned char *prop;
-
-   motifDragWindow = gdk_atom_intern("_MOTIF_DRAG_WINDOW", TRUE);
-   if (motifDragWindow == None) {
-      Warning("DnDGHMotifDragPending: could not obtain Motif "
-              "drag window atom\n");
-      return FALSE;
-   }
-
-   dndXDisplay = GDK_WINDOW_XDISPLAY(widget->window);
-   rootXWindow = RootWindow(dndXDisplay, DefaultScreen(dndXDisplay));
-
-   /*
-    * Try and get the Motif drag window property from X's root window.  If one
-    * is provided, a DnD is pending.
-    */
-   ret = XGetWindowProperty(dndXDisplay, rootXWindow, GDKATOM_TO_ATOM(motifDragWindow),
-                            0, 1, False, XA_WINDOW,
-                            &type, &format, &nitems, &bytesAfter, &prop);
-   if (ret != Success) {
-      Warning("DnDGHMotifDragPending: XGetWindowProperty() error.\n");
-      return FALSE;
-   }
-
-   if (type == None) {
-      Debug("DnDGHXdndDragPending: a Motif drag is not pending\n");
-      return FALSE;
-   }
-
-   Debug("DnDGHXdndDragPending: a Motif drag is pending\n");
-
-   XFree(prop);
-   return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHFileListClear --
- *
- *    Clears existing Guest->Host file list, releasing any used resources.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-DnDGHFileListClear(void)
-{
-   Debug("DnDGHFileListClear: clearing G->H file list\n");
-   if (gGHState.dndFileList) {
-      free(gGHState.dndFileList);
-      gGHState.dndFileList = NULL;
-   }
-   gGHState.dndFileListSize = 0;
-   gGHState.dndFileListNext = NULL;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHFileListSet --
- *
- *    Sets the Guest->Host file list that is accessed through
- *    DnDGHFileListGetNext().
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    Clears the existing Guest->Host file list if it exists.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-DnDGHFileListSet(char *fileList,      // IN: new Guest->Host file list
-                 size_t fileListSize) // IN: size of the provided list
-{
-   DnDGHFileListClear();
-   gGHState.dndFileList = fileList;
-   gGHState.dndFileListSize = fileListSize;
-   gGHState.dndFileListNext = fileList;
-
-   Debug("DnDGHFileListSet: [%s] (%"FMTSZ"u)\n",
-         CPName_Print(gGHState.dndFileList, gGHState.dndFileListSize),
-         gGHState.dndFileListSize);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHFileListGetNext --
- *
- *    Retrieves the next file in the Guest->Host file list.
- *
- *    Note that this function may only be called after calling
- *    DnDGHFileListSet() and before calling DnDGHFileListClear().
- *
- * Results:
- *    TRUE on success, FALSE on failure.  If TRUE is returned, fileName is
- *    given a pointer to the filename's location or NULL if there are no more
- *    files, and fileNameSize is given the length of fileName.
- *
- * Side effects:
- *    The fileListNext value of the Guest->Host global state is updated.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE Bool
-DnDGHFileListGetNext(char **fileName,       // OUT: fill with filename location
-                     size_t *fileNameSize)  // OUT: fill with filename length
-{
-   char const *end;
-   char const *next;
-   int len;
-
-   ASSERT(gGHState.dndFileList);
-   ASSERT(gGHState.dndFileListNext);
-   ASSERT(gGHState.dndFileListSize > 0);
-
-   /* Ensure end is the last NUL character */
-   end = CPNameUtil_Strrchr(gGHState.dndFileList, gGHState.dndFileListSize, '\0');
-   ASSERT(end);
-
-   /* Get the length of this filename and a pointer to the next one */
-   len = CPName_GetComponent(gGHState.dndFileListNext, end, &next);
-   if (len < 0) {
-      Warning("DnDGHFileListGetNext: error retrieving next component\n");
-      return FALSE;
-   }
-
-   /* No more entries in the list */
-   if (len == 0) {
-      Debug("DnDGHFileListGetNext: no more entries\n");
-      *fileName = NULL;
-      *fileNameSize = 0;
-      return TRUE;
-   }
-
-   Debug("DnDGHFileListGetNext: returning [%s] (%d)\n",
-         gGHState.dndFileListNext, len);
-
-   *fileName = gGHState.dndFileListNext;
-   *fileNameSize = len;
-   gGHState.dndFileListNext = (char *)next;
-   return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHStateInit --
- *
- *    Initializes the Guest->Host DnD state.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-DnDGHStateInit(GtkWidget *widget)  // IN
-{
-   Debug("DnDGHStateInit: initializing guest->host state\n");
-   gGHState.time = 0;
-   gGHState.dragContext = NULL;
-   gGHState.dragInProgress = FALSE;
-   gGHState.ungrabReceived = FALSE;
-   gGHState.event = NULL;
-   DnDGHXdndClearPending(widget);
-   if (!gUnity) {
-      gtk_widget_hide(widget);
-   }
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDHGStateInit --
- *
- *    Initialize the Host->Guest DnD state.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE void
-DnDHGStateInit(void)
-{
-   gHGDnDInProgress = FALSE;
-   gDoneDragging = FALSE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHCancel --
- *
- *    Resets state and sends a DnD cancel message to the host.
- *
- * Results:
- *    TRUE on success, FALSE on failure.
- *
- * Side effects:
- *    DnD operation is cancelled.
- *
- *----------------------------------------------------------------------------
- */
-
-static INLINE Bool
-DnDGHCancel(GtkWidget *widget) // IN: program's widget
-{
-   /* Hide our widget so we don't receive stray signals */
-   if (widget && !gUnity) {
-      gtk_widget_hide(widget);
-   }
-
-   if (gGHState.dragContext) {
-      gdk_drag_status(gGHState.dragContext, 0, gGHState.time);
-   }
-
-   gGHState.dragInProgress = FALSE;
-
-   /*
-    * We don't initialize Guest->Host state here since an ungrab/grab/ungrab
-    * will cause a cancel but we want the drop of the DnD to still work.
-    */
-   return RpcOut_sendOne(NULL, NULL, "dnd.finish cancel");
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnDGHXEventTimeout --
- *
- *    Cleans up after fake X events do not cause intended events.  Hides the
- *    provided widget and resets all Guest->Host DnD state.
- *
- *    Note that this is expected to occur on ungrab if there is not a DnD
- *    pending, but may also occur at other times (sometimes we do not receive
- *    the drag drop after the mouse button release is faked on KDE).
- *
- *    This function is invoked by the event manager; it is added/removed
- *    to/from the queue in both DnDRpcInMouseUngrabCB() and DnDRpcInFinishCB(),
- *    and DnDGtkDragMotionCB() and DnDGtkDragDropCB() respectively.
- *
- * Results:
- *    TRUE always, so the event manager doesn't stop running.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static Bool
-DnDGHXEventTimeout(void *clientData) // IN: our widget
-{
-   GtkWidget *widget = (GtkWidget *)clientData;
-
-   Debug("DnDGHXEventTimeout time out \n");
-
-   RpcOut_sendOne(NULL, NULL, "dnd.notpending");
-
-   if (!gGHState.dragInProgress && !gUnity) {
-      gtk_widget_hide(widget);
-   }
-
-   /* gGHState.event is cleared with the rest of Guest->Host state */
-   DnDGHStateInit(widget);
-
-   return TRUE;
-}
-
-
-/*
- * Public functions invoked by the rest of vmware-user
- */
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnD_GetVmxDnDVersion --
- *
- *      Ask the vmx for it's dnd version.
- *
- * Results:
- *      The dnd version the vmx supports, 0 if the vmx doesn't know
- *      what we're talking about.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-uint32
-DnD_GetVmxDnDVersion(void)
-{
-   char *reply = NULL;
-   size_t replyLen;
-   uint32 vmxVersion;
-
-   if (!RpcOut_sendOne(&reply, &replyLen, "vmx.capability.dnd_version")) {
-      Debug("DnD_GetVmxDnDVersion: could not get VMX DnD version "
-            "capability: %s\n", reply ? reply : "NULL");
-      vmxVersion = 0;
-   } else {
-      vmxVersion = atoi(reply);
-      ASSERT(vmxVersion > 1);      /* DnD versions start at 2 */
-   }
-
-   free(reply);
-   return vmxVersion;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnD_RegisterCapability --
- *
- *      Register the "dnd" capability. Sometimes this needs to be done separately
- *      from the rest of DnD registration, so we provide it separately here.
- *
- * Results:
- *      TRUE on success
- *      FALSE on failure
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-DnD_RegisterCapability(void)
-{
-   /* Tell the VMX about the DnD version we support. */
-   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.dnd_version 2")) {
-      Debug("DnD_RegisterCapability: could not set guest DnD version capability\n");
-      return FALSE;
-   } else if (!DnDSendVmxNewFileRoot("dnd.ready enable")) {
-      Debug("DnD_RegisterCapability: failed to send dnd.ready message to host\n");
-      return FALSE;
-   }
-   return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnD_Register --
- *
- *      Register the DnD capability, setup callbacks, initialize.
- *
- * Results:
- *      TRUE on success, FALSE otherwise.
- *
- * Side effects:
- *      mainWnd will be a dragSource in the guest, and dnd will work from
- *      host to guest.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-DnD_Register(GtkWidget *hgWnd, // IN: The widget to register as a drag source.
-             GtkWidget *ghWnd) // IN: The widget to register as a drag target.
-{
-   uint32 i;
-
-   gDragCtx = NULL;
-
-   ASSERT(hgWnd);
-   ASSERT(ghWnd);
-
-   if (DnD_GetVmxDnDVersion() < 2) {
-      goto error;
-   }
-
-   /*
-    * We can't pass in NULL to XTestQueryExtension(), so pass in a dummy
-    * variable to avoid segfaults.  If we have a reason to check the major and
-    * minor numbers of the running extension, that would go here.
-    */
-   if (!XTestQueryExtension(GDK_WINDOW_XDISPLAY(hgWnd->window),
-                            &i, &i, &i, &i)) {
-      goto error;
-   }
-
-   /* Host->Guest RPC callbacks */
-   RpcIn_RegisterCallback(gRpcIn, "dnd.data.set", DnDRpcInDataSetCB, hgWnd);
-   RpcIn_RegisterCallback(gRpcIn, "dnd.enter", DnDRpcInEnterCB, hgWnd);
-   RpcIn_RegisterCallback(gRpcIn, "dnd.move", DnDRpcInMoveCB, hgWnd);
-   RpcIn_RegisterCallback(gRpcIn, "dnd.drop", DnDRpcInDropCB, hgWnd);
-   RpcIn_RegisterCallback(gRpcIn, "dnd.data.finish", DnDRpcInDataFinishCB,
-                          hgWnd);
-
-   /* Guest->Host RPC callbacks */
-   RpcIn_RegisterCallback(gRpcIn, "dnd.ungrab",
-                          DnDRpcInMouseUngrabCB, ghWnd);
-   RpcIn_RegisterCallback(gRpcIn, "dnd.data.get.file",
-                          DnDRpcInGetNextFileCB, ghWnd);
-   RpcIn_RegisterCallback(gRpcIn, "dnd.finish",
-                          DnDRpcInFinishCB, ghWnd);
-
-   /*
-    * Setup mainWnd as a DND source/dest.
-    *
-    * Note that G->H drag targets should come first in this array.  Currently
-    * G->H only supports text/uri-list targets.
-    */
-   gTargetEntry[0].target = DRAG_TARGET_NAME_URI_LIST;
-   gTargetEntry[0].info = DRAG_TARGET_INFO_URI_LIST;
-   gTargetEntry[0].flags = 0;
-   gTargetEntry[1].target = DRAG_TARGET_NAME_TEXT_PLAIN;
-   gTargetEntry[1].info = DRAG_TARGET_INFO_TEXT_PLAIN;
-   gTargetEntry[1].flags = 0;
-   gTargetEntry[2].target = DRAG_TARGET_NAME_STRING;
-   gTargetEntry[2].info = DRAG_TARGET_INFO_STRING;
-   gTargetEntry[2].flags = 0;
-
-   /* Populate our GdkAtom table for our supported Guest->Host targets */
-   for (i = 0;
-        i < ARRAYSIZE(gTargetEntry) && i < ARRAYSIZE(gTargetEntryAtom);
-        i++) {
-      gTargetEntryAtom[i] = gdk_atom_intern(gTargetEntry[i].target, FALSE);
-   }
-
-   /* Drag source for Host->Guest */
-   gtk_drag_source_set(hgWnd, GDK_BUTTON1_MASK,
-                       gTargetEntry, ARRAYSIZE(gTargetEntry),
-                       GDK_ACTION_COPY | GDK_ACTION_MOVE);
-
-   gtk_signal_connect(GTK_OBJECT(hgWnd), "drag_begin",
-                      GTK_SIGNAL_FUNC(DnDGtkBeginCB), hgWnd);
-   gtk_signal_connect(GTK_OBJECT(hgWnd), "drag_end",
-                      GTK_SIGNAL_FUNC(DnDGtkEndCB), hgWnd);
-   gtk_signal_connect(GTK_OBJECT(hgWnd), "drag_data_get",
-                      GTK_SIGNAL_FUNC(DnDGtkDataRequestCB), hgWnd);
-
-
-   /*
-    * Drop target (destination) for Guest->Host
-    *
-    * We provide NR_GH_DRAG_TARGETS (rather than ARRAYSIZE(gTargetEntry)) to
-    * gtk_drag_dest_set() since we support less targets for G->H than H->G.
-    */
-   gtk_drag_dest_set(ghWnd,
-                     GTK_DEST_DEFAULT_MOTION,
-                     gTargetEntry, NR_GH_DRAG_TARGETS,
-                     GDK_ACTION_COPY | GDK_ACTION_MOVE);
-
-   gtk_signal_connect(GTK_OBJECT(ghWnd), "drag_motion",
-                      GTK_SIGNAL_FUNC(DnDGtkDragMotionCB), ghWnd);
-   gtk_signal_connect(GTK_OBJECT(ghWnd), "drag_data_received",
-                      GTK_SIGNAL_FUNC(DnDGtkDragDataReceivedCB),
-                      ghWnd);
-   gtk_signal_connect(GTK_OBJECT(ghWnd), "drag_drop",
-                      GTK_SIGNAL_FUNC(DnDGtkDragDropCB), ghWnd);
-
-   DnD_OnReset(hgWnd, ghWnd);
-
-   if (DnD_RegisterCapability()) {
-      return TRUE;
-   }
-
-   /*
-    * We get here if DnD registration fails for some reason
-    */
-error:
-   DnD_Unregister(hgWnd, ghWnd);
-   return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DnD_Unregister --
- *
- *      Cleanup dnd related things.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      DnD is stopped, the rpc channel to the vmx is closed.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-DnD_Unregister(GtkWidget *hgWnd,        // IN: The widget for hg dnd
-               GtkWidget *ghWnd)        // IN: The widget for gh dnd
-{
-   RpcOut_sendOne(NULL, NULL, "dnd.ready disable");
-
-   DnDGHFileListClear();
-
-   /* Unregister source for Host->Guest DnD. */
-   gtk_drag_source_unset(hgWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(hgWnd),
-                                 GTK_SIGNAL_FUNC(DnDGtkBeginCB),
-                                 hgWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(hgWnd),
-                                 GTK_SIGNAL_FUNC(DnDGtkEndCB),
-                                 hgWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(hgWnd),
-                                 GTK_SIGNAL_FUNC(DnDGtkDataRequestCB),
-                                 hgWnd);
-
-   /* Unregister destination for Guest->Host DnD. */
-   gtk_drag_dest_unset(ghWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(ghWnd),
-                                 GTK_SIGNAL_FUNC(DnDGtkDragMotionCB),
-                                 ghWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(ghWnd),
-                                 GTK_SIGNAL_FUNC(DnDGtkDragDataReceivedCB),
-                                 ghWnd);
-   gtk_signal_disconnect_by_func(GTK_OBJECT(ghWnd),
-                                 GTK_SIGNAL_FUNC(DnDGtkDragDropCB),
-                                 ghWnd);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnD_OnReset --
- *
- *    Handles reinitializing DnD state on a reset.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    DnD is stopped and restarted.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-DnD_OnReset(GtkWidget *hgWnd,   // IN: The widget for hg dnd
-            GtkWidget *ghWnd)   // IN: The widget for gh dnd
-
-{
-   Debug("DnD_OnReset: entry\n");
-
-   /* Cancel file transfer. */
-   if (gHGDnDInProgress || gHGDataPending) {
-      DnD_DeleteStagingFiles(gFileRoot, FALSE);
-      if (gBlockFd >= 0 && !DnD_RemoveBlock(gBlockFd, gFileRoot)) {
-         Warning("DnD_OnReset: could not remove block on %s\n",
-                 gFileRoot);
-      }
-   }
-
-   /*
-    * If a DnD in either direction was in progress during suspend, send an
-    * escape to cancel the operation and reset the pointer state.
-    */
-   if (gHGDnDInProgress) {
-      Debug("DnD_OnReset: sending hgWnd escape\n");
-      DnDSendEscapeKey(hgWnd);
-   }
-
-   if (gGHState.dragInProgress) {
-      Debug("DnD_OnReset: sending ghWnd escape\n");
-      DnDSendEscapeKey(ghWnd);
-   }
-
-   if (gGHState.dragInProgress) {
-      Debug("DnD_OnReset: canceling host->guest DnD\n");
-      DnDGHCancel(ghWnd);
-   }
-
-   /* Reset DnD state. */
-   DnDHGStateInit();
-   DnDGHStateInit(ghWnd);
-   DnDGHFileListClear();
-   DnD_SetMode(FALSE);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnD_InProgress --
- *
- *    Indicates whether a DnD (or its data transfer) is currently in progress.
- *
- * Results:
- *    TRUE if a DnD is in progress, FALSE otherwise.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-DnD_InProgress(void)
-{
-   return gGHState.dragInProgress || gHGDnDInProgress || gHGDataPending;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * DnD_SetMode --
- *
- *      Sets dnd mode to single window or unity mode.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      Controls if the g->h det window is automatically hidden.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-DnD_SetMode(Bool unity) // IN
-{
-   gUnity = unity;
-}
index e489d88f5e5cdbd0c3029b63efca0810514155f3..2f8a9037349bc40d7d664749181d64453f9cb03a 100644 (file)
@@ -25,7 +25,7 @@
  * user.
  */
 
-#include "copyPasteWrapper.h"
+#include "copyPasteDnDWrapper.h"
 
 extern "C" {
 #include <errno.h>
@@ -134,7 +134,7 @@ static Bool gSigExit;           // Set by all but SIGUSR1; triggers app shutdown
  */
 RpcIn *gRpcIn;
 Display *gXDisplay;
-GtkWidget *gUserMainWidget;
+GtkWidget *gUserMainWidget = NULL;
 
 GtkWidget *gHGWnd;
 GtkWidget *gGHWnd;
@@ -145,7 +145,7 @@ Bool optionDnD;
 Bool gCanUseVMwareCtrl;
 Bool gCanUseVMwareCtrlTopologySet;
 guint gTimeoutId;
-int gBlockFd;
+int gBlockFd = -1;
 
 /*
  * All signals that:
@@ -204,7 +204,7 @@ void VMwareUserCleanupRpc(void)
          gDnDRegistered = FALSE;
       }
 
-      CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+      CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
       if (p && p->IsRegistered()) {
          p->Unregister();
       }
@@ -375,7 +375,7 @@ VMwareUserRpcInResetCB(RpcInData *data)   // IN/OUT
    if (gDnDRegistered) {
       DnD_OnReset(gHGWnd, gGHWnd);
    }
-   CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+   CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
    if (p) {
       p->OnReset();
    }
@@ -472,7 +472,7 @@ VMwareUserRpcInCapRegCB(char const **result,     // OUT
  *
  * VMwareUserRegisterCopyPaste
  *
- *      Call the CopyPasteWrapper singleton to register, or unregister,
+ *      Call the CopyPasteDnDWrapper singleton to register, or unregister,
  *      copy and paste with the host. The wrapper class will try whatever
  *      versions are supported, in highest to lowest order when registering.
  *
@@ -488,7 +488,7 @@ VMwareUserRpcInCapRegCB(char const **result,     // OUT
 static void
 VMwareUserRegisterCopyPaste(bool reg)  // IN: if TRUE, register, else unregister
 {
-   CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+   CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
    if (p) {
       p->SetUserData(static_cast<void *>(gUserMainWidget));
       if (reg) {
@@ -770,6 +770,7 @@ main(int argc, char *argv[])
    gtk_init(&argc, &argv);
 #endif
 
+
    /*
     * Running more than 1 VMware user process (vmware-user) per X11 session
     * invites bad juju.  The following routine ensures that only one instance
@@ -856,14 +857,23 @@ main(int argc, char *argv[])
     * initialize it and pass block fd in. If manually run vmware-user, here will
     * try to initialize the blocking driver.
     */
+
    if (gBlockFd < 0) {
       gBlockFd = DnD_InitializeBlocking();
       if (gBlockFd < 0) {
-         Warning("vmware-user failed to initialize blocking driver.\n");
+         Debug("%s: vmware-user failed to initialize blocking driver.\n",
+         __FUNCTION__);
       }
    }
 
    gUserMainWidget = VMwareUser_CreateWindow();
+
+   CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
+   if (p) {
+      p->SetUserData(static_cast<void *>(gUserMainWidget));
+      p->SetBlockFd(gBlockFd);
+   }
+
    gHGWnd = VMwareUser_CreateWindow();
    gGHWnd = VMwareUser_CreateWindow();
    /*
@@ -969,7 +979,7 @@ main(int argc, char *argv[])
             DnD_Unregister(gHGWnd, gGHWnd);
             gDnDRegistered = FALSE;
          }
-         CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+         CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
          if (p) {
             p->Unregister();
          }