summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Network/DrvDedicatedNic.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/Network/DrvDedicatedNic.cpp
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/Network/DrvDedicatedNic.cpp')
-rw-r--r--src/VBox/Devices/Network/DrvDedicatedNic.cpp577
1 files changed, 577 insertions, 0 deletions
diff --git a/src/VBox/Devices/Network/DrvDedicatedNic.cpp b/src/VBox/Devices/Network/DrvDedicatedNic.cpp
new file mode 100644
index 00000000..c1de8109
--- /dev/null
+++ b/src/VBox/Devices/Network/DrvDedicatedNic.cpp
@@ -0,0 +1,577 @@
+/* $Id: DrvDedicatedNic.cpp $ */
+/** @file
+ * DrvDedicatedNic - Experimental network driver for using a dedicated (V)NIC.
+ */
+
+/*
+ * Copyright (C) 2010-2023 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 LOG_GROUP LOG_GROUP_DEFAULT
+#include <VBox/log.h>
+#include <VBox/vmm/pdmcritsect.h>
+#include <VBox/vmm/pdmdrv.h>
+#include <VBox/vmm/pdmnetifs.h>
+#include <VBox/vmm/pdmnetinline.h>
+#include <VBox/intnet.h>
+#include <VBox/intnetinline.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+#include <iprt/uuid.h>
+
+#include "VBoxDD.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * Instance data for the dedicated (V)NIC driver.
+ *
+ * @implements PDMINETWORKUP
+ */
+typedef struct DRVDEDICATEDNIC
+{
+ /** The network interface. */
+ PDMINETWORKUP INetworkUpR3;
+ /** The network interface. */
+ R3PTRTYPE(PPDMINETWORKDOWN) pIAboveNet;
+ /** The network config interface.
+ * Can (in theory at least) be NULL. */
+ R3PTRTYPE(PPDMINETWORKCONFIG) pIAboveConfigR3;
+ /** Pointer to the driver instance. */
+ PPDMDRVINSR3 pDrvInsR3;
+ /** Ring-3 base interface for the ring-0 context. */
+ PDMIBASER0 IBaseR0;
+ /** Ring-3 base interface for the raw-mode context. */
+ PDMIBASERC IBaseRC;
+ RTR3PTR R3PtrAlignment;
+
+
+ /** The network interface for the ring-0 context. */
+ PDMINETWORKUPR0 INetworkUpR0;
+ /** Pointer to the driver instance. */
+ PPDMDRVINSR0 pDrvInsR0;
+ RTR0PTR R0PtrAlignment;
+
+ /** The interface we're talking to. */
+ R0PTRTYPE(PINTNETTRUNKIFPORT) pIfPortR0;
+ /** Set if the link is up, clear if its down. */
+ bool fLinkDown;
+ /** Set if the current transmit operation is done the XMIT thread. If clear,
+ * we assume its an EMT. */
+ bool fXmitOnXmitThread;
+ /** The name of the interface that we're connected to. */
+ char szIfName[128 + 8 - 2];
+
+ /** Critical section serializing transmission. */
+ PDMCRITSECT XmitLock;
+ /** The transmit scatter gather buffer (ring-3 -> ring-0). */
+ PDMSCATTERGATHER XmitSg;
+ /** The transmit GSO context (when applicable). */
+ PDMNETWORKGSO XmitGso;
+ /** The transmit buffer (ring-3 -> ring-0). */
+ uint8_t abXmitBuf[_64K];
+
+ /** The receive scatter gather buffer. */
+ PDMSCATTERGATHER RecvSg;
+ /** The receive buffer (ring-0 -> ring-3). */
+ uint8_t abRecvBuf[_64K];
+
+} DRVDEDICATEDNIC;
+/** Pointer to the instance data for the dedicated (V)NIC driver. */
+typedef DRVDEDICATEDNIC *PDRVDEDICATEDNIC;
+
+/**
+ * Ring-0 operations.
+ */
+typedef enum DRVDEDICATEDNICR0OP
+{
+ /** Invalid zero value.. */
+ DRVDEDICATEDNICR0OP_INVALID = 0,
+ /** Initialize the connection to the NIC. */
+ DRVDEDICATEDNICR0OP_INIT,
+ /** Terminate the connection to the NIC. */
+ DRVDEDICATEDNICR0OP_TERM,
+ /** Suspend the operation. */
+ DRVDEDICATEDNICR0OP_SUSPEND,
+ /** Resume the operation. */
+ DRVDEDICATEDNICR0OP_RESUME,
+ /** Wait for and do receive work.
+ * We do this in ring-0 instead of ring-3 to save 1-2 buffer copies and
+ * unnecessary context switching. */
+ DRVDEDICATEDNICR0OP_RECV,
+ /** Wait for and do transmit work.
+ * We do this in ring-0 instead of ring-3 to save 1-2 buffer copies and
+ * unnecessary context switching. */
+ DRVDEDICATEDNICR0OP_SEND,
+ /** Changes the promiscuousness of the interface (guest point of view). */
+ DRVDEDICATEDNICR0OP_PROMISC,
+ /** End of the valid operations. */
+ DRVDEDICATEDNICR0OP_END,
+ /** The usual 32-bit hack. */
+ DRVDEDICATEDNICR0OP_32BIT_HACK = 0x7fffffff
+} DRVDEDICATEDNICR0OP;
+
+
+
+#ifdef IN_RING0
+
+/**
+ * @interface_method_impl{FNPDMDRVREQHANDLERR0}
+ */
+PDMBOTHCBDECL(int) drvR0DedicatedNicReqHandler(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
+{
+ RT_NOREF_PV(pDrvIns); RT_NOREF_PV(u64Arg);
+ switch ((DRVDEDICATEDNICR0OP)uOperation)
+ {
+ case DRVDEDICATEDNICR0OP_INIT:
+ return VERR_NOT_IMPLEMENTED;//drvR0DedicatedNicReqInit(pDrvIns, u64Arg);
+
+ case DRVDEDICATEDNICR0OP_TERM:
+ return VERR_NOT_IMPLEMENTED;//drvR0DedicatedNicReqTerm(pDrvIns);
+
+ case DRVDEDICATEDNICR0OP_SUSPEND:
+ return VERR_NOT_IMPLEMENTED;//drvR0DedicatedNicReqSuspend(pDrvIns);
+
+ case DRVDEDICATEDNICR0OP_RESUME:
+ return VERR_NOT_IMPLEMENTED;//drvR0DedicatedNicReqResume(pDrvIns);
+
+ case DRVDEDICATEDNICR0OP_RECV:
+ return VERR_NOT_IMPLEMENTED;//drvR0DedicatedNicReqRecv(pDrvIns);
+
+ case DRVDEDICATEDNICR0OP_SEND:
+ return VERR_NOT_IMPLEMENTED;//drvR0DedicatedNicReqSend(pDrvIns);
+
+ case DRVDEDICATEDNICR0OP_PROMISC:
+ return VERR_NOT_IMPLEMENTED;//drvR0DedicatedNicReqPromisc(pDrvIns, !!u64Arg);
+
+ case DRVDEDICATEDNICR0OP_END:
+ default:
+ return VERR_INVALID_FUNCTION;
+ }
+}
+
+#endif /* IN_RING0 */
+
+
+
+#if 0 /* currently unused */
+
+/* -=-=-=-=- PDMINETWORKUP -=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
+ */
+PDMBOTHCBDECL(int) drvDedicatedNicUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
+{
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
+ int rc = PDMCritSectTryEnter(&pThis->XmitLock);
+ if (RT_SUCCESS(rc))
+ ASMAtomicUoWriteBool(&pThis->fXmitOnXmitThread, fOnWorkerThread);
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
+ */
+PDMBOTHCBDECL(int) drvDedicatedNicUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
+ PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
+{
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
+ Assert(PDMCritSectIsOwner(&pThis->XmitLock));
+
+ /*
+ * If the net is down, we can return immediately.
+ */
+ if (pThis->fLinkDown)
+ return VERR_NET_DOWN;
+
+#ifdef IN_RING0
+ /** @todo Ask the driver for a buffer, atomically if we're called on EMT. */
+ RT_NOREF_PV(cbMin); RT_NOREF_PV(pGso); RT_NOREF_PV(ppSgBuf);
+ return VERR_TRY_AGAIN;
+
+#else /* IN_RING3 */
+ /*
+ * Are we busy or is the request too big?
+ */
+ if (RT_UNLIKELY((pThis->XmitSg.fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC))
+ return VERR_TRY_AGAIN;
+ if (cbMin > sizeof(pThis->abXmitBuf))
+ return VERR_NO_MEMORY;
+
+ /*
+ * Initialize the S/G buffer and return.
+ */
+ pThis->XmitSg.fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
+ pThis->XmitSg.cbUsed = 0;
+ pThis->XmitSg.cbAvailable = sizeof(pThis->abXmitBuf);
+ pThis->XmitSg.pvAllocator = NULL;
+ if (!pGso)
+ {
+ pThis->XmitSg.pvUser = NULL;
+ pThis->XmitGso.u8Type = PDMNETWORKGSOTYPE_INVALID;
+ }
+ else
+ {
+ pThis->XmitSg.pvUser = &pThis->XmitGso;
+ pThis->XmitGso = *pGso;
+ }
+ pThis->XmitSg.cSegs = 1;
+ pThis->XmitSg.aSegs[0].cbSeg = pThis->XmitSg.cbAvailable;
+ pThis->XmitSg.aSegs[0].pvSeg = &pThis->abXmitBuf[0];
+
+# if 0 /* poison */
+ memset(pThis->XmitSg.aSegs[0].pvSeg, 'F', pThis->XmitSg.aSegs[0].cbSeg);
+# endif
+
+ *ppSgBuf = &pThis->XmitSg;
+ return VINF_SUCCESS;
+#endif /* IN_RING3 */
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
+ */
+PDMBOTHCBDECL(int) drvDedicatedNicUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
+{
+#ifdef VBOX_STRICT
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
+ Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
+ Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
+ Assert(PDMCritSectIsOwner(&pThis->XmitLock));
+#else
+ RT_NOREF1(pInterface);
+#endif
+
+ if (pSgBuf)
+ {
+#ifdef IN_RING0
+ // ...
+#else
+ Assert(pSgBuf == &pThis->XmitSg);
+ Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
+ pSgBuf->fFlags = 0;
+#endif
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
+ */
+PDMBOTHCBDECL(int) drvDedicatedNicUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
+{
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
+ STAM_PROFILE_START(&pThis->StatTransmit, a);
+
+ AssertPtr(pSgBuf);
+ Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
+ Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
+#ifdef IN_RING0
+ Assert(pSgBuf == &pThis->XmitSg);
+#endif
+ Assert(PDMCritSectIsOwner(&pThis->XmitLock));
+
+#ifdef IN_RING0
+ /*
+ * Tell the driver to send the packet.
+ */
+ RT_NOREF_PV(pThis); RT_NOREF_PV(pSgBuf); RT_NOREF_PV(fOnWorkerThread);
+ return VERR_INTERNAL_ERROR_4;
+
+#else /* IN_RING3 */
+ NOREF(fOnWorkerThread);
+
+ /*
+ * Call ring-0 to start the transfer.
+ */
+ int rc = PDMDrvHlpCallR0(pThis->pDrvInsR3, DRVDEDICATEDNICR0OP_SEND, pSgBuf->cbUsed);
+ if (RT_FAILURE(rc) && rc != VERR_NET_DOWN)
+ rc = VERR_NET_NO_BUFFER_SPACE;
+ pSgBuf->fFlags = 0;
+ return rc;
+#endif /* IN_RING3 */
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
+ */
+PDMBOTHCBDECL(void) drvDedicatedNicUp_EndXmit(PPDMINETWORKUP pInterface)
+{
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
+ ASMAtomicUoWriteBool(&pThis->fXmitOnXmitThread, false);
+ PDMCritSectLeave(&pThis->XmitLock);
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
+ */
+PDMBOTHCBDECL(void) drvDedicatedNicUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
+{
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
+ /** @todo enable/disable promiscuous mode (should be easy) */
+ NOREF(pThis); RT_NOREF_PV(fPromiscuous);
+}
+
+#endif /* unused */
+#ifdef IN_RING3
+# if 0 /* currently unused */
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnNotifyLinkChanged}
+ */
+static DECLCALLBACK(void) drvR3DedicatedNicUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
+{
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, CTX_SUFF(INetworkUp));
+ bool fLinkDown;
+ switch (enmLinkState)
+ {
+ case PDMNETWORKLINKSTATE_DOWN:
+ case PDMNETWORKLINKSTATE_DOWN_RESUME:
+ fLinkDown = true;
+ break;
+ default:
+ AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
+ case PDMNETWORKLINKSTATE_UP:
+ fLinkDown = false;
+ break;
+ }
+ LogFlow(("drvR3DedicatedNicUp_NotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
+ ASMAtomicWriteBool(&pThis->fLinkDown, fLinkDown);
+}
+
+
+/* -=-=-=-=- PDMIBASER0 -=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMIBASER0,pfnQueryInterface}
+ */
+static DECLCALLBACK(RTR0PTR) drvR3DedicatedNicIBaseR0_QueryInterface(PPDMIBASER0 pInterface, const char *pszIID)
+{
+ PDRVDEDICATEDNIC pThis = RT_FROM_MEMBER(pInterface, DRVDEDICATEDNIC, IBaseR0);
+ PDMIBASER0_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMINETWORKUP, &pThis->INetworkUpR0);
+ return NIL_RTR0PTR;
+}
+
+
+/* -=-=-=-=- PDMIBASE -=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvR3DedicatedNicIBase_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVDEDICATEDNIC pThis = PDMINS_2_DATA(pDrvIns, PDRVDEDICATEDNIC);
+
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASER0, &pThis->IBaseR0);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUpR3);
+ return NULL;
+}
+
+# endif /* Currently unused */
+
+
+/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnPowerOff}
+ */
+static DECLCALLBACK(void) drvR3DedicatedNicPowerOff(PPDMDRVINS pDrvIns)
+{
+ LogFlow(("drvR3DedicatedNicPowerOff\n"));
+ int rc = PDMDrvHlpCallR0(pDrvIns, DRVDEDICATEDNICR0OP_SUSPEND, 0);
+ AssertRC(rc);
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnResume}
+ */
+static DECLCALLBACK(void) drvR3DedicatedNicResume(PPDMDRVINS pDrvIns)
+{
+ LogFlow(("drvR3DedicatedNicPowerResume\n"));
+ int rc = PDMDrvHlpCallR0(pDrvIns, DRVDEDICATEDNICR0OP_RESUME, 0);
+ AssertRC(rc);
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnSuspend}
+ */
+static DECLCALLBACK(void) drvR3DedicatedNicSuspend(PPDMDRVINS pDrvIns)
+{
+ LogFlow(("drvR3DedicatedNicPowerSuspend\n"));
+ int rc = PDMDrvHlpCallR0(pDrvIns, DRVDEDICATEDNICR0OP_SUSPEND, 0);
+ AssertRC(rc);
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnPowerOn}
+ */
+static DECLCALLBACK(void) drvR3DedicatedNicPowerOn(PPDMDRVINS pDrvIns)
+{
+ LogFlow(("drvR3DedicatedNicPowerOn\n"));
+ int rc = PDMDrvHlpCallR0(pDrvIns, DRVDEDICATEDNICR0OP_RESUME, 0);
+ AssertRC(rc);
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnDestruct}
+ */
+static DECLCALLBACK(void) drvR3DedicatedNicDestruct(PPDMDRVINS pDrvIns)
+{
+ LogFlow(("drvR3DedicatedNicDestruct\n"));
+ PDRVDEDICATEDNIC pThis = PDMINS_2_DATA(pDrvIns, PDRVDEDICATEDNIC);
+ PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+
+ if (pThis->pIfPortR0)
+ {
+ int rc = PDMDrvHlpCallR0(pDrvIns, DRVDEDICATEDNICR0OP_TERM, 0);
+ AssertRC(rc);;
+ }
+}
+
+
+/**
+ * @interface_method_impl{PDMDRVREG,pfnConstruct}
+ */
+static DECLCALLBACK(int) drvR3DedicatedNicConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+ RT_NOREF(pCfg, fFlags);
+ PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+ PDRVDEDICATEDNIC pThis = PDMINS_2_DATA(pDrvIns, PDRVDEDICATEDNIC);
+
+ /*
+ * Init the static parts.
+ */
+ pThis->pDrvInsR3 = pDrvIns;
+ pThis->pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
+#if 0
+ pThis->hRecvThread = NIL_RTTHREAD;
+ pThis->hRecvEvt = NIL_RTSEMEVENT;
+ pThis->pXmitThread = NULL;
+ pThis->hXmitEvt = NIL_SUPSEMEVENT;
+ pThis->pSupDrvSession = PDMDrvHlpGetSupDrvSession(pDrvIns);
+ pThis->hSgCache = NIL_RTMEMCACHE;
+ pThis->enmRecvState = RECVSTATE_SUSPENDED;
+ pThis->fActivateEarlyDeactivateLate = false;
+ /* IBase* */
+ pDrvIns->IBase.pfnQueryInterface = drvR3DedicatedNicIBase_QueryInterface;
+ pThis->IBaseR0.pfnQueryInterface = drvR3DedicatedNicIBaseR0_QueryInterface;
+ pThis->IBaseRC.pfnQueryInterface = drvR3DedicatedNicIBaseRC_QueryInterface;
+ /* INetworkUp */
+ pThis->INetworkUpR3.pfnBeginXmit = drvDedicatedNic_BeginXmit;
+ pThis->INetworkUpR3.pfnAllocBuf = drvDedicatedNic_AllocBuf;
+ pThis->INetworkUpR3.pfnFreeBuf = drvDedicatedNic_FreeBuf;
+ pThis->INetworkUpR3.pfnSendBuf = drvDedicatedNic_SendBuf;
+ pThis->INetworkUpR3.pfnEndXmit = drvDedicatedNic_EndXmit;
+ pThis->INetworkUpR3.pfnSetPromiscuousMode = drvDedicatedNic_SetPromiscuousMode;
+ pThis->INetworkUpR3.pfnNotifyLinkChanged = drvR3DedicatedNicUp_NotifyLinkChanged;
+#endif
+
+ /** @todo
+ * Need to create a generic way of calling into the ring-0 side of the driver so
+ * we can initialize the thing as well as send and receive. Hmm ... the
+ * sending could be done more efficiently from a ring-0 kernel thread actually
+ * (saves context switching and 1-2 copy operations). Ditto for receive, except
+ * we need to tie the thread to the process or we cannot access the guest ram so
+ * easily.
+ */
+
+ return VERR_NOT_IMPLEMENTED;
+}
+
+
+
+/**
+ * Internal networking transport driver registration record.
+ */
+const PDMDRVREG g_DrvDedicatedNic =
+{
+ /* u32Version */
+ PDM_DRVREG_VERSION,
+ /* szName */
+ "DedicatedNic",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "VBoxDDR0.r0",
+ /* pszDescription */
+ "Dedicated (V)NIC Driver",
+ /* fFlags */
+ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0,
+ /* fClass. */
+ PDM_DRVREG_CLASS_NETWORK,
+ /* cMaxInstances */
+ ~0U,
+ /* cbInstance */
+ sizeof(DRVDEDICATEDNIC),
+ /* pfnConstruct */
+ drvR3DedicatedNicConstruct,
+ /* pfnDestruct */
+ drvR3DedicatedNicDestruct,
+ /* pfnRelocate */
+ NULL,
+ /* pfnIOCtl */
+ NULL,
+ /* pfnPowerOn */
+ drvR3DedicatedNicPowerOn,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ drvR3DedicatedNicSuspend,
+ /* pfnResume */
+ drvR3DedicatedNicResume,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnPowerOff */
+ drvR3DedicatedNicPowerOff,
+ /* pfnSoftReset */
+ NULL,
+ /* u32EndVersion */
+ PDM_DRVREG_VERSION
+};
+
+#endif /* IN_RING3 */
+