summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetAdp/win
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/HostDrivers/VBoxNetAdp/win
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/HostDrivers/VBoxNetAdp/win')
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp1888
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h71
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc72
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf101
5 files changed, 2132 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup b/src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp
new file mode 100644
index 00000000..d89ba4d0
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp
@@ -0,0 +1,1888 @@
+/* $Id: VBoxNetAdp-win.cpp $ */
+/** @file
+ * VBoxNetAdp-win.cpp - NDIS6 Host-only Networking Driver, Windows-specific code.
+ */
+/*
+ * Copyright (C) 2014-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+
+#include <VBox/log.h>
+#include <VBox/version.h>
+#include <VBox/err.h>
+#include <VBox/sup.h>
+#include <VBox/intnet.h>
+#include <VBox/intnetinline.h>
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/list.h>
+#include <iprt/net.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+
+#include <iprt/nt/ntddk.h>
+#include <iprt/nt/ndis.h>
+
+#include "VBoxNetAdp-win.h"
+#include "VBox/VBoxNetCmn-win.h"
+
+#define VBOXNETADP_MEM_TAG 'OHBV'
+
+/*
+ * By default the link speed reported to be 1Gbps. We may wish to lower
+ * it to 100Mbps to work around issues with multi-cast traffic on the host.
+ * See @bugref{6379}.
+ */
+#define VBOXNETADPWIN_LINK_SPEED 1000000000ULL
+
+#define LogError LogRel
+
+/* Forward declarations */
+MINIPORT_INITIALIZE vboxNetAdpWinInitializeEx;
+MINIPORT_HALT vboxNetAdpWinHaltEx;
+MINIPORT_UNLOAD vboxNetAdpWinUnload;
+MINIPORT_PAUSE vboxNetAdpWinPause;
+MINIPORT_RESTART vboxNetAdpWinRestart;
+MINIPORT_OID_REQUEST vboxNetAdpWinOidRequest;
+MINIPORT_SEND_NET_BUFFER_LISTS vboxNetAdpWinSendNetBufferLists;
+MINIPORT_RETURN_NET_BUFFER_LISTS vboxNetAdpWinReturnNetBufferLists;
+MINIPORT_CANCEL_SEND vboxNetAdpWinCancelSend;
+MINIPORT_CHECK_FOR_HANG vboxNetAdpWinCheckForHangEx;
+MINIPORT_RESET vboxNetAdpWinResetEx;
+MINIPORT_DEVICE_PNP_EVENT_NOTIFY vboxNetAdpWinDevicePnPEventNotify;
+MINIPORT_SHUTDOWN vboxNetAdpWinShutdownEx;
+MINIPORT_CANCEL_OID_REQUEST vboxNetAdpWinCancelOidRequest;
+
+
+/* Packet types by destination address; used in statistics. */
+typedef enum {
+ kVBoxNetAdpWinPacketType_Unicast,
+ kVBoxNetAdpWinPacketType_Multicast,
+ kVBoxNetAdpWinPacketType_Broadcast,
+ kVBoxNetAdpWinPacketType_ArraySize /* Must be the last one */
+} VBOXNETADPWIN_PACKET_TYPE;
+
+
+/* Miniport states as defined by NDIS. */
+typedef enum {
+ kVBoxNetAdpWinState_Initializing,
+ kVBoxNetAdpWinState_Paused,
+ kVBoxNetAdpWinState_Restarting,
+ kVBoxNetAdpWinState_Running,
+ kVBoxNetAdpWinState_Pausing,
+ kVBoxNetAdpWinState_32BitHack = 0x7fffffff
+} VBOXNETADPWIN_ADAPTER_STATE;
+
+
+/*
+ * Valid state transitions are:
+ * 1) Disconnected -> Connecting : start the worker thread, attempting to init IDC;
+ * 2) Connecting -> Disconnected : failed to start IDC init worker thread;
+ * 3) Connecting -> Connected : IDC init successful, terminate the worker;
+ * 4) Connecting -> Stopping : IDC init incomplete, but the driver is being unloaded, terminate the worker;
+ * 5) Connected -> Stopping : IDC init was successful, no worker, the driver is being unloaded;
+ *
+ * Driver terminates in either in Disconnected or in Stopping state.
+ */
+typedef enum {
+ kVBoxNetAdpWinIdcState_Disconnected = 0, /* Initial state */
+ kVBoxNetAdpWinIdcState_Connecting, /* Attemping to init IDC, worker thread running */
+ kVBoxNetAdpWinIdcState_Connected, /* Successfully connected to IDC, worker thread terminated */
+ kVBoxNetAdpWinIdcState_Stopping /* Terminating the worker thread and disconnecting IDC */
+} VBOXNETADPWIN_IDC_STATE;
+
+typedef struct _VBOXNETADPGLOBALS
+{
+ /** Miniport driver handle. */
+ NDIS_HANDLE hMiniportDriver;
+ /** Power management capabilities, shared by all instances, do not change after init. */
+ NDIS_PNP_CAPABILITIES PMCaps;
+ /** The INTNET trunk network interface factory. */
+ INTNETTRUNKFACTORY TrunkFactory;
+ /** The SUPDRV component factory registration. */
+ SUPDRVFACTORY SupDrvFactory;
+ /** The SUPDRV IDC handle (opaque struct). */
+ SUPDRVIDCHANDLE SupDrvIDC;
+ /** IDC init thread handle. */
+ HANDLE hInitIdcThread;
+ /** Lock protecting the following members. */
+ NDIS_SPIN_LOCK Lock;
+ /** Lock-protected: the head of module list. */
+ RTLISTANCHOR ListOfAdapters;
+ /** Lock-protected: The number of current factory references. */
+ int32_t volatile cFactoryRefs;
+ /** Lock-protected: IDC initialization state. */
+ volatile uint32_t enmIdcState;
+ /** Lock-protected: event signaled when trunk factory is not in use. */
+ NDIS_EVENT EventUnloadAllowed;
+} VBOXNETADPGLOBALS, *PVBOXNETADPGLOBALS;
+
+/* win-specific global data */
+VBOXNETADPGLOBALS g_VBoxNetAdpGlobals;
+
+
+typedef struct _VBOXNETADP_ADAPTER {
+ /** Auxiliary member to link adapters into a list. */
+ RTLISTNODE node;
+ /** Adapter handle for NDIS. */
+ NDIS_HANDLE hAdapter;
+ /** Memory pool network buffers are allocated from. */
+ NDIS_HANDLE hPool;
+ /** Our RJ-45 port.
+ * This is what the internal network plugs into. */
+ INTNETTRUNKIFPORT MyPort;
+ /** The RJ-45 port on the INTNET "switch".
+ * This is what we're connected to. */
+ PINTNETTRUNKSWPORT pSwitchPort;
+ /** Pointer to global data */
+ PVBOXNETADPGLOBALS pGlobals;
+ /** Adapter state in NDIS, used for assertions only */
+ VBOXNETADPWIN_ADAPTER_STATE volatile enmAdapterState; /// @todo do we need it really?
+ /** The trunk state. */
+ INTNETTRUNKIFSTATE volatile enmTrunkState;
+ /** Number of pending operations, when it reaches zero we signal EventIdle. */
+ int32_t volatile cBusy;
+ /** The event that is signaled when we go idle and that pfnWaitForIdle blocks on. */
+ NDIS_EVENT EventIdle;
+ /** MAC address of adapter. */
+ RTMAC MacAddr;
+ /** Statistics: bytes received from internal network. */
+ uint64_t au64StatsInOctets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Statistics: packets received from internal network. */
+ uint64_t au64StatsInPackets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Statistics: bytes sent to internal network. */
+ uint64_t au64StatsOutOctets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Statistics: packets sent to internal network. */
+ uint64_t au64StatsOutPackets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Adapter friendly name. */
+ char szName[1];
+} VBOXNETADP_ADAPTER;
+typedef VBOXNETADP_ADAPTER *PVBOXNETADP_ADAPTER;
+
+
+/* Port */
+
+#define IFPORT_2_VBOXNETADP_ADAPTER(pIfPort) \
+ ( (PVBOXNETADP_ADAPTER)((uint8_t *)(pIfPort) - RT_UOFFSETOF(VBOXNETADP_ADAPTER, MyPort)) )
+
+DECLINLINE(VBOXNETADPWIN_ADAPTER_STATE) vboxNetAdpWinGetState(PVBOXNETADP_ADAPTER pThis)
+{
+ return (VBOXNETADPWIN_ADAPTER_STATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmAdapterState);
+}
+
+DECLINLINE(VBOXNETADPWIN_ADAPTER_STATE) vboxNetAdpWinSetState(PVBOXNETADP_ADAPTER pThis, VBOXNETADPWIN_ADAPTER_STATE enmNewState)
+{
+ return (VBOXNETADPWIN_ADAPTER_STATE)ASMAtomicXchgU32((uint32_t volatile *)&pThis->enmAdapterState, enmNewState);
+}
+
+DECLINLINE(bool) vboxNetAdpWinSetState(PVBOXNETADP_ADAPTER pThis, VBOXNETADPWIN_ADAPTER_STATE enmNewState,
+ VBOXNETADPWIN_ADAPTER_STATE enmOldState)
+{
+ return ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmAdapterState, enmNewState, enmOldState);
+}
+
+#ifdef DEBUG
+
+DECLHIDDEN(void) vboxNetAdpWinDumpPackets(const char *pszMsg, PNET_BUFFER_LIST pBufLists)
+{
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
+ {
+ Log6(("%s packet: cb=%d offset=%d", pszMsg, NET_BUFFER_DATA_LENGTH(pBuf), NET_BUFFER_DATA_OFFSET(pBuf)));
+ for (PMDL pMdl = NET_BUFFER_FIRST_MDL(pBuf);
+ pMdl != NULL;
+ pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ Log6((" MDL: cb=%d", MmGetMdlByteCount(pMdl)));
+ }
+ Log6(("\n"));
+ }
+ }
+}
+
+DECLINLINE(const char *) vboxNetAdpWinEthTypeStr(uint16_t uType)
+{
+ switch (uType)
+ {
+ case RTNET_ETHERTYPE_IPV4: return "IP";
+ case RTNET_ETHERTYPE_IPV6: return "IPv6";
+ case RTNET_ETHERTYPE_ARP: return "ARP";
+ }
+ return "unknown";
+}
+
+#define VBOXNETADP_PKTDMPSIZE 0x50
+
+/**
+ * Dump a packet to debug log.
+ *
+ * @param cpPacket The packet.
+ * @param cb The size of the packet.
+ * @param cszText A string denoting direction of packet transfer.
+ */
+DECLINLINE(void) vboxNetAdpWinDumpPacket(PCINTNETSG pSG, const char *cszText)
+{
+ uint8_t bPacket[VBOXNETADP_PKTDMPSIZE];
+
+ uint32_t cb = pSG->cbTotal < VBOXNETADP_PKTDMPSIZE ? pSG->cbTotal : VBOXNETADP_PKTDMPSIZE;
+ IntNetSgReadEx(pSG, 0, cb, bPacket);
+
+ AssertReturnVoid(cb >= 14);
+
+ uint8_t *pHdr = bPacket;
+ uint8_t *pEnd = bPacket + cb;
+ AssertReturnVoid(pEnd - pHdr >= 14);
+ uint16_t uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+12));
+ Log2(("NetADP: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n",
+ cszText, pSG->cbTotal, pHdr+6, pHdr, vboxNetAdpWinEthTypeStr(uEthType), uEthType));
+ pHdr += sizeof(RTNETETHERHDR);
+ if (uEthType == RTNET_ETHERTYPE_VLAN)
+ {
+ AssertReturnVoid(pEnd - pHdr >= 4);
+ uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+2));
+ Log2((" + VLAN: id=%d EthType=%s(0x%x)\n", RT_N2H_U16(*(uint16_t*)(pHdr)) & 0xFFF,
+ vboxNetAdpWinEthTypeStr(uEthType), uEthType));
+ pHdr += 2 * sizeof(uint16_t);
+ }
+ uint8_t uProto = 0xFF;
+ switch (uEthType)
+ {
+ case RTNET_ETHERTYPE_IPV6:
+ AssertReturnVoid(pEnd - pHdr >= 40);
+ uProto = pHdr[6];
+ Log2((" + IPv6: %RTnaipv6 => %RTnaipv6\n", pHdr+8, pHdr+24));
+ pHdr += 40;
+ break;
+ case RTNET_ETHERTYPE_IPV4:
+ AssertReturnVoid(pEnd - pHdr >= 20);
+ uProto = pHdr[9];
+ Log2((" + IP: %RTnaipv4 => %RTnaipv4\n", *(uint32_t*)(pHdr+12), *(uint32_t*)(pHdr+16)));
+ pHdr += (pHdr[0] & 0xF) * 4;
+ break;
+ case RTNET_ETHERTYPE_ARP:
+ AssertReturnVoid(pEnd - pHdr >= 28);
+ AssertReturnVoid(RT_N2H_U16(*(uint16_t*)(pHdr+2)) == RTNET_ETHERTYPE_IPV4);
+ switch (RT_N2H_U16(*(uint16_t*)(pHdr+6)))
+ {
+ case 1: /* ARP request */
+ Log2((" + ARP-REQ: who-has %RTnaipv4 tell %RTnaipv4\n",
+ *(uint32_t*)(pHdr+24), *(uint32_t*)(pHdr+14)));
+ break;
+ case 2: /* ARP reply */
+ Log2((" + ARP-RPL: %RTnaipv4 is-at %RTmac\n",
+ *(uint32_t*)(pHdr+14), pHdr+8));
+ break;
+ default:
+ Log2((" + ARP: unknown op %d\n", RT_N2H_U16(*(uint16_t*)(pHdr+6))));
+ break;
+ }
+ break;
+ /* There is no default case as uProto is initialized with 0xFF */
+ }
+ while (uProto != 0xFF)
+ {
+ switch (uProto)
+ {
+ case 0: /* IPv6 Hop-by-Hop option*/
+ case 60: /* IPv6 Destination option*/
+ case 43: /* IPv6 Routing option */
+ case 44: /* IPv6 Fragment option */
+ Log2((" + IPv6 option (%d): <not implemented>\n", uProto));
+ uProto = pHdr[0];
+ pHdr += pHdr[1] * 8 + 8; /* Skip to the next extension/protocol */
+ break;
+ case 51: /* IPv6 IPsec AH */
+ Log2((" + IPv6 IPsec AH: <not implemented>\n"));
+ uProto = pHdr[0];
+ pHdr += (pHdr[1] + 2) * 4; /* Skip to the next extension/protocol */
+ break;
+ case 50: /* IPv6 IPsec ESP */
+ /* Cannot decode IPsec, fall through */
+ Log2((" + IPv6 IPsec ESP: <not implemented>\n"));
+ uProto = 0xFF;
+ break;
+ case 59: /* No Next Header */
+ Log2((" + IPv6 No Next Header\n"));
+ uProto = 0xFF;
+ break;
+ case 58: /* IPv6-ICMP */
+ switch (pHdr[0])
+ {
+ case 1: Log2((" + IPv6-ICMP: destination unreachable, code %d\n", pHdr[1])); break;
+ case 128: Log2((" + IPv6-ICMP: echo request\n")); break;
+ case 129: Log2((" + IPv6-ICMP: echo reply\n")); break;
+ default: Log2((" + IPv6-ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
+ }
+ uProto = 0xFF;
+ break;
+ case 1: /* ICMP */
+ switch (pHdr[0])
+ {
+ case 0: Log2((" + ICMP: echo reply\n")); break;
+ case 8: Log2((" + ICMP: echo request\n")); break;
+ case 3: Log2((" + ICMP: destination unreachable, code %d\n", pHdr[1])); break;
+ default: Log2((" + ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
+ }
+ uProto = 0xFF;
+ break;
+ case 6: /* TCP */
+ Log2((" + TCP: src=%d dst=%d seq=%x ack=%x\n",
+ RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)),
+ RT_N2H_U32(*(uint32_t*)(pHdr+4)), RT_N2H_U32(*(uint32_t*)(pHdr+8))));
+ uProto = 0xFF;
+ break;
+ case 17: /* UDP */
+ Log2((" + UDP: src=%d dst=%d\n",
+ RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2))));
+ uProto = 0xFF;
+ break;
+ default:
+ Log2((" + Unknown: proto=0x%x\n", uProto));
+ uProto = 0xFF;
+ break;
+ }
+ }
+ Log3(("%.*Rhxd\n", cb, bPacket));
+}
+
+#else /* !DEBUG */
+//# define vboxNetAdpWinDumpFilterTypes(uFlags) do { } while (0)
+//# define vboxNetAdpWinDumpOffloadSettings(p) do { } while (0)
+//# define vboxNetAdpWinDumpSetOffloadSettings(p) do { } while (0)
+# define vboxNetAdpWinDumpPackets(m,l) do { } while (0)
+# define vboxNetAdpWinDumpPacket(p,t) do { } while (0)
+#endif /* !DEBUG */
+
+
+DECLHIDDEN(VBOXNETADPWIN_PACKET_TYPE) vboxNetAdpWinPacketType(PINTNETSG pSG)
+{
+ static const uint8_t g_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ AssertReturn(pSG->cbTotal >= sizeof(g_abBcastAddr), kVBoxNetAdpWinPacketType_Unicast);
+ AssertReturn(pSG->cSegsUsed > 0, kVBoxNetAdpWinPacketType_Unicast);
+ AssertReturn(pSG->aSegs[0].cb >= sizeof(g_abBcastAddr), kVBoxNetAdpWinPacketType_Unicast);
+ if (!memcmp(pSG->aSegs[0].pv, g_abBcastAddr, sizeof(g_abBcastAddr)))
+ return kVBoxNetAdpWinPacketType_Broadcast;
+ if ((*(uint8_t*)pSG->aSegs[0].pv) & 1)
+ return kVBoxNetAdpWinPacketType_Multicast;
+ return kVBoxNetAdpWinPacketType_Unicast;
+}
+
+DECLINLINE(void) vboxNetAdpWinUpdateStats(uint64_t *pPacketStats, uint64_t *pOctetStats, PINTNETSG pSG)
+{
+ VBOXNETADPWIN_PACKET_TYPE enmPktType = vboxNetAdpWinPacketType(pSG);
+ ASMAtomicIncU64(&pPacketStats[enmPktType]);
+ ASMAtomicAddU64(&pOctetStats[enmPktType], pSG->cbTotal);
+}
+
+DECLINLINE(void) vboxNetAdpWinFreeMdlChain(PMDL pMdl)
+{
+ PMDL pMdlNext;
+ while (pMdl)
+ {
+ pMdlNext = pMdl->Next;
+ PUCHAR pDataBuf;
+ ULONG cb = 0;
+ NdisQueryMdl(pMdl, &pDataBuf, &cb, NormalPagePriority);
+ NdisFreeMdl(pMdl);
+ Log4(("vboxNetAdpWinFreeMdlChain: freed MDL 0x%p\n", pMdl));
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetAdpWinFreeMdlChain: freed data buffer 0x%p\n", pDataBuf));
+ pMdl = pMdlNext;
+ }
+}
+
+DECLHIDDEN(PNET_BUFFER_LIST) vboxNetAdpWinSGtoNB(PVBOXNETADP_ADAPTER pThis, PINTNETSG pSG)
+{
+ AssertReturn(pSG->cSegsUsed >= 1, NULL);
+ LogFlow(("==>vboxNetAdpWinSGtoNB: segments=%d hPool=%p cb=%u\n", pSG->cSegsUsed,
+ pThis->hPool, pSG->cbTotal));
+ AssertReturn(pThis->hPool, NULL);
+
+
+ PNET_BUFFER_LIST pBufList = NULL;
+ ULONG cbMdl = pSG->cbTotal;
+ ULONG uDataOffset = cbMdl - pSG->cbTotal;
+ PUCHAR pDataBuf = (PUCHAR)NdisAllocateMemoryWithTagPriority(pThis->hAdapter, cbMdl,
+ VBOXNETADP_MEM_TAG, NormalPoolPriority);
+ if (pDataBuf)
+ {
+ Log4(("vboxNetAdpWinSGtoNB: allocated data buffer (cb=%u) 0x%p\n", cbMdl, pDataBuf));
+ PMDL pMdl = NdisAllocateMdl(pThis->hAdapter, pDataBuf, cbMdl);
+ if (!pMdl)
+ {
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetAdpWinSGtoNB: freed data buffer 0x%p\n", pDataBuf));
+ LogError(("vboxNetAdpWinSGtoNB: failed to allocate an MDL (cb=%u)\n", cbMdl));
+ LogFlow(("<==vboxNetAdpWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ PUCHAR pDst = pDataBuf + uDataOffset;
+ for (int i = 0; i < pSG->cSegsUsed; i++)
+ {
+ NdisMoveMemory(pDst, pSG->aSegs[i].pv, pSG->aSegs[i].cb);
+ pDst += pSG->aSegs[i].cb;
+ }
+ pBufList = NdisAllocateNetBufferAndNetBufferList(pThis->hPool,
+ 0 /* ContextSize */,
+ 0 /* ContextBackFill */,
+ pMdl,
+ uDataOffset,
+ pSG->cbTotal);
+ if (pBufList)
+ {
+ Log4(("vboxNetAdpWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pThis->hAdapter;
+ /** @todo Do we need to initialize anything else? */
+ }
+ else
+ {
+ LogError(("vboxNetAdpWinSGtoNB: failed to allocate an NBL+NB\n"));
+ vboxNetAdpWinFreeMdlChain(pMdl);
+ }
+ }
+ else
+ {
+ LogError(("vboxNetAdpWinSGtoNB: failed to allocate data buffer (size=%u)\n", cbMdl));
+ }
+
+ LogFlow(("<==vboxNetAdpWinSGtoNB: return %p\n", pBufList));
+ return pBufList;
+}
+
+DECLINLINE(void) vboxNetAdpWinDestroySG(PINTNETSG pSG)
+{
+ NdisFreeMemory(pSG, 0, 0);
+ Log4(("vboxNetAdpWinDestroySG: freed SG 0x%p\n", pSG));
+}
+
+/**
+ * Worker for vboxNetAdpWinNBtoSG() that gets the max segment count needed.
+ * @note vboxNetAdpWinNBtoSG may use fewer depending on cbPacket and offset!
+ * @note vboxNetLwfWinCalcSegments() is a copy of this code.
+ */
+DECLINLINE(ULONG) vboxNetAdpWinCalcSegments(PNET_BUFFER pNetBuf)
+{
+ ULONG cSegs = 0;
+ for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf); pMdl; pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ /* Skip empty MDLs (see @bugref{9233}) */
+ if (MmGetMdlByteCount(pMdl))
+ cSegs++;
+ }
+ return cSegs;
+}
+
+/**
+ * @note vboxNetLwfWinNBtoSG() is a copy of this code.
+ */
+DECLHIDDEN(PINTNETSG) vboxNetAdpWinNBtoSG(PVBOXNETADP_ADAPTER pThis, PNET_BUFFER pNetBuf)
+{
+ ULONG cbPacket = NET_BUFFER_DATA_LENGTH(pNetBuf);
+ ULONG cSegs = vboxNetAdpWinCalcSegments(pNetBuf);
+ /* Allocate and initialize SG */
+ PINTNETSG pSG = (PINTNETSG)NdisAllocateMemoryWithTagPriority(pThis->hAdapter,
+ RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]),
+ VBOXNETADP_MEM_TAG,
+ NormalPoolPriority);
+ AssertReturn(pSG, pSG);
+ Log4(("vboxNetAdpWinNBtoSG: allocated SG 0x%p\n", pSG));
+ IntNetSgInitTempSegs(pSG, cbPacket /*cbTotal*/, cSegs, cSegs /*cSegsUsed*/);
+
+ ULONG uOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pNetBuf);
+ cSegs = 0;
+ for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf);
+ pMdl != NULL && cbPacket > 0;
+ pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ ULONG cbSrc = MmGetMdlByteCount(pMdl);
+ if (cbSrc == 0)
+ continue; /* Skip empty MDLs (see @bugref{9233}) */
+
+ PUCHAR pSrc = (PUCHAR)MmGetSystemAddressForMdlSafe(pMdl, LowPagePriority);
+ if (!pSrc)
+ {
+ vboxNetAdpWinDestroySG(pSG);
+ return NULL;
+ }
+
+ /* Handle the offset in the current (which is the first for us) MDL */
+ if (uOffset)
+ {
+ if (uOffset < cbSrc)
+ {
+ pSrc += uOffset;
+ cbSrc -= uOffset;
+ uOffset = 0;
+ }
+ else
+ {
+ /* This is an invalid MDL chain */
+ vboxNetAdpWinDestroySG(pSG);
+ return NULL;
+ }
+ }
+
+ /* Do not read the last MDL beyond packet's end */
+ if (cbSrc > cbPacket)
+ cbSrc = cbPacket;
+
+ Assert(cSegs < pSG->cSegsAlloc);
+ pSG->aSegs[cSegs].pv = pSrc;
+ pSG->aSegs[cSegs].cb = cbSrc;
+ pSG->aSegs[cSegs].Phys = NIL_RTHCPHYS;
+ cSegs++;
+ cbPacket -= cbSrc;
+ }
+
+ Assert(cbPacket == 0);
+ Assert(cSegs <= pSG->cSegsUsed);
+
+ /* Update actual segment count in case we used fewer than anticipated. */
+ pSG->cSegsUsed = (uint16_t)cSegs;
+
+ return pSG;
+}
+
+DECLINLINE(bool) vboxNetAdpWinIsActive(PVBOXNETADP_ADAPTER pThis)
+{
+ if (vboxNetAdpWinGetState(pThis) != kVBoxNetAdpWinState_Running)
+ return false;
+ if (pThis->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE)
+ return false;
+ AssertPtrReturn(pThis->pSwitchPort, false);
+ return true;
+}
+
+DECLHIDDEN(bool) vboxNetAdpWinForwardToIntNet(PVBOXNETADP_ADAPTER pThis, PNET_BUFFER_LIST pList, uint32_t fSrc)
+{
+ if (!vboxNetAdpWinIsActive(pThis))
+ {
+ LogFlow(("vboxNetAdpWinForwardToIntNet: not active\n"));
+ return false;
+ }
+ AssertReturn(pThis->pSwitchPort, false);
+ AssertReturn(pThis->pSwitchPort->pfnRecv, false);
+ LogFlow(("==>vboxNetAdpWinForwardToIntNet\n"));
+
+ if (ASMAtomicIncS32(&pThis->cBusy) == 1)
+ NdisResetEvent(&pThis->EventIdle);
+ for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
+ {
+ PINTNETSG pSG = vboxNetAdpWinNBtoSG(pThis, pBuf);
+ if (pSG)
+ {
+ vboxNetAdpWinUpdateStats(pThis->au64StatsOutPackets, pThis->au64StatsOutOctets, pSG);
+ vboxNetAdpWinDumpPacket(pSG, (fSrc & INTNETTRUNKDIR_WIRE)?"intnet <-- wire":"intnet <-- host");
+ pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL, pSG, fSrc);
+ vboxNetAdpWinDestroySG(pSG);
+ }
+ }
+ if (ASMAtomicDecS32(&pThis->cBusy) == 0)
+ NdisSetEvent(&pThis->EventIdle);
+
+ return true;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnRetain
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortRetain(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ RT_NOREF1(pThis);
+ LogFlow(("vboxNetAdpWinPortRetain: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnRelease
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortRelease(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ RT_NOREF1(pThis);
+ LogFlow(("vboxNetAdpWinPortRelease: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+
+ LogFlow(("vboxNetAdpWinPortDisconnectAndRelease: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
+ /*
+ * Serious paranoia.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->szName[0]);
+
+ AssertPtr(pThis->pSwitchPort);
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
+
+ pThis->pSwitchPort = NULL;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnSetState
+ */
+static DECLCALLBACK(INTNETTRUNKIFSTATE) vboxNetAdpWinPortSetState(PINTNETTRUNKIFPORT pIfPort, INTNETTRUNKIFSTATE enmState)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ INTNETTRUNKIFSTATE enmOldTrunkState;
+
+ LogFlow(("vboxNetAdpWinPortSetState: pThis=%p, pIfPort=%p, enmState=%d\n", pThis, pIfPort, enmState));
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertPtrReturn(pThis->pSwitchPort, INTNETTRUNKIFSTATE_INVALID);
+ AssertReturn(enmState > INTNETTRUNKIFSTATE_INVALID && enmState < INTNETTRUNKIFSTATE_END,
+ INTNETTRUNKIFSTATE_INVALID);
+
+ enmOldTrunkState = pThis->enmTrunkState;
+ if (enmOldTrunkState != enmState)
+ ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmTrunkState, enmState);
+
+ return enmOldTrunkState;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
+ */
+static DECLCALLBACK(int) vboxNetAdpWinPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc;
+
+ LogFlow(("vboxNetAdpWinPortWaitForIdle: pThis=%p, pIfPort=%p, cMillies=%u\n", pThis, pIfPort, cMillies));
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertPtrReturn(pThis->pSwitchPort, VERR_INVALID_STATE);
+ AssertReturn(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING, VERR_INVALID_STATE);
+
+ rc = NdisWaitEvent(&pThis->EventIdle, cMillies) ? VINF_SUCCESS : VERR_TIMEOUT;
+
+ return rc;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnXmit
+ */
+static DECLCALLBACK(int) vboxNetAdpWinPortXmit(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
+{
+ RT_NOREF1(fDst);
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc = VINF_SUCCESS;
+
+ LogFlow(("vboxNetAdpWinPortXmit: pThis=%p, pIfPort=%p, pvIfData=%p, pSG=%p, fDst=0x%x\n", pThis, pIfPort, pvIfData, pSG, fDst));
+ RT_NOREF1(pvIfData);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ AssertPtr(pSG);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertPtrReturn(pThis->pSwitchPort, VERR_INVALID_STATE);
+
+ vboxNetAdpWinDumpPacket(pSG, "intnet --> host");
+
+ /*
+ * First of all, indicate we are busy. It is possible the trunk or the adapter
+ * will get paused or even disconnected, so we need to check the state after
+ * we have marked ourselves busy.
+ * Later, when NDIS returns all buffers, we will mark ourselves idle.
+ */
+ if (ASMAtomicIncS32(&pThis->cBusy) == 1)
+ NdisResetEvent(&pThis->EventIdle);
+
+ if (vboxNetAdpWinIsActive(pThis))
+ {
+ PNET_BUFFER_LIST pBufList = vboxNetAdpWinSGtoNB(pThis, pSG);
+ if (pBufList)
+ {
+ NdisMIndicateReceiveNetBufferLists(pThis->hAdapter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 1, 0);
+ vboxNetAdpWinUpdateStats(pThis->au64StatsInPackets, pThis->au64StatsInOctets, pSG);
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnNotifyMacAddress
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortNotifyMacAddress(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PCRTMAC pMac)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+
+ LogFlow(("vboxNetAdpWinPortNotifyMacAddress: pThis=%p, pIfPort=%p, pvIfData=%p, pMac=%p\n", pThis, pIfPort, pvIfData, pMac));
+ RT_NOREF3(pThis, pvIfData, pMac);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+
+ /// @todo Do we really need to handle this?
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnConnectInterface
+ */
+static DECLCALLBACK(int) vboxNetAdpWinPortConnectInterface(PINTNETTRUNKIFPORT pIfPort, void *pvIf, void **ppvIfData)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc;
+
+ LogFlow(("vboxNetAdpWinPortConnectInterface: pThis=%p, pIfPort=%p, pvIf=%p, ppvIfData=%p\n", pThis, pIfPort, pvIf, ppvIfData));
+ RT_NOREF3(pThis, pvIf, ppvIfData);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+
+ rc = VINF_SUCCESS;
+
+ return rc;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnDisconnectInterface
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortDisconnectInterface(PINTNETTRUNKIFPORT pIfPort, void *pvIfData)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc;
+
+ LogFlow(("vboxNetAdpWinPortDisconnectInterface: pThis=%p, pIfPort=%p, pvIfData=%p\n", pThis, pIfPort, pvIfData));
+ RT_NOREF2(pThis, pvIfData);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+
+ rc = VINF_SUCCESS;
+ AssertRC(rc);
+}
+
+
+
+/**
+ * Implements the SUPDRV component factor interface query method.
+ *
+ * @returns Pointer to an interface. NULL if not supported.
+ *
+ * @param pSupDrvFactory Pointer to the component factory registration structure.
+ * @param pSession The session - unused.
+ * @param pszInterfaceUuid The factory interface id.
+ */
+static DECLCALLBACK(void *) vboxNetAdpWinQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession,
+ const char *pszInterfaceUuid)
+{
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_UOFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
+
+ /*
+ * Convert the UUID strings and compare them.
+ */
+ RTUUID UuidReq;
+ int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
+ if (RT_SUCCESS(rc))
+ {
+ if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
+ {
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ if (pGlobals->enmIdcState == kVBoxNetAdpWinIdcState_Connected)
+ {
+ pGlobals->cFactoryRefs++;
+ NdisResetEvent(&pGlobals->EventUnloadAllowed);
+ }
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ return &pGlobals->TrunkFactory;
+ }
+#ifdef LOG_ENABLED
+ else
+ Log(("VBoxNetFlt: unknown factory interface query (%s)\n", pszInterfaceUuid));
+#endif
+ }
+ else
+ Log(("VBoxNetFlt: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
+
+ RT_NOREF1(pSession);
+ return NULL;
+}
+
+
+DECLHIDDEN(void) vboxNetAdpWinReportCapabilities(PVBOXNETADP_ADAPTER pThis)
+{
+ if (pThis->pSwitchPort)
+ {
+ pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->MacAddr);
+ /* Promiscuous mode makes no sense for host-only adapters, does it? */
+ pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
+ INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
+ pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
+ }
+}
+
+/**
+ * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
+ */
+static DECLCALLBACK(int) vboxNetAdpWinFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
+ PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags,
+ PINTNETTRUNKIFPORT *ppIfPort)
+{
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_UOFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
+
+ LogFlow(("==>vboxNetAdpWinFactoryCreateAndConnect: pszName=%p:{%s} fFlags=%#x\n", pszName, pszName, fFlags));
+ Assert(pGlobals->cFactoryRefs > 0);
+ AssertMsgReturn(!(fFlags & ~(INTNETTRUNKFACTORY_FLAG_NO_PROMISC)),
+ ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+
+ DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: looking for %s...\n", pszName);
+ PVBOXNETADP_ADAPTER pAdapter = NULL;
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ RTListForEach(&g_VBoxNetAdpGlobals.ListOfAdapters, pAdapter, VBOXNETADP_ADAPTER, node)
+ {
+ Log(("vboxNetAdpWinFactoryCreateAndConnect: evaluating adapter=%s\n", pAdapter->szName));
+ DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: evaluating %s...\n", pAdapter->szName);
+ if (!RTStrICmp(pszName, pAdapter->szName))
+ {
+ pAdapter->pSwitchPort = pSwitchPort;
+ *ppIfPort = &pAdapter->MyPort;
+ NdisReleaseSpinLock(&g_VBoxNetAdpGlobals.Lock); /// @todo too early? adp should have been connected by the time we do this
+ Log(("vboxNetAdpWinFactoryCreateAndConnect: found matching adapter, name=%s\n", pszName));
+ vboxNetAdpWinReportCapabilities(pAdapter);
+ /// @todo I guess there is no need in vboxNetAdpWinRegisterIpAddrNotifier(pThis);
+ LogFlow(("<==vboxNetAdpWinFactoryCreateAndConnect: return VINF_SUCCESS\n"));
+ return VINF_SUCCESS;
+ }
+ }
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ /// @todo vboxNetAdpLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 6);
+ DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: could not find %s\n", pszName);
+ LogFlow(("<==vboxNetAdpWinFactoryCreateAndConnect: return VERR_INTNET_FLT_IF_NOT_FOUND\n"));
+ return VERR_INTNET_FLT_IF_NOT_FOUND;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKFACTORY::pfnRelease
+ */
+static DECLCALLBACK(void) vboxNetAdpWinFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
+{
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
+
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
+ if (cRefs == 0)
+ NdisSetEvent(&pGlobals->EventUnloadAllowed);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ Assert(cRefs >= 0); NOREF(cRefs);
+ LogFlow(("vboxNetAdpWinFactoryRelease: cRefs=%d (new)\n", cRefs));
+}
+
+
+
+/* IDC */
+
+DECLINLINE(const char *) vboxNetAdpWinIdcStateToText(uint32_t enmState)
+{
+ switch (enmState)
+ {
+ case kVBoxNetAdpWinIdcState_Disconnected: return "Disconnected";
+ case kVBoxNetAdpWinIdcState_Connecting: return "Connecting";
+ case kVBoxNetAdpWinIdcState_Connected: return "Connected";
+ case kVBoxNetAdpWinIdcState_Stopping: return "Stopping";
+ }
+ return "Unknown";
+}
+
+static VOID vboxNetAdpWinInitIdcWorker(PVOID pvContext)
+{
+ int rc;
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)pvContext;
+
+ /*
+ * Note that we break the rules here and access IDC state wihout acquiring
+ * the lock. This is ok because vboxNetAdpWinUnload will wait for this
+ * thread to terminate itself and we always use atomic access to IDC state.
+ * We check the state (while holding the lock) further when we have succeeded
+ * to connect. We cannot take the lock here and release it later as we will
+ * be holding it for too long.
+ */
+ while (ASMAtomicReadU32(&pGlobals->enmIdcState) == kVBoxNetAdpWinIdcState_Connecting)
+ {
+ /*
+ * Establish a connection to SUPDRV and register our component factory.
+ */
+ rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * At this point we should take the lock to access IDC state as
+ * we technically may now race with factory methods.
+ */
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ bool fSuccess = ASMAtomicCmpXchgU32(&pGlobals->enmIdcState,
+ kVBoxNetAdpWinIdcState_Connected,
+ kVBoxNetAdpWinIdcState_Connecting);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ if (!fSuccess)
+ {
+ /* The state has been changed (the only valid transition is to "Stopping"), undo init */
+ rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ AssertRC(rc);
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+ Log(("vboxNetAdpWinInitIdcWorker: state change (Connecting -> %s) while initializing IDC, closed IDC, rc=0x%x\n",
+ vboxNetAdpWinIdcStateToText(ASMAtomicReadU32(&pGlobals->enmIdcState)), rc));
+ }
+ else
+ {
+ Log(("vboxNetAdpWinInitIdcWorker: IDC state change Connecting -> Connected\n"));
+ }
+ }
+ }
+ else
+ {
+ LARGE_INTEGER WaitIn100nsUnits;
+ WaitIn100nsUnits.QuadPart = -(LONGLONG)5000000; /* 0.5 sec */
+ KeDelayExecutionThread(KernelMode, FALSE /* non-alertable */, &WaitIn100nsUnits);
+ }
+ }
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+
+DECLHIDDEN(int) vboxNetAdpWinStartInitIdcThread(PVBOXNETADPGLOBALS pGlobals)
+{
+ int rc = VERR_INVALID_STATE;
+
+ /* No locking needed yet */
+ if (ASMAtomicCmpXchgU32(&pGlobals->enmIdcState, kVBoxNetAdpWinIdcState_Connecting, kVBoxNetAdpWinIdcState_Disconnected))
+ {
+ Log(("vboxNetAdpWinStartInitIdcThread: IDC state change Diconnected -> Connecting\n"));
+
+ NTSTATUS Status = PsCreateSystemThread(&g_VBoxNetAdpGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ vboxNetAdpWinInitIdcWorker,
+ &g_VBoxNetAdpGlobals);
+ Log(("vboxNetAdpWinStartInitIdcThread: create IDC initialization thread, status=0x%x\n", Status));
+ if (Status != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetAdpWinStartInitIdcThread: IDC initialization failed (system thread creation, status=0x%x)\n", Status));
+ /*
+ * We failed to init IDC and there will be no second chance.
+ */
+ Log(("vboxNetAdpWinStartInitIdcThread: IDC state change Connecting -> Diconnected\n"));
+ ASMAtomicWriteU32(&g_VBoxNetAdpGlobals.enmIdcState, kVBoxNetAdpWinIdcState_Disconnected);
+ }
+ rc = RTErrConvertFromNtStatus(Status);
+ }
+ return rc;
+}
+
+
+
+/* === !!!! */
+
+
+NDIS_OID g_SupportedOids[] =
+{
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_INTERRUPT_MODERATION,
+ OID_GEN_LINK_PARAMETERS,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_RCV_OK,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_STATISTICS,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_XMIT_OK,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_PNP_CAPABILITIES,
+ OID_PNP_QUERY_POWER,
+ OID_PNP_SET_POWER
+};
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinAllocAdapter(NDIS_HANDLE hAdapter, PVBOXNETADP_ADAPTER *ppAdapter, ULONG uIfIndex)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PVBOXNETADP_ADAPTER pAdapter = NULL;
+ PVBOXNETADPGLOBALS pGlobals = &g_VBoxNetAdpGlobals;
+
+ LogFlow(("==>vboxNetAdpWinAllocAdapter: adapter handle=%p\n", hAdapter));
+
+ /* Get the name */
+ UNICODE_STRING strUnicodeName;
+ Status = NdisMQueryAdapterInstanceName(&strUnicodeName, hAdapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetAdpWinAllocAdapter: NdisMQueryAdapterInstanceName failed with 0x%x\n", Status));
+ return Status;
+ }
+
+ ANSI_STRING strAnsiName;
+ /* We use the miniport name to associate this filter module with the netflt instance */
+ NTSTATUS rc = RtlUnicodeStringToAnsiString(&strAnsiName,
+ &strUnicodeName,
+ TRUE);
+ if (rc != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetAdpWinAllocAdapter: RtlUnicodeStringToAnsiString(%ls) failed with 0x%x\n",
+ strUnicodeName, rc));
+ //vboxNetAdpLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 2);
+ NdisFreeMemory(strUnicodeName.Buffer, 0, 0);
+ return NDIS_STATUS_FAILURE;
+ }
+ NdisFreeMemory(strUnicodeName.Buffer, 0, 0);
+ DbgPrint("vboxNetAdpWinAllocAdapter: name=%Z\n", &strAnsiName);
+
+ *ppAdapter = NULL;
+
+ UINT cbAdapterWithNameExtra = sizeof(VBOXNETADP_ADAPTER) + strAnsiName.Length;
+ pAdapter = (PVBOXNETADP_ADAPTER)NdisAllocateMemoryWithTagPriority(pGlobals->hMiniportDriver,
+ cbAdapterWithNameExtra,
+ VBOXNETADPWIN_TAG,
+ NormalPoolPriority);
+ if (!pAdapter)
+ {
+ RtlFreeAnsiString(&strAnsiName);
+ Status = NDIS_STATUS_RESOURCES;
+ Log(("vboxNetAdpWinAllocAdapter: Out of memory while allocating adapter context (size=%d)\n", sizeof(VBOXNETADP_ADAPTER)));
+ }
+ else
+ {
+ NdisZeroMemory(pAdapter, cbAdapterWithNameExtra);
+ NdisMoveMemory(pAdapter->szName, strAnsiName.Buffer, strAnsiName.Length);
+ RtlFreeAnsiString(&strAnsiName);
+
+ /* Allocate buffer pool */
+ NET_BUFFER_LIST_POOL_PARAMETERS PoolParams;
+ NdisZeroMemory(&PoolParams, sizeof(PoolParams));
+ PoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ PoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ PoolParams.Header.Size = sizeof(PoolParams);
+ PoolParams.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
+ PoolParams.fAllocateNetBuffer = TRUE;
+ PoolParams.ContextSize = 0;
+ PoolParams.PoolTag = VBOXNETADP_MEM_TAG;
+ pAdapter->hPool = NdisAllocateNetBufferListPool(hAdapter, &PoolParams);
+ if (!pAdapter->hPool)
+ {
+ LogError(("vboxNetAdpWinAllocAdapter: NdisAllocateNetBufferListPool failed\n"));
+ NdisFreeMemory(pAdapter, 0, 0);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetAdpWinAllocAdapter: allocated NBL+NB pool 0x%p\n", pAdapter->hPool));
+
+ pAdapter->hAdapter = hAdapter;
+ pAdapter->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
+ pAdapter->MyPort.pfnRetain = vboxNetAdpWinPortRetain;
+ pAdapter->MyPort.pfnRelease = vboxNetAdpWinPortRelease;
+ pAdapter->MyPort.pfnDisconnectAndRelease = vboxNetAdpWinPortDisconnectAndRelease;
+ pAdapter->MyPort.pfnSetState = vboxNetAdpWinPortSetState;
+ pAdapter->MyPort.pfnWaitForIdle = vboxNetAdpWinPortWaitForIdle;
+ pAdapter->MyPort.pfnXmit = vboxNetAdpWinPortXmit;
+ pAdapter->MyPort.pfnNotifyMacAddress = vboxNetAdpWinPortNotifyMacAddress;
+ pAdapter->MyPort.pfnConnectInterface = vboxNetAdpWinPortConnectInterface;
+ pAdapter->MyPort.pfnDisconnectInterface = vboxNetAdpWinPortDisconnectInterface;
+ pAdapter->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
+ pAdapter->pGlobals = pGlobals;
+ pAdapter->enmAdapterState = kVBoxNetAdpWinState_Initializing;
+ pAdapter->enmTrunkState = INTNETTRUNKIFSTATE_INACTIVE;
+ pAdapter->cBusy = 0;
+ NdisInitializeEvent(&pAdapter->EventIdle);
+ NdisSetEvent(&pAdapter->EventIdle); /* We are idle initially */
+
+ /* Use a locally administered version of the OUI we use for the guest NICs. */
+ pAdapter->MacAddr.au8[0] = 0x08 | 2;
+ pAdapter->MacAddr.au8[1] = 0x00;
+ pAdapter->MacAddr.au8[2] = 0x27;
+
+ pAdapter->MacAddr.au8[3] = (uIfIndex >> 16) & 0xFF;
+ pAdapter->MacAddr.au8[4] = (uIfIndex >> 8) & 0xFF;
+ pAdapter->MacAddr.au8[5] = uIfIndex & 0xFF;
+
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ RTListPrepend(&pGlobals->ListOfAdapters, &pAdapter->node);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+
+ *ppAdapter = pAdapter;
+ }
+ LogFlow(("<==vboxNetAdpWinAllocAdapter: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(void) vboxNetAdpWinFreeAdapter(PVBOXNETADP_ADAPTER pAdapter)
+{
+ /* Remove from adapter chain */
+ NdisAcquireSpinLock(&pAdapter->pGlobals->Lock);
+ RTListNodeRemove(&pAdapter->node);
+ NdisReleaseSpinLock(&pAdapter->pGlobals->Lock);
+
+ NdisFreeMemory(pAdapter, 0, 0);
+}
+
+DECLINLINE(NDIS_MEDIA_CONNECT_STATE) vboxNetAdpWinGetConnectState(PVBOXNETADP_ADAPTER pAdapter)
+{
+ RT_NOREF1(pAdapter);
+ return MediaConnectStateConnected;
+}
+
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinInitializeEx(IN NDIS_HANDLE NdisMiniportHandle,
+ IN NDIS_HANDLE MiniportDriverContext,
+ IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters)
+{
+ RT_NOREF1(MiniportDriverContext);
+ PVBOXNETADP_ADAPTER pAdapter = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ LogFlow(("==>vboxNetAdpWinInitializeEx: miniport=0x%x\n", NdisMiniportHandle));
+
+ do
+ {
+ NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES RAttrs = {{0}};
+ NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES GAttrs = {{0}};
+
+ Status = vboxNetAdpWinAllocAdapter(NdisMiniportHandle, &pAdapter, MiniportInitParameters->IfIndex);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinInitializeEx: Failed to allocate the adapter context with 0x%x\n", Status));
+ break;
+ }
+
+ RAttrs.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
+ RAttrs.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+ RAttrs.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+ RAttrs.MiniportAdapterContext = pAdapter;
+ RAttrs.AttributeFlags = VBOXNETADPWIN_ATTR_FLAGS; // NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM
+ RAttrs.CheckForHangTimeInSeconds = VBOXNETADPWIN_HANG_CHECK_TIME;
+ RAttrs.InterfaceType = NdisInterfaceInternal;
+
+ Status = NdisMSetMiniportAttributes(NdisMiniportHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&RAttrs);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinInitializeEx: NdisMSetMiniportAttributes(registration) failed with 0x%x\n", Status));
+ break;
+ }
+
+ /// @todo Registry?
+
+ /// @todo WDM stack?
+
+ /// @todo DPC?
+
+ GAttrs.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
+ GAttrs.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+ GAttrs.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+
+ GAttrs.MediaType = NdisMedium802_3;
+ GAttrs.PhysicalMediumType = NdisPhysicalMediumUnspecified;
+ GAttrs.MtuSize = 1500; /// @todo
+ GAttrs.MaxXmitLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.XmitLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.MaxRcvLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.RcvLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.MediaConnectState = vboxNetAdpWinGetConnectState(pAdapter);
+ GAttrs.MediaDuplexState = MediaDuplexStateFull;
+ GAttrs.LookaheadSize = 1500; /// @todo
+ GAttrs.MacOptions = VBOXNETADP_MAC_OPTIONS;
+ GAttrs.SupportedPacketFilters = VBOXNETADP_SUPPORTED_FILTERS;
+ GAttrs.MaxMulticastListSize = 32; /// @todo
+
+ GAttrs.MacAddressLength = ETH_LENGTH_OF_ADDRESS;
+ Assert(GAttrs.MacAddressLength == sizeof(pAdapter->MacAddr));
+ memcpy(GAttrs.PermanentMacAddress, pAdapter->MacAddr.au8, GAttrs.MacAddressLength);
+ memcpy(GAttrs.CurrentMacAddress, pAdapter->MacAddr.au8, GAttrs.MacAddressLength);
+
+ GAttrs.RecvScaleCapabilities = NULL;
+ GAttrs.AccessType = NET_IF_ACCESS_BROADCAST;
+ GAttrs.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
+ GAttrs.ConnectionType = NET_IF_CONNECTION_DEDICATED;
+ GAttrs.IfType = IF_TYPE_ETHERNET_CSMACD;
+ GAttrs.IfConnectorPresent = false;
+ GAttrs.SupportedStatistics = VBOXNETADPWIN_SUPPORTED_STATISTICS;
+ GAttrs.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
+ GAttrs.DataBackFillSize = 0;
+ GAttrs.ContextBackFillSize = 0;
+ GAttrs.SupportedOidList = g_SupportedOids;
+ GAttrs.SupportedOidListLength = sizeof(g_SupportedOids);
+ GAttrs.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
+ GAttrs.PowerManagementCapabilities = &g_VBoxNetAdpGlobals.PMCaps;
+
+ Status = NdisMSetMiniportAttributes(NdisMiniportHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&GAttrs);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinInitializeEx: NdisMSetMiniportAttributes(general) failed with 0x%x\n", Status));
+ break;
+ }
+
+ VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pAdapter, kVBoxNetAdpWinState_Paused);
+ RT_NOREF1(enmPrevState);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Initializing);
+ } while (false);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pAdapter)
+ vboxNetAdpWinFreeAdapter(pAdapter);
+ }
+
+ LogFlow(("<==vboxNetAdpWinInitializeEx: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinHaltEx(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HALT_ACTION HaltAction)
+{
+ RT_NOREF1(HaltAction);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ LogFlow(("==>vboxNetAdpWinHaltEx\n"));
+ AssertPtr(pThis);
+ Assert(vboxNetAdpWinGetState(pThis) == kVBoxNetAdpWinState_Paused);
+ /*
+ * Check if the trunk is active which means the adapter gets disabled
+ * while it is used by VM(s) and we need to disconnect the trunk.
+ */
+ if (pThis->pSwitchPort && pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE)
+ pThis->pSwitchPort->pfnDisconnect(pThis->pSwitchPort, &pThis->MyPort, NULL);
+ /*
+ * Since we are already in the paused state and we have disconnected
+ * the trunk, we can safely destroy this adapter.
+ */
+ vboxNetAdpWinFreeAdapter(pThis);
+ LogFlow(("<==vboxNetAdpWinHaltEx\n"));
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinPause(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
+{
+ RT_NOREF1(MiniportPauseParameters);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LogFlow(("==>vboxNetAdpWinPause\n"));
+ VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Pausing);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Running);
+ if (!NdisWaitEvent(&pThis->EventIdle, 1000 /* ms */))
+ {
+ LogError(("vboxNetAdpWinPause: timed out while pausing the adapter\n"));
+ /// @todo implement NDIS_STATUS_PENDING case? probably not.
+ }
+ enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Paused);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Pausing);
+ LogFlow(("<==vboxNetAdpWinPause: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinRestart(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
+{
+ RT_NOREF1(MiniportRestartParameters);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LogFlow(("==>vboxNetAdpWinRestart\n"));
+ VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Restarting);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Paused);
+ /// @todo anything?
+ enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Running);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Restarting);
+ LogFlow(("<==vboxNetAdpWinRestart: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLINLINE(uint64_t) vboxNetAdpWinStatsTotals(uint64_t *pStats)
+{
+ return pStats[kVBoxNetAdpWinPacketType_Unicast]
+ + pStats[kVBoxNetAdpWinPacketType_Multicast]
+ + pStats[kVBoxNetAdpWinPacketType_Broadcast];
+}
+
+DECLINLINE(PVOID) vboxNetAdpWinStatsU64(uint64_t *pTmp, ULONG *pcbTmp, uint64_t u64Stat)
+{
+ *pcbTmp = sizeof(*pTmp);
+ *pTmp = u64Stat;
+ return pTmp;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRqQuery(PVBOXNETADP_ADAPTER pThis,
+ PNDIS_OID_REQUEST pRequest)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _NDIS_OID_REQUEST::_REQUEST_DATA::_QUERY *pQuery = &pRequest->DATA.QUERY_INFORMATION;
+
+ LogFlow(("==>vboxNetAdpWinOidRqQuery\n"));
+
+ uint64_t u64Tmp = 0;
+ ULONG ulTmp = 0;
+ PVOID pInfo = &ulTmp;
+ ULONG cbInfo = sizeof(ulTmp);
+
+ switch (pQuery->Oid)
+ {
+ case OID_GEN_INTERRUPT_MODERATION:
+ {
+ PNDIS_INTERRUPT_MODERATION_PARAMETERS pParams =
+ (PNDIS_INTERRUPT_MODERATION_PARAMETERS)pQuery->InformationBuffer;
+ cbInfo = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ if (cbInfo > pQuery->InformationBufferLength)
+ break;
+ pParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ pParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ pParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ pParams->Flags = 0;
+ pParams->InterruptModeration = NdisInterruptModerationNotSupported;
+ pInfo = NULL; /* Do not copy */
+ break;
+ }
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ ulTmp = VBOXNETADP_MAX_FRAME_SIZE;
+ break;
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ /// @todo Make configurable
+ ulTmp = VBOXNETADP_MAX_FRAME_SIZE * 40;
+ break;
+ case OID_GEN_RCV_OK:
+ pInfo = vboxNetAdpWinStatsU64(&u64Tmp, &cbInfo, vboxNetAdpWinStatsTotals(pThis->au64StatsInPackets));
+ break;
+ case OID_GEN_XMIT_OK:
+ pInfo = vboxNetAdpWinStatsU64(&u64Tmp, &cbInfo, vboxNetAdpWinStatsTotals(pThis->au64StatsOutPackets));
+ break;
+ case OID_GEN_STATISTICS:
+ {
+ PNDIS_STATISTICS_INFO pStats =
+ (PNDIS_STATISTICS_INFO)pQuery->InformationBuffer;
+ cbInfo = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ if (cbInfo > pQuery->InformationBufferLength)
+ break;
+ pInfo = NULL; /* Do not copy */
+ memset(pStats, 0, cbInfo);
+ pStats->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ pStats->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
+ pStats->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ pStats->SupportedStatistics =
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS
+ | NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR
+ | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR
+ | NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS
+ | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT;
+
+ pStats->ifHCInOctets = vboxNetAdpWinStatsTotals(pThis->au64StatsInOctets);
+ pStats->ifHCInUcastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCInMulticastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCInBroadcastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Broadcast]);
+ pStats->ifHCOutOctets = vboxNetAdpWinStatsTotals(pThis->au64StatsOutOctets);;
+ pStats->ifHCOutUcastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCOutMulticastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCOutBroadcastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Broadcast]);
+ pStats->ifHCInUcastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCInMulticastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCInBroadcastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Broadcast]);
+ pStats->ifHCOutUcastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCOutMulticastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCOutBroadcastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Broadcast]);
+ break;
+ }
+ case OID_GEN_VENDOR_DESCRIPTION:
+ pInfo = VBOXNETADP_VENDOR_NAME;
+ cbInfo = sizeof(VBOXNETADP_VENDOR_NAME);
+ break;
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ ulTmp = (VBOXNETADP_VERSION_NDIS_MAJOR << 16) | VBOXNETADP_VERSION_NDIS_MINOR;
+ break;
+ case OID_GEN_VENDOR_ID:
+ ulTmp = VBOXNETADP_VENDOR_ID;
+ break;
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ pInfo = &pThis->MacAddr;
+ cbInfo = sizeof(pThis->MacAddr);
+ break;
+ //case OID_802_3_MULTICAST_LIST:
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ ulTmp = VBOXNETADP_MCAST_LIST_SIZE;
+ break;
+ case OID_PNP_CAPABILITIES:
+ pInfo = &pThis->pGlobals->PMCaps;
+ cbInfo = sizeof(pThis->pGlobals->PMCaps);
+ break;
+ case OID_PNP_QUERY_POWER:
+ pInfo = NULL; /* Do not copy */
+ cbInfo = 0;
+ break;
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (cbInfo > pQuery->InformationBufferLength)
+ {
+ pQuery->BytesNeeded = cbInfo;
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ else
+ {
+ if (pInfo)
+ NdisMoveMemory(pQuery->InformationBuffer, pInfo, cbInfo);
+ pQuery->BytesWritten = cbInfo;
+ }
+ }
+
+ LogFlow(("<==vboxNetAdpWinOidRqQuery: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRqSet(PVBOXNETADP_ADAPTER pAdapter,
+ PNDIS_OID_REQUEST pRequest)
+{
+ RT_NOREF1(pAdapter);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _NDIS_OID_REQUEST::_REQUEST_DATA::_SET *pSet = &pRequest->DATA.SET_INFORMATION;
+
+ LogFlow(("==>vboxNetAdpWinOidRqSet\n"));
+
+ switch (pSet->Oid)
+ {
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (pSet->InformationBufferLength != sizeof(ULONG))
+ {
+ pSet->BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+ /// @todo For the time being we simply ignore lookahead settings.
+ pSet->BytesRead = sizeof(ULONG);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (pSet->InformationBufferLength != sizeof(ULONG))
+ {
+ pSet->BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+ /// @todo For the time being we simply ignore packet filter settings.
+ pSet->BytesRead = pSet->InformationBufferLength;
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_GEN_INTERRUPT_MODERATION:
+ pSet->BytesNeeded = 0;
+ pSet->BytesRead = 0;
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ case OID_PNP_SET_POWER:
+ if (pSet->InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+ pSet->BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ LogFlow(("<==vboxNetAdpWinOidRqSet: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRequest(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_OID_REQUEST NdisRequest)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PVBOXNETADP_ADAPTER pAdapter = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ LogFlow(("==>vboxNetAdpWinOidRequest\n"));
+ vboxNetCmnWinDumpOidRequest(__FUNCTION__, NdisRequest);
+
+ switch (NdisRequest->RequestType)
+ {
+#if 0
+ case NdisRequestMethod:
+ Status = vboxNetAdpWinOidRqMethod(pAdapter, NdisRequest);
+ break;
+#endif
+
+ case NdisRequestSetInformation:
+ Status = vboxNetAdpWinOidRqSet(pAdapter, NdisRequest);
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ Status = vboxNetAdpWinOidRqQuery(pAdapter, NdisRequest);
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ LogFlow(("<==vboxNetAdpWinOidRequest: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinSendNetBufferLists(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN NDIS_PORT_NUMBER PortNumber,
+ IN ULONG SendFlags)
+{
+ RT_NOREF1(PortNumber);
+ PVBOXNETADP_ADAPTER pAdapter = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ LogFlow(("==>vboxNetAdpWinSendNetBufferLists\n"));
+ PNET_BUFFER_LIST pNbl = NetBufferLists;
+ vboxNetAdpWinDumpPackets("vboxNetAdpWinSendNetBufferLists: got", pNbl);
+
+ /* We alwast complete all send requests. */
+ for (pNbl = NetBufferLists; pNbl; pNbl = NET_BUFFER_LIST_NEXT_NBL(pNbl))
+ {
+ vboxNetAdpWinForwardToIntNet(pAdapter, pNbl, INTNETTRUNKDIR_HOST);
+ NET_BUFFER_LIST_STATUS(pNbl) = NDIS_STATUS_SUCCESS;
+ }
+ NdisMSendNetBufferListsComplete(pAdapter->hAdapter, NetBufferLists,
+ (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL) ?
+ NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+ LogFlow(("<==vboxNetAdpWinSendNetBufferLists\n"));
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinReturnNetBufferLists(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN ULONG ReturnFlags)
+{
+ LogFlow(("==>vboxNetAdpWinReturnNetBufferLists\n"));
+ RT_NOREF1(ReturnFlags);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ PNET_BUFFER_LIST pList = NetBufferLists;
+ while (pList)
+ {
+ Assert(pList->SourceHandle == pThis->hAdapter);
+ Assert(NET_BUFFER_LIST_FIRST_NB(pList));
+ Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+
+ PNET_BUFFER_LIST pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
+
+ vboxNetAdpWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ NdisFreeNetBufferList(pList);
+ Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB+MDL+Data 0x%p\n", pList));
+ Assert(ASMAtomicReadS32(&pThis->cBusy) > 0);
+ if (ASMAtomicDecS32(&pThis->cBusy) == 0)
+ NdisSetEvent(&pThis->EventIdle);
+
+ pList = pNextList;
+ }
+ LogFlow(("<==vboxNetAdpWinReturnNetBufferLists\n"));
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinCancelSend(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID CancelId)
+{
+ RT_NOREF2(MiniportAdapterContext, CancelId);
+ LogFlow(("==>vboxNetAdpWinCancelSend\n"));
+ Log(("vboxNetAdpWinCancelSend: We should not be here!\n"));
+ LogFlow(("<==vboxNetAdpWinCancelSend\n"));
+}
+
+
+DECLHIDDEN(BOOLEAN) vboxNetAdpWinCheckForHangEx(IN NDIS_HANDLE MiniportAdapterContext)
+{
+ RT_NOREF1(MiniportAdapterContext);
+ LogFlow(("==>vboxNetAdpWinCheckForHangEx\n"));
+ LogFlow(("<==vboxNetAdpWinCheckForHangEx return false\n"));
+ return FALSE;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinResetEx(IN NDIS_HANDLE MiniportAdapterContext,
+ OUT PBOOLEAN AddressingReset)
+{
+ RT_NOREF2(MiniportAdapterContext, AddressingReset);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LogFlow(("==>vboxNetAdpWinResetEx\n"));
+ LogFlow(("<==vboxNetAdpWinResetEx: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinDevicePnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
+{
+ RT_NOREF2(MiniportAdapterContext, NetDevicePnPEvent);
+ LogFlow(("==>vboxNetAdpWinDevicePnPEventNotify\n"));
+ Log(("vboxNetAdpWinDevicePnPEventNotify: PnP event=%d\n", NetDevicePnPEvent->DevicePnPEvent));
+ LogFlow(("<==vboxNetAdpWinDevicePnPEventNotify\n"));
+}
+
+
+DECLHIDDEN(VOID) vboxNetAdpWinShutdownEx(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_SHUTDOWN_ACTION ShutdownAction)
+{
+ RT_NOREF2(MiniportAdapterContext, ShutdownAction);
+ LogFlow(("==>vboxNetAdpWinShutdownEx\n"));
+ Log(("vboxNetAdpWinShutdownEx: action=%d\n", ShutdownAction));
+ LogFlow(("<==vboxNetAdpWinShutdownEx\n"));
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinCancelOidRequest(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID RequestId)
+{
+ RT_NOREF2(MiniportAdapterContext, RequestId);
+ LogFlow(("==>vboxNetAdpWinCancelOidRequest\n"));
+ Log(("vboxNetAdpWinCancelOidRequest: req id=%p\n", RequestId));
+ LogFlow(("<==vboxNetAdpWinCancelOidRequest\n"));
+}
+
+
+
+DECLHIDDEN(VOID) vboxNetAdpWinUnload(IN PDRIVER_OBJECT DriverObject)
+{
+ RT_NOREF1(DriverObject);
+ LogFlow(("==>vboxNetAdpWinUnload\n"));
+ PVBOXNETADPGLOBALS pGlobals = &g_VBoxNetAdpGlobals;
+ int rc;
+ NDIS_STATUS Status;
+ PKTHREAD pThread = NULL;
+
+ /* We are about to disconnect IDC, let's make it clear so the factories will know */
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ uint32_t enmPrevState = ASMAtomicXchgU32(&g_VBoxNetAdpGlobals.enmIdcState, kVBoxNetAdpWinIdcState_Stopping);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ Log(("vboxNetAdpWinUnload: IDC state change %s -> Stopping\n", vboxNetAdpWinIdcStateToText(enmPrevState)));
+
+ switch (enmPrevState)
+ {
+ case kVBoxNetAdpWinIdcState_Disconnected:
+ /* Have not even attempted to connect -- nothing to do. */
+ break;
+ case kVBoxNetAdpWinIdcState_Stopping:
+ /* Impossible, but another thread is alreading doing StopIdc, bail out */
+ LogError(("vboxNetAdpWinUnload: called in 'Stopping' state\n"));
+ break;
+ case kVBoxNetAdpWinIdcState_Connecting:
+ /* the worker thread is running, let's wait for it to stop */
+ Status = ObReferenceObjectByHandle(g_VBoxNetAdpGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS, NULL, KernelMode,
+ (PVOID*)&pThread, NULL);
+ if (Status == STATUS_SUCCESS)
+ {
+ KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
+ ObDereferenceObject(pThread);
+ }
+ else
+ {
+ LogError(("vboxNetAdpWinStopIdc: ObReferenceObjectByHandle(%p) failed with 0x%x\n",
+ g_VBoxNetAdpGlobals.hInitIdcThread, Status));
+ }
+ break;
+ case kVBoxNetAdpWinIdcState_Connected:
+ /* the worker succeeded in IDC init and terminated */
+ /* Make sure nobody uses the trunk factory. Wait half a second if needed. */
+ if (!NdisWaitEvent(&pGlobals->EventUnloadAllowed, 500))
+ LogRel(("VBoxNetAdp: unloading driver while trunk factory is in use!\n"));
+ rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ AssertRC(rc);
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+ Log(("vboxNetAdpWinUnload: closed IDC, rc=0x%x\n", rc));
+ break;
+ }
+ if (pGlobals->hMiniportDriver)
+ NdisMDeregisterMiniportDriver(pGlobals->hMiniportDriver);
+ NdisFreeSpinLock(&pGlobals->Lock);
+ LogFlow(("<==vboxNetAdpWinUnload\n"));
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+ RTR0Term();
+}
+
+
+/**
+ * register the miniport driver
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinRegister(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
+{
+ NDIS_MINIPORT_DRIVER_CHARACTERISTICS MChars;
+
+ NdisZeroMemory(&MChars, sizeof (MChars));
+
+ MChars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
+ MChars.Header.Size = sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS);
+ MChars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
+
+ MChars.MajorNdisVersion = VBOXNETADP_VERSION_NDIS_MAJOR;
+ MChars.MinorNdisVersion = VBOXNETADP_VERSION_NDIS_MINOR;
+
+ MChars.MajorDriverVersion = VBOXNETADP_VERSION_MAJOR;
+ MChars.MinorDriverVersion = VBOXNETADP_VERSION_MINOR;
+
+ MChars.InitializeHandlerEx = vboxNetAdpWinInitializeEx;
+ MChars.HaltHandlerEx = vboxNetAdpWinHaltEx;
+ MChars.UnloadHandler = vboxNetAdpWinUnload;
+ MChars.PauseHandler = vboxNetAdpWinPause;
+ MChars.RestartHandler = vboxNetAdpWinRestart;
+ MChars.OidRequestHandler = vboxNetAdpWinOidRequest;
+ MChars.SendNetBufferListsHandler = vboxNetAdpWinSendNetBufferLists;
+ MChars.ReturnNetBufferListsHandler = vboxNetAdpWinReturnNetBufferLists;
+ MChars.CancelSendHandler = vboxNetAdpWinCancelSend;
+ MChars.CheckForHangHandlerEx = vboxNetAdpWinCheckForHangEx;
+ MChars.ResetHandlerEx = vboxNetAdpWinResetEx;
+ MChars.DevicePnPEventNotifyHandler = vboxNetAdpWinDevicePnPEventNotify;
+ MChars.ShutdownHandlerEx = vboxNetAdpWinShutdownEx;
+ MChars.CancelOidRequestHandler = vboxNetAdpWinCancelOidRequest;
+
+ NDIS_STATUS Status;
+ g_VBoxNetAdpGlobals.hMiniportDriver = NULL;
+ Log(("vboxNetAdpWinRegister: registering miniport driver...\n"));
+ Status = NdisMRegisterMiniportDriver(pDriverObject,
+ pRegistryPathStr,
+ (NDIS_HANDLE)&g_VBoxNetAdpGlobals,
+ &MChars,
+ &g_VBoxNetAdpGlobals.hMiniportDriver);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinRegister: successfully registered miniport driver; registering device...\n"));
+ }
+ else
+ {
+ Log(("ERROR! vboxNetAdpWinRegister: failed to register miniport driver, status=0x%x", Status));
+ }
+ return Status;
+}
+
+
+RT_C_DECLS_BEGIN
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath);
+
+RT_C_DECLS_END
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ int rc;
+
+
+ rc = RTR0Init(0);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ NdisZeroMemory(&g_VBoxNetAdpGlobals, sizeof (g_VBoxNetAdpGlobals));
+ RTListInit(&g_VBoxNetAdpGlobals.ListOfAdapters);
+ NdisAllocateSpinLock(&g_VBoxNetAdpGlobals.Lock);
+ NdisInitializeEvent(&g_VBoxNetAdpGlobals.EventUnloadAllowed);
+ //g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
+ g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
+
+ /* Initialize SupDrv interface */
+ g_VBoxNetAdpGlobals.SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpWinQueryFactoryInterface;
+ memcpy(g_VBoxNetAdpGlobals.SupDrvFactory.szName, "VBoxNetAdp", sizeof("VBoxNetAdp"));
+ /* Initialize trunk factory interface */
+ g_VBoxNetAdpGlobals.TrunkFactory.pfnRelease = vboxNetAdpWinFactoryRelease;
+ g_VBoxNetAdpGlobals.TrunkFactory.pfnCreateAndConnect = vboxNetAdpWinFactoryCreateAndConnect;
+
+ rc = vboxNetAdpWinStartInitIdcThread(&g_VBoxNetAdpGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ Status = vboxNetAdpWinRegister(pDriverObject, pRegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Log(("NETADP: started successfully\n"));
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreeSpinLock(&g_VBoxNetAdpGlobals.Lock);
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+
+ RTR0Term();
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h
new file mode 100644
index 00000000..8d9d15a5
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h
@@ -0,0 +1,71 @@
+/* $Id: VBoxNetAdp-win.h $ */
+/** @file
+ * VBoxNetAdp-win.h - Host-only Miniport Driver, Windows-specific code.
+ */
+/*
+ * Copyright (C) 2014-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetAdp_win_VBoxNetAdp_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetAdp_win_VBoxNetAdp_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define VBOXNETADP_VERSION_NDIS_MAJOR 6
+#define VBOXNETADP_VERSION_NDIS_MINOR 0
+
+#define VBOXNETADP_VERSION_MAJOR 1
+#define VBOXNETADP_VERSION_MINOR 0
+
+#define VBOXNETADP_VENDOR_NAME "Oracle"
+#define VBOXNETADP_VENDOR_ID 0xFFFFFF
+#define VBOXNETADP_MCAST_LIST_SIZE 32
+#define VBOXNETADP_MAX_FRAME_SIZE 1518 // TODO: 14+4+1500
+
+//#define VBOXNETADP_NAME_UNIQUE L"{7af6b074-048d-4444-bfce-1ecc8bc5cb76}"
+#define VBOXNETADP_NAME_SERVICE L"VBoxNetAdp"
+
+#define VBOXNETADP_NAME_LINK L"\\DosDevices\\Global\\VBoxNetAdp"
+#define VBOXNETADP_NAME_DEVICE L"\\Device\\VBoxNetAdp"
+
+#define VBOXNETADPWIN_TAG 'ANBV'
+
+#define VBOXNETADPWIN_ATTR_FLAGS NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM | NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND
+#define VBOXNETADP_MAC_OPTIONS NDIS_MAC_OPTION_NO_LOOPBACK
+#define VBOXNETADP_SUPPORTED_FILTERS (NDIS_PACKET_TYPE_DIRECTED | \
+ NDIS_PACKET_TYPE_MULTICAST | \
+ NDIS_PACKET_TYPE_BROADCAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS | \
+ NDIS_PACKET_TYPE_ALL_MULTICAST)
+#define VBOXNETADPWIN_SUPPORTED_STATISTICS 0 //TODO!
+#define VBOXNETADPWIN_HANG_CHECK_TIME 4
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetAdp_win_VBoxNetAdp_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc
new file mode 100644
index 00000000..61cdb6e7
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc
@@ -0,0 +1,72 @@
+/* $Id: VBoxNetAdp-win.rc $ */
+/** @file
+ * VBoxNetAdp6 - Resource file containing version info and icon.
+ */
+/*
+ * Copyright (C) 2014-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+#define DESCRIPTION_STR "VirtualBox NDIS 6.0 Host-Only Network Adapter Driver\0"
+#define FILENAME_STR "VBoxNetAdp6"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DRV
+ FILESUBTYPE VFT2_DRV_NETWORK
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", DESCRIPTION_STR
+ VALUE "InternalName", FILENAME_STR "\0"
+ VALUE "OriginalFilename", FILENAME_STR ".sys\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf
new file mode 100644
index 00000000..6c18bf6a
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf
@@ -0,0 +1,101 @@
+; $Id: VBoxNetAdp6.inf $
+;; @file
+; VBoxNetAdp6.inf - VirtualBox NDIS6 Miniport Driver inf file
+;
+; Note: We use the same component id as the old NetAdp implementation ?
+;
+
+;
+; Copyright (C) 2014-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>.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+; in the VirtualBox distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+;
+
+[Version]
+Signature = "$Windows NT$"
+;cat CatalogFile = VBoxNetAdp6.cat
+Class = Net
+ClassGUID = {4D36E972-E325-11CE-BFC1-08002BE10318}
+Provider = %ORACLE%
+;edit-DriverVer=10/23/2014,1.0.1.0
+
+
+[Manufacturer]
+%ORACLE% = VBoxNetAdp6@COMMA-NT-ARCH@
+
+[ControlFlags]
+
+[VBoxNetAdp6@DOT-NT-ARCH@]
+%VBoxNetAdp6_Desc% = VBoxNetAdp6.ndi, sun_VBoxNetAdp
+
+[VBoxNetAdp6.ndi]
+AddReg = VBoxNetAdp6.ndi.AddReg
+Characteristics = 0x1 ; NCF_VIRTUAL
+*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD
+*MediaType = 0x0 ; NdisMedium802_3
+*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3
+CopyFiles = VBoxNetAdp6.Files.Sys
+
+[VBoxNetAdp6.ndi.Services]
+AddService = VBoxNetAdp, 2, VBoxNetAdp6.AddService
+
+[VBoxNetAdp6.AddService]
+DisplayName = %VBoxNetAdp6Service_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetAdp6.sys
+LoadOrderGroup = NDIS
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetAdp6.sys=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetAdp6.Files.Sys = 12 ; %windir%\System32\drivers
+
+[VBoxNetAdp6.Files.Sys]
+VBoxNetAdp6.sys,,,2
+
+[VBoxNetAdp6.ndi.AddReg]
+HKR, , *NdisDeviceType, 0x00010001, 1 ; NDIS_DEVICE_TYPE_ENDPOINT
+HKR, , BusNumber, 0, "0"
+HKR, Ndi, Service, 0, VBoxNetAdp
+HKR, Ndi, HelpText, , %VBoxNetAdp6_HELP%
+HKR, Ndi\Interfaces, UpperRange, 0, ndis5
+HKR, Ndi\Interfaces, LowerRange, 0, ethernet
+
+[Strings]
+ORACLE = "Oracle Corporation"
+DiskDescription = "VirtualBox NDIS 6.0 Miniport Driver"
+VBoxNetAdp6_Desc = "VirtualBox Host-Only Ethernet Adapter"
+VBoxNetAdp6_HELP = "VirtualBox NDIS 6.0 Miniport Driver"
+VBoxNetAdp6Service_Desc = "VirtualBox NDIS 6.0 Miniport Service"