+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.
SUBDIRS =
SUBDIRS += lib
+SUBDIRS += libvmtools
SUBDIRS += guestd
if HAVE_X11
SUBDIRS += $(X11_SUBDIRS)
endif
SUBDIRS += checkvm
SUBDIRS += libguestlib
-SUBDIRS += libvmtools
+SUBDIRS += rpctool
SUBDIRS += scripts
SUBDIRS += services
SUBDIRS += toolbox
+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.
# 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
################################################################################
###
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
;;
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.
# 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
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
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
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")
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
lib/sync/Makefile \
lib/syncDriver/Makefile \
lib/system/Makefile \
- lib/toolsLogger/Makefile \
lib/unicode/Makefile \
lib/unity/Makefile \
lib/unityStub/Makefile \
hgfsclient/Makefile \
hgfsmounter/Makefile \
checkvm/Makefile \
+ rpctool/Makefile \
libguestlib/Makefile \
libvmtools/Makefile \
xferlogs/Makefile \
################################################################################
sbin_PROGRAMS = vmware-guestd
-pamdir = $(PAM_PREFIX)/pam.d
AM_CFLAGS = -I$(top_builddir)/include
AM_CFLAGS += -I$(top_srcdir)/services/plugins/vix
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
# 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"
#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:
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 */
-
/*
*-----------------------------------------------------------------------------
#endif
struct timeval tv;
int status;
-#if defined(VM_GUESTD_RUNS_HGFS_PSERVER)
- PserverState *pState = &globalHgfsState;
-#endif
ASSERT(tdData);
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,
} 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 */
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,
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");
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);
}
/*
* 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);
}
#include "foundryToolsDaemon.h"
#include "util.h"
#include "vmcheck.h"
+#include "guestInfo.h"
#ifndef N_PLAT_NLM
#include "vm_atomic.h"
for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
if (strcmp(name, stateChangeCmdTable[i].tcloCmd) == 0) {
- const char *script;
+ char *script;
char *scriptCmd;
unsigned int stateId;
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;
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",
unsigned int minResolutionHeight;
#endif
ToolsDaemon_Data *data;
+ uint32 version;
data = (ToolsDaemon_Data *)clientData;
ASSERT(data);
* 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");
}
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);
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@
#include "vmware.h"
#include "guestApp.h"
#include "vmcheck.h"
-#include "toolsLogger.h"
#include "escBitvector.h"
#include "hgfsEscape.h"
#include "hgfs.h"
#include "hgfsProto.h"
#include "conf.h"
#include "str.h"
+#include "vmtools.h"
#include "hgfsclient_version.h"
#include "embed_version.h"
RpcOut *gChannel = NULL;
char *gPacketBuffer = NULL;
-static GuestApp_Dict *gConfDict = NULL;
static Bool HgfsClient_Open(HgfsHandle *rootHandle);
static HgfsFileName *HgfsClient_Read(HgfsHandle rootHandle,
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();
-}
-
/*
*-----------------------------------------------------------------------------
*
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");
success = FALSE;
}
}
- ToolsLogger_Cleanup();
- if (gConfDict) {
- GuestApp_FreeDict(gConfDict);
- }
return success;
}
+++ /dev/null
-/*********************************************************
- * 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();
-}
-
SUBDIRS += sync
SUBDIRS += syncDriver
SUBDIRS += system
-SUBDIRS += toolsLogger
SUBDIRS += unicode
if ENABLE_UNITY
SUBDIRS += unity
"python2.4",
"python2.3",
"python2.2",
- "perl"
+ "perl",
+ "sh",
+ "bash",
};
char cbuf[PATH_MAX];
int i;
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
FileIOResult fretR;
do {
- unsigned char buf[1024];
+ unsigned char buf[8 * 1024];
size_t actual;
FileIOResult fretW;
result = FALSE;
}
+ if (result == FALSE) {
+ /* The copy failed: ensure the destination file is removed */
+ File_Unlink(dstName);
+ }
+
return result;
}
result = FALSE;
}
+ if (result == FALSE) {
+ /* The copy failed: ensure the destination file is removed */
+ File_Unlink(dstName);
+ }
+
return result;
}
*----------------------------------------------------------------------
*
* 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.
*
*----------------------------------------------------------------------
*/
{
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) {
* 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.
*
*-----------------------------------------------------------------------------
*/
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",
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),
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;
GHITcloSetGuestHandler, NULL);
RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_RESTORE_DEFAULT_GUEST_HANDLER,
GHITcloRestoreDefaultGuestHandler, NULL);
+ RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_OUTLOOK_SET_TEMP_FOLDER,
+ GHITcloSetOutlookTempFolder, NULL);
}
}
}
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;
+}
+
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);
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;
+}
+
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) {
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;
};
#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"
#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.
*
*********************************************************/
-/*
- * 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_
#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
#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,
* 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);
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_
*
*********************************************************/
-/*
- * 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;
#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"
#define STR_OS_FREEBSD "FreeBSD"
/* Solaris */
-#define STR_OS_SOLARIS "Solaris"
+#define STR_OS_SOLARIS "solaris"
/* All */
#define STR_OS_64BIT_SUFFIX "-64"
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);
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);
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);
# 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
#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"
+++ /dev/null
-/*********************************************************
- * 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__ */
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);
/*
*-----------------------------------------------------------------------------
#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"
/* @} */
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,
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
#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;
#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
*
* 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."
/*
|| 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
#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)
/*
/*
* 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"
*/
#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.
*
#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
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)
{
#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
}
-/*
- *----------------------------------------------------------------------------
- *
- * 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
/*
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
}
/*
- * 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;
}
}
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;
#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;
}
}
} 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")) {
} 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) {
return FALSE;
}
- Str_Strcpy(osName, STR_OS_SOLARIS, outBufLen);
+ Str_Snprintf(osName, outBufLen, "%s%s", STR_OS_SOLARIS, solarisRelease);
}
if (Hostinfo_GetSystemBitness() == 64) {
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);
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.
#include "user_layout.h"
#endif
+#if !defined(N_PLAT_NLM)
/*
*-----------------------------------------------------------------------------
*
#endif
return canonicalPath;
}
+#endif
#if defined(_WIN32)
#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.
*
*----------------------------------------------------------------------
*/
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);
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 { */
{
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
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;
}
}
/* 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 /* } */
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;
va_end(aq);
}
#else
- retval = bsd_vsnprintf(&str, size, format, ap);
+ retval = vsnprintf(str, size, format, ap);
#endif
/*
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);
+++ /dev/null
-/*********************************************************
- * 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;
-}
+++ /dev/null
-/*********************************************************
- * 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__ */
*
* 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.
*-----------------------------------------------------------------------------
*/
-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);
while (srcList[length] != NULL) {
length++;
}
-
+
/* Include the sentinel element. */
length++;
}
#include <ctype.h>
#include <string.h>
+#include <stdio.h>
#include "unicodeBase.h"
#include "unicodeInt.h"
#include "vm_assert.h"
#include "util.h"
#include "hashTable.h"
+#include "vm_atomic.h"
static char *UnicodeNormalizeEncodingName(const char *encoding);
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
*
* 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).
#include "appUtil.h"
#include <stdio.h>
+
/*
* Singleton object for tracking the state of the service.
*/
Bool forceEnable;
Bool isEnabled;
UnityVirtualDesktopArray virtDesktopArray; // Virtual desktop configuration
-
+ UnityUpdateChannel updateChannel; // Unity update transmission channel.
UnityPlatform *up; // Platform-specific state
} UnityState;
*/
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.
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);
}
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();
/*
*-----------------------------------------------------------------------------
*
- * UnityUpdateThreadInit --
+ * UnityUpdateChannelInit --
*
* Initialize the state for the update thread.
*
*/
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;
}
/*
*-----------------------------------------------------------------------------
*
- * UnityUpdateThreadCleanup --
+ * UnityUpdateChannelCleanup --
*
* Cleanup the unity update thread state.
*
*/
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
/*
* 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.
*
*/
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)) {
/*
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;
}
*
*********************************************************/
-/*
- * 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;
Bool UnityPlatformIsSupported(void);
UnityPlatform *UnityPlatformInit(UnityWindowTracker *tracker,
+ UnityUpdateChannel *updateChannel,
int* blockedWnd);
void UnityPlatformCleanup(UnityPlatform *up);
void UnityPlatformRegisterCaps(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
*
*********************************************************/
-/*
- * 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"
*/
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.
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);
up->display = NULL;
}
- UnityUpdateThreadCleanup(&up->updateData);
-
free(up->desktopInfo.guestDesktopToUnity);
up->desktopInfo.guestDesktopToUnity = NULL;
free(up->desktopInfo.unityDesktopToGuest);
}
-/*
- *-----------------------------------------------------------------------------
- *
- * 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
Bool restackDetWnd = FALSE;
ASSERT(up);
+ ASSERT(up->isRunning);
if (errorOccurred) {
/*
UnityPlatformStackDnDDetWnd(up);
}
UnityPlatformUpdateZOrder(up);
- UnityPlatformSendPendingUpdates(up, UNITY_UPDATE_INCREMENTAL);
+ UnityPlatformDoUpdate(up, TRUE);
}
return TRUE;
}
-/*
- *-----------------------------------------------------------------------------
- *
- * 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);
-}
-
-
/*
*----------------------------------------------------------------------------
*
{
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;
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");
+ }
+ }
+}
}
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. */
__FUNCTION__);
}
- UnityPlatformSendPendingUpdates(up, UNITY_UPDATE_INCREMENTAL);
+ UnityPlatformDoUpdate(up, TRUE);
}
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
/*
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;
}
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,
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};
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");
ASSERT(desktopId < up->desktopInfo.numDesktops);
guestDesktopId = up->desktopInfo.unityDesktopToGuest[desktopId];
- UPWindowSetEWMHDesktop(up, upw, guestDesktopId);
+ UPWindow_SetEWMHDesktop(up, upw, guestDesktopId);
return TRUE;
}
/*
*------------------------------------------------------------------------------
*
- * UPWindowSetEWMHDesktop --
+ * UPWindow_SetEWMHDesktop --
*
* Move the window to the specified desktop. ewmhDesktopId corresponds
* to a desktop index to be used with _NET_WM_DESKTOP.
*/
-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.
/*
* 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,
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;
+}
_NET_SUPPORTED,
_NET_FRAME_EXTENTS,
WM_CLASS,
+ WM_CLIENT_LEADER,
WM_DELETE_WINDOW,
WM_ICON,
WM_NAME,
} atoms;
UnityWindowTracker *tracker;
- UnityUpdateThreadData updateData;
+ UnityUpdateChannel *updateChannel;
/*
* This tracks all toplevel windows, whether or not they are showing through to the
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);
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,
#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"
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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);
+}
+
+
/*
*----------------------------------------------------------------------
*
*
* 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:
}
}
-#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();
}
}
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);
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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;
+}
+
# include "netutil.h"
#endif
+#include "vm_assert.h"
#include "vmtools.h"
#include "wiper.h"
VM_EMBED_VERSION(VMTOOLSLIB_VERSION_STRING);
#endif
-extern void VMTools_InitLogging(void);
+extern void VMTools_ResetLogging(gboolean cleanDefault);
/**
#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
}
#if defined(_WIN32)
NetUtil_FreeIpHlpApiDll();
#endif
+ VMTools_ResetLogging(TRUE);
}
#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"
# include "coreDump.h"
#endif
#include "file.h"
+#include "hostinfo.h"
#include "str.h"
#include "system.h"
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;
static guint gPanicCount = 0;
static LogHandlerData *gDefaultData = NULL;
static GLogFunc gDefaultLogFunc = DEFAULT_HANDLER;
+static GPtrArray *gDomains = NULL;
/* Internal functions. */
VMToolsLogOpenFile(const gchar *path)
{
FILE *logfile = NULL;
+ gchar *pathLocal;
g_assert(path != NULL);
if (File_Exists(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;
}
}
-/**
- * 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
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)
}
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);
gchar **list;
gchar **curr;
+ VMTools_ResetLogging(FALSE);
+
if (!g_key_file_has_group(cfg, LOGGING_GROUP)) {
return;
}
}
+/**
+ * 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. */
/**
$(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
* 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
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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
+
+
/*
*-----------------------------------------------------------------------------
*
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.
#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;
#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
#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
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()
};
*/
{
* 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];
vrele(fvp);
return EXDEV;
}
-
+
return VMBlockVopBypass((struct vop_generic_args *)ap);
}
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;
* 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
#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;
#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
#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
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)
{
#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;
#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
#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
* 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 **************************/
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; \
$(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) \
* Command descriptors.
*/
-struct CmdDescIssueSCSI {
+typedef struct CmdDescIssueSCSI {
PA reqAddr;
PA cmpAddr;
-};
+} CmdDescIssueSCSI;
struct CmdDescResetDevice {
uint32 target;
#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
#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;
#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
* 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 **************************/
$(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) \
/*
* 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) \
__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) \
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__ */
#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;
#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
$(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) \
/*
* 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) \
__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) \
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__ */
#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;
#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
* 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 **************************/
*
*********************************************************/
-/*
+/*
* 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);
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__ */
$(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) \
CC_OPTS += -DVMW_KMEMCR_HAS_DTOR
# Core driver components
-OBJS = bdhandler.o
+OBJS = bdhandler.o
OBJS += dentry.o
OBJS += dir.o
OBJS += file.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
/*
* 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) \
__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) \
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__ */
#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;
#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
#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
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)
{
$(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) \
/*
* 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) \
__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) \
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__ */
#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;
#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
$(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) \
$(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) \
# 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
# 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)
#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) && \
#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
#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
* 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 **************************/
#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"
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;
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';
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;
}
if (value.data) {
- struct Vmxnet_Private *lp = (struct Vmxnet_Private *)dev->priv;
+ struct Vmxnet_Private *lp = netdev_priv(dev);
if (!lp->tso) {
return -EINVAL;
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) */
{
#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)) {
}
}
- 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;
#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);
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
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);
}
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;
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;
#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;
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;
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;
}
}
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;
/* 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);
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);
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) {
}
- lp = (struct Vmxnet_Private *)dev->priv;
+ lp = netdev_priv(dev);
outl(VMXNET_CMD_INTR_ACK, dev->base_addr + VMXNET_COMMAND_ADDR);
dd = lp->dd;
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)
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;
dev->start = 0;
#endif
- compat_netif_stop_queue(dev);
+ netif_stop_queue(dev);
lp->devOpen = FALSE;
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;
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
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);
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;
}
$(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) \
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
| 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
--- /dev/null
+/*********************************************************
+ * 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);
+}
# 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
# 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)
#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) && \
#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
#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
* 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 **************************/
#endif
};
-static int disable_lro = 0;
+static int disable_lro;
/*
*----------------------------------------------------------------------------
{
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;
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);
#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);
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);
#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_ */
$(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) \
/*
* 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) \
__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) \
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__ */
#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;
#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
*
*********************************************************/
-/*
+/*
* 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);
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__ */
#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
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)
{
static void VSockVmciTestUnregister(void);
static int VSockVmciRegisterAddressFamily(void);
static void VSockVmciUnregisterAddressFamily(void);
+static int64 VSockVmciStreamHasData(VSockVmciSock *vsk);
+static int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk);
/* Socket operations. */
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;
* 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;
}
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
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;
}
VSockVmciRecvConnected(struct sock *sk, // IN
VSockPacket *pkt) // IN
{
+ VSockVmciSock *vsk;
+
ASSERT(sk);
ASSERT(pkt);
ASSERT(sk->compat_sk_state == SS_CONNECTED);
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:
}
+/*
+ *----------------------------------------------------------------------------
+ *
+ * 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.
*/
*/
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 {
/*
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) {
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)) {
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)) {
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;
}
* 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);
# 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
#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;
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;
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
* 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
# 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.
CFLAGS += $(GLOBAL_DEFS)
CFLAGS += $(CC_WARNINGS)
CFLAGS += -DVMX86_TOOLS
+CFLAGS += -I.
ifdef VMX86_DEVEL
CFLAGS += -DVMX86_DEVEL
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
--- /dev/null
+/*********************************************************
+ * 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 */
#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"
#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;
#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
#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
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)
{
#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
* 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 **************************/
--- /dev/null
+
+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.
+
--- /dev/null
+#!/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
--- /dev/null
+/*********************************************************
+ * 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
--- /dev/null
+/*********************************************************
+ * 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
--- /dev/null
+/*********************************************************
+ * 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
--- /dev/null
+/*********************************************************
+ * 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
--- /dev/null
+/*********************************************************
+ * 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_ */
--- /dev/null
+/*********************************************************
+ * 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 */
--- /dev/null
+/*********************************************************
+ * 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_
--- /dev/null
+/*********************************************************
+ * 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
--- /dev/null
+/*********************************************************
+ * 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
--- /dev/null
+/*********************************************************
+ * 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
+
--- /dev/null
+/*********************************************************
+ * 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_ */
--- /dev/null
+/*********************************************************
+ * 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);
+}
--- /dev/null
+/*********************************************************
+ * 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 = ∓
+ 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;
+}
--- /dev/null
+/*********************************************************
+ * 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_ */
--- /dev/null
+/*********************************************************
+ * 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_ */
--- /dev/null
+/*********************************************************
+ * 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;
+}
--- /dev/null
+/*********************************************************
+ * 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;
+}
--- /dev/null
+# 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;
--- /dev/null
+/*********************************************************
+ * 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_ */
################################################################################
-### 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
--- /dev/null
+/*********************************************************
+ * 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
+}
+
+
} GuestInfoCache;
-/*
- * Local variables.
- */
-static gboolean gDisableQueryDiskInfo = FALSE;
-
/* Local cache of the guest information that was last sent to vmx. */
static GuestInfoCache gInfoCache;
char name[255];
char osNameFull[MAX_VALUE_LEN];
char osName[MAX_VALUE_LEN];
+ gboolean disableQueryDiskInfo;
GuestNicList nicInfo;
GuestDiskInfo diskInfo;
#if defined(_WIN32) || defined(linux)
}
}
- 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 {
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);
{
#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
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);
}
}
}
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
GPid pid;
#endif
ToolsAppCtx *ctx;
+ gboolean scriptEnabled[GUESTOS_STATECHANGE_LAST];
} PowerOpState;
}
+/**
+ * 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.
*
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],
ToolsPluginSignalCb sigs[] = {
{ TOOLS_CORE_SIG_CAPABILITIES, PowerOpsCapabilityCb, NULL },
+ { TOOLS_CORE_SIG_SET_OPTION, PowerOpsSetOption, ®Data },
{ TOOLS_CORE_SIG_SHUTDOWN, PowerOpsShutdown, ®Data }
};
ToolsAppReg regs[] = {
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));
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.
*
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);
break;
default:
- g_error("Unexpected machine state: %d\n", gBackupState->machineState);
+ g_error("Unexpected machine state: %s\n",
+ VmBackupGetStateName(gBackupState->machineState));
}
exit:
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);
}
+/**
+ * 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.
*
{ 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 },
};
################################################################################
bin_PROGRAMS = vmtoolsd
+pamdir = $(PAM_PREFIX)/pam.d
+
vmtoolsd_CPPFLAGS =
vmtoolsd_CPPFLAGS += @VMTOOLS_CPPFLAGS@
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
/**
- * 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;
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:
gboolean ret = FALSE;
gboolean version = FALSE;
#if defined(G_PLATFORM_WIN32)
+ gboolean dumpState = FALSE;
gboolean kill = FALSE;
#endif
GOptionEntry clOptions[] = {
{ "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,
#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. */
}
+/**
+ * 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.
}
+/**
+ * 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.
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();
}
exit:
- if (state->configFile == NULL) {
- g_free(confFile);
- }
return (state->ctx.mainLoop != NULL);
}
int
ToolsCore_Run(ToolsServiceState *state)
{
+ g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreReloadConfig, state);
#if defined(__APPLE__)
ToolsCore_CFRunLoop(state);
#else
#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__)
}
+/**
+ * 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.
*
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;
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);
#include "vmtools.h"
+#ifdef USE_APPLOADER
+static Bool (*LoadDependencies)(char *libName);
+#endif
+
+
/**
* Compares two strings. To be used with g_ptr_array_sort.
*
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);
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;
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);
g_ptr_array_free(state->plugins, TRUE);
state->plugins = NULL;
}
-
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,
#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. */
typedef struct ToolsServiceState {
gchar *name;
gchar *configFile;
+ time_t configMtime;
gboolean log;
gboolean mainService;
gchar *pluginPath;
void
ToolsCore_Cleanup(ToolsServiceState *state);
+void
+ToolsCore_DumpState(ToolsServiceState *state);
+
const char *
ToolsCore_GetTcloName(ToolsServiceState *state);
static Bool
ToolsCoreRpcCapReg(RpcInData *data)
{
+ char *confPath = GuestApp_GetConfPath();
+ gchar *msg;
GArray *pcaps = NULL;
ToolsServiceState *state = data->clientData;
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)) {
g_free(toolsVersion);
}
+ free(confPath);
return RPCIN_SETRETVALS(data, "", TRUE);
}
#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"
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);
/*
*-----------------------------------------------------------------------------
*/
-void
+static void
ToolsMainCleanupRpc(void)
{
if (gRpcInCtlPanel) {
*-----------------------------------------------------------------------------
*/
-void ToolsMainSignalHandler(int sig) // IN
+static void
+ToolsMainSignalHandler(int sig) // IN
{
/* We want to kill the event manager before gtk_main_quit. */
ToolsMainCleanupRpc();
*-----------------------------------------------------------------------------
*/
-void
+static void
ToolsMain_OpenHelp(const char *help) // IN
{
char helpPage[1000];
*-----------------------------------------------------------------------------
*/
-void
+static void
ToolsMain_OnHelp(gpointer btn, // IN: Unused
gpointer data) // IN: notebook containing all tabs
{
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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;
+}
+
/*
*-----------------------------------------------------------------------------
*
*-----------------------------------------------------------------------------
*/
-void
+static void
ToolsMain_YesNoBoxOnClicked(GtkButton *btn, // IN: clicked button
gpointer user_data) // OUT: pointer to result value
{
*-----------------------------------------------------------------------------
*/
-void
+static void
ToolsMain_OnDestroy(GtkWidget *widget, // IN: Unused
gpointer data) // IN: Unused
{
*-----------------------------------------------------------------------------
*/
-gint
+static gint
EventQueuePump(gpointer data) // IN: Unused
{
int ret;
*-----------------------------------------------------------------------------
*/
-GtkWidget*
+static GtkWidget*
ToolsMain_Create(void)
{
GtkWidget *ToolsMain;
#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",
*-----------------------------------------------------------------------------
*/
-Bool
+static Bool
RpcInResetCB(RpcInData *data) // IN/OUT
{
Debug("----------toolbox: Received 'reset' from vmware\n");
*-----------------------------------------------------------------------------
*/
-void
+static void
RpcInErrorCB(void *clientdata, char const *status)
{
Warning("Error in the RPC recieve loop: %s\n", status);
*-----------------------------------------------------------------------------
*/
-Bool
+static Bool
RpcInSetOptionCB(char const **result, // OUT
size_t *resultLen, // OUT
const char *name, // IN
*-----------------------------------------------------------------------------
*/
-Bool
+static Bool
RpcInCapRegCB(char const **result, // OUT
size_t *resultLen, // OUT
const char *name, // 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.
*-----------------------------------------------------------------------------
*/
-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;
*-----------------------------------------------------------------------------
*/
-void
+static void
ShowUsage(char const *prog)
{
fprintf(stderr,
Debug_EnableToFile(g_key_file_get_string(pConfDict, "logging",
CONFNAME_LOGFILE, NULL),
FALSE);
- InitHelpDir(pConfDict);
+ InitHelpDir();
g_key_file_free(pConfDict);
optionAutoHide = FALSE;
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);
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
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));
g_free(msg);
}
-exit:
free(editor);
}
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
+++ /dev/null
-/*********************************************************
- * 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);
- }
-}
*********************************************************/
/**
- * @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"
/**
- * 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;
}
* Constructor.
*/
-CopyPasteWrapper::CopyPasteWrapper() :
+CopyPasteDnDWrapper::CopyPasteDnDWrapper() :
#if defined(HAVE_GTKMM)
m_copyPasteUI(NULL),
#endif
* Destructor.
*/
-CopyPasteWrapper::~CopyPasteWrapper()
+CopyPasteDnDWrapper::~CopyPasteDnDWrapper()
{
if (IsRegistered()) {
Unregister();
*/
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
*/
bool
-CopyPasteWrapper::Register()
+CopyPasteDnDWrapper::Register()
{
+ Debug("%s: mBlockFd %d\n", __FUNCTION__, mBlockFd);
if (IsRegistered()) {
return TRUE;
}
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);
}
#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();
}
*/
void
-CopyPasteWrapper::Unregister()
+CopyPasteDnDWrapper::Unregister()
{
if (!IsRegistered()) {
return;
*/
int
-CopyPasteWrapper::GetVersion()
+CopyPasteDnDWrapper::GetVersion()
{
if (IsRegistered()) {
m_version = CopyPaste_GetVmxCopyPasteVersion();
*/
void
-CopyPasteWrapper::SetIsRegistered(bool isRegistered)
+CopyPasteDnDWrapper::SetIsRegistered(bool isRegistered)
{
m_isRegistered = isRegistered;
}
*/
bool
-CopyPasteWrapper::IsRegistered()
+CopyPasteDnDWrapper::IsRegistered()
{
return m_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()) {
*********************************************************/
/**
- * @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;
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
#include "dndFileList.hh"
extern "C" {
+ #include "vmwareuserInt.h"
#include "vmblock.h"
#include "vm_app.h"
#include "file.h"
#include "debug.h"
#include "cpNameUtil.h"
#include "rpcout.h"
+ #include "eventManager.h"
}
/*
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);
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",
*
* 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.
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;
}
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__,
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) {
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());
* 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.
* 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.
*
* 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:
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
*/
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);
void *buf;
size_t sz;
+ Debug("%s: enter\n", __FUNCTION__);
if (!clip) {
Debug("%s: No clipboard contents.", __FUNCTION__);
return;
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;
-}
-
-
/*
*-----------------------------------------------------------------------------
*
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;
}
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 */
// Member variables
CopyPaste mCP;
bool mClipboardEmpty;
- std::string mHGStagingDir;
+ utf::string mHGStagingDir;
std::list<Gtk::TargetEntry> mListTargets;
bool mIsClipboardOwner;
uint64 mClipTime;
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
+++ /dev/null
-/*********************************************************
- * 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;
-}
* user.
*/
-#include "copyPasteWrapper.h"
+#include "copyPasteDnDWrapper.h"
extern "C" {
#include <errno.h>
*/
RpcIn *gRpcIn;
Display *gXDisplay;
-GtkWidget *gUserMainWidget;
+GtkWidget *gUserMainWidget = NULL;
GtkWidget *gHGWnd;
GtkWidget *gGHWnd;
Bool gCanUseVMwareCtrl;
Bool gCanUseVMwareCtrlTopologySet;
guint gTimeoutId;
-int gBlockFd;
+int gBlockFd = -1;
/*
* All signals that:
gDnDRegistered = FALSE;
}
- CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+ CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
if (p && p->IsRegistered()) {
p->Unregister();
}
if (gDnDRegistered) {
DnD_OnReset(gHGWnd, gGHWnd);
}
- CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+ CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
if (p) {
p->OnReset();
}
*
* 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.
*
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) {
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
* 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();
/*
DnD_Unregister(gHGWnd, gGHWnd);
gDnDRegistered = FALSE;
}
- CopyPasteWrapper *p = CopyPasteWrapper::GetInstance();
+ CopyPasteDnDWrapper *p = CopyPasteDnDWrapper::GetInstance();
if (p) {
p->Unregister();
}