Index: trunk/src/VBox/NetworkServices/NetLib/IntNetIf.cpp
===================================================================
--- trunk/src/VBox/NetworkServices/NetLib/IntNetIf.cpp	(revision 97075)
+++ trunk/src/VBox/NetworkServices/NetLib/IntNetIf.cpp	(revision 97078)
@@ -1,9 +1,9 @@
 /* $Id$ */
 /** @file
- * IntNetIf - Convenience class implementing an IntNet connection.
+ * IntNetIfCtx - Abstract API implementing an IntNet connection using the R0 support driver or some R3 IPC variant.
  */
 
 /*
- * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ * Copyright (C) 2022 Oracle and/or its affiliates.
  *
  * This file is part of VirtualBox base platform packages, as
@@ -26,321 +26,524 @@
  */
 
-#include "IntNetIf.h"
-
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+# if defined(RT_OS_DARWIN)
+#  include <xpc/xpc.h> /* This needs to be here because it drags PVM in and cdefs.h needs to undefine it... */
+# else
+#  error "R3 internal networking not implemented for this platform yet!"
+# endif
+#endif
+
+#include <iprt/cdefs.h>
 #include <iprt/path.h>
-
+#include <iprt/semaphore.h>
+
+#include <VBox/err.h>
+#include <VBox/sup.h>
 #include <VBox/intnetinline.h>
 #include <VBox/vmm/pdmnetinline.h>
 
-IntNetIf::IntNetIf()
-  : m_hIf(NULL),
-    m_pIfBuf(NULL),
-    m_pfnInput(NULL),
-    m_pvUser(NULL),
-    m_pfnInputGSO(NULL),
-    m_pvUserGSO(NULL)
-{
-    return;
-}
-
-
-IntNetIf::~IntNetIf()
-{
-    uninit();
-}
-
-
-/*
- * Wrappers for VMM ioctl requests and low-level intnet operations.
+#include "IntNetIf.h"
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+
+
+/**
+ * Internal network interface context instance data.
  */
+typedef struct INTNETIFCTXINT
+{
+    /** The support driver session handle. */
+    PSUPDRVSESSION                  pSupDrvSession;
+    /** Interface handle. */
+    INTNETIFHANDLE                  hIf;
+    /** The internal network buffer. */
+    PINTNETBUF                      pBuf;
+#if defined (VBOX_WITH_INTNET_SERVICE_IN_R3)
+    /** Flag whether this interface is using the internal network switch in userspace path. */
+    bool                            fIntNetR3Svc;
+    /** Receive event semaphore. */
+    RTSEMEVENT                      hEvtRecv;
+# if defined(RT_OS_DARWIN)
+    /** XPC connection handle to the R3 internal network switch service. */
+    xpc_connection_t                hXpcCon;
+    /** Size of the communication buffer in bytes. */
+    size_t                          cbBuf;
+# endif
+#endif
+} INTNETIFCTXINT;
+/** Pointer to the internal network interface context instance data. */
+typedef INTNETIFCTXINT *PINTNETIFCTXINT;
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
 
 /**
- * Open the specified internal network.
- * Perform VMMR0_DO_INTNET_OPEN.
- *
- * @param strNetwork    The name of the network.
- * @param enmTrunkType  The trunk type.
- * @param strTrunk      The trunk name, its meaning is specific to the type.
- * @return              iprt status code.
+ * Calls the internal networking switch service living in either R0 or in another R3 process.
+ *
+ * @returns VBox status code.
+ * @param   pThis           The internal network driver instance data.
+ * @param   uOperation      The operation to execute.
+ * @param   pReqHdr         Pointer to the request header.
  */
-int
-IntNetIf::ifOpen(const RTCString &strNetwork,
-                 INTNETTRUNKTYPE enmTrunkType,
-                 const RTCString &strTrunk)
-{
-    AssertReturn(m_hIf == NULL, VERR_GENERAL_FAILURE);
-
-    if (enmTrunkType == kIntNetTrunkType_Invalid)
-        enmTrunkType = kIntNetTrunkType_WhateverNone;
-
-    return IntNetR3IfCtxCreate(&m_hIf, strNetwork.c_str(), enmTrunkType,
-                               strTrunk.c_str(), _128K /*cbSend*/, _256K /*cbRecv*/,
-                               0 /*fFlags*/);
-}
-
-
+static int intnetR3IfCallSvc(PINTNETIFCTXINT pThis, uint32_t uOperation, PSUPVMMR0REQHDR pReqHdr)
+{
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+    if (pThis->fIntNetR3Svc)
+    {
+# if defined(RT_OS_DARWIN)
+        size_t cbReq = pReqHdr->cbReq;
+        xpc_object_t hObj = xpc_dictionary_create(NULL, NULL, 0);
+        xpc_dictionary_set_uint64(hObj, "req-id", uOperation);
+        xpc_dictionary_set_data(hObj, "req", pReqHdr, pReqHdr->cbReq);
+        xpc_object_t hObjReply = xpc_connection_send_message_with_reply_sync(pThis->hXpcCon, hObj);
+        int rc = (int)xpc_dictionary_get_int64(hObjReply, "rc");
+
+        size_t cbReply = 0;
+        const void *pvData = xpc_dictionary_get_data(hObjReply, "reply", &cbReply);
+        AssertRelease(cbReply == cbReq);
+        memcpy(pReqHdr, pvData, cbReq);
+        xpc_release(hObjReply);
+
+        return rc;
+# endif
+    }
+    else
+#else
+        RT_NOREF(pThis);
+#endif
+        return SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, uOperation, 0, pReqHdr);
+}
+
+
+#if defined(RT_OS_DARWIN) && defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
 /**
- * Set promiscuous mode on the interface.
+ * Calls the internal networking switch service living in either R0 or in another R3 process.
+ *
+ * @returns VBox status code.
+ * @param   pThis           The internal network driver instance data.
+ * @param   uOperation      The operation to execute.
+ * @param   pReqHdr         Pointer to the request header.
  */
-int
-IntNetIf::ifSetPromiscuous(bool fPromiscuous)
-{
-    AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
-
-    return IntNetR3IfCtxSetPromiscuous(m_hIf, fPromiscuous);
-}
+static int intnetR3IfCallSvcAsync(PINTNETIFCTXINT pThis, uint32_t uOperation, PSUPVMMR0REQHDR pReqHdr)
+{
+    if (pThis->fIntNetR3Svc)
+    {
+        xpc_object_t hObj = xpc_dictionary_create(NULL, NULL, 0);
+        xpc_dictionary_set_uint64(hObj, "req-id", uOperation);
+        xpc_dictionary_set_data(hObj, "req", pReqHdr, pReqHdr->cbReq);
+        xpc_connection_send_message(pThis->hXpcCon, hObj);
+        return VINF_SUCCESS;
+    }
+    else
+        return SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, uOperation, 0, pReqHdr);
+}
+#endif
 
 
 /**
- * Obtain R3 send/receive ring buffers for the internal network.
- * Performs VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS.
- * @return iprt status code.
+ * Map the ring buffer pointer into this process R3 address space.
+ *
+ * @returns VBox status code.
+ * @param   pThis           The internal network driver instance data.
  */
-int
-IntNetIf::ifGetBuf()
-{
-    AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
-    AssertReturn(m_pIfBuf == NULL, VERR_GENERAL_FAILURE);
-
-    return IntNetR3IfCtxQueryBufferPtr(m_hIf, &m_pIfBuf);
-}
-
-
-/**
- * Activate the network interface.
- * Performs VMMR0_DO_INTNET_IF_SET_ACTIVE.
- * @return iprt status code.
- */
-int
-IntNetIf::ifActivate()
-{
-    AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
-    AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
-
-    return IntNetR3IfCtxSetActive(m_hIf, true /*fActive*/);
-}
-
-
-/**
- * Wait for input frame(s) to become available in the receive ring
- * buffer.  Performs VMMR0_DO_INTNET_IF_WAIT.
- *
- * @param cMillies      Timeout, defaults to RT_INDEFINITE_WAIT.
- * @return              iprt status code.
- */
-int
-IntNetIf::ifWait(uint32_t cMillies)
-{
-    AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
-
-    return IntNetR3IfWait(m_hIf, cMillies);
-}
-
-
-/**
- * Abort pending ifWait(), prevent any further attempts to wait.
- */
-int
-IntNetIf::ifAbort()
-{
-    AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
-
-    return IntNetR3IfWaitAbort(m_hIf);
-}
-
-
-/**
- * Process input available in the receive ring buffer.
- * Feeds input frames to the user callback.
- * @return iprt status code.
- */
-int
-IntNetIf::ifProcessInput()
-{
-    AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
-    AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
-    AssertReturn(m_pfnInput != NULL, VERR_GENERAL_FAILURE);
-
-    PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv);
-    while (pHdr)
-    {
-        const uint8_t u8Type = pHdr->u8Type;
-        void *pvSegFrame;
-        uint32_t cbSegFrame;
-
-        if (u8Type == INTNETHDR_TYPE_FRAME)
+static int intnetR3IfMapBufferPointers(PINTNETIFCTXINT pThis)
+{
+    int rc = VINF_SUCCESS;
+
+    INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
+    GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+    GetBufferPtrsReq.Hdr.cbReq    = sizeof(GetBufferPtrsReq);
+    GetBufferPtrsReq.pSession     = pThis->pSupDrvSession;
+    GetBufferPtrsReq.hIf          = pThis->hIf;
+    GetBufferPtrsReq.pRing3Buf    = NULL;
+    GetBufferPtrsReq.pRing0Buf    = NIL_RTR0PTR;
+
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+    if (pThis->fIntNetR3Svc)
+    {
+#if defined(RT_OS_DARWIN)
+        xpc_object_t hObj = xpc_dictionary_create(NULL, NULL, 0);
+        xpc_dictionary_set_uint64(hObj, "req-id", VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS);
+        xpc_dictionary_set_data(hObj, "req", &GetBufferPtrsReq, sizeof(GetBufferPtrsReq));
+        xpc_object_t hObjReply = xpc_connection_send_message_with_reply_sync(pThis->hXpcCon, hObj);
+        rc = (int)xpc_dictionary_get_int64(hObjReply, "rc");
+        if (RT_SUCCESS(rc))
         {
-            pvSegFrame = IntNetHdrGetFramePtr(pHdr, m_pIfBuf);
-            cbSegFrame = pHdr->cbFrame;
-
-            /* pass the frame to the user callback */
-            (*m_pfnInput)(m_pvUser, pvSegFrame, cbSegFrame);
+            /* Get the shared memory object. */
+            xpc_object_t hObjShMem = xpc_dictionary_get_value(hObjReply, "buf-ptr");
+            size_t cbMem = xpc_shmem_map(hObjShMem, (void **)&pThis->pBuf);
+            if (!cbMem)
+                rc = VERR_NO_MEMORY;
+            else
+                pThis->cbBuf = cbMem;
         }
-        else if (u8Type == INTNETHDR_TYPE_GSO)
+        xpc_release(hObjReply);
+#endif
+    }
+    else
+#endif
+    {
+        rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0 /*u64Arg*/, &GetBufferPtrsReq.Hdr);
+        if (RT_SUCCESS(rc))
         {
-            size_t cbGso = pHdr->cbFrame;
-            size_t cbFrame = cbGso - sizeof(PDMNETWORKGSO);
-
-            PCPDMNETWORKGSO pcGso = IntNetHdrGetGsoContext(pHdr, m_pIfBuf);
-            if (PDMNetGsoIsValid(pcGso, cbGso, cbFrame))
+            AssertRelease(RT_VALID_PTR(GetBufferPtrsReq.pRing3Buf));
+            pThis->pBuf = GetBufferPtrsReq.pRing3Buf;
+        }
+    }
+
+    return rc;
+}
+
+
+static void intnetR3IfClose(PINTNETIFCTXINT pThis)
+{
+    if (pThis->hIf != INTNET_HANDLE_INVALID)
+    {
+        INTNETIFCLOSEREQ CloseReq;
+        CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+        CloseReq.Hdr.cbReq    = sizeof(CloseReq);
+        CloseReq.pSession     = pThis->pSupDrvSession;
+        CloseReq.hIf          = pThis->hIf;
+
+        pThis->hIf = INTNET_HANDLE_INVALID;
+        int rc = intnetR3IfCallSvc(pThis, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq.Hdr);
+        AssertRC(rc);
+    }
+}
+
+
+DECLHIDDEN(int) IntNetR3IfCreate(PINTNETIFCTX phIfCtx, const char *pszNetwork)
+{
+    return IntNetR3IfCreateEx(phIfCtx, pszNetwork, kIntNetTrunkType_WhateverNone, "",
+                              _128K /*cbSend*/, _256K /*cbRecv*/, 0 /*fFlags*/);
+}
+
+
+DECLHIDDEN(int) IntNetR3IfCreateEx(PINTNETIFCTX phIfCtx, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
+                                   const char *pszTrunk, uint32_t cbSend, uint32_t cbRecv, uint32_t fFlags)
+{
+    AssertPtrReturn(phIfCtx, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszNetwork, VERR_INVALID_POINTER);
+    AssertPtrReturn(pszTrunk, VERR_INVALID_POINTER);
+
+    PSUPDRVSESSION pSession = NIL_RTR0PTR;
+    int rc = SUPR3Init(&pSession);
+    if (RT_SUCCESS(rc))
+    {
+        PINTNETIFCTXINT pThis = (PINTNETIFCTXINT)RTMemAllocZ(sizeof(*pThis));
+        if (RT_LIKELY(pThis))
+        {
+            pThis->pSupDrvSession = pSession;
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+            pThis->hEvtRecv       = NIL_RTSEMEVENT;
+#endif
+
+            /* Driverless operation needs support for running the internal network switch using IPC. */
+            if (SUPR3IsDriverless())
             {
-                if (m_pfnInputGSO != NULL)
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+# if defined(RT_OS_DARWIN)
+                xpc_connection_t hXpcCon = xpc_connection_create(INTNET_R3_SVC_NAME, NULL);
+                xpc_connection_set_event_handler(hXpcCon, ^(xpc_object_t hObj) {
+                    if (xpc_get_type(hObj) == XPC_TYPE_ERROR)
+                    {
+                        /** @todo Error handling - reconnecting. */
+                    }
+                    else
+                    {
+                        /* Out of band messages should only come when there is something to receive. */
+                        RTSemEventSignal(pThis->hEvtRecv);
+                    }
+                });
+
+                xpc_connection_activate(hXpcCon);
+                pThis->hXpcCon      = hXpcCon;
+# endif
+                pThis->fIntNetR3Svc = true;
+                rc = RTSemEventCreate(&pThis->hEvtRecv);
+#else
+                rc = VERR_SUP_DRIVERLESS;
+#endif
+            }
+            else
+            {
+                /* Need to load VMMR0.r0 containing the network switching code. */
+                char szPathVMMR0[RTPATH_MAX];
+
+                rc = RTPathExecDir(szPathVMMR0, sizeof(szPathVMMR0));
+                if (RT_SUCCESS(rc))
                 {
-                    /* pass the frame to the user GSO input callback if set */
-                    (*m_pfnInputGSO)(m_pvUserGSO, pcGso, (uint32_t)cbFrame);
+                    rc = RTPathAppend(szPathVMMR0, sizeof(szPathVMMR0), "VMMR0.r0");
+                    if (RT_SUCCESS(rc))
+                        rc = SUPR3LoadVMM(szPathVMMR0, /* :pErrInfo */ NULL);
                 }
-                else
+            }
+
+            if (RT_SUCCESS(rc))
+            {
+                /* Open the interface. */
+                INTNETOPENREQ OpenReq;
+                RT_ZERO(OpenReq);
+
+                OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+                OpenReq.Hdr.cbReq    = sizeof(OpenReq);
+                OpenReq.pSession     = pThis->pSupDrvSession;
+                OpenReq.enmTrunkType = enmTrunkType;
+                OpenReq.fFlags       = fFlags;
+                OpenReq.cbSend       = cbSend;
+                OpenReq.cbRecv       = cbRecv;
+                OpenReq.hIf          = INTNET_HANDLE_INVALID;
+
+                rc = RTStrCopy(OpenReq.szNetwork, sizeof(OpenReq.szNetwork), pszNetwork);
+                if (RT_SUCCESS(rc))
+                    rc = RTStrCopy(OpenReq.szTrunk, sizeof(OpenReq.szTrunk), pszTrunk);
+                if (RT_SUCCESS(rc))
                 {
-                    const uint32_t cSegs = PDMNetGsoCalcSegmentCount(pcGso, cbFrame);
-                    for (uint32_t i = 0; i < cSegs; ++i)
+                    rc = intnetR3IfCallSvc(pThis, VMMR0_DO_INTNET_OPEN, &OpenReq.Hdr);
+                    if (RT_SUCCESS(rc))
                     {
-                        uint8_t abHdrScratch[256];
-                        pvSegFrame = PDMNetGsoCarveSegmentQD(pcGso, (uint8_t *)(pcGso + 1), cbFrame,
-                                                             abHdrScratch,
-                                                             i, cSegs,
-                                                             &cbSegFrame);
-
-                        /* pass carved frames to the user input callback */
-                        (*m_pfnInput)(m_pvUser, pvSegFrame, (uint32_t)cbSegFrame);
+                        pThis->hIf = OpenReq.hIf;
+
+                        rc = intnetR3IfMapBufferPointers(pThis);
+                        if (RT_SUCCESS(rc))
+                        {
+                            *phIfCtx = pThis;
+                            return VINF_SUCCESS;
+                        }
+                    }
+
+                    intnetR3IfClose(pThis);
+                }
+            }
+
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+            if (pThis->fIntNetR3Svc)
+            {
+# if defined(RT_OS_DARWIN)
+                if (pThis->hXpcCon)
+                    xpc_connection_cancel(pThis->hXpcCon);
+                pThis->hXpcCon = NULL;
+# endif
+
+                if (pThis->hEvtRecv != NIL_RTSEMEVENT)
+                    RTSemEventDestroy(pThis->hEvtRecv);
+            }
+#endif
+
+            RTMemFree(pThis);
+        }
+
+        SUPR3Term();
+    }
+
+    return rc;
+}
+
+
+DECLHIDDEN(int) IntNetR3IfDestroy(INTNETIFCTX hIfCtx)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    intnetR3IfClose(pThis);
+
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+    if (pThis->fIntNetR3Svc)
+    {
+# if defined(RT_OS_DARWIN)
+        /* Unmap the shared buffer. */
+        munmap(pThis->pBuf, pThis->cbBuf);
+        xpc_connection_cancel(pThis->hXpcCon);
+        pThis->hXpcCon      = NULL;
+# endif
+        RTSemEventDestroy(pThis->hEvtRecv);
+        pThis->fIntNetR3Svc = false;
+    }
+#endif
+
+    RTMemFree(pThis);
+    return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) IntNetR3IfQueryBufferPtr(INTNETIFCTX hIfCtx, PINTNETBUF *ppIfBuf)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertPtrReturn(ppIfBuf, VERR_INVALID_POINTER);
+
+    *ppIfBuf = pThis->pBuf;
+    return VINF_SUCCESS;
+}
+
+
+DECLHIDDEN(int) IntNetR3IfSetActive(INTNETIFCTX hIfCtx, bool fActive)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    INTNETIFSETACTIVEREQ Req;
+    Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+    Req.Hdr.cbReq    = sizeof(Req);
+    Req.pSession     = pThis->pSupDrvSession;
+    Req.hIf          = pThis->hIf;
+    Req.fActive      = fActive;
+    return intnetR3IfCallSvc(pThis, VMMR0_DO_INTNET_IF_SET_ACTIVE, &Req.Hdr);
+}
+
+
+DECLHIDDEN(int) IntNetR3IfSetPromiscuous(INTNETIFCTX hIfCtx, bool fPromiscuous)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    INTNETIFSETPROMISCUOUSMODEREQ Req;
+    Req.Hdr.u32Magic    = SUPVMMR0REQHDR_MAGIC;
+    Req.Hdr.cbReq       = sizeof(Req);
+    Req.pSession        = pThis->pSupDrvSession;
+    Req.hIf             = pThis->hIf;
+    Req.fPromiscuous    = fPromiscuous;
+    return intnetR3IfCallSvc(pThis, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req.Hdr);
+}
+
+
+DECLHIDDEN(int) IntNetR3IfSend(INTNETIFCTX hIfCtx)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    INTNETIFSENDREQ Req;
+    Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+    Req.Hdr.cbReq    = sizeof(Req);
+    Req.pSession     = pThis->pSupDrvSession;
+    Req.hIf          = pThis->hIf;
+    return intnetR3IfCallSvc(pThis, VMMR0_DO_INTNET_IF_SEND, &Req.Hdr);
+}
+
+
+DECLHIDDEN(int) IntNetR3IfWait(INTNETIFCTX hIfCtx, uint32_t cMillies)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    int rc = VINF_SUCCESS;
+    INTNETIFWAITREQ WaitReq;
+    WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+    WaitReq.Hdr.cbReq    = sizeof(WaitReq);
+    WaitReq.pSession     = pThis->pSupDrvSession;
+    WaitReq.hIf          = pThis->hIf;
+    WaitReq.cMillies     = cMillies;
+#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
+    if (pThis->fIntNetR3Svc)
+    {
+        /* Send an asynchronous message. */
+        rc = intnetR3IfCallSvcAsync(pThis, VMMR0_DO_INTNET_IF_WAIT, &WaitReq.Hdr);
+        if (RT_SUCCESS(rc))
+        {
+            /* Wait on the receive semaphore. */
+            rc = RTSemEventWait(pThis->hEvtRecv, cMillies);
+        }
+    }
+    else
+#endif
+        rc = intnetR3IfCallSvc(pThis, VMMR0_DO_INTNET_IF_WAIT, &WaitReq.Hdr);
+
+    return rc;
+}
+
+
+DECLHIDDEN(int) IntNetR3IfWaitAbort(INTNETIFCTX hIfCtx)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    INTNETIFABORTWAITREQ AbortWaitReq;
+    AbortWaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+    AbortWaitReq.Hdr.cbReq    = sizeof(AbortWaitReq);
+    AbortWaitReq.pSession     = pThis->pSupDrvSession;
+    AbortWaitReq.hIf          = pThis->hIf;
+    AbortWaitReq.fNoMoreWaits = true;
+    return intnetR3IfCallSvc(pThis, VMMR0_DO_INTNET_IF_ABORT_WAIT, &AbortWaitReq.Hdr);
+}
+
+
+DECLHIDDEN(int) IntNetR3IfPumpPkts(INTNETIFCTX hIfCtx, PFNINPUT pfnInput, void *pvUser,
+                                      PFNINPUTGSO pfnInputGso, void *pvUserGso)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+    AssertPtrReturn(pfnInput, VERR_INVALID_POINTER);
+
+    int rc;
+    for (;;)
+    {
+        rc = IntNetR3IfWait(hIfCtx, RT_INDEFINITE_WAIT);
+        if (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED || rc == VERR_TIMEOUT)
+        {
+            PCINTNETHDR pHdr = IntNetRingGetNextFrameToRead(&pThis->pBuf->Recv);
+            while (pHdr)
+            {
+                const uint8_t u8Type = pHdr->u8Type;
+                void *pvSegFrame;
+                uint32_t cbSegFrame;
+
+                if (u8Type == INTNETHDR_TYPE_FRAME)
+                {
+                    pvSegFrame = IntNetHdrGetFramePtr(pHdr, pThis->pBuf);
+                    cbSegFrame = pHdr->cbFrame;
+
+                    /* pass the frame to the user callback */
+                    pfnInput(pvUser, pvSegFrame, cbSegFrame);
+                }
+                else if (u8Type == INTNETHDR_TYPE_GSO)
+                {
+                    size_t cbGso = pHdr->cbFrame;
+                    size_t cbFrame = cbGso - sizeof(PDMNETWORKGSO);
+
+                    PCPDMNETWORKGSO pcGso = IntNetHdrGetGsoContext(pHdr, pThis->pBuf);
+                    if (PDMNetGsoIsValid(pcGso, cbGso, cbFrame))
+                    {
+                        if (pfnInputGso != NULL)
+                        {
+                            /* pass the frame to the user GSO input callback if set */
+                            pfnInputGso(pvUserGso, pcGso, (uint32_t)cbFrame);
+                        }
+                        else
+                        {
+                            const uint32_t cSegs = PDMNetGsoCalcSegmentCount(pcGso, cbFrame);
+                            for (uint32_t i = 0; i < cSegs; ++i)
+                            {
+                                uint8_t abHdrScratch[256];
+                                pvSegFrame = PDMNetGsoCarveSegmentQD(pcGso, (uint8_t *)(pcGso + 1), cbFrame,
+                                                                     abHdrScratch,
+                                                                     i, cSegs,
+                                                                     &cbSegFrame);
+
+                                /* pass carved frames to the user input callback */
+                                pfnInput(pvUser, pvSegFrame, (uint32_t)cbSegFrame);
+                            }
+                        }
                     }
                 }
+
+                /* advance to the next input frame */
+                IntNetRingSkipFrame(&pThis->pBuf->Recv);
+                pHdr = IntNetRingGetNextFrameToRead(&pThis->pBuf->Recv);
             }
         }
-
-        /* advance to the next input frame */
-        IntNetRingSkipFrame(&m_pIfBuf->Recv);
-        pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv);
-    }
-
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Flush output frames from the send ring buffer to the network.
- * Performs VMMR0_DO_INTNET_IF_SEND.
- */
-int
-IntNetIf::ifFlush()
-{
-    AssertReturn(m_hIf != NULL, VERR_GENERAL_FAILURE);
-
-    return IntNetR3IfSend(m_hIf);
-}
-
-
-/**
- * Close the connection to the network.
- * Performs VMMR0_DO_INTNET_IF_CLOSE.
- */
-int
-IntNetIf::ifClose()
-{
-    if (m_hIf == NULL)
-        return VINF_SUCCESS;
-
-    int rc = IntNetR3IfCtxDestroy(m_hIf);
-    m_hIf = NULL;
-    return rc;
-}
-
-
-
-/*
- * Public high-level user interface.
- */
-
-/**
- * Connect to the specified internal network.
- *
- * @param strNetwork    The name of the network.
- * @param enmTrunkType  The trunk type.  Defaults to kIntNetTrunkType_WhateverNone.
- * @param strTrunk      The trunk name, its meaning is specific to the type.
- *                      Defaults to an empty string.
- * @return              iprt status code.
- */
-int
-IntNetIf::init(const RTCString &strNetwork,
-               INTNETTRUNKTYPE enmTrunkType,
-               const RTCString &strTrunk)
-{
-    int rc = ifOpen(strNetwork, enmTrunkType, strTrunk);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    rc = ifGetBuf();
-    if (RT_FAILURE(rc))
-        return rc;
-
-    rc = ifActivate();
-    if (RT_FAILURE(rc))
-        return rc;
-
-    return VINF_SUCCESS;
-}
-
-
-void
-IntNetIf::uninit()
-{
-    ifClose();
-}
-
-
-/**
- * Set the user input callback function.
- *
- * @param pfnInput      User input callback.
- * @param pvUser        The user specified argument to the callback.
- * @return              iprt status code.
- */
-int
-IntNetIf::setInputCallback(PFNINPUT pfnInput, void *pvUser)
-{
-    AssertReturn(pfnInput != NULL, VERR_INVALID_STATE);
-
-    m_pfnInput = pfnInput;
-    m_pvUser = pvUser;
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Set the user GSO input callback function.
- *
- * @param pfnInputGSO   User input callback.
- * @param pvUserGSO     The user specified argument to the callback.
- * @return              iprt status code.
- */
-int
-IntNetIf::setInputGSOCallback(PFNINPUTGSO pfnInputGSO, void *pvUserGSO)
-{
-    AssertReturn(pfnInputGSO != NULL, VERR_INVALID_STATE);
-
-    m_pfnInputGSO = pfnInputGSO;
-    m_pvUserGSO = pvUserGSO;
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Process incoming packets forever.
- *
- * User call this method on its receive thread.  The packets are
- * passed to the user inpiut callbacks.  If the GSO input callback is
- * not registered, a GSO input frame is carved into normal frames and
- * those frames are passed to the normal input callback.
- */
-int
-IntNetIf::ifPump()
-{
-    AssertReturn(m_pfnInput != NULL, VERR_GENERAL_FAILURE);
-
-    int rc;
-    for (;;)
-    {
-        rc = ifWait();
-        if (RT_SUCCESS(rc) || rc == VERR_INTERRUPTED || rc == VERR_TIMEOUT)
-            ifProcessInput();
         else
             break;
@@ -350,23 +553,19 @@
 
 
-int
-IntNetIf::getOutputFrame(IntNetIf::Frame &rFrame, size_t cbFrame)
-{
-    int rc;
-
-    rc = IntNetRingAllocateFrame(&m_pIfBuf->Send, (uint32_t)cbFrame,
-                                 &rFrame.pHdr, &rFrame.pvFrame);
-    return rc;
-}
-
-
-int
-IntNetIf::ifOutput(IntNetIf::Frame &rFrame)
-{
-    int rc;
-
-    IntNetRingCommitFrame(&m_pIfBuf->Send, rFrame.pHdr);
-
-    rc = ifFlush();
-    return rc;
-}
+DECLHIDDEN(int) IntNetR3IfQueryOutputFrame(INTNETIFCTX hIfCtx, uint32_t cbFrame, PINTNETFRAME pFrame)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    return IntNetRingAllocateFrame(&pThis->pBuf->Send, cbFrame, &pFrame->pHdr, &pFrame->pvFrame);
+}
+
+
+DECLHIDDEN(int) IntNetR3IfOutputFrameCommit(INTNETIFCTX hIfCtx, PCINTNETFRAME pFrame)
+{
+    PINTNETIFCTXINT pThis = hIfCtx;
+    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
+
+    IntNetRingCommitFrame(&pThis->pBuf->Send, pFrame->pHdr);
+    return IntNetR3IfSend(hIfCtx);
+}
Index: trunk/src/VBox/NetworkServices/NetLib/IntNetIf.h
===================================================================
--- trunk/src/VBox/NetworkServices/NetLib/IntNetIf.h	(revision 97075)
+++ trunk/src/VBox/NetworkServices/NetLib/IntNetIf.h	(revision 97078)
@@ -51,104 +51,62 @@
 typedef INTNETIFCTX *PINTNETIFCTX;
 
+/**
+ * User input callback function.
+ *
+ * @param pvUser    The user specified argument.
+ * @param pvFrame   The pointer to the frame data.
+ * @param cbFrame   The length of the frame data.
+ */
+typedef DECLCALLBACKTYPE(void, FNINPUT,(void *pvUser, void *pvFrame, uint32_t cbFrame));
 
-DECLHIDDEN(int) IntNetR3IfCtxCreate(PINTNETIFCTX phIfCtx, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
-                                    const char *pszTrunk, uint32_t cbSend, uint32_t cbRecv, uint32_t fFlags);
-DECLHIDDEN(int) IntNetR3IfCtxDestroy(INTNETIFCTX hIfCtx);
-DECLHIDDEN(int) IntNetR3IfCtxQueryBufferPtr(INTNETIFCTX hIfCtx, PINTNETBUF *ppIfBuf);
-DECLHIDDEN(int) IntNetR3IfCtxSetActive(INTNETIFCTX hIfCtx, bool fActive);
-DECLHIDDEN(int) IntNetR3IfCtxSetPromiscuous(INTNETIFCTX hIfCtx, bool fPromiscuous);
+/** Pointer to the user input callback function. */
+typedef FNINPUT *PFNINPUT;
+
+/**
+ * User GSO input callback function.
+ *
+ * @param pvUser    The user specified argument.
+ * @param pcGso     The pointer to the GSO context.
+ * @param cbFrame   The length of the GSO data.
+ */
+typedef DECLCALLBACKTYPE(void, FNINPUTGSO,(void *pvUser, PCPDMNETWORKGSO pcGso, uint32_t cbFrame));
+
+/** Pointer to the user GSO input callback function. */
+typedef FNINPUTGSO *PFNINPUTGSO;
+
+
+/**
+ * An output frame in the send ring buffer.
+ *
+ * Obtained with IntNetR3IfCtxQueryOutputFrame().  Caller should copy frame
+ * contents to pvFrame and pass the frame structure to IntNetR3IfCtxOutputFrameCommit()
+ * to be sent to the network.
+ */
+typedef struct INTNETFRAME
+{
+    /** The intrnal network frame header. */
+    PINTNETHDR pHdr;
+    /** The actual frame data. */
+    void       *pvFrame;
+} INTNETFRAME;
+typedef INTNETFRAME *PINTNETFRAME;
+typedef const INTNETFRAME *PCINTNETFRAME;
+
+
+DECLHIDDEN(int) IntNetR3IfCreate(PINTNETIFCTX phIfCtx, const char *pszNetwork);
+DECLHIDDEN(int) IntNetR3IfCreateEx(PINTNETIFCTX phIfCtx, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
+                                   const char *pszTrunk, uint32_t cbSend, uint32_t cbRecv, uint32_t fFlags);
+DECLHIDDEN(int) IntNetR3IfDestroy(INTNETIFCTX hIfCtx);
+DECLHIDDEN(int) IntNetR3IfQueryBufferPtr(INTNETIFCTX hIfCtx, PINTNETBUF *ppIfBuf);
+DECLHIDDEN(int) IntNetR3IfSetActive(INTNETIFCTX hIfCtx, bool fActive);
+DECLHIDDEN(int) IntNetR3IfSetPromiscuous(INTNETIFCTX hIfCtx, bool fPromiscuous);
 DECLHIDDEN(int) IntNetR3IfSend(INTNETIFCTX hIfCtx);
 DECLHIDDEN(int) IntNetR3IfWait(INTNETIFCTX hIfCtx, uint32_t cMillies);
 DECLHIDDEN(int) IntNetR3IfWaitAbort(INTNETIFCTX hIfCtx);
 
-
-/**
- * Convenience class implementing an IntNet connection.
- */
-class IntNetIf
-{
-public:
-    /**
-     * User input callback function.
-     *
-     * @param pvUser    The user specified argument.
-     * @param pvFrame   The pointer to the frame data.
-     * @param cbFrame   The length of the frame data.
-     */
-    typedef DECLCALLBACKTYPE(void, FNINPUT,(void *pvUser, void *pvFrame, uint32_t cbFrame));
-
-    /** Pointer to the user input callback function. */
-    typedef FNINPUT *PFNINPUT;
-
-    /**
-     * User GSO input callback function.
-     *
-     * @param pvUser    The user specified argument.
-     * @param pcGso     The pointer to the GSO context.
-     * @param cbFrame   The length of the GSO data.
-     */
-    typedef DECLCALLBACKTYPE(void, FNINPUTGSO,(void *pvUser, PCPDMNETWORKGSO pcGso, uint32_t cbFrame));
-
-    /** Pointer to the user GSO input callback function. */
-    typedef FNINPUTGSO *PFNINPUTGSO;
-
-
-    /**
-     * An output frame in the send ring buffer.
-     *
-     * Obtained with getOutputFrame().  Caller should copy frame
-     * contents to pvFrame and pass the frame structure to ifOutput()
-     * to be sent to the network.
-     */
-    struct Frame {
-        PINTNETHDR pHdr;
-        void *pvFrame;
-    };
-
-
-private:
-    INTNETIFCTX m_hIf;
-    PINTNETBUF  m_pIfBuf;
-
-    PFNINPUT m_pfnInput;
-    void *m_pvUser;
-
-    PFNINPUTGSO m_pfnInputGSO;
-    void *m_pvUserGSO;
-
-public:
-    IntNetIf();
-    ~IntNetIf();
-
-    int init(const RTCString &strNetwork,
-             INTNETTRUNKTYPE enmTrunkType = kIntNetTrunkType_WhateverNone,
-             const RTCString &strTrunk = RTCString());
-    void uninit();
-
-    int setInputCallback(PFNINPUT pfnInput, void *pvUser);
-    int setInputGSOCallback(PFNINPUTGSO pfnInputGSO, void *pvUser);
-
-    int ifSetPromiscuous(bool fPromiscuous = true);
-
-    int ifPump();
-    int ifAbort();
-
-    int getOutputFrame(Frame &rFrame, size_t cbFrame);
-    int ifOutput(Frame &rFrame);
-
-    int ifClose();
-
-private:
-    int ifOpen(const RTCString &strNetwork,
-               INTNETTRUNKTYPE enmTrunkType,
-               const RTCString &strTrunk);
-    int ifGetBuf();
-    int ifActivate();
-
-    int ifWait(uint32_t cMillies = RT_INDEFINITE_WAIT);
-    int ifProcessInput();
-
-    int ifFlush();
-};
+DECLHIDDEN(int) IntNetR3IfPumpPkts(INTNETIFCTX hIfCtx, PFNINPUT pfnInput, void *pvUser,
+                                   PFNINPUTGSO pfnInputGso, void *pvUserGso);
+DECLHIDDEN(int) IntNetR3IfQueryOutputFrame(INTNETIFCTX hIfCtx, uint32_t cbFrame, PINTNETFRAME pFrame);
+DECLHIDDEN(int) IntNetR3IfOutputFrameCommit(INTNETIFCTX hIfCtx, PCINTNETFRAME pFrame);
 
 #endif /* !VBOX_INCLUDED_SRC_NetLib_IntNetIf_h */
Index: trunk/src/VBox/NetworkServices/NetLib/IntNetIfCtx.cpp
===================================================================
--- trunk/src/VBox/NetworkServices/NetLib/IntNetIfCtx.cpp	(revision 97075)
+++ 	(revision )
@@ -1,474 +1,0 @@
-/* $Id$ */
-/** @file
- * IntNetIfCtx - Abstract API implementing an IntNet connection using the R0 support driver or some R3 IPC variant.
- */
-
-/*
- * 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
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-# if defined(RT_OS_DARWIN)
-#  include <xpc/xpc.h> /* This needs to be here because it drags PVM in and cdefs.h needs to undefine it... */
-# else
-#  error "R3 internal networking not implemented for this platform yet!"
-# endif
-#endif
-
-#include <iprt/cdefs.h>
-#include <iprt/path.h>
-#include <iprt/semaphore.h>
-
-#include <VBox/err.h>
-#include <VBox/sup.h>
-#include <VBox/intnetinline.h>
-#include <VBox/vmm/pdmnetinline.h>
-
-#include "IntNetIf.h"
-
-
-/*********************************************************************************************************************************
-*   Defined Constants And Macros                                                                                                 *
-*********************************************************************************************************************************/
-
-
-/*********************************************************************************************************************************
-*   Structures and Typedefs                                                                                                      *
-*********************************************************************************************************************************/
-
-
-/**
- * Internal network interface context instance data.
- */
-typedef struct INTNETIFCTXINT
-{
-    /** The support driver session handle. */
-    PSUPDRVSESSION                  pSupDrvSession;
-    /** Interface handle. */
-    INTNETIFHANDLE                  hIf;
-    /** The internal network buffer. */
-    PINTNETBUF                      pBuf;
-#if defined (VBOX_WITH_INTNET_SERVICE_IN_R3)
-    /** Flag whether this interface is using the internal network switch in userspace path. */
-    bool                            fIntNetR3Svc;
-    /** Receive event semaphore. */
-    RTSEMEVENT                      hEvtRecv;
-# if defined(RT_OS_DARWIN)
-    /** XPC connection handle to the R3 internal network switch service. */
-    xpc_connection_t                hXpcCon;
-    /** Size of the communication buffer in bytes. */
-    size_t                          cbBuf;
-# endif
-#endif
-} INTNETIFCTXINT;
-/** Pointer to the internal network interface context instance data. */
-typedef INTNETIFCTXINT *PINTNETIFCTXINT;
-
-
-/*********************************************************************************************************************************
-*   Internal Functions                                                                                                           *
-*********************************************************************************************************************************/
-
-/**
- * Calls the internal networking switch service living in either R0 or in another R3 process.
- *
- * @returns VBox status code.
- * @param   pThis           The internal network driver instance data.
- * @param   uOperation      The operation to execute.
- * @param   pReqHdr         Pointer to the request header.
- */
-static int intnetR3IfCtxCallSvc(PINTNETIFCTXINT pThis, uint32_t uOperation, PSUPVMMR0REQHDR pReqHdr)
-{
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-    if (pThis->fIntNetR3Svc)
-    {
-# if defined(RT_OS_DARWIN)
-        size_t cbReq = pReqHdr->cbReq;
-        xpc_object_t hObj = xpc_dictionary_create(NULL, NULL, 0);
-        xpc_dictionary_set_uint64(hObj, "req-id", uOperation);
-        xpc_dictionary_set_data(hObj, "req", pReqHdr, pReqHdr->cbReq);
-        xpc_object_t hObjReply = xpc_connection_send_message_with_reply_sync(pThis->hXpcCon, hObj);
-        int rc = (int)xpc_dictionary_get_int64(hObjReply, "rc");
-
-        size_t cbReply = 0;
-        const void *pvData = xpc_dictionary_get_data(hObjReply, "reply", &cbReply);
-        AssertRelease(cbReply == cbReq);
-        memcpy(pReqHdr, pvData, cbReq);
-        xpc_release(hObjReply);
-
-        return rc;
-# endif
-    }
-    else
-#else
-        RT_NOREF(pThis);
-#endif
-        return SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, uOperation, 0, pReqHdr);
-}
-
-
-#if defined(RT_OS_DARWIN) && defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-/**
- * Calls the internal networking switch service living in either R0 or in another R3 process.
- *
- * @returns VBox status code.
- * @param   pThis           The internal network driver instance data.
- * @param   uOperation      The operation to execute.
- * @param   pReqHdr         Pointer to the request header.
- */
-static int intnetR3IfCtxCallSvcAsync(PINTNETIFCTXINT pThis, uint32_t uOperation, PSUPVMMR0REQHDR pReqHdr)
-{
-    if (pThis->fIntNetR3Svc)
-    {
-        xpc_object_t hObj = xpc_dictionary_create(NULL, NULL, 0);
-        xpc_dictionary_set_uint64(hObj, "req-id", uOperation);
-        xpc_dictionary_set_data(hObj, "req", pReqHdr, pReqHdr->cbReq);
-        xpc_connection_send_message(pThis->hXpcCon, hObj);
-        return VINF_SUCCESS;
-    }
-    else
-        return SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, uOperation, 0, pReqHdr);
-}
-#endif
-
-
-/**
- * Map the ring buffer pointer into this process R3 address space.
- *
- * @returns VBox status code.
- * @param   pThis           The internal network driver instance data.
- */
-static int intnetR3IfCtxMapBufferPointers(PINTNETIFCTXINT pThis)
-{
-    int rc = VINF_SUCCESS;
-
-    INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
-    GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-    GetBufferPtrsReq.Hdr.cbReq    = sizeof(GetBufferPtrsReq);
-    GetBufferPtrsReq.pSession     = pThis->pSupDrvSession;
-    GetBufferPtrsReq.hIf          = pThis->hIf;
-    GetBufferPtrsReq.pRing3Buf    = NULL;
-    GetBufferPtrsReq.pRing0Buf    = NIL_RTR0PTR;
-
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-    if (pThis->fIntNetR3Svc)
-    {
-#if defined(RT_OS_DARWIN)
-        xpc_object_t hObj = xpc_dictionary_create(NULL, NULL, 0);
-        xpc_dictionary_set_uint64(hObj, "req-id", VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS);
-        xpc_dictionary_set_data(hObj, "req", &GetBufferPtrsReq, sizeof(GetBufferPtrsReq));
-        xpc_object_t hObjReply = xpc_connection_send_message_with_reply_sync(pThis->hXpcCon, hObj);
-        rc = (int)xpc_dictionary_get_int64(hObjReply, "rc");
-        if (RT_SUCCESS(rc))
-        {
-            /* Get the shared memory object. */
-            xpc_object_t hObjShMem = xpc_dictionary_get_value(hObjReply, "buf-ptr");
-            size_t cbMem = xpc_shmem_map(hObjShMem, (void **)&pThis->pBuf);
-            if (!cbMem)
-                rc = VERR_NO_MEMORY;
-            else
-                pThis->cbBuf = cbMem;
-        }
-        xpc_release(hObjReply);
-#endif
-    }
-    else
-#endif
-    {
-        rc = SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, 0 /*u64Arg*/, &GetBufferPtrsReq.Hdr);
-        if (RT_SUCCESS(rc))
-        {
-            AssertRelease(RT_VALID_PTR(GetBufferPtrsReq.pRing3Buf));
-            pThis->pBuf = GetBufferPtrsReq.pRing3Buf;
-        }
-    }
-
-    return rc;
-}
-
-
-static void intnetR3IfCtxClose(PINTNETIFCTXINT pThis)
-{
-    if (pThis->hIf != INTNET_HANDLE_INVALID)
-    {
-        INTNETIFCLOSEREQ CloseReq;
-        CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-        CloseReq.Hdr.cbReq    = sizeof(CloseReq);
-        CloseReq.pSession     = pThis->pSupDrvSession;
-        CloseReq.hIf          = pThis->hIf;
-
-        pThis->hIf = INTNET_HANDLE_INVALID;
-        int rc = intnetR3IfCtxCallSvc(pThis, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq.Hdr);
-        AssertRC(rc);
-    }
-}
-
-
-DECLHIDDEN(int) IntNetR3IfCtxCreate(PINTNETIFCTX phIfCtx, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
-                                    const char *pszTrunk, uint32_t cbSend, uint32_t cbRecv, uint32_t fFlags)
-{
-    AssertPtrReturn(phIfCtx, VERR_INVALID_POINTER);
-    AssertPtrReturn(pszNetwork, VERR_INVALID_POINTER);
-    AssertPtrReturn(pszTrunk, VERR_INVALID_POINTER);
-
-    PSUPDRVSESSION pSession = NIL_RTR0PTR;
-    int rc = SUPR3Init(&pSession);
-    if (RT_SUCCESS(rc))
-    {
-        PINTNETIFCTXINT pThis = (PINTNETIFCTXINT)RTMemAllocZ(sizeof(*pThis));
-        if (RT_LIKELY(pThis))
-        {
-            pThis->pSupDrvSession = pSession;
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-            pThis->hEvtRecv       = NIL_RTSEMEVENT;
-#endif
-
-            /* Driverless operation needs support for running the internal network switch using IPC. */
-            if (SUPR3IsDriverless())
-            {
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-# if defined(RT_OS_DARWIN)
-                xpc_connection_t hXpcCon = xpc_connection_create(INTNET_R3_SVC_NAME, NULL);
-                xpc_connection_set_event_handler(hXpcCon, ^(xpc_object_t hObj) {
-                    if (xpc_get_type(hObj) == XPC_TYPE_ERROR)
-                    {
-                        /** @todo Error handling - reconnecting. */
-                    }
-                    else
-                    {
-                        /* Out of band messages should only come when there is something to receive. */
-                        RTSemEventSignal(pThis->hEvtRecv);
-                    }
-                });
-
-                xpc_connection_activate(hXpcCon);
-                pThis->hXpcCon      = hXpcCon;
-# endif
-                pThis->fIntNetR3Svc = true;
-                rc = RTSemEventCreate(&pThis->hEvtRecv);
-#else
-                rc = VERR_SUP_DRIVERLESS;
-#endif
-            }
-            else
-            {
-                /* Need to load VMMR0.r0 containing the network switching code. */
-                char szPathVMMR0[RTPATH_MAX];
-
-                rc = RTPathExecDir(szPathVMMR0, sizeof(szPathVMMR0));
-                if (RT_SUCCESS(rc))
-                {
-                    rc = RTPathAppend(szPathVMMR0, sizeof(szPathVMMR0), "VMMR0.r0");
-                    if (RT_SUCCESS(rc))
-                        rc = SUPR3LoadVMM(szPathVMMR0, /* :pErrInfo */ NULL);
-                }
-            }
-
-            if (RT_SUCCESS(rc))
-            {
-                /* Open the interface. */
-                INTNETOPENREQ OpenReq;
-                RT_ZERO(OpenReq);
-
-                OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-                OpenReq.Hdr.cbReq    = sizeof(OpenReq);
-                OpenReq.pSession     = pThis->pSupDrvSession;
-                OpenReq.enmTrunkType = enmTrunkType;
-                OpenReq.fFlags       = fFlags;
-                OpenReq.cbSend       = cbSend;
-                OpenReq.cbRecv       = cbRecv;
-                OpenReq.hIf          = INTNET_HANDLE_INVALID;
-
-                rc = RTStrCopy(OpenReq.szNetwork, sizeof(OpenReq.szNetwork), pszNetwork);
-                if (RT_SUCCESS(rc))
-                    rc = RTStrCopy(OpenReq.szTrunk, sizeof(OpenReq.szTrunk), pszTrunk);
-                if (RT_SUCCESS(rc))
-                {
-                    rc = intnetR3IfCtxCallSvc(pThis, VMMR0_DO_INTNET_OPEN, &OpenReq.Hdr);
-                    if (RT_SUCCESS(rc))
-                    {
-                        pThis->hIf = OpenReq.hIf;
-
-                        rc = intnetR3IfCtxMapBufferPointers(pThis);
-                        if (RT_SUCCESS(rc))
-                        {
-                            *phIfCtx = pThis;
-                            return VINF_SUCCESS;
-                        }
-                    }
-
-                    intnetR3IfCtxClose(pThis);
-                }
-            }
-
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-            if (pThis->fIntNetR3Svc)
-            {
-# if defined(RT_OS_DARWIN)
-                if (pThis->hXpcCon)
-                    xpc_connection_cancel(pThis->hXpcCon);
-                pThis->hXpcCon = NULL;
-# endif
-
-                if (pThis->hEvtRecv != NIL_RTSEMEVENT)
-                    RTSemEventDestroy(pThis->hEvtRecv);
-            }
-#endif
-
-            RTMemFree(pThis);
-        }
-
-        SUPR3Term();
-    }
-
-    return rc;
-}
-
-
-DECLHIDDEN(int) IntNetR3IfCtxDestroy(INTNETIFCTX hIfCtx)
-{
-    PINTNETIFCTXINT pThis = hIfCtx;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-
-    intnetR3IfCtxClose(pThis);
-
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-    if (pThis->fIntNetR3Svc)
-    {
-# if defined(RT_OS_DARWIN)
-        /* Unmap the shared buffer. */
-        munmap(pThis->pBuf, pThis->cbBuf);
-        xpc_connection_cancel(pThis->hXpcCon);
-        pThis->hXpcCon      = NULL;
-# endif
-        RTSemEventDestroy(pThis->hEvtRecv);
-        pThis->fIntNetR3Svc = false;
-    }
-#endif
-
-    RTMemFree(pThis);
-    return VINF_SUCCESS;
-}
-
-
-DECLHIDDEN(int) IntNetR3IfCtxQueryBufferPtr(INTNETIFCTX hIfCtx, PINTNETBUF *ppIfBuf)
-{
-    PINTNETIFCTXINT pThis = hIfCtx;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-    AssertPtrReturn(ppIfBuf, VERR_INVALID_POINTER);
-
-    *ppIfBuf = pThis->pBuf;
-    return VINF_SUCCESS;
-}
-
-
-DECLHIDDEN(int) IntNetR3IfCtxSetActive(INTNETIFCTX hIfCtx, bool fActive)
-{
-    PINTNETIFCTXINT pThis = hIfCtx;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-
-    INTNETIFSETACTIVEREQ Req;
-    Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-    Req.Hdr.cbReq    = sizeof(Req);
-    Req.pSession     = pThis->pSupDrvSession;
-    Req.hIf          = pThis->hIf;
-    Req.fActive      = fActive;
-    return intnetR3IfCtxCallSvc(pThis, VMMR0_DO_INTNET_IF_SET_ACTIVE, &Req.Hdr);
-}
-
-
-DECLHIDDEN(int) IntNetR3IfCtxSetPromiscuous(INTNETIFCTX hIfCtx, bool fPromiscuous)
-{
-    PINTNETIFCTXINT pThis = hIfCtx;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-
-    INTNETIFSETPROMISCUOUSMODEREQ Req;
-    Req.Hdr.u32Magic    = SUPVMMR0REQHDR_MAGIC;
-    Req.Hdr.cbReq       = sizeof(Req);
-    Req.pSession        = pThis->pSupDrvSession;
-    Req.hIf             = pThis->hIf;
-    Req.fPromiscuous    = fPromiscuous;
-    return intnetR3IfCtxCallSvc(pThis, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req.Hdr);
-}
-
-
-DECLHIDDEN(int) IntNetR3IfSend(INTNETIFCTX hIfCtx)
-{
-    PINTNETIFCTXINT pThis = hIfCtx;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-
-    INTNETIFSENDREQ Req;
-    Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-    Req.Hdr.cbReq    = sizeof(Req);
-    Req.pSession     = pThis->pSupDrvSession;
-    Req.hIf          = pThis->hIf;
-    return intnetR3IfCtxCallSvc(pThis, VMMR0_DO_INTNET_IF_SEND, &Req.Hdr);
-}
-
-
-DECLHIDDEN(int) IntNetR3IfWait(INTNETIFCTX hIfCtx, uint32_t cMillies)
-{
-    PINTNETIFCTXINT pThis = hIfCtx;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-
-    int rc = VINF_SUCCESS;
-    INTNETIFWAITREQ WaitReq;
-    WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-    WaitReq.Hdr.cbReq    = sizeof(WaitReq);
-    WaitReq.pSession     = pThis->pSupDrvSession;
-    WaitReq.hIf          = pThis->hIf;
-    WaitReq.cMillies     = cMillies;
-#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3)
-    if (pThis->fIntNetR3Svc)
-    {
-        /* Send an asynchronous message. */
-        rc = intnetR3IfCtxCallSvcAsync(pThis, VMMR0_DO_INTNET_IF_WAIT, &WaitReq.Hdr);
-        if (RT_SUCCESS(rc))
-        {
-            /* Wait on the receive semaphore. */
-            rc = RTSemEventWait(pThis->hEvtRecv, cMillies);
-        }
-    }
-    else
-#endif
-        rc = intnetR3IfCtxCallSvc(pThis, VMMR0_DO_INTNET_IF_WAIT, &WaitReq.Hdr);
-
-    return rc;
-}
-
-
-DECLHIDDEN(int) IntNetR3IfWaitAbort(INTNETIFCTX hIfCtx)
-{
-    PINTNETIFCTXINT pThis = hIfCtx;
-    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
-
-    INTNETIFABORTWAITREQ AbortWaitReq;
-    AbortWaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-    AbortWaitReq.Hdr.cbReq    = sizeof(AbortWaitReq);
-    AbortWaitReq.pSession     = pThis->pSupDrvSession;
-    AbortWaitReq.hIf          = pThis->hIf;
-    AbortWaitReq.fNoMoreWaits = true;
-    return intnetR3IfCtxCallSvc(pThis, VMMR0_DO_INTNET_IF_ABORT_WAIT, &AbortWaitReq.Hdr);
-}
