summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetFlt/win/drv
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetFlt/win/drv')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf95
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc77
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt.inf117
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h533
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp1570
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h67
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf82
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp1595
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h52
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp3650
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h972
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp2736
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h55
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf120
15 files changed, 11721 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf
new file mode 100644
index 00000000..9e13a198
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetAdp.inf
@@ -0,0 +1,95 @@
+; $Id: VBoxNetAdp.inf $
+;; @file
+; VBoxNetAdp.inf - VirtualBox Host-Only Driver inf file
+;
+
+;
+; Copyright (C) 2011-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 = VBoxNetAdp.cat
+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %ORACLE%
+; DriverPackageType=Network
+; DriverPackageDisplayName=%VBoxNetAdp_Desc%
+;edit-DriverVer=08/13/2008,1.1.0.1
+
+[ControlFlags]
+;ExcludeFromSelect = sun_VBoxNetAdp
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetAdp.sys=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetAdp.Files.Sys = 12 ; %windir%\System32\drivers
+
+[Manufacturer]
+%ORACLE% = VBoxNetAdp@COMMA-NT-ARCH@
+
+[VBoxNetAdp@DOT-NT-ARCH@]
+%VBoxNetAdp_Desc% = VBoxNetAdp.ndi, sun_VBoxNetAdp
+
+[VBoxNetAdp.ndi]
+Characteristics = 0x1 ; NCF_VIRTUAL
+CopyFiles = VBoxNetAdp.Files.Sys
+AddReg = VBoxNetAdp.AddReg
+
+[VBoxNetAdp.Files.Sys]
+VBoxNetAdp.sys,,,2
+
+[VBoxNetAdp.ndi.Services]
+AddService = VBoxNetAdp,0x2, VBoxNetAdp.AddService
+
+[VBoxNetAdp.AddService]
+DisplayName = %VBoxNetAdp_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetAdp.sys
+LoadOrderGroup = NDIS
+
+[VBoxNetAdp.AddReg]
+HKR, , *NdisDeviceType, 0x00010001, 1 ; NDIS_DEVICE_TYPE_ENDPOINT
+HKR, Ndi, Service, 0, "VBoxNetAdp"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+
+[Strings]
+ORACLE = "Oracle Corporation"
+VBoxNetAdp_Desc = "VirtualBox Host-Only Ethernet Adapter"
+DiskDescription = "VirtualBox Host-Only Ethernet Adapter"
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc
new file mode 100644
index 00000000..979fb6dd
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt-win.rc
@@ -0,0 +1,77 @@
+/* $Id: VBoxNetFlt-win.rc $ */
+/** @file
+ * VBoxNetFlt - Resource file containing version info and icon.
+ */
+/*
+ * Copyright (C) 2011-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>
+
+#ifndef VBOXNETADP
+# define DESCRIPTION_STR "VirtualBox Bridged Networking Driver\0"
+# define FILENAME_STR "VBoxNetFlt"
+#else
+# define DESCRIPTION_STR "VirtualBox Host-Only Network Adapter Driver\0"
+# define FILENAME_STR "VBoxNetAdp"
+#endif
+
+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" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileDescription", DESCRIPTION_STR
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "InternalName", FILENAME_STR "\0"
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", FILENAME_STR ".sys\0"
+ 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/VBoxNetFlt/win/drv/VBoxNetFlt.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt.inf
new file mode 100644
index 00000000..22425793
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFlt.inf
@@ -0,0 +1,117 @@
+; $Id: VBoxNetFlt.inf $
+;; @file
+; VBoxNetFlt.inf - VirtualBox Bridged Networking Driver inf file Protocol edge
+;
+
+;
+; Copyright (C) 2011-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 = VBoxNetFlt.cat
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+Provider = %ORACLE%
+;DriverPackageType=Network
+;DriverPackageDisplayName=%VBoxNetFlt_Desc%
+;edit-DriverVer=08/13/2008,1.1.0.1
+
+
+[Manufacturer]
+%ORACLE% = VBoxNetFlt@COMMA-NT-ARCH@
+
+[ControlFlags]
+
+[VBoxNetFlt@DOT-NT-ARCH@]
+%VBoxNetFlt_Desc% = VBoxNetFlt.ndi, sun_VBoxNetFlt
+
+[VBoxNetFlt.ndi]
+AddReg = VBoxNetFlt.ndi.AddReg, VBoxNetFlt.AddReg
+Characteristics = 0x4410 ; NCF_FILTER | NCF_NDIS_PROTOCOL
+CopyFiles = VBoxNetFlt.Files.DLL, VBoxNetFlt.Files.Sys
+CopyInf = VBoxNetFltM.inf
+
+[VBoxNetFlt.ndi.Remove]
+DelFiles = VBoxNetFlt.Files.DLL, VBoxNetFlt.Files.Sys
+
+[VBoxNetFlt.ndi.Services]
+AddService = VBoxNetFlt,, VBoxNetFlt.AddService
+
+[VBoxNetFlt.AddService]
+DisplayName = %VBoxNetFltService_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetFlt.sys
+LoadOrderGroup = PNP_TDI
+AddReg = VBoxNetFlt.AddService.AddReg
+
+
+[VBoxNetFlt.AddService.AddReg]
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetFlt.sys=1
+VBoxNetFltNobj.dll=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetFlt.Files.DLL = 11 ; %windir%\System32
+VBoxNetFlt.Files.Sys = 12 ; %windir%\System32\drivers
+
+[VBoxNetFlt.Files.Sys]
+VBoxNetFlt.sys,,,2
+
+[VBoxNetFlt.Files.DLL]
+VBoxNetFltNobj.dll,,,2
+
+[VBoxNetFlt.ndi.AddReg]
+HKR, Ndi, HelpText, , %VBoxNetFlt_HELP%
+HKR, Ndi, ClsID, 0, {f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}
+HKR, Ndi, ComponentDll, , VBoxNetFltNobj.dll
+HKR, Ndi, FilterClass, , failover
+HKR, Ndi, FilterDeviceInfId, , sun_VBoxNetFltmp
+HKR, Ndi, Service, , VBoxNetFlt
+HKR, Ndi\Interfaces, UpperRange, , noupper
+HKR, Ndi\Interfaces, LowerRange, , nolower
+HKR, Ndi\Interfaces, FilterMediaTypes, , "ethernet, nolower"
+
+[VBoxNetFlt.AddReg]
+HKR, Parameters, Param1, 0, 4
+
+[Strings]
+ORACLE = "Oracle Corporation"
+DiskDescription = "VirtualBox Bridged Networking Driver"
+VBoxNetFlt_Desc = "VirtualBox Bridged Networking Driver"
+VBoxNetFlt_HELP = "VirtualBox Bridged Networking Driver"
+VBoxNetFltService_Desc = "VirtualBox Bridged Networking Service"
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h
new file mode 100644
index 00000000..520a7d7c
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltCmn-win.h
@@ -0,0 +1,533 @@
+/* $Id: VBoxNetFltCmn-win.h $ */
+/** @file
+ * VBoxNetFltCmn-win.h - Bridged Networking Driver, Windows Specific Code.
+ * Common header with configuration defines and global defs
+ */
+
+/*
+ * Copyright (C) 2011-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_VBoxNetFlt_win_drv_VBoxNetFltCmn_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltCmn_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+
+/* debugging flags */
+#ifdef DEBUG
+//# define DEBUG_NETFLT_PACKETS
+# ifndef DEBUG_misha
+# define RT_NO_STRICT
+# endif
+/* # define DEBUG_NETFLT_LOOPBACK */
+/* receive logic has several branches */
+/* the DEBUG_NETFLT_RECV* macros used to debug the ProtocolReceive callback
+ * which is typically not used in case the underlying miniport indicates the packets with NdisMIndicateReceivePacket
+ * the best way to debug the ProtocolReceive (which in turn has several branches) is to enable the DEBUG_NETFLT_RECV
+ * one by one in the below order, i.e.
+ * first DEBUG_NETFLT_RECV
+ * then DEBUG_NETFLT_RECV + DEBUG_NETFLT_RECV_NOPACKET */
+//# define DEBUG_NETFLT_RECV
+//# define DEBUG_NETFLT_RECV_NOPACKET
+//# define DEBUG_NETFLT_RECV_TRANSFERDATA
+/* use ExAllocatePoolWithTag instead of NdisAllocateMemoryWithTag */
+// #define DEBUG_NETFLT_USE_EXALLOC
+#endif
+
+#include <VBox/intnet.h>
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/version.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/semaphore.h>
+#include <iprt/process.h>
+#include <iprt/alloc.h>
+#include <iprt/alloca.h>
+#include <iprt/time.h>
+#include <iprt/net.h>
+#include <iprt/list.h>
+
+#include <iprt/nt/ntddk.h>
+#include <iprt/nt/ndis.h>
+
+#define VBOXNETFLT_OS_SPECFIC 1
+
+/** version
+ * NOTE: we are NOT using NDIS 5.1 features now */
+#ifdef NDIS51_MINIPORT
+# define VBOXNETFLT_VERSION_MP_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_MP_NDIS_MINOR 1
+#else
+# define VBOXNETFLT_VERSION_MP_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_MP_NDIS_MINOR 0
+#endif
+
+#ifndef VBOXNETADP
+#ifdef NDIS51
+# define VBOXNETFLT_VERSION_PT_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_PT_NDIS_MINOR 1 /* todo: use 0 here as well ? */
+#else
+# define VBOXNETFLT_VERSION_PT_NDIS_MAJOR 5
+# define VBOXNETFLT_VERSION_PT_NDIS_MINOR 0
+#endif
+
+# define VBOXNETFLT_NAME_PROTOCOL L"VBoxNetFlt"
+/** device to be used to prevent the driver unload & ioctl interface (if necessary in the future) */
+# define VBOXNETFLT_NAME_LINK L"\\DosDevices\\Global\\VBoxNetFlt"
+# define VBOXNETFLT_NAME_DEVICE L"\\Device\\VBoxNetFlt"
+#else
+# define VBOXNETFLT_NAME_LINK L"\\DosDevices\\Global\\VBoxNetAdp"
+# define VBOXNETFLT_NAME_DEVICE L"\\Device\\VBoxNetAdp"
+#endif
+
+typedef struct VBOXNETFLTINS *PVBOXNETFLTINS;
+
+/** configuration */
+
+/** Ndis Packet pool settings
+ * these are applied to both receive and send packet pools */
+/* number of packets for normal used */
+#define VBOXNETFLT_PACKET_POOL_SIZE_NORMAL 0x000000FF
+/* number of additional overflow packets */
+#define VBOXNETFLT_PACKET_POOL_SIZE_OVERFLOW 0x0000FF00
+
+/** packet queue size used when the driver is working in the "active" mode */
+#define VBOXNETFLT_PACKET_INFO_POOL_SIZE 0x0000FFFF
+
+#ifndef VBOXNETADP
+/** memory tag used for memory allocations
+ * (VBNF stands for VBox NetFlt) */
+# define VBOXNETFLT_MEM_TAG 'FNBV'
+#else
+/** memory tag used for memory allocations
+ * (VBNA stands for VBox NetAdp) */
+# define VBOXNETFLT_MEM_TAG 'ANBV'
+#endif
+
+/** receive and transmit Ndis buffer pool size */
+#define VBOXNETFLT_BUFFER_POOL_SIZE_TX 128
+#define VBOXNETFLT_BUFFER_POOL_SIZE_RX 128
+
+#define VBOXNETFLT_PACKET_ETHEADER_SIZE 14
+#define VBOXNETFLT_PACKET_HEADER_MATCH_SIZE 24
+#define VBOXNETFLT_PACKET_QUEUE_SG_SEGS_ALLOC 32
+
+
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+# define VBOXNETFLT_PACKETMATCH_LENGTH (VBOXNETFLT_PACKET_ETHEADER_SIZE + 2)
+#endif
+
+#ifdef VBOXNETADP
+#define VBOXNETADP_HEADER_SIZE 14
+#define VBOXNETADP_MAX_DATA_SIZE 1500
+#define VBOXNETADP_MAX_PACKET_SIZE (VBOXNETADP_HEADER_SIZE + VBOXNETADP_MAX_DATA_SIZE)
+#define VBOXNETADP_MIN_PACKET_SIZE 60
+/* link speed 100Mbps (measured in 100 bps) */
+#define VBOXNETADP_LINK_SPEED 1000000
+#define VBOXNETADP_MAX_LOOKAHEAD_SIZE VBOXNETADP_MAX_DATA_SIZE
+#define VBOXNETADP_VENDOR_ID 0x080027
+#define VBOXNETADP_VENDOR_DRIVER_VERSION 0x00010000
+#define VBOXNETADP_VENDOR_DESC "Sun"
+#define VBOXNETADP_MAX_MCAST_LIST 32
+#define VBOXNETADP_ETH_ADDRESS_LENGTH 6
+
+//#define VBOXNETADP_REPORT_DISCONNECTED
+#endif
+/* type defs */
+
+/** Flag specifying that the type of enqueued packet
+ * if set the info contains the PINTNETSG packet
+ * if clear the packet info contains the PNDIS_PACKET packet
+ * Typically the packet queue we are maintaining contains PNDIS_PACKETs only,
+ * however in case the underlying miniport indicates a packet with the NDIS_STATUS_RESOURCES status
+ * we MUST return the packet back to the miniport immediately
+ * this is why we are creating the INTNETSG, copying the ndis packet info there and enqueueing it */
+#define VBOXNETFLT_PACKET_SG 0x00000001
+
+/** the flag specifying that the packet source
+ * if set the packet comes from the host (upperlying protocol)
+ * if clear the packet comes from the wire (underlying miniport) */
+#define VBOXNETFLT_PACKET_SRC_HOST 0x00000002
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+/** flag specifying the packet was originated by our driver
+ * i.e. we could use it on our needs and should not return it
+ * we are enqueueing "our" packets on ProtocolReceive call-back when
+ * Ndis does not give us a receive packet (the driver below us has called NdisM..IndicateReceive)
+ * this is supported for Ndis Packet only */
+#define VBOXNETFLT_PACKET_MINE 0x00000004
+
+/** flag passed to vboxNetFltWinQuEnqueuePacket specifying that the packet should be copied
+ * this is supported for Ndis Packet only */
+#define VBOXNETFLT_PACKET_COPY 0x00000008
+#endif
+
+/** packet queue element containing the packet info */
+typedef struct VBOXNETFLT_PACKET_INFO
+{
+ /** list entry used for enqueueing the info */
+ LIST_ENTRY ListEntry;
+ /** pointer to the pool containing this packet info */
+ struct VBOXNETFLT_PACKET_INFO_POOL *pPool;
+ /** flags describing the referenced packet. Contains PACKET_xxx flags (i.e. PACKET_SG, PACKET_SRC_HOST) */
+ uint32_t fFlags;
+ /** pointer to the packet this info represents */
+ PVOID pPacket;
+} VBOXNETFLT_PACKET_INFO, *PVBOXNETFLT_PACKET_INFO;
+
+/* paranoid check to make sure the elements in the packet info array are properly aligned */
+AssertCompile((sizeof(VBOXNETFLT_PACKET_INFO) & (sizeof(PVOID) - 1)) == 0);
+
+/** represents the packet queue */
+typedef LIST_ENTRY PVBOXNETFLT_ACKET_QUEUE, *PVBOXNETFLT_PACKET_QUEUE;
+
+/*
+ * we are using non-interlocked versions of LIST_ENTRY-related operations macros and synchronize
+ * access to the queue and its elements by acquiring/releasing a spinlock using Ndis[Acquire,Release]Spinlock
+ *
+ * we are NOT using interlocked versions of insert/remove head/tail list functions because we need to iterate though
+ * the queue elements as well as remove elements from the midle of the queue
+ *
+ * * @todo: it seems that we can switch to using interlocked versions of list-entry functions
+ * since we have removed all functionality (mentioned above, i.e. queue elements iteration, etc.) that might prevent us from doing this
+ */
+typedef struct VBOXNETFLT_INTERLOCKED_PACKET_QUEUE
+{
+ /** queue */
+ PVBOXNETFLT_ACKET_QUEUE Queue;
+ /** queue lock */
+ NDIS_SPIN_LOCK Lock;
+} VBOXNETFLT_INTERLOCKED_PACKET_QUEUE, *PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE;
+
+typedef struct VBOXNETFLT_SINGLE_LIST
+{
+ /** queue */
+ SINGLE_LIST_ENTRY Head;
+ /** pointer to the list tail. used to enqueue elements to the tail of the list */
+ PSINGLE_LIST_ENTRY pTail;
+} VBOXNETFLT_SINGLE_LIST, *PVBOXNETFLT_SINGLE_LIST;
+
+typedef struct VBOXNETFLT_INTERLOCKED_SINGLE_LIST
+{
+ /** queue */
+ VBOXNETFLT_SINGLE_LIST List;
+ /** queue lock */
+ NDIS_SPIN_LOCK Lock;
+} VBOXNETFLT_INTERLOCKED_SINGLE_LIST, *PVBOXNETFLT_INTERLOCKED_SINGLE_LIST;
+
+/** packet info pool contains free packet info elements to be used for the packet queue
+ * we are using the pool mechanism to allocate packet queue elements
+ * the pool mechanism is pretty simple now, we are allocating a bunch of memory
+ * for maintaining VBOXNETFLT_PACKET_INFO_POOL_SIZE queue elements and just returning null when the pool is exhausted
+ * This mechanism seems to be enough for now since we are using VBOXNETFLT_PACKET_INFO_POOL_SIZE = 0xffff which is
+ * the maximum size of packets the ndis packet pool supports */
+typedef struct VBOXNETFLT_PACKET_INFO_POOL
+{
+ /** free packet info queue */
+ VBOXNETFLT_INTERLOCKED_PACKET_QUEUE Queue;
+ /** memory bugger used by the pool */
+ PVOID pBuffer;
+} VBOXNETFLT_PACKET_INFO_POOL, *PVBOXNETFLT_PACKET_INFO_POOL;
+
+typedef enum VBOXNETDEVOPSTATE
+{
+ kVBoxNetDevOpState_InvalidValue = 0,
+ kVBoxNetDevOpState_Initializing,
+ kVBoxNetDevOpState_Initialized,
+ kVBoxNetDevOpState_Deinitializing,
+ kVBoxNetDevOpState_Deinitialized,
+
+} VBOXNETDEVOPSTATE;
+
+typedef enum VBOXNETFLT_WINIFSTATE
+{
+ /** The usual invalid state. */
+ kVBoxWinIfState_Invalid = 0,
+ /** Initialization. */
+ kVBoxWinIfState_Connecting,
+ /** Connected fuly functional state */
+ kVBoxWinIfState_Connected,
+ /** Disconnecting */
+ kVBoxWinIfState_Disconnecting,
+ /** Disconnected */
+ kVBoxWinIfState_Disconnected,
+} VBOXNETFLT_WINIFSTATE;
+
+/** structure used to maintain the state and reference count of the miniport and protocol */
+typedef struct VBOXNETFLT_WINIF_DEVICE
+{
+ /** initialize state */
+ VBOXNETDEVOPSTATE OpState;
+ /** ndis power state */
+ NDIS_DEVICE_POWER_STATE PowerState;
+ /** reference count */
+ uint32_t cReferences;
+} VBOXNETFLT_WINIF_DEVICE, *PVBOXNETFLT_WINIF_DEVICE;
+
+#define VBOXNDISREQUEST_INPROGRESS 1
+#define VBOXNDISREQUEST_QUEUED 2
+
+typedef struct VBOXNETFLTWIN_STATE
+{
+ union
+ {
+ struct
+ {
+ UINT fRequestInfo : 2;
+ UINT fInterfaceClosing : 1;
+ UINT fStandBy : 1;
+ UINT fProcessingPacketFilter : 1;
+ UINT fPPFNetFlt : 1;
+ UINT fUpperProtSetFilterInitialized : 1;
+ UINT Reserved : 25;
+ };
+ UINT Value;
+ };
+} VBOXNETFLTWIN_STATE, *PVBOXNETFLTWIN_STATE;
+
+DECLINLINE(VBOXNETFLTWIN_STATE) vboxNetFltWinAtomicUoReadWinState(VBOXNETFLTWIN_STATE State)
+{
+ UINT fValue = ASMAtomicUoReadU32((volatile uint32_t *)&State.Value);
+ return *((PVBOXNETFLTWIN_STATE)((void*)&fValue));
+}
+
+/* miniport layer globals */
+typedef struct VBOXNETFLTGLOBALS_MP
+{
+ /** our miniport handle */
+ NDIS_HANDLE hMiniport;
+ /** ddis wrapper handle */
+ NDIS_HANDLE hNdisWrapper;
+} VBOXNETFLTGLOBALS_MP, *PVBOXNETFLTGLOBALS_MP;
+
+#ifndef VBOXNETADP
+/* protocol layer globals */
+typedef struct VBOXNETFLTGLOBALS_PT
+{
+ /** our protocol handle */
+ NDIS_HANDLE hProtocol;
+} VBOXNETFLTGLOBALS_PT, *PVBOXNETFLTGLOBALS_PT;
+#endif /* #ifndef VBOXNETADP */
+
+typedef struct VBOXNETFLTGLOBALS_WIN
+{
+ /** synch event used for device creation synchronization */
+ KEVENT SynchEvent;
+ /** Device reference count */
+ int cDeviceRefs;
+ /** ndis device */
+ NDIS_HANDLE hDevice;
+ /** device object */
+ PDEVICE_OBJECT pDevObj;
+ /* loopback flags */
+ /* ndis packet flags to disable packet loopback */
+ UINT fPacketDontLoopBack;
+ /* ndis packet flags specifying whether the packet is looped back */
+ UINT fPacketIsLoopedBack;
+ /* Minport info */
+ VBOXNETFLTGLOBALS_MP Mp;
+#ifndef VBOXNETADP
+ /* Protocol info */
+ VBOXNETFLTGLOBALS_PT Pt;
+ /** lock protecting the filter list */
+ NDIS_SPIN_LOCK lockFilters;
+ /** the head of filter list */
+ RTLISTANCHOR listFilters;
+ /** IP address change notifier handle */
+ HANDLE hNotifier;
+#endif
+} VBOXNETFLTGLOBALS_WIN, *PVBOXNETFLTGLOBALS_WIN;
+
+extern VBOXNETFLTGLOBALS_WIN g_VBoxNetFltGlobalsWin;
+
+/** represents filter driver device context*/
+typedef struct VBOXNETFLTWIN
+{
+ /** handle used by miniport edge for ndis calls */
+ NDIS_HANDLE hMiniport;
+ /** miniport edge state */
+ VBOXNETFLT_WINIF_DEVICE MpState;
+ /** ndis packet pool used for receives */
+ NDIS_HANDLE hRecvPacketPool;
+ /** ndis buffer pool used for receives */
+ NDIS_HANDLE hRecvBufferPool;
+ /** driver bind adapter state. */
+ VBOXNETFLT_WINIFSTATE enmState;
+#ifndef VBOXNETADP
+ /* misc state flags */
+ VBOXNETFLTWIN_STATE StateFlags;
+ /** handle used by protocol edge for ndis calls */
+ NDIS_HANDLE hBinding;
+ /** protocol edge state */
+ VBOXNETFLT_WINIF_DEVICE PtState;
+ /** ndis packet pool used for receives */
+ NDIS_HANDLE hSendPacketPool;
+ /** ndis buffer pool used for receives */
+ NDIS_HANDLE hSendBufferPool;
+ /** used for maintaining the pending send packets for handling packet loopback */
+ VBOXNETFLT_INTERLOCKED_SINGLE_LIST SendPacketQueue;
+ /** used for serializing calls to the NdisRequest in the vboxNetFltWinSynchNdisRequest */
+ RTSEMFASTMUTEX hSynchRequestMutex;
+ /** event used to synchronize with the Ndis Request completion in the vboxNetFltWinSynchNdisRequest */
+ KEVENT hSynchCompletionEvent;
+ /** status of the Ndis Request initiated by the vboxNetFltWinSynchNdisRequest */
+ NDIS_STATUS volatile SynchCompletionStatus;
+ /** pointer to the Ndis Request being executed by the vboxNetFltWinSynchNdisRequest */
+ PNDIS_REQUEST volatile pSynchRequest;
+ /** open/close adapter status.
+ * Since ndis adapter open and close requests may complete asynchronously,
+ * we are using event mechanism to wait for open/close completion
+ * the status field is being set by the completion call-back */
+ NDIS_STATUS OpenCloseStatus;
+ /** open/close adaptor completion event */
+ NDIS_EVENT OpenCloseEvent;
+ /** medium we are attached to */
+ NDIS_MEDIUM enmMedium;
+ /**
+ * Passdown request info
+ */
+ /** ndis request we pass down to the miniport below */
+ NDIS_REQUEST PassDownRequest;
+ /** Ndis pass down request bytes read or written original pointer */
+ PULONG pcPDRBytesRW;
+ /** Ndis pass down request bytes needed original pointer */
+ PULONG pcPDRBytesNeeded;
+ /** true if we should indicate the receive complete used by the ProtocolReceive mechanism.
+ * We need to indicate it only with the ProtocolReceive + NdisMEthIndicateReceive path.
+ * Note: we're using KeGetCurrentProcessorNumber, which is not entirely correct in case
+ * we're running on 64bit win7+, which can handle > 64 CPUs, however since KeGetCurrentProcessorNumber
+ * always returns the number < than the number of CPUs in the first group, we're guaranteed to have CPU index < 64
+ * @todo: use KeGetCurrentProcessorNumberEx for Win7+ 64 and dynamically extended array */
+ bool abIndicateRxComplete[64];
+ /** Pending transfer data packet queue (i.e. packets that were indicated as pending on NdisTransferData call */
+ VBOXNETFLT_INTERLOCKED_SINGLE_LIST TransferDataList;
+ /* mac options initialized on OID_GEN_MAC_OPTIONS */
+ ULONG fMacOptions;
+ /** our miniport devuice name */
+ NDIS_STRING MpDeviceName;
+ /** synchronize with unbind with Miniport initialization */
+ NDIS_EVENT MpInitCompleteEvent;
+ /** media connect status that we indicated */
+ NDIS_STATUS MpIndicatedMediaStatus;
+ /** media connect status pending to indicate */
+ NDIS_STATUS MpUnindicatedMediaStatus;
+ /** packet filter flags set by the upper protocols */
+ ULONG fUpperProtocolSetFilter;
+ /** packet filter flags set by the upper protocols */
+ ULONG fSetFilterBuffer;
+ /** packet filter flags set by us */
+ ULONG fOurSetFilter;
+ /** our own list of filters, needed by notifier */
+ RTLISTNODE node;
+#else
+ volatile ULONG cTxSuccess;
+ volatile ULONG cRxSuccess;
+ volatile ULONG cTxError;
+ volatile ULONG cRxError;
+#endif
+} VBOXNETFLTWIN, *PVBOXNETFLTWIN;
+
+typedef struct VBOXNETFLT_PACKET_QUEUE_WORKER
+{
+ /** this event is used to initiate a packet queue worker thread kill */
+ KEVENT KillEvent;
+ /** this event is used to notify a worker thread that the packets are added to the queue */
+ KEVENT NotifyEvent;
+ /** pointer to the packet queue worker thread object */
+ PKTHREAD pThread;
+ /** pointer to the SG used by the packet queue for IntNet receive notifications */
+ PINTNETSG pSG;
+ /** Packet queue */
+ VBOXNETFLT_INTERLOCKED_PACKET_QUEUE PacketQueue;
+ /** Packet info pool, i.e. the pool for the packet queue elements */
+ VBOXNETFLT_PACKET_INFO_POOL PacketInfoPool;
+} VBOXNETFLT_PACKET_QUEUE_WORKER, *PVBOXNETFLT_PACKET_QUEUE_WORKER;
+
+/* protocol reserved data held in ndis packet */
+typedef struct VBOXNETFLT_PKTRSVD_PT
+{
+ /** original packet received from the upperlying protocol
+ * can be null if the packet was originated by intnet */
+ PNDIS_PACKET pOrigPacket;
+ /** pointer to the buffer to be freed on send completion
+ * can be null if no buffer is to be freed */
+ PVOID pBufToFree;
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+ SINGLE_LIST_ENTRY ListEntry;
+ /* true if the packet is from IntNet */
+ bool bFromIntNet;
+#endif
+} VBOXNETFLT_PKTRSVD_PT, *PVBOXNETFLT_PKTRSVD_PT;
+
+/** miniport reserved data held in ndis packet */
+typedef struct VBOXNETFLT_PKTRSVD_MP
+{
+ /** original packet received from the underling miniport
+ * can be null if the packet was originated by intnet */
+ PNDIS_PACKET pOrigPacket;
+ /** pointer to the buffer to be freed on receive completion
+ * can be null if no buffer is to be freed */
+ PVOID pBufToFree;
+} VBOXNETFLT_PKTRSVD_MP, *PVBOXNETFLT_PKTRSVD_MP;
+
+/** represents the data stored in the protocol reserved field of ndis packet on NdisTransferData processing */
+typedef struct VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT
+{
+ /** next packet in a list */
+ SINGLE_LIST_ENTRY ListEntry;
+ /* packet buffer start */
+ PNDIS_BUFFER pOrigBuffer;
+} VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT, *PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT;
+
+/* VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT should fit into PROTOCOL_RESERVED_SIZE_IN_PACKET because we use protocol reserved part
+ * of our miniport edge on transfer data processing for honding our own info */
+AssertCompile(sizeof (VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT) <= PROTOCOL_RESERVED_SIZE_IN_PACKET);
+/* this should fit in MiniportReserved */
+AssertCompile(sizeof (VBOXNETFLT_PKTRSVD_MP) <= RT_SIZEOFMEMB(NDIS_PACKET, MiniportReserved));
+/* we use RTAsmAtomic*U32 for those, make sure we're correct */
+AssertCompile(sizeof (NDIS_DEVICE_POWER_STATE) == sizeof (uint32_t));
+AssertCompile(sizeof (UINT) == sizeof (uint32_t));
+
+
+#define NDIS_FLAGS_SKIP_LOOPBACK_W2K 0x400
+
+#include "../../VBoxNetFltInternal.h"
+#include "VBoxNetFltRt-win.h"
+#ifndef VBOXNETADP
+# include "VBoxNetFltP-win.h"
+#endif
+#include "VBoxNetFltM-win.h"
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltCmn_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp
new file mode 100644
index 00000000..65bde454
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.cpp
@@ -0,0 +1,1570 @@
+/* $Id: VBoxNetFltM-win.cpp $ */
+/** @file
+ * VBoxNetFltM-win.cpp - Bridged Networking Driver, Windows Specific Code.
+ * Miniport edge
+ */
+/*
+ * Copyright (C) 2011-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 "VBoxNetFltCmn-win.h"
+
+static const char* vboxNetFltWinMpDumpOid(ULONG oid);
+
+#ifndef VBOXNETADP
+static NDIS_STATUS vboxNetFltWinMpInitialize(OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext)
+{
+ RT_NOREF1(WrapperConfigurationContext);
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)NdisIMGetDeviceContext(MiniportAdapterHandle);
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ pNetFlt->u.s.WinIf.hMiniport = MiniportAdapterHandle;
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initializing);
+ /* the MP state should be already set to kVBoxNetDevOpState_Initializing, just a paranoia
+ * in case NDIS for some reason calls us in some irregular way */
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initializing);
+
+ NDIS_MEDIUM enmMedium = pNetFlt->u.s.WinIf.enmMedium;
+ if (enmMedium == NdisMediumWan)
+ enmMedium = NdisMedium802_3;
+
+ UINT i = 0;
+ for (; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == enmMedium)
+ {
+ *SelectedMediumIndex = i;
+ break;
+ }
+ }
+
+ do
+ {
+ if (i != MediumArraySize)
+ {
+ NdisMSetAttributesEx(MiniportAdapterHandle, pNetFlt, 0,
+ NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
+ NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT|
+ NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
+ NDIS_ATTRIBUTE_DESERIALIZE |
+ NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+ NdisInterfaceInternal /* 0 */);
+
+ pNetFlt->u.s.WinIf.MpIndicatedMediaStatus = NDIS_STATUS_MEDIA_CONNECT;
+ Assert(vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD3);
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.MpState, NdisDeviceStateD0);
+ Assert(pNetFlt->u.s.WinIf.MpState.OpState == kVBoxNetDevOpState_Initializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initialized);
+
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+ else
+ {
+ Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ Assert(Status != NDIS_STATUS_SUCCESS);
+ Assert(vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD3);
+ Assert(pNetFlt->u.s.WinIf.MpState.OpState == kVBoxNetDevOpState_Initializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ } while (0);
+
+ NdisSetEvent(&pNetFlt->u.s.WinIf.MpInitCompleteEvent);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+
+ *OpenErrorStatus = Status;
+
+ return Status;
+}
+
+/**
+ * process the packet send in a "passthru" mode
+ */
+static NDIS_STATUS vboxNetFltWinSendPassThru(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ , bool bNetFltActive
+#endif
+ )
+{
+ PNDIS_PACKET pMyPacket;
+ NDIS_STATUS Status = vboxNetFltWinPrepareSendPacket(pNetFlt, pPacket, &pMyPacket);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+#if !defined(VBOX_LOOPBACK_USEFLAGS) /* || defined(DEBUG_NETFLT_PACKETS) */
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (bNetFltActive)
+ vboxNetFltWinLbPutSendPacket(pNetFlt, pMyPacket, false /* bFromIntNet */);
+# else
+ /* no need for the loop enqueue & check in a passthru mode , ndis will do everything for us */
+# endif
+#endif
+ NdisSend(&Status, pNetFlt->u.s.WinIf.hBinding, pMyPacket);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisIMCopySendCompletePerPacketInfo(pPacket, pMyPacket);
+#if defined(VBOXNETFLT_NO_PACKET_QUEUE) && !defined(VBOX_LOOPBACK_USEFLAGS)
+ if (bNetFltActive)
+ vboxNetFltWinLbRemoveSendPacket(pNetFlt, pMyPacket);
+#endif
+ NdisFreePacket(pMyPacket);
+ }
+ }
+ return Status;
+}
+
+#else /* defined VBOXNETADP */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoDeinitialization(PVBOXNETFLTINS pNetFlt)
+{
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true);
+ ASMAtomicUoWriteBool(&pNetFlt->fRediscoveryPending, false);
+ ASMAtomicUoWriteU64(&pNetFlt->NanoTSLastRediscovery, NanoTS);
+
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.MpState);
+
+ /* check packet pool is empty */
+ int cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(cPPUsage == 0);
+ /* for debugging only, ignore the err in release */
+ NOREF(cPPUsage);
+
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+static NDIS_STATUS vboxNetFltWinMpReadApplyConfig(PVBOXNETFLTINS pThis, NDIS_HANDLE hMiniportAdapter,
+ NDIS_HANDLE hWrapperConfigurationContext)
+{
+ RT_NOREF1(hMiniportAdapter);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HANDLE hConfiguration;
+ PNDIS_CONFIGURATION_PARAMETER pParameterValue;
+ NDIS_STRING strMAC = NDIS_STRING_CONST("MAC");
+ RTMAC mac;
+
+ NdisOpenConfiguration(
+ &Status,
+ &hConfiguration,
+ hWrapperConfigurationContext);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ do
+ {
+ int rc;
+ NDIS_CONFIGURATION_PARAMETER param;
+ WCHAR MacBuf[13];
+
+ NdisReadConfiguration(&Status,
+ &pParameterValue,
+ hConfiguration,
+ &strMAC,
+ NdisParameterString);
+// Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+
+ rc = vboxNetFltWinMACFromNdisString(&mac, &pParameterValue->ParameterData.StringData);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ break;
+ }
+ }
+
+ vboxNetFltWinGenerateMACAddress(&mac);
+ param.ParameterType = NdisParameterString;
+ param.ParameterData.StringData.Buffer = MacBuf;
+ param.ParameterData.StringData.MaximumLength = sizeof(MacBuf);
+
+ rc = vboxNetFltWinMAC2NdisString(&mac, &param.ParameterData.StringData);
+ Assert(RT_SUCCESS(rc));
+ if (RT_SUCCESS(rc))
+ {
+ NdisWriteConfiguration(&Status,
+ hConfiguration,
+ &strMAC,
+ &param);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ /* ignore the failure */
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ }
+ } while (0);
+
+ NdisCloseConfiguration(hConfiguration);
+ }
+ else
+ {
+ vboxNetFltWinGenerateMACAddress(&mac);
+ }
+
+ pThis->u.s.MacAddr = mac;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoInitialization(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE hMiniportAdapter, NDIS_HANDLE hWrapperConfigurationContext)
+{
+ NDIS_STATUS Status;
+ pNetFlt->u.s.WinIf.hMiniport = hMiniportAdapter;
+
+ LogFlowFunc(("ENTER: pNetFlt 0x%p\n", pNetFlt));
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initializing);
+
+ vboxNetFltWinMpReadApplyConfig(pNetFlt, hMiniportAdapter, hWrapperConfigurationContext);
+
+ NdisMSetAttributesEx(hMiniportAdapter, pNetFlt,
+ 0, /* CheckForHangTimeInSeconds */
+ NDIS_ATTRIBUTE_DESERIALIZE |
+ NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+ NdisInterfaceInternal/* 0 */);
+
+ Assert(vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD3);
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.MpState, NdisDeviceStateD0);
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initialized);
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ LogFlowFunc(("pNetFlt 0x%p, Status 0x%x\n", pNetFlt, Status));
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinMpInitialize(OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext)
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+ UINT i = 0;
+
+ LogFlowFuncEnter();
+
+ for (; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == NdisMedium802_3)
+ {
+ *SelectedMediumIndex = i;
+ break;
+ }
+ }
+
+ if (i != MediumArraySize)
+ {
+ PDEVICE_OBJECT pPdo, pFdo;
+#define KEY_PREFIX L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
+ UCHAR Buf[512];
+ PUCHAR pSuffix;
+ ULONG cbBuf;
+ NDIS_STRING RtlStr;
+
+ wcscpy((WCHAR*)Buf, KEY_PREFIX);
+ pSuffix = Buf + (sizeof(KEY_PREFIX)-2);
+
+ NdisMGetDeviceProperty(MiniportAdapterHandle,
+ &pPdo,
+ &pFdo,
+ NULL, //Next Device Object
+ NULL,
+ NULL);
+
+ Status = IoGetDeviceProperty (pPdo,
+ DevicePropertyDriverKeyName,
+ sizeof(Buf) - (sizeof(KEY_PREFIX)-2),
+ pSuffix,
+ &cbBuf);
+ if (Status == STATUS_SUCCESS)
+ {
+ OBJECT_ATTRIBUTES ObjAttr;
+ HANDLE hDrvKey;
+ RtlStr.Buffer=(WCHAR*)Buf;
+ RtlStr.Length=(USHORT)cbBuf - 2 + sizeof(KEY_PREFIX) - 2;
+ RtlStr.MaximumLength=sizeof(Buf);
+
+ InitializeObjectAttributes(&ObjAttr, &RtlStr, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ Status = ZwOpenKey(&hDrvKey, KEY_READ, &ObjAttr);
+ if (Status == STATUS_SUCCESS)
+ {
+ static UNICODE_STRING NetCfgInstanceIdValue = NDIS_STRING_CONST("NetCfgInstanceId");
+// UCHAR valBuf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + RTUUID_STR_LENGTH*2 + 10];
+// ULONG cLength = sizeof(valBuf);
+#define NAME_PREFIX L"\\DEVICE\\"
+ PKEY_VALUE_PARTIAL_INFORMATION pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buf;
+ Status = ZwQueryValueKey(hDrvKey,
+ &NetCfgInstanceIdValue,
+ KeyValuePartialInformation,
+ pInfo,
+ sizeof(Buf),
+ &cbBuf);
+ if (Status == STATUS_SUCCESS)
+ {
+ if (pInfo->Type == REG_SZ && pInfo->DataLength > 2)
+ {
+ WCHAR *pName;
+ Status = vboxNetFltWinMemAlloc((PVOID*)&pName, pInfo->DataLength + sizeof(NAME_PREFIX));
+ if (Status == STATUS_SUCCESS)
+ {
+ PVBOXNETFLTINS pNetFlt;
+ wcscpy(pName, NAME_PREFIX);
+ wcscpy(pName+(sizeof(NAME_PREFIX)-2)/2, (WCHAR*)pInfo->Data);
+ RtlStr.Buffer=pName;
+ RtlStr.Length = (USHORT)pInfo->DataLength - 2 + sizeof(NAME_PREFIX) - 2;
+ RtlStr.MaximumLength = (USHORT)pInfo->DataLength + sizeof(NAME_PREFIX);
+
+ Status = vboxNetFltWinPtInitBind(&pNetFlt, MiniportAdapterHandle, &RtlStr, WrapperConfigurationContext);
+
+ if (Status == STATUS_SUCCESS)
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Initialized);
+#if 0
+ NdisMIndicateStatus(pNetFlt->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_CONNECT,
+ (PVOID)NULL,
+ 0);
+#endif
+ }
+ else
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+
+ vboxNetFltWinMemFree(pName);
+
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ /** @todo */
+ *OpenErrorStatus = Status;
+
+ LogFlowFunc(("LEAVE: Status (0x%x)\n", Status));
+
+ return Status;
+}
+#endif
+
+static VOID vboxNetFltWinMpSendPackets(IN NDIS_HANDLE hMiniportAdapterContext,
+ IN PPNDIS_PACKET pPacketArray,
+ IN UINT cNumberOfPackets)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hMiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ bool bNetFltActive;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ Assert(cNumberOfPackets);
+
+ if (vboxNetFltWinIncReferenceWinIfNetFlt(pNetFlt, cNumberOfPackets, &bNetFltActive))
+ {
+ uint32_t cAdaptRefs = cNumberOfPackets;
+ uint32_t cNetFltRefs;
+ uint32_t cPassThruRefs;
+ if (bNetFltActive)
+ {
+ cNetFltRefs = cNumberOfPackets;
+ cPassThruRefs = 0;
+ }
+ else
+ {
+ cPassThruRefs = cNumberOfPackets;
+ cNetFltRefs = 0;
+ }
+
+ for (UINT i = 0; i < cNumberOfPackets; i++)
+ {
+ PNDIS_PACKET pPacket;
+
+ pPacket = pPacketArray[i];
+
+ if (!cNetFltRefs
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ || !vboxNetFltWinPostIntnet(pNetFlt, pPacket, VBOXNETFLT_PACKET_SRC_HOST)
+#else
+ || (fStatus = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, VBOXNETFLT_PACKET_SRC_HOST)) != NDIS_STATUS_SUCCESS
+#endif
+ )
+ {
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinSendPassThru(pNetFlt, pPacket
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ , !!cNetFltRefs
+#endif
+ );
+#else
+ if (!cNetFltRefs)
+ {
+# ifdef VBOXNETADP_REPORT_DISCONNECTED
+ Status = NDIS_STATUS_MEDIA_DISCONNECT;
+ STATISTIC_INCREASE(pNetFlt->u.s.WinIf.cTxError);
+# else
+ Status = NDIS_STATUS_SUCCESS;
+# endif
+ }
+#endif
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMSendComplete(pNetFlt->u.s.WinIf.hMiniport, pPacket, Status);
+ }
+ else
+ {
+ cAdaptRefs--;
+ }
+ }
+ else
+ {
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ NdisMSendComplete(pNetFlt->u.s.WinIf.hMiniport, pPacket, NDIS_STATUS_SUCCESS);
+#else
+ cAdaptRefs--;
+ cNetFltRefs--;
+#endif
+ }
+ }
+
+ if (cNetFltRefs)
+ {
+ vboxNetFltWinDecReferenceNetFlt(pNetFlt, cNetFltRefs);
+ }
+ else if (cPassThruRefs)
+ {
+ vboxNetFltWinDecReferenceModePassThru(pNetFlt, cPassThruRefs);
+ }
+ if (cAdaptRefs)
+ {
+ vboxNetFltWinDecReferenceWinIf(pNetFlt, cAdaptRefs);
+ }
+ }
+ else
+ {
+ NDIS_HANDLE h = pNetFlt->u.s.WinIf.hMiniport;
+ AssertFailed();
+ if (h)
+ {
+ for (UINT i = 0; i < cNumberOfPackets; i++)
+ {
+ PNDIS_PACKET pPacket;
+ pPacket = pPacketArray[i];
+ NdisMSendComplete(h, pPacket, NDIS_STATUS_FAILURE);
+ }
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+#ifndef VBOXNETADP
+static UINT vboxNetFltWinMpRequestStatePrep(PVBOXNETFLTINS pNetFlt, NDIS_STATUS *pStatus)
+{
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fRequestInfo);
+
+ if (vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) > kVBoxNetDevOpState_Initialized /* protocol unbind in progress */
+ || vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0)
+ {
+ *pStatus = NDIS_STATUS_FAILURE;
+ return 0;
+ }
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fRequestInfo);
+ if (vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) > kVBoxNetDevOpState_Initialized /* protocol unbind in progress */
+ || vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pStatus = NDIS_STATUS_FAILURE;
+ return 0;
+ }
+
+ if ((vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState) > NdisDeviceStateD0)
+ && !pNetFlt->u.s.WinIf.StateFlags.fStandBy)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS | VBOXNDISREQUEST_QUEUED;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pStatus = NDIS_STATUS_PENDING;
+ return VBOXNDISREQUEST_INPROGRESS | VBOXNDISREQUEST_QUEUED;
+ }
+
+ if (pNetFlt->u.s.WinIf.StateFlags.fStandBy)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pStatus = NDIS_STATUS_FAILURE;
+ return 0;
+ }
+
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS;
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ *pStatus = NDIS_STATUS_SUCCESS;
+ return VBOXNDISREQUEST_INPROGRESS;
+}
+
+static NDIS_STATUS vboxNetFltWinMpRequestPostQuery(PVBOXNETFLTINS pNetFlt)
+{
+ if (pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ bool fNetFltActive;
+ const bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &fNetFltActive);
+
+ Assert(pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBuffer);
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter);
+
+ if (fNetFltActive)
+ {
+ /* netflt is active, simply return the cached value */
+ *((PULONG)pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBuffer) = pNetFlt->u.s.WinIf.fUpperProtocolSetFilter;
+
+ /* we've intercepted the query and completed it */
+ vboxNetFltWinMpRequestStateComplete(pNetFlt);
+
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ return NDIS_STATUS_SUCCESS;
+ }
+ else if (fWinIfActive)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 1;
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 0;
+ /* we're cleaning it in RequestComplete */
+ }
+ }
+
+ NDIS_STATUS Status;
+ /* issue the request */
+ NdisRequest(&Status, pNetFlt->u.s.WinIf.hBinding, &pNetFlt->u.s.WinIf.PassDownRequest);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ vboxNetFltWinPtRequestComplete(pNetFlt, &pNetFlt->u.s.WinIf.PassDownRequest, Status);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinMpQueryInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ /* fist check if this is the oid we want to pass down */
+ switch (Oid)
+ {
+ case OID_PNP_QUERY_POWER:
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ case OID_TCP_TASK_OFFLOAD:
+ case OID_GEN_SUPPORTED_GUIDS:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ default:
+ {
+ /* the oid is to be passed down,
+ * check the device state if we can do it
+ * and update device state accordingly */
+ UINT uOp = vboxNetFltWinMpRequestStatePrep(pNetFlt, &Status);
+ if (uOp)
+ {
+ /* save the request info */
+ pNetFlt->u.s.WinIf.PassDownRequest.RequestType = NdisRequestQueryInformation;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.Oid = Oid;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;
+ pNetFlt->u.s.WinIf.pcPDRBytesNeeded = BytesNeeded;
+ pNetFlt->u.s.WinIf.pcPDRBytesRW = BytesWritten;
+
+ /* the oid can be processed */
+ if (!(uOp & VBOXNDISREQUEST_QUEUED))
+ {
+ Status = vboxNetFltWinMpRequestPostQuery(pNetFlt);
+ }
+ }
+ break;
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+
+#endif /* ifndef VBOXNETADP*/
+
+static NDIS_STATUS vboxNetFltWinMpHandlePowerState(PVBOXNETFLTINS pNetFlt, NDIS_DEVICE_POWER_STATE enmState)
+{
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0
+ && enmState != NdisDeviceStateD0)
+ {
+ /* invalid state transformation */
+ AssertFailed();
+ return NDIS_STATUS_FAILURE;
+ }
+
+#ifndef VBOXNETADP
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) == NdisDeviceStateD0
+ && enmState > NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = TRUE;
+ }
+
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) > NdisDeviceStateD0
+ && enmState == NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = FALSE;
+ }
+#endif
+
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.MpState, enmState);
+
+#ifndef VBOXNETADP
+ if (pNetFlt->u.s.WinIf.StateFlags.fStandBy == FALSE)
+ {
+ if (pNetFlt->u.s.WinIf.MpIndicatedMediaStatus != pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus)
+ {
+ NdisMIndicateStatus(pNetFlt->u.s.WinIf.hMiniport, pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus, NULL, 0);
+ NdisMIndicateStatusComplete(pNetFlt->u.s.WinIf.hMiniport);
+ pNetFlt->u.s.WinIf.MpIndicatedMediaStatus = pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus;
+ }
+ }
+ else
+ {
+ pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus = pNetFlt->u.s.WinIf.MpIndicatedMediaStatus;
+ }
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+#ifndef VBOXNETADP
+static NDIS_STATUS vboxNetFltWinMpRequestPostSet(PVBOXNETFLTINS pNetFlt)
+{
+ if (pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ /* need to disable cleaning promiscuous here ?? */
+ bool fNetFltActive;
+ const bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &fNetFltActive);
+
+ Assert(pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer);
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter);
+
+ if (fNetFltActive)
+ {
+ Assert(fWinIfActive);
+
+ /* netflt is active, update the cached value */
+ /** @todo in case we are are not in promiscuous now, we are issuing a request.
+ * what should we do in case of a failure?
+ * i.e. should we update the fUpperProtocolSetFilter in completion routine in this case? etc. */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *((PULONG)pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer);
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+
+ if (!(pNetFlt->u.s.WinIf.fOurSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS))
+ {
+ pNetFlt->u.s.WinIf.fSetFilterBuffer = NDIS_PACKET_TYPE_PROMISCUOUS;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer = &pNetFlt->u.s.WinIf.fSetFilterBuffer;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof (pNetFlt->u.s.WinIf.fSetFilterBuffer);
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 1;
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 1;
+ /* we'll do dereferencing in request complete */
+ }
+ else
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ /* we've intercepted the query and completed it */
+ vboxNetFltWinMpRequestStateComplete(pNetFlt);
+ return NDIS_STATUS_SUCCESS;
+ }
+ }
+ else if (fWinIfActive)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 1;
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 0;
+ /* dereference on completion */
+ }
+ }
+
+ NDIS_STATUS Status;
+
+ NdisRequest(&Status, pNetFlt->u.s.WinIf.hBinding, &pNetFlt->u.s.WinIf.PassDownRequest);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ vboxNetFltWinPtRequestComplete(pNetFlt, &pNetFlt->u.s.WinIf.PassDownRequest, Status);
+ }
+
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRequestPost(PVBOXNETFLTINS pNetFlt)
+{
+ switch (pNetFlt->u.s.WinIf.PassDownRequest.RequestType)
+ {
+ case NdisRequestQueryInformation:
+ return vboxNetFltWinMpRequestPostQuery(pNetFlt);
+ case NdisRequestSetInformation:
+ return vboxNetFltWinMpRequestPostSet(pNetFlt);
+ default:
+ AssertBreakpoint();
+ return NDIS_STATUS_FAILURE;
+ }
+}
+
+static NDIS_STATUS vboxNetFltWinMpSetInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ switch (Oid)
+ {
+ case OID_PNP_SET_POWER:
+ {
+ if (InformationBufferLength >= sizeof (NDIS_DEVICE_POWER_STATE))
+ {
+ NDIS_DEVICE_POWER_STATE *penmState = (NDIS_DEVICE_POWER_STATE*)InformationBuffer;
+ Status = vboxNetFltWinMpHandlePowerState(pNetFlt, *penmState);
+ }
+ else
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
+ *BytesNeeded = 0;
+ }
+ else
+ {
+ *BytesRead = 0;
+ *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+ }
+ break;
+ }
+ default:
+ {
+ /* the oid is to be passed down,
+ * check the device state if we can do it
+ * and update device state accordingly */
+ UINT uOp = vboxNetFltWinMpRequestStatePrep(pNetFlt, &Status);
+ if (uOp)
+ {
+ /* save the request info */
+ pNetFlt->u.s.WinIf.PassDownRequest.RequestType = NdisRequestSetInformation;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.Oid = Oid;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+ pNetFlt->u.s.WinIf.PassDownRequest.DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;
+ pNetFlt->u.s.WinIf.pcPDRBytesNeeded = BytesNeeded;
+ pNetFlt->u.s.WinIf.pcPDRBytesRW = BytesRead;
+
+ /* the oid can be processed */
+ if (!(uOp & VBOXNDISREQUEST_QUEUED))
+ {
+ Status = vboxNetFltWinMpRequestPostSet(pNetFlt);
+ }
+ }
+ break;
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+#else
+static NDIS_OID g_vboxNetFltWinMpSupportedOids[] =
+{
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_PNP_CAPABILITIES,
+ OID_PNP_QUERY_POWER,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_PNP_SET_POWER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAC_OPTIONS,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS,
+};
+
+static NDIS_STATUS vboxNetFltWinMpQueryInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded)
+{
+ /* static data */
+ static const NDIS_HARDWARE_STATUS enmHwStatus = NdisHardwareStatusReady;
+ static const NDIS_MEDIUM enmMedium = NdisMedium802_3;
+ static NDIS_PNP_CAPABILITIES PnPCaps = {0};
+ static BOOLEAN bPnPCapsInited = FALSE;
+
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG64 u64Info = 0;
+ ULONG u32Info = 0;
+ USHORT u16Info = 0;
+ /* default is 4bytes */
+ const void* pvInfo = (void*)&u32Info;
+ ULONG cbInfo = sizeof (u32Info);
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ *BytesWritten = 0;
+ *BytesNeeded = 0;
+
+ switch (Oid)
+ {
+ case OID_GEN_SUPPORTED_LIST:
+ pvInfo = g_vboxNetFltWinMpSupportedOids;
+ cbInfo = sizeof (g_vboxNetFltWinMpSupportedOids);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ pvInfo = &enmHwStatus;
+ cbInfo = sizeof (NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ pvInfo = &enmMedium;
+ cbInfo = sizeof (NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ u32Info = VBOXNETADP_MAX_LOOKAHEAD_SIZE;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ u32Info = VBOXNETADP_MAX_PACKET_SIZE - VBOXNETADP_HEADER_SIZE;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ u32Info = VBOXNETADP_MAX_PACKET_SIZE;
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ u32Info = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_NO_LOOPBACK;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ u32Info = VBOXNETADP_LINK_SPEED;
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ u32Info = VBOXNETADP_MAX_PACKET_SIZE * VBOXNETFLT_PACKET_INFO_POOL_SIZE;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ u32Info = VBOXNETADP_VENDOR_ID;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ pvInfo = VBOXNETADP_VENDOR_DESC;
+ cbInfo = sizeof (VBOXNETADP_VENDOR_DESC);
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ u32Info = VBOXNETADP_VENDOR_DRIVER_VERSION;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ u16Info = (USHORT)((VBOXNETFLT_VERSION_MP_NDIS_MAJOR << 8) + VBOXNETFLT_VERSION_MP_NDIS_MINOR);
+ pvInfo = (PVOID)&u16Info;
+ cbInfo = sizeof (USHORT);
+ break;
+
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ u32Info = VBOXNETFLT_PACKET_INFO_POOL_SIZE;
+ break;
+
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+#ifdef VBOXNETADP_REPORT_DISCONNECTED
+ {
+ bool bNetFltActive;
+ bool bActive = vboxNetFltWinReferenceWinIfNetFltFromAdapt(pNetFlt, bNetFltActive);
+ if (bActive && bNetFltActive)
+ {
+ u32Info = NdisMediaStateConnected;
+ }
+ else
+ {
+ u32Info = NdisMediaStateDisconnected;
+ }
+
+ if (bActive)
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ if (bNetFltActive)
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else
+ {
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+ }
+#else
+ u32Info = NdisMediaStateConnected;
+#endif
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ u32Info = NDIS_PACKET_TYPE_BROADCAST
+ | NDIS_PACKET_TYPE_DIRECTED
+ | NDIS_PACKET_TYPE_ALL_FUNCTIONAL
+ | NDIS_PACKET_TYPE_ALL_LOCAL
+ | NDIS_PACKET_TYPE_GROUP
+ | NDIS_PACKET_TYPE_MULTICAST;
+ break;
+
+ case OID_PNP_CAPABILITIES:
+ if (!bPnPCapsInited)
+ {
+ PnPCaps.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ PnPCaps.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
+ bPnPCapsInited = TRUE;
+ }
+ cbInfo = sizeof (NDIS_PNP_CAPABILITIES);
+ pvInfo = &PnPCaps;
+
+ break;
+
+ case OID_PNP_QUERY_POWER:
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ u64Info = pNetFlt->u.s.WinIf.cTxSuccess;
+ pvInfo = &u64Info;
+ if (InformationBufferLength >= sizeof (ULONG64) || InformationBufferLength == 0)
+ {
+ cbInfo = sizeof (ULONG64);
+ }
+ else
+ {
+ cbInfo = sizeof (ULONG);
+ }
+ *BytesNeeded = sizeof (ULONG64);
+ break;
+
+ case OID_GEN_RCV_OK:
+ u64Info = pNetFlt->u.s.WinIf.cRxSuccess;
+ pvInfo = &u64Info;
+ if (InformationBufferLength >= sizeof (ULONG64) || InformationBufferLength == 0)
+ {
+ cbInfo = sizeof (ULONG64);
+ }
+ else
+ {
+ cbInfo = sizeof (ULONG);
+ }
+ *BytesNeeded = sizeof (ULONG64);
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ u32Info = pNetFlt->u.s.WinIf.cTxError;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ u32Info = pNetFlt->u.s.WinIf.cRxError;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ case OID_GEN_RCV_CRC_ERROR:
+ u32Info = 0;
+ break;
+
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ u32Info = VBOXNETFLT_PACKET_INFO_POOL_SIZE;
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ pvInfo = &pNetFlt->u.s.MacAddr;
+ cbInfo = VBOXNETADP_ETH_ADDRESS_LENGTH;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ pvInfo = &pNetFlt->u.s.MacAddr;
+ cbInfo = VBOXNETADP_ETH_ADDRESS_LENGTH;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ u32Info = VBOXNETADP_MAX_MCAST_LIST;
+ break;
+
+ case OID_802_3_MAC_OPTIONS:
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ case OID_802_3_XMIT_ONE_COLLISION:
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ case OID_802_3_XMIT_DEFERRED:
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+ case OID_802_3_RCV_OVERRUN:
+ case OID_802_3_XMIT_UNDERRUN:
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+ u32Info = 0;
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (cbInfo <= InformationBufferLength)
+ {
+ *BytesWritten = cbInfo;
+ if (cbInfo)
+ NdisMoveMemory(InformationBuffer, pvInfo, cbInfo);
+ }
+ else
+ {
+ *BytesNeeded = cbInfo;
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ }
+
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinMpSetInformation(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS) MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Oid (%s)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid)));
+
+ *BytesRead = 0;
+ *BytesNeeded = 0;
+
+ switch (Oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ *BytesRead = InformationBufferLength;
+ if (InformationBufferLength % VBOXNETADP_ETH_ADDRESS_LENGTH)
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ if (InformationBufferLength > (VBOXNETADP_MAX_MCAST_LIST * VBOXNETADP_ETH_ADDRESS_LENGTH))
+ {
+ Status = NDIS_STATUS_MULTICAST_FULL;
+ *BytesNeeded = VBOXNETADP_MAX_MCAST_LIST * VBOXNETADP_ETH_ADDRESS_LENGTH;
+ break;
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (InformationBufferLength != sizeof (ULONG))
+ {
+ *BytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ *BytesRead = InformationBufferLength;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (InformationBufferLength != sizeof (ULONG)){
+ *BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ break;
+
+ case OID_PNP_SET_POWER:
+ if (InformationBufferLength >= sizeof(NDIS_DEVICE_POWER_STATE))
+ {
+ NDIS_DEVICE_POWER_STATE *penmState = (NDIS_DEVICE_POWER_STATE*)InformationBuffer;
+ Status = vboxNetFltWinMpHandlePowerState(pNetFlt, *penmState);
+ }
+ else
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ *BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
+ *BytesNeeded = 0;
+ }
+ else
+ {
+ *BytesRead = 0;
+ *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+ }
+ break;
+
+ default:
+ Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Oid (%s), Status (0x%x)\n", pNetFlt, vboxNetFltWinMpDumpOid(Oid), Status));
+
+ return Status;
+}
+
+#endif
+
+#define VBOXNETFLTDUMP_STRCASE(_t) \
+ case _t: return #_t;
+#define VBOXNETFLTDUMP_STRCASE_UNKNOWN() \
+ default: /*AssertFailed();*/ return "Unknown";
+
+static const char* vboxNetFltWinMpDumpOid(ULONG oid)
+{
+ switch (oid)
+ {
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_SUPPORTED_LIST)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_HARDWARE_STATUS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_SUPPORTED)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_IN_USE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_LOOKAHEAD)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_FRAME_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_LINK_SPEED)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSMIT_BUFFER_SPACE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RECEIVE_BUFFER_SPACE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSMIT_BLOCK_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RECEIVE_BLOCK_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VENDOR_ID)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VENDOR_DESCRIPTION)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_CURRENT_PACKET_FILTER)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_CURRENT_LOOKAHEAD)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DRIVER_VERSION)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_TOTAL_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_PROTOCOL_OPTIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAC_OPTIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_CONNECT_STATUS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MAXIMUM_SEND_PACKETS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VENDOR_DRIVER_VERSION)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_SUPPORTED_GUIDS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_NETWORK_LAYER_ADDRESSES)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSPORT_HEADER_OFFSET)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MACHINE_NAME)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RNDIS_CONFIG_PARAMETER)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_VLAN_ID)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_CAPABILITIES)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_PHYSICAL_MEDIUM)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_XMIT_OK)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_OK)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_XMIT_ERROR)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_ERROR)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_NO_BUFFER)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_BYTES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_FRAMES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_BYTES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_FRAMES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_BYTES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_FRAMES_XMIT)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_BYTES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DIRECTED_FRAMES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_BYTES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MULTICAST_FRAMES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_BYTES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_BROADCAST_FRAMES_RCV)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RCV_CRC_ERROR)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_TRANSMIT_QUEUE_LENGTH)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_GET_TIME_CAPS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_GET_NETCARD_TIME)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_NETCARD_LOAD)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_DEVICE_PROFILE)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_INIT_TIME_MS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_RESET_COUNTS)
+ VBOXNETFLTDUMP_STRCASE(OID_GEN_MEDIA_SENSE_COUNTS)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_CAPABILITIES)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_SET_POWER)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_QUERY_POWER)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_ADD_WAKE_UP_PATTERN)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_REMOVE_WAKE_UP_PATTERN)
+ VBOXNETFLTDUMP_STRCASE(OID_PNP_ENABLE_WAKE_UP)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_PERMANENT_ADDRESS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_CURRENT_ADDRESS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_MULTICAST_LIST)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_MAXIMUM_LIST_SIZE)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_MAC_OPTIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_RCV_ERROR_ALIGNMENT)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_ONE_COLLISION)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_MORE_COLLISIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_DEFERRED)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_MAX_COLLISIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_RCV_OVERRUN)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_UNDERRUN)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_HEARTBEAT_FAILURE)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_TIMES_CRS_LOST)
+ VBOXNETFLTDUMP_STRCASE(OID_802_3_XMIT_LATE_COLLISIONS)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_OFFLOAD)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_ADD_SA)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_DELETE_SA)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_SAN_SUPPORT)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA)
+ VBOXNETFLTDUMP_STRCASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA)
+ VBOXNETFLTDUMP_STRCASE_UNKNOWN()
+ }
+}
+
+DECLHIDDEN(VOID) vboxNetFltWinMpReturnPacket(IN NDIS_HANDLE hMiniportAdapterContext, IN PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hMiniportAdapterContext;
+ PVBOXNETFLT_PKTRSVD_MP pInfo = (PVBOXNETFLT_PKTRSVD_MP)pPacket->MiniportReserved;
+ PNDIS_PACKET pOrigPacket = pInfo->pOrigPacket;
+ PVOID pBufToFree = pInfo->pBufToFree;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (pOrigPacket)
+ {
+ /* the packet was sent from underlying miniport */
+ NdisFreePacket(pPacket);
+ NdisReturnPackets(&pOrigPacket, 1);
+ }
+ else
+ {
+ /* the packet was sent from IntNet or it is a packet we allocated on PtReceive for TransferData processing */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, !pBufToFree /* bFreeMem */);
+ }
+
+ if (pBufToFree)
+ {
+ vboxNetFltWinMemFree(pBufToFree);
+ }
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static NDIS_STATUS vboxNetFltWinMpTransferData(OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE hContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer)
+{
+#ifndef VBOXNETADP
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ NDIS_STATUS Status;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if ( vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState) != NdisDeviceStateD0
+ || vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.MpState) != NdisDeviceStateD0)
+ {
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, NDIS_STATUS_FAILURE));
+ return NDIS_STATUS_FAILURE;
+ }
+
+ NdisTransferData(&Status, pNetFlt->u.s.WinIf.hBinding, MiniportReceiveContext,
+ ByteOffset, BytesToTransfer, Packet, BytesTransferred);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+ return Status;
+
+#else
+ RT_NOREF6(Packet, BytesTransferred, hContext, MiniportReceiveContext, ByteOffset, BytesToTransfer);
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", hContext));
+ /* should never be here */
+ AssertFailed();
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", hContext, NDIS_STATUS_FAILURE));
+ return NDIS_STATUS_FAILURE;
+#endif
+}
+
+static void vboxNetFltWinMpHalt(IN NDIS_HANDLE hContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ NDIS_STATUS Status;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+#ifndef VBOXNETADP
+ if (vboxNetFltWinGetWinIfState(pNetFlt) == kVBoxWinIfState_Disconnecting)
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+
+ vboxNetFltWinPtCloseInterface(pNetFlt, &Status);
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+#endif
+ {
+ /* we're NOT called from protocolUnbinAdapter, perform a full disconnect */
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+#ifndef VBOXNETADP
+ AssertBreakpoint();
+#endif
+ Status = vboxNetFltWinDetachFromInterface(pNetFlt, false);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+/**
+ * register the miniport edge
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRegister(PVBOXNETFLTGLOBALS_MP pGlobalsMp, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
+{
+ NDIS_MINIPORT_CHARACTERISTICS MpChars;
+
+ NdisMInitializeWrapper(&pGlobalsMp->hNdisWrapper, pDriverObject, pRegistryPathStr, NULL);
+
+ NdisZeroMemory(&MpChars, sizeof (MpChars));
+
+ MpChars.MajorNdisVersion = VBOXNETFLT_VERSION_MP_NDIS_MAJOR;
+ MpChars.MinorNdisVersion = VBOXNETFLT_VERSION_MP_NDIS_MINOR;
+
+ MpChars.HaltHandler = vboxNetFltWinMpHalt;
+ MpChars.InitializeHandler = vboxNetFltWinMpInitialize;
+ MpChars.QueryInformationHandler = vboxNetFltWinMpQueryInformation;
+ MpChars.SetInformationHandler = vboxNetFltWinMpSetInformation;
+ MpChars.TransferDataHandler = vboxNetFltWinMpTransferData;
+ MpChars.ReturnPacketHandler = vboxNetFltWinMpReturnPacket;
+ MpChars.SendPacketsHandler = vboxNetFltWinMpSendPackets;
+
+#ifndef VBOXNETADP
+ NDIS_STATUS Status = NdisIMRegisterLayeredMiniport(pGlobalsMp->hNdisWrapper, &MpChars, sizeof (MpChars), &pGlobalsMp->hMiniport);
+#else
+ NDIS_STATUS Status = NdisMRegisterMiniport(pGlobalsMp->hNdisWrapper, &MpChars, sizeof (MpChars));
+#endif
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisMRegisterUnloadHandler(pGlobalsMp->hNdisWrapper, vboxNetFltWinUnload);
+ }
+
+ return Status;
+}
+
+/**
+ * deregister the miniport edge
+ */
+DECLHIDDEN(VOID) vboxNetFltWinMpDeregister(PVBOXNETFLTGLOBALS_MP pGlobalsMp)
+{
+#ifndef VBOXNETADP
+ NdisIMDeregisterLayeredMiniport(pGlobalsMp->hMiniport);
+#endif
+ NdisTerminateWrapper(pGlobalsMp->hNdisWrapper, NULL);
+
+ NdisZeroMemory(pGlobalsMp, sizeof (*pGlobalsMp));
+}
+
+#ifndef VBOXNETADP
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpInitializeDevideInstance(PVBOXNETFLTINS pThis)
+{
+ NDIS_STATUS Status;
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Initializing);
+
+ Status = NdisIMInitializeDeviceInstanceEx(g_VBoxNetFltGlobalsWin.Mp.hMiniport,
+ &pThis->u.s.WinIf.MpDeviceName,
+ pThis);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pThis->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+ AssertBreakpoint();
+ vboxNetFltWinMpDeInitializeDeviceInstance(pThis, &Status);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ return pThis->u.s.WinIf.OpenCloseStatus;
+ }
+
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+
+ return Status;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinMpDeInitializeDeviceInstance(PVBOXNETFLTINS pThis, PNDIS_STATUS pStatus)
+{
+ NDIS_STATUS Status;
+
+ if (vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initializing)
+ {
+ Status = NdisIMCancelInitializeDeviceInstance(g_VBoxNetFltGlobalsWin.Mp.hMiniport, &pThis->u.s.WinIf.MpDeviceName);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ /* we've canceled the initialization successfully */
+ Assert(pThis->u.s.WinIf.hMiniport == NULL);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+ NdisWaitEvent(&pThis->u.s.WinIf.MpInitCompleteEvent, 0);
+ }
+ else
+ Status = NDIS_STATUS_SUCCESS;
+
+ Assert( vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized
+ || vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ if (vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized)
+ {
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+
+ Status = NdisIMDeInitializeDeviceInstance(pThis->u.s.WinIf.hMiniport);
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ if (Status != NDIS_STATUS_SUCCESS)
+ Status = NDIS_STATUS_FAILURE;
+
+ *pStatus = Status;
+ return true;
+ }
+
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+
+ *pStatus = Status;
+ return false;
+}
+
+#endif /* !VBOXNETADP */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h
new file mode 100644
index 00000000..7a904aa8
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM-win.h
@@ -0,0 +1,67 @@
+/* $Id: VBoxNetFltM-win.h $ */
+/** @file
+ * VBoxNetFltM-win.h - Bridged Networking Driver, Windows Specific Code - Miniport edge API
+ */
+
+/*
+ * Copyright (C) 2011-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_VBoxNetFlt_win_drv_VBoxNetFltM_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltM_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRegister(PVBOXNETFLTGLOBALS_MP pGlobalsMp, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr);
+DECLHIDDEN(VOID) vboxNetFltWinMpDeregister(PVBOXNETFLTGLOBALS_MP pGlobalsMp);
+DECLHIDDEN(VOID) vboxNetFltWinMpReturnPacket(IN NDIS_HANDLE hMiniportAdapterContext, IN PNDIS_PACKET pPacket);
+
+#ifdef VBOXNETADP
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoInitialization(PVBOXNETFLTINS pThis, NDIS_HANDLE hMiniportAdapter, NDIS_HANDLE hWrapperConfigurationContext);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoDeinitialization(PVBOXNETFLTINS pThis);
+
+#else
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpInitializeDevideInstance(PVBOXNETFLTINS pThis);
+DECLHIDDEN(bool) vboxNetFltWinMpDeInitializeDeviceInstance(PVBOXNETFLTINS pThis, PNDIS_STATUS pStatus);
+
+DECLINLINE(VOID) vboxNetFltWinMpRequestStateComplete(PVBOXNETFLTINS pNetFlt)
+{
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = 0;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRequestPost(PVBOXNETFLTINS pNetFlt);
+#endif
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltM_win_h */
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf
new file mode 100644
index 00000000..fcf30fc8
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltM.inf
@@ -0,0 +1,82 @@
+; $Id: VBoxNetFltM.inf $
+;; @file
+; VBoxNetFltM.inf - VirtualBox Bridged Networking Driver inf file Miniport edge
+;
+
+;
+; Copyright (C) 2011-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 = VBoxNetFlt.cat
+Class = Net
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %ORACLE%
+;DriverPackageType=NdisImMiniport
+;DriverPackageDisplayName=%VBoxNetFltMP_Desc%
+;edit-DriverVer=08/13/2008,1.1.0.1
+
+[ControlFlags]
+ExcludeFromSelect = sun_VBoxNetFltmp
+
+[DestinationDirs]
+DefaultDestDir=12
+; No files to copy
+
+[Manufacturer]
+%ORACLE% = VBoxNetFltMP@COMMA-NT-ARCH@
+
+[VBoxNetFltMP@DOT-NT-ARCH@]
+%VBoxNetFltMP_Desc% = VBoxNetFltMP.ndi, sun_VBoxNetFltmp
+
+[VBoxNetFltMP.ndi]
+Characteristics = 0x29 ;NCF_NOT_USER_REMOVABLE | NCF_VIRTUAL | NCF_HIDDEN
+CopyFiles =
+
+[VBoxNetFltMP.ndi.Services]
+AddService = VBoxNetFlt,0x2, VBoxNetFltMP.AddService
+
+[VBoxNetFltMP.AddService]
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetFlt.sys
+
+[VBoxNetFltMP.AddService.AddReg]
+
+[Strings]
+ORACLE = "Oracle Corporation"
+VBoxNetFltMP_Desc = "VirtualBox Bridged Networking Driver Miniport"
+
+[SourceDisksNames]
+
+[SourceDisksFiles]
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp
new file mode 100644
index 00000000..3e06f3c2
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.cpp
@@ -0,0 +1,1595 @@
+/* $Id: VBoxNetFltP-win.cpp $ */
+/** @file
+ * VBoxNetFltP-win.cpp - Bridged Networking Driver, Windows Specific Code.
+ * Protocol edge
+ */
+/*
+ * Copyright (C) 2011-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 "VBoxNetFltCmn-win.h"
+
+#ifdef VBOXNETADP
+# error "No protocol edge"
+#endif
+
+#define VBOXNETFLT_PT_STATUS_IS_FILTERED(_s) (\
+ (_s) == NDIS_STATUS_MEDIA_CONNECT \
+ || (_s) == NDIS_STATUS_MEDIA_DISCONNECT \
+ )
+
+/**
+ * performs binding to the given adapter
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(PVBOXNETFLTINS pThis, PNDIS_STRING pOurDeviceName, PNDIS_STRING pBindToDeviceName)
+{
+ Assert(pThis->u.s.WinIf.PtState.PowerState == NdisDeviceStateD3);
+ Assert(pThis->u.s.WinIf.PtState.OpState == kVBoxNetDevOpState_Deinitialized);
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Initializing);
+
+ NDIS_STATUS Status = vboxNetFltWinCopyString(&pThis->u.s.WinIf.MpDeviceName, pOurDeviceName);
+ Assert (Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ vboxNetFltWinSetPowerState(&pThis->u.s.WinIf.PtState, NdisDeviceStateD0);
+ pThis->u.s.WinIf.OpenCloseStatus = NDIS_STATUS_SUCCESS;
+
+ UINT iMedium;
+ NDIS_STATUS TmpStatus;
+ NDIS_MEDIUM aenmNdisMedium[] =
+ {
+ /* Ethernet */
+ NdisMedium802_3,
+ /* Wan */
+ NdisMediumWan
+ };
+
+ NdisResetEvent(&pThis->u.s.WinIf.OpenCloseEvent);
+
+ NdisOpenAdapter(&Status, &TmpStatus, &pThis->u.s.WinIf.hBinding, &iMedium,
+ aenmNdisMedium, RT_ELEMENTS(aenmNdisMedium),
+ g_VBoxNetFltGlobalsWin.Pt.hProtocol,
+ pThis,
+ pBindToDeviceName,
+ 0, /* IN UINT OpenOptions, (reserved, should be NULL) */
+ NULL /* IN PSTRING AddressingInformation OPTIONAL */
+ );
+ Assert(Status == NDIS_STATUS_PENDING || Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pThis->u.s.WinIf.OpenCloseEvent, 0);
+ Status = pThis->u.s.WinIf.OpenCloseStatus;
+ }
+
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Assert(pThis->u.s.WinIf.hBinding);
+ pThis->u.s.WinIf.enmMedium = aenmNdisMedium[iMedium];
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Initialized);
+
+ Status = vboxNetFltWinMpInitializeDevideInstance(pThis);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ LogRelFunc(("vboxNetFltWinMpInitializeDevideInstance failed, Status 0x%x\n", Status));
+ }
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinPtCloseInterface(pThis, &TmpStatus);
+ Assert(TmpStatus == NDIS_STATUS_SUCCESS);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+ {
+ LogRelFunc(("NdisOpenAdapter failed, Status (0x%x)", Status));
+ }
+
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+ pThis->u.s.WinIf.hBinding = NULL;
+ }
+
+ return Status;
+}
+
+static VOID vboxNetFltWinPtBindAdapter(OUT PNDIS_STATUS pStatus,
+ IN NDIS_HANDLE hBindContext,
+ IN PNDIS_STRING pDeviceNameStr,
+ IN PVOID pvSystemSpecific1,
+ IN PVOID pvSystemSpecific2)
+{
+ LogFlowFuncEnter();
+ RT_NOREF2(hBindContext, pvSystemSpecific2);
+
+ NDIS_STATUS Status;
+ NDIS_HANDLE hConfig = NULL;
+
+ NdisOpenProtocolConfiguration(&Status, &hConfig, (PNDIS_STRING)pvSystemSpecific1);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PNDIS_CONFIGURATION_PARAMETER pParam;
+ NDIS_STRING UppedBindStr = NDIS_STRING_CONST("UpperBindings");
+ NdisReadConfiguration(&Status, &pParam, hConfig, &UppedBindStr, NdisParameterString);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLTINS pNetFlt;
+ Status = vboxNetFltWinPtInitBind(&pNetFlt, &pParam->ParameterData.StringData, pDeviceNameStr);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ }
+
+ NdisCloseConfiguration(hConfig);
+ }
+
+ *pStatus = Status;
+
+ LogFlowFunc(("LEAVE: Status 0x%x\n", Status));
+}
+
+static VOID vboxNetFltWinPtOpenAdapterComplete(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ RT_NOREF1(OpenErrorStatus);
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Status (0x%x), OpenErrorStatus(0x%x)\n", pNetFlt, Status, OpenErrorStatus));
+ Assert(pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+ {
+ pNetFlt->u.s.WinIf.OpenCloseStatus = Status;
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status != NDIS_STATUS_SUCCESS)
+ LogRelFunc(("Open Complete status is 0x%x", Status));
+ }
+ else
+ LogRelFunc(("Adapter maintained status is 0x%x", pNetFlt->u.s.WinIf.OpenCloseStatus));
+ NdisSetEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent);
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x), OpenErrorStatus(0x%x)\n", pNetFlt, Status, OpenErrorStatus));
+}
+
+static void vboxNetFltWinPtRequestsWaitComplete(PVBOXNETFLTINS pNetFlt)
+{
+ /* wait for request to complete */
+ while (vboxNetFltWinAtomicUoReadWinState(pNetFlt->u.s.WinIf.StateFlags).fRequestInfo == VBOXNDISREQUEST_INPROGRESS)
+ {
+ vboxNetFltWinSleep(2);
+ }
+
+ /*
+ * If the below miniport is going to low power state, complete the queued request
+ */
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+ if (pNetFlt->u.s.WinIf.StateFlags.fRequestInfo & VBOXNDISREQUEST_QUEUED)
+ {
+ /* mark the request as InProgress before posting it to RequestComplete */
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ vboxNetFltWinPtRequestComplete(pNetFlt, &pNetFlt->u.s.WinIf.PassDownRequest, NDIS_STATUS_FAILURE);
+ }
+ else
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ }
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoUnbinding(PVBOXNETFLTINS pNetFlt, bool bOnUnbind)
+{
+ NDIS_STATUS Status;
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+ int cPPUsage;
+
+ LogFlowFunc(("ENTER: pNetFlt 0x%p\n", pNetFlt));
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Initialized);
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+
+ ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true);
+ ASMAtomicUoWriteBool(&pNetFlt->fRediscoveryPending, false);
+ ASMAtomicUoWriteU64(&pNetFlt->NanoTSLastRediscovery, NanoTS);
+
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitializing);
+ if (!bOnUnbind)
+ {
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitializing);
+ }
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ vboxNetFltWinPtRequestsWaitComplete(pNetFlt);
+
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.MpState);
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.PtState);
+
+ /* check packet pool is empty */
+ cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hSendPacketPool);
+ Assert(cPPUsage == 0);
+ cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(cPPUsage == 0);
+ /* for debugging only, ignore the err in release */
+ NOREF(cPPUsage);
+
+ if (!bOnUnbind || !vboxNetFltWinMpDeInitializeDeviceInstance(pNetFlt, &Status))
+ {
+ vboxNetFltWinPtCloseInterface(pNetFlt, &Status);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+
+ if (!bOnUnbind)
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitializing);
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ else
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ }
+ }
+ else
+ {
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt 0x%p\n", pNetFlt));
+
+ return Status;
+}
+
+static VOID vboxNetFltWinPtUnbindAdapter(OUT PNDIS_STATUS pStatus,
+ IN NDIS_HANDLE hContext,
+ IN NDIS_HANDLE hUnbindContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ RT_NOREF1(hUnbindContext);
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ *pStatus = vboxNetFltWinDetachFromInterface(pNetFlt, true);
+ Assert(*pStatus == NDIS_STATUS_SUCCESS);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static VOID vboxNetFltWinPtUnloadProtocol()
+{
+ LogFlowFuncEnter();
+ NDIS_STATUS Status = vboxNetFltWinPtDeregister(&g_VBoxNetFltGlobalsWin.Pt);
+ Assert(Status == NDIS_STATUS_SUCCESS); NOREF(Status);
+ LogFlowFunc(("LEAVE: PtDeregister Status (0x%x)\n", Status));
+}
+
+
+static VOID vboxNetFltWinPtCloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)ProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+ Assert(pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ Assert(pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS);
+ if (pNetFlt->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+ {
+ pNetFlt->u.s.WinIf.OpenCloseStatus = Status;
+ }
+ NdisSetEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent);
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), Status (0x%x)\n", pNetFlt, Status));
+}
+
+static VOID vboxNetFltWinPtResetComplete(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS Status)
+{
+ RT_NOREF2(hProtocolBindingContext, Status);
+ LogFlowFunc(("ENTER: pNetFlt 0x%p, Status 0x%x\n", hProtocolBindingContext, Status));
+ /*
+ * should never be here
+ */
+ AssertFailed();
+ LogFlowFunc(("LEAVE: pNetFlt 0x%p, Status 0x%x\n", hProtocolBindingContext, Status));
+}
+
+static NDIS_STATUS vboxNetFltWinPtHandleQueryInfoComplete(PVBOXNETFLTINS pNetFlt, NDIS_STATUS Status)
+{
+ PNDIS_REQUEST pRequest = &pNetFlt->u.s.WinIf.PassDownRequest;
+
+ switch (pRequest->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_PNP_CAPABILITIES:
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof (NDIS_PNP_CAPABILITIES))
+ {
+ PNDIS_PNP_CAPABILITIES pPnPCaps = (PNDIS_PNP_CAPABILITIES)(pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ PNDIS_PM_WAKE_UP_CAPABILITIES pPmWuCaps = &pPnPCaps->WakeUpCapabilities;
+ pPmWuCaps->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pPmWuCaps->MinPatternWakeUp = NdisDeviceStateUnspecified;
+ pPmWuCaps->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+ *pNetFlt->u.s.WinIf.pcPDRBytesRW = sizeof (NDIS_PNP_CAPABILITIES);
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = 0;
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof(NDIS_PNP_CAPABILITIES);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ break;
+ }
+
+ case OID_GEN_MAC_OPTIONS:
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ pNetFlt->u.s.WinIf.fMacOptions = *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ /* clearing this flag tells ndis we'll handle loopback ourselves
+ * the ndis layer or nic driver below us would loopback packets as necessary */
+ *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
+#else
+ /* we have to catch loopbacks from the underlying driver, so no duplications will occur,
+ * just indicate NDIS to handle loopbacks for the packets coming from the protocol */
+ *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer |= NDIS_MAC_OPTION_NO_LOOPBACK;
+#endif
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ break;
+ }
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ {
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ /* we're here _ONLY_ in the passthru mode */
+ Assert(pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter && !pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt);
+ if (pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter && !pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt)
+ {
+ Assert(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE);
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ /* the filter request is issued below only in case netflt is not active,
+ * simply update the cache here */
+ /* cache the filter used by upper protocols */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ Assert(pRequest->DATA.QUERY_INFORMATION.Oid != OID_PNP_QUERY_POWER);
+ break;
+ }
+
+ *pNetFlt->u.s.WinIf.pcPDRBytesRW = pRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = pRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinPtHandleSetInfoComplete(PVBOXNETFLTINS pNetFlt, NDIS_STATUS Status)
+{
+ PNDIS_REQUEST pRequest = &pNetFlt->u.s.WinIf.PassDownRequest;
+
+ switch (pRequest->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ {
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter)
+ {
+ if (pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt)
+ {
+ Assert(pNetFlt->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE);
+ pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt = 0;
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.SET_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ pNetFlt->u.s.WinIf.fOurSetFilter = *((PULONG)pRequest->DATA.SET_INFORMATION.InformationBuffer);
+ Assert(pNetFlt->u.s.WinIf.fOurSetFilter == NDIS_PACKET_TYPE_PROMISCUOUS);
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else
+ {
+ Assert(pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (pRequest->DATA.SET_INFORMATION.InformationBufferLength >= sizeof (ULONG))
+ {
+ /* the request was issued when the netflt was not active, simply update the cache here */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *((PULONG)pRequest->DATA.SET_INFORMATION.InformationBuffer);
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+ }
+ else
+ {
+ AssertFailed();
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = sizeof (ULONG);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+
+ pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter = 0;
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+#ifdef DEBUG_misha
+ else
+ {
+ AssertFailed();
+ }
+#endif
+ }
+ break;
+ }
+
+ default:
+ Assert(pRequest->DATA.SET_INFORMATION.Oid != OID_PNP_SET_POWER);
+ break;
+ }
+
+ *pNetFlt->u.s.WinIf.pcPDRBytesRW = pRequest->DATA.SET_INFORMATION.BytesRead;
+ *pNetFlt->u.s.WinIf.pcPDRBytesNeeded = pRequest->DATA.SET_INFORMATION.BytesNeeded;
+
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetFltWinPtRequestComplete(NDIS_HANDLE hContext, PNDIS_REQUEST pNdisRequest, NDIS_STATUS Status)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hContext;
+ PNDIS_REQUEST pSynchRequest = pNetFlt->u.s.WinIf.pSynchRequest;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
+
+ if (pSynchRequest == pNdisRequest)
+ {
+ /* asynchronous completion of our sync request */
+ /*1.set the status */
+ pNetFlt->u.s.WinIf.SynchCompletionStatus = Status;
+ /* 2. set event */
+ KeSetEvent(&pNetFlt->u.s.WinIf.hSynchCompletionEvent, 0, FALSE);
+ /* 3. return; */
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
+ return;
+ }
+
+ Assert(&pNetFlt->u.s.WinIf.PassDownRequest == pNdisRequest);
+ Assert(pNetFlt->u.s.WinIf.StateFlags.fRequestInfo == VBOXNDISREQUEST_INPROGRESS);
+ vboxNetFltWinMpRequestStateComplete(pNetFlt);
+
+ switch (pNdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+ Status = vboxNetFltWinPtHandleQueryInfoComplete(pNetFlt, Status);
+ NdisMQueryInformationComplete(pNetFlt->u.s.WinIf.hMiniport, Status);
+ break;
+
+ case NdisRequestSetInformation:
+ Status = vboxNetFltWinPtHandleSetInfoComplete(pNetFlt, Status);
+ NdisMSetInformationComplete(pNetFlt->u.s.WinIf.hMiniport, Status);
+ break;
+
+ default:
+ AssertFailed();
+ break;
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
+}
+
+static VOID vboxNetFltWinPtStatus(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID pvStatusBuffer, IN UINT cbStatusBuffer)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), GeneralStatus (0x%x)\n", pNetFlt, GeneralStatus));
+
+ if (vboxNetFltWinReferenceWinIf(pNetFlt))
+ {
+ Assert(pNetFlt->u.s.WinIf.hMiniport);
+
+ if (VBOXNETFLT_PT_STATUS_IS_FILTERED(GeneralStatus))
+ {
+ pNetFlt->u.s.WinIf.MpIndicatedMediaStatus = GeneralStatus;
+ }
+ NdisMIndicateStatus(pNetFlt->u.s.WinIf.hMiniport,
+ GeneralStatus,
+ pvStatusBuffer,
+ cbStatusBuffer);
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ else
+ {
+ if (pNetFlt->u.s.WinIf.hMiniport != NULL
+ && VBOXNETFLT_PT_STATUS_IS_FILTERED(GeneralStatus)
+ )
+ {
+ pNetFlt->u.s.WinIf.MpUnindicatedMediaStatus = GeneralStatus;
+ }
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), GeneralStatus (0x%x)\n", pNetFlt, GeneralStatus));
+}
+
+
+static VOID vboxNetFltWinPtStatusComplete(IN NDIS_HANDLE hProtocolBindingContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (vboxNetFltWinReferenceWinIf(pNetFlt))
+ {
+ NdisMIndicateStatusComplete(pNetFlt->u.s.WinIf.hMiniport);
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static VOID vboxNetFltWinPtSendComplete(IN NDIS_HANDLE hProtocolBindingContext, IN PNDIS_PACKET pPacket, IN NDIS_STATUS Status)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ PVBOXNETFLT_PKTRSVD_PT pSendInfo = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ PNDIS_PACKET pOrigPacket = pSendInfo->pOrigPacket;
+ PVOID pBufToFree = pSendInfo->pBufToFree;
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x)\n", pNetFlt, pPacket, Status));
+
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ /** @todo for optimization we could check only for netflt-mode packets
+ * do it for all for now */
+ vboxNetFltWinLbRemoveSendPacket(pNetFlt, pPacket);
+#endif
+
+ if (pOrigPacket)
+ {
+ NdisIMCopySendCompletePerPacketInfo(pOrigPacket, pPacket);
+ NdisFreePacket(pPacket);
+ /* the ptk was posted from the upperlying protocol */
+ NdisMSendComplete(pNetFlt->u.s.WinIf.hMiniport, pOrigPacket, Status);
+ }
+ else
+ {
+ /* if the pOrigPacket is zero - the ptk was originated by netFlt send/receive
+ * need to free packet buffers */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, !pBufToFree);
+ }
+
+ if (pBufToFree)
+ {
+ vboxNetFltWinMemFree(pBufToFree);
+ }
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x)\n", pNetFlt, pPacket, Status));
+}
+
+/**
+ * removes searches for the packet in the list and removes it if found
+ * @return true if the packet was found and removed, false - otherwise
+ */
+static bool vboxNetFltWinRemovePacketFromList(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
+ return vboxNetFltWinInterlockedSearchListEntry(pList, &pTDR->ListEntry, true /* remove*/);
+}
+
+/**
+ * puts the packet to the tail of the list
+ */
+static void vboxNetFltWinPutPacketToList(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket, PNDIS_BUFFER pOrigBuffer)
+{
+ PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
+ pTDR->pOrigBuffer = pOrigBuffer;
+ vboxNetFltWinInterlockedPutTail(pList, &pTDR->ListEntry);
+}
+
+static bool vboxNetFltWinPtTransferDataCompleteActive(PVBOXNETFLTINS pNetFltIf, PNDIS_PACKET pPacket, NDIS_STATUS Status)
+{
+ PNDIS_BUFFER pBuffer;
+ PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR;
+
+ if (!vboxNetFltWinRemovePacketFromList(&pNetFltIf->u.s.WinIf.TransferDataList, pPacket))
+ return false;
+
+ pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
+ Assert(pTDR);
+ Assert(pTDR->pOrigBuffer);
+
+ do
+ {
+ NdisUnchainBufferAtFront(pPacket, &pBuffer);
+
+ Assert(pBuffer);
+
+ NdisFreeBuffer(pBuffer);
+
+ pBuffer = pTDR->pOrigBuffer;
+
+ NdisChainBufferAtBack(pPacket, pBuffer);
+
+ /* data transfer was initiated when the netFlt was active
+ * the netFlt is still retained by us
+ * 1. check if loopback
+ * 2. enqueue packet
+ * 3. release netFlt */
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ if (vboxNetFltWinIsLoopedBackPacket(pPacket))
+ {
+ /* should not be here */
+ AssertFailed();
+ }
+#else
+ PNDIS_PACKET pLb = vboxNetFltWinLbSearchLoopBack(pNetFltIf, pPacket, false);
+ if (pLb)
+ {
+#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
+ /* should not be here */
+ AssertFailed();
+#endif
+ if (!vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ /* the packet is not from int net, need to pass it up to the host */
+ NdisMIndicateReceivePacket(pNetFltIf->u.s.WinIf.hMiniport, &pPacket, 1);
+ /* dereference NetFlt, WinIf will be dereferenced on Packet return */
+ vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+ break;
+ }
+ }
+#endif
+ else
+ {
+ /* 2. enqueue */
+ /* use the same packet info to put the packet in the processing packet queue */
+ PVBOXNETFLT_PKTRSVD_MP pRecvInfo = (PVBOXNETFLT_PKTRSVD_MP)pPacket->MiniportReserved;
+
+ VBOXNETFLT_LBVERIFY(pNetFltIf, pPacket);
+
+ pRecvInfo->pOrigPacket = NULL;
+ pRecvInfo->pBufToFree = NULL;
+
+ NdisGetPacketFlags(pPacket) = 0;
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFltIf, pPacket, 0))
+ {
+ /* drop it */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ vboxNetFltWinDereferenceWinIf(pNetFltIf);
+ }
+ else
+ {
+ NdisMIndicateReceivePacket(pNetFltIf->u.s.WinIf.hMiniport, &pPacket, 1);
+ }
+ vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+ break;
+# else
+ Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, PACKET_MINE);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ AssertFailed();
+# endif
+ }
+ }
+ else
+ {
+ AssertFailed();
+ }
+ /* we are here because of error either in data transfer or in enqueueing the packet */
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+ vboxNetFltWinDereferenceWinIf(pNetFltIf);
+ } while (0);
+
+ return true;
+}
+
+static VOID vboxNetFltWinPtTransferDataComplete(IN NDIS_HANDLE hProtocolBindingContext,
+ IN PNDIS_PACKET pPacket,
+ IN NDIS_STATUS Status,
+ IN UINT cbTransferred)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x), cbTransfered (%d)\n", pNetFlt, pPacket, Status, cbTransferred));
+ if (!vboxNetFltWinPtTransferDataCompleteActive(pNetFlt, pPacket, Status))
+ {
+ if (pNetFlt->u.s.WinIf.hMiniport)
+ {
+ NdisMTransferDataComplete(pNetFlt->u.s.WinIf.hMiniport,
+ pPacket,
+ Status,
+ cbTransferred);
+ }
+
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ /* else - all processing is done with vboxNetFltWinPtTransferDataCompleteActive already */
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), pPacket (0x%p), Status (0x%x), cbTransfered (%d)\n", pNetFlt, pPacket, Status, cbTransferred));
+}
+
+static INT vboxNetFltWinRecvPacketPassThru(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket)
+{
+ Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ PNDIS_PACKET pMyPacket;
+ NDIS_STATUS Status = vboxNetFltWinPrepareRecvPacket(pNetFlt, pPacket, &pMyPacket, true);
+ /* the Status holds the current packet status it will be checked for NDIS_STATUS_RESOURCES later
+ * (see below) */
+ Assert(pMyPacket);
+ if (pMyPacket)
+ {
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+ if (Status == NDIS_STATUS_RESOURCES)
+ {
+ NdisDprFreePacket(pMyPacket);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * process the packet receive in a "passthru" mode
+ */
+static NDIS_STATUS vboxNetFltWinRecvPassThru(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket)
+{
+ Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NDIS_STATUS Status;
+ PNDIS_PACKET pMyPacket;
+
+ NdisDprAllocatePacket(&Status, &pMyPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ vboxNetFltWinCopyPacketInfoOnRecv(pMyPacket, pPacket, true /* force NDIS_STATUS_RESOURCES */);
+ Assert(NDIS_GET_PACKET_STATUS(pMyPacket) == NDIS_STATUS_RESOURCES);
+
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+
+ NdisDprFreePacket(pMyPacket);
+ }
+ return Status;
+}
+
+static VOID vboxNetFltWinRecvIndicatePassThru(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE MacReceiveContext,
+ PVOID pHeaderBuffer, UINT cbHeaderBuffer, PVOID pLookAheadBuffer, UINT cbLookAheadBuffer, UINT cbPacket)
+{
+ /* Note: we're using KeGetCurrentProcessorNumber, which is not entirely correct in case
+ * we're running on 64bit win7+, which can handle > 64 CPUs, however since KeGetCurrentProcessorNumber
+ * always returns the number < than the number of CPUs in the first group, we're guaranteed to have CPU index < 64
+ * @todo: use KeGetCurrentProcessorNumberEx for Win7+ 64 and dynamically extended array */
+ ULONG Proc = KeGetCurrentProcessorNumber();
+ Assert(Proc < RT_ELEMENTS(pNetFlt->u.s.WinIf.abIndicateRxComplete));
+ pNetFlt->u.s.WinIf.abIndicateRxComplete[Proc] = TRUE;
+ switch (pNetFlt->u.s.WinIf.enmMedium)
+ {
+ case NdisMedium802_3:
+ case NdisMediumWan:
+ NdisMEthIndicateReceive(pNetFlt->u.s.WinIf.hMiniport,
+ MacReceiveContext,
+ (PCHAR)pHeaderBuffer,
+ cbHeaderBuffer,
+ pLookAheadBuffer,
+ cbLookAheadBuffer,
+ cbPacket);
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+}
+
+/**
+ * process the ProtocolReceive in an "active" mode
+ *
+ * @return NDIS_STATUS_SUCCESS - the packet is processed
+ * NDIS_STATUS_PENDING - the packet is being processed, we are waiting for the ProtocolTransferDataComplete to be called
+ * NDIS_STATUS_NOT_ACCEPTED - the packet is not needed - typically this is because this is a loopback packet
+ * NDIS_STATUS_FAILURE - packet processing failed
+ */
+static NDIS_STATUS vboxNetFltWinPtReceiveActive(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE MacReceiveContext, PVOID pHeaderBuffer, UINT cbHeaderBuffer,
+ PVOID pLookaheadBuffer, UINT cbLookaheadBuffer, UINT cbPacket)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ if (cbHeaderBuffer != VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ {
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+
+#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
+ if (cbPacket == cbLookaheadBuffer)
+ {
+ PINTNETSG pSG;
+ PUCHAR pRcvData;
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ PNDIS_PACKET pLb;
+#endif
+
+ /* allocate SG buffer */
+ Status = vboxNetFltWinAllocSG(cbPacket + cbHeaderBuffer, &pSG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ break;
+ }
+
+ pRcvData = (PUCHAR)pSG->aSegs[0].pv;
+
+ NdisMoveMappedMemory(pRcvData, pHeaderBuffer, cbHeaderBuffer);
+
+ NdisCopyLookaheadData(pRcvData+cbHeaderBuffer,
+ pLookaheadBuffer,
+ cbLookaheadBuffer,
+ pNetFlt->u.s.WinIf.fMacOptions);
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ pLb = vboxNetFltWinLbSearchLoopBackBySG(pNetFlt, pSG, false);
+ if (pLb)
+ {
+#ifndef DEBUG_NETFLT_RECV_NOPACKET
+ /* should not be here */
+ AssertFailed();
+#endif
+ if (!vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ PNDIS_PACKET pMyPacket;
+ pMyPacket = vboxNetFltWinNdisPacketFromSG(pNetFlt, /* PVBOXNETFLTINS */
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ false, /* bool bToWire */
+ false); /* bool bCopyMemory */
+ if (pMyPacket)
+ {
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+ /* dereference the NetFlt here & indicate SUCCESS, which would mean the caller would not do a dereference
+ * the WinIf dereference will be done on packet return */
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ vboxNetFltWinMemFree(pSG);
+ Status = NDIS_STATUS_FAILURE;
+ }
+ }
+ else
+ {
+ vboxNetFltWinMemFree(pSG);
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ }
+ break;
+ }
+#endif
+ VBOXNETFLT_LBVERIFYSG(pNetFlt, pSG);
+
+ /* enqueue SG */
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFlt, pSG, VBOXNETFLT_PACKET_SG))
+ {
+ /* drop it */
+ vboxNetFltWinMemFree(pSG);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ else
+ {
+ PNDIS_PACKET pMyPacket = vboxNetFltWinNdisPacketFromSG(pNetFlt, /* PVBOXNETFLTINS */
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ false, /* bool bToWire */
+ false); /* bool bCopyMemory */
+ Assert(pMyPacket);
+ if (pMyPacket)
+ {
+ NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_SUCCESS);
+
+ DBG_CHECK_PACKET_AND_SG(pMyPacket, pSG);
+
+ LogFlow(("non-ndis packet info, packet created (%p)\n", pMyPacket));
+ NdisMIndicateReceivePacket(pNetFlt->u.s.WinIf.hMiniport, &pMyPacket, 1);
+ }
+ else
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+# else
+ Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, PACKET_SG | PACKET_MINE);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ vboxNetFltWinMemFree(pSG);
+ break;
+ }
+# endif
+#endif
+ }
+ else
+ {
+ PNDIS_PACKET pPacket;
+ PNDIS_BUFFER pTransferBuffer;
+ PNDIS_BUFFER pOrigBuffer;
+ PUCHAR pMemBuf;
+ UINT cbBuf = cbPacket + cbHeaderBuffer;
+ UINT cbTransferred;
+
+ /* allocate NDIS Packet buffer */
+ NdisAllocatePacket(&Status, &pPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ break;
+ }
+
+ VBOXNETFLT_OOB_INIT(pPacket);
+
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ /* set "don't loopback" flags */
+ NdisGetPacketFlags(pPacket) = g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#else
+ NdisGetPacketFlags(pPacket) = 0;
+#endif
+
+ Status = vboxNetFltWinMemAlloc((PVOID*)(&pMemBuf), cbBuf);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ NdisFreePacket(pPacket);
+ break;
+ }
+ NdisAllocateBuffer(&Status, &pTransferBuffer, pNetFlt->u.s.WinIf.hRecvBufferPool, pMemBuf + cbHeaderBuffer, cbPacket);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreePacket(pPacket);
+ vboxNetFltWinMemFree(pMemBuf);
+ break;
+ }
+
+ NdisAllocateBuffer(&Status, &pOrigBuffer, pNetFlt->u.s.WinIf.hRecvBufferPool, pMemBuf, cbBuf);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreeBuffer(pTransferBuffer);
+ NdisFreePacket(pPacket);
+ vboxNetFltWinMemFree(pMemBuf);
+ break;
+ }
+
+ NdisChainBufferAtBack(pPacket, pTransferBuffer);
+
+ NdisMoveMappedMemory(pMemBuf, pHeaderBuffer, cbHeaderBuffer);
+
+ vboxNetFltWinPutPacketToList(&pNetFlt->u.s.WinIf.TransferDataList, pPacket, pOrigBuffer);
+
+#ifdef DEBUG_NETFLT_RECV_TRANSFERDATA
+ if (cbPacket == cbLookaheadBuffer)
+ {
+ NdisCopyLookaheadData(pMemBuf+cbHeaderBuffer,
+ pLookaheadBuffer,
+ cbLookaheadBuffer,
+ pNetFlt->u.s.WinIf.fMacOptions);
+ }
+ else
+#endif
+ {
+ Assert(cbPacket > cbLookaheadBuffer);
+
+ NdisTransferData(&Status, pNetFlt->u.s.WinIf.hBinding, MacReceiveContext,
+ 0, /* ByteOffset */
+ cbPacket, pPacket, &cbTransferred);
+ }
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ vboxNetFltWinPtTransferDataComplete(pNetFlt, pPacket, Status, cbTransferred);
+ }
+ }
+ } while (0);
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinPtReceive(IN NDIS_HANDLE hProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID pHeaderBuffer,
+ IN UINT cbHeaderBuffer,
+ IN PVOID pLookAheadBuffer,
+ IN UINT cbLookAheadBuffer,
+ IN UINT cbPacket)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ PNDIS_PACKET pPacket = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ bool bNetFltActive;
+ bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &bNetFltActive);
+ const bool bPassThruActive = !bNetFltActive;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (fWinIfActive)
+ {
+ do
+ {
+#ifndef DEBUG_NETFLT_RECV_NOPACKET
+ pPacket = NdisGetReceivedPacket(pNetFlt->u.s.WinIf.hBinding, MacReceiveContext);
+ if (pPacket)
+ {
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ PNDIS_PACKET pLb = NULL;
+# else
+ if (vboxNetFltWinIsLoopedBackPacket(pPacket))
+ {
+ AssertFailed();
+ /* nothing else to do here, just return the packet */
+ //NdisReturnPackets(&pPacket, 1);
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+# endif
+
+ if (bNetFltActive)
+ {
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ pLb = vboxNetFltWinLbSearchLoopBack(pNetFlt, pPacket, false);
+ if (!pLb)
+# endif
+ {
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+
+# ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFlt, pPacket, 0))
+ {
+ /* drop it */
+ break;
+ }
+# else
+ Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, PACKET_COPY);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //NdisReturnPackets(&pPacket, 1);
+ fWinIfActive = false;
+ bNetFltActive = false;
+ break;
+ }
+# endif
+ }
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ else if (vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ /* nothing else to do here, just return the packet */
+ //NdisReturnPackets(&pPacket, 1);
+ Status = NDIS_STATUS_NOT_ACCEPTED;
+ break;
+ }
+ /* we are here because this is a looped back packet set not from intnet
+ * we will post it to the upper protocol */
+# endif
+ }
+
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+# ifndef VBOX_LOOPBACK_USEFLAGS
+ Assert(!pLb || !vboxNetFltWinLbIsFromIntNet(pLb));
+# endif
+ Status = vboxNetFltWinRecvPassThru(pNetFlt, pPacket);
+ Assert(Status == STATUS_SUCCESS);
+ /* we are done with packet processing, and we will
+ * not receive packet return event for this packet,
+ * fWinIfActive should be true to ensure we release WinIf*/
+ Assert(fWinIfActive);
+ if (Status == STATUS_SUCCESS)
+ break;
+ }
+ else
+ {
+ /* intnet processing failed - fall back to no-packet mode */
+ Assert(bNetFltActive);
+ Assert(fWinIfActive);
+ }
+
+ }
+#endif /* #ifndef DEBUG_NETFLT_RECV_NOPACKET */
+
+ if (bNetFltActive)
+ {
+ Status = vboxNetFltWinPtReceiveActive(pNetFlt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
+ pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
+ if (NT_SUCCESS(Status))
+ {
+ if (Status != NDIS_STATUS_NOT_ACCEPTED)
+ {
+ fWinIfActive = false;
+ bNetFltActive = false;
+ }
+ else
+ {
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ /* this is a loopback packet, nothing to do here */
+#else
+ AssertFailed();
+ /* should not be here */
+#endif
+ }
+ break;
+ }
+ }
+
+ /* we are done with packet processing, and we will
+ * not receive packet return event for this packet,
+ * fWinIfActive should be true to ensure we release WinIf*/
+ Assert(fWinIfActive);
+
+ vboxNetFltWinRecvIndicatePassThru(pNetFlt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer, pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
+ /* the status could contain an error value here in case the IntNet recv failed,
+ * ensure we return back success status */
+ Status = NDIS_STATUS_SUCCESS;
+
+ } while (0);
+
+ if (bNetFltActive)
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else if (bPassThruActive)
+ {
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+ if (fWinIfActive)
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+
+ return Status;
+
+}
+
+static VOID vboxNetFltWinPtReceiveComplete(NDIS_HANDLE hProtocolBindingContext)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ bool fNetFltActive;
+ bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &fNetFltActive);
+ NDIS_HANDLE hMiniport = pNetFlt->u.s.WinIf.hMiniport;
+ /* Note: we're using KeGetCurrentProcessorNumber, which is not entirely correct in case
+ * we're running on 64bit win7+, which can handle > 64 CPUs, however since KeGetCurrentProcessorNumber
+ * always returns the number < than the number of CPUs in the first group, we're guaranteed to have CPU index < 64
+ * @todo: use KeGetCurrentProcessorNumberEx for Win7+ 64 and dynamically extended array */
+ ULONG iProc = KeGetCurrentProcessorNumber();
+ Assert(iProc < RT_ELEMENTS(pNetFlt->u.s.WinIf.abIndicateRxComplete));
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (hMiniport != NULL && pNetFlt->u.s.WinIf.abIndicateRxComplete[iProc])
+ {
+ switch (pNetFlt->u.s.WinIf.enmMedium)
+ {
+ case NdisMedium802_3:
+ case NdisMediumWan:
+ NdisMEthIndicateReceiveComplete(hMiniport);
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+ }
+
+ pNetFlt->u.s.WinIf.abIndicateRxComplete[iProc] = FALSE;
+
+ if (fWinIfActive)
+ {
+ if (fNetFltActive)
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ else
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p)\n", pNetFlt));
+}
+
+static INT vboxNetFltWinPtReceivePacket(NDIS_HANDLE hProtocolBindingContext, PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+ INT cRefCount = 0;
+ bool bNetFltActive;
+ bool fWinIfActive = vboxNetFltWinReferenceWinIfNetFlt(pNetFlt, &bNetFltActive);
+ const bool bPassThruActive = !bNetFltActive;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p)\n", pNetFlt));
+
+ if (fWinIfActive)
+ {
+ do
+ {
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ if (vboxNetFltWinIsLoopedBackPacket(pPacket))
+ {
+ AssertFailed();
+ Log(("lb_rp"));
+
+ /* nothing else to do here, just return the packet */
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ break;
+ }
+
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+#endif
+
+ if (bNetFltActive)
+ {
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ PNDIS_PACKET pLb = vboxNetFltWinLbSearchLoopBack(pNetFlt, pPacket, false);
+ if (!pLb)
+#endif
+ {
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ NDIS_STATUS fStatus;
+#endif
+ bool fResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES; NOREF(fResources);
+
+ VBOXNETFLT_LBVERIFY(pNetFlt, pPacket);
+#ifdef DEBUG_misha
+ /** @todo remove this assert.
+ * this is a temporary assert for debugging purposes:
+ * we're probably doing something wrong with the packets if the miniport reports NDIS_STATUS_RESOURCES */
+ Assert(!fResources);
+#endif
+
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ if (vboxNetFltWinPostIntnet(pNetFlt, pPacket, 0))
+ {
+ /* drop it */
+ cRefCount = 0;
+ break;
+ }
+
+#else
+ fStatus = vboxNetFltWinQuEnqueuePacket(pNetFlt, pPacket, fResources ? PACKET_COPY : 0);
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ bNetFltActive = false;
+ fWinIfActive = false;
+ if (fResources)
+ {
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ }
+ else
+ cRefCount = 1;
+ break;
+ }
+ else
+ {
+ AssertFailed();
+ }
+#endif
+ }
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ else if (vboxNetFltWinLbIsFromIntNet(pLb))
+ {
+ /* the packet is from intnet, it has already been set to the host,
+ * no need for loopng it back to the host again */
+ /* nothing else to do here, just return the packet */
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ break;
+ }
+#endif
+ }
+
+ cRefCount = vboxNetFltWinRecvPacketPassThru(pNetFlt, pPacket);
+ if (cRefCount)
+ {
+ Assert(cRefCount == 1);
+ fWinIfActive = false;
+ }
+
+ } while (FALSE);
+
+ if (bNetFltActive)
+ {
+ vboxNetFltWinDereferenceNetFlt(pNetFlt);
+ }
+ else if (bPassThruActive)
+ {
+ vboxNetFltWinDereferenceModePassThru(pNetFlt);
+ }
+ if (fWinIfActive)
+ {
+ vboxNetFltWinDereferenceWinIf(pNetFlt);
+ }
+ }
+ else
+ {
+ cRefCount = 0;
+ //NdisReturnPackets(&pPacket, 1);
+ }
+
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), cRefCount (%d)\n", pNetFlt, cRefCount));
+
+ return cRefCount;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinPtCloseInterface(PVBOXNETFLTINS pNetFlt, PNDIS_STATUS pStatus)
+{
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+
+ if (pNetFlt->u.s.WinIf.StateFlags.fInterfaceClosing)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ AssertFailed();
+ return false;
+ }
+ if (pNetFlt->u.s.WinIf.hBinding == NULL)
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ AssertFailed();
+ return false;
+ }
+
+ pNetFlt->u.s.WinIf.StateFlags.fInterfaceClosing = TRUE;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ NdisResetEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent);
+ NdisCloseAdapter(pStatus, pNetFlt->u.s.WinIf.hBinding);
+ if (*pStatus == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pNetFlt->u.s.WinIf.OpenCloseEvent, 0);
+ *pStatus = pNetFlt->u.s.WinIf.OpenCloseStatus;
+ }
+
+ Assert (*pStatus == NDIS_STATUS_SUCCESS);
+
+ pNetFlt->u.s.WinIf.hBinding = NULL;
+
+ return true;
+}
+
+static NDIS_STATUS vboxNetFltWinPtPnPSetPower(PVBOXNETFLTINS pNetFlt, NDIS_DEVICE_POWER_STATE enmPowerState)
+{
+ NDIS_DEVICE_POWER_STATE enmPrevPowerState = vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState);
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+
+ vboxNetFltWinSetPowerState(&pNetFlt->u.s.WinIf.PtState, enmPowerState);
+
+ if (vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState) > NdisDeviceStateD0)
+ {
+ if (enmPrevPowerState == NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = TRUE;
+ }
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ vboxNetFltWinPtRequestsWaitComplete(pNetFlt);
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.MpState);
+ vboxNetFltWinWaitDereference(&pNetFlt->u.s.WinIf.PtState);
+
+ /* check packet pool is empty */
+ UINT cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hSendPacketPool);
+ Assert(cPPUsage == 0);
+ cPPUsage = NdisPacketPoolUsage(pNetFlt->u.s.WinIf.hRecvPacketPool);
+ Assert(cPPUsage == 0);
+ /* for debugging only, ignore the err in release */
+ NOREF(cPPUsage);
+
+ Assert(!pNetFlt->u.s.WinIf.StateFlags.fRequestInfo);
+ }
+ else
+ {
+ if (enmPrevPowerState > NdisDeviceStateD0)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fStandBy = FALSE;
+ }
+
+ if (pNetFlt->u.s.WinIf.StateFlags.fRequestInfo & VBOXNDISREQUEST_QUEUED)
+ {
+ pNetFlt->u.s.WinIf.StateFlags.fRequestInfo = VBOXNDISREQUEST_INPROGRESS;
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ vboxNetFltWinMpRequestPost(pNetFlt);
+ }
+ else
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ }
+ }
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+static NDIS_STATUS vboxNetFltWinPtPnPEvent(IN NDIS_HANDLE hProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
+{
+ PVBOXNETFLTINS pNetFlt = (PVBOXNETFLTINS)hProtocolBindingContext;
+
+ LogFlowFunc(("ENTER: pNetFlt (0x%p), NetEvent (%d)\n", pNetFlt, pNetPnPEvent->NetEvent));
+
+ switch (pNetPnPEvent->NetEvent)
+ {
+ case NetEventSetPower:
+ {
+ NDIS_DEVICE_POWER_STATE enmPowerState = *((PNDIS_DEVICE_POWER_STATE)pNetPnPEvent->Buffer);
+ NDIS_STATUS rcNdis = vboxNetFltWinPtPnPSetPower(pNetFlt, enmPowerState);
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), NetEvent (%d), rcNdis=%#x\n", pNetFlt, pNetPnPEvent->NetEvent, rcNdis));
+ return rcNdis;
+ }
+
+ case NetEventReconfigure:
+ {
+ if (!pNetFlt)
+ {
+ NdisReEnumerateProtocolBindings(g_VBoxNetFltGlobalsWin.Pt.hProtocol);
+ }
+ }
+ /** @todo r=bird: Is the fall thru intentional?? */
+ default:
+ LogFlowFunc(("LEAVE: pNetFlt (0x%p), NetEvent (%d)\n", pNetFlt, pNetPnPEvent->NetEvent));
+ return NDIS_STATUS_SUCCESS;
+ }
+
+}
+
+#ifdef __cplusplus
+# define PTCHARS_40(_p) ((_p).Ndis40Chars)
+#else
+# define PTCHARS_40(_p) (_p)
+#endif
+
+/**
+ * register the protocol edge
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtRegister(PVBOXNETFLTGLOBALS_PT pGlobalsPt, PDRIVER_OBJECT pDriverObject,
+ PUNICODE_STRING pRegistryPathStr)
+{
+ RT_NOREF2(pDriverObject, pRegistryPathStr);
+ NDIS_PROTOCOL_CHARACTERISTICS PtChars;
+ NDIS_STRING NameStr;
+
+ NdisInitUnicodeString(&NameStr, VBOXNETFLT_NAME_PROTOCOL);
+
+ NdisZeroMemory(&PtChars, sizeof (PtChars));
+ PTCHARS_40(PtChars).MajorNdisVersion = VBOXNETFLT_VERSION_PT_NDIS_MAJOR;
+ PTCHARS_40(PtChars).MinorNdisVersion = VBOXNETFLT_VERSION_PT_NDIS_MINOR;
+
+ PTCHARS_40(PtChars).Name = NameStr;
+ PTCHARS_40(PtChars).OpenAdapterCompleteHandler = vboxNetFltWinPtOpenAdapterComplete;
+ PTCHARS_40(PtChars).CloseAdapterCompleteHandler = vboxNetFltWinPtCloseAdapterComplete;
+ PTCHARS_40(PtChars).SendCompleteHandler = vboxNetFltWinPtSendComplete;
+ PTCHARS_40(PtChars).TransferDataCompleteHandler = vboxNetFltWinPtTransferDataComplete;
+ PTCHARS_40(PtChars).ResetCompleteHandler = vboxNetFltWinPtResetComplete;
+ PTCHARS_40(PtChars).RequestCompleteHandler = vboxNetFltWinPtRequestComplete;
+ PTCHARS_40(PtChars).ReceiveHandler = vboxNetFltWinPtReceive;
+ PTCHARS_40(PtChars).ReceiveCompleteHandler = vboxNetFltWinPtReceiveComplete;
+ PTCHARS_40(PtChars).StatusHandler = vboxNetFltWinPtStatus;
+ PTCHARS_40(PtChars).StatusCompleteHandler = vboxNetFltWinPtStatusComplete;
+ PTCHARS_40(PtChars).BindAdapterHandler = vboxNetFltWinPtBindAdapter;
+ PTCHARS_40(PtChars).UnbindAdapterHandler = vboxNetFltWinPtUnbindAdapter;
+ PTCHARS_40(PtChars).UnloadHandler = vboxNetFltWinPtUnloadProtocol;
+#if !defined(DEBUG_NETFLT_RECV)
+ PTCHARS_40(PtChars).ReceivePacketHandler = vboxNetFltWinPtReceivePacket;
+#endif
+ PTCHARS_40(PtChars).PnPEventHandler = vboxNetFltWinPtPnPEvent;
+
+ NDIS_STATUS Status;
+ NdisRegisterProtocol(&Status, &pGlobalsPt->hProtocol, &PtChars, sizeof (PtChars));
+ Assert(Status == STATUS_SUCCESS);
+ return Status;
+}
+
+/**
+ * deregister the protocol edge
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDeregister(PVBOXNETFLTGLOBALS_PT pGlobalsPt)
+{
+ if (!pGlobalsPt->hProtocol)
+ return NDIS_STATUS_SUCCESS;
+
+ NDIS_STATUS Status;
+
+ NdisDeregisterProtocol(&Status, pGlobalsPt->hProtocol);
+ Assert (Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NdisZeroMemory(pGlobalsPt, sizeof (*pGlobalsPt));
+ }
+ return Status;
+}
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h
new file mode 100644
index 00000000..11910676
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltP-win.h
@@ -0,0 +1,52 @@
+/* $Id: VBoxNetFltP-win.h $ */
+/** @file
+ * VBoxNetFltP-win.h - Bridged Networking Driver, Windows Specific Code.
+ * Protocol edge API
+ */
+/*
+ * Copyright (C) 2011-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_VBoxNetFlt_win_drv_VBoxNetFltP_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltP_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#ifdef VBOXNETADP
+# error "No protocol edge"
+#endif
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtRegister(PVBOXNETFLTGLOBALS_PT pGlobalsPt, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDeregister(PVBOXNETFLTGLOBALS_PT pGlobalsPt);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoUnbinding(PVBOXNETFLTINS pNetFlt, bool bOnUnbind);
+DECLHIDDEN(VOID) vboxNetFltWinPtRequestComplete(NDIS_HANDLE hContext, PNDIS_REQUEST pNdisRequest, NDIS_STATUS Status);
+DECLHIDDEN(bool) vboxNetFltWinPtCloseInterface(PVBOXNETFLTINS pNetFlt, PNDIS_STATUS pStatus);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(PVBOXNETFLTINS pThis, PNDIS_STRING pOurDeviceName, PNDIS_STRING pBindToDeviceName);
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltP_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp
new file mode 100644
index 00000000..44c7338c
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.cpp
@@ -0,0 +1,3650 @@
+/* $Id: VBoxNetFltRt-win.cpp $ */
+/** @file
+ * VBoxNetFltRt-win.cpp - Bridged Networking Driver, Windows Specific Runtime Code.
+ */
+
+/*
+ * Copyright (C) 2011-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
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "VBoxNetFltCmn-win.h"
+#include <VBox/intnetinline.h>
+#include <iprt/thread.h>
+
+#include <iprt/nt/tdikrnl.h>
+#include <mstcpip.h>
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/** represents the job element of the job queue
+ * see comments for VBOXNETFLT_JOB_QUEUE */
+typedef struct VBOXNETFLT_JOB
+{
+ /** link in the job queue */
+ LIST_ENTRY ListEntry;
+ /** job function to be executed */
+ PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine;
+ /** parameter to be passed to the job function */
+ PVOID pContext;
+ /** event that will be fired on job completion */
+ KEVENT CompletionEvent;
+ /** true if the job manager should use the completion even for completion indication, false-otherwise*/
+ bool bUseCompletionEvent;
+} VBOXNETFLT_JOB, *PVBOXNETFLT_JOB;
+
+/**
+ * represents the queue of jobs processed by the worker thread
+ *
+ * we use the thread to process tasks which are required to be done at passive level
+ * our callbacks may be called at APC level by IntNet, there are some tasks that we can not create at APC,
+ * e.g. thread creation. This is why we schedule such jobs to the worker thread working at passive level
+ */
+typedef struct VBOXNETFLT_JOB_QUEUE
+{
+ /* jobs */
+ LIST_ENTRY Jobs;
+ /* we are using ExInterlocked..List functions to access the jobs list */
+ KSPIN_LOCK Lock;
+ /** this event is used to initiate a job worker thread kill */
+ KEVENT KillEvent;
+ /** this event is used to notify a worker thread that jobs are added to the queue */
+ KEVENT NotifyEvent;
+ /** worker thread */
+ PKTHREAD pThread;
+} VBOXNETFLT_JOB_QUEUE, *PVBOXNETFLT_JOB_QUEUE;
+
+typedef struct _CREATE_INSTANCE_CONTEXT
+{
+#ifndef VBOXNETADP
+ PNDIS_STRING pOurName;
+ PNDIS_STRING pBindToName;
+#else
+ NDIS_HANDLE hMiniportAdapter;
+ NDIS_HANDLE hWrapperConfigurationContext;
+#endif
+ NDIS_STATUS Status;
+} CREATE_INSTANCE_CONTEXT, *PCREATE_INSTANCE_CONTEXT;
+
+/*contexts used for our jobs */
+/* Attach context */
+typedef struct _ATTACH_INFO
+{
+ PVBOXNETFLTINS pNetFltIf;
+ PCREATE_INSTANCE_CONTEXT pCreateContext;
+ bool fRediscovery;
+ int Status;
+} ATTACH_INFO, *PATTACH_INFO;
+
+/* general worker context */
+typedef struct _WORKER_INFO
+{
+ PVBOXNETFLTINS pNetFltIf;
+ int Status;
+} WORKER_INFO, *PWORKER_INFO;
+
+/* idc initialization */
+typedef struct _INIT_IDC_INFO
+{
+ VBOXNETFLT_JOB Job;
+ bool bInitialized;
+ volatile bool bStop;
+ volatile int rc;
+ KEVENT hCompletionEvent;
+} INIT_IDC_INFO, *PINIT_IDC_INFO;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** global job queue. some operations are required to be done at passive level, e.g. thread creation, adapter bind/unbind initiation,
+ * while IntNet typically calls us APC_LEVEL, so we just create a system thread in our DriverEntry and enqueue the jobs to that thread */
+static VBOXNETFLT_JOB_QUEUE g_VBoxJobQueue;
+volatile static bool g_bVBoxIdcInitialized;
+INIT_IDC_INFO g_VBoxInitIdcInfo;
+
+/**
+ * The (common) global data.
+ */
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+/* win-specific global data */
+VBOXNETFLTGLOBALS_WIN g_VBoxNetFltGlobalsWin = {{{0}}};
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define LIST_ENTRY_2_JOB(pListEntry) \
+ ( (PVBOXNETFLT_JOB)((uint8_t *)(pListEntry) - RT_UOFFSETOF(VBOXNETFLT_JOB, ListEntry)) )
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery);
+static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis);
+static int vboxNetFltWinFiniIdc();
+static void vboxNetFltWinFiniNetFltBase();
+static int vboxNetFltWinInitNetFltBase();
+static int vboxNetFltWinFiniNetFlt();
+static int vboxNetFltWinStartInitIdcProbing();
+static int vboxNetFltWinStopInitIdcProbing();
+
+
+
+/** makes the current thread to sleep for the given number of miliseconds */
+DECLHIDDEN(void) vboxNetFltWinSleep(ULONG milis)
+{
+ RTThreadSleep(milis);
+}
+
+/** wait for the given device to be dereferenced */
+DECLHIDDEN(void) vboxNetFltWinWaitDereference(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+#ifdef DEBUG
+ uint64_t StartNanoTS = RTTimeSystemNanoTS();
+ uint64_t CurNanoTS;
+#endif
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ while (ASMAtomicUoReadU32((volatile uint32_t *)&pState->cReferences))
+ {
+ vboxNetFltWinSleep(2);
+#ifdef DEBUG
+ CurNanoTS = RTTimeSystemNanoTS();
+ if (CurNanoTS - StartNanoTS > 20000000)
+ {
+ LogRel(("device not idle"));
+ AssertFailed();
+// break;
+ }
+#endif
+ }
+}
+
+/**
+ * mem functions
+ */
+/* allocates and zeroes the nonpaged memory of a given size */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMemAlloc(PVOID *ppvMemBuf, UINT cbLength)
+{
+#ifdef DEBUG_NETFLT_USE_EXALLOC
+ *ppvMemBuf = ExAllocatePoolWithTag(NonPagedPool, cbLength, VBOXNETFLT_MEM_TAG);
+ if (*ppvMemBuf)
+ {
+ NdisZeroMemory(*ppvMemBuf, cbLength);
+ return NDIS_STATUS_SUCCESS;
+ }
+ return NDIS_STATUS_FAILURE;
+#else
+ NDIS_STATUS fStatus = NdisAllocateMemoryWithTag(ppvMemBuf, cbLength, VBOXNETFLT_MEM_TAG);
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ NdisZeroMemory(*ppvMemBuf, cbLength);
+ return fStatus;
+#endif
+}
+
+/* frees memory allocated with vboxNetFltWinMemAlloc */
+DECLHIDDEN(void) vboxNetFltWinMemFree(PVOID pvMemBuf)
+{
+#ifdef DEBUG_NETFLT_USE_EXALLOC
+ ExFreePool(pvMemBuf);
+#else
+ NdisFreeMemory(pvMemBuf, 0, 0);
+#endif
+}
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+
+/* initializes packet info pool and allocates the cSize packet infos for the pool */
+static NDIS_STATUS vboxNetFltWinPpAllocatePacketInfoPool(PVBOXNETFLT_PACKET_INFO_POOL pPool, UINT cSize)
+{
+ UINT cbBufSize = sizeof(PACKET_INFO)*cSize;
+ PACKET_INFO * pPacketInfos;
+ NDIS_STATUS fStatus;
+ UINT i;
+
+ Assert(cSize > 0);
+
+ INIT_INTERLOCKED_PACKET_QUEUE(&pPool->Queue);
+
+ fStatus = vboxNetFltWinMemAlloc((PVOID*)&pPacketInfos, cbBufSize);
+
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLTPACKET_INFO pInfo;
+ pPool->pBuffer = pPacketInfos;
+
+ for (i = 0; i < cSize; i++)
+ {
+ pInfo = &pPacketInfos[i];
+ vboxNetFltWinQuEnqueueTail(&pPool->Queue.Queue, pInfo);
+ pInfo->pPool = pPool;
+ }
+ }
+ else
+ {
+ AssertFailed();
+ }
+
+ return fStatus;
+}
+
+/* frees the packet info pool */
+VOID vboxNetFltWinPpFreePacketInfoPool(PVBOXNETFLT_PACKET_INFO_POOL pPool)
+{
+ vboxNetFltWinMemFree(pPool->pBuffer);
+
+ FINI_INTERLOCKED_PACKET_QUEUE(&pPool->Queue)
+}
+
+#endif
+
+/**
+ * copies one string to another. in case the destination string size is not enough to hold the complete source string
+ * does nothing and returns NDIS_STATUS_RESOURCES .
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinCopyString(PNDIS_STRING pDst, PNDIS_STRING pSrc)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ if (pDst != pSrc)
+ {
+ if (pDst->MaximumLength < pSrc->Length)
+ {
+ AssertFailed();
+ Status = NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ pDst->Length = pSrc->Length;
+
+ if (pDst->Buffer != pSrc->Buffer)
+ {
+ NdisMoveMemory(pDst->Buffer, pSrc->Buffer, pSrc->Length);
+ }
+ }
+ }
+ return Status;
+}
+
+/************************************************************************************
+ * PINTNETSG pSG manipulation functions
+ ************************************************************************************/
+
+/* moves the contents of the given NDIS_BUFFER and all other buffers chained to it to the PINTNETSG
+ * the PINTNETSG is expected to contain one segment whose bugger is large enough to maintain
+ * the contents of the given NDIS_BUFFER and all other buffers chained to it */
+static NDIS_STATUS vboxNetFltWinNdisBufferMoveToSG0(PNDIS_BUFFER pBuffer, PINTNETSG pSG)
+{
+ PINTNETSEG paSeg;
+ uint8_t * ptr;
+ PVOID pVirtualAddress;
+ UINT cbCurrentLength;
+ NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
+
+ Assert(pSG->cSegsAlloc == 1);
+
+ paSeg = pSG->aSegs;
+ ptr = (uint8_t*)paSeg->pv;
+ paSeg->cb = 0;
+ paSeg->Phys = NIL_RTHCPHYS;
+ pSG->cbTotal = 0;
+
+ Assert(paSeg->pv);
+
+ while (pBuffer)
+ {
+ NdisQueryBufferSafe(pBuffer, &pVirtualAddress, &cbCurrentLength, NormalPagePriority);
+
+ if (!pVirtualAddress)
+ {
+ fStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pSG->cbTotal += cbCurrentLength;
+ paSeg->cb += cbCurrentLength;
+ NdisMoveMemory(ptr, pVirtualAddress, cbCurrentLength);
+ ptr += cbCurrentLength;
+
+ NdisGetNextBuffer(pBuffer, &pBuffer);
+ }
+
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ pSG->cSegsUsed = 1;
+ Assert(pSG->cbTotal == paSeg->cb);
+ }
+ return fStatus;
+}
+
+/* converts the PNDIS_BUFFER to PINTNETSG by making the PINTNETSG segments to point to the memory buffers the
+ * ndis buffer(s) point to (as opposed to vboxNetFltWinNdisBufferMoveToSG0 which copies the memory from ndis buffers(s) to PINTNETSG) */
+static NDIS_STATUS vboxNetFltWinNdisBuffersToSG(PNDIS_BUFFER pBuffer, PINTNETSG pSG)
+{
+ UINT cSegs = 0;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PVOID pVirtualAddress;
+ UINT cbCurrentLength;
+
+ while (pBuffer)
+ {
+ NdisQueryBufferSafe(pBuffer, &pVirtualAddress, &cbCurrentLength, NormalPagePriority);
+
+ if (!pVirtualAddress)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pSG->cbTotal += cbCurrentLength;
+ pSG->aSegs[cSegs].cb = cbCurrentLength;
+ pSG->aSegs[cSegs].pv = pVirtualAddress;
+ pSG->aSegs[cSegs].Phys = NIL_RTHCPHYS;
+ cSegs++;
+
+ NdisGetNextBuffer(pBuffer, &pBuffer);
+ }
+
+ AssertFatal(cSegs <= pSG->cSegsAlloc);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pSG->cSegsUsed = cSegs;
+ }
+
+ return Status;
+}
+
+static void vboxNetFltWinDeleteSG(PINTNETSG pSG)
+{
+ vboxNetFltWinMemFree(pSG);
+}
+
+static PINTNETSG vboxNetFltWinCreateSG(uint32_t cSegs)
+{
+ PINTNETSG pSG;
+ NTSTATUS Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]));
+ if (Status == STATUS_SUCCESS)
+ {
+ IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
+ return pSG;
+ }
+
+ return NULL;
+}
+
+/************************************************************************************
+ * packet queue functions
+ ************************************************************************************/
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+#if !defined(VBOXNETADP)
+static NDIS_STATUS vboxNetFltWinQuPostPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PINTNETSG pSG, uint32_t fFlags
+# ifdef DEBUG_NETFLT_PACKETS
+ , PNDIS_PACKET pTmpPacket
+# endif
+ )
+{
+ NDIS_STATUS Status;
+ PNDIS_PACKET pMyPacket;
+ bool bSrcHost = fFlags & PACKET_SRC_HOST;
+
+ LogFlow(("posting packet back to driver stack..\n"));
+
+ if (!pPacket)
+ {
+ /* INTNETSG was in the packet queue, create a new NdisPacket from INTNETSG*/
+ pMyPacket = vboxNetFltWinNdisPacketFromSG(pNetFlt,
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ bSrcHost, /* bool bToWire */
+ false); /* bool bCopyMemory */
+
+ Assert(pMyPacket);
+
+ NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_SUCCESS);
+
+ DBG_CHECK_PACKET_AND_SG(pMyPacket, pSG);
+
+#ifdef DEBUG_NETFLT_PACKETS
+ Assert(pTmpPacket);
+
+ DBG_CHECK_PACKET_AND_SG(pTmpPacket, pSG);
+
+ DBG_CHECK_PACKETS(pTmpPacket, pMyPacket);
+#endif
+
+ LogFlow(("non-ndis packet info, packet created (%p)\n", pMyPacket));
+ }
+ else
+ {
+ /* NDIS_PACKET was in the packet queue */
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+
+ if (!(fFlags & PACKET_MINE))
+ {
+ /* the packet is the one that was passed to us in send/receive callback
+ * According to the DDK, we can not post it further,
+ * instead we should allocate our own packet.
+ * So, allocate our own packet (pMyPacket) and copy the packet info there */
+ if (bSrcHost)
+ {
+ Status = vboxNetFltWinPrepareSendPacket(pNetFlt, pPacket, &pMyPacket/*, true*/);
+ LogFlow(("packet from wire, packet created (%p)\n", pMyPacket));
+ }
+ else
+ {
+ Status = vboxNetFltWinPrepareRecvPacket(pNetFlt, pPacket, &pMyPacket, false);
+ LogFlow(("packet from wire, packet created (%p)\n", pMyPacket));
+ }
+ }
+ else
+ {
+ /* the packet enqueued is ours, simply assign pMyPacket and zero pPacket */
+ pMyPacket = pPacket;
+ pPacket = NULL;
+ }
+ Assert(pMyPacket);
+ }
+
+ if (pMyPacket)
+ {
+ /* we have successfully initialized our packet, post it to the host or to the wire */
+ if (bSrcHost)
+ {
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ vboxNetFltWinLbPutSendPacket(pNetFlt, pMyPacket, false /* bFromIntNet */);
+#endif
+ NdisSend(&Status, pNetFlt->u.s.hBinding, pMyPacket);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ /* the status is NOT pending, complete the packet */
+ bool bTmp = vboxNetFltWinLbRemoveSendPacket(pNetFlt, pMyPacket);
+ Assert(bTmp);
+#endif
+ if (pPacket)
+ {
+ LogFlow(("status is not pending, completing packet (%p)\n", pPacket));
+
+ NdisIMCopySendCompletePerPacketInfo (pPacket, pMyPacket);
+
+ NdisFreePacket(pMyPacket);
+ }
+ else
+ {
+ /* should never be here since the PINTNETSG is stored only when the underlying miniport
+ * indicates NDIS_STATUS_RESOURCES, we should never have this when processing
+ * the "from-host" packets */
+ AssertFailed();
+ LogFlow(("status is not pending, freeing myPacket (%p)\n", pMyPacket));
+ vboxNetFltWinFreeSGNdisPacket(pMyPacket, false);
+ }
+ }
+ }
+ else
+ {
+ NdisMIndicateReceivePacket(pNetFlt->u.s.hMiniport, &pMyPacket, 1);
+
+ Status = NDIS_STATUS_PENDING;
+ /* the packet receive completion is always indicated via MiniportReturnPacket */
+ }
+ }
+ else
+ {
+ /*we failed to create our packet */
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+#endif
+
+static bool vboxNetFltWinQuProcessInfo(PVBOXNETFLTINS pNetFltIf, PPACKET_QUEUE_WORKER pWorker, PVOID pvPacket, const UINT fFlags)
+#else
+DECLHIDDEN(bool) vboxNetFltWinPostIntnet(PVBOXNETFLTINS pNetFltIf, PVOID pvPacket, const UINT fFlags)
+#endif
+{
+ PNDIS_PACKET pPacket = NULL;
+ PINTNETSG pSG = NULL;
+ NDIS_STATUS Status;
+#ifndef VBOXNETADP
+ bool bSrcHost;
+ bool bDropIt;
+# ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ bool bPending;
+# endif
+#endif
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ bool bDeleteSG = false;
+#endif
+#ifdef DEBUG_NETFLT_PACKETS
+ /* packet used for matching */
+ PNDIS_PACKET pTmpPacket = NULL;
+#endif
+
+#ifndef VBOXNETADP
+ bSrcHost = (fFlags & VBOXNETFLT_PACKET_SRC_HOST) != 0;
+#endif
+
+ /* we first need to obtain the INTNETSG to be passed to intnet */
+
+ /* the queue may contain two "types" of packets:
+ * the NDIS_PACKET and the INTNETSG.
+ * I.e. on send/receive we typically enqueue the NDIS_PACKET passed to us by ndis,
+ * however in case our ProtocolReceive is called or the packet's status is set to NDIS_STSTUS_RESOURCES
+ * in ProtocolReceivePacket, we must return the packet immediately on ProtocolReceive*** exit
+ * In this case we allocate the INTNETSG, copy the ndis packet data there and enqueue it.
+ * In this case the packet info flags has the VBOXNETFLT_PACKET_SG fag set
+ *
+ * Besides that the NDIS_PACKET contained in the queue could be either the one passed to us in our send/receive callback
+ * or the one created by us. The latter is possible in case our ProtocolReceive callback is called and we call NdisTransferData
+ * in this case we need to allocate the packet the data to be transferred to.
+ * If the enqueued packet is the one allocated by us the VBOXNETFLT_PACKET_MINE flag is set
+ * */
+ if ((fFlags & VBOXNETFLT_PACKET_SG) == 0)
+ {
+ /* we have NDIS_PACKET enqueued, we need to convert it to INTNETSG to be passed to intnet */
+ PNDIS_BUFFER pCurrentBuffer = NULL;
+ UINT cBufferCount;
+ UINT cbPacketLength;
+
+ pPacket = (PNDIS_PACKET)pvPacket;
+
+ LogFlow(("ndis packet info, packet (%p)\n", pPacket));
+
+ LogFlow(("preparing pSG"));
+ NdisQueryPacket(pPacket, NULL, &cBufferCount, &pCurrentBuffer, &cbPacketLength);
+ Assert(cBufferCount);
+
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ pSG = vboxNetFltWinCreateSG(cBufferCount);
+#else
+ /* we can not allocate the INTNETSG on stack since in this case we may get stack overflow
+ * somewhere outside of our driver (3 pages of system thread stack does not seem to be enough)
+ *
+ * since we have a "serialized" packet processing, i.e. all packets are being processed and passed
+ * to intnet by this thread, we just use one previously allocated INTNETSG which is stored in PVBOXNETFLTINS */
+ pSG = pWorker->pSG;
+
+ if (cBufferCount > pSG->cSegsAlloc)
+ {
+ pSG = vboxNetFltWinCreateSG(cBufferCount + 2);
+ if (pSG)
+ {
+ vboxNetFltWinDeleteSG(pWorker->pSG);
+ pWorker->pSG = pSG;
+ }
+ else
+ {
+ LogRel(("Failed to reallocate the pSG\n"));
+ }
+ }
+#endif
+
+ if (pSG)
+ {
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ bDeleteSG = true;
+#endif
+ /* reinitialize */
+ IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, pSG->cSegsAlloc, 0 /*cSegsUsed*/);
+
+ /* convert the ndis buffers to INTNETSG */
+ Status = vboxNetFltWinNdisBuffersToSG(pCurrentBuffer, pSG);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ pSG = NULL;
+ }
+ else
+ {
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+ }
+ }
+ }
+ else
+ {
+ /* we have the INTNETSG enqueued. (see the above comment explaining why/when this may happen)
+ * just use the INTNETSG to pass it to intnet */
+#ifndef VBOXNETADP
+ /* the PINTNETSG is stored only when the underlying miniport
+ * indicates NDIS_STATUS_RESOURCES, we should never have this when processing
+ * the "from-host" packedts */
+ Assert(!bSrcHost);
+#endif
+ pSG = (PINTNETSG)pvPacket;
+
+ LogFlow(("not ndis packet info, pSG (%p)\n", pSG));
+ }
+
+#ifdef DEBUG_NETFLT_PACKETS
+ if (!pPacket && !pTmpPacket)
+ {
+ /* create tmp packet that woud be used for matching */
+ pTmpPacket = vboxNetFltWinNdisPacketFromSG(pNetFltIf,
+ pSG, /* PINTNETSG */
+ pSG, /* PVOID pBufToFree */
+ bSrcHost, /* bool bToWire */
+ true); /* bool bCopyMemory */
+
+ NDIS_SET_PACKET_STATUS(pTmpPacket, NDIS_STATUS_SUCCESS);
+
+ DBG_CHECK_PACKET_AND_SG(pTmpPacket, pSG);
+
+ Assert(pTmpPacket);
+ }
+#endif
+ do
+ {
+#ifndef VBOXNETADP
+ /* the pSG was successfully initialized, post it to the netFlt*/
+ bDropIt = pSG ? pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, NULL /* pvIf */, pSG,
+ bSrcHost ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE
+ )
+ : false;
+#else
+ if (pSG)
+ {
+ pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_HOST);
+ STATISTIC_INCREASE(pNetFltIf->u.s.WinIf.cTxSuccess);
+ }
+ else
+ {
+ STATISTIC_INCREASE(pNetFltIf->u.s.WinIf.cTxError);
+ }
+#endif
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+
+# if !defined(VBOXNETADP)
+ if (!bDropIt)
+ {
+ Status = vboxNetFltWinQuPostPacket(pNetFltIf, pPacket, pSG, fFlags
+# ifdef DEBUG_NETFLT_PACKETS
+ , pTmpPacket
+# endif
+ );
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ /* we will process packet completion in the completion routine */
+ bPending = true;
+ break;
+ }
+ }
+ else
+# endif
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+
+ /* drop it */
+ if (pPacket)
+ {
+ if (!(fFlags & PACKET_MINE))
+ {
+# if !defined(VBOXNETADP)
+ /* complete the packets */
+ if (fFlags & PACKET_SRC_HOST)
+ {
+# endif
+/* NDIS_SET_PACKET_STATUS(pPacket, Status); */
+ NdisMSendComplete(pNetFltIf->u.s.hMiniport, pPacket, Status);
+# if !defined(VBOXNETADP)
+ }
+ else
+ {
+# endif
+# ifndef VBOXNETADP
+ NdisReturnPackets(&pPacket, 1);
+# endif
+# if !defined(VBOXNETADP)
+ }
+# endif
+ }
+ else
+ {
+ Assert(!(fFlags & PACKET_SRC_HOST));
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ }
+ }
+ else
+ {
+ Assert(pSG);
+ vboxNetFltWinMemFree(pSG);
+ }
+# ifndef VBOXNETADP
+ bPending = false;
+# endif
+ } while (0);
+
+#ifdef DEBUG_NETFLT_PACKETS
+ if (pTmpPacket)
+ {
+ vboxNetFltWinFreeSGNdisPacket(pTmpPacket, true);
+ }
+#endif
+
+#ifndef VBOXNETADP
+ return bPending;
+#else
+ return false;
+#endif
+#else /* #ifdef VBOXNETFLT_NO_PACKET_QUEUE */
+ } while (0);
+
+ if (bDeleteSG)
+ vboxNetFltWinMemFree(pSG);
+
+# ifndef VBOXNETADP
+ return bDropIt;
+# else
+ return true;
+# endif
+#endif
+}
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+/*
+ * thread start function for the thread which processes the packets enqueued in our send and receive callbacks called by ndis
+ *
+ * ndis calls us at DISPATCH_LEVEL, while IntNet is using kernel functions which require Irql<DISPATCH_LEVEL
+ * this is why we can not immediately post packets to IntNet from our sen/receive callbacks
+ * instead we put the incoming packets to the queue and maintain the system thread running at passive level
+ * which processes the queue and posts the packets to IntNet, and further to the host or to the wire.
+ */
+static VOID vboxNetFltWinQuPacketQueueWorkerThreadProc(PVBOXNETFLTINS pNetFltIf)
+{
+ bool fResume = true;
+ NTSTATUS fStatus;
+ PPACKET_QUEUE_WORKER pWorker = &pNetFltIf->u.s.PacketQueueWorker;
+
+ PVOID apEvents[] = {
+ (PVOID)&pWorker->KillEvent,
+ (PVOID)&pWorker->NotifyEvent
+ };
+
+ while (fResume)
+ {
+ uint32_t cNumProcessed;
+ uint32_t cNumPostedToHostWire;
+
+ fStatus = KeWaitForMultipleObjects(RT_ELEMENTS(apEvents), apEvents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
+ if (!NT_SUCCESS(fStatus) || fStatus == STATUS_WAIT_0)
+ {
+ /* "kill" event was set
+ * will process queued packets and exit */
+ fResume = false;
+ }
+
+ LogFlow(("processing vboxNetFltWinQuPacketQueueWorkerThreadProc\n"));
+
+ cNumProcessed = 0;
+ cNumPostedToHostWire = 0;
+
+ do
+ {
+ PVBOXNETFLTPACKET_INFO pInfo;
+
+#ifdef DEBUG_NETFLT_PACKETS
+ /* packet used for matching */
+ PNDIS_PACKET pTmpPacket = NULL;
+#endif
+
+ /** @todo FIXME: !!! the better approach for performance would be to dequeue all packets at once
+ * and then go through all dequeued packets
+ * the same should be done for enqueue !!! */
+ pInfo = vboxNetFltWinQuInterlockedDequeueHead(&pWorker->PacketQueue);
+
+ if (!pInfo)
+ {
+ break;
+ }
+
+ LogFlow(("found info (0x%p)\n", pInfo));
+
+ if (vboxNetFltWinQuProcessInfo(pNetFltIf, pWorker, pInfo->pPacket, pInfo->fFlags))
+ {
+ cNumPostedToHostWire++;
+ }
+
+ vboxNetFltWinPpFreePacketInfo(pInfo);
+
+ cNumProcessed++;
+ } while (TRUE);
+
+ if (cNumProcessed)
+ {
+ vboxNetFltWinDecReferenceNetFlt(pNetFltIf, cNumProcessed);
+
+ Assert(cNumProcessed >= cNumPostedToHostWire);
+
+ if (cNumProcessed != cNumPostedToHostWire)
+ {
+ vboxNetFltWinDecReferenceWinIf(pNetFltIf, cNumProcessed - cNumPostedToHostWire);
+ }
+ }
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+#endif
+/**
+ * thread start function for the job processing thread
+ *
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static VOID vboxNetFltWinJobWorkerThreadProc(PVBOXNETFLT_JOB_QUEUE pQueue)
+{
+ bool fResume = true;
+ NTSTATUS Status;
+
+ PVOID apEvents[] = {
+ (PVOID)&pQueue->KillEvent,
+ (PVOID)&pQueue->NotifyEvent,
+ };
+
+ do
+ {
+ Status = KeWaitForMultipleObjects(RT_ELEMENTS(apEvents), apEvents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
+ Assert(NT_SUCCESS(Status));
+ if (!NT_SUCCESS(Status) || Status == STATUS_WAIT_0)
+ {
+ /* will process queued jobs and exit */
+ Assert(Status == STATUS_WAIT_0);
+ fResume = false;
+ }
+
+ do
+ {
+ PLIST_ENTRY pJobEntry = ExInterlockedRemoveHeadList(&pQueue->Jobs, &pQueue->Lock);
+ PVBOXNETFLT_JOB pJob;
+
+ if (!pJobEntry)
+ break;
+
+ pJob = LIST_ENTRY_2_JOB(pJobEntry);
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ pJob->pfnRoutine(pJob->pContext);
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ if (pJob->bUseCompletionEvent)
+ {
+ KeSetEvent(&pJob->CompletionEvent, 1, FALSE);
+ }
+ } while (TRUE);
+ } while (fResume);
+
+ Assert(Status == STATUS_WAIT_0);
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+/**
+ * enqueues the job to the job queue to be processed by the job worker thread
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static VOID vboxNetFltWinJobEnqueueJob(PVBOXNETFLT_JOB_QUEUE pQueue, PVBOXNETFLT_JOB pJob, bool bEnqueueHead)
+{
+ if (bEnqueueHead)
+ {
+ ExInterlockedInsertHeadList(&pQueue->Jobs, &pJob->ListEntry, &pQueue->Lock);
+ }
+ else
+ {
+ ExInterlockedInsertTailList(&pQueue->Jobs, &pJob->ListEntry, &pQueue->Lock);
+ }
+
+ KeSetEvent(&pQueue->NotifyEvent, 1, FALSE);
+}
+
+DECLINLINE(VOID) vboxNetFltWinJobInit(PVBOXNETFLT_JOB pJob, PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext, bool bUseEvent)
+{
+ pJob->pfnRoutine = pfnRoutine;
+ pJob->pContext = pContext;
+ pJob->bUseCompletionEvent = bUseEvent;
+ if (bUseEvent)
+ KeInitializeEvent(&pJob->CompletionEvent, NotificationEvent, FALSE);
+}
+
+/**
+ * enqueues the job to the job queue to be processed by the job worker thread and
+ * blocks until the job is done
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static VOID vboxNetFltWinJobSynchExec(PVBOXNETFLT_JOB_QUEUE pQueue, PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext)
+{
+ VBOXNETFLT_JOB Job;
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ vboxNetFltWinJobInit(&Job, pfnRoutine, pContext, true);
+
+ vboxNetFltWinJobEnqueueJob(pQueue, &Job, false);
+
+ KeWaitForSingleObject(&Job.CompletionEvent, Executive, KernelMode, FALSE, NULL);
+}
+
+/**
+ * enqueues the job to be processed by the job worker thread at passive level and
+ * blocks until the job is done
+ */
+DECLHIDDEN(VOID) vboxNetFltWinJobSynchExecAtPassive(PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext)
+{
+ vboxNetFltWinJobSynchExec(&g_VBoxJobQueue, pfnRoutine, pContext);
+}
+
+/**
+ * helper function used for system thread creation
+ */
+static NTSTATUS vboxNetFltWinQuCreateSystemThread(PKTHREAD *ppThread, PKSTART_ROUTINE pfnStartRoutine, PVOID pvStartContext)
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ HANDLE hThread;
+ NTSTATUS Status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, (PKSTART_ROUTINE)pfnStartRoutine, pvStartContext);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Status = ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*)ppThread, NULL);
+ Assert(Status == STATUS_SUCCESS);
+ ZwClose(hThread);
+ if (Status == STATUS_SUCCESS)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /** @todo how would we fail in this case ?*/
+ }
+ return Status;
+}
+
+/**
+ * initialize the job queue
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static NTSTATUS vboxNetFltWinJobInitQueue(PVBOXNETFLT_JOB_QUEUE pQueue)
+{
+ NTSTATUS fStatus;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ NdisZeroMemory(pQueue, sizeof(VBOXNETFLT_JOB_QUEUE));
+
+ KeInitializeEvent(&pQueue->KillEvent, NotificationEvent, FALSE);
+
+ KeInitializeEvent(&pQueue->NotifyEvent, SynchronizationEvent, FALSE);
+
+ InitializeListHead(&pQueue->Jobs);
+
+ fStatus = vboxNetFltWinQuCreateSystemThread(&pQueue->pThread, (PKSTART_ROUTINE)vboxNetFltWinJobWorkerThreadProc, pQueue);
+ if (fStatus != STATUS_SUCCESS)
+ {
+ pQueue->pThread = NULL;
+ }
+ else
+ {
+ Assert(pQueue->pThread);
+ }
+
+ return fStatus;
+}
+
+/**
+ * deinitialize the job queue
+ * see comments for PVBOXNETFLT_JOB_QUEUE
+ */
+static void vboxNetFltWinJobFiniQueue(PVBOXNETFLT_JOB_QUEUE pQueue)
+{
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ if (pQueue->pThread)
+ {
+ KeSetEvent(&pQueue->KillEvent, 0, FALSE);
+
+ KeWaitForSingleObject(pQueue->pThread, Executive,
+ KernelMode, FALSE, NULL);
+ }
+}
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+
+/**
+ * initializes the packet queue
+ * */
+DECLHIDDEN(NTSTATUS) vboxNetFltWinQuInitPacketQueue(PVBOXNETFLTINS pInstance)
+{
+ NTSTATUS Status;
+ PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
+
+ AssertFatal(!pWorker->pSG);
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ KeInitializeEvent(&pWorker->KillEvent, NotificationEvent, FALSE);
+
+ KeInitializeEvent(&pWorker->NotifyEvent, SynchronizationEvent, FALSE);
+
+ INIT_INTERLOCKED_PACKET_QUEUE(&pWorker->PacketQueue);
+
+ do
+ {
+ Status = vboxNetFltWinPpAllocatePacketInfoPool(&pWorker->PacketInfoPool, VBOXNETFLT_PACKET_INFO_POOL_SIZE);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pWorker->pSG = vboxNetFltWinCreateSG(PACKET_QUEUE_SG_SEGS_ALLOC);
+ if (!pWorker->pSG)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ Status = vboxNetFltWinQuCreateSystemThread(&pWorker->pThread, (PKSTART_ROUTINE)vboxNetFltWinQuPacketQueueWorkerThreadProc, pInstance);
+ if (Status != STATUS_SUCCESS)
+ {
+ vboxNetFltWinPpFreePacketInfoPool(&pWorker->PacketInfoPool);
+ vboxNetFltWinMemFree(pWorker->pSG);
+ pWorker->pSG = NULL;
+ break;
+ }
+ }
+
+ } while (0);
+
+ return Status;
+}
+
+/*
+ * deletes the packet queue
+ */
+DECLHIDDEN(void) vboxNetFltWinQuFiniPacketQueue(PVBOXNETFLTINS pInstance)
+{
+ PINTNETSG pSG;
+ PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ /* using the pPacketQueueSG as an indicator that the packet queue is initialized */
+ RTSpinlockAcquire((pInstance)->hSpinlock);
+ if (pWorker->pSG)
+ {
+ pSG = pWorker->pSG;
+ pWorker->pSG = NULL;
+ RTSpinlockRelease((pInstance)->hSpinlock);
+ KeSetEvent(&pWorker->KillEvent, 0, FALSE);
+
+ KeWaitForSingleObject(pWorker->pThread, Executive,
+ KernelMode, FALSE, NULL);
+
+ vboxNetFltWinPpFreePacketInfoPool(&pWorker->PacketInfoPool);
+
+ vboxNetFltWinDeleteSG(pSG);
+
+ FINI_INTERLOCKED_PACKET_QUEUE(&pWorker->PacketQueue);
+ }
+ else
+ {
+ RTSpinlockRelease((pInstance)->hSpinlock);
+ }
+}
+
+#endif
+
+/*
+ * creates the INTNETSG containing one segment pointing to the buffer of size cbBufSize
+ * the INTNETSG created should be cleaned with vboxNetFltWinMemFree
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinAllocSG(UINT cbPacket, PINTNETSG *ppSG)
+{
+ NDIS_STATUS Status;
+ PINTNETSG pSG;
+
+ /* allocation:
+ * 1. SG_PACKET - with one aSegs pointing to
+ * 2. buffer of cbPacket containing the entire packet */
+ AssertCompileSizeAlignment(INTNETSG, sizeof(PVOID));
+ Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, cbPacket + sizeof(INTNETSG));
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ IntNetSgInitTemp(pSG, pSG + 1, cbPacket);
+ LogFlow(("pSG created (%p)\n", pSG));
+ *ppSG = pSG;
+ }
+ return Status;
+}
+
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+/**
+ * put the packet info to the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuEnqueueInfo(PVBOXNETFLTPACKET_QUEUE_WORKER pWorker, PVBOXNETFLTPACKET_INFO pInfo)
+{
+ vboxNetFltWinQuInterlockedEnqueueTail(&pWorker->PacketQueue, pInfo);
+
+ KeSetEvent(&pWorker->NotifyEvent, IO_NETWORK_INCREMENT, FALSE);
+}
+
+/**
+ * puts the packet to the queue
+ *
+ * @return NDIST_STATUS_SUCCESS iff the packet was enqueued successfully
+ * and error status otherwise.
+ * NOTE: that the success status does NOT mean that the packet processing is completed, but only that it was enqueued successfully
+ * the packet can be returned to the caller protocol/moniport only in case the bReleasePacket was set to true (in this case the copy of the packet was enqueued)
+ * or if vboxNetFltWinQuEnqueuePacket failed, i.e. the packet was NOT enqueued
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQuEnqueuePacket(PVBOXNETFLTINS pInstance, PVOID pPacket, const UINT fPacketFlags)
+{
+ PVBOXNETFLT_PACKET_INFO pInfo;
+ PVBOXNETFLT_PACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
+ NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ if (fPacketFlags & PACKET_COPY)
+ {
+ PNDIS_BUFFER pBuffer = NULL;
+ UINT cBufferCount;
+ UINT uBytesCopied = 0;
+ UINT cbPacketLength;
+ PINTNETSG pSG;
+
+ /* the packet is Ndis packet */
+ Assert(!(fPacketFlags & PACKET_SG));
+ Assert(!(fPacketFlags & PACKET_MINE));
+
+ NdisQueryPacket((PNDIS_PACKET)pPacket,
+ NULL,
+ &cBufferCount,
+ &pBuffer,
+ &cbPacketLength);
+
+
+ Assert(cBufferCount);
+
+ fStatus = vboxNetFltWinAllocSG(cbPacketLength, &pSG);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ break;
+ }
+
+ pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
+
+ if (!pInfo)
+ {
+ AssertFailed();
+ /** @todo what status to set? */
+ fStatus = NDIS_STATUS_FAILURE;
+ vboxNetFltWinMemFree(pSG);
+ break;
+ }
+
+ Assert(pInfo->pPool);
+
+ /* the packet we are queueing is SG, add PACKET_SG to flags */
+ SET_FLAGS_TO_INFO(pInfo, fPacketFlags | PACKET_SG);
+ SET_PACKET_TO_INFO(pInfo, pSG);
+
+ fStatus = vboxNetFltWinNdisBufferMoveToSG0(pBuffer, pSG);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ AssertFailed();
+ vboxNetFltWinPpFreePacketInfo(pInfo);
+ vboxNetFltWinMemFree(pSG);
+ break;
+ }
+
+ DBG_CHECK_PACKET_AND_SG((PNDIS_PACKET)pPacket, pSG);
+ }
+ else
+ {
+ pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
+
+ if (!pInfo)
+ {
+ AssertFailed();
+ /** @todo what status to set? */
+ fStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ Assert(pInfo->pPool);
+
+ SET_FLAGS_TO_INFO(pInfo, fPacketFlags);
+ SET_PACKET_TO_INFO(pInfo, pPacket);
+ }
+
+ vboxNetFltWinQuEnqueueInfo(pWorker, pInfo);
+
+ } while (0);
+
+ return fStatus;
+}
+#endif
+
+
+/*
+ * netflt
+ */
+#ifndef VBOXNETADP
+static NDIS_STATUS vboxNetFltWinSynchNdisRequest(PVBOXNETFLTINS pNetFlt, PNDIS_REQUEST pRequest)
+{
+ int rc;
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ /* 1. serialize */
+ rc = RTSemFastMutexRequest(pNetFlt->u.s.WinIf.hSynchRequestMutex); AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ NDIS_STATUS fRequestStatus = NDIS_STATUS_SUCCESS;
+
+ /* 2. set pNetFlt->u.s.pSynchRequest */
+ Assert(!pNetFlt->u.s.WinIf.pSynchRequest);
+ pNetFlt->u.s.WinIf.pSynchRequest = pRequest;
+
+ /* 3. call NdisRequest */
+ NdisRequest(&fRequestStatus, pNetFlt->u.s.WinIf.hBinding, pRequest);
+
+ if (fRequestStatus == NDIS_STATUS_PENDING)
+ {
+ /* 3.1 if pending wait and assign the resulting status */
+ KeWaitForSingleObject(&pNetFlt->u.s.WinIf.hSynchCompletionEvent, Executive,
+ KernelMode, FALSE, NULL);
+
+ fRequestStatus = pNetFlt->u.s.WinIf.SynchCompletionStatus;
+ }
+
+ /* 4. clear the pNetFlt->u.s.pSynchRequest */
+ pNetFlt->u.s.WinIf.pSynchRequest = NULL;
+
+ RTSemFastMutexRelease(pNetFlt->u.s.WinIf.hSynchRequestMutex); AssertRC(rc);
+ return fRequestStatus;
+ }
+ return NDIS_STATUS_FAILURE;
+}
+
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinGetMacAddress(PVBOXNETFLTINS pNetFlt, PRTMAC pMac)
+{
+ NDIS_REQUEST request;
+ NDIS_STATUS status;
+ request.RequestType = NdisRequestQueryInformation;
+ request.DATA.QUERY_INFORMATION.InformationBuffer = pMac;
+ request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(RTMAC);
+ request.DATA.QUERY_INFORMATION.Oid = OID_802_3_CURRENT_ADDRESS;
+ status = vboxNetFltWinSynchNdisRequest(pNetFlt, &request);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ }
+
+ return status;
+
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PVBOXNETFLTINS pNetFlt, NDIS_PHYSICAL_MEDIUM * pMedium)
+{
+ NDIS_REQUEST Request;
+ NDIS_STATUS Status;
+ Request.RequestType = NdisRequestQueryInformation;
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = pMedium;
+ Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(NDIS_PHYSICAL_MEDIUM);
+ Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_PHYSICAL_MEDIUM;
+ Status = vboxNetFltWinSynchNdisRequest(pNetFlt, &Request);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (Status == NDIS_STATUS_NOT_SUPPORTED || Status == NDIS_STATUS_NOT_RECOGNIZED || Status == NDIS_STATUS_INVALID_OID)
+ {
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ LogRel(("OID_GEN_PHYSICAL_MEDIUM failed: Status (0x%x)", Status));
+ AssertFailed();
+ }
+ }
+ return Status;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinIsPromiscuous(PVBOXNETFLTINS pNetFlt)
+{
+ /** @todo r=bird: This is too slow and is probably returning the wrong
+ * information. What we're interested in is whether someone besides us
+ * has put the interface into promiscuous mode. */
+ NDIS_REQUEST request;
+ NDIS_STATUS status;
+ ULONG filter;
+ Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt));
+ request.RequestType = NdisRequestQueryInformation;
+ request.DATA.QUERY_INFORMATION.InformationBuffer = &filter;
+ request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(filter);
+ request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ status = vboxNetFltWinSynchNdisRequest(pNetFlt, &request);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ return false;
+ }
+ return (filter & NDIS_PACKET_TYPE_PROMISCUOUS) != 0;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinSetPromiscuous(PVBOXNETFLTINS pNetFlt, bool bYes)
+{
+/** @todo Need to report changes to the switch via:
+ * pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, fPromisc);
+ */
+ Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt));
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pNetFlt))
+ {
+ NDIS_REQUEST Request;
+ NDIS_STATUS fStatus;
+ ULONG fFilter;
+ ULONG fExpectedFilter;
+ ULONG fOurFilter;
+ Request.RequestType = NdisRequestQueryInformation;
+ Request.DATA.QUERY_INFORMATION.InformationBuffer = &fFilter;
+ Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(fFilter);
+ Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ fStatus = vboxNetFltWinSynchNdisRequest(pNetFlt, &Request);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ return fStatus;
+ }
+
+ if (!pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized)
+ {
+ /* the cache was not initialized yet, initiate it with the current filter value */
+ pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = fFilter;
+ pNetFlt->u.s.WinIf.StateFlags.fUpperProtSetFilterInitialized = TRUE;
+ }
+
+
+ if (bYes)
+ {
+ fExpectedFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
+ fOurFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+ else
+ {
+ fExpectedFilter = pNetFlt->u.s.WinIf.fUpperProtocolSetFilter;
+ fOurFilter = 0;
+ }
+
+ if (fExpectedFilter != fFilter)
+ {
+ Request.RequestType = NdisRequestSetInformation;
+ Request.DATA.SET_INFORMATION.InformationBuffer = &fExpectedFilter;
+ Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(fExpectedFilter);
+ Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ fStatus = vboxNetFltWinSynchNdisRequest(pNetFlt, &Request);
+ if (fStatus != NDIS_STATUS_SUCCESS)
+ {
+ /** @todo */
+ AssertFailed();
+ return fStatus;
+ }
+ }
+ pNetFlt->u.s.WinIf.fOurSetFilter = fOurFilter;
+ return fStatus;
+ }
+ return NDIS_STATUS_NOT_SUPPORTED;
+}
+
+#else /* VBOXNETADP */
+
+/**
+ * Generates a new unique MAC address based on our vendor ID
+ */
+DECLHIDDEN(void) vboxNetFltWinGenerateMACAddress(RTMAC *pMac)
+{
+ /* temporary use a time info */
+ uint64_t NanoTS = RTTimeSystemNanoTS();
+ pMac->au8[0] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 16) & 0xff);
+ pMac->au8[1] = (uint8_t)((VBOXNETADP_VENDOR_ID >> 8) & 0xff);
+ pMac->au8[2] = (uint8_t)(VBOXNETADP_VENDOR_ID & 0xff);
+ pMac->au8[3] = (uint8_t)(NanoTS & 0xff0000);
+ pMac->au16[2] = (uint16_t)(NanoTS & 0xffff);
+}
+
+DECLHIDDEN(int) vboxNetFltWinMAC2NdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
+{
+ static const char s_achDigits[17] = "0123456789abcdef";
+ PWSTR pString;
+
+ /* validate parameters */
+ AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
+ AssertReturn(pNdisString->MaximumLength >= 13*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
+
+ pString = pNdisString->Buffer;
+
+ for (int i = 0; i < 6; i++)
+ {
+ uint8_t u8 = pMac->au8[i];
+ pString[0] = s_achDigits[(u8 >> 4) & 0xf];
+ pString[1] = s_achDigits[(u8/*>>0*/)& 0xf];
+ pString += 2;
+ }
+
+ pNdisString->Length = 12*sizeof(pNdisString->Buffer[0]);
+
+ *pString = L'\0';
+
+ return VINF_SUCCESS;
+}
+
+static int vboxNetFltWinWchar2Byte(WCHAR c, uint8_t *pb)
+{
+ if (c >= L'A' && c <= L'F')
+ *pb = (c - L'A') + 10;
+ else if (c >= L'a' && c <= L'f')
+ *pb = (c - L'a') + 10;
+ else if (c >= L'0' && c <= L'9')
+ *pb = (c - L'0');
+ else
+ return VERR_INVALID_PARAMETER;
+ return VINF_SUCCESS;
+}
+
+DECLHIDDEN(int) vboxNetFltWinMACFromNdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
+{
+
+ /* validate parameters */
+ AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
+ AssertReturn(pNdisString->Length >= 12*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
+
+ int rc = VINF_SUCCESS;
+ PWSTR pString = pNdisString->Buffer;
+ for (int i = 0; i < 6; i++)
+ {
+ uint8_t v1, v2;
+ rc = vboxNetFltWinWchar2Byte(pString[0], &v1);
+ if (RT_FAILURE(rc))
+ break;
+
+ rc = vboxNetFltWinWchar2Byte(pString[1], &v2);
+ if (RT_FAILURE(rc))
+ break;
+
+ pMac->au8[i] = (v1 << 4) | v2;
+
+ pString += 2;
+ }
+
+ return rc;
+}
+
+#endif /* VBOXNETADP */
+
+/**
+ * creates a NDIS_PACKET from the PINTNETSG
+ */
+DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PVBOXNETFLTINS pNetFlt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory)
+{
+ NDIS_STATUS fStatus;
+ PNDIS_PACKET pPacket;
+
+ Assert(pSG->aSegs[0].pv);
+ Assert(pSG->cbTotal >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+
+/** @todo Hrmpf, how can we fix this assumption? I fear this'll cause data
+ * corruption and maybe even BSODs ... */
+ AssertReturn(pSG->cSegsUsed == 1 || bCopyMemory, NULL);
+
+#ifdef VBOXNETADP
+ NdisAllocatePacket(&fStatus, &pPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+#else
+ NdisAllocatePacket(&fStatus, &pPacket, bToWire ? pNetFlt->u.s.WinIf.hSendPacketPool : pNetFlt->u.s.WinIf.hRecvPacketPool);
+#endif
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ PNDIS_BUFFER pBuffer;
+ PVOID pvMemBuf;
+
+ /** @todo generally we do not always need to zero-initialize the complete OOB data here, reinitialize only when/what we need,
+ * however we DO need to reset the status for the packets we indicate via NdisMIndicateReceivePacket to avoid packet loss
+ * in case the status contains NDIS_STATUS_RESOURCES */
+ VBOXNETFLT_OOB_INIT(pPacket);
+
+ if (bCopyMemory)
+ {
+ fStatus = vboxNetFltWinMemAlloc(&pvMemBuf, pSG->cbTotal);
+ Assert(fStatus == NDIS_STATUS_SUCCESS);
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ IntNetSgRead(pSG, pvMemBuf);
+ }
+ else
+ {
+ pvMemBuf = pSG->aSegs[0].pv;
+ }
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+#ifdef VBOXNETADP
+ NdisAllocateBuffer(&fStatus, &pBuffer,
+ pNetFlt->u.s.WinIf.hRecvBufferPool,
+ pvMemBuf,
+ pSG->cbTotal);
+#else
+ NdisAllocateBuffer(&fStatus, &pBuffer,
+ bToWire ? pNetFlt->u.s.WinIf.hSendBufferPool : pNetFlt->u.s.WinIf.hRecvBufferPool,
+ pvMemBuf,
+ pSG->cbTotal);
+#endif
+
+ if (fStatus == NDIS_STATUS_SUCCESS)
+ {
+ NdisChainBufferAtBack(pPacket, pBuffer);
+
+ if (bToWire)
+ {
+ PVBOXNETFLT_PKTRSVD_PT pSendInfo = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ pSendInfo->pOrigPacket = NULL;
+ pSendInfo->pBufToFree = pBufToFree;
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ /* set "don't loopback" flags */
+ NdisGetPacketFlags(pPacket) = g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#else
+ NdisGetPacketFlags(pPacket) = 0;
+#endif
+ }
+ else
+ {
+ PVBOXNETFLT_PKTRSVD_MP pRecvInfo = (PVBOXNETFLT_PKTRSVD_MP)pPacket->MiniportReserved;
+ pRecvInfo->pOrigPacket = NULL;
+ pRecvInfo->pBufToFree = pBufToFree;
+
+ /* we must set the header size on receive */
+ NDIS_SET_PACKET_HEADER_SIZE(pPacket, VBOXNETFLT_PACKET_ETHEADER_SIZE);
+ /* NdisAllocatePacket zero-initializes the OOB data,
+ * but keeps the packet flags, clean them here */
+ NdisGetPacketFlags(pPacket) = 0;
+ }
+ /** @todo set out of bound data */
+ }
+ else
+ {
+ AssertFailed();
+ if (bCopyMemory)
+ {
+ vboxNetFltWinMemFree(pvMemBuf);
+ }
+ NdisFreePacket(pPacket);
+ pPacket = NULL;
+ }
+ }
+ else
+ {
+ AssertFailed();
+ NdisFreePacket(pPacket);
+ pPacket = NULL;
+ }
+ }
+ else
+ {
+ pPacket = NULL;
+ }
+
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+
+ return pPacket;
+}
+
+/*
+ * frees NDIS_PACKET created with vboxNetFltWinNdisPacketFromSG
+ */
+DECLHIDDEN(void) vboxNetFltWinFreeSGNdisPacket(PNDIS_PACKET pPacket, bool bFreeMem)
+{
+ UINT cBufCount;
+ PNDIS_BUFFER pFirstBuffer;
+ UINT uTotalPacketLength;
+ PNDIS_BUFFER pBuffer;
+
+ NdisQueryPacket(pPacket, NULL, &cBufCount, &pFirstBuffer, &uTotalPacketLength);
+
+ Assert(cBufCount == 1);
+
+ do
+ {
+ NdisUnchainBufferAtBack(pPacket, &pBuffer);
+ if (pBuffer != NULL)
+ {
+ PVOID pvMemBuf;
+ UINT cbLength;
+
+ NdisQueryBufferSafe(pBuffer, &pvMemBuf, &cbLength, NormalPagePriority);
+ NdisFreeBuffer(pBuffer);
+ if (bFreeMem)
+ {
+ vboxNetFltWinMemFree(pvMemBuf);
+ }
+ }
+ else
+ {
+ break;
+ }
+ } while (true);
+
+ NdisFreePacket(pPacket);
+}
+
+#if !defined(VBOXNETADP)
+static void vboxNetFltWinAssociateMiniportProtocol(PVBOXNETFLTGLOBALS_WIN pGlobalsWin)
+{
+ NdisIMAssociateMiniport(pGlobalsWin->Mp.hMiniport, pGlobalsWin->Pt.hProtocol);
+}
+#endif
+
+/*
+ * NetFlt driver unload function
+ */
+DECLHIDDEN(VOID) vboxNetFltWinUnload(IN PDRIVER_OBJECT DriverObject)
+{
+ int rc;
+ UNREFERENCED_PARAMETER(DriverObject);
+
+ LogFlowFunc(("ENTER: DO (0x%x)\n", DriverObject));
+
+ rc = vboxNetFltWinFiniIdc();
+ if (RT_FAILURE(rc))
+ {
+ /** @todo we can not prevent driver unload here */
+ AssertFailed();
+
+ LogFlowFunc(("vboxNetFltWinFiniIdc - failed, busy.\n"));
+ }
+
+ vboxNetFltWinJobFiniQueue(&g_VBoxJobQueue);
+#ifndef VBOXNETADP
+ vboxNetFltWinPtDeregister(&g_VBoxNetFltGlobalsWin.Pt);
+#endif
+
+ vboxNetFltWinMpDeregister(&g_VBoxNetFltGlobalsWin.Mp);
+
+#ifndef VBOXNETADP
+ NdisFreeSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+#endif /* VBOXNETADP */
+
+ LogFlow(("LEAVE: DO (0x%x)\n", DriverObject));
+
+ vboxNetFltWinFiniNetFltBase();
+ /* don't use logging or any RT after de-init */
+}
+
+RT_C_DECLS_BEGIN
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
+
+RT_C_DECLS_END
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ int rc;
+
+ /* the idc registration is initiated via IOCTL since our driver
+ * can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
+ rc = vboxNetFltWinInitNetFltBase();
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ Status = vboxNetFltWinJobInitQueue(&g_VBoxJobQueue);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ ULONG MjVersion;
+ ULONG MnVersion;
+
+ /* note: we do it after we initialize the Job Queue */
+ vboxNetFltWinStartInitIdcProbing();
+
+ NdisZeroMemory(&g_VBoxNetFltGlobalsWin, sizeof (g_VBoxNetFltGlobalsWin));
+ KeInitializeEvent(&g_VBoxNetFltGlobalsWin.SynchEvent, SynchronizationEvent, TRUE /* signalled*/);
+
+ PsGetVersion(&MjVersion, &MnVersion,
+ NULL, /* PULONG BuildNumber OPTIONAL */
+ NULL /* PUNICODE_STRING CSDVersion OPTIONAL */
+ );
+
+ g_VBoxNetFltGlobalsWin.fPacketDontLoopBack = NDIS_FLAGS_DONT_LOOPBACK;
+
+ if (MjVersion == 5 && MnVersion == 0)
+ {
+ /* this is Win2k, we don't support it actually, but just in case */
+ g_VBoxNetFltGlobalsWin.fPacketDontLoopBack |= NDIS_FLAGS_SKIP_LOOPBACK_W2K;
+ }
+
+ g_VBoxNetFltGlobalsWin.fPacketIsLoopedBack = NDIS_FLAGS_IS_LOOPBACK_PACKET;
+
+#ifndef VBOXNETADP
+ RTListInit(&g_VBoxNetFltGlobalsWin.listFilters);
+ NdisAllocateSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+#endif
+
+ Status = vboxNetFltWinMpRegister(&g_VBoxNetFltGlobalsWin.Mp, DriverObject, RegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtRegister(&g_VBoxNetFltGlobalsWin.Pt, DriverObject, RegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+#endif
+ {
+#ifndef VBOXNETADP
+ vboxNetFltWinAssociateMiniportProtocol(&g_VBoxNetFltGlobalsWin);
+#endif
+ return STATUS_SUCCESS;
+
+//#ifndef VBOXNETADP
+// vboxNetFltWinPtDeregister(&g_VBoxNetFltGlobalsWin.Pt);
+//#endif
+ }
+#ifndef VBOXNETADP /* unreachable for VBOXNETADP because of the above return */
+ vboxNetFltWinMpDeregister(&g_VBoxNetFltGlobalsWin.Mp);
+# ifndef VBOXNETADP
+ NdisFreeSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+# endif
+#endif
+ }
+ vboxNetFltWinJobFiniQueue(&g_VBoxJobQueue);
+ }
+ vboxNetFltWinFiniNetFlt();
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+
+#ifndef VBOXNETADP
+/**
+ * creates and initializes the packet to be sent to the underlying miniport given a packet posted to our miniport edge
+ * according to DDK docs we must create our own packet rather than posting the one passed to us
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket)
+{
+ NDIS_STATUS Status;
+
+ NdisAllocatePacket(&Status, ppMyPacket, pNetFlt->u.s.WinIf.hSendPacketPool);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLT_PKTRSVD_PT pSendInfo = (PVBOXNETFLT_PKTRSVD_PT)((*ppMyPacket)->ProtocolReserved);
+ pSendInfo->pOrigPacket = pPacket;
+ pSendInfo->pBufToFree = NULL;
+ /* the rest will be filled on send */
+
+ vboxNetFltWinCopyPacketInfoOnSend(*ppMyPacket, pPacket);
+
+#ifdef VBOX_LOOPBACK_USEFLAGS
+ NdisGetPacketFlags(*ppMyPacket) |= g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#endif
+ }
+ else
+ {
+ *ppMyPacket = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ * creates and initializes the packet to be sent to the upperlying protocol given a packet indicated to our protocol edge
+ * according to DDK docs we must create our own packet rather than posting the one passed to us
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareRecvPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket, bool bDpr)
+{
+ NDIS_STATUS Status;
+
+ if (bDpr)
+ {
+ Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+ NdisDprAllocatePacket(&Status, ppMyPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ }
+ else
+ {
+ NdisAllocatePacket(&Status, ppMyPacket, pNetFlt->u.s.WinIf.hRecvPacketPool);
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PVBOXNETFLT_PKTRSVD_MP pRecvInfo = (PVBOXNETFLT_PKTRSVD_MP)((*ppMyPacket)->MiniportReserved);
+ pRecvInfo->pOrigPacket = pPacket;
+ pRecvInfo->pBufToFree = NULL;
+
+ Status = vboxNetFltWinCopyPacketInfoOnRecv(*ppMyPacket, pPacket, false);
+ }
+ else
+ {
+ *ppMyPacket = NULL;
+ }
+ return Status;
+}
+#endif
+/**
+ * initializes the VBOXNETFLTINS (our context structure) and binds to the given adapter
+ */
+#if defined(VBOXNETADP)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext)
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName)
+#endif
+{
+ NDIS_STATUS Status;
+ do
+ {
+ ANSI_STRING AnsiString;
+ int rc;
+ PVBOXNETFLTINS pInstance;
+ USHORT cbAnsiName = pBindToMiniportName->Length;/* the length is is bytes ; *2 ;RtlUnicodeStringToAnsiSize(pBindToMiniportName)*/
+ CREATE_INSTANCE_CONTEXT Context;
+
+# ifndef VBOXNETADP
+ Context.pOurName = pOurMiniportName;
+ Context.pBindToName = pBindToMiniportName;
+# else
+ Context.hMiniportAdapter = hMiniportAdapter;
+ Context.hWrapperConfigurationContext = hWrapperConfigurationContext;
+# endif
+ Context.Status = NDIS_STATUS_SUCCESS;
+
+ AnsiString.Buffer = 0; /* will be allocated by RtlUnicodeStringToAnsiString */
+ AnsiString.Length = 0;
+ AnsiString.MaximumLength = cbAnsiName;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ Status = RtlUnicodeStringToAnsiString(&AnsiString, pBindToMiniportName, true);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ rc = vboxNetFltSearchCreateInstance(&g_VBoxNetFltGlobals, AnsiString.Buffer, &pInstance, &Context);
+ RtlFreeAnsiString(&AnsiString);
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ Assert(pInstance);
+
+ if (rc == VINF_ALREADY_INITIALIZED)
+ {
+ /* the case when our adapter was unbound while IntNet was connected to it */
+ /* the instance remains valid until IntNet disconnects from it, we simply search and re-use it*/
+ rc = vboxNetFltWinAttachToInterface(pInstance, &Context, true);
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
+ /* release netflt */
+ vboxNetFltRelease(pInstance, false);
+
+ break;
+ }
+ }
+
+ *ppNetFlt = pInstance;
+
+ } while (FALSE);
+
+ return Status;
+}
+/*
+ * deinitializes the VBOXNETFLTWIN
+ */
+DECLHIDDEN(VOID) vboxNetFltWinPtFiniWinIf(PVBOXNETFLTWIN pWinIf)
+{
+#ifndef VBOXNETADP
+ int rc;
+#endif
+
+ LogFlowFunc(("ENTER: pWinIf 0x%p\n", pWinIf));
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+#ifndef VBOXNETADP
+ if (pWinIf->MpDeviceName.Buffer)
+ {
+ vboxNetFltWinMemFree(pWinIf->MpDeviceName.Buffer);
+ }
+
+ FINI_INTERLOCKED_SINGLE_LIST(&pWinIf->TransferDataList);
+# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ FINI_INTERLOCKED_SINGLE_LIST(&pWinIf->SendPacketQueue);
+# endif
+ NdisFreeBufferPool(pWinIf->hSendBufferPool);
+ NdisFreePacketPool(pWinIf->hSendPacketPool);
+ rc = RTSemFastMutexDestroy(pWinIf->hSynchRequestMutex); AssertRC(rc);
+#endif
+
+ /* NOTE: NULL is a valid handle */
+ NdisFreeBufferPool(pWinIf->hRecvBufferPool);
+ NdisFreePacketPool(pWinIf->hRecvPacketPool);
+
+ LogFlowFunc(("LEAVE: pWinIf 0x%p\n", pWinIf));
+}
+
+#ifndef VBOXNETADP
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf, IN PNDIS_STRING pOurDeviceName)
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf)
+#endif
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifndef VBOXNETADP
+ int rc;
+#endif
+
+ LogFlowFunc(("ENTER: pWinIf 0x%p\n", pWinIf));
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ NdisZeroMemory(pWinIf, sizeof (VBOXNETFLTWIN));
+ NdisAllocatePacketPoolEx(&Status, &pWinIf->hRecvPacketPool,
+ VBOXNETFLT_PACKET_POOL_SIZE_NORMAL,
+ VBOXNETFLT_PACKET_POOL_SIZE_OVERFLOW,
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ /* NOTE: NULL is a valid handle !!! */
+ NdisAllocateBufferPool(&Status, &pWinIf->hRecvBufferPool, VBOXNETFLT_BUFFER_POOL_SIZE_RX);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pWinIf->MpState.PowerState = NdisDeviceStateD3;
+ vboxNetFltWinSetOpState(&pWinIf->MpState, kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ pWinIf->PtState.PowerState = NdisDeviceStateD3;
+ vboxNetFltWinSetOpState(&pWinIf->PtState, kVBoxNetDevOpState_Deinitialized);
+
+ NdisAllocateBufferPool(&Status,
+ &pWinIf->hSendBufferPool,
+ VBOXNETFLT_BUFFER_POOL_SIZE_TX);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ INIT_INTERLOCKED_SINGLE_LIST(&pWinIf->TransferDataList);
+
+# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ INIT_INTERLOCKED_SINGLE_LIST(&pWinIf->SendPacketQueue);
+# endif
+ NdisInitializeEvent(&pWinIf->OpenCloseEvent);
+
+ KeInitializeEvent(&pWinIf->hSynchCompletionEvent, SynchronizationEvent, FALSE);
+
+ NdisInitializeEvent(&pWinIf->MpInitCompleteEvent);
+
+ NdisAllocatePacketPoolEx(&Status, &pWinIf->hSendPacketPool,
+ VBOXNETFLT_PACKET_POOL_SIZE_NORMAL,
+ VBOXNETFLT_PACKET_POOL_SIZE_OVERFLOW,
+ sizeof (PVBOXNETFLT_PKTRSVD_PT));
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ rc = RTSemFastMutexCreate(&pWinIf->hSynchRequestMutex);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ Status = vboxNetFltWinMemAlloc((PVOID*)&pWinIf->MpDeviceName.Buffer, pOurDeviceName->Length);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pWinIf->MpDeviceName.MaximumLength = pOurDeviceName->Length;
+ pWinIf->MpDeviceName.Length = 0;
+ Status = vboxNetFltWinCopyString(&pWinIf->MpDeviceName, pOurDeviceName);
+#endif
+ return NDIS_STATUS_SUCCESS;
+#ifndef VBOXNETADP
+ // unreachable: vboxNetFltWinMemFree(pWinIf->MpDeviceName.Buffer);
+ }
+ RTSemFastMutexDestroy(pWinIf->hSynchRequestMutex);
+ }
+ else
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreePacketPool(pWinIf->hSendPacketPool);
+ }
+ NdisFreeBufferPool(pWinIf->hSendBufferPool);
+ }
+ NdisFreeBufferPool(pWinIf->hRecvBufferPool);
+#endif
+ }
+ NdisFreePacketPool(pWinIf->hRecvPacketPool);
+ }
+
+ LogFlowFunc(("LEAVE: pWinIf 0x%p, Status 0x%x\n", pWinIf, Status));
+
+ return Status;
+}
+
+/**
+ * match packets
+ */
+#define NEXT_LIST_ENTRY(_Entry) ((_Entry)->Flink)
+#define PREV_LIST_ENTRY(_Entry) ((_Entry)->Blink)
+#define FIRST_LIST_ENTRY NEXT_LIST_ENTRY
+#define LAST_LIST_ENTRY PREV_LIST_ENTRY
+
+#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
+
+#ifndef VBOXNETADP
+
+#ifdef DEBUG_misha
+
+RTMAC g_vboxNetFltWinVerifyMACBroadcast = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+RTMAC g_vboxNetFltWinVerifyMACGuest = {0x08, 0x00, 0x27, 0x01, 0x02, 0x03};
+
+DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdr(PNDIS_PACKET pPacket)
+{
+ UINT cBufCount1;
+ PNDIS_BUFFER pBuffer1;
+ UINT uTotalPacketLength1;
+ RTNETETHERHDR* pEth;
+ UINT cbLength1 = 0;
+ UINT i = 0;
+
+ NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
+
+ Assert(pBuffer1);
+ Assert(uTotalPacketLength1 >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+ if (uTotalPacketLength1 < VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ return NULL;
+
+ NdisQueryBufferSafe(pBuffer1, &pEth, &cbLength1, NormalPagePriority);
+ Assert(cbLength1 >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+ if (cbLength1 < VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ return NULL;
+
+ return pEth;
+}
+
+DECLHIDDEN(PRTNETETHERHDR) vboxNetFltWinGetEthHdrSG(PINTNETSG pSG)
+{
+ Assert(pSG->cSegsUsed);
+ Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
+ Assert(pSG->aSegs[0].cb >= VBOXNETFLT_PACKET_ETHEADER_SIZE);
+
+ if (!pSG->cSegsUsed)
+ return NULL;
+
+ if (pSG->aSegs[0].cb < VBOXNETFLT_PACKET_ETHEADER_SIZE)
+ return NULL;
+
+ return (PRTNETETHERHDR)pSG->aSegs[0].pv;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc)
+{
+ PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdr(pPacket);
+ Assert(pHdr);
+
+ if (!pHdr)
+ return false;
+
+ if (pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
+ return false;
+
+ if (pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
+ return false;
+
+ return true;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc)
+{
+ PRTNETETHERHDR pHdr = vboxNetFltWinGetEthHdrSG(pSG);
+ Assert(pHdr);
+
+ if (!pHdr)
+ return false;
+
+ if (pDst && memcmp(pDst, &pHdr->DstMac, sizeof(RTMAC)))
+ return false;
+
+ if (pSrc && memcmp(pSrc, &pHdr->SrcMac, sizeof(RTMAC)))
+ return false;
+
+ return true;
+}
+#endif
+
+# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+/*
+ * answers whether the two given packets match based on the packet length and the first cbMatch bytes of the packets
+ * if cbMatch < 0 matches complete packets.
+ */
+DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch)
+{
+ UINT cBufCount1;
+ PNDIS_BUFFER pBuffer1;
+ UINT uTotalPacketLength1;
+ uint8_t *pbMemBuf1 = NULL;
+ UINT cbLength1 = 0;
+
+ UINT cBufCount2;
+ PNDIS_BUFFER pBuffer2;
+ UINT uTotalPacketLength2;
+ uint8_t *pbMemBuf2 = NULL;
+ UINT cbLength2 = 0;
+ bool bMatch = true;
+
+#ifdef DEBUG_NETFLT_PACKETS
+ bool bCompleteMatch = false;
+#endif
+
+ NdisQueryPacket(pPacket1, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
+ NdisQueryPacket(pPacket2, NULL, &cBufCount2, &pBuffer2, &uTotalPacketLength2);
+
+ Assert(pBuffer1);
+ Assert(pBuffer2);
+
+ if (uTotalPacketLength1 != uTotalPacketLength2)
+ {
+ bMatch = false;
+ }
+ else
+ {
+ UINT ucbLength2Match = 0;
+ UINT ucbMatch;
+ if (cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
+ {
+ /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
+ ucbMatch = uTotalPacketLength1;
+#ifdef DEBUG_NETFLT_PACKETS
+ bCompleteMatch = true;
+#endif
+ }
+ else
+ {
+ ucbMatch = (UINT)cbMatch;
+ }
+
+ for (;;)
+ {
+ if (!cbLength1)
+ {
+ NdisQueryBufferSafe(pBuffer1, &pbMemBuf1, &cbLength1, NormalPagePriority);
+ NdisGetNextBuffer(pBuffer1, &pBuffer1);
+ }
+ else
+ {
+ Assert(pbMemBuf1);
+ Assert(ucbLength2Match);
+ pbMemBuf1 += ucbLength2Match;
+ }
+
+ if (!cbLength2)
+ {
+ NdisQueryBufferSafe(pBuffer2, &pbMemBuf2, &cbLength2, NormalPagePriority);
+ NdisGetNextBuffer(pBuffer2, &pBuffer2);
+ }
+ else
+ {
+ Assert(pbMemBuf2);
+ Assert(ucbLength2Match);
+ pbMemBuf2 += ucbLength2Match;
+ }
+
+ ucbLength2Match = MIN(ucbMatch, cbLength1);
+ ucbLength2Match = MIN(ucbLength2Match, cbLength2);
+
+ if (memcmp(pbMemBuf1, pbMemBuf2, ucbLength2Match))
+ {
+ bMatch = false;
+ break;
+ }
+
+ ucbMatch -= ucbLength2Match;
+ if (!ucbMatch)
+ break;
+
+ cbLength1 -= ucbLength2Match;
+ cbLength2 -= ucbLength2Match;
+ }
+ }
+
+#ifdef DEBUG_NETFLT_PACKETS
+ if (bMatch && !bCompleteMatch)
+ {
+ /* check that the packets fully match */
+ DBG_CHECK_PACKETS(pPacket1, pPacket2);
+ }
+#endif
+
+ return bMatch;
+}
+
+/*
+ * answers whether the ndis packet and PINTNETSG match based on the packet length and the first cbMatch bytes of the packet and PINTNETSG
+ * if cbMatch < 0 matches complete packets.
+ */
+DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch)
+{
+ UINT cBufCount1;
+ PNDIS_BUFFER pBuffer1;
+ UINT uTotalPacketLength1;
+ uint8_t *pbMemBuf1 = NULL;
+ UINT cbLength1 = 0;
+ UINT uTotalPacketLength2 = pSG->cbTotal;
+ uint8_t *pbMemBuf2 = NULL;
+ UINT cbLength2 = 0;
+ bool bMatch = true;
+ bool bCompleteMatch = false;
+ UINT i = 0;
+
+ NdisQueryPacket(pPacket, NULL, &cBufCount1, &pBuffer1, &uTotalPacketLength1);
+
+ Assert(pBuffer1);
+ Assert(pSG->cSegsUsed);
+ Assert(pSG->cSegsAlloc >= pSG->cSegsUsed);
+
+ if (uTotalPacketLength1 != uTotalPacketLength2)
+ {
+ AssertFailed();
+ bMatch = false;
+ }
+ else
+ {
+ UINT ucbLength2Match = 0;
+ UINT ucbMatch;
+
+ if (cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
+ {
+ /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
+ ucbMatch = uTotalPacketLength1;
+ bCompleteMatch = true;
+ }
+ else
+ {
+ ucbMatch = (UINT)cbMatch;
+ }
+
+ for (;;)
+ {
+ if (!cbLength1)
+ {
+ NdisQueryBufferSafe(pBuffer1, &pbMemBuf1, &cbLength1, NormalPagePriority);
+ NdisGetNextBuffer(pBuffer1, &pBuffer1);
+ }
+ else
+ {
+ Assert(pbMemBuf1);
+ Assert(ucbLength2Match);
+ pbMemBuf1 += ucbLength2Match;
+ }
+
+ if (!cbLength2)
+ {
+ Assert(i < pSG->cSegsUsed);
+ pbMemBuf2 = (uint8_t*)pSG->aSegs[i].pv;
+ cbLength2 = pSG->aSegs[i].cb;
+ i++;
+ }
+ else
+ {
+ Assert(pbMemBuf2);
+ Assert(ucbLength2Match);
+ pbMemBuf2 += ucbLength2Match;
+ }
+
+ ucbLength2Match = MIN(ucbMatch, cbLength1);
+ ucbLength2Match = MIN(ucbLength2Match, cbLength2);
+
+ if (memcmp(pbMemBuf1, pbMemBuf2, ucbLength2Match))
+ {
+ bMatch = false;
+ AssertFailed();
+ break;
+ }
+
+ ucbMatch -= ucbLength2Match;
+ if (!ucbMatch)
+ break;
+
+ cbLength1 -= ucbLength2Match;
+ cbLength2 -= ucbLength2Match;
+ }
+ }
+
+ if (bMatch && !bCompleteMatch)
+ {
+ /* check that the packets fully match */
+ DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+ }
+ return bMatch;
+}
+
+# if 0
+/*
+ * answers whether the two PINTNETSGs match based on the packet length and the first cbMatch bytes of the PINTNETSG
+ * if cbMatch < 0 matches complete packets.
+ */
+static bool vboxNetFltWinMatchSGs(PINTNETSG pSG1, PINTNETSG pSG2, const INT cbMatch)
+{
+ UINT uTotalPacketLength1 = pSG1->cbTotal;
+ PVOID pbMemBuf1 = NULL;
+ UINT cbLength1 = 0;
+ UINT i1 = 0;
+ UINT uTotalPacketLength2 = pSG2->cbTotal;
+ PVOID pbMemBuf2 = NULL;
+ UINT cbLength2 = 0;
+
+ bool bMatch = true;
+ bool bCompleteMatch = false;
+ UINT i2 = 0;
+
+ Assert(pSG1->cSegsUsed);
+ Assert(pSG2->cSegsUsed);
+ Assert(pSG1->cSegsAlloc >= pSG1->cSegsUsed);
+ Assert(pSG2->cSegsAlloc >= pSG2->cSegsUsed);
+
+ if (uTotalPacketLength1 != uTotalPacketLength2)
+ {
+ AssertFailed();
+ bMatch = false;
+ }
+ else
+ {
+ UINT ucbMatch;
+ if (cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
+ {
+ /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
+ ucbMatch = uTotalPacketLength1;
+ bCompleteMatch = true;
+ }
+ else
+ {
+ ucbMatch = (UINT)cbMatch;
+ }
+
+ do
+ {
+ UINT ucbLength2Match;
+ if (!cbLength1)
+ {
+ Assert(i1 < pSG1->cSegsUsed);
+ pbMemBuf1 = pSG1->aSegs[i1].pv;
+ cbLength1 = pSG1->aSegs[i1].cb;
+ i1++;
+ }
+
+ if (!cbLength2)
+ {
+ Assert(i2 < pSG2->cSegsUsed);
+ pbMemBuf2 = pSG2->aSegs[i2].pv;
+ cbLength2 = pSG2->aSegs[i2].cb;
+ i2++;
+ }
+
+ ucbLength2Match = MIN(ucbMatch, cbLength1);
+ ucbLength2Match = MIN(ucbLength2Match, cbLength2);
+
+ if (memcmp(pbMemBuf1, pbMemBuf2, ucbLength2Match))
+ {
+ bMatch = false;
+ AssertFailed();
+ break;
+ }
+ ucbMatch -= ucbLength2Match;
+ cbLength1 -= ucbLength2Match;
+ cbLength2 -= ucbLength2Match;
+ } while (ucbMatch);
+ }
+
+ if (bMatch && !bCompleteMatch)
+ {
+ /* check that the packets fully match */
+ DBG_CHECK_SGS(pSG1, pSG2);
+ }
+ return bMatch;
+}
+# endif
+# endif
+#endif
+
+static void vboxNetFltWinFiniNetFltBase()
+{
+ do
+ {
+ vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+
+ RTR0Term();
+ } while (0);
+}
+
+/*
+ * Defines max timeout for waiting for driver unloading
+ * (3000 * 100 ms = 5 minutes)
+ */
+#define MAX_UNLOAD_PROBES 3000
+
+static int vboxNetFltWinFiniIdc()
+{
+ int rc;
+ int i;
+
+ vboxNetFltWinStopInitIdcProbing();
+
+ if (g_bVBoxIdcInitialized)
+ {
+ for (i = 0; (rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals)) == VERR_WRONG_ORDER
+ && i < MAX_UNLOAD_PROBES; i++)
+ {
+ RTThreadSleep(100);
+ }
+ if (i == MAX_UNLOAD_PROBES)
+ {
+ // seems something hungs in driver
+ LogFlow(("vboxNetFltWinFiniIdc - Can't delete Idc. pInH=%p cFRefs=%d fIDcOpen=%s",
+ g_VBoxNetFltGlobals.pInstanceHead, g_VBoxNetFltGlobals.cFactoryRefs,
+ g_VBoxNetFltGlobals.fIDCOpen ? "true" : "false"));
+ LogFlow(("vboxNetFltWinFiniIdc g_VBoxNetFltGlobalsWin cDvRefs=%d hDev=%x pDev=%p Mp=%x \n",
+ g_VBoxNetFltGlobalsWin.cDeviceRefs, g_VBoxNetFltGlobalsWin.hDevice,
+ g_VBoxNetFltGlobalsWin.pDevObj, g_VBoxNetFltGlobalsWin.Mp.hMiniport));
+ Assert(i == MAX_UNLOAD_PROBES);
+ return VERR_WRONG_ORDER;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ g_bVBoxIdcInitialized = false;
+ }
+ }
+ else
+ {
+ rc = VINF_SUCCESS;
+ }
+ return rc;
+
+}
+
+static int vboxNetFltWinFiniNetFlt()
+{
+ int rc = vboxNetFltWinFiniIdc();
+ if (RT_SUCCESS(rc))
+ {
+ vboxNetFltWinFiniNetFltBase();
+ }
+ return rc;
+}
+
+/**
+ * base netflt initialization
+ */
+static int vboxNetFltWinInitNetFltBase()
+{
+ int rc;
+
+ do
+ {
+ Assert(!g_bVBoxIdcInitialized);
+
+ rc = RTR0Init(0);
+ if (!RT_SUCCESS(rc))
+ {
+ break;
+ }
+
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
+ if (!RT_SUCCESS(rc))
+ {
+ RTR0Term();
+ break;
+ }
+ }while (0);
+
+ return rc;
+}
+
+/**
+ * initialize IDC
+ */
+static int vboxNetFltWinInitIdc()
+{
+ int rc;
+
+ do
+ {
+ if (g_bVBoxIdcInitialized)
+ {
+ rc = VINF_ALREADY_INITIALIZED;
+ break;
+ }
+
+ /*
+ * connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
+ if (!RT_SUCCESS(rc))
+ {
+ break;
+ }
+
+ g_bVBoxIdcInitialized = true;
+ } while (0);
+
+ return rc;
+}
+
+static VOID vboxNetFltWinInitIdcProbingWorker(PVOID pvContext)
+{
+ PINIT_IDC_INFO pInitIdcInfo = (PINIT_IDC_INFO)pvContext;
+ int rc = vboxNetFltWinInitIdc();
+ if (RT_FAILURE(rc))
+ {
+ bool bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
+ if (!bInterupted)
+ {
+ RTThreadSleep(1000); /* 1 s */
+ bInterupted = ASMAtomicUoReadBool(&pInitIdcInfo->bStop);
+ if (!bInterupted)
+ {
+ vboxNetFltWinJobEnqueueJob(&g_VBoxJobQueue, &pInitIdcInfo->Job, false);
+ return;
+ }
+ }
+
+ /* it's interrupted */
+ rc = VERR_INTERRUPTED;
+ }
+
+ ASMAtomicUoWriteS32(&pInitIdcInfo->rc, rc);
+ KeSetEvent(&pInitIdcInfo->hCompletionEvent, 0, FALSE);
+}
+
+static int vboxNetFltWinStopInitIdcProbing()
+{
+ if (!g_VBoxInitIdcInfo.bInitialized)
+ return VERR_INVALID_STATE;
+
+ ASMAtomicUoWriteBool(&g_VBoxInitIdcInfo.bStop, true);
+ KeWaitForSingleObject(&g_VBoxInitIdcInfo.hCompletionEvent, Executive, KernelMode, FALSE, NULL);
+
+ return g_VBoxInitIdcInfo.rc;
+}
+
+static int vboxNetFltWinStartInitIdcProbing()
+{
+ Assert(!g_bVBoxIdcInitialized);
+ KeInitializeEvent(&g_VBoxInitIdcInfo.hCompletionEvent, NotificationEvent, FALSE);
+ g_VBoxInitIdcInfo.bStop = false;
+ g_VBoxInitIdcInfo.bInitialized = true;
+ vboxNetFltWinJobInit(&g_VBoxInitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_VBoxInitIdcInfo, false);
+ vboxNetFltWinJobEnqueueJob(&g_VBoxJobQueue, &g_VBoxInitIdcInfo.Job, false);
+ return VINF_SUCCESS;
+}
+
+static int vboxNetFltWinInitNetFlt()
+{
+ int rc;
+
+ do
+ {
+ rc = vboxNetFltWinInitNetFltBase();
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ break;
+ }
+
+ /*
+ * connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ rc = vboxNetFltWinInitIdc();
+ if (RT_FAILURE(rc))
+ {
+ AssertFailed();
+ vboxNetFltWinFiniNetFltBase();
+ break;
+ }
+ } while (0);
+
+ return rc;
+}
+
+/* detach*/
+static int vboxNetFltWinDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("vboxNetFltWinDeleteInstance: pThis=0x%p \n", pThis));
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+ Assert(pThis);
+ Assert(pThis->fDisconnectedFromHost);
+ Assert(!pThis->fRediscoveryPending);
+ Assert(pThis->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE);
+#ifndef VBOXNETADP
+ Assert(pThis->u.s.WinIf.PtState.OpState == kVBoxNetDevOpState_Deinitialized);
+ Assert(!pThis->u.s.WinIf.hBinding);
+#endif
+ Assert(pThis->u.s.WinIf.MpState.OpState == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ Assert(!pThis->u.s.PacketQueueWorker.pSG);
+#endif
+
+ RTSemMutexDestroy(pThis->u.s.hWinIfMutex);
+
+ vboxNetFltWinDrvDereference();
+
+ return VINF_SUCCESS;
+}
+
+static NDIS_STATUS vboxNetFltWinDisconnectIt(PVBOXNETFLTINS pInstance)
+{
+#ifndef VBOXNETFLT_NO_PACKET_QUEUE
+ vboxNetFltWinQuFiniPacketQueue(pInstance);
+#else
+ RT_NOREF1(pInstance);
+#endif
+ return NDIS_STATUS_SUCCESS;
+}
+
+/* detach*/
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PVBOXNETFLTINS pNetFlt, bool bOnUnbind)
+{
+ NDIS_STATUS Status;
+ int rc;
+ LogFlowFunc(("ENTER: pThis=%0xp\n", pNetFlt));
+
+ Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+ Assert(pNetFlt);
+
+ /* paranoia to ensure the instance is not removed while we're waiting on the mutex
+ * in case ndis does something unpredictable, e.g. calls our miniport halt independently
+ * from protocol unbind and concurrently with it*/
+ vboxNetFltRetain(pNetFlt, false);
+
+ rc = RTSemMutexRequest(pNetFlt->u.s.hWinIfMutex, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(vboxNetFltWinGetWinIfState(pNetFlt) == kVBoxWinIfState_Connected);
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Initialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Initialized);
+#endif
+ if (vboxNetFltWinGetWinIfState(pNetFlt) == kVBoxWinIfState_Connected)
+ {
+ vboxNetFltWinSetWinIfState(pNetFlt, kVBoxWinIfState_Disconnecting);
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtDoUnbinding(pNetFlt, bOnUnbind);
+#else
+ Status = vboxNetFltWinMpDoDeinitialization(pNetFlt);
+#endif
+ Assert(Status == NDIS_STATUS_SUCCESS);
+
+ vboxNetFltWinSetWinIfState(pNetFlt, kVBoxWinIfState_Disconnected);
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pNetFlt->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+ vboxNetFltWinPtFiniWinIf(&pNetFlt->u.s.WinIf);
+
+ /* we're unbinding, make an unbind-related release */
+ vboxNetFltRelease(pNetFlt, false);
+ }
+ else
+ {
+ AssertBreakpoint();
+#ifndef VBOXNETADP
+ pNetFlt->u.s.WinIf.OpenCloseStatus = NDIS_STATUS_FAILURE;
+#endif
+ if (!bOnUnbind)
+ {
+ vboxNetFltWinSetOpState(&pNetFlt->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+ }
+ Status = NDIS_STATUS_FAILURE;
+ }
+ RTSemMutexRelease(pNetFlt->u.s.hWinIfMutex);
+ }
+ else
+ {
+ AssertBreakpoint();
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ /* release for the retain we made before waining on the mutex */
+ vboxNetFltRelease(pNetFlt, false);
+
+ LogFlowFunc(("LEAVE: Status 0x%x\n", Status));
+
+ return Status;
+}
+
+
+/**
+ * Checks if the host (not us) has put the adapter in promiscuous mode.
+ *
+ * @returns true if promiscuous, false if not.
+ * @param pThis The instance.
+ */
+static bool vboxNetFltWinIsPromiscuous2(PVBOXNETFLTINS pThis)
+{
+#ifndef VBOXNETADP
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pThis))
+ {
+ bool bPromiscuous;
+ if (!vboxNetFltWinReferenceWinIf(pThis))
+ return false;
+
+ bPromiscuous = (pThis->u.s.WinIf.fUpperProtocolSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
+ /*vboxNetFltWinIsPromiscuous(pAdapt);*/
+
+ vboxNetFltWinDereferenceWinIf(pThis);
+ return bPromiscuous;
+ }
+ return false;
+#else
+ RT_NOREF1(pThis);
+ return true;
+#endif
+}
+
+
+/**
+ * Report the MAC address, promiscuous mode setting, GSO capabilities and
+ * no-preempt destinations to the internal network.
+ *
+ * Does nothing if we're not currently connected to an internal network.
+ *
+ * @param pThis The instance data.
+ */
+static void vboxNetFltWinReportStuff(PVBOXNETFLTINS pThis)
+{
+ /** @todo Keep these up to date, esp. the promiscuous mode bit. */
+ if (pThis->pSwitchPort
+ && vboxNetFltTryRetainBusyNotDisconnected(pThis))
+ {
+ pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
+ pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort,
+ vboxNetFltWinIsPromiscuous2(pThis));
+ pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
+ INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
+ /** @todo We should be able to do pfnXmit at DISPATCH_LEVEL... */
+ pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
+ vboxNetFltRelease(pThis, true /*fBusy*/);
+ }
+}
+
+/**
+ * Worker for vboxNetFltWinAttachToInterface.
+ *
+ * @param pAttachInfo Structure for communicating with
+ * vboxNetFltWinAttachToInterface.
+ */
+static void vboxNetFltWinAttachToInterfaceWorker(PATTACH_INFO pAttachInfo)
+{
+ PVBOXNETFLTINS pThis = pAttachInfo->pNetFltIf;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ int rc;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ /* to ensure we're not removed while we're here */
+ vboxNetFltRetain(pThis, false);
+
+ rc = RTSemMutexRequest(pThis->u.s.hWinIfMutex, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(vboxNetFltWinGetWinIfState(pThis) == kVBoxWinIfState_Disconnected);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+ if (vboxNetFltWinGetWinIfState(pThis) == kVBoxWinIfState_Disconnected)
+ {
+ if (pAttachInfo->fRediscovery)
+ {
+ /* rediscovery means adaptor bind is performed while intnet is already using it
+ * i.e. adaptor was unbound while being used by intnet and now being bound back again */
+ Assert( ((VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState))
+ == kVBoxNetFltInsState_Connected);
+ }
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtInitWinIf(&pThis->u.s.WinIf, pAttachInfo->pCreateContext->pOurName);
+#else
+ Status = vboxNetFltWinPtInitWinIf(&pThis->u.s.WinIf);
+#endif
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Connecting);
+
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinPtDoBinding(pThis, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
+#else
+ Status = vboxNetFltWinMpDoInitialization(pThis, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
+#endif
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (!pAttachInfo->fRediscovery)
+ vboxNetFltWinDrvReference();
+#ifndef VBOXNETADP
+ if (pThis->u.s.WinIf.OpenCloseStatus == NDIS_STATUS_SUCCESS)
+#endif
+ {
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Connected);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.PtState) == kVBoxNetDevOpState_Initialized);
+#endif
+ /* 4. mark as connected */
+ RTSpinlockAcquire(pThis->hSpinlock);
+ ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+ RTSpinlockRelease(pThis->hSpinlock);
+
+ pAttachInfo->Status = VINF_SUCCESS;
+ pAttachInfo->pCreateContext->Status = NDIS_STATUS_SUCCESS;
+
+ RTSemMutexRelease(pThis->u.s.hWinIfMutex);
+
+ vboxNetFltRelease(pThis, false);
+
+ /* 5. Report MAC address, promiscuousness and GSO capabilities. */
+ vboxNetFltWinReportStuff(pThis);
+
+ return;
+ }
+#ifndef VBOXNETADP /* unreachable for VBOXNETADP because of the return above */
+ AssertBreakpoint();
+
+ if (!pAttachInfo->fRediscovery)
+ {
+ vboxNetFltWinDrvDereference();
+ }
+# ifndef VBOXNETADP
+ vboxNetFltWinPtDoUnbinding(pThis, true);
+/*# else - unreachable
+ vboxNetFltWinMpDoDeinitialization(pThis); */
+# endif
+#endif
+ }
+ AssertBreakpoint();
+ vboxNetFltWinPtFiniWinIf(&pThis->u.s.WinIf);
+ }
+ AssertBreakpoint();
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Disconnected);
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.MpState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ Assert(vboxNetFltWinGetOpState(&pThis->u.s.WinIf.PtState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+ }
+ AssertBreakpoint();
+
+ pAttachInfo->Status = VERR_GENERAL_FAILURE;
+ pAttachInfo->pCreateContext->Status = Status;
+ RTSemMutexRelease(pThis->u.s.hWinIfMutex);
+ }
+ else
+ {
+ AssertBreakpoint();
+ pAttachInfo->Status = rc;
+ }
+
+ vboxNetFltRelease(pThis, false);
+
+ return;
+}
+
+/**
+ * Common code for vboxNetFltOsInitInstance and
+ * vboxNetFltOsMaybeRediscovered.
+ *
+ * @returns IPRT status code.
+ * @param pThis The instance.
+ * @param fRediscovery True if vboxNetFltOsMaybeRediscovered is calling,
+ * false if it's vboxNetFltOsInitInstance.
+ */
+static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery)
+{
+ ATTACH_INFO Info;
+ Info.pNetFltIf = pThis;
+ Info.fRediscovery = fRediscovery;
+ Info.pCreateContext = (PCREATE_INSTANCE_CONTEXT)pContext;
+
+ vboxNetFltWinAttachToInterfaceWorker(&Info);
+
+ return Info.Status;
+}
+static NTSTATUS vboxNetFltWinPtDevDispatch(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
+{
+ RT_NOREF1(pDevObj);
+ PIO_STACK_LOCATION pIrpSl = IoGetCurrentIrpStackLocation(pIrp);;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ switch (pIrpSl->MajorFunction)
+ {
+ case IRP_MJ_DEVICE_CONTROL:
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ case IRP_MJ_CREATE:
+ case IRP_MJ_CLEANUP:
+ case IRP_MJ_CLOSE:
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+
+ pIrp->IoStatus.Status = Status;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevCreate(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ NDIS_STRING DevName, LinkName;
+ PDRIVER_DISPATCH aMajorFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
+ NdisInitUnicodeString(&DevName, VBOXNETFLT_NAME_DEVICE);
+ NdisInitUnicodeString(&LinkName, VBOXNETFLT_NAME_LINK);
+
+ Assert(!pGlobals->hDevice);
+ Assert(!pGlobals->pDevObj);
+ NdisZeroMemory(aMajorFunctions, sizeof (aMajorFunctions));
+ aMajorFunctions[IRP_MJ_CREATE] = vboxNetFltWinPtDevDispatch;
+ aMajorFunctions[IRP_MJ_CLEANUP] = vboxNetFltWinPtDevDispatch;
+ aMajorFunctions[IRP_MJ_CLOSE] = vboxNetFltWinPtDevDispatch;
+ aMajorFunctions[IRP_MJ_DEVICE_CONTROL] = vboxNetFltWinPtDevDispatch;
+
+ NDIS_STATUS Status = NdisMRegisterDevice(pGlobals->Mp.hNdisWrapper,
+ &DevName, &LinkName,
+ aMajorFunctions,
+ &pGlobals->pDevObj,
+ &pGlobals->hDevice);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevDestroy(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ Assert(pGlobals->hDevice);
+ Assert(pGlobals->pDevObj);
+ NDIS_STATUS Status = NdisMDeregisterDevice(pGlobals->hDevice);
+ Assert(Status == NDIS_STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pGlobals->hDevice = NULL;
+ pGlobals->pDevObj = NULL;
+ }
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevCreateReference(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ NDIS_STATUS Status = KeWaitForSingleObject(&pGlobals->SynchEvent, Executive, KernelMode, FALSE, NULL);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Assert(pGlobals->cDeviceRefs >= 0);
+ if (++pGlobals->cDeviceRefs == 1)
+ {
+ Status = vboxNetFltWinDevCreate(pGlobals);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ ObReferenceObject(pGlobals->pDevObj);
+ }
+ }
+ else
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ KeSetEvent(&pGlobals->SynchEvent, 0, FALSE);
+ }
+ else
+ {
+ /* should never happen actually */
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ }
+ return Status;
+}
+
+static NDIS_STATUS vboxNetFltWinDevDereference(PVBOXNETFLTGLOBALS_WIN pGlobals)
+{
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+ NDIS_STATUS Status = KeWaitForSingleObject(&pGlobals->SynchEvent, Executive, KernelMode, FALSE, NULL);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Assert(pGlobals->cDeviceRefs > 0);
+ if (!(--pGlobals->cDeviceRefs))
+ {
+ ObDereferenceObject(pGlobals->pDevObj);
+ Status = vboxNetFltWinDevDestroy(pGlobals);
+ }
+ else
+ {
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ KeSetEvent(&pGlobals->SynchEvent, 0, FALSE);
+ }
+ else
+ {
+ /* should never happen actually */
+ AssertFailed();
+ Status = NDIS_STATUS_FAILURE;
+ }
+ return Status;
+}
+
+/* reference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvReference()
+{
+ vboxNetFltWinDevCreateReference(&g_VBoxNetFltGlobalsWin);
+}
+
+/* dereference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvDereference()
+{
+ vboxNetFltWinDevDereference(&g_VBoxNetFltGlobalsWin);
+}
+
+/*
+ *
+ * The OS specific interface definition
+ *
+ */
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ /* AttachToInterface true if disconnected */
+ return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
+}
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
+{
+ RT_NOREF1(pvIfData);
+ int rc = VINF_SUCCESS;
+ uint32_t cRefs = 0;
+#ifndef VBOXNETADP
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ cRefs++;
+ if (fDst & INTNETTRUNKDIR_HOST)
+ cRefs++;
+#else
+ if ((fDst & INTNETTRUNKDIR_WIRE) || (fDst & INTNETTRUNKDIR_HOST))
+ cRefs = 1;
+#endif
+
+ AssertReturn(cRefs, VINF_SUCCESS);
+
+ if (!vboxNetFltWinIncReferenceWinIf(pThis, cRefs))
+ {
+ return VERR_GENERAL_FAILURE;
+ }
+#ifndef VBOXNETADP
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ {
+ PNDIS_PACKET pPacket;
+
+ pPacket = vboxNetFltWinNdisPacketFromSG(pThis, pSG, NULL /*pBufToFree*/,
+ true /*fToWire*/, true /*fCopyMemory*/);
+
+ if (pPacket)
+ {
+ NDIS_STATUS fStatus;
+
+#ifndef VBOX_LOOPBACK_USEFLAGS
+ /* force "don't loopback" flags to prevent loopback branch invocation in any case
+ * to avoid ndis misbehave */
+ NdisGetPacketFlags(pPacket) |= g_VBoxNetFltGlobalsWin.fPacketDontLoopBack;
+#else
+ /* this is done by default in vboxNetFltWinNdisPacketFromSG */
+#endif
+
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ vboxNetFltWinLbPutSendPacket(pThis, pPacket, true /* bFromIntNet */);
+#endif
+ NdisSend(&fStatus, pThis->u.s.WinIf.hBinding, pPacket);
+ if (fStatus != NDIS_STATUS_PENDING)
+ {
+#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+ /* the status is NOT pending, complete the packet */
+ bool fTmp = vboxNetFltWinLbRemoveSendPacket(pThis, pPacket);
+ Assert(fTmp); NOREF(fTmp);
+#endif
+ if (!NT_SUCCESS(fStatus))
+ rc = VERR_GENERAL_FAILURE; /** @todo convert status to VERR_xxx */
+
+ vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+ }
+ else
+ {
+ /* pending, dereference on packet complete */
+ cRefs--;
+ }
+ }
+ else
+ {
+ AssertFailed();
+ rc = VERR_NO_MEMORY;
+ }
+ }
+#endif
+
+#ifndef VBOXNETADP
+ if (fDst & INTNETTRUNKDIR_HOST)
+#else
+ if (cRefs)
+#endif
+ {
+ PNDIS_PACKET pPacket = vboxNetFltWinNdisPacketFromSG(pThis, pSG, NULL /*pBufToFree*/,
+ false /*fToWire*/, true /*fCopyMemory*/);
+ if (pPacket)
+ {
+ NdisMIndicateReceivePacket(pThis->u.s.WinIf.hMiniport, &pPacket, 1);
+ cRefs--;
+#ifdef VBOXNETADP
+ STATISTIC_INCREASE(pThis->u.s.WinIf.cRxSuccess);
+#endif
+ }
+ else
+ {
+ AssertFailed();
+#ifdef VBOXNETADP
+ STATISTIC_INCREASE(pThis->u.s.WinIf.cRxError);
+#endif
+ rc = VERR_NO_MEMORY;
+ }
+ }
+
+ Assert(cRefs <= 2);
+
+ if (cRefs)
+ {
+ vboxNetFltWinDecReferenceWinIf(pThis, cRefs);
+ }
+
+ return rc;
+}
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+#ifndef VBOXNETADP
+ NDIS_STATUS Status;
+#endif
+ /* we first wait for all pending ops to complete
+ * this might include all packets queued for processing */
+ for (;;)
+ {
+ if (fActive)
+ {
+ if (!pThis->u.s.cModePassThruRefs)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if (!pThis->u.s.cModeNetFltRefs)
+ {
+ break;
+ }
+ }
+ vboxNetFltWinSleep(2);
+ }
+
+ if (!vboxNetFltWinReferenceWinIf(pThis))
+ return;
+#ifndef VBOXNETADP
+
+ if (fActive)
+ {
+#ifdef DEBUG_misha
+ NDIS_PHYSICAL_MEDIUM PhMedium;
+ bool bPromiscSupported;
+
+ Status = vboxNetFltWinQueryPhysicalMedium(pThis, &PhMedium);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+
+ LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
+ Assert(Status == NDIS_STATUS_NOT_SUPPORTED);
+ if (Status != NDIS_STATUS_NOT_SUPPORTED)
+ {
+ LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
+ }
+ PhMedium = NdisPhysicalMediumUnspecified;
+ }
+ else
+ {
+ LogRel(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
+ }
+
+ bPromiscSupported = (!(PhMedium == NdisPhysicalMediumWirelessWan
+ || PhMedium == NdisPhysicalMediumWirelessLan
+ || PhMedium == NdisPhysicalMediumNative802_11
+ || PhMedium == NdisPhysicalMediumBluetooth
+ /*|| PhMedium == NdisPhysicalMediumWiMax */
+ ));
+
+ Assert(bPromiscSupported == VBOXNETFLT_PROMISCUOUS_SUPPORTED(pThis));
+#endif
+ }
+
+ if (VBOXNETFLT_PROMISCUOUS_SUPPORTED(pThis))
+ {
+ Status = vboxNetFltWinSetPromiscuous(pThis, fActive);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogRel(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
+ AssertFailed();
+ }
+ }
+#else
+# ifdef VBOXNETADP_REPORT_DISCONNECTED
+ if (fActive)
+ {
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_CONNECT,
+ (PVOID)NULL,
+ 0);
+ }
+ else
+ {
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_DISCONNECT,
+ (PVOID)NULL,
+ 0);
+ }
+#else
+ if (fActive)
+ {
+ /* indicate status change to make the ip settings be re-picked for dhcp */
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_DISCONNECT,
+ (PVOID)NULL,
+ 0);
+
+ NdisMIndicateStatus(pThis->u.s.WinIf.hMiniport,
+ NDIS_STATUS_MEDIA_CONNECT,
+ (PVOID)NULL,
+ 0);
+ }
+# endif
+#endif
+ vboxNetFltWinDereferenceWinIf(pThis);
+
+ return;
+}
+
+#ifndef VBOXNETADP
+
+DECLINLINE(bool) vboxNetFltWinIsAddrLinkLocal4(PCRTNETADDRIPV4 pAddr)
+{
+ return (pAddr->s.Lo == 0xfea9); /* 169.254 */
+}
+
+DECLINLINE(bool) vboxNetFltWinIsAddrLinkLocal6(PCRTNETADDRIPV6 pAddr)
+{
+ return ((pAddr->au8[0] == 0xfe) && ((pAddr->au8[1] & 0xc0) == 0x80));
+}
+
+void vboxNetFltWinNotifyHostAddress(PTA_ADDRESS pAddress, bool fAdded)
+{
+ void *pvAddr = NULL;
+ INTNETADDRTYPE enmAddrType = kIntNetAddrType_Invalid;
+
+ LogFlow(("==>vboxNetFltWinNotifyHostAddress: AddrType=%d %s\n",
+ pAddress->AddressType, fAdded ? "added" : "deleted"));
+ if (pAddress->AddressType == TDI_ADDRESS_TYPE_IP)
+ {
+ PTDI_ADDRESS_IP pTdiAddrIp = (PTDI_ADDRESS_IP)pAddress->Address;
+ /*
+ * Note that we do not get loopback addresses here. If we did we should
+ * have checked and ignored them too.
+ */
+ if (!vboxNetFltWinIsAddrLinkLocal4((PCRTNETADDRIPV4)(&pTdiAddrIp->in_addr)))
+ {
+ pvAddr = &pTdiAddrIp->in_addr;
+ enmAddrType = kIntNetAddrType_IPv4;
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: ignoring link-local address %RTnaipv4\n",
+ pTdiAddrIp->in_addr));
+ }
+ else if (pAddress->AddressType == TDI_ADDRESS_TYPE_IP6)
+ {
+ PTDI_ADDRESS_IP6 pTdiAddrIp6 = (PTDI_ADDRESS_IP6)pAddress->Address;
+ if (!vboxNetFltWinIsAddrLinkLocal6((PCRTNETADDRIPV6)(pTdiAddrIp6->sin6_addr)))
+ {
+ pvAddr = pTdiAddrIp6->sin6_addr;
+ enmAddrType = kIntNetAddrType_IPv6;
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: ignoring link-local address %RTnaipv6\n",
+ pTdiAddrIp6->sin6_addr));
+ }
+ else
+ {
+ Log2(("vboxNetFltWinNotifyHostAddress: ignoring irrelevant address type %d\n",
+ pAddress->AddressType));
+ LogFlow(("<==vboxNetFltWinNotifyHostAddress\n"));
+ return;
+ }
+ if (pvAddr)
+ {
+ NdisAcquireSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ /* At this point the list must contain at least one element. */
+ PVBOXNETFLTINS pInstance = NULL;
+ PVBOXNETFLTWIN pFilter;
+ RTListForEach(&g_VBoxNetFltGlobalsWin.listFilters, pFilter, VBOXNETFLTWIN, node)
+ {
+ pInstance = RT_FROM_MEMBER(pFilter, VBOXNETFLTINS, u.s.WinIf);
+ if (vboxNetFltWinReferenceWinIf(pInstance))
+ {
+ if (pInstance->pSwitchPort && pInstance->pSwitchPort->pfnNotifyHostAddress)
+ break;
+ vboxNetFltWinDereferenceWinIf(pInstance);
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: failed to retain filter instance %p\n", pInstance));
+ pInstance = NULL;
+ }
+ NdisReleaseSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ if (pInstance)
+ {
+ if (enmAddrType == kIntNetAddrType_IPv4)
+ Log2(("vboxNetFltWin%sAddressHandler: %RTnaipv4\n",
+ fAdded ? "Add" : "Del", *(PCRTNETADDRIPV4)pvAddr));
+ else
+ Log2(("vboxNetFltWin%sAddressHandler: %RTnaipv6\n",
+ fAdded ? "Add" : "Del", pvAddr));
+ pInstance->pSwitchPort->pfnNotifyHostAddress(pInstance->pSwitchPort, fAdded,
+ enmAddrType, pvAddr);
+ vboxNetFltWinDereferenceWinIf(pInstance);
+ }
+ else
+ Log2(("vboxNetFltWinNotifyHostAddress: no filters require notification\n"));
+ }
+ LogFlow(("<==vboxNetFltWinNotifyHostAddress\n"));
+}
+
+void vboxNetFltWinAddAddressHandler(PTA_ADDRESS Address,
+ PUNICODE_STRING DeviceName,
+ PTDI_PNP_CONTEXT Context)
+{
+ RT_NOREF2(DeviceName, Context);
+ vboxNetFltWinNotifyHostAddress(Address, true);
+}
+
+void vboxNetFltWinDelAddressHandler(PTA_ADDRESS Address,
+ PUNICODE_STRING DeviceName,
+ PTDI_PNP_CONTEXT Context)
+{
+ RT_NOREF2(DeviceName, Context);
+ vboxNetFltWinNotifyHostAddress(Address, false);
+}
+
+void vboxNetFltWinRegisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltWinRegisterIpAddrNotifier: instance=%p pThis->pSwitchPort=%p pThis->pSwitchPort->pfnNotifyHostAddress=%p\n",
+ pThis, pThis->pSwitchPort, pThis->pSwitchPort ? pThis->pSwitchPort->pfnNotifyHostAddress : NULL));
+ if (pThis->pSwitchPort && pThis->pSwitchPort->pfnNotifyHostAddress)
+ {
+ NdisAcquireSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ bool fRegisterHandlers = RTListIsEmpty(&g_VBoxNetFltGlobalsWin.listFilters);
+ RTListPrepend(&g_VBoxNetFltGlobalsWin.listFilters, &pThis->u.s.WinIf.node);
+ NdisReleaseSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+
+ if (fRegisterHandlers)
+ {
+ TDI_CLIENT_INTERFACE_INFO Info;
+ UNICODE_STRING ClientName = RTL_CONSTANT_STRING(L"VBoxNetFlt");
+ memset(&Info, 0, sizeof(Info));
+ Info.MajorTdiVersion = 2;
+ Info.MinorTdiVersion = 0;
+ Info.ClientName = &ClientName;
+ Info.AddAddressHandlerV2 = vboxNetFltWinAddAddressHandler;
+ Info.DelAddressHandlerV2 = vboxNetFltWinDelAddressHandler;
+ Assert(!g_VBoxNetFltGlobalsWin.hNotifier);
+ NTSTATUS Status = TdiRegisterPnPHandlers(&Info, sizeof(Info), &g_VBoxNetFltGlobalsWin.hNotifier);
+ Log2(("vboxNetFltWinRegisterIpAddrNotifier: TdiRegisterPnPHandlers returned %d\n", Status)); NOREF(Status);
+ }
+ else
+ Log2(("vboxNetFltWinRegisterIpAddrNotifier: already registed\n"));
+ }
+ else
+ Log2(("vboxNetFltWinRegisterIpAddrNotifier: this instance does not require notifications, ignoring...\n"));
+ LogFlow(("<==vboxNetFltWinRegisterIpAddrNotifier: notifier=%p\n", g_VBoxNetFltGlobalsWin.hNotifier));
+}
+
+void vboxNetFltWinUnregisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltWinUnregisterIpAddrNotifier: notifier=%p\n", g_VBoxNetFltGlobalsWin.hNotifier));
+ if (pThis->pSwitchPort && pThis->pSwitchPort->pfnNotifyHostAddress)
+ {
+ NdisAcquireSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ /* At this point the list must contain at least one element. */
+ Assert(!RTListIsEmpty(&g_VBoxNetFltGlobalsWin.listFilters));
+ RTListNodeRemove(&pThis->u.s.WinIf.node);
+ HANDLE hNotifier = NULL;
+ if (RTListIsEmpty(&g_VBoxNetFltGlobalsWin.listFilters))
+ {
+ /*
+ * The list has become empty, so we need to deregister handlers. We
+ * grab hNotifier and reset it while still holding the lock. This
+ * guaranties that we won't interfere with setting it in
+ * vboxNetFltWinRegisterIpAddrNotifier(). It is inconceivable that
+ * vboxNetFltWinUnregisterIpAddrNotifier() will be called for the
+ * same filter instance while it is still being processed by
+ * vboxNetFltWinRegisterIpAddrNotifier(). This would require trunk
+ * destruction in the middle of its creation. It is possible that
+ * vboxNetFltWinUnregisterIpAddrNotifier() is called for another
+ * filter instance, but in such case we won't even get here as the
+ * list won't be empty.
+ */
+ hNotifier = g_VBoxNetFltGlobalsWin.hNotifier;
+ g_VBoxNetFltGlobalsWin.hNotifier = NULL;
+ }
+ NdisReleaseSpinLock(&g_VBoxNetFltGlobalsWin.lockFilters);
+ if (hNotifier)
+ {
+ NTSTATUS Status = TdiDeregisterPnPHandlers(hNotifier);
+ Log2(("vboxNetFltWinUnregisterIpAddrNotifier: TdiDeregisterPnPHandlers(%p) returned %d\n",
+ hNotifier, Status)); NOREF(Status);
+ }
+ else
+ Log2(("vboxNetFltWinUnregisterIpAddrNotifier: filters remain, do not deregister handlers yet\n"));
+ }
+ else
+ Log2(("vboxNetFltWinUnregisterIpAddrNotifier: this instance did not require notifications, ignoring...\n"));
+ LogFlow(("<==vboxNetFltWinUnregisterIpAddrNotifier\n"));
+}
+#else /* VBOXNETADP */
+#define vboxNetFltWinRegisterIpAddrNotifier(x)
+#define vboxNetFltWinUnregisterIpAddrNotifier(x)
+#endif /* VBOXNETADP */
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ NDIS_STATUS Status = vboxNetFltWinDisconnectIt(pThis);
+ Log2(("vboxNetFltOsDisconnectIt: pThis=%p pThis->pSwitchPort=%p pThis->pSwitchPort->pfnNotifyHostAddress=%p\n",
+ pThis, pThis->pSwitchPort, pThis->pSwitchPort ? pThis->pSwitchPort->pfnNotifyHostAddress : NULL));
+ vboxNetFltWinUnregisterIpAddrNotifier(pThis);
+ return Status == NDIS_STATUS_SUCCESS ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
+}
+
+static void vboxNetFltWinConnectItWorker(PVOID pvContext)
+{
+ PWORKER_INFO pInfo = (PWORKER_INFO)pvContext;
+#if !defined(VBOXNETADP) || !defined(VBOXNETFLT_NO_PACKET_QUEUE)
+ NDIS_STATUS Status;
+#endif
+ PVBOXNETFLTINS pInstance = pInfo->pNetFltIf;
+
+ Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ /* this is not a rediscovery, initialize Mac cache */
+ if (vboxNetFltWinReferenceWinIf(pInstance))
+ {
+#ifndef VBOXNETADP
+ Status = vboxNetFltWinGetMacAddress(pInstance, &pInstance->u.s.MacAddr);
+ if (Status == NDIS_STATUS_SUCCESS)
+#endif
+ {
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+ pInfo->Status = VINF_SUCCESS;
+#else
+ Status = vboxNetFltWinQuInitPacketQueue(pInstance);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ pInfo->Status = VINF_SUCCESS;
+ }
+ else
+ {
+ pInfo->Status = VERR_GENERAL_FAILURE;
+ }
+#endif
+ }
+#ifndef VBOXNETADP
+ else
+ {
+ pInfo->Status = VERR_INTNET_FLT_IF_FAILED;
+ }
+#endif
+
+ vboxNetFltWinDereferenceWinIf(pInstance);
+ }
+ else
+ {
+ pInfo->Status = VERR_INTNET_FLT_IF_NOT_FOUND;
+ }
+}
+
+static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis)
+{
+ WORKER_INFO Info;
+ Info.pNetFltIf = pThis;
+
+ vboxNetFltWinJobSynchExecAtPassive(vboxNetFltWinConnectItWorker, &Info);
+
+ if (RT_SUCCESS(Info.Status))
+ vboxNetFltWinReportStuff(pThis);
+
+ return Info.Status;
+}
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ Log2(("vboxNetFltOsConnectIt: pThis=%p pThis->pSwitchPort=%p pThis->pSwitchPort->pfnNotifyHostAddress=%p\n",
+ pThis, pThis->pSwitchPort, pThis->pSwitchPort ? pThis->pSwitchPort->pfnNotifyHostAddress : NULL));
+ vboxNetFltWinRegisterIpAddrNotifier(pThis);
+ return vboxNetFltWinConnectIt(pThis);
+}
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ vboxNetFltWinDeleteInstance(pThis);
+}
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
+{
+ int rc = RTSemMutexCreate(&pThis->u.s.hWinIfMutex);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxNetFltWinAttachToInterface(pThis, pvContext, false /*fRediscovery*/ );
+ if (RT_SUCCESS(rc))
+ {
+ return rc;
+ }
+ RTSemMutexDestroy(pThis->u.s.hWinIfMutex);
+ }
+ return rc;
+}
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ pThis->u.s.cModeNetFltRefs = 0;
+ pThis->u.s.cModePassThruRefs = 0;
+ vboxNetFltWinSetWinIfState(pThis, kVBoxWinIfState_Disconnected);
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.MpState, kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+ vboxNetFltWinSetOpState(&pThis->u.s.WinIf.PtState, kVBoxNetDevOpState_Deinitialized);
+#endif
+ return VINF_SUCCESS;
+}
+
+void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
+{
+ RT_NOREF3(pThis, pvIfData, pMac);
+}
+
+int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
+{
+ /* Nothing to do */
+ RT_NOREF3(pThis, pvIf, ppvIfData);
+ return VINF_SUCCESS;
+}
+
+int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
+{
+ /* Nothing to do */
+ RT_NOREF2(pThis, pvIfData);
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h
new file mode 100644
index 00000000..36235409
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetFltRt-win.h
@@ -0,0 +1,972 @@
+/* $Id: VBoxNetFltRt-win.h $ */
+/** @file
+ * VBoxNetFltRt-win.h - Bridged Networking Driver, Windows Specific Code.
+ * NetFlt Runtime API
+ */
+/*
+ * Copyright (C) 2011-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_VBoxNetFlt_win_drv_VBoxNetFltRt_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltRt_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+DECLHIDDEN(VOID) vboxNetFltWinUnload(IN PDRIVER_OBJECT DriverObject);
+
+#ifndef VBOXNETADP
+# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch);
+DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch);
+# endif
+#endif
+
+/*************************
+ * packet queue API *
+ *************************/
+
+
+#define LIST_ENTRY_2_PACKET_INFO(pListEntry) \
+ ( (PVBOXNETFLT_PACKET_INFO)((uint8_t *)(pListEntry) - RT_UOFFSETOF(VBOXNETFLT_PACKET_INFO, ListEntry)) )
+
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+
+#define VBOX_SLE_2_PKTRSVD_PT(_pEntry) \
+ ( (PVBOXNETFLT_PKTRSVD_PT)((uint8_t *)(_pEntry) - RT_UOFFSETOF(VBOXNETFLT_PKTRSVD_PT, ListEntry)) )
+
+#define VBOX_SLE_2_SENDPACKET(_pEntry) \
+ ( (PNDIS_PACKET)((uint8_t *)(VBOX_SLE_2_PKTRSVD_PT(_pEntry)) - RT_UOFFSETOF(NDIS_PACKET, ProtocolReserved)) )
+
+#endif
+/**
+ * enqueus the packet info to the tail of the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuEnqueueTail(PVBOXNETFLT_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ InsertTailList(pQueue, &pPacketInfo->ListEntry);
+}
+
+DECLINLINE(void) vboxNetFltWinQuEnqueueHead(PVBOXNETFLT_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ Assert(pPacketInfo->pPool);
+ InsertHeadList(pQueue, &pPacketInfo->ListEntry);
+}
+
+/**
+ * enqueus the packet info to the tail of the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuInterlockedEnqueueTail(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ Assert(pPacketInfo->pPool);
+ NdisAcquireSpinLock(&pQueue->Lock);
+ vboxNetFltWinQuEnqueueTail(&pQueue->Queue, pPacketInfo);
+ NdisReleaseSpinLock(&pQueue->Lock);
+}
+
+DECLINLINE(void) vboxNetFltWinQuInterlockedEnqueueHead(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pQueue, PVBOXNETFLT_PACKET_INFO pPacketInfo)
+{
+ NdisAcquireSpinLock(&pQueue->Lock);
+ vboxNetFltWinQuEnqueueHead(&pQueue->Queue, pPacketInfo);
+ NdisReleaseSpinLock(&pQueue->Lock);
+}
+
+/**
+ * dequeus the packet info from the head of the queue
+ */
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuDequeueHead(PVBOXNETFLT_PACKET_QUEUE pQueue)
+{
+ PLIST_ENTRY pListEntry = RemoveHeadList(pQueue);
+ if (pListEntry != pQueue)
+ {
+ PVBOXNETFLT_PACKET_INFO pInfo = LIST_ENTRY_2_PACKET_INFO(pListEntry);
+ Assert(pInfo->pPool);
+ return pInfo;
+ }
+ return NULL;
+}
+
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuDequeueTail(PVBOXNETFLT_PACKET_QUEUE pQueue)
+{
+ PLIST_ENTRY pListEntry = RemoveTailList(pQueue);
+ if (pListEntry != pQueue)
+ {
+ PVBOXNETFLT_PACKET_INFO pInfo = LIST_ENTRY_2_PACKET_INFO(pListEntry);
+ Assert(pInfo->pPool);
+ return pInfo;
+ }
+ return NULL;
+}
+
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuInterlockedDequeueHead(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pInterlockedQueue)
+{
+ PVBOXNETFLT_PACKET_INFO pInfo;
+ NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+ pInfo = vboxNetFltWinQuDequeueHead(&pInterlockedQueue->Queue);
+ NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+ return pInfo;
+}
+
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinQuInterlockedDequeueTail(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pInterlockedQueue)
+{
+ PVBOXNETFLT_PACKET_INFO pInfo;
+ NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+ pInfo = vboxNetFltWinQuDequeueTail(&pInterlockedQueue->Queue);
+ NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+ return pInfo;
+}
+
+DECLINLINE(void) vboxNetFltWinQuDequeue(PVBOXNETFLT_PACKET_INFO pInfo)
+{
+ RemoveEntryList(&pInfo->ListEntry);
+}
+
+DECLINLINE(void) vboxNetFltWinQuInterlockedDequeue(PVBOXNETFLT_INTERLOCKED_PACKET_QUEUE pInterlockedQueue, PVBOXNETFLT_PACKET_INFO pInfo)
+{
+ NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+ vboxNetFltWinQuDequeue(pInfo);
+ NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+}
+
+/**
+ * allocates the packet info from the pool
+ */
+DECLINLINE(PVBOXNETFLT_PACKET_INFO) vboxNetFltWinPpAllocPacketInfo(PVBOXNETFLT_PACKET_INFO_POOL pPool)
+{
+ return vboxNetFltWinQuInterlockedDequeueHead(&pPool->Queue);
+}
+
+/**
+ * returns the packet info to the pool
+ */
+DECLINLINE(void) vboxNetFltWinPpFreePacketInfo(PVBOXNETFLT_PACKET_INFO pInfo)
+{
+ PVBOXNETFLT_PACKET_INFO_POOL pPool = pInfo->pPool;
+ vboxNetFltWinQuInterlockedEnqueueHead(&pPool->Queue, pInfo);
+}
+
+/** initializes the packet queue */
+#define INIT_PACKET_QUEUE(_pQueue) InitializeListHead((_pQueue))
+
+/** initializes the packet queue */
+#define INIT_INTERLOCKED_PACKET_QUEUE(_pQueue) \
+ { \
+ INIT_PACKET_QUEUE(&(_pQueue)->Queue); \
+ NdisAllocateSpinLock(&(_pQueue)->Lock); \
+ }
+
+/** delete the packet queue */
+#define FINI_INTERLOCKED_PACKET_QUEUE(_pQueue) NdisFreeSpinLock(&(_pQueue)->Lock)
+
+/** returns the packet the packet info contains */
+#define GET_PACKET_FROM_INFO(_pPacketInfo) (ASMAtomicUoReadPtr((void * volatile *)&(_pPacketInfo)->pPacket))
+
+/** assignes the packet to the packet info */
+#define SET_PACKET_TO_INFO(_pPacketInfo, _pPacket) (ASMAtomicUoWritePtr(&(_pPacketInfo)->pPacket, (_pPacket)))
+
+/** returns the flags the packet info contains */
+#define GET_FLAGS_FROM_INFO(_pPacketInfo) (ASMAtomicUoReadU32((volatile uint32_t *)&(_pPacketInfo)->fFlags))
+
+/** sets flags to the packet info */
+#define SET_FLAGS_TO_INFO(_pPacketInfo, _fFlags) (ASMAtomicUoWriteU32((volatile uint32_t *)&(_pPacketInfo)->fFlags, (_fFlags)))
+
+#ifdef VBOXNETFLT_NO_PACKET_QUEUE
+DECLHIDDEN(bool) vboxNetFltWinPostIntnet(PVBOXNETFLTINS pInstance, PVOID pvPacket, const UINT fFlags);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQuEnqueuePacket(PVBOXNETFLTINS pInstance, PVOID pPacket, const UINT fPacketFlags);
+DECLHIDDEN(void) vboxNetFltWinQuFiniPacketQueue(PVBOXNETFLTINS pInstance);
+DECLHIDDEN(NTSTATUS) vboxNetFltWinQuInitPacketQueue(PVBOXNETFLTINS pInstance);
+#endif /* #ifndef VBOXNETFLT_NO_PACKET_QUEUE */
+
+
+#ifndef VBOXNETADP
+/**
+ * searches the list entry in a single-linked list
+ */
+DECLINLINE(bool) vboxNetFltWinSearchListEntry(PVBOXNETFLT_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry2Search, bool bRemove)
+{
+ PSINGLE_LIST_ENTRY pHead = &pList->Head;
+ PSINGLE_LIST_ENTRY pCur;
+ PSINGLE_LIST_ENTRY pPrev;
+ for (pCur = pHead->Next, pPrev = pHead; pCur; pPrev = pCur, pCur = pCur->Next)
+ {
+ if (pEntry2Search == pCur)
+ {
+ if (bRemove)
+ {
+ pPrev->Next = pCur->Next;
+ if (pCur == pList->pTail)
+ {
+ pList->pTail = pPrev;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinSearchPacket(PVBOXNETFLT_SINGLE_LIST pList, PNDIS_PACKET pPacket2Search, int cbMatch, bool bRemove)
+{
+ PSINGLE_LIST_ENTRY pHead = &pList->Head;
+ PSINGLE_LIST_ENTRY pCur;
+ PSINGLE_LIST_ENTRY pPrev;
+ PNDIS_PACKET pCurPacket;
+ for (pCur = pHead->Next, pPrev = pHead; pCur; pPrev = pCur, pCur = pCur->Next)
+ {
+ pCurPacket = VBOX_SLE_2_SENDPACKET(pCur);
+ if (pCurPacket == pPacket2Search || vboxNetFltWinMatchPackets(pPacket2Search, pCurPacket, cbMatch))
+ {
+ if (bRemove)
+ {
+ pPrev->Next = pCur->Next;
+ if (pCur == pList->pTail)
+ {
+ pList->pTail = pPrev;
+ }
+ }
+ return pCurPacket;
+ }
+ }
+ return NULL;
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinSearchPacketBySG(PVBOXNETFLT_SINGLE_LIST pList, PINTNETSG pSG, int cbMatch, bool bRemove)
+{
+ PSINGLE_LIST_ENTRY pHead = &pList->Head;
+ PSINGLE_LIST_ENTRY pCur;
+ PSINGLE_LIST_ENTRY pPrev;
+ PNDIS_PACKET pCurPacket;
+ for (pCur = pHead->Next, pPrev = pHead; pCur; pPrev = pCur, pCur = pCur->Next)
+ {
+ pCurPacket = VBOX_SLE_2_SENDPACKET(pCur);
+ if (vboxNetFltWinMatchPacketAndSG(pCurPacket, pSG, cbMatch))
+ {
+ if (bRemove)
+ {
+ pPrev->Next = pCur->Next;
+ if (pCur == pList->pTail)
+ {
+ pList->pTail = pPrev;
+ }
+ }
+ return pCurPacket;
+ }
+ }
+ return NULL;
+}
+
+#endif /* #if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS) */
+
+DECLINLINE(bool) vboxNetFltWinSListIsEmpty(PVBOXNETFLT_SINGLE_LIST pList)
+{
+ return !pList->Head.Next;
+}
+
+DECLINLINE(void) vboxNetFltWinPutTail(PVBOXNETFLT_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ pList->pTail->Next = pEntry;
+ pList->pTail = pEntry;
+ pEntry->Next = NULL;
+}
+
+DECLINLINE(void) vboxNetFltWinPutHead(PVBOXNETFLT_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ pEntry->Next = pList->Head.Next;
+ pList->Head.Next = pEntry;
+ if (!pEntry->Next)
+ pList->pTail = pEntry;
+}
+
+DECLINLINE(PSINGLE_LIST_ENTRY) vboxNetFltWinGetHead(PVBOXNETFLT_SINGLE_LIST pList)
+{
+ PSINGLE_LIST_ENTRY pEntry = pList->Head.Next;
+ if (pEntry && pEntry == pList->pTail)
+ {
+ pList->Head.Next = NULL;
+ pList->pTail = &pList->Head;
+ }
+ return pEntry;
+}
+
+DECLINLINE(bool) vboxNetFltWinInterlockedSearchListEntry(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry2Search, bool bRemove)
+{
+ bool bFound;
+ NdisAcquireSpinLock(&pList->Lock);
+ bFound = vboxNetFltWinSearchListEntry(&pList->List, pEntry2Search, bRemove);
+ NdisReleaseSpinLock(&pList->Lock);
+ return bFound;
+}
+
+#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinInterlockedSearchPacket(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket2Search, int cbMatch, bool bRemove)
+{
+ PNDIS_PACKET pFound;
+ NdisAcquireSpinLock(&pList->Lock);
+ pFound = vboxNetFltWinSearchPacket(&pList->List, pPacket2Search, cbMatch, bRemove);
+ NdisReleaseSpinLock(&pList->Lock);
+ return pFound;
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinInterlockedSearchPacketBySG(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PINTNETSG pSG, int cbMatch, bool bRemove)
+{
+ PNDIS_PACKET pFound;
+ NdisAcquireSpinLock(&pList->Lock);
+ pFound = vboxNetFltWinSearchPacketBySG(&pList->List, pSG, cbMatch, bRemove);
+ NdisReleaseSpinLock(&pList->Lock);
+ return pFound;
+}
+#endif /* #if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS) */
+
+DECLINLINE(void) vboxNetFltWinInterlockedPutTail(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ NdisAcquireSpinLock(&pList->Lock);
+ vboxNetFltWinPutTail(&pList->List, pEntry);
+ NdisReleaseSpinLock(&pList->Lock);
+}
+
+DECLINLINE(void) vboxNetFltWinInterlockedPutHead(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+ NdisAcquireSpinLock(&pList->Lock);
+ vboxNetFltWinPutHead(&pList->List, pEntry);
+ NdisReleaseSpinLock(&pList->Lock);
+}
+
+DECLINLINE(PSINGLE_LIST_ENTRY) vboxNetFltWinInterlockedGetHead(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList)
+{
+ PSINGLE_LIST_ENTRY pEntry;
+ NdisAcquireSpinLock(&pList->Lock);
+ pEntry = vboxNetFltWinGetHead(&pList->List);
+ NdisReleaseSpinLock(&pList->Lock);
+ return pEntry;
+}
+
+# if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
+DECLINLINE(void) vboxNetFltWinLbPutSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, bool bFromIntNet)
+{
+ PVBOXNETFLT_PKTRSVD_PT pSrv = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ pSrv->bFromIntNet = bFromIntNet;
+ vboxNetFltWinInterlockedPutHead(&pNetFlt->u.s.WinIf.SendPacketQueue, &pSrv->ListEntry);
+}
+
+DECLINLINE(bool) vboxNetFltWinLbIsFromIntNet(PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLT_PKTRSVD_PT pSrv = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ return pSrv->bFromIntNet;
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinLbSearchLoopBack(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, bool bRemove)
+{
+ return vboxNetFltWinInterlockedSearchPacket(&pNetFlt->u.s.WinIf.SendPacketQueue, pPacket, VBOXNETFLT_PACKETMATCH_LENGTH, bRemove);
+}
+
+DECLINLINE(PNDIS_PACKET) vboxNetFltWinLbSearchLoopBackBySG(PVBOXNETFLTINS pNetFlt, PINTNETSG pSG, bool bRemove)
+{
+ return vboxNetFltWinInterlockedSearchPacketBySG(&pNetFlt->u.s.WinIf.SendPacketQueue, pSG, VBOXNETFLT_PACKETMATCH_LENGTH, bRemove);
+}
+
+DECLINLINE(bool) vboxNetFltWinLbRemoveSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket)
+{
+ PVBOXNETFLT_PKTRSVD_PT pSrv = (PVBOXNETFLT_PKTRSVD_PT)pPacket->ProtocolReserved;
+ bool bRet = vboxNetFltWinInterlockedSearchListEntry(&pNetFlt->u.s.WinIf.SendPacketQueue, &pSrv->ListEntry, true);
+#ifdef DEBUG_misha
+ Assert(bRet == (pNetFlt->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE));
+#endif
+ return bRet;
+}
+
+# endif
+
+#endif
+
+#ifdef DEBUG_misha
+DECLHIDDEN(bool) vboxNetFltWinCheckMACs(PNDIS_PACKET pPacket, PRTMAC pDst, PRTMAC pSrc);
+DECLHIDDEN(bool) vboxNetFltWinCheckMACsSG(PINTNETSG pSG, PRTMAC pDst, PRTMAC pSrc);
+extern RTMAC g_vboxNetFltWinVerifyMACBroadcast;
+extern RTMAC g_vboxNetFltWinVerifyMACGuest;
+
+# define VBOXNETFLT_LBVERIFY(_pnf, _p) \
+ do { \
+ Assert(!vboxNetFltWinCheckMACs(_p, NULL, &g_vboxNetFltWinVerifyMACGuest)); \
+ Assert(!vboxNetFltWinCheckMACs(_p, NULL, &(_pnf)->u.s.MacAddr)); \
+ } while (0)
+
+# define VBOXNETFLT_LBVERIFYSG(_pnf, _p) \
+ do { \
+ Assert(!vboxNetFltWinCheckMACsSG(_p, NULL, &g_vboxNetFltWinVerifyMACGuest)); \
+ Assert(!vboxNetFltWinCheckMACsSG(_p, NULL, &(_pnf)->u.s.MacAddr)); \
+ } while (0)
+
+#else
+# define VBOXNETFLT_LBVERIFY(_pnf, _p) do { } while (0)
+# define VBOXNETFLT_LBVERIFYSG(_pnf, _p) do { } while (0)
+#endif
+
+/** initializes the list */
+#define INIT_SINGLE_LIST(_pList) \
+ { \
+ (_pList)->Head.Next = NULL; \
+ (_pList)->pTail = &(_pList)->Head; \
+ }
+
+/** initializes the list */
+#define INIT_INTERLOCKED_SINGLE_LIST(_pList) \
+ do { \
+ INIT_SINGLE_LIST(&(_pList)->List); \
+ NdisAllocateSpinLock(&(_pList)->Lock); \
+ } while (0)
+
+/** delete the packet queue */
+#define FINI_INTERLOCKED_SINGLE_LIST(_pList) \
+ do { \
+ Assert(vboxNetFltWinSListIsEmpty(&(_pList)->List)); \
+ NdisFreeSpinLock(&(_pList)->Lock); \
+ } while (0)
+
+
+/**************************************************************************
+ * PVBOXNETFLTINS , WinIf reference/dereference (i.e. retain/release) API *
+ **************************************************************************/
+
+
+DECLHIDDEN(void) vboxNetFltWinWaitDereference(PVBOXNETFLT_WINIF_DEVICE pState);
+
+DECLINLINE(void) vboxNetFltWinReferenceModeNetFlt(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicIncU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinReferenceModePassThru(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicIncU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinIncReferenceModeNetFlt(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs, v);
+}
+
+DECLINLINE(void) vboxNetFltWinIncReferenceModePassThru(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs, v);
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceModeNetFlt(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicDecU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceModePassThru(PVBOXNETFLTINS pIns)
+{
+ ASMAtomicDecU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs);
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceModeNetFlt(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ Assert(v);
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModeNetFltRefs, (uint32_t)(-((int32_t)v)));
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceModePassThru(PVBOXNETFLTINS pIns, uint32_t v)
+{
+ Assert(v);
+ ASMAtomicAddU32((volatile uint32_t *)&pIns->u.s.cModePassThruRefs, (uint32_t)(-((int32_t)v)));
+}
+
+DECLINLINE(void) vboxNetFltWinSetPowerState(PVBOXNETFLT_WINIF_DEVICE pState, NDIS_DEVICE_POWER_STATE State)
+{
+ ASMAtomicUoWriteU32((volatile uint32_t *)&pState->PowerState, State);
+}
+
+DECLINLINE(NDIS_DEVICE_POWER_STATE) vboxNetFltWinGetPowerState(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ return (NDIS_DEVICE_POWER_STATE)ASMAtomicUoReadU32((volatile uint32_t *)&pState->PowerState);
+}
+
+DECLINLINE(void) vboxNetFltWinSetOpState(PVBOXNETFLT_WINIF_DEVICE pState, VBOXNETDEVOPSTATE State)
+{
+ ASMAtomicUoWriteU32((volatile uint32_t *)&pState->OpState, State);
+}
+
+DECLINLINE(VBOXNETDEVOPSTATE) vboxNetFltWinGetOpState(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ return (VBOXNETDEVOPSTATE)ASMAtomicUoReadU32((volatile uint32_t *)&pState->OpState);
+}
+
+DECLINLINE(bool) vboxNetFltWinDoReferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ if (vboxNetFltWinGetPowerState(pState) == NdisDeviceStateD0 && vboxNetFltWinGetOpState(pState) == kVBoxNetDevOpState_Initialized)
+ {
+ /** @todo r=bird: Since this is a volatile member, why don't you declare it as
+ * such and save yourself all the casting? */
+ ASMAtomicIncU32((uint32_t volatile *)&pState->cReferences);
+ return true;
+ }
+ return false;
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(bool) vboxNetFltWinDoReferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2)
+{
+ if (vboxNetFltWinGetPowerState(pState1) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState1) == kVBoxNetDevOpState_Initialized
+ && vboxNetFltWinGetPowerState(pState2) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState2) == kVBoxNetDevOpState_Initialized)
+ {
+ ASMAtomicIncU32((uint32_t volatile *)&pState1->cReferences);
+ ASMAtomicIncU32((uint32_t volatile *)&pState2->cReferences);
+ return true;
+ }
+ return false;
+}
+#endif
+
+DECLINLINE(void) vboxNetFltWinDereferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState)
+{
+ ASMAtomicDecU32((uint32_t volatile *)&pState->cReferences);
+ /** @todo r=bird: Add comment explaining why these cannot hit 0 or why
+ * reference are counted */
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(void) vboxNetFltWinDereferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2)
+{
+ ASMAtomicDecU32((uint32_t volatile *)&pState1->cReferences);
+ ASMAtomicDecU32((uint32_t volatile *)&pState2->cReferences);
+}
+#endif
+
+DECLINLINE(void) vboxNetFltWinDecReferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState, uint32_t v)
+{
+ Assert(v);
+ ASMAtomicAddU32((uint32_t volatile *)&pState->cReferences, (uint32_t)(-((int32_t)v)));
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(void) vboxNetFltWinDecReferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2, uint32_t v)
+{
+ ASMAtomicAddU32((uint32_t volatile *)&pState1->cReferences, (uint32_t)(-((int32_t)v)));
+ ASMAtomicAddU32((uint32_t volatile *)&pState2->cReferences, (uint32_t)(-((int32_t)v)));
+}
+#endif
+
+DECLINLINE(bool) vboxNetFltWinDoIncReferenceDevice(PVBOXNETFLT_WINIF_DEVICE pState, uint32_t v)
+{
+ Assert(v);
+ if (vboxNetFltWinGetPowerState(pState) == NdisDeviceStateD0 && vboxNetFltWinGetOpState(pState) == kVBoxNetDevOpState_Initialized)
+ {
+ ASMAtomicAddU32((uint32_t volatile *)&pState->cReferences, v);
+ return true;
+ }
+ return false;
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(bool) vboxNetFltWinDoIncReferenceDevices(PVBOXNETFLT_WINIF_DEVICE pState1, PVBOXNETFLT_WINIF_DEVICE pState2, uint32_t v)
+{
+ if (vboxNetFltWinGetPowerState(pState1) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState1) == kVBoxNetDevOpState_Initialized
+ && vboxNetFltWinGetPowerState(pState2) == NdisDeviceStateD0
+ && vboxNetFltWinGetOpState(pState2) == kVBoxNetDevOpState_Initialized)
+ {
+ ASMAtomicAddU32((uint32_t volatile *)&pState1->cReferences, v);
+ ASMAtomicAddU32((uint32_t volatile *)&pState2->cReferences, v);
+ return true;
+ }
+ return false;
+}
+#endif
+
+
+DECLINLINE(bool) vboxNetFltWinReferenceWinIfNetFlt(PVBOXNETFLTINS pNetFlt, bool * pbNetFltActive)
+{
+ RTSpinlockAcquire((pNetFlt)->hSpinlock);
+#ifndef VBOXNETADP
+ if (!vboxNetFltWinDoReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState))
+#else
+ if (!vboxNetFltWinDoReferenceDevice(&pNetFlt->u.s.WinIf.MpState))
+#endif
+ {
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+ *pbNetFltActive = false;
+ return false;
+ }
+
+ if (pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE)
+ {
+ vboxNetFltWinReferenceModePassThru(pNetFlt);
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+ *pbNetFltActive = false;
+ return true;
+ }
+
+ vboxNetFltRetain((pNetFlt), true /* fBusy */);
+ vboxNetFltWinReferenceModeNetFlt(pNetFlt);
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+
+ *pbNetFltActive = true;
+ return true;
+}
+
+DECLINLINE(bool) vboxNetFltWinIncReferenceWinIfNetFlt(PVBOXNETFLTINS pNetFlt, uint32_t v, bool *pbNetFltActive)
+{
+ uint32_t i;
+
+ Assert(v);
+ if (!v)
+ {
+ *pbNetFltActive = false;
+ return false;
+ }
+
+ RTSpinlockAcquire((pNetFlt)->hSpinlock);
+#ifndef VBOXNETADP
+ if (!vboxNetFltWinDoIncReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState, v))
+#else
+ if (!vboxNetFltWinDoIncReferenceDevice(&pNetFlt->u.s.WinIf.MpState, v))
+#endif
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ *pbNetFltActive = false;
+ return false;
+ }
+
+ if (pNetFlt->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE)
+ {
+ vboxNetFltWinIncReferenceModePassThru(pNetFlt, v);
+
+ RTSpinlockRelease((pNetFlt)->hSpinlock);
+ *pbNetFltActive = false;
+ return true;
+ }
+
+ vboxNetFltRetain(pNetFlt, true /* fBusy */);
+
+ vboxNetFltWinIncReferenceModeNetFlt(pNetFlt, v);
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+
+ /* we have marked it as busy, so can do the res references outside the lock */
+ for (i = 0; i < v-1; i++)
+ {
+ vboxNetFltRetain(pNetFlt, true /* fBusy */);
+ }
+
+ *pbNetFltActive = true;
+
+ return true;
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceNetFlt(PVBOXNETFLTINS pNetFlt, uint32_t n)
+{
+ uint32_t i;
+ for (i = 0; i < n; i++)
+ {
+ vboxNetFltRelease(pNetFlt, true);
+ }
+
+ vboxNetFltWinDecReferenceModeNetFlt(pNetFlt, n);
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceNetFlt(PVBOXNETFLTINS pNetFlt)
+{
+ vboxNetFltRelease(pNetFlt, true);
+
+ vboxNetFltWinDereferenceModeNetFlt(pNetFlt);
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceWinIf(PVBOXNETFLTINS pNetFlt, uint32_t v)
+{
+#ifdef VBOXNETADP
+ vboxNetFltWinDecReferenceDevice(&pNetFlt->u.s.WinIf.MpState, v);
+#else
+ vboxNetFltWinDecReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState, v);
+#endif
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceWinIf(PVBOXNETFLTINS pNetFlt)
+{
+#ifdef VBOXNETADP
+ vboxNetFltWinDereferenceDevice(&pNetFlt->u.s.WinIf.MpState);
+#else
+ vboxNetFltWinDereferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState);
+#endif
+}
+
+DECLINLINE(bool) vboxNetFltWinIncReferenceWinIf(PVBOXNETFLTINS pNetFlt, uint32_t v)
+{
+ Assert(v);
+ if (!v)
+ {
+ return false;
+ }
+
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+#ifdef VBOXNETADP
+ if (vboxNetFltWinDoIncReferenceDevice(&pNetFlt->u.s.WinIf.MpState, v))
+#else
+ if (vboxNetFltWinDoIncReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState, v))
+#endif
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return true;
+ }
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return false;
+}
+
+DECLINLINE(bool) vboxNetFltWinReferenceWinIf(PVBOXNETFLTINS pNetFlt)
+{
+ RTSpinlockAcquire(pNetFlt->hSpinlock);
+#ifdef VBOXNETADP
+ if (vboxNetFltWinDoReferenceDevice(&pNetFlt->u.s.WinIf.MpState))
+#else
+ if (vboxNetFltWinDoReferenceDevices(&pNetFlt->u.s.WinIf.MpState, &pNetFlt->u.s.WinIf.PtState))
+#endif
+ {
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return true;
+ }
+
+ RTSpinlockRelease(pNetFlt->hSpinlock);
+ return false;
+}
+
+/***********************************************
+ * methods for accessing the network card info *
+ ***********************************************/
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinGetMacAddress(PVBOXNETFLTINS pNetFlt, PRTMAC pMac);
+DECLHIDDEN(bool) vboxNetFltWinIsPromiscuous(PVBOXNETFLTINS pNetFlt);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinSetPromiscuous(PVBOXNETFLTINS pNetFlt, bool bYes);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PVBOXNETFLTINS pNetFlt, NDIS_PHYSICAL_MEDIUM * pMedium);
+
+/*********************
+ * mem alloc API *
+ *********************/
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMemAlloc(PVOID* ppMemBuf, UINT cbLength);
+
+DECLHIDDEN(void) vboxNetFltWinMemFree(PVOID pMemBuf);
+
+/* convenience method used which allocates and initializes the PINTNETSG containing one
+ * segment referring the buffer of size cbBufSize
+ * the allocated PINTNETSG should be freed with the vboxNetFltWinMemFree.
+ *
+ * This is used when our ProtocolReceive callback is called and we have to return the indicated NDIS_PACKET
+ * on a callback exit. This is why we allocate the PINTNETSG and put the packet info there and enqueue it
+ * for the packet queue */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinAllocSG(UINT cbBufSize, PINTNETSG *ppSG);
+
+/************************
+ * WinIf init/fini API *
+ ************************/
+#if defined(VBOXNETADP)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf, PNDIS_STRING pOurDeviceName);
+#endif
+
+DECLHIDDEN(VOID) vboxNetFltWinPtFiniWinIf(PVBOXNETFLTWIN pWinIf);
+
+/************************************
+ * Execute Job at passive level API *
+ ************************************/
+
+typedef VOID (*PFNVBOXNETFLT_JOB_ROUTINE) (PVOID pContext);
+
+DECLHIDDEN(VOID) vboxNetFltWinJobSynchExecAtPassive(PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext);
+
+/*******************************
+ * Ndis Packets processing API *
+ *******************************/
+DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PVBOXNETFLTINS pNetFlt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory);
+
+DECLHIDDEN(void) vboxNetFltWinFreeSGNdisPacket(PNDIS_PACKET pPacket, bool bFreeMem);
+
+#ifdef DEBUG_NETFLT_PACKETS
+#define DBG_CHECK_PACKETS(_p1, _p2) \
+ { \
+ bool _b = vboxNetFltWinMatchPackets(_p1, _p2, -1); \
+ Assert(_b); \
+ }
+
+#define DBG_CHECK_PACKET_AND_SG(_p, _sg) \
+ { \
+ bool _b = vboxNetFltWinMatchPacketAndSG(_p, _sg, -1); \
+ Assert(_b); \
+ }
+
+#define DBG_CHECK_SGS(_sg1, _sg2) \
+ { \
+ bool _b = vboxNetFltWinMatchSGs(_sg1, _sg2, -1); \
+ Assert(_b); \
+ }
+
+#else
+#define DBG_CHECK_PACKETS(_p1, _p2)
+#define DBG_CHECK_PACKET_AND_SG(_p, _sg)
+#define DBG_CHECK_SGS(_sg1, _sg2)
+#endif
+
+/**
+ * Ndis loops back broadcast packets posted to the wire by IntNet
+ * This routine is used in the mechanism of preventing this looping
+ *
+ * @param pAdapt
+ * @param pPacket
+ * @param bOnRecv true is we are receiving the packet from the wire
+ * false otherwise (i.e. the packet is from the host)
+ *
+ * @return true if the packet is a looped back one, false otherwise
+ */
+#ifdef VBOX_LOOPBACK_USEFLAGS
+DECLINLINE(bool) vboxNetFltWinIsLoopedBackPacket(PNDIS_PACKET pPacket)
+{
+ return (NdisGetPacketFlags(pPacket) & g_fPacketIsLoopedBack) == g_fPacketIsLoopedBack;
+}
+#endif
+
+/**************************************************************
+ * utility methods for ndis packet creation/initialization *
+ **************************************************************/
+
+#define VBOXNETFLT_OOB_INIT(_p) \
+ { \
+ NdisZeroMemory(NDIS_OOB_DATA_FROM_PACKET(_p), sizeof(NDIS_PACKET_OOB_DATA)); \
+ NDIS_SET_PACKET_HEADER_SIZE(_p, VBOXNETFLT_PACKET_ETHEADER_SIZE); \
+ }
+
+#ifndef VBOXNETADP
+
+DECLINLINE(NDIS_STATUS) vboxNetFltWinCopyPacketInfoOnRecv(PNDIS_PACKET pDstPacket, PNDIS_PACKET pSrcPacket, bool bForceStatusResources)
+{
+ NDIS_STATUS Status = bForceStatusResources ? NDIS_STATUS_RESOURCES : NDIS_GET_PACKET_STATUS(pSrcPacket);
+ NDIS_SET_PACKET_STATUS(pDstPacket, Status);
+
+ NDIS_PACKET_FIRST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pSrcPacket);
+ NDIS_PACKET_LAST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pSrcPacket);
+
+ NdisGetPacketFlags(pDstPacket) = NdisGetPacketFlags(pSrcPacket);
+
+ NDIS_SET_ORIGINAL_PACKET(pDstPacket, NDIS_GET_ORIGINAL_PACKET(pSrcPacket));
+ NDIS_SET_PACKET_HEADER_SIZE(pDstPacket, NDIS_GET_PACKET_HEADER_SIZE(pSrcPacket));
+
+ return Status;
+}
+
+DECLINLINE(void) vboxNetFltWinCopyPacketInfoOnSend(PNDIS_PACKET pDstPacket, PNDIS_PACKET pSrcPacket)
+{
+ NDIS_PACKET_FIRST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pSrcPacket);
+ NDIS_PACKET_LAST_NDIS_BUFFER(pDstPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pSrcPacket);
+
+ NdisGetPacketFlags(pDstPacket) = NdisGetPacketFlags(pSrcPacket);
+
+ NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(pDstPacket),
+ NDIS_OOB_DATA_FROM_PACKET(pSrcPacket),
+ sizeof (NDIS_PACKET_OOB_DATA));
+
+ NdisIMCopySendPerPacketInfo(pDstPacket, pSrcPacket);
+
+ PVOID pMediaSpecificInfo = NULL;
+ UINT fMediaSpecificInfoSize = 0;
+
+ NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(pSrcPacket, &pMediaSpecificInfo, &fMediaSpecificInfoSize);
+
+ if (pMediaSpecificInfo || fMediaSpecificInfoSize)
+ {
+ NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(pDstPacket, pMediaSpecificInfo, fMediaSpecificInfoSize);
+ }
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareRecvPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket, bool bDpr);
+#endif
+
+DECLHIDDEN(void) vboxNetFltWinSleep(ULONG milis);
+
+#define MACS_EQUAL(_m1, _m2) \
+ ((_m1).au16[0] == (_m2).au16[0] \
+ && (_m1).au16[1] == (_m2).au16[1] \
+ && (_m1).au16[2] == (_m2).au16[2])
+
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PVBOXNETFLTINS pNetFlt, bool bOnUnbind);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinCopyString(PNDIS_STRING pDst, PNDIS_STRING pSrc);
+
+
+/**
+ * Sets the enmState member atomically.
+ *
+ * Used for all updates.
+ *
+ * @param pThis The instance.
+ * @param enmNewState The new value.
+ */
+DECLINLINE(void) vboxNetFltWinSetWinIfState(PVBOXNETFLTINS pNetFlt, VBOXNETFLT_WINIFSTATE enmNewState)
+{
+ ASMAtomicWriteU32((uint32_t volatile *)&pNetFlt->u.s.WinIf.enmState, enmNewState);
+}
+
+/**
+ * Gets the enmState member atomically.
+ *
+ * Used for all reads.
+ *
+ * @returns The enmState value.
+ * @param pThis The instance.
+ */
+DECLINLINE(VBOXNETFLT_WINIFSTATE) vboxNetFltWinGetWinIfState(PVBOXNETFLTINS pNetFlt)
+{
+ return (VBOXNETFLT_WINIFSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pNetFlt->u.s.WinIf.enmState);
+}
+
+/* reference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvReference();
+/* dereference the driver module to prevent driver unload */
+DECLHIDDEN(void) vboxNetFltWinDrvDereference();
+
+
+#ifndef VBOXNETADP
+# define VBOXNETFLT_PROMISCUOUS_SUPPORTED(_pNetFlt) (!(_pNetFlt)->fDisablePromiscuous)
+#else
+# define STATISTIC_INCREASE(_s) ASMAtomicIncU32((uint32_t volatile *)&(_s));
+
+DECLHIDDEN(void) vboxNetFltWinGenerateMACAddress(RTMAC *pMac);
+DECLHIDDEN(int) vboxNetFltWinMAC2NdisString(RTMAC *pMac, PNDIS_STRING pNdisString);
+DECLHIDDEN(int) vboxNetFltWinMACFromNdisString(RTMAC *pMac, PNDIS_STRING pNdisString);
+
+#endif
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetFltRt_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp
new file mode 100644
index 00000000..6520e909
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.cpp
@@ -0,0 +1,2736 @@
+/* $Id: VBoxNetLwf-win.cpp $ */
+/** @file
+ * VBoxNetLwf-win.cpp - NDIS6 Bridged 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_FLT_DRV
+
+/*
+ * If VBOXNETLWF_SYNC_SEND is defined we won't allocate data buffers, but use
+ * the original buffers coming from IntNet to build MDLs around them. This
+ * also means that we need to wait for send operation to complete before
+ * returning the buffers, which hinders performance way too much.
+ */
+//#define VBOXNETLWF_SYNC_SEND
+
+/*
+ * If VBOXNETLWF_FIXED_SIZE_POOLS is defined we pre-allocate data buffers of
+ * fixed size in five pools. Each pool uses different size to accomodate packets
+ * of various sizes. We allocate these buffers once and re-use them when send
+ * operation is complete.
+ * If VBOXNETLWF_FIXED_SIZE_POOLS is not defined we allocate data buffers before
+ * each send operation and free then upon completion.
+ */
+#define VBOXNETLWF_FIXED_SIZE_POOLS
+
+/*
+ * Don't ask me why it is 42. Empirically this is what goes down the stack.
+ * OTOH, as we know from trustworthy sources, 42 is the answer, so be it.
+ */
+#define VBOXNETLWF_MAX_FRAME_SIZE(mtu) (mtu + 42)
+
+#include <VBox/version.h>
+#include <VBox/err.h>
+#include <iprt/initterm.h>
+#include <iprt/net.h>
+#include <iprt/list.h>
+#include <VBox/intnetinline.h>
+
+#include <iprt/nt/ntddk.h>
+#include <iprt/nt/ndis.h>
+#include <iprt/win/netioapi.h>
+#include <mstcpip.h>
+
+#define LogError(x) DbgPrint x
+
+#if 0
+#undef Log
+#define Log(x) DbgPrint x
+#undef LogFlow
+#define LogFlow(x) DbgPrint x
+#endif
+
+/** We have an entirely different structure than the one defined in VBoxNetFltCmn-win.h */
+typedef struct VBOXNETFLTWIN
+{
+ /** filter module context handle */
+ NDIS_HANDLE hModuleCtx;
+ /** IP address change notifier handle */
+ HANDLE hNotifier; /* Must be here as hModuleCtx may already be NULL when vboxNetFltOsDeleteInstance is called */
+} VBOXNETFLTWIN, *PVBOXNETFLTWIN;
+#define VBOXNETFLT_NO_PACKET_QUEUE
+#define VBOXNETFLT_OS_SPECFIC 1
+#include "VBoxNetFltInternal.h"
+
+#include "VBoxNetLwf-win.h"
+#include "VBox/VBoxNetCmn-win.h"
+
+typedef enum {
+ LwfState_Detached = 0,
+ LwfState_Attaching,
+ LwfState_Paused,
+ LwfState_Restarting,
+ LwfState_Running,
+ LwfState_Pausing,
+ LwfState_32BitHack = 0x7fffffff
+} VBOXNETLWFSTATE;
+
+/*
+ * 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 Stopping state.
+ */
+typedef enum {
+ LwfIdcState_Disconnected = 0, /* Initial state */
+ LwfIdcState_Connecting, /* Attemping to init IDC, worker thread running */
+ LwfIdcState_Connected, /* Successfully connected to IDC, worker thread terminated */
+ LwfIdcState_Stopping /* Terminating the worker thread and disconnecting IDC */
+} VBOXNETLWFIDCSTATE;
+
+struct _VBOXNETLWF_MODULE;
+
+typedef struct VBOXNETLWFGLOBALS
+{
+ /** synch event used for device creation synchronization */
+ //KEVENT SynchEvent;
+ /** Device reference count */
+ //int cDeviceRefs;
+ /** ndis device */
+ NDIS_HANDLE hDevice;
+ /** device object */
+ PDEVICE_OBJECT pDevObj;
+ /** our filter driver handle */
+ NDIS_HANDLE hFilterDriver;
+ /** lock protecting the module list */
+ NDIS_SPIN_LOCK Lock;
+ /** the head of module list */
+ RTLISTANCHOR listModules;
+ /** IDC initialization state */
+ volatile uint32_t enmIdcState;
+ /** IDC init thread handle */
+ HANDLE hInitIdcThread;
+} VBOXNETLWFGLOBALS, *PVBOXNETLWFGLOBALS;
+
+/**
+ * The (common) global data.
+ */
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+/* win-specific global data */
+VBOXNETLWFGLOBALS g_VBoxNetLwfGlobals;
+
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+static ULONG g_cbPool[] = { 576+56, 1556, 4096+56, 6192+56, 9056 };
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+
+typedef struct _VBOXNETLWF_MODULE {
+ RTLISTNODE node;
+
+ NDIS_HANDLE hFilter;
+#ifndef VBOXNETLWF_FIXED_SIZE_POOLS
+ NDIS_HANDLE hPool;
+#else /* VBOXNETLWF_FIXED_SIZE_POOLS */
+ NDIS_HANDLE hPool[RT_ELEMENTS(g_cbPool)];
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+ PVBOXNETLWFGLOBALS pGlobals;
+ /** Associated instance of NetFlt, one-to-one relationship */
+ PVBOXNETFLTINS pNetFlt; /// @todo Consider automic access!
+ /** Module state as described in http://msdn.microsoft.com/en-us/library/windows/hardware/ff550017(v=vs.85).aspx */
+ volatile uint32_t enmState; /* No lock needed yet, atomic should suffice. */
+ /** Mutex to prevent pausing while transmitting on behalf of NetFlt */
+ NDIS_MUTEX InTransmit;
+#ifdef VBOXNETLWF_SYNC_SEND
+ /** Event signalled when sending to the wire is complete */
+ KEVENT EventWire;
+ /** Event signalled when NDIS returns our receive notification */
+ KEVENT EventHost;
+#else /* !VBOXNETLWF_SYNC_SEND */
+ /** Event signalled when all pending sends (both to wire and host) have completed */
+ NDIS_EVENT EventSendComplete;
+ /** Counter for pending sends (both to wire and host) */
+ int32_t cPendingBuffers;
+ /** Work Item to deliver offloading indications at passive IRQL */
+ NDIS_HANDLE hWorkItem;
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ /** MAC address of underlying adapter */
+ RTMAC MacAddr;
+ /** Size of offload config structure */
+ USHORT cbOffloadConfig;
+ /** Saved offload configuration */
+ PNDIS_OFFLOAD pSavedOffloadConfig;
+ /** Temporary buffer for disabling offload configuration */
+ PNDIS_OFFLOAD pDisabledOffloadConfig;
+ /** the cloned request we have passed down */
+ PNDIS_OID_REQUEST pPendingRequest;
+ /** true if the underlying miniport supplied offloading config */
+ bool fOffloadConfigValid;
+ /** true if the trunk expects data from us */
+ bool fActive;
+ /** true if the host wants the adapter to be in promisc mode */
+ bool fHostPromisc;
+ /** true if the user wants packets being sent or received by VMs to be visible to the host in promisc mode */
+ bool fPassVmTrafficToHost;
+ /** Name of underlying adapter */
+ char szMiniportName[1];
+} VBOXNETLWF_MODULE;
+typedef VBOXNETLWF_MODULE *PVBOXNETLWF_MODULE;
+
+/*
+ * A structure to wrap OID requests in.
+ */
+typedef struct _VBOXNETLWF_OIDREQ {
+ NDIS_OID_REQUEST Request;
+ NDIS_STATUS Status;
+ NDIS_EVENT Event;
+} VBOXNETLWF_OIDREQ;
+typedef VBOXNETLWF_OIDREQ *PVBOXNETLWF_OIDREQ;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static FILTER_ATTACH vboxNetLwfWinAttach;
+static FILTER_DETACH vboxNetLwfWinDetach;
+static FILTER_RESTART vboxNetLwfWinRestart;
+static FILTER_PAUSE vboxNetLwfWinPause;
+static FILTER_OID_REQUEST vboxNetLwfWinOidRequest;
+static FILTER_OID_REQUEST_COMPLETE vboxNetLwfWinOidRequestComplete;
+//static FILTER_CANCEL_OID_REQUEST vboxNetLwfWinCancelOidRequest;
+static FILTER_STATUS vboxNetLwfWinStatus;
+//static FILTER_NET_PNP_EVENT vboxNetLwfWinPnPEvent;
+static FILTER_SEND_NET_BUFFER_LISTS vboxNetLwfWinSendNetBufferLists;
+static FILTER_SEND_NET_BUFFER_LISTS_COMPLETE vboxNetLwfWinSendNetBufferListsComplete;
+static FILTER_RECEIVE_NET_BUFFER_LISTS vboxNetLwfWinReceiveNetBufferLists;
+static FILTER_RETURN_NET_BUFFER_LISTS vboxNetLwfWinReturnNetBufferLists;
+static KSTART_ROUTINE vboxNetLwfWinInitIdcWorker;
+
+static VOID vboxNetLwfWinUnloadDriver(IN PDRIVER_OBJECT pDriver);
+static int vboxNetLwfWinInitBase(void);
+static int vboxNetLwfWinFini(void);
+
+
+
+/**
+ * Logs an error to the system event log.
+ *
+ * @param ErrCode Error to report to event log.
+ * @param ReturnedStatus Error that was reported by the driver to the caller.
+ * @param uErrId Unique error id representing the location in the driver.
+ * @param cbDumpData Number of bytes at pDumpData.
+ * @param pDumpData Pointer to data that will be added to the message (see 'details' tab).
+ */
+static void vboxNetLwfLogErrorEvent(NTSTATUS uErrCode, NTSTATUS uReturnedStatus, ULONG uErrId)
+{
+ /* Figure out how many modules are attached and if they are going to fit into the dump data. */
+ unsigned cMaxModules = (ERROR_LOG_MAXIMUM_SIZE - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)) / sizeof(RTMAC);
+ unsigned cModules = 0;
+ PVBOXNETLWF_MODULE pModuleCtx;
+ NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
+ ++cModules;
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ /* Prevent overflow */
+ if (cModules > cMaxModules)
+ cModules = cMaxModules;
+
+ /* DumpDataSize must be a multiple of sizeof(ULONG). */
+ unsigned cbDumpData = (cModules * sizeof(RTMAC) + 3) & ~3;
+ /* Prevent underflow */
+ unsigned cbTotal = RT_MAX(FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData,
+ sizeof(IO_ERROR_LOG_PACKET));
+
+ PIO_ERROR_LOG_PACKET pErrEntry;
+ pErrEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(g_VBoxNetLwfGlobals.pDevObj,
+ (UCHAR)cbTotal);
+ if (pErrEntry)
+ {
+ PRTMAC pDump = (PRTMAC)pErrEntry->DumpData;
+ /*
+ * Initialize the whole structure with zeros in case we are suddenly short
+ * of data because the list is empty or has become smaller.
+ */
+ memset(pErrEntry, 0, cbTotal);
+
+ NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
+ {
+ /* The list could have been modified while we were allocating the entry, rely on cModules instead! */
+ if (cModules-- == 0)
+ break;
+ *pDump++ = pModuleCtx->MacAddr;
+ }
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+
+ pErrEntry->DumpDataSize = cbDumpData;
+ pErrEntry->ErrorCode = uErrCode;
+ pErrEntry->UniqueErrorValue = uErrId;
+ pErrEntry->FinalStatus = uReturnedStatus;
+ IoWriteErrorLogEntry(pErrEntry);
+ }
+ else
+ {
+ DbgPrint("Failed to allocate error log entry (cb=%u)\n", cbTotal);
+ }
+}
+
+#ifdef DEBUG
+
+static const char *vboxNetLwfWinStatusToText(NDIS_STATUS code)
+{
+ switch (code)
+ {
+ case NDIS_STATUS_MEDIA_CONNECT: return "NDIS_STATUS_MEDIA_CONNECT";
+ case NDIS_STATUS_MEDIA_DISCONNECT: return "NDIS_STATUS_MEDIA_DISCONNECT";
+ case NDIS_STATUS_RESET_START: return "NDIS_STATUS_RESET_START";
+ case NDIS_STATUS_RESET_END: return "NDIS_STATUS_RESET_END";
+ case NDIS_STATUS_MEDIA_BUSY: return "NDIS_STATUS_MEDIA_BUSY";
+ case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: return "NDIS_STATUS_MEDIA_SPECIFIC_INDICATION";
+ case NDIS_STATUS_LINK_SPEED_CHANGE: return "NDIS_STATUS_LINK_SPEED_CHANGE";
+ case NDIS_STATUS_LINK_STATE: return "NDIS_STATUS_LINK_STATE";
+ case NDIS_STATUS_PORT_STATE: return "NDIS_STATUS_PORT_STATE";
+ case NDIS_STATUS_OPER_STATUS: return "NDIS_STATUS_OPER_STATUS";
+ case NDIS_STATUS_NETWORK_CHANGE: return "NDIS_STATUS_NETWORK_CHANGE";
+ case NDIS_STATUS_PACKET_FILTER: return "NDIS_STATUS_PACKET_FILTER";
+ case NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: return "NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG";
+ case NDIS_STATUS_TASK_OFFLOAD_HARDWARE_CAPABILITIES: return "NDIS_STATUS_TASK_OFFLOAD_HARDWARE_CAPABILITIES";
+ case NDIS_STATUS_OFFLOAD_ENCASPULATION_CHANGE: return "NDIS_STATUS_OFFLOAD_ENCASPULATION_CHANGE";
+ case NDIS_STATUS_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES: return "NDIS_STATUS_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES";
+ }
+ return "unknown";
+}
+
+static void vboxNetLwfWinDumpFilterTypes(ULONG uFlags)
+{
+ if (uFlags & NDIS_PACKET_TYPE_DIRECTED) Log5((" NDIS_PACKET_TYPE_DIRECTED\n"));
+ if (uFlags & NDIS_PACKET_TYPE_MULTICAST) Log5((" NDIS_PACKET_TYPE_MULTICAST\n"));
+ if (uFlags & NDIS_PACKET_TYPE_ALL_MULTICAST) Log5((" NDIS_PACKET_TYPE_ALL_MULTICAST\n"));
+ if (uFlags & NDIS_PACKET_TYPE_BROADCAST) Log5((" NDIS_PACKET_TYPE_BROADCAST\n"));
+ if (uFlags & NDIS_PACKET_TYPE_PROMISCUOUS) Log5((" NDIS_PACKET_TYPE_PROMISCUOUS\n"));
+ if (uFlags & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) Log5((" NDIS_PACKET_TYPE_ALL_FUNCTIONAL\n"));
+ if (uFlags & NDIS_PACKET_TYPE_ALL_LOCAL) Log5((" NDIS_PACKET_TYPE_ALL_LOCAL\n"));
+ if (uFlags & NDIS_PACKET_TYPE_FUNCTIONAL) Log5((" NDIS_PACKET_TYPE_FUNCTIONAL\n"));
+ if (uFlags & NDIS_PACKET_TYPE_GROUP) Log5((" NDIS_PACKET_TYPE_GROUP\n"));
+ if (uFlags & NDIS_PACKET_TYPE_MAC_FRAME) Log5((" NDIS_PACKET_TYPE_MAC_FRAME\n"));
+ if (uFlags & NDIS_PACKET_TYPE_SMT) Log5((" NDIS_PACKET_TYPE_SMT\n"));
+ if (uFlags & NDIS_PACKET_TYPE_SOURCE_ROUTING) Log5((" NDIS_PACKET_TYPE_SOURCE_ROUTING\n"));
+ if (uFlags == 0) Log5((" NONE\n"));
+}
+
+DECLINLINE(void) vboxNetLwfWinDumpEncapsulation(const char *pcszText, ULONG uEncapsulation)
+{
+ if (uEncapsulation == NDIS_ENCAPSULATION_NOT_SUPPORTED)
+ Log5(("%s not supported\n", pcszText));
+ else
+ {
+ Log5(("%s", pcszText));
+ if (uEncapsulation & NDIS_ENCAPSULATION_NULL)
+ Log5((" null"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3)
+ Log5((" 802.3"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q)
+ Log5((" 802.3pq"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_802_3_P_AND_Q_IN_OOB)
+ Log5((" 802.3pq(oob)"));
+ if (uEncapsulation & NDIS_ENCAPSULATION_IEEE_LLC_SNAP_ROUTED)
+ Log5((" LLC"));
+ Log5(("\n"));
+ }
+}
+
+DECLINLINE(const char *) vboxNetLwfWinSetOnOffText(ULONG uOnOff)
+{
+ switch (uOnOff)
+ {
+ case NDIS_OFFLOAD_SET_NO_CHANGE: return "no change";
+ case NDIS_OFFLOAD_SET_ON: return "on";
+ case NDIS_OFFLOAD_SET_OFF: return "off";
+ }
+ return "unknown";
+}
+
+DECLINLINE(const char *) vboxNetLwfWinOnOffText(ULONG uOnOff)
+{
+ switch (uOnOff)
+ {
+ case NDIS_OFFLOAD_NOT_SUPPORTED: return "off";
+ case NDIS_OFFLOAD_SUPPORTED: return "on";
+ }
+ return "unknown";
+}
+
+DECLINLINE(const char *) vboxNetLwfWinSupportedText(ULONG uSupported)
+{
+ switch (uSupported)
+ {
+ case NDIS_OFFLOAD_NOT_SUPPORTED: return "not supported";
+ case NDIS_OFFLOAD_SUPPORTED: return "supported";
+ }
+ return "unknown";
+}
+
+static void vboxNetLwfWinDumpSetOffloadSettings(PNDIS_OFFLOAD pOffloadConfig)
+{
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv4Transmit.Encapsulation);
+ Log5((" Checksum.IPv4Transmit.IpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv4Transmit.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum)));
+ Log5((" Checksum.IPv4Transmit.IpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Receive.Encapsulation =", pOffloadConfig->Checksum.IPv4Receive.Encapsulation);
+ Log5((" Checksum.IPv4Receive.IpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpChecksum)));
+ Log5((" Checksum.IPv4Receive.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.UdpChecksum)));
+ Log5((" Checksum.IPv4Receive.IpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv6Transmit.Encapsulation);
+ Log5((" Checksum.IPv6Transmit.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv6Transmit.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Receive.Encapsulation =", pOffloadConfig->Checksum.IPv6Receive.Encapsulation);
+ Log5((" Checksum.IPv6Receive.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Receive.TcpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpChecksum)));
+ Log5((" Checksum.IPv6Receive.UdpChecksum = %s\n", vboxNetLwfWinSetOnOffText(pOffloadConfig->Checksum.IPv6Receive.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV1.IPv4.Encapsulation =", pOffloadConfig->LsoV1.IPv4.Encapsulation);
+ Log5((" LsoV1.IPv4.TcpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.TcpOptions)));
+ Log5((" LsoV1.IPv4.IpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.IpOptions)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv4.Encapsulation =", pOffloadConfig->LsoV2.IPv4.Encapsulation);
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv6.Encapsulation =", pOffloadConfig->LsoV2.IPv6.Encapsulation);
+ Log5((" LsoV2.IPv6.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported)));
+ Log5((" LsoV2.IPv6.TcpOptionsSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported)));
+}
+
+static void vboxNetLwfWinDumpOffloadSettings(PNDIS_OFFLOAD pOffloadConfig)
+{
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv4Transmit.Encapsulation);
+ Log5((" Checksum.IPv4Transmit.IpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Transmit.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv4Transmit.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum)));
+ Log5((" Checksum.IPv4Transmit.IpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Transmit.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv4Receive.Encapsulation =", pOffloadConfig->Checksum.IPv4Receive.Encapsulation);
+ Log5((" Checksum.IPv4Receive.IpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv4Receive.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.TcpChecksum)));
+ Log5((" Checksum.IPv4Receive.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.UdpChecksum)));
+ Log5((" Checksum.IPv4Receive.IpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv4Receive.IpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Transmit.Encapsulation =", pOffloadConfig->Checksum.IPv6Transmit.Encapsulation);
+ Log5((" Checksum.IPv6Transmit.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Transmit.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum)));
+ Log5((" Checksum.IPv6Transmit.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" Checksum.IPv6Receive.Encapsulation =", pOffloadConfig->Checksum.IPv6Receive.Encapsulation);
+ Log5((" Checksum.IPv6Receive.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.IpExtensionHeadersSupported)));
+ Log5((" Checksum.IPv6Receive.TcpOptionsSupported = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpOptionsSupported)));
+ Log5((" Checksum.IPv6Receive.TcpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.TcpChecksum)));
+ Log5((" Checksum.IPv6Receive.UdpChecksum = %s\n", vboxNetLwfWinOnOffText(pOffloadConfig->Checksum.IPv6Receive.UdpChecksum)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV1.IPv4.Encapsulation =", pOffloadConfig->LsoV1.IPv4.Encapsulation);
+ Log5((" LsoV1.IPv4.TcpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.TcpOptions)));
+ Log5((" LsoV1.IPv4.IpOptions = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV1.IPv4.IpOptions)));
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv4.Encapsulation =", pOffloadConfig->LsoV2.IPv4.Encapsulation);
+ vboxNetLwfWinDumpEncapsulation(" LsoV2.IPv6.Encapsulation =", pOffloadConfig->LsoV2.IPv6.Encapsulation);
+ Log5((" LsoV2.IPv6.IpExtensionHeadersSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported)));
+ Log5((" LsoV2.IPv6.TcpOptionsSupported = %s\n", vboxNetLwfWinSupportedText(pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported)));
+}
+
+static const char *vboxNetLwfWinStateToText(uint32_t enmState)
+{
+ switch (enmState)
+ {
+ case LwfState_Detached: return "Detached";
+ case LwfState_Attaching: return "Attaching";
+ case LwfState_Paused: return "Paused";
+ case LwfState_Restarting: return "Restarting";
+ case LwfState_Running: return "Running";
+ case LwfState_Pausing: return "Pausing";
+ }
+ return "invalid";
+}
+
+static void vboxNetLwfWinDumpPackets(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: src=%p cb=%d offset=%d", pszMsg, pList->SourceHandle, 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 *) vboxNetLwfWinEthTypeStr(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 VBOXNETLWF_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) vboxNetLwfWinDumpPacket(PCINTNETSG pSG, const char *cszText)
+{
+ uint8_t bPacket[VBOXNETLWF_PKTDMPSIZE];
+
+ uint32_t cb = pSG->cbTotal < VBOXNETLWF_PKTDMPSIZE ? pSG->cbTotal : VBOXNETLWF_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(("NetLWF: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n",
+ cszText, pSG->cbTotal, pHdr+6, pHdr, vboxNetLwfWinEthTypeStr(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,
+ vboxNetLwfWinEthTypeStr(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 vboxNetLwfWinDumpFilterTypes(uFlags) do { } while (0)
+# define vboxNetLwfWinDumpOffloadSettings(p) do { } while (0)
+# define vboxNetLwfWinDumpSetOffloadSettings(p) do { } while (0)
+# define vboxNetLwfWinDumpPackets(m,l) do { } while (0)
+# define vboxNetLwfWinDumpPacket(p,t) do { } while (0)
+#endif /* !DEBUG */
+
+DECLINLINE(bool) vboxNetLwfWinChangeState(PVBOXNETLWF_MODULE pModuleCtx, uint32_t enmNew, uint32_t enmOld = LwfState_32BitHack)
+{
+ AssertReturn(pModuleCtx, false);
+
+ bool fSuccess = true;
+ if (enmOld != LwfState_32BitHack)
+ {
+ fSuccess = ASMAtomicCmpXchgU32(&pModuleCtx->enmState, enmNew, enmOld);
+ if (fSuccess)
+ Log(("vboxNetLwfWinChangeState: state change %s -> %s\n",
+ vboxNetLwfWinStateToText(enmOld),
+ vboxNetLwfWinStateToText(enmNew)));
+ else
+ Log(("ERROR! vboxNetLwfWinChangeState: failed state change %s (actual=%s) -> %s\n",
+ vboxNetLwfWinStateToText(enmOld),
+ vboxNetLwfWinStateToText(ASMAtomicReadU32(&pModuleCtx->enmState)),
+ vboxNetLwfWinStateToText(enmNew)));
+ Assert(fSuccess);
+ }
+ else
+ {
+ uint32_t enmPrevState = ASMAtomicXchgU32(&pModuleCtx->enmState, enmNew);
+ Log(("vboxNetLwfWinChangeState: state change %s -> %s\n",
+ vboxNetLwfWinStateToText(enmPrevState),
+ vboxNetLwfWinStateToText(enmNew)));
+ NOREF(enmPrevState);
+ }
+ return fSuccess;
+}
+
+DECLINLINE(void) vboxNetLwfWinInitOidRequest(PVBOXNETLWF_OIDREQ pRequest)
+{
+ NdisZeroMemory(pRequest, sizeof(VBOXNETLWF_OIDREQ));
+
+ NdisInitializeEvent(&pRequest->Event);
+
+ pRequest->Request.Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST;
+ pRequest->Request.Header.Revision = NDIS_OID_REQUEST_REVISION_1;
+ pRequest->Request.Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1;
+
+ pRequest->Request.RequestId = (PVOID)VBOXNETLWF_REQ_ID;
+}
+
+static NDIS_STATUS vboxNetLwfWinSyncOidRequest(PVBOXNETLWF_MODULE pModuleCtx, PVBOXNETLWF_OIDREQ pRequest)
+{
+ NDIS_STATUS Status = NdisFOidRequest(pModuleCtx->hFilter, &pRequest->Request);
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pRequest->Event, 0);
+ Status = pRequest->Status;
+ }
+ return Status;
+}
+
+DECLINLINE(void) vboxNetLwfWinCopyOidRequestResults(PNDIS_OID_REQUEST pFrom, PNDIS_OID_REQUEST pTo)
+{
+ switch (pFrom->RequestType)
+ {
+ case NdisRequestSetInformation:
+ pTo->DATA.SET_INFORMATION.BytesRead = pFrom->DATA.SET_INFORMATION.BytesRead;
+ pTo->DATA.SET_INFORMATION.BytesNeeded = pFrom->DATA.SET_INFORMATION.BytesNeeded;
+ break;
+ case NdisRequestMethod:
+ pTo->DATA.METHOD_INFORMATION.OutputBufferLength = pFrom->DATA.METHOD_INFORMATION.OutputBufferLength;
+ pTo->DATA.METHOD_INFORMATION.BytesWritten = pFrom->DATA.METHOD_INFORMATION.BytesWritten;
+ pTo->DATA.METHOD_INFORMATION.BytesRead = pFrom->DATA.METHOD_INFORMATION.BytesRead;
+ pTo->DATA.METHOD_INFORMATION.BytesNeeded = pFrom->DATA.METHOD_INFORMATION.BytesNeeded;
+ break;
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ default:
+ pTo->DATA.QUERY_INFORMATION.BytesWritten = pFrom->DATA.QUERY_INFORMATION.BytesWritten;
+ pTo->DATA.QUERY_INFORMATION.BytesNeeded = pFrom->DATA.QUERY_INFORMATION.BytesNeeded;
+ }
+}
+
+void inline vboxNetLwfWinOverridePacketFiltersUp(PVBOXNETLWF_MODULE pModuleCtx, ULONG *pFilters)
+{
+ if (ASMAtomicReadBool(&pModuleCtx->fActive) && !ASMAtomicReadBool(&pModuleCtx->fHostPromisc))
+ *pFilters &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
+}
+
+NDIS_STATUS vboxNetLwfWinOidRequest(IN NDIS_HANDLE hModuleCtx,
+ IN PNDIS_OID_REQUEST pOidRequest)
+{
+ LogFlow(("==>vboxNetLwfWinOidRequest: module=%p\n", hModuleCtx));
+ vboxNetCmnWinDumpOidRequest(__FUNCTION__, pOidRequest);
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNDIS_OID_REQUEST pClone = NULL;
+ NDIS_STATUS Status = NdisAllocateCloneOidRequest(pModuleCtx->hFilter,
+ pOidRequest,
+ VBOXNETLWF_MEM_TAG,
+ &pClone);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ /* Save the pointer to the original */
+ *((PNDIS_OID_REQUEST*)(pClone->SourceReserved)) = pOidRequest;
+
+ pClone->RequestId = pOidRequest->RequestId;
+ /* We are not supposed to get another request until we are through with the one we "postponed" */
+ PNDIS_OID_REQUEST pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, pClone, PNDIS_OID_REQUEST);
+ Assert(pPrev == NULL);
+ pModuleCtx->pPendingRequest = pClone;
+ if (pOidRequest->RequestType == NdisRequestSetInformation
+ && pOidRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
+ {
+ ASMAtomicWriteBool(&pModuleCtx->fHostPromisc, !!(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer & NDIS_PACKET_TYPE_PROMISCUOUS));
+ Log(("vboxNetLwfWinOidRequest: host wanted to set packet filter value to:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
+ /* Keep adapter in promisc mode as long as we are active. */
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ *(ULONG*)pClone->DATA.SET_INFORMATION.InformationBuffer |= NDIS_PACKET_TYPE_PROMISCUOUS;
+ Log5(("vboxNetLwfWinOidRequest: pass the following packet filters to miniport:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
+ }
+ if (pOidRequest->RequestType == NdisRequestSetInformation
+ && pOidRequest->DATA.SET_INFORMATION.Oid == OID_TCP_OFFLOAD_CURRENT_CONFIG)
+ {
+ Log5(("vboxNetLwfWinOidRequest: offloading set to:\n"));
+ vboxNetLwfWinDumpSetOffloadSettings((PNDIS_OFFLOAD)pOidRequest->DATA.SET_INFORMATION.InformationBuffer);
+ }
+
+ /* Forward the clone to underlying filters/miniport */
+ Status = NdisFOidRequest(pModuleCtx->hFilter, pClone);
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ /* Synchronous completion */
+ pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, NULL, PNDIS_OID_REQUEST);
+ Assert(pPrev == pClone);
+ Log5(("vboxNetLwfWinOidRequest: got the following packet filters from miniport:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ /*
+ * The host does not expect the adapter to be in promisc mode,
+ * unless it enabled the mode. Let's not disillusion it.
+ */
+ if ( pOidRequest->RequestType == NdisRequestQueryInformation
+ && pOidRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
+ vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ Log5(("vboxNetLwfWinOidRequest: reporting to the host the following packet filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pOidRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ vboxNetLwfWinCopyOidRequestResults(pClone, pOidRequest);
+ NdisFreeCloneOidRequest(pModuleCtx->hFilter, pClone);
+ }
+ /* In case of async completion we do the rest in vboxNetLwfWinOidRequestComplete() */
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinOidRequest: NdisAllocateCloneOidRequest failed with 0x%x\n", Status));
+ }
+ LogFlow(("<==vboxNetLwfWinOidRequest: Status=0x%x\n", Status));
+ return Status;
+}
+
+VOID vboxNetLwfWinOidRequestComplete(IN NDIS_HANDLE hModuleCtx,
+ IN PNDIS_OID_REQUEST pRequest,
+ IN NDIS_STATUS Status)
+{
+ LogFlow(("==>vboxNetLwfWinOidRequestComplete: module=%p req=%p status=0x%x\n", hModuleCtx, pRequest, Status));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNDIS_OID_REQUEST pOriginal = *((PNDIS_OID_REQUEST*)(pRequest->SourceReserved));
+ if (pOriginal)
+ {
+ /* NDIS is supposed to serialize requests */
+ PNDIS_OID_REQUEST pPrev = ASMAtomicXchgPtrT(&pModuleCtx->pPendingRequest, NULL, PNDIS_OID_REQUEST);
+ Assert(pPrev == pRequest); NOREF(pPrev);
+
+ Log5(("vboxNetLwfWinOidRequestComplete: completed rq type=%d oid=%x\n", pRequest->RequestType, pRequest->DATA.QUERY_INFORMATION.Oid));
+ vboxNetLwfWinCopyOidRequestResults(pRequest, pOriginal);
+ if ( pRequest->RequestType == NdisRequestQueryInformation
+ && pRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER)
+ {
+ Log5(("vboxNetLwfWinOidRequestComplete: underlying miniport reports its packet filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ Log5(("vboxNetLwfWinOidRequestComplete: reporting the following packet filters to upper protocol:\n"));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
+ }
+ NdisFreeCloneOidRequest(pModuleCtx->hFilter, pRequest);
+ NdisFOidRequestComplete(pModuleCtx->hFilter, pOriginal, Status);
+ }
+ else
+ {
+ /* This is not a clone, we originated it */
+ Log(("vboxNetLwfWinOidRequestComplete: locally originated request (%p) completed, status=0x%x\n", pRequest, Status));
+ PVBOXNETLWF_OIDREQ pRqWrapper = RT_FROM_MEMBER(pRequest, VBOXNETLWF_OIDREQ, Request);
+ pRqWrapper->Status = Status;
+ NdisSetEvent(&pRqWrapper->Event);
+ }
+ LogFlow(("<==vboxNetLwfWinOidRequestComplete\n"));
+}
+
+
+static bool vboxNetLwfWinIsPromiscuous(PVBOXNETLWF_MODULE pModuleCtx)
+{
+ return ASMAtomicReadBool(&pModuleCtx->fHostPromisc);
+}
+
+#if 0
+static NDIS_STATUS vboxNetLwfWinGetPacketFilter(PVBOXNETLWF_MODULE pModuleCtx)
+{
+ LogFlow(("==>vboxNetLwfWinGetPacketFilter: module=%p\n", pModuleCtx));
+ VBOXNETLWF_OIDREQ Rq;
+ vboxNetLwfWinInitOidRequest(&Rq);
+ Rq.Request.RequestType = NdisRequestQueryInformation;
+ Rq.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBuffer = &pModuleCtx->uPacketFilter;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(pModuleCtx->uPacketFilter);
+ NDIS_STATUS Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinGetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed with 0x%x\n", Status));
+ return FALSE;
+ }
+ if (Rq.Request.DATA.QUERY_INFORMATION.BytesWritten != sizeof(pModuleCtx->uPacketFilter))
+ {
+ LogError(("vboxNetLwfWinGetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed to write neccessary amount (%d bytes), actually written %d bytes\n", sizeof(pModuleCtx->uPacketFilter), Rq.Request.DATA.QUERY_INFORMATION.BytesWritten));
+ }
+
+ Log5(("vboxNetLwfWinGetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER query returned the following filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(pModuleCtx->uPacketFilter);
+
+ LogFlow(("<==vboxNetLwfWinGetPacketFilter: status=0x%x\n", Status));
+ return Status;
+}
+#endif
+
+static NDIS_STATUS vboxNetLwfWinSetPacketFilter(PVBOXNETLWF_MODULE pModuleCtx, bool fPromisc)
+{
+ LogFlow(("==>vboxNetLwfWinSetPacketFilter: module=%p %s\n", pModuleCtx, fPromisc ? "promiscuous" : "normal"));
+ ULONG uFilter = 0;
+ VBOXNETLWF_OIDREQ Rq;
+ vboxNetLwfWinInitOidRequest(&Rq);
+ Rq.Request.RequestType = NdisRequestQueryInformation;
+ Rq.Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBuffer = &uFilter;
+ Rq.Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(uFilter);
+ NDIS_STATUS Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed with 0x%x\n", Status));
+ return Status;
+ }
+ if (Rq.Request.DATA.QUERY_INFORMATION.BytesWritten != sizeof(uFilter))
+ {
+ LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(query, OID_GEN_CURRENT_PACKET_FILTER) failed to write neccessary amount (%d bytes), actually written %d bytes\n", sizeof(uFilter), Rq.Request.DATA.QUERY_INFORMATION.BytesWritten));
+ return NDIS_STATUS_FAILURE;
+ }
+
+ Log5(("vboxNetLwfWinSetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER query returned the following filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(uFilter);
+
+ if (fPromisc)
+ {
+ /* If we about to go promiscuous, save the state before we change it. */
+ ASMAtomicWriteBool(&pModuleCtx->fHostPromisc, !!(uFilter & NDIS_PACKET_TYPE_PROMISCUOUS));
+ uFilter |= NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+ else
+ {
+ /* Reset promisc only if it was not enabled before we had changed it. */
+ if (!ASMAtomicReadBool(&pModuleCtx->fHostPromisc))
+ uFilter &= ~NDIS_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ Log5(("vboxNetLwfWinSetPacketFilter: OID_GEN_CURRENT_PACKET_FILTER about to set the following filters:\n"));
+ vboxNetLwfWinDumpFilterTypes(uFilter);
+
+ NdisResetEvent(&Rq.Event); /* need to reset as it has been set by query op */
+ Rq.Request.RequestType = NdisRequestSetInformation;
+ Rq.Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ Rq.Request.DATA.SET_INFORMATION.InformationBuffer = &uFilter;
+ Rq.Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(uFilter);
+ Status = vboxNetLwfWinSyncOidRequest(pModuleCtx, &Rq);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinSetPacketFilter: vboxNetLwfWinSyncOidRequest(set, OID_GEN_CURRENT_PACKET_FILTER, vvv below vvv) failed with 0x%x\n", Status));
+ vboxNetLwfWinDumpFilterTypes(uFilter);
+ }
+ LogFlow(("<==vboxNetLwfWinSetPacketFilter: status=0x%x\n", Status));
+ return Status;
+}
+
+
+static NTSTATUS vboxNetLwfWinDevDispatch(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
+{
+ RT_NOREF1(pDevObj);
+ PIO_STACK_LOCATION pIrpSl = IoGetCurrentIrpStackLocation(pIrp);;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ switch (pIrpSl->MajorFunction)
+ {
+ case IRP_MJ_DEVICE_CONTROL:
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ case IRP_MJ_CREATE:
+ case IRP_MJ_CLEANUP:
+ case IRP_MJ_CLOSE:
+ break;
+ default:
+ AssertFailed();
+ break;
+ }
+
+ pIrp->IoStatus.Status = Status;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+ return Status;
+}
+
+/** @todo So far we had no use for device, should we even bother to create it? */
+static NDIS_STATUS vboxNetLwfWinDevCreate(PVBOXNETLWFGLOBALS pGlobals)
+{
+ NDIS_STRING DevName, LinkName;
+ PDRIVER_DISPATCH aMajorFunctions[IRP_MJ_MAXIMUM_FUNCTION+1];
+ NdisInitUnicodeString(&DevName, VBOXNETLWF_NAME_DEVICE);
+ NdisInitUnicodeString(&LinkName, VBOXNETLWF_NAME_LINK);
+
+ Assert(!pGlobals->hDevice);
+ Assert(!pGlobals->pDevObj);
+ NdisZeroMemory(aMajorFunctions, sizeof (aMajorFunctions));
+ aMajorFunctions[IRP_MJ_CREATE] = vboxNetLwfWinDevDispatch;
+ aMajorFunctions[IRP_MJ_CLEANUP] = vboxNetLwfWinDevDispatch;
+ aMajorFunctions[IRP_MJ_CLOSE] = vboxNetLwfWinDevDispatch;
+ aMajorFunctions[IRP_MJ_DEVICE_CONTROL] = vboxNetLwfWinDevDispatch;
+
+ NDIS_DEVICE_OBJECT_ATTRIBUTES DeviceAttributes;
+ NdisZeroMemory(&DeviceAttributes, sizeof(DeviceAttributes));
+ DeviceAttributes.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
+ DeviceAttributes.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
+ DeviceAttributes.Header.Size = sizeof(DeviceAttributes);
+ DeviceAttributes.DeviceName = &DevName;
+ DeviceAttributes.SymbolicName = &LinkName;
+ DeviceAttributes.MajorFunctions = aMajorFunctions;
+ //DeviceAttributes.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
+
+ NDIS_STATUS Status = NdisRegisterDeviceEx(pGlobals->hFilterDriver,
+ &DeviceAttributes,
+ &pGlobals->pDevObj,
+ &pGlobals->hDevice);
+ Log(("vboxNetLwfWinDevCreate: NdisRegisterDeviceEx returned 0x%x\n", Status));
+ Assert(Status == NDIS_STATUS_SUCCESS);
+#if 0
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PFILTER_DEVICE_EXTENSION pExtension;
+ pExtension = NdisGetDeviceReservedExtension(pGlobals->pDevObj);
+ pExtension->Signature = VBOXNETLWF_MEM_TAG;
+ pExtension->Handle = pGlobals->hFilterDriver;
+ }
+#endif
+ return Status;
+}
+
+static void vboxNetLwfWinDevDestroy(PVBOXNETLWFGLOBALS pGlobals)
+{
+ Assert(pGlobals->hDevice);
+ Assert(pGlobals->pDevObj);
+ NdisDeregisterDeviceEx(pGlobals->hDevice);
+ pGlobals->hDevice = NULL;
+ pGlobals->pDevObj = NULL;
+}
+
+static void vboxNetLwfWinDisableOffloading(PNDIS_OFFLOAD pOffloadConfig)
+{
+ pOffloadConfig->Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.TcpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->Checksum.IPv6Transmit.UdpChecksum = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv6.Encapsulation = NDIS_ENCAPSULATION_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv6.IpExtensionHeadersSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+ pOffloadConfig->LsoV2.IPv6.TcpOptionsSupported = NDIS_OFFLOAD_NOT_SUPPORTED;
+}
+
+static void vboxNetLwfWinUpdateSavedOffloadConfig(PVBOXNETLWF_MODULE pModuleCtx, PNDIS_OFFLOAD pOffload)
+{
+ if (pModuleCtx->cbOffloadConfig < pOffload->Header.Size)
+ {
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 10);
+ return;
+ }
+
+ NdisMoveMemory(pModuleCtx->pSavedOffloadConfig, pOffload, pOffload->Header.Size);
+ NdisMoveMemory(pModuleCtx->pDisabledOffloadConfig, pOffload, pOffload->Header.Size);
+ vboxNetLwfWinDisableOffloading(pModuleCtx->pDisabledOffloadConfig);
+ pModuleCtx->fOffloadConfigValid = true;
+}
+
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+static void vboxNetLwfWinFreePools(PVBOXNETLWF_MODULE pModuleCtx, int cPools)
+{
+ for (int i = 0; i < cPools; ++i)
+ {
+ if (pModuleCtx->hPool[i])
+ {
+ NdisFreeNetBufferListPool(pModuleCtx->hPool[i]);
+ Log4(("vboxNetLwfWinFreePools: freed NBL+NB pool 0x%p\n", pModuleCtx->hPool[i]));
+ }
+ }
+}
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+
+
+static void vboxNetLwfWinFreeModuleResources(PVBOXNETLWF_MODULE pModuleCtx)
+{
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+ vboxNetLwfWinFreePools(pModuleCtx, RT_ELEMENTS(g_cbPool));
+#else /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ if (pModuleCtx->hPool)
+ {
+ NdisFreeNetBufferListPool(pModuleCtx->hPool);
+ Log4(("vboxNetLwfWinFreeModuleResources: freed NBL+NB pool 0x%p\n", pModuleCtx->hPool));
+ }
+#endif /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ if (pModuleCtx->pDisabledOffloadConfig)
+ NdisFreeMemory(pModuleCtx->pDisabledOffloadConfig, 0, 0);
+ if (pModuleCtx->pSavedOffloadConfig)
+ NdisFreeMemory(pModuleCtx->pSavedOffloadConfig, 0, 0);
+ if (pModuleCtx->hWorkItem)
+ NdisFreeIoWorkItem(pModuleCtx->hWorkItem);
+ NdisFreeMemory(pModuleCtx, 0, 0);
+}
+
+
+DECLARE_GLOBAL_CONST_UNICODE_STRING(g_strHostOnlyMiniportName, L"VirtualBox Host-Only");
+
+static NDIS_STATUS vboxNetLwfWinAttach(IN NDIS_HANDLE hFilter, IN NDIS_HANDLE hDriverCtx,
+ IN PNDIS_FILTER_ATTACH_PARAMETERS pParameters)
+{
+ LogFlow(("==>vboxNetLwfWinAttach: filter=%p\n", hFilter));
+
+ PVBOXNETLWFGLOBALS pGlobals = (PVBOXNETLWFGLOBALS)hDriverCtx;
+ if (!pGlobals)
+ {
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 1);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ /*
+ * We need a copy of NDIS_STRING structure as we are going to modify length
+ * of the base miniport instance name since RTL does not support comparing
+ * first n characters of two strings. We check if miniport names start with
+ * "Virtual Host-Only" to detect host-only adapters. It is a waste of resources
+ * to bind our filter to host-only adapters since they now operate independently.
+ */
+ NDIS_STRING strTruncatedInstanceName = *pParameters->BaseMiniportInstanceName; /* Do not copy data, only the structure itself */
+ strTruncatedInstanceName.Length = g_strHostOnlyMiniportName.Length; /* Truncate instance name */
+ if (RtlEqualUnicodeString(&strTruncatedInstanceName, &g_strHostOnlyMiniportName, TRUE /* Case insensitive */))
+ {
+ DbgPrint("vboxNetLwfWinAttach: won't attach to %wZ\n", pParameters->BaseMiniportInstanceName);
+ return NDIS_STATUS_FAILURE;
+ }
+
+ ANSI_STRING strMiniportName;
+ /* We use the miniport name to associate this filter module with the netflt instance */
+ NTSTATUS rc = RtlUnicodeStringToAnsiString(&strMiniportName,
+ pParameters->BaseMiniportName,
+ TRUE);
+ if (rc != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinAttach: RtlUnicodeStringToAnsiString(%ls) failed with 0x%x\n",
+ pParameters->BaseMiniportName, rc));
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 2);
+ return NDIS_STATUS_FAILURE;
+ }
+ DbgPrint("vboxNetLwfWinAttach: friendly name=%wZ\n", pParameters->BaseMiniportInstanceName);
+ DbgPrint("vboxNetLwfWinAttach: name=%Z\n", &strMiniportName);
+
+ UINT cbModuleWithNameExtra = sizeof(VBOXNETLWF_MODULE) + strMiniportName.Length;
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)NdisAllocateMemoryWithTagPriority(hFilter,
+ cbModuleWithNameExtra,
+ VBOXNETLWF_MEM_TAG,
+ LowPoolPriority);
+ if (!pModuleCtx)
+ {
+ LogError(("vboxNetLwfWinAttach: Failed to allocate module context for %ls\n", pParameters->BaseMiniportName));
+ RtlFreeAnsiString(&strMiniportName);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 3);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetLwfWinAttach: allocated module context 0x%p\n", pModuleCtx));
+
+ NdisZeroMemory(pModuleCtx, cbModuleWithNameExtra);
+ NdisMoveMemory(pModuleCtx->szMiniportName, strMiniportName.Buffer, strMiniportName.Length);
+ RtlFreeAnsiString(&strMiniportName);
+
+ pModuleCtx->hWorkItem = NdisAllocateIoWorkItem(g_VBoxNetLwfGlobals.hFilterDriver);
+ if (!pModuleCtx->hWorkItem)
+ {
+ LogError(("vboxNetLwfWinAttach: Failed to allocate work item for %ls\n",
+ pParameters->BaseMiniportName));
+ NdisFreeMemory(pModuleCtx, 0, 0);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 4);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ Assert(pParameters->MacAddressLength == sizeof(RTMAC));
+ NdisMoveMemory(&pModuleCtx->MacAddr, pParameters->CurrentMacAddress, RT_MIN(sizeof(RTMAC), pParameters->MacAddressLength));
+
+ pModuleCtx->cbOffloadConfig = sizeof(NDIS_OFFLOAD) * 2; /* Best guess to accomodate future expansion. */
+ /* Get the exact size, if possible. */
+ if (pParameters->DefaultOffloadConfiguration)
+ pModuleCtx->cbOffloadConfig = pParameters->DefaultOffloadConfiguration->Header.Size;
+ else
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 8);
+
+ pModuleCtx->pSavedOffloadConfig =
+ (PNDIS_OFFLOAD)NdisAllocateMemoryWithTagPriority(hFilter, pModuleCtx->cbOffloadConfig,
+ VBOXNETLWF_MEM_TAG, LowPoolPriority);
+ pModuleCtx->pDisabledOffloadConfig =
+ (PNDIS_OFFLOAD)NdisAllocateMemoryWithTagPriority(hFilter, pModuleCtx->cbOffloadConfig,
+ VBOXNETLWF_MEM_TAG, LowPoolPriority);
+ if (!pModuleCtx->pSavedOffloadConfig || !pModuleCtx->pDisabledOffloadConfig)
+ {
+ LogError(("vboxNetLwfWinAttach: Failed to allocate offload config buffers for %ls\n",
+ pParameters->BaseMiniportName));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 9);
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ if (pParameters->DefaultOffloadConfiguration)
+ vboxNetLwfWinUpdateSavedOffloadConfig(pModuleCtx, pParameters->DefaultOffloadConfiguration);
+ else
+ {
+ NdisZeroMemory(pModuleCtx->pDisabledOffloadConfig, pModuleCtx->cbOffloadConfig);
+ pModuleCtx->pDisabledOffloadConfig->Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
+ pModuleCtx->pDisabledOffloadConfig->Header.Revision = NDIS_OFFLOAD_REVISION_1;
+ pModuleCtx->pDisabledOffloadConfig->Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1;
+ }
+
+ pModuleCtx->pGlobals = pGlobals;
+ pModuleCtx->hFilter = hFilter;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Attaching);
+ /* Initialize transmission mutex and events */
+ NDIS_INIT_MUTEX(&pModuleCtx->InTransmit);
+#ifdef VBOXNETLWF_SYNC_SEND
+ KeInitializeEvent(&pModuleCtx->EventWire, SynchronizationEvent, FALSE);
+ KeInitializeEvent(&pModuleCtx->EventHost, SynchronizationEvent, FALSE);
+#else /* !VBOXNETLWF_SYNC_SEND */
+ NdisInitializeEvent(&pModuleCtx->EventSendComplete);
+ pModuleCtx->cPendingBuffers = 0;
+#endif /* !VBOXNETLWF_SYNC_SEND */
+
+#ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+ for (int i = 0; i < RT_ELEMENTS(g_cbPool); ++i)
+ {
+ /* Allocate buffer pools */
+ 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; /** @todo Do we need to consider underlying drivers? I think not. */
+ PoolParams.PoolTag = VBOXNETLWF_MEM_TAG;
+ PoolParams.DataSize = g_cbPool[i];
+ pModuleCtx->hPool[i] = NdisAllocateNetBufferListPool(hFilter, &PoolParams);
+ if (!pModuleCtx->hPool[i])
+ {
+ LogError(("vboxNetLwfWinAttach: NdisAllocateNetBufferListPool failed\n"));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 7);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetLwfWinAttach: allocated NBL+NB pool (data size=%u) 0x%p\n",
+ PoolParams.DataSize, pModuleCtx->hPool[i]));
+ }
+#else /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ /* Allocate buffer pools */
+ 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; /** @todo Do we need to consider underlying drivers? I think not. */
+ PoolParams.PoolTag = VBOXNETLWF_MEM_TAG;
+ pModuleCtx->hPool = NdisAllocateNetBufferListPool(hFilter, &PoolParams);
+ if (!pModuleCtx->hPool)
+ {
+ LogError(("vboxNetLwfWinAttach: NdisAllocateNetBufferListPool failed\n"));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INSUFFICIENT_RESOURCES, NDIS_STATUS_RESOURCES, 7);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetLwfWinAttach: allocated NBL+NB pool 0x%p\n", pModuleCtx->hPool));
+#endif /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+
+ NDIS_FILTER_ATTRIBUTES Attributes;
+ NdisZeroMemory(&Attributes, sizeof(Attributes));
+ Attributes.Header.Revision = NDIS_FILTER_ATTRIBUTES_REVISION_1;
+ Attributes.Header.Size = sizeof(Attributes);
+ Attributes.Header.Type = NDIS_OBJECT_TYPE_FILTER_ATTRIBUTES;
+ Attributes.Flags = 0;
+ NDIS_STATUS Status = NdisFSetAttributes(hFilter, pModuleCtx, &Attributes);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinAttach: NdisFSetAttributes failed with 0x%x\n", Status));
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_RESOURCES, 5);
+ return NDIS_STATUS_RESOURCES;
+ }
+ /* Insert into module chain */
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ RTListPrepend(&pGlobals->listModules, &pModuleCtx->node);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Paused);
+
+ /// @todo Somehow the packet filter is 0 at this point: Status = vboxNetLwfWinGetPacketFilter(pModuleCtx);
+ /// @todo We actually update it later in status handler, perhaps we should not do anything here.
+
+ LogFlow(("<==vboxNetLwfWinAttach: Status = 0x%x\n", Status));
+ return Status;
+}
+
+static VOID vboxNetLwfWinDetach(IN NDIS_HANDLE hModuleCtx)
+{
+ LogFlow(("==>vboxNetLwfWinDetach: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Detached, LwfState_Paused);
+
+ /* Remove from module chain */
+ NdisAcquireSpinLock(&pModuleCtx->pGlobals->Lock);
+ RTListNodeRemove(&pModuleCtx->node);
+ NdisReleaseSpinLock(&pModuleCtx->pGlobals->Lock);
+
+ PVBOXNETFLTINS pNetFltIns = pModuleCtx->pNetFlt; /// @todo Atomic?
+ if (pNetFltIns && vboxNetFltTryRetainBusyNotDisconnected(pNetFltIns))
+ {
+ /*
+ * Set hModuleCtx to null now in order to prevent filter restart,
+ * OID requests and other stuff associated with NetFlt deactivation.
+ */
+ pNetFltIns->u.s.WinIf.hModuleCtx = NULL;
+ /* Notify NetFlt that we are going down */
+ pNetFltIns->pSwitchPort->pfnDisconnect(pNetFltIns->pSwitchPort, &pNetFltIns->MyPort, vboxNetFltPortReleaseBusy);
+ /* We do not 'release' netflt instance since it has been done by pfnDisconnect */
+ }
+ pModuleCtx->pNetFlt = NULL;
+
+ /*
+ * We have to make sure that all NET_BUFFER_LIST structures have been freed by now, but
+ * it does not require us to do anything here since it has already been taken care of
+ * by vboxNetLwfWinPause().
+ */
+ vboxNetLwfWinFreeModuleResources(pModuleCtx);
+ Log4(("vboxNetLwfWinDetach: freed module context 0x%p\n", pModuleCtx));
+ LogFlow(("<==vboxNetLwfWinDetach\n"));
+}
+
+
+static NDIS_STATUS vboxNetLwfWinPause(IN NDIS_HANDLE hModuleCtx, IN PNDIS_FILTER_PAUSE_PARAMETERS pParameters)
+{
+ RT_NOREF1(pParameters);
+ LogFlow(("==>vboxNetLwfWinPause: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Pausing, LwfState_Running);
+ /* Wait for pending send/indication operations to complete. */
+ NDIS_WAIT_FOR_MUTEX(&pModuleCtx->InTransmit);
+#ifndef VBOXNETLWF_SYNC_SEND
+ NdisWaitEvent(&pModuleCtx->EventSendComplete, 1000 /* ms */);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Paused, LwfState_Pausing);
+ NDIS_RELEASE_MUTEX(&pModuleCtx->InTransmit);
+ LogFlow(("<==vboxNetLwfWinPause\n"));
+ return NDIS_STATUS_SUCCESS; /* Failure is not an option */
+}
+
+
+static void vboxNetLwfWinIndicateOffload(PVBOXNETLWF_MODULE pModuleCtx, PNDIS_OFFLOAD pOffload)
+{
+ Log5(("vboxNetLwfWinIndicateOffload: offload config changed to:\n"));
+ vboxNetLwfWinDumpOffloadSettings(pOffload);
+ NDIS_STATUS_INDICATION OffloadingIndication;
+ NdisZeroMemory(&OffloadingIndication, sizeof(OffloadingIndication));
+ OffloadingIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ OffloadingIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ OffloadingIndication.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
+ OffloadingIndication.SourceHandle = pModuleCtx->hFilter;
+ OffloadingIndication.StatusCode = NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG;
+ OffloadingIndication.StatusBuffer = pOffload;
+ OffloadingIndication.StatusBufferSize = pOffload->Header.Size;
+ NdisFIndicateStatus(pModuleCtx->hFilter, &OffloadingIndication);
+}
+
+
+static NDIS_STATUS vboxNetLwfWinRestart(IN NDIS_HANDLE hModuleCtx, IN PNDIS_FILTER_RESTART_PARAMETERS pParameters)
+{
+ RT_NOREF1(pParameters);
+ LogFlow(("==>vboxNetLwfWinRestart: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Restarting, LwfState_Paused);
+
+ /* By default the packets that go between VMs and wire are invisible to the host. */
+ pModuleCtx->fPassVmTrafficToHost = false;
+
+ NDIS_HANDLE hConfig;
+ NDIS_CONFIGURATION_OBJECT cfgObj;
+ cfgObj.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ cfgObj.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+ cfgObj.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
+ cfgObj.NdisHandle = g_VBoxNetLwfGlobals.hFilterDriver;
+
+ NDIS_STATUS Status = NdisOpenConfigurationEx(&cfgObj, &hConfig);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ NDIS_STRING strCfgParam = NDIS_STRING_CONST("PassVmTrafficToHost");
+ PNDIS_CONFIGURATION_PARAMETER pParam = NULL;
+ NdisReadConfiguration(&Status, &pParam, hConfig, &strCfgParam, NdisParameterInteger);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetLwfWinRestart: Failed to read 'PassVmTrafficToHost' from the registry.\n"));
+ }
+ else if (pParam->ParameterData.IntegerData != 0)
+ {
+ Log(("vboxNetLwfWinRestart: Allowing the host to see VM traffic in promisc mode by user request.\n"));
+ pModuleCtx->fPassVmTrafficToHost = true;
+ }
+ NdisCloseConfiguration(hConfig);
+ }
+ vboxNetLwfWinChangeState(pModuleCtx, LwfState_Running, LwfState_Restarting);
+ LogFlow(("<==vboxNetLwfWinRestart: Status = 0x%x, returning NDIS_STATUS_SUCCESS nontheless.\n", Status));
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+static void vboxNetLwfWinDestroySG(PINTNETSG pSG)
+{
+ NdisFreeMemory(pSG, 0, 0);
+ Log4(("vboxNetLwfWinDestroySG: freed SG 0x%p\n", pSG));
+}
+
+/**
+ * Worker for vboxNetLwfWinNBtoSG() that gets the max segment count needed.
+ * @note vboxNetLwfWinNBtoSG may use fewer depending on cbPacket and offset!
+ * @note vboxNetAdpWinCalcSegments() is a copy of this code.
+ */
+DECLINLINE(ULONG) vboxNetLwfWinCalcSegments(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;
+}
+
+DECLINLINE(void) vboxNetLwfWinFreeMdlChain(PMDL pMdl)
+{
+#ifndef VBOXNETLWF_FIXED_SIZE_POOLS
+ PMDL pMdlNext;
+ while (pMdl)
+ {
+ pMdlNext = pMdl->Next;
+# ifndef VBOXNETLWF_SYNC_SEND
+ PUCHAR pDataBuf;
+ ULONG cb = 0;
+ NdisQueryMdl(pMdl, &pDataBuf, &cb, NormalPagePriority);
+# endif /* !VBOXNETLWF_SYNC_SEND */
+ NdisFreeMdl(pMdl);
+ Log4(("vboxNetLwfWinFreeMdlChain: freed MDL 0x%p\n", pMdl));
+# ifndef VBOXNETLWF_SYNC_SEND
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetLwfWinFreeMdlChain: freed data buffer 0x%p\n", pDataBuf));
+# endif /* !VBOXNETLWF_SYNC_SEND */
+ pMdl = pMdlNext;
+ }
+#else /* VBOXNETLWF_FIXED_SIZE_POOLS */
+ RT_NOREF1(pMdl);
+#endif /* VBOXNETLWF_FIXED_SIZE_POOLS */
+}
+
+/** @todo
+ * 1) Copy data from SG to MDL (if we decide to complete asynchronously).
+ * 2) Provide context/backfill space. Nobody does it, should we?
+ * 3) We always get a single segment from intnet. Simplify?
+ */
+static PNET_BUFFER_LIST vboxNetLwfWinSGtoNB(PVBOXNETLWF_MODULE pModule, PINTNETSG pSG)
+{
+ AssertReturn(pSG->cSegsUsed >= 1, NULL);
+ LogFlow(("==>vboxNetLwfWinSGtoNB: segments=%d hPool=%p cb=%u\n", pSG->cSegsUsed,
+ pModule->hPool, pSG->cbTotal));
+ AssertReturn(pModule->hPool, NULL);
+
+#ifdef VBOXNETLWF_SYNC_SEND
+ PINTNETSEG pSeg = pSG->aSegs;
+ PMDL pMdl = NdisAllocateMdl(pModule->hFilter, pSeg->pv, pSeg->cb);
+ if (!pMdl)
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL\n"));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ Log4(("vboxNetLwfWinSGtoNB: allocated Mdl 0x%p\n", pMdl));
+ PMDL pMdlCurr = pMdl;
+ for (int i = 1; i < pSG->cSegsUsed; i++)
+ {
+ pSeg = &pSG->aSegs[i];
+ pMdlCurr->Next = NdisAllocateMdl(pModule->hFilter, pSeg->pv, pSeg->cb);
+ if (!pMdlCurr->Next)
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL\n"));
+ /* Tear down all MDL we chained so far */
+ vboxNetLwfWinFreeMdlChain(pMdl);
+ return NULL;
+ }
+ pMdlCurr = pMdlCurr->Next;
+ Log4(("vboxNetLwfWinSGtoNB: allocated Mdl 0x%p\n", pMdlCurr));
+ }
+ PNET_BUFFER_LIST pBufList = NdisAllocateNetBufferAndNetBufferList(pModule->hPool,
+ 0 /* ContextSize */,
+ 0 /* ContextBackFill */,
+ pMdl,
+ 0 /* DataOffset */,
+ pSG->cbTotal);
+ if (pBufList)
+ {
+ Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pModule->hFilter;
+ /** @todo Do we need to initialize anything else? */
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an NBL+NB\n"));
+ vboxNetLwfWinFreeMdlChain(pMdl);
+ }
+#else /* !VBOXNETLWF_SYNC_SEND */
+
+# ifdef VBOXNETLWF_FIXED_SIZE_POOLS
+ int iPool = 0;
+ ULONG cbFrame = VBOXNETLWF_MAX_FRAME_SIZE(pSG->cbTotal);
+ /* Let's find the appropriate pool first */
+ for (iPool = 0; iPool < RT_ELEMENTS(g_cbPool); ++iPool)
+ if (cbFrame <= g_cbPool[iPool])
+ break;
+ if (iPool >= RT_ELEMENTS(g_cbPool))
+ {
+ LogError(("vboxNetLwfWinSGtoNB: frame is too big (%u > %u), drop it.\n", cbFrame, g_cbPool[RT_ELEMENTS(g_cbPool)-1]));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ PNET_BUFFER_LIST pBufList = NdisAllocateNetBufferList(pModule->hPool[iPool],
+ 0 /** @todo ContextSize */,
+ 0 /** @todo ContextBackFill */);
+ if (!pBufList)
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate netbuffer (cb=%u) from pool %d\n", cbFrame, iPool));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ const ULONG cbAlignmentMask = sizeof(USHORT) - 1; /* Microsoft LB/FO provider expects packets to be aligned at word boundary. */
+ ULONG cbAlignedFrame = (pSG->cbTotal + cbAlignmentMask) & ~cbAlignmentMask;
+ Assert(cbAlignedFrame >= pSG->cbTotal);
+ Assert(cbFrame >= cbAlignedFrame);
+ NET_BUFFER *pBuffer = NET_BUFFER_LIST_FIRST_NB(pBufList);
+ NDIS_STATUS Status = NdisRetreatNetBufferDataStart(pBuffer, cbAlignedFrame, 0 /** @todo DataBackfill */, NULL);
+ if (cbAlignedFrame - pSG->cbTotal > 0)
+ {
+ /* Make sure padding zeros do not get to the wire. */
+ if (NET_BUFFER_DATA_LENGTH(pBuffer) != cbAlignedFrame)
+ vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 11);
+ else
+ NET_BUFFER_DATA_LENGTH(pBuffer) = pSG->cbTotal;
+ }
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ uint8_t *pDst = (uint8_t*)NdisGetDataBuffer(pBuffer, pSG->cbTotal, NULL, 1, 0);
+ if (pDst)
+ {
+ for (int i = 0; i < pSG->cSegsUsed; i++)
+ {
+ NdisMoveMemory(pDst, pSG->aSegs[i].pv, pSG->aSegs[i].cb);
+ pDst += pSG->aSegs[i].cb;
+ }
+ Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pModule->hFilter;
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to obtain the buffer pointer (size=%u)\n", pSG->cbTotal));
+ NdisAdvanceNetBufferDataStart(pBuffer, cbAlignedFrame, false, NULL); /** @todo why bother? */
+ NdisFreeNetBufferList(pBufList);
+ pBufList = NULL;
+ }
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: NdisRetreatNetBufferDataStart failed with 0x%x (size=%u)\n", Status, pSG->cbTotal));
+ NdisFreeNetBufferList(pBufList);
+ pBufList = NULL;
+ }
+# else /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+ PNET_BUFFER_LIST pBufList = NULL;
+ ULONG cbMdl = VBOXNETLWF_MAX_FRAME_SIZE(pSG->cbTotal);
+ ULONG uDataOffset = cbMdl - pSG->cbTotal;
+ PUCHAR pDataBuf = (PUCHAR)NdisAllocateMemoryWithTagPriority(pModule->hFilter, cbMdl,
+ VBOXNETLWF_MEM_TAG, NormalPoolPriority);
+ if (pDataBuf)
+ {
+ Log4(("vboxNetLwfWinSGtoNB: allocated data buffer (cb=%u) 0x%p\n", cbMdl, pDataBuf));
+ PMDL pMdl = NdisAllocateMdl(pModule->hFilter, pDataBuf, cbMdl);
+ if (!pMdl)
+ {
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetLwfWinSGtoNB: freed data buffer 0x%p\n", pDataBuf));
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an MDL (cb=%u)\n", cbMdl));
+ LogFlow(("<==vboxNetLwfWinSGtoNB: 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(pModule->hPool,
+ 0 /* ContextSize */,
+ 0 /* ContextBackFill */,
+ pMdl,
+ uDataOffset,
+ pSG->cbTotal);
+ if (pBufList)
+ {
+ Log4(("vboxNetLwfWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pModule->hFilter;
+ /** @todo Do we need to initialize anything else? */
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate an NBL+NB\n"));
+ vboxNetLwfWinFreeMdlChain(pMdl);
+ }
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinSGtoNB: failed to allocate data buffer (size=%u)\n", cbMdl));
+ }
+# endif /* !VBOXNETLWF_FIXED_SIZE_POOLS */
+
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ LogFlow(("<==vboxNetLwfWinSGtoNB: return %p\n", pBufList));
+ return pBufList;
+}
+
+/**
+ * @note vboxNetAdpWinNBtoSG() is a copy of this code.
+ */
+static PINTNETSG vboxNetLwfWinNBtoSG(PVBOXNETLWF_MODULE pModule, PNET_BUFFER pNetBuf)
+{
+ ULONG cbPacket = NET_BUFFER_DATA_LENGTH(pNetBuf);
+ ULONG cSegs = vboxNetLwfWinCalcSegments(pNetBuf);
+ /* Allocate and initialize SG */
+ PINTNETSG pSG = (PINTNETSG)NdisAllocateMemoryWithTagPriority(pModule->hFilter,
+ RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]),
+ VBOXNETLWF_MEM_TAG,
+ NormalPoolPriority);
+ AssertReturn(pSG, pSG);
+ Log4(("vboxNetLwfWinNBtoSG: 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)
+ {
+ vboxNetLwfWinDestroySG(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 */
+ vboxNetLwfWinDestroySG(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;
+}
+
+VOID vboxNetLwfWinStatus(IN NDIS_HANDLE hModuleCtx, IN PNDIS_STATUS_INDICATION pIndication)
+{
+ LogFlow(("==>vboxNetLwfWinStatus: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)hModuleCtx;
+ Log(("vboxNetLwfWinStatus: Got status indication: %s\n", vboxNetLwfWinStatusToText(pIndication->StatusCode)));
+ switch (pIndication->StatusCode)
+ {
+ case NDIS_STATUS_PACKET_FILTER:
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pIndication->StatusBuffer);
+ vboxNetLwfWinOverridePacketFiltersUp(pModuleCtx, (ULONG*)pIndication->StatusBuffer);
+ Log(("vboxNetLwfWinStatus: Reporting status: %s\n", vboxNetLwfWinStatusToText(pIndication->StatusCode)));
+ vboxNetLwfWinDumpFilterTypes(*(ULONG*)pIndication->StatusBuffer);
+ break;
+ case NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
+ Log5(("vboxNetLwfWinStatus: offloading currently set to:\n"));
+ vboxNetLwfWinDumpOffloadSettings((PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ vboxNetLwfWinUpdateSavedOffloadConfig(pModuleCtx, (PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ vboxNetLwfWinDisableOffloading((PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ Log5(("vboxNetLwfWinStatus: reporting offloading up as:\n"));
+ vboxNetLwfWinDumpOffloadSettings((PNDIS_OFFLOAD)pIndication->StatusBuffer);
+ break;
+ }
+ NdisFIndicateStatus(pModuleCtx->hFilter, pIndication);
+ LogFlow(("<==vboxNetLwfWinStatus\n"));
+}
+
+static bool vboxNetLwfWinForwardToIntNet(PVBOXNETLWF_MODULE pModuleCtx, PNET_BUFFER_LIST pBufLists, uint32_t fSrc)
+{
+ /* We must not forward anything to the trunk unless it is ready to receive. */
+ if (!ASMAtomicReadBool(&pModuleCtx->fActive))
+ {
+ Log(("vboxNetLwfWinForwardToIntNet: trunk is inactive, won't forward\n"));
+ return false;
+ }
+ /* Some NPF protocols make NDIS to loop back packets at miniport level, we must ignore those. */
+ if (NdisTestNblFlag(pBufLists, NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET))
+ {
+ if (pBufLists->SourceHandle == pModuleCtx->hFilter && !pModuleCtx->fPassVmTrafficToHost)
+ {
+ /* Drop the packets we've injected. */
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinForwardToIntNet: dropping loopback", pBufLists);
+ return true;
+ }
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinForwardToIntNet: passing through loopback", pBufLists);
+ return false;
+ }
+
+ AssertReturn(pModuleCtx->pNetFlt, false);
+ AssertReturn(pModuleCtx->pNetFlt->pSwitchPort, false);
+ AssertReturn(pModuleCtx->pNetFlt->pSwitchPort->pfnRecv, false);
+ LogFlow(("==>vboxNetLwfWinForwardToIntNet: module=%p\n", pModuleCtx));
+ Assert(pBufLists); /* The chain must contain at least one list */
+ Assert(NET_BUFFER_LIST_NEXT_NBL(pBufLists) == NULL); /* The caller is supposed to unlink the list from the chain */
+ /*
+ * Even if NBL contains more than one buffer we are prepared to deal with it.
+ * When any of buffers should not be dropped we keep the whole list. It is
+ * better to leak some "unexpected" packets to the wire/host than to loose any.
+ */
+ bool fDropIt = false;
+ bool fDontDrop = false;
+ int nLists = 0;
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ int nBuffers = 0;
+ nLists++;
+ for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
+ {
+ nBuffers++;
+ PINTNETSG pSG = vboxNetLwfWinNBtoSG(pModuleCtx, pBuf);
+ if (pSG)
+ {
+ vboxNetLwfWinDumpPacket(pSG, (fSrc & INTNETTRUNKDIR_WIRE)?"intnet <-- wire":"intnet <-- host");
+ /* A bit paranoid, but we do not use any locks, so... */
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ if (pModuleCtx->pNetFlt->pSwitchPort->pfnRecv(pModuleCtx->pNetFlt->pSwitchPort, NULL, pSG, fSrc))
+ fDropIt = true;
+ else
+ fDontDrop = true;
+ vboxNetLwfWinDestroySG(pSG);
+ }
+ }
+ Log(("vboxNetLwfWinForwardToIntNet: list=%d buffers=%d\n", nLists, nBuffers));
+ }
+ Log(("vboxNetLwfWinForwardToIntNet: lists=%d drop=%s don't=%s\n", nLists, fDropIt ? "true":"false", fDontDrop ? "true":"false"));
+
+ /* If the host (and the user) wants to see all packets we must not drop any. */
+ if (pModuleCtx->fPassVmTrafficToHost && vboxNetLwfWinIsPromiscuous(pModuleCtx))
+ fDropIt = false;
+
+ LogFlow(("<==vboxNetLwfWinForwardToIntNet: return '%s'\n",
+ fDropIt ? (fDontDrop ? "do not drop (some)" : "drop it") : "do not drop (any)"));
+ return fDropIt && !fDontDrop; /* Drop the list if ALL its buffers are being dropped! */
+}
+
+DECLINLINE(bool) vboxNetLwfWinIsRunning(PVBOXNETLWF_MODULE pModule)
+{
+ Log(("vboxNetLwfWinIsRunning: state=%d\n", ASMAtomicReadU32(&pModule->enmState)));
+ return ASMAtomicReadU32(&pModule->enmState) == LwfState_Running;
+}
+
+VOID vboxNetLwfWinSendNetBufferLists(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN NDIS_PORT_NUMBER nPort, IN ULONG fFlags)
+{
+ LogFlow(("==>vboxNetLwfWinSendNetBufferLists: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: got", pBufLists);
+
+ if (!ASMAtomicReadBool(&pModule->fActive))
+ {
+ /*
+ * The trunk is inactive, jusp pass along all packets to the next
+ * underlying driver.
+ */
+ NdisFSendNetBufferLists(pModule->hFilter, pBufLists, nPort, fFlags);
+ return;
+ }
+
+ if (vboxNetLwfWinIsRunning(pModule))
+ {
+ PNET_BUFFER_LIST pNext = NULL;
+ PNET_BUFFER_LIST pDropHead = NULL;
+ PNET_BUFFER_LIST pDropTail = NULL;
+ PNET_BUFFER_LIST pPassHead = NULL;
+ PNET_BUFFER_LIST pPassTail = NULL;
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = pNext)
+ {
+ pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
+ NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink */
+ if (vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_HOST))
+ {
+ NET_BUFFER_LIST_STATUS(pList) = NDIS_STATUS_SUCCESS;
+ if (pDropHead)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pDropTail) = pList;
+ pDropTail = pList;
+ }
+ else
+ pDropHead = pDropTail = pList;
+ }
+ else
+ {
+ if (pPassHead)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pPassTail) = pList;
+ pPassTail = pList;
+ }
+ else
+ pPassHead = pPassTail = pList;
+ }
+ }
+ Assert((pBufLists == pPassHead) || (pBufLists == pDropHead));
+ if (pPassHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: passing down", pPassHead);
+ NdisFSendNetBufferLists(pModule->hFilter, pBufLists, nPort, fFlags);
+ }
+ if (pDropHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: consumed", pDropHead);
+ NdisFSendNetBufferListsComplete(pModule->hFilter, pDropHead,
+ fFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+ }
+ }
+ else
+ {
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ NET_BUFFER_LIST_STATUS(pList) = NDIS_STATUS_PAUSED;
+ }
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinSendNetBufferLists: consumed", pBufLists);
+ NdisFSendNetBufferListsComplete(pModule->hFilter, pBufLists,
+ fFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL ? NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+
+ }
+ LogFlow(("<==vboxNetLwfWinSendNetBufferLists\n"));
+}
+
+VOID vboxNetLwfWinSendNetBufferListsComplete(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN ULONG fFlags)
+{
+ LogFlow(("==>vboxNetLwfWinSendNetBufferListsComplete: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNET_BUFFER_LIST pList = pBufLists;
+ PNET_BUFFER_LIST pNextList;
+ PNET_BUFFER_LIST pPrevList = NULL;
+ while (pList)
+ {
+ pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
+ if (pList->SourceHandle == pModule->hFilter)
+ {
+ /* We allocated this NET_BUFFER_LIST, let's free it up */
+ Assert(NET_BUFFER_LIST_FIRST_NB(pList));
+ Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /*
+ * All our NBLs hold a single NB each, no need to iterate over a list.
+ * There is no need to free an associated NB explicitly either, as it was
+ * preallocated with NBL structure.
+ */
+ Assert(!NET_BUFFER_NEXT_NB(NET_BUFFER_LIST_FIRST_NB(pList)));
+ vboxNetLwfWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /* Unlink this list from the chain */
+ if (pPrevList)
+ NET_BUFFER_LIST_NEXT_NBL(pPrevList) = pNextList;
+ else
+ pBufLists = pNextList;
+ Log(("vboxNetLwfWinSendNetBufferListsComplete: our list %p, next=%p, previous=%p, head=%p\n", pList, pNextList, pPrevList, pBufLists));
+ NdisFreeNetBufferList(pList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ Log4(("vboxNetLwfWinSendNetBufferListsComplete: freed NBL+NB 0x%p\n", pList));
+ KeSetEvent(&pModule->EventWire, 0, FALSE);
+#else /* !VBOXNETLWF_SYNC_SEND */
+ Log4(("vboxNetLwfWinSendNetBufferListsComplete: freed NBL+NB+MDL+Data 0x%p\n", pList));
+ Assert(ASMAtomicReadS32(&pModule->cPendingBuffers) > 0);
+ if (ASMAtomicDecS32(&pModule->cPendingBuffers) == 0)
+ NdisSetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ }
+ else
+ {
+ pPrevList = pList;
+ Log(("vboxNetLwfWinSendNetBufferListsComplete: passing list %p, next=%p, previous=%p, head=%p\n", pList, pNextList, pPrevList, pBufLists));
+ }
+ pList = pNextList;
+ }
+ if (pBufLists)
+ {
+ /* There are still lists remaining in the chain, pass'em up */
+ NdisFSendNetBufferListsComplete(pModule->hFilter, pBufLists, fFlags);
+ }
+ LogFlow(("<==vboxNetLwfWinSendNetBufferListsComplete\n"));
+}
+
+VOID vboxNetLwfWinReceiveNetBufferLists(IN NDIS_HANDLE hModuleCtx,
+ IN PNET_BUFFER_LIST pBufLists,
+ IN NDIS_PORT_NUMBER nPort,
+ IN ULONG nBufLists,
+ IN ULONG fFlags)
+{
+ /// @todo Do we need loopback handling?
+ LogFlow(("==>vboxNetLwfWinReceiveNetBufferLists: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: got", pBufLists);
+
+ if (!ASMAtomicReadBool(&pModule->fActive))
+ {
+ /*
+ * The trunk is inactive, just pass along all packets to the next
+ * overlying driver.
+ */
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pBufLists, nPort, nBufLists, fFlags);
+ LogFlow(("<==vboxNetLwfWinReceiveNetBufferLists: inactive trunk\n"));
+ return;
+ }
+
+ if (vboxNetLwfWinIsRunning(pModule))
+ {
+ if (NDIS_TEST_RECEIVE_CANNOT_PEND(fFlags))
+ {
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ PNET_BUFFER_LIST pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
+ NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink temporarily */
+ if (!vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_WIRE))
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: passing up", pList);
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pList, nPort, nBufLists, fFlags);
+ }
+ NET_BUFFER_LIST_NEXT_NBL(pList) = pNext; /* Restore the link */
+ }
+ }
+ else
+ {
+ /* We collect dropped NBLs in a separate list in order to "return" them. */
+ PNET_BUFFER_LIST pNext = NULL;
+ PNET_BUFFER_LIST pDropHead = NULL;
+ PNET_BUFFER_LIST pDropTail = NULL;
+ PNET_BUFFER_LIST pPassHead = NULL;
+ PNET_BUFFER_LIST pPassTail = NULL;
+ ULONG nDrop = 0, nPass = 0;
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = pNext)
+ {
+ pNext = NET_BUFFER_LIST_NEXT_NBL(pList);
+ NET_BUFFER_LIST_NEXT_NBL(pList) = NULL; /* Unlink */
+ if (vboxNetLwfWinForwardToIntNet(pModule, pList, INTNETTRUNKDIR_WIRE))
+ {
+ if (nDrop++)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pDropTail) = pList;
+ pDropTail = pList;
+ }
+ else
+ pDropHead = pDropTail = pList;
+ }
+ else
+ {
+ if (nPass++)
+ {
+ NET_BUFFER_LIST_NEXT_NBL(pPassTail) = pList;
+ pPassTail = pList;
+ }
+ else
+ pPassHead = pPassTail = pList;
+ }
+ }
+ Assert((pBufLists == pPassHead) || (pBufLists == pDropHead));
+ Assert(nDrop + nPass == nBufLists);
+ if (pPassHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: passing up", pPassHead);
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pPassHead, nPort, nPass, fFlags);
+ }
+ if (pDropHead)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: consumed", pDropHead);
+ NdisFReturnNetBufferLists(pModule->hFilter, pDropHead,
+ fFlags & NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0);
+ }
+ }
+
+ }
+ else
+ {
+ vboxNetLwfWinDumpPackets("vboxNetLwfWinReceiveNetBufferLists: consumed", pBufLists);
+ if ((fFlags & NDIS_RECEIVE_FLAGS_RESOURCES) == 0)
+ NdisFReturnNetBufferLists(pModule->hFilter, pBufLists,
+ fFlags & NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL ? NDIS_RETURN_FLAGS_DISPATCH_LEVEL : 0);
+ }
+ LogFlow(("<==vboxNetLwfWinReceiveNetBufferLists\n"));
+}
+
+VOID vboxNetLwfWinReturnNetBufferLists(IN NDIS_HANDLE hModuleCtx, IN PNET_BUFFER_LIST pBufLists, IN ULONG fFlags)
+{
+ LogFlow(("==>vboxNetLwfWinReturnNetBufferLists: module=%p\n", hModuleCtx));
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)hModuleCtx;
+ PNET_BUFFER_LIST pList = pBufLists;
+ PNET_BUFFER_LIST pNextList;
+ PNET_BUFFER_LIST pPrevList = NULL;
+ /** @todo Move common part into a separate function to be used by vboxNetLwfWinSendNetBufferListsComplete() as well */
+ while (pList)
+ {
+ pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
+ if (pList->SourceHandle == pModule->hFilter)
+ {
+ /* We allocated this NET_BUFFER_LIST, let's free it up */
+ Assert(NET_BUFFER_LIST_FIRST_NB(pList));
+ Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /*
+ * All our NBLs hold a single NB each, no need to iterate over a list.
+ * There is no need to free an associated NB explicitly either, as it was
+ * preallocated with NBL structure.
+ */
+ vboxNetLwfWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ /* Unlink this list from the chain */
+ if (pPrevList)
+ NET_BUFFER_LIST_NEXT_NBL(pPrevList) = pNextList;
+ else
+ pBufLists = pNextList;
+ NdisFreeNetBufferList(pList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB 0x%p\n", pList));
+ KeSetEvent(&pModule->EventHost, 0, FALSE);
+#else /* !VBOXNETLWF_SYNC_SEND */
+ Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB+MDL+Data 0x%p\n", pList));
+ Assert(ASMAtomicReadS32(&pModule->cPendingBuffers) > 0);
+ if (ASMAtomicDecS32(&pModule->cPendingBuffers) == 0)
+ NdisSetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ }
+ else
+ pPrevList = pList;
+ pList = pNextList;
+ }
+ if (pBufLists)
+ {
+ /* There are still lists remaining in the chain, pass'em up */
+ NdisFReturnNetBufferLists(pModule->hFilter, pBufLists, fFlags);
+ }
+ LogFlow(("<==vboxNetLwfWinReturnNetBufferLists\n"));
+}
+
+/**
+ * register the filter driver
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetLwfWinRegister(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
+{
+ RT_NOREF1(pRegistryPathStr);
+ NDIS_FILTER_DRIVER_CHARACTERISTICS FChars;
+ NDIS_STRING FriendlyName;
+ NDIS_STRING UniqueName;
+ NDIS_STRING ServiceName;
+
+ NdisInitUnicodeString(&FriendlyName, VBOXNETLWF_NAME_FRIENDLY);
+ NdisInitUnicodeString(&UniqueName, VBOXNETLWF_NAME_UNIQUE);
+ NdisInitUnicodeString(&ServiceName, VBOXNETLWF_NAME_SERVICE);
+
+ NdisZeroMemory(&FChars, sizeof (FChars));
+
+ FChars.Header.Type = NDIS_OBJECT_TYPE_FILTER_DRIVER_CHARACTERISTICS;
+ FChars.Header.Size = sizeof(NDIS_FILTER_DRIVER_CHARACTERISTICS);
+ FChars.Header.Revision = NDIS_FILTER_CHARACTERISTICS_REVISION_1;
+
+ FChars.MajorNdisVersion = VBOXNETLWF_VERSION_NDIS_MAJOR;
+ FChars.MinorNdisVersion = VBOXNETLWF_VERSION_NDIS_MINOR;
+
+ FChars.FriendlyName = FriendlyName;
+ FChars.UniqueName = UniqueName;
+ FChars.ServiceName = ServiceName;
+
+ /* Mandatory functions */
+ FChars.AttachHandler = vboxNetLwfWinAttach;
+ FChars.DetachHandler = vboxNetLwfWinDetach;
+ FChars.RestartHandler = vboxNetLwfWinRestart;
+ FChars.PauseHandler = vboxNetLwfWinPause;
+
+ /* Optional functions, non changeble at run-time */
+ FChars.OidRequestHandler = vboxNetLwfWinOidRequest;
+ FChars.OidRequestCompleteHandler = vboxNetLwfWinOidRequestComplete;
+ //FChars.CancelOidRequestHandler = vboxNetLwfWinCancelOidRequest;
+ FChars.StatusHandler = vboxNetLwfWinStatus;
+ //FChars.NetPnPEventHandler = vboxNetLwfWinPnPEvent;
+
+ /* Datapath functions */
+ FChars.SendNetBufferListsHandler = vboxNetLwfWinSendNetBufferLists;
+ FChars.SendNetBufferListsCompleteHandler = vboxNetLwfWinSendNetBufferListsComplete;
+ FChars.ReceiveNetBufferListsHandler = vboxNetLwfWinReceiveNetBufferLists;
+ FChars.ReturnNetBufferListsHandler = vboxNetLwfWinReturnNetBufferLists;
+
+ pDriverObject->DriverUnload = vboxNetLwfWinUnloadDriver;
+
+ NDIS_STATUS Status;
+ g_VBoxNetLwfGlobals.hFilterDriver = NULL;
+ Log(("vboxNetLwfWinRegister: registering filter driver...\n"));
+ Status = NdisFRegisterFilterDriver(pDriverObject,
+ (NDIS_HANDLE)&g_VBoxNetLwfGlobals,
+ &FChars,
+ &g_VBoxNetLwfGlobals.hFilterDriver);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Log(("vboxNetLwfWinRegister: successfully registered filter driver; registering device...\n"));
+ Status = vboxNetLwfWinDevCreate(&g_VBoxNetLwfGlobals);
+ Assert(Status == STATUS_SUCCESS);
+ Log(("vboxNetLwfWinRegister: vboxNetLwfWinDevCreate() returned 0x%x\n", Status));
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinRegister: failed to register filter driver, status=0x%x", Status));
+ }
+ return Status;
+}
+
+static int vboxNetLwfWinStartInitIdcThread()
+{
+ int rc = VERR_INVALID_STATE;
+
+ if (ASMAtomicCmpXchgU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Connecting, LwfIdcState_Disconnected))
+ {
+ Log(("vboxNetLwfWinStartInitIdcThread: IDC state change Diconnected -> Connecting\n"));
+
+ NTSTATUS Status = PsCreateSystemThread(&g_VBoxNetLwfGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ vboxNetLwfWinInitIdcWorker,
+ &g_VBoxNetLwfGlobals);
+ Log(("vboxNetLwfWinStartInitIdcThread: create IDC initialization thread, status=0x%x\n", Status));
+ if (Status != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetLwfWinStartInitIdcThread: IDC initialization failed (system thread creation, status=0x%x)\n", Status));
+ /*
+ * We failed to init IDC and there will be no second chance.
+ */
+ Log(("vboxNetLwfWinStartInitIdcThread: IDC state change Connecting -> Diconnected\n"));
+ ASMAtomicWriteU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Disconnected);
+ }
+ rc = RTErrConvertFromNtStatus(Status);
+ }
+ return rc;
+}
+
+static void vboxNetLwfWinStopInitIdcThread()
+{
+}
+
+
+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;
+
+ /* the idc registration is initiated via IOCTL since our driver
+ * can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
+ rc = vboxNetLwfWinInitBase();
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ NdisZeroMemory(&g_VBoxNetLwfGlobals, sizeof (g_VBoxNetLwfGlobals));
+ RTListInit(&g_VBoxNetLwfGlobals.listModules);
+ NdisAllocateSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ /*
+ * We choose to ignore IDC initialization errors here because if we fail to load
+ * our filter the upper protocols won't bind to the associated adapter, causing
+ * network failure at the host. Better to have non-working filter than broken
+ * networking on the host.
+ */
+ rc = vboxNetLwfWinStartInitIdcThread();
+ AssertRC(rc);
+
+ Status = vboxNetLwfWinRegister(pDriverObject, pRegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Log(("NETLWF: started successfully\n"));
+ return STATUS_SUCCESS;
+ }
+ NdisFreeSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ vboxNetLwfWinFini();
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+
+
+static VOID vboxNetLwfWinUnloadDriver(IN PDRIVER_OBJECT pDriver)
+{
+ RT_NOREF1(pDriver);
+ LogFlow(("==>vboxNetLwfWinUnloadDriver: driver=%p\n", pDriver));
+ vboxNetLwfWinDevDestroy(&g_VBoxNetLwfGlobals);
+ NdisFDeregisterFilterDriver(g_VBoxNetLwfGlobals.hFilterDriver);
+ NdisFreeSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ LogFlow(("<==vboxNetLwfWinUnloadDriver\n"));
+ vboxNetLwfWinFini();
+}
+
+static const char *vboxNetLwfWinIdcStateToText(uint32_t enmState)
+{
+ switch (enmState)
+ {
+ case LwfIdcState_Disconnected: return "Disconnected";
+ case LwfIdcState_Connecting: return "Connecting";
+ case LwfIdcState_Connected: return "Connected";
+ case LwfIdcState_Stopping: return "Stopping";
+ }
+ return "Unknown";
+}
+
+static VOID vboxNetLwfWinInitIdcWorker(PVOID pvContext)
+{
+ int rc;
+ PVBOXNETLWFGLOBALS pGlobals = (PVBOXNETLWFGLOBALS)pvContext;
+
+ while (ASMAtomicReadU32(&pGlobals->enmIdcState) == LwfIdcState_Connecting)
+ {
+ rc = vboxNetFltInitIdc(&g_VBoxNetFltGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ if (!ASMAtomicCmpXchgU32(&pGlobals->enmIdcState, LwfIdcState_Connected, LwfIdcState_Connecting))
+ {
+ /* The state has been changed (the only valid transition is to "Stopping"), undo init */
+ rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
+ Log(("vboxNetLwfWinInitIdcWorker: state change (Connecting -> %s) while initializing IDC, deleted IDC, rc=0x%x\n",
+ vboxNetLwfWinIdcStateToText(ASMAtomicReadU32(&pGlobals->enmIdcState)), rc));
+ }
+ else
+ {
+ Log(("vboxNetLwfWinInitIdcWorker: IDC state change Connecting -> Connected\n"));
+ }
+ }
+ else
+ {
+ LARGE_INTEGER WaitIn100nsUnits;
+ WaitIn100nsUnits.QuadPart = -(LONGLONG)10000000; /* 1 sec */
+ KeDelayExecutionThread(KernelMode, FALSE /* non-alertable */, &WaitIn100nsUnits);
+ }
+ }
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+static int vboxNetLwfWinTryFiniIdc()
+{
+ int rc = VINF_SUCCESS;
+ NTSTATUS Status;
+ PKTHREAD pThread = NULL;
+ uint32_t enmPrevState = ASMAtomicXchgU32(&g_VBoxNetLwfGlobals.enmIdcState, LwfIdcState_Stopping);
+
+ Log(("vboxNetLwfWinTryFiniIdc: IDC state change %s -> Stopping\n", vboxNetLwfWinIdcStateToText(enmPrevState)));
+
+ switch (enmPrevState)
+ {
+ case LwfIdcState_Disconnected:
+ /* Have not even attempted to connect -- nothing to do. */
+ break;
+ case LwfIdcState_Stopping:
+ /* Impossible, but another thread is alreading doing FiniIdc, bail out */
+ LogError(("vboxNetLwfWinTryFiniIdc: called in 'Stopping' state\n"));
+ rc = VERR_INVALID_STATE;
+ break;
+ case LwfIdcState_Connecting:
+ /* the worker thread is running, let's wait for it to stop */
+ Status = ObReferenceObjectByHandle(g_VBoxNetLwfGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS, NULL, KernelMode,
+ (PVOID*)&pThread, NULL);
+ if (Status == STATUS_SUCCESS)
+ {
+ KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
+ ObDereferenceObject(pThread);
+ }
+ else
+ {
+ LogError(("vboxNetLwfWinTryFiniIdc: ObReferenceObjectByHandle(%p) failed with 0x%x\n",
+ g_VBoxNetLwfGlobals.hInitIdcThread, Status));
+ }
+ rc = RTErrConvertFromNtStatus(Status);
+ break;
+ case LwfIdcState_Connected:
+ /* the worker succeeded in IDC init and terminated */
+ rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
+ Log(("vboxNetLwfWinTryFiniIdc: deleted IDC, rc=0x%x\n", rc));
+ break;
+ }
+ return rc;
+}
+
+static void vboxNetLwfWinFiniBase()
+{
+ vboxNetFltDeleteGlobals(&g_VBoxNetFltGlobals);
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+
+ RTR0Term();
+}
+
+static int vboxNetLwfWinInitBase()
+{
+ int rc = RTR0Init(0);
+ if (!RT_SUCCESS(rc))
+ return rc;
+
+ memset(&g_VBoxNetFltGlobals, 0, sizeof(g_VBoxNetFltGlobals));
+ rc = vboxNetFltInitGlobals(&g_VBoxNetFltGlobals);
+ if (!RT_SUCCESS(rc))
+ RTR0Term();
+
+ return rc;
+}
+
+static int vboxNetLwfWinFini()
+{
+ int rc = vboxNetLwfWinTryFiniIdc();
+ if (RT_SUCCESS(rc))
+ {
+ vboxNetLwfWinFiniBase();
+ }
+ return rc;
+}
+
+
+/*
+ *
+ * The OS specific interface definition
+ *
+ */
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltOsMaybeRediscovered: instance=%p\n", pThis));
+ LogFlow(("<==vboxNetFltOsMaybeRediscovered: return %RTbool\n", !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)));
+ /* AttachToInterface true if disconnected */
+ return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
+}
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
+{
+ RT_NOREF1(pvIfData);
+ int rc = VINF_SUCCESS;
+
+ PVBOXNETLWF_MODULE pModule = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
+ LogFlow(("==>vboxNetFltPortOsXmit: instance=%p module=%p\n", pThis, pModule));
+ if (!pModule)
+ {
+ LogFlow(("<==vboxNetFltPortOsXmit: pModule is null, return %d\n", VERR_INTERNAL_ERROR));
+ return VERR_INTERNAL_ERROR;
+ }
+ /* Prevent going into "paused" state until all transmissions have been completed. */
+ NDIS_WAIT_FOR_MUTEX(&pModule->InTransmit);
+ /* Ignore all sends if the stack is paused or being paused, etc... */
+ if (!vboxNetLwfWinIsRunning(pModule))
+ {
+ NDIS_RELEASE_MUTEX(&pModule->InTransmit);
+ return VINF_SUCCESS;
+ }
+
+ vboxNetLwfWinDumpPacket(pSG, !(fDst & INTNETTRUNKDIR_WIRE) ? "intnet --> host"
+ : !(fDst & INTNETTRUNKDIR_HOST) ? "intnet --> wire" : "intnet --> all");
+
+ /*
+ * There are two possible strategies to deal with incoming SGs:
+ * 1) make a copy of data and complete asynchronously;
+ * 2) complete synchronously using the original data buffers.
+ * Before we consider implementing (1) it is quite interesting to see
+ * how well (2) performs. So we block until our requests are complete.
+ * Actually there is third possibility -- to use SG retain/release
+ * callbacks, but those seem not be fully implemented yet.
+ * Note that ansynchronous completion will require different implementation
+ * of vboxNetLwfWinPause(), not relying on InTransmit mutex.
+ */
+#ifdef VBOXNETLWF_SYNC_SEND
+ PVOID aEvents[2]; /* To wire and to host */
+ ULONG nEvents = 0;
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = -(LONGLONG)10000000; /* 1 sec */
+#endif /* VBOXNETLWF_SYNC_SEND */
+ if (fDst & INTNETTRUNKDIR_WIRE)
+ {
+ PNET_BUFFER_LIST pBufList = vboxNetLwfWinSGtoNB(pModule, pSG);
+ if (pBufList)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetFltPortOsXmit: sending down", pBufList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ aEvents[nEvents++] = &pModule->EventWire;
+#else /* !VBOXNETLWF_SYNC_SEND */
+ if (ASMAtomicIncS32(&pModule->cPendingBuffers) == 1)
+ NdisResetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ NdisFSendNetBufferLists(pModule->hFilter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 0); /** @todo sendFlags! */
+ }
+ }
+ if (fDst & INTNETTRUNKDIR_HOST)
+ {
+ PNET_BUFFER_LIST pBufList = vboxNetLwfWinSGtoNB(pModule, pSG);
+ if (pBufList)
+ {
+ vboxNetLwfWinDumpPackets("vboxNetFltPortOsXmit: sending up", pBufList);
+#ifdef VBOXNETLWF_SYNC_SEND
+ aEvents[nEvents++] = &pModule->EventHost;
+#else /* !VBOXNETLWF_SYNC_SEND */
+ if (ASMAtomicIncS32(&pModule->cPendingBuffers) == 1)
+ NdisResetEvent(&pModule->EventSendComplete);
+#endif /* !VBOXNETLWF_SYNC_SEND */
+ NdisFIndicateReceiveNetBufferLists(pModule->hFilter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 1, 0);
+ }
+ }
+#ifdef VBOXNETLWF_SYNC_SEND
+ if (nEvents)
+ {
+ NTSTATUS Status = KeWaitForMultipleObjects(nEvents, aEvents, WaitAll, Executive, KernelMode, FALSE, &timeout, NULL);
+ if (Status != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetFltPortOsXmit: KeWaitForMultipleObjects() failed with 0x%x\n", Status));
+ if (Status == STATUS_TIMEOUT)
+ rc = VERR_TIMEOUT;
+ else
+ rc = RTErrConvertFromNtStatus(Status);
+ }
+ }
+#endif /* VBOXNETLWF_SYNC_SEND */
+ NDIS_RELEASE_MUTEX(&pModule->InTransmit);
+
+ LogFlow(("<==vboxNetFltPortOsXmit: return %d\n", rc));
+ return rc;
+}
+
+
+NDIS_IO_WORKITEM_FUNCTION vboxNetLwfWinToggleOffloading;
+
+VOID vboxNetLwfWinToggleOffloading(PVOID WorkItemContext, NDIS_HANDLE NdisIoWorkItemHandle)
+{
+ /* WARNING! Call this with IRQL=Passive! */
+ RT_NOREF1(NdisIoWorkItemHandle);
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)WorkItemContext;
+
+ if (ASMAtomicReadBool(&pModuleCtx->fActive))
+ {
+ /* Disable offloading temporarily by indicating offload config change. */
+ /** @todo Be sure to revise this when implementing offloading support! */
+ vboxNetLwfWinIndicateOffload(pModuleCtx, pModuleCtx->pDisabledOffloadConfig);
+ Log(("vboxNetLwfWinToggleOffloading: set offloading off\n"));
+ }
+ else
+ {
+ /* The filter is inactive -- restore offloading configuration. */
+ if (pModuleCtx->fOffloadConfigValid)
+ {
+ vboxNetLwfWinIndicateOffload(pModuleCtx, pModuleCtx->pSavedOffloadConfig);
+ Log(("vboxNetLwfWinToggleOffloading: restored offloading config\n"));
+ }
+ else
+ DbgPrint("VBoxNetLwf: no saved offload config to restore for %s\n", pModuleCtx->szMiniportName);
+ }
+}
+
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
+ LogFlow(("==>vboxNetFltPortOsSetActive: instance=%p module=%p fActive=%RTbool\n", pThis, pModuleCtx, fActive));
+ if (!pModuleCtx)
+ {
+ LogFlow(("<==vboxNetFltPortOsSetActive: pModuleCtx is null\n"));
+ return;
+ }
+
+ NDIS_STATUS Status = STATUS_SUCCESS;
+ bool fOldActive = ASMAtomicXchgBool(&pModuleCtx->fActive, fActive);
+ if (fOldActive != fActive)
+ {
+ NdisQueueIoWorkItem(pModuleCtx->hWorkItem, vboxNetLwfWinToggleOffloading, pModuleCtx);
+ Status = vboxNetLwfWinSetPacketFilter(pModuleCtx, fActive);
+ LogFlow(("<==vboxNetFltPortOsSetActive: vboxNetLwfWinSetPacketFilter() returned 0x%x\n", Status));
+ }
+ else
+ LogFlow(("<==vboxNetFltPortOsSetActive: no change, remain %sactive\n", fActive ? "":"in"));
+}
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ RT_NOREF1(pThis);
+ LogFlow(("==>vboxNetFltOsDisconnectIt: instance=%p\n", pThis));
+ LogFlow(("<==vboxNetFltOsDisconnectIt: return 0\n"));
+ return VINF_SUCCESS;
+}
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ RT_NOREF1(pThis);
+ LogFlow(("==>vboxNetFltOsConnectIt: instance=%p\n", pThis));
+ LogFlow(("<==vboxNetFltOsConnectIt: return 0\n"));
+ return VINF_SUCCESS;
+}
+
+/*
+ * Uncommenting the following line produces debug log messages on IP address changes,
+ * including wired interfaces. No actual calls to a switch port are made. This is for
+ * debug purposes only!
+ * #define VBOXNETLWFWIN_DEBUGIPADDRNOTIF 1
+ */
+static void __stdcall vboxNetLwfWinIpAddrChangeCallback(IN PVOID pvCtx,
+ IN PMIB_UNICASTIPADDRESS_ROW pRow,
+ IN MIB_NOTIFICATION_TYPE enmNotifType)
+{
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvCtx;
+
+ /* We are only interested in add or remove notifications. */
+ bool fAdded;
+ if (enmNotifType == MibAddInstance)
+ fAdded = true;
+ else if (enmNotifType == MibDeleteInstance)
+ fAdded = false;
+ else
+ return;
+
+ if ( pRow
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ && pThis->pSwitchPort->pfnNotifyHostAddress
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ )
+ {
+ switch (pRow->Address.si_family)
+ {
+ case AF_INET:
+ if ( IN4_IS_ADDR_LINKLOCAL(&pRow->Address.Ipv4.sin_addr)
+ || pRow->Address.Ipv4.sin_addr.s_addr == IN4ADDR_LOOPBACK)
+ {
+ Log(("vboxNetLwfWinIpAddrChangeCallback: ignoring %s address (%RTnaipv4)\n",
+ pRow->Address.Ipv4.sin_addr.s_addr == IN4ADDR_LOOPBACK ? "loopback" : "link-local",
+ pRow->Address.Ipv4.sin_addr));
+ break;
+ }
+ Log(("vboxNetLwfWinIpAddrChangeCallback: %s IPv4 addr=%RTnaipv4 on luid=(%u,%u)\n",
+ fAdded ? "add" : "remove", pRow->Address.Ipv4.sin_addr,
+ pRow->InterfaceLuid.Info.IfType, pRow->InterfaceLuid.Info.NetLuidIndex));
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, fAdded, kIntNetAddrType_IPv4,
+ &pRow->Address.Ipv4.sin_addr);
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ break;
+ case AF_INET6:
+ if (Ipv6AddressScope(pRow->Address.Ipv6.sin6_addr.u.Byte) <= ScopeLevelLink)
+ {
+ Log(("vboxNetLwfWinIpAddrChangeCallback: ignoring link-local address (%RTnaipv6)\n",
+ &pRow->Address.Ipv6.sin6_addr));
+ break;
+ }
+ Log(("vboxNetLwfWinIpAddrChangeCallback: %s IPv6 addr=%RTnaipv6 scope=%d luid=(%u,%u)\n",
+ fAdded ? "add" : "remove", &pRow->Address.Ipv6.sin6_addr,
+ Ipv6AddressScope(pRow->Address.Ipv6.sin6_addr.u.Byte),
+ pRow->InterfaceLuid.Info.IfType, pRow->InterfaceLuid.Info.NetLuidIndex));
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ pThis->pSwitchPort->pfnNotifyHostAddress(pThis->pSwitchPort, fAdded, kIntNetAddrType_IPv6,
+ &pRow->Address.Ipv6.sin6_addr);
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ break;
+ }
+ }
+ else
+ Log(("vboxNetLwfWinIpAddrChangeCallback: pRow=%p pfnNotifyHostAddress=%p\n",
+ pRow, pThis->pSwitchPort->pfnNotifyHostAddress));
+}
+
+void vboxNetLwfWinRegisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetLwfWinRegisterIpAddrNotifier: instance=%p\n", pThis));
+ if ( pThis->pSwitchPort
+#ifndef VBOXNETLWFWIN_DEBUGIPADDRNOTIF
+ && pThis->pSwitchPort->pfnNotifyHostAddress
+#endif /* !VBOXNETLWFWIN_DEBUGIPADDRNOTIF */
+ )
+ {
+ NETIO_STATUS Status;
+ /* First we need to go over all host IP addresses and add them via pfnNotifyHostAddress. */
+ PMIB_UNICASTIPADDRESS_TABLE HostIpAddresses = NULL;
+ Status = GetUnicastIpAddressTable(AF_UNSPEC, &HostIpAddresses);
+ if (NETIO_SUCCESS(Status))
+ {
+ for (unsigned i = 0; i < HostIpAddresses->NumEntries; i++)
+ vboxNetLwfWinIpAddrChangeCallback(pThis, &HostIpAddresses->Table[i], MibAddInstance);
+ }
+ else
+ LogError(("vboxNetLwfWinRegisterIpAddrNotifier: GetUnicastIpAddressTable failed with %x\n", Status));
+ /* Now we can register a callback function to keep track of address changes. */
+ Status = NotifyUnicastIpAddressChange(AF_UNSPEC, vboxNetLwfWinIpAddrChangeCallback,
+ pThis, false, &pThis->u.s.WinIf.hNotifier);
+ if (NETIO_SUCCESS(Status))
+ Log(("vboxNetLwfWinRegisterIpAddrNotifier: notifier=%p\n", pThis->u.s.WinIf.hNotifier));
+ else
+ LogError(("vboxNetLwfWinRegisterIpAddrNotifier: NotifyUnicastIpAddressChange failed with %x\n", Status));
+ }
+ else
+ pThis->u.s.WinIf.hNotifier = NULL;
+ LogFlow(("<==vboxNetLwfWinRegisterIpAddrNotifier\n"));
+}
+
+void vboxNetLwfWinUnregisterIpAddrNotifier(PVBOXNETFLTINS pThis)
+{
+ Log(("vboxNetLwfWinUnregisterIpAddrNotifier: notifier=%p\n", pThis->u.s.WinIf.hNotifier));
+ if (pThis->u.s.WinIf.hNotifier)
+ CancelMibChangeNotify2(pThis->u.s.WinIf.hNotifier);
+}
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ PVBOXNETLWF_MODULE pModuleCtx = (PVBOXNETLWF_MODULE)pThis->u.s.WinIf.hModuleCtx;
+ LogFlow(("==>vboxNetFltOsDeleteInstance: instance=%p module=%p\n", pThis, pModuleCtx));
+ /* Cancel IP address change notifications */
+ vboxNetLwfWinUnregisterIpAddrNotifier(pThis);
+ /* Technically it is possible that the module has already been gone by now. */
+ if (pModuleCtx)
+ {
+ Assert(!pModuleCtx->fActive); /* Deactivation ensures bypass mode */
+ pModuleCtx->pNetFlt = NULL;
+ pThis->u.s.WinIf.hModuleCtx = NULL;
+ }
+ LogFlow(("<==vboxNetFltOsDeleteInstance\n"));
+}
+
+static void vboxNetLwfWinReportCapabilities(PVBOXNETFLTINS pThis, PVBOXNETLWF_MODULE pModuleCtx)
+{
+ if (pThis->pSwitchPort
+ && vboxNetFltTryRetainBusyNotDisconnected(pThis))
+ {
+ pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pModuleCtx->MacAddr);
+ pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort,
+ vboxNetLwfWinIsPromiscuous(pModuleCtx));
+ pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
+ INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
+ pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
+ vboxNetFltRelease(pThis, true /*fBusy*/);
+ }
+}
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
+{
+ RT_NOREF1(pvContext);
+ LogFlow(("==>vboxNetFltOsInitInstance: instance=%p context=%p\n", pThis, pvContext));
+ AssertReturn(pThis, VERR_INVALID_PARAMETER);
+ Log(("vboxNetFltOsInitInstance: trunk name=%s\n", pThis->szName));
+ NdisAcquireSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ PVBOXNETLWF_MODULE pModuleCtx;
+ RTListForEach(&g_VBoxNetLwfGlobals.listModules, pModuleCtx, VBOXNETLWF_MODULE, node)
+ {
+ DbgPrint("vboxNetFltOsInitInstance: evaluating module, name=%s\n", pModuleCtx->szMiniportName);
+ if (!RTStrICmp(pThis->szName, pModuleCtx->szMiniportName))
+ {
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ Log(("vboxNetFltOsInitInstance: found matching module, name=%s\n", pThis->szName));
+ pThis->u.s.WinIf.hModuleCtx = pModuleCtx;
+ pModuleCtx->pNetFlt = pThis;
+ vboxNetLwfWinReportCapabilities(pThis, pModuleCtx);
+ vboxNetLwfWinRegisterIpAddrNotifier(pThis);
+ LogFlow(("<==vboxNetFltOsInitInstance: return 0\n"));
+ return VINF_SUCCESS;
+ }
+ }
+ NdisReleaseSpinLock(&g_VBoxNetLwfGlobals.Lock);
+ // Internal network code will try to reconnect periodically, we should not spam in event log
+ //vboxNetLwfLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 6);
+ LogFlow(("<==vboxNetFltOsInitInstance: return VERR_INTNET_FLT_IF_NOT_FOUND\n"));
+ return VERR_INTNET_FLT_IF_NOT_FOUND;
+}
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ LogFlow(("==>vboxNetFltOsPreInitInstance: instance=%p\n", pThis));
+ pThis->u.s.WinIf.hModuleCtx = 0;
+ pThis->u.s.WinIf.hNotifier = NULL;
+ LogFlow(("<==vboxNetFltOsPreInitInstance: return 0\n"));
+ return VINF_SUCCESS;
+}
+
+void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
+{
+ RT_NOREF3(pThis, pvIfData, pMac);
+ LogFlow(("==>vboxNetFltPortOsNotifyMacAddress: instance=%p data=%p mac=%RTmac\n", pThis, pvIfData, pMac));
+ LogFlow(("<==vboxNetFltPortOsNotifyMacAddress\n"));
+}
+
+int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
+{
+ RT_NOREF3(pThis, pvIf, ppvIfData);
+ LogFlow(("==>vboxNetFltPortOsConnectInterface: instance=%p if=%p data=%p\n", pThis, pvIf, ppvIfData));
+ LogFlow(("<==vboxNetFltPortOsConnectInterface: return 0\n"));
+ /* Nothing to do */
+ return VINF_SUCCESS;
+}
+
+int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
+{
+ RT_NOREF2(pThis, pvIfData);
+ LogFlow(("==>vboxNetFltPortOsDisconnectInterface: instance=%p data=%p\n", pThis, pvIfData));
+ LogFlow(("<==vboxNetFltPortOsDisconnectInterface: return 0\n"));
+ /* Nothing to do */
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h
new file mode 100644
index 00000000..1a0a9e7e
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf-win.h
@@ -0,0 +1,55 @@
+/* $Id: VBoxNetLwf-win.h $ */
+/** @file
+ * VBoxNetLwf-win.h - Bridged 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
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetLwf_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetLwf_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define VBOXNETLWF_VERSION_NDIS_MAJOR 6
+#define VBOXNETLWF_VERSION_NDIS_MINOR 0
+
+#define VBOXNETLWF_NAME_FRIENDLY L"VirtualBox NDIS Light-Weight Filter"
+#define VBOXNETLWF_NAME_UNIQUE L"{7af6b074-048d-4444-bfce-1ecc8bc5cb76}"
+#define VBOXNETLWF_NAME_SERVICE L"VBoxNetLwf"
+
+#define VBOXNETLWF_NAME_LINK L"\\DosDevices\\Global\\VBoxNetLwf"
+#define VBOXNETLWF_NAME_DEVICE L"\\Device\\VBoxNetLwf"
+
+#define VBOXNETLWF_MEM_TAG 'FLBV'
+#define VBOXNETLWF_REQ_ID 'fLBV'
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetFlt_win_drv_VBoxNetLwf_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf
new file mode 100644
index 00000000..f5d9cdca
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/drv/VBoxNetLwf.inf
@@ -0,0 +1,120 @@
+; $Id: VBoxNetLwf.inf $
+; @file
+; VBoxNetLwf.inf - VirtualBox Bridged Networking Driver inf file
+;
+
+;
+; 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 = VBoxNetLwf.cat
+Class = NetService
+ClassGUID = {4D36E974-E325-11CE-BFC1-08002BE10318}
+Provider = %ORACLE%
+;edit-DriverVer=10/23/2014,1.0.1.0
+
+
+[Manufacturer]
+%ORACLE% = VBoxNetLwf@COMMA-NT-ARCH@
+
+[ControlFlags]
+
+[VBoxNetLwf@DOT-NT-ARCH@]
+%VBoxNetLwf_Desc% = VBoxNetLwf.ndi, oracle_VBoxNetLwf
+
+[VBoxNetLwf.ndi]
+AddReg = VBoxNetLwf.ndi.AddReg, VBoxNetLwf.AddReg
+Characteristics = 0x40000 ; NCF_LW_FILTER
+CopyFiles = VBoxNetLwf.Files.Sys
+NetCfgInstanceId = "{7af6b074-048d-4444-bfce-1ecc8bc5cb76}"
+
+[VBoxNetLwf.ndi.Remove.Services]
+DelService = VBoxNetLwf,0x200 ; Stop the service before uninstalling
+
+[VBoxNetLwf.ndi.Services]
+AddService = VBoxNetLwf,, VBoxNetLwf.AddService, VBoxNetLwf.AddEventLog
+
+[VBoxNetLwf.AddService]
+DisplayName = %VBoxNetLwfService_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 1 ;SERVICE_SYSTEM_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetLwf.sys
+LoadOrderGroup = NDIS
+AddReg = VBoxNetLwf.AddService.AddReg
+
+[VBoxNetLwf.AddService.AddReg]
+
+[VBoxNetLwf.AddEventLog]
+AddReg = VBoxNetLwf.AddEventLog.AddReg
+
+[VBoxNetLwf.AddEventLog.AddReg]
+HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll"
+HKR,,TypesSupported,0x00010001,7
+
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetLwf.sys=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetLwf.Files.Sys = 12 ; %windir%\System32\drivers
+
+[VBoxNetLwf.Files.Sys]
+VBoxNetLwf.sys,,,2
+
+
+[VBoxNetLwf.ndi.AddReg]
+HKR, Ndi, HelpText, , %VBoxNetLwf_HELP%
+;HKR, Ndi, ClsID, 0, {f374d1a0-bf08-4bdc-9cb2-c15ddaeef955}
+;HKR, Ndi, ComponentDll, , VBoxNetLwfNobj.dll
+HKR, Ndi, FilterClass, , compression
+HKR, Ndi, FilterType, 0x10001, 0x2
+HKR, Ndi, FilterRunType,0x10001, 2 ; OPTIONAL, to prevent unbinding of protocol drivers
+HKR, Ndi, Service, , VBoxNetLwf
+HKR, Ndi, CoServices, 0x10000, VBoxNetLwf
+HKR, Ndi\Interfaces, UpperRange, , noupper
+HKR, Ndi\Interfaces, LowerRange, , nolower
+HKR, Ndi\Interfaces, FilterMediaTypes, , ethernet
+
+[VBoxNetLwf.AddReg]
+;HKR, Parameters, Param1, 0, 4
+
+[Strings]
+ORACLE = "Oracle Corporation"
+DiskDescription = "VirtualBox NDIS6 Bridged Networking Driver"
+VBoxNetLwf_Desc = "VirtualBox NDIS6 Bridged Networking Driver"
+VBoxNetLwf_HELP = "VirtualBox NDIS6 Bridged Networking Driver"
+VBoxNetLwfService_Desc = "VirtualBox NDIS6 Bridged Networking Service"