diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:49:04 +0000 |
commit | 16f504a9dca3fe3b70568f67b7d41241ae485288 (patch) | |
tree | c60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/NetworkServices/IntNetSwitch | |
parent | Initial commit. (diff) | |
download | virtualbox-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 '')
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> |