summaryrefslogtreecommitdiffstats
path: root/src/VBox/NetworkServices/IntNetSwitch
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
commit16f504a9dca3fe3b70568f67b7d41241ae485288 (patch)
treec60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/NetworkServices/IntNetSwitch
parentInitial commit. (diff)
downloadvirtualbox-upstream.tar.xz
virtualbox-upstream.zip
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/VBox/NetworkServices/IntNetSwitch/IntNetSwitchInternal.h109
-rw-r--r--src/VBox/NetworkServices/IntNetSwitch/Makefile.kmk75
-rw-r--r--src/VBox/NetworkServices/IntNetSwitch/SrvIntNetWrapper.cpp63
-rw-r--r--src/VBox/NetworkServices/IntNetSwitch/VBoxIntNetSwitch.cpp664
-rw-r--r--src/VBox/NetworkServices/IntNetSwitch/darwin/Info.plist22
5 files changed, 933 insertions, 0 deletions
diff --git a/src/VBox/NetworkServices/IntNetSwitch/IntNetSwitchInternal.h b/src/VBox/NetworkServices/IntNetSwitch/IntNetSwitchInternal.h
new file mode 100644
index 00000000..f0e98efd
--- /dev/null
+++ b/src/VBox/NetworkServices/IntNetSwitch/IntNetSwitchInternal.h
@@ -0,0 +1,109 @@
+/* $Id: IntNetSwitchInternal.h $ */
+/** @file
+ * VirtualBox internal network switch process - Internal header.
+ */
+
+/*
+ * Copyright (C) 2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * 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, in version 3 of the
+ * License.
+ *
+ * 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, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef VBOX_INCLUDED_SRC_IntNetSwitch_IntNetSwitchInternal_h
+#define VBOX_INCLUDED_SRC_IntNetSwitch_IntNetSwitchInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define IN_INTNET_TESTCASE
+#define IN_INTNET_R3
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+
+#undef INTNETR0DECL
+#define INTNETR0DECL INTNETR3DECL
+#undef DECLR0CALLBACKMEMBER
+#define DECLR0CALLBACKMEMBER(type, name, args) DECLR3CALLBACKMEMBER(type, name, args)
+typedef struct SUPDRVSESSION *MYPSUPDRVSESSION;
+#define PSUPDRVSESSION MYPSUPDRVSESSION
+
+#include <VBox/intnet.h>
+#include <VBox/sup.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+
+/**
+ * Security objectype.
+ */
+typedef enum SUPDRVOBJTYPE
+{
+ /** The usual invalid object. */
+ SUPDRVOBJTYPE_INVALID = 0,
+ /** Internal network. */
+ SUPDRVOBJTYPE_INTERNAL_NETWORK,
+ /** Internal network interface. */
+ SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE,
+ /** The first invalid object type in this end. */
+ SUPDRVOBJTYPE_END,
+ /** The usual 32-bit type size hack. */
+ SUPDRVOBJTYPE_32_BIT_HACK = 0x7ffffff
+} SUPDRVOBJTYPE;
+
+/**
+ * Object destructor callback.
+ * This is called for reference counted objectes when the count reaches 0.
+ *
+ * @param pvObj The object pointer.
+ * @param pvUser1 The first user argument.
+ * @param pvUser2 The second user argument.
+ */
+typedef DECLCALLBACKTYPE(void, FNSUPDRVDESTRUCTOR,(void *pvObj, void *pvUser1, void *pvUser2));
+/** Pointer to a FNSUPDRVDESTRUCTOR(). */
+typedef FNSUPDRVDESTRUCTOR *PFNSUPDRVDESTRUCTOR;
+
+
+RT_C_DECLS_BEGIN
+
+INTNETR3DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType,
+ PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2);
+INTNETR3DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking);
+INTNETR3DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession);
+INTNETR3DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession);
+INTNETR3DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName);
+INTNETR3DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3);
+INTNETR3DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr);
+
+
+RT_C_DECLS_END
+
+#endif /* !VBOX_INCLUDED_SRC_IntNetSwitch_IntNetSwitchInternal_h */
+
diff --git a/src/VBox/NetworkServices/IntNetSwitch/Makefile.kmk b/src/VBox/NetworkServices/IntNetSwitch/Makefile.kmk
new file mode 100644
index 00000000..b5256c55
--- /dev/null
+++ b/src/VBox/NetworkServices/IntNetSwitch/Makefile.kmk
@@ -0,0 +1,75 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-makefile for the Ring-3 based network switch process.
+#
+
+#
+# Copyright (C) 2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# 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, in version 3 of the
+# License.
+#
+# 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, see <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH := ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+#
+# The internal network switch module.
+#
+PROGRAMS += VBoxIntNetSwitch
+VBoxIntNetSwitch_TEMPLATE := VBOXR3EXE
+
+ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING
+VBoxIntNetSwitch_DEFS = KBUILD_TYPE="$(KBUILD_TYPE)"
+else
+VBoxIntNetSwitch_DEFS = KBUILD_TYPE=\"$(KBUILD_TYPE)\"
+endif
+VBoxIntNetSwitch_DEFS += VBOX_WITH_INTNET_SERVICE_IN_R3
+VBoxIntNetSwitch_INST.darwin = $(VBoxIntNetSwitch.xpc_INST)/MacOS/
+VBoxIntNetSwitch_SOURCES = \
+ VBoxIntNetSwitch.cpp \
+ SrvIntNetWrapper.cpp
+VBoxIntNetSwitch_LIBS = $(LIB_RUNTIME)
+VBoxIntNetSwitch_LDFLAGS.darwin = \
+ -rpath @executable_path/../../../../MacOS
+
+ifeq ($(KBUILD_TARGET),darwin)
+INSTALLS += VBoxIntNetSwitch.xpc
+
+VBoxIntNetSwitch.xpc_MODE = 644
+VBoxIntNetSwitch.xpc_INST = $(INST_VIRTUALBOX)Contents/XPCServices/org.virtualbox.intnet.xpc/Contents/
+VBoxIntNetSwitch.xpc_SOURCES = \
+ $(VBoxIntNetSwitch.xpc_0_OUTDIR)/Info.plist
+
+ $$(VBoxIntNetSwitch.xpc_0_OUTDIR)/Info.plist: $(PATH_SUB_CURRENT)/darwin/Info.plist $(VBOX_VERSION_MK) | $$(@D)/
+ $(call MSG_GENERATE,VBoxIntNetSwitch.xpc,$<,$@)
+ $(QUIET)$(RM) -f $@
+ $(QUIET)$(SED) \
+ -e 's+@VBOX_VERSION_STRING@+$(VBOX_VERSION_STRING)+g' \
+ -e 's+@VBOX_VERSION_MAJOR@+$(VBOX_VERSION_MAJOR)+g' \
+ -e 's+@VBOX_VERSION_MINOR@+$(VBOX_VERSION_MINOR)+g' \
+ -e 's+@VBOX_VERSION_BUILD@+$(VBOX_VERSION_BUILD)+g' \
+ -e 's+@VBOX_VENDOR@+$(VBOX_VENDOR)+g' \
+ -e 's+@VBOX_PRODUCT@+$(VBOX_PRODUCT)+g' \
+ -e 's+@VBOX_C_YEAR@+$(VBOX_C_YEAR)+g' \
+ $< > $@
+endif
+
+$(call VBOX_SET_VER_INFO_EXE,VBoxIntNetSwitch,VirtualBox Internal Network Switch,$(VBOX_WINDOWS_ICON_FILE)) # Version info / description.
+
+include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/NetworkServices/IntNetSwitch/SrvIntNetWrapper.cpp b/src/VBox/NetworkServices/IntNetSwitch/SrvIntNetWrapper.cpp
new file mode 100644
index 00000000..2cb8ba4a
--- /dev/null
+++ b/src/VBox/NetworkServices/IntNetSwitch/SrvIntNetWrapper.cpp
@@ -0,0 +1,63 @@
+/* $Id: SrvIntNetWrapper.cpp $ */
+/** @file
+ * Internal networking - Wrapper for the R0 network service.
+ *
+ * This is a bit hackish as we're mixing context here, however it is
+ * very useful when making changes to the internal networking service.
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * 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, in version 3 of the
+ * License.
+ *
+ * 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, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "IntNetSwitchInternal.h"
+
+#include <iprt/asm.h>
+#include <iprt/mp.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+
+/* Fake non-existing ring-0 APIs. */
+#define RTThreadIsInInterrupt(hThread) false
+#define RTThreadPreemptIsEnabled(hThread) true
+#define RTMpCpuId() 0
+
+/* No CLI/POPF, please. */
+#include <iprt/spinlock.h>
+#undef RTSPINLOCK_FLAGS_INTERRUPT_SAFE
+#define RTSPINLOCK_FLAGS_INTERRUPT_SAFE RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE
+
+
+/* ugly but necessary for making R0 code compilable for R3. */
+#undef LOG_GROUP
+#include "../../Devices/Network/SrvIntNetR0.cpp"
diff --git a/src/VBox/NetworkServices/IntNetSwitch/VBoxIntNetSwitch.cpp b/src/VBox/NetworkServices/IntNetSwitch/VBoxIntNetSwitch.cpp
new file mode 100644
index 00000000..f07c1166
--- /dev/null
+++ b/src/VBox/NetworkServices/IntNetSwitch/VBoxIntNetSwitch.cpp
@@ -0,0 +1,664 @@
+/* $Id: VBoxIntNetSwitch.cpp $ */
+/** @file
+ * Internal networking - Wrapper for the R0 network service.
+ *
+ * This is a bit hackish as we're mixing context here, however it is
+ * very useful when making changes to the internal networking service.
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * 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, in version 3 of the
+ * License.
+ *
+ * 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, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define IN_INTNET_TESTCASE
+#define IN_INTNET_R3
+#include "IntNetSwitchInternal.h"
+
+#include <VBox/err.h>
+#include <VBox/vmm/vmm.h>
+#include <iprt/asm.h>
+#include <iprt/critsect.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include <iprt/semaphore.h>
+#include <iprt/time.h>
+
+#include <xpc/xpc.h>
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+
+/**
+ * Registered object.
+ * This takes care of reference counting and tracking data for access checks.
+ */
+typedef struct SUPDRVOBJ
+{
+ /** Pointer to the next in the global list. */
+ struct SUPDRVOBJ * volatile pNext;
+ /** Pointer to the object destructor.
+ * This may be set to NULL if the image containing the destructor get unloaded. */
+ PFNSUPDRVDESTRUCTOR pfnDestructor;
+ /** User argument 1. */
+ void *pvUser1;
+ /** User argument 2. */
+ void *pvUser2;
+ /** The total sum of all per-session usage. */
+ uint32_t volatile cUsage;
+} SUPDRVOBJ, *PSUPDRVOBJ;
+
+
+/**
+ * The per-session object usage record.
+ */
+typedef struct SUPDRVUSAGE
+{
+ /** Pointer to the next in the list. */
+ struct SUPDRVUSAGE * volatile pNext;
+ /** Pointer to the object we're recording usage for. */
+ PSUPDRVOBJ pObj;
+ /** The usage count. */
+ uint32_t volatile cUsage;
+} SUPDRVUSAGE, *PSUPDRVUSAGE;
+
+
+/**
+ * Device extension.
+ */
+typedef struct SUPDRVDEVEXT
+{
+ /** Number of references to this service. */
+ uint32_t volatile cRefs;
+ /** Critical section to serialize the initialization, usage counting and objects. */
+ RTCRITSECT CritSect;
+ /** List of registered objects. Protected by the spinlock. */
+ PSUPDRVOBJ volatile pObjs;
+} SUPDRVDEVEXT;
+typedef SUPDRVDEVEXT *PSUPDRVDEVEXT;
+
+
+/**
+ * Per session data.
+ * This is mainly for memory tracking.
+ */
+typedef struct SUPDRVSESSION
+{
+ PSUPDRVDEVEXT pDevExt;
+ /** List of generic usage records. (protected by SUPDRVDEVEXT::CritSect) */
+ PSUPDRVUSAGE volatile pUsage;
+ /** The XPC connection handle for this session. */
+ xpc_connection_t hXpcCon;
+ /** The intnet interface handle to wait on. */
+ INTNETIFHANDLE hIfWait;
+ /** Flag whether a receive wait was initiated. */
+ bool volatile fRecvWait;
+ /** Flag whether there is something to receive. */
+ bool volatile fRecvAvail;
+} SUPDRVSESSION;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static SUPDRVDEVEXT g_DevExt;
+
+
+INTNETR3DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType,
+ PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2)
+{
+ RT_NOREF(enmType);
+
+ PSUPDRVOBJ pObj = (PSUPDRVOBJ)RTMemAllocZ(sizeof(*pObj));
+ if (!pObj)
+ return NULL;
+ pObj->cUsage = 1;
+ pObj->pfnDestructor = pfnDestructor;
+ pObj->pvUser1 = pvUser1;
+ pObj->pvUser2 = pvUser2;
+
+ /*
+ * Insert the object and create the session usage record.
+ */
+ PSUPDRVUSAGE pUsage = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsage));
+ if (!pUsage)
+ {
+ RTMemFree(pObj);
+ return NULL;
+ }
+
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ RTCritSectEnter(&pDevExt->CritSect);
+
+ /* The object. */
+ pObj->pNext = pDevExt->pObjs;
+ pDevExt->pObjs = pObj;
+
+ /* The session record. */
+ pUsage->cUsage = 1;
+ pUsage->pObj = pObj;
+ pUsage->pNext = pSession->pUsage;
+ pSession->pUsage = pUsage;
+
+ RTCritSectLeave(&pDevExt->CritSect);
+ return pObj;
+}
+
+
+INTNETR3DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking)
+{
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
+ int rc = VINF_SUCCESS;
+ PSUPDRVUSAGE pUsage;
+
+ RT_NOREF(fNoBlocking);
+
+ RTCritSectEnter(&pDevExt->CritSect);
+
+ /*
+ * Reference the object.
+ */
+ ASMAtomicIncU32(&pObj->cUsage);
+
+ /*
+ * Look for the session record.
+ */
+ for (pUsage = pSession->pUsage; pUsage; pUsage = pUsage->pNext)
+ {
+ if (pUsage->pObj == pObj)
+ break;
+ }
+
+ if (pUsage)
+ pUsage->cUsage++;
+ else
+ {
+ /* create a new session record. */
+ pUsage = (PSUPDRVUSAGE)RTMemAlloc(sizeof(*pUsage));
+ if (RT_LIKELY(pUsage))
+ {
+ pUsage->cUsage = 1;
+ pUsage->pObj = pObj;
+ pUsage->pNext = pSession->pUsage;
+ pSession->pUsage = pUsage;
+ }
+ else
+ {
+ ASMAtomicDecU32(&pObj->cUsage);
+ rc = VERR_TRY_AGAIN;
+ }
+ }
+
+ RTCritSectLeave(&pDevExt->CritSect);
+ return rc;
+}
+
+
+INTNETR3DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession)
+{
+ return SUPR0ObjAddRefEx(pvObj, pSession, false);
+}
+
+
+INTNETR3DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession)
+{
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ PSUPDRVOBJ pObj = (PSUPDRVOBJ)pvObj;
+ int rc = VERR_INVALID_PARAMETER;
+ PSUPDRVUSAGE pUsage;
+ PSUPDRVUSAGE pUsagePrev;
+
+ /*
+ * Acquire the spinlock and look for the usage record.
+ */
+ RTCritSectEnter(&pDevExt->CritSect);
+
+ for (pUsagePrev = NULL, pUsage = pSession->pUsage;
+ pUsage;
+ pUsagePrev = pUsage, pUsage = pUsage->pNext)
+ {
+ if (pUsage->pObj == pObj)
+ {
+ rc = VINF_SUCCESS;
+ AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
+ if (pUsage->cUsage > 1)
+ {
+ pObj->cUsage--;
+ pUsage->cUsage--;
+ }
+ else
+ {
+ /*
+ * Free the session record.
+ */
+ if (pUsagePrev)
+ pUsagePrev->pNext = pUsage->pNext;
+ else
+ pSession->pUsage = pUsage->pNext;
+ RTMemFree(pUsage);
+
+ /* What about the object? */
+ if (pObj->cUsage > 1)
+ pObj->cUsage--;
+ else
+ {
+ /*
+ * Object is to be destroyed, unlink it.
+ */
+ rc = VINF_OBJECT_DESTROYED;
+ if (pDevExt->pObjs == pObj)
+ pDevExt->pObjs = pObj->pNext;
+ else
+ {
+ PSUPDRVOBJ pObjPrev;
+ for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
+ if (pObjPrev->pNext == pObj)
+ {
+ pObjPrev->pNext = pObj->pNext;
+ break;
+ }
+ Assert(pObjPrev);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ RTCritSectLeave(&pDevExt->CritSect);
+
+ /*
+ * Call the destructor and free the object if required.
+ */
+ if (rc == VINF_OBJECT_DESTROYED)
+ {
+ if (pObj->pfnDestructor)
+ pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
+ RTMemFree(pObj);
+ }
+
+ return rc;
+}
+
+
+INTNETR3DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName)
+{
+ RT_NOREF(pvObj, pSession, pszObjName);
+ return VINF_SUCCESS;
+}
+
+
+INTNETR3DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
+{
+ RT_NOREF(pSession);
+
+ /*
+ * This is used to allocate and map the send/receive buffers into the callers process space, meaning
+ * we have to mmap it with the shareable attribute.
+ */
+ void *pv = mmap(NULL, cb, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
+ if (pv == MAP_FAILED)
+ return VERR_NO_MEMORY;
+
+ *ppvR0 = (RTR0PTR)pv;
+ if (ppvR3)
+ *ppvR3 = pv;
+ return VINF_SUCCESS;
+}
+
+
+INTNETR3DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr)
+{
+ RT_NOREF(pSession);
+
+ PINTNETBUF pBuf = (PINTNETBUF)uPtr; /// @todo Hack hack hack!
+ munmap((void *)uPtr, pBuf->cbBuf);
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Destroys the given internal network XPC connection session freeing all allocated resources.
+ *
+ * @returns Reference count of the device extension..
+ * @param pSession The ession to destroy.
+ */
+static uint32_t intnetR3SessionDestroy(PSUPDRVSESSION pSession)
+{
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+ uint32_t cRefs = ASMAtomicDecU32(&pDevExt->cRefs);
+ xpc_transaction_end();
+ xpc_connection_set_context(pSession->hXpcCon, NULL);
+ xpc_connection_cancel(pSession->hXpcCon);
+ pSession->hXpcCon = NULL;
+
+ ASMAtomicXchgBool(&pSession->fRecvAvail, true);
+
+ if (pSession->pUsage)
+ {
+ PSUPDRVUSAGE pUsage;
+ RTCritSectEnter(&pDevExt->CritSect);
+
+ while ((pUsage = pSession->pUsage) != NULL)
+ {
+ PSUPDRVOBJ pObj = pUsage->pObj;
+ pSession->pUsage = pUsage->pNext;
+
+ AssertMsg(pUsage->cUsage >= 1 && pObj->cUsage >= pUsage->cUsage, ("glob %d; sess %d\n", pObj->cUsage, pUsage->cUsage));
+ if (pUsage->cUsage < pObj->cUsage)
+ {
+ pObj->cUsage -= pUsage->cUsage;
+ }
+ else
+ {
+ /* Destroy the object and free the record. */
+ if (pDevExt->pObjs == pObj)
+ pDevExt->pObjs = pObj->pNext;
+ else
+ {
+ PSUPDRVOBJ pObjPrev;
+ for (pObjPrev = pDevExt->pObjs; pObjPrev; pObjPrev = pObjPrev->pNext)
+ if (pObjPrev->pNext == pObj)
+ {
+ pObjPrev->pNext = pObj->pNext;
+ break;
+ }
+ Assert(pObjPrev);
+ }
+
+ RTCritSectLeave(&pDevExt->CritSect);
+
+ if (pObj->pfnDestructor)
+ pObj->pfnDestructor(pObj, pObj->pvUser1, pObj->pvUser2);
+ RTMemFree(pObj);
+
+ RTCritSectEnter(&pDevExt->CritSect);
+ }
+
+ /* free it and continue. */
+ RTMemFree(pUsage);
+ }
+
+ RTCritSectLeave(&pDevExt->CritSect);
+ AssertMsg(!pSession->pUsage, ("Some buster reregistered an object during destruction!\n"));
+ }
+
+ RTMemFree(pSession);
+ return cRefs;
+}
+
+
+/**
+ * Data available in th receive buffer callback.
+ */
+static DECLCALLBACK(void) intnetR3RecvAvail(INTNETIFHANDLE hIf, void *pvUser)
+{
+ RT_NOREF(hIf);
+ PSUPDRVSESSION pSession = (PSUPDRVSESSION)pvUser;
+
+ if (ASMAtomicXchgBool(&pSession->fRecvWait, false))
+ {
+ /* Send an empty message. */
+ xpc_object_t hObjPoke = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_connection_send_message(pSession->hXpcCon, hObjPoke);
+ }
+ else
+ ASMAtomicXchgBool(&pSession->fRecvAvail, true);
+}
+
+
+static void intnetR3RequestProcess(xpc_connection_t hCon, xpc_object_t hObj, PSUPDRVSESSION pSession)
+{
+ int rc = VINF_SUCCESS;
+ uint64_t iReq = xpc_dictionary_get_uint64(hObj, "req-id");
+ size_t cbReq = 0;
+ const void *pvReq = xpc_dictionary_get_data(hObj, "req", &cbReq);
+ union
+ {
+ INTNETOPENREQ OpenReq;
+ INTNETIFCLOSEREQ IfCloseReq;
+ INTNETIFGETBUFFERPTRSREQ IfGetBufferPtrsReq;
+ INTNETIFSETPROMISCUOUSMODEREQ IfSetPromiscuousModeReq;
+ INTNETIFSETMACADDRESSREQ IfSetMacAddressReq;
+ INTNETIFSETACTIVEREQ IfSetActiveReq;
+ INTNETIFSENDREQ IfSendReq;
+ INTNETIFWAITREQ IfWaitReq;
+ INTNETIFABORTWAITREQ IfAbortWaitReq;
+ } ReqReply;
+
+ memcpy(&ReqReply, pvReq, RT_MIN(sizeof(ReqReply), cbReq));
+ size_t cbReply = 0;
+
+ if (pvReq)
+ {
+ switch (iReq)
+ {
+ case VMMR0_DO_INTNET_OPEN:
+ {
+ if (cbReq == sizeof(INTNETOPENREQ))
+ {
+ rc = IntNetR3Open(pSession, &ReqReply.OpenReq.szNetwork[0], ReqReply.OpenReq.enmTrunkType, ReqReply.OpenReq.szTrunk,
+ ReqReply.OpenReq.fFlags, ReqReply.OpenReq.cbSend, ReqReply.OpenReq.cbRecv,
+ intnetR3RecvAvail, pSession, &ReqReply.OpenReq.hIf);
+ cbReply = sizeof(INTNETOPENREQ);
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_CLOSE:
+ {
+ if (cbReq == sizeof(INTNETIFCLOSEREQ))
+ {
+ rc = IntNetR0IfCloseReq(pSession, &ReqReply.IfCloseReq);
+ cbReply = sizeof(INTNETIFCLOSEREQ);
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS:
+ {
+ if (cbReq == sizeof(INTNETIFGETBUFFERPTRSREQ))
+ {
+ rc = IntNetR0IfGetBufferPtrsReq(pSession, &ReqReply.IfGetBufferPtrsReq);
+ /* This is special as we need to return a shared memory segment. */
+ xpc_object_t hObjReply = xpc_dictionary_create_reply(hObj);
+ xpc_object_t hObjShMem = xpc_shmem_create(ReqReply.IfGetBufferPtrsReq.pRing3Buf, ReqReply.IfGetBufferPtrsReq.pRing3Buf->cbBuf);
+ if (hObjShMem)
+ {
+ xpc_dictionary_set_value(hObjReply, "buf-ptr", hObjShMem);
+ xpc_release(hObjShMem);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ xpc_dictionary_set_uint64(hObjReply, "rc", INTNET_R3_SVC_SET_RC(rc));
+ xpc_connection_send_message(hCon, hObjReply);
+ return;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE:
+ {
+ if (cbReq == sizeof(INTNETIFSETPROMISCUOUSMODEREQ))
+ {
+ rc = IntNetR0IfSetPromiscuousModeReq(pSession, &ReqReply.IfSetPromiscuousModeReq);
+ cbReply = sizeof(INTNETIFSETPROMISCUOUSMODEREQ);
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS:
+ {
+ if (cbReq == sizeof(INTNETIFSETMACADDRESSREQ))
+ {
+ rc = IntNetR0IfSetMacAddressReq(pSession, &ReqReply.IfSetMacAddressReq);
+ cbReply = sizeof(INTNETIFSETMACADDRESSREQ);
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_SET_ACTIVE:
+ {
+ if (cbReq == sizeof(INTNETIFSETACTIVEREQ))
+ {
+ rc = IntNetR0IfSetActiveReq(pSession, &ReqReply.IfSetActiveReq);
+ cbReply = sizeof(INTNETIFSETACTIVEREQ);
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_SEND:
+ {
+ if (cbReq == sizeof(INTNETIFSENDREQ))
+ {
+ rc = IntNetR0IfSendReq(pSession, &ReqReply.IfSendReq);
+ cbReply = sizeof(INTNETIFSENDREQ);
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_WAIT:
+ {
+ if (cbReq == sizeof(INTNETIFWAITREQ))
+ {
+ ASMAtomicXchgBool(&pSession->fRecvWait, true);
+ if (ASMAtomicXchgBool(&pSession->fRecvAvail, false))
+ {
+ ASMAtomicXchgBool(&pSession->fRecvWait, false);
+
+ /* Send an empty message. */
+ xpc_object_t hObjPoke = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_connection_send_message(pSession->hXpcCon, hObjPoke);
+ }
+ return;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ case VMMR0_DO_INTNET_IF_ABORT_WAIT:
+ {
+ if (cbReq == sizeof(INTNETIFABORTWAITREQ))
+ {
+ ASMAtomicXchgBool(&pSession->fRecvWait, false);
+ if (ASMAtomicXchgBool(&pSession->fRecvAvail, false))
+ {
+ /* Send an empty message. */
+ xpc_object_t hObjPoke = xpc_dictionary_create(NULL, NULL, 0);
+ xpc_connection_send_message(pSession->hXpcCon, hObjPoke);
+ }
+ cbReply = sizeof(INTNETIFABORTWAITREQ);
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ default:
+ rc = VERR_INVALID_PARAMETER;
+ }
+ }
+
+ xpc_object_t hObjReply = xpc_dictionary_create_reply(hObj);
+ xpc_dictionary_set_uint64(hObjReply, "rc", INTNET_R3_SVC_SET_RC(rc));
+ xpc_dictionary_set_data(hObjReply, "reply", &ReqReply, cbReply);
+ xpc_connection_send_message(hCon, hObjReply);
+}
+
+
+DECLCALLBACK(void) xpcConnHandler(xpc_connection_t hXpcCon)
+{
+ xpc_connection_set_event_handler(hXpcCon, ^(xpc_object_t hObj) {
+ PSUPDRVSESSION pSession = (PSUPDRVSESSION)xpc_connection_get_context(hXpcCon);
+
+ if (xpc_get_type(hObj) == XPC_TYPE_ERROR)
+ {
+ if (hObj == XPC_ERROR_CONNECTION_INVALID)
+ intnetR3SessionDestroy(pSession);
+ else if (hObj == XPC_ERROR_TERMINATION_IMMINENT)
+ {
+ PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
+
+ uint32_t cRefs = intnetR3SessionDestroy(pSession);
+ if (!cRefs)
+ {
+ /* Last one cleans up the global data. */
+ RTCritSectDelete(&pDevExt->CritSect);
+ }
+ }
+ }
+ else
+ intnetR3RequestProcess(hXpcCon, hObj, pSession);
+ });
+
+ PSUPDRVSESSION pSession = (PSUPDRVSESSION)RTMemAllocZ(sizeof(*pSession));
+ if (pSession)
+ {
+ pSession->pDevExt = &g_DevExt;
+ pSession->hXpcCon = hXpcCon;
+
+ xpc_connection_set_context(hXpcCon, pSession);
+ xpc_connection_resume(hXpcCon);
+ xpc_transaction_begin();
+ ASMAtomicIncU32(&g_DevExt.cRefs);
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
+ if (RT_SUCCESS(rc))
+ {
+ IntNetR0Init();
+
+ g_DevExt.pObjs = NULL;
+ rc = RTCritSectInit(&g_DevExt.CritSect);
+ if (RT_SUCCESS(rc))
+ xpc_main(xpcConnHandler); /* Never returns. */
+
+ exit(EXIT_FAILURE);
+ }
+
+ return RTMsgInitFailure(rc);
+}
+
diff --git a/src/VBox/NetworkServices/IntNetSwitch/darwin/Info.plist b/src/VBox/NetworkServices/IntNetSwitch/darwin/Info.plist
new file mode 100644
index 00000000..ea39dfd8
--- /dev/null
+++ b/src/VBox/NetworkServices/IntNetSwitch/darwin/Info.plist
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundlePackageType</key> <string>XPC!</string>
+ <key>CFBundleSignature</key> <string>VBOX</string>
+ <key>CFBundleDevelopmentRegion</key> <string>English</string>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.intnet</string>
+ <key>CFBundleName</key> <string>VBoxIntNetSwitch</string>
+ <key>CFBundleExecutable</key> <string>VBoxIntNetSwitch</string>
+ <key>CFBundleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>CFBundleShortVersionString</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>CFBundleGetInfoString</key> <string>@VBOX_PRODUCT@ Manager @VBOX_VERSION_STRING@, © 2007-@VBOX_C_YEAR@ @VBOX_VENDOR@</string>
+ <key>CFBundleIconFile</key> <string>virtualbox</string>
+ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
+ <key>XPCService</key>
+ <dict>
+ <key>RunloopType</key> <string>dispatch_main</string>
+ <key>ServiceType</key> <string>User</string>
+ </dict>
+</dict>
+</plist>