Index: /trunk/include/VBox/WinNetConfig.h
===================================================================
--- /trunk/include/VBox/WinNetConfig.h	(revision 21333)
+++ /trunk/include/VBox/WinNetConfig.h	(revision 21333)
@@ -0,0 +1,108 @@
+/** @file
+ * VBoxNetFlt - Briefly describe this file, optionally with a longer description
+ * in a separate paragraph. (HostDrivers)
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ *+---------------------------------------------------------------------------
+ *
+ *  Microsoft Windows
+ *  Copyright (C) Microsoft Corporation, 2001.
+ *
+ *  Author:     Alok Sinha    15-May-01
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#ifndef ___VBox_WinNetConfig_h
+#define ___VBox_WinNetConfig_h
+
+#include <winsock2.h>
+#include <Windows.h>
+#include <Netcfgn.h>
+#include <Setupapi.h>
+#include <iprt/cdefs.h>
+
+/** @defgroup grp_vboxnetcfgwin     The Windows Network Configration Library
+ * @{ */
+
+/** @def VBOXNETCFGWIN_DECL
+ * The usual declaration wrapper.
+ */
+#if 0
+/* enable this in case we include this in a dll*/
+# ifdef IN_VBOXDDU
+#  define VBOXNETCFGWIN_DECL(_type) DECLEXPORT(_type)
+# else
+#  define VBOXNETCFGWIN_DECL(_type) DECLIMPORT(_type)
+# endif
+#else
+/*enable this in case we include this in a static lib*/
+# define VBOXNETCFGWIN_DECL(_type) _type
+#endif
+
+RT_C_DECLS_BEGIN
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(IN BOOL fGetWriteLock, IN LPCWSTR lpszAppName, OUT INetCfg** ppnc, OUT LPWSTR *lpszLockedBy);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pnc, IN BOOL fHasWriteLock);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentEnum(INetCfg *pnc, IN const GUID *pguidClass, OUT IEnumNetCfgComponent **ppencc);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetFirstComponent(IN IEnumNetCfgComponent *pencc, OUT INetCfgComponent **ppncc);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetNextComponent(IN IEnumNetCfgComponent *pencc, OUT INetCfgComponent **ppncc);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pnc, IN LPCWSTR szComponentId, IN const GUID *pguidClass);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallNetComponent(IN INetCfg *pnc, IN LPCWSTR lpszComponentId, IN const GUID *pguidClass,
+                                                             IN LPCWSTR * apInfFullPaths, IN UINT cInfFullPaths);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUninstallComponent(IN INetCfg *pnc, IN INetCfgComponent *pncc);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetNextBindingPath(IN IEnumNetCfgBindingPath *pencbp, OUT INetCfgBindingPath **ppncbp);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetNextBindingInterface(IN IEnumNetCfgBindingInterface *pencbi, OUT INetCfgBindingInterface **ppncbi);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetFirstBindingInterface(IN IEnumNetCfgBindingInterface *pencbi, OUT INetCfgBindingInterface **ppncbi);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetBindingInterfaceEnum(IN INetCfgBindingPath *pncbp, OUT IEnumNetCfgBindingInterface **ppencbi);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetFirstBindingPath(IN IEnumNetCfgBindingPath *pencbp, OUT INetCfgBindingPath **ppncbp);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetBindingPathEnum(IN INetCfgComponent *pncc, IN DWORD dwBindingType, OUT IEnumNetCfgBindingPath **ppencbp);
+VBOXNETCFGWIN_DECL(VOID)    VBoxNetCfgWinReleaseRef(IN IUnknown *punk);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc, IN const GUID *pguidClass, IN const GUID * pComponentGuid, OUT INetCfgComponent **ppncc);
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc, IN LPCWSTR * apInfFullPaths, IN UINT cInfFullPaths);
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName (PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection (LPWSTR pGuid, PCWSTR NewName);
+
+typedef BOOL (*VBOXNETCFGWIN_NETENUM_CALLBACK) (HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnumNetDevices(LPWSTR pPnPId, VBOXNETCFGWIN_NETENUM_CALLBACK callback, PVOID pContext);
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface (const GUID *pGUID, BSTR *pErrMsg);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(LPWSTR pPnPId);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface (GUID *pGuid, BSTR *lppszName, BSTR *pErrMsg);
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(const GUID *pGuid);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(const GUID *pGuid);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(const GUID *pGuid, ULONG ip, ULONG mask);
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinIsDhcpEnabled(const GUID * pGuid, BOOL *pEnabled);
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(PULONG pNetIp, PULONG pNetMask);
+
+typedef struct _ADAPTER_SETTINGS
+{
+    ULONG ip;
+    ULONG mask;
+    BOOL bDhcp;
+}ADAPTER_SETTINGS, *PADAPTER_SETTINGS;
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(const GUID * pGuid, PADAPTER_SETTINGS pSettings);
+
+typedef VOID (*LOG_ROUTINE) (LPCWSTR szString);
+VBOXNETCFGWIN_DECL(VOID) VBoxNetCfgWinSetLogging(LOG_ROUTINE Log);
+
+RT_C_DECLS_END
+
+/** @} */
+
+#endif
+
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetAdpInstall.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetAdpInstall.cpp	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetAdpInstall.cpp	(revision 21333)
@@ -0,0 +1,84 @@
+/* $Id$ */
+/** @file
+ * NetAdpInstall - VBoxNetAdp installer command line tool
+ */
+
+/*
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+
+#include <vbox/WinNetConfig.h>
+#include <stdio.h>
+
+static VOID winNetCfgLogger (LPCWSTR szString)
+{
+    wprintf(L"%s", szString);
+}
+
+static int InstallNetAdp()
+{
+    int r = 0;
+    VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+    HRESULT hr = CoInitialize(NULL);
+    if(hr == S_OK)
+    {
+#ifndef DEBUG_misha
+        printf("not implemented yet, please use device manager for Host-Only net interface installation.. sorry :( \n");
+#else
+        /* this installs the Net Adp from the pre-installed driver package,
+         * it does NOT install the new driver package, so the installation might use old drivers
+         * or fail in case no NetAdp package is currently installed
+         * the code is here for debugging NetAdp installation only */
+        GUID guid;
+        BSTR name, errMsg;
+        printf("adding host-only interface..\n");
+        hr = VBoxNetCfgWinCreateHostOnlyNetworkInterface (&guid, &name, &errMsg);
+        if(hr == S_OK)
+        {
+            ULONG ip, mask;
+            hr = VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(&ip, &mask);
+            if(hr == S_OK)
+            {
+                /* ip returned by VBoxNetCfgWinGenHostOnlyNetworkNetworkIp is a network ip,
+                 * i.e. 192.168.xxx.0, assign  192.168.xxx.1 for the hostonly adapter */
+                ip = ip | (1 << 24);
+                hr = VBoxNetCfgWinEnableStaticIpConfig(&guid, ip, mask);
+                if(hr != S_OK)
+                {
+                    printf("VBoxNetCfgWinEnableStaticIpConfig failed: hr = 0x%x\n", hr);
+                }
+            }
+            else
+            {
+                printf("VBoxNetCfgWinGenHostOnlyNetworkNetworkIp failed: hr = 0x%x\n", hr);
+            }
+        }
+        else
+        {
+            printf("VBoxNetCfgWinCreateHostOnlyNetworkInterface failed: hr = 0x%x\n", hr);
+        }
+#endif
+
+        r = 1;
+
+        CoUninitialize();
+    }
+    else
+    {
+        wprintf(L"Error initializing COM (0x%x)\n", hr);
+        r = 1;
+    }
+
+    VBoxNetCfgWinSetLogging(NULL);
+
+    return r;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+    return InstallNetAdp();
+}
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetAdpUninstall.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetAdpUninstall.cpp	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetAdpUninstall.cpp	(revision 21333)
@@ -0,0 +1,57 @@
+/* $Id$ */
+/** @file
+ * NetAdpUninstall - VBoxNetAdp uninstaller command line tool
+ */
+
+/*
+ * Copyright (C) 2009 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+
+#include <vbox/WinNetConfig.h>
+#include <stdio.h>
+
+static VOID winNetCfgLogger (LPCWSTR szString)
+{
+    wprintf(L"%s", szString);
+}
+
+static int UninstallNetAdp()
+{
+    int r = 0;
+    VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+    printf("uninstalling all Host-Only interfaces..\n");
+
+    HRESULT hr = CoInitialize(NULL);
+    if(hr == S_OK)
+    {
+        hr = VBoxNetCfgWinRemoveAllNetDevicesOfId(L"sun_VBoxNetAdp");
+        if(hr == S_OK)
+        {
+            printf("uninstalled successfully\n");
+        }
+        else
+        {
+            printf("uninstall failed, hr = 0x%x\n", hr);
+        }
+
+        CoUninitialize();
+    }
+    else
+    {
+        wprintf(L"Error initializing COM (0x%x)\n", hr);
+        r = 1;
+    }
+
+    VBoxNetCfgWinSetLogging(NULL);
+
+    return r;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+    return UninstallNetAdp();
+}
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetFltInstall.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetFltInstall.cpp	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetFltInstall.cpp	(revision 21333)
@@ -0,0 +1,124 @@
+/* $Id$ */
+/** @file
+ * NetFltInstall - VBoxNetFlt installer command line tool
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+
+#include <vbox/WinNetConfig.h>
+#include <devguid.h>
+#include <stdio.h>
+
+#define NETFLT_ID  L"sun_VBoxNetFlt"
+#define VBOX_NETCFG_APP_NAME L"NetFltInstall"
+#define VBOX_NETFLT_PT_INF L".\\VBoxNetFlt.inf"
+#define VBOX_NETFLT_MP_INF L".\\VBoxNetFlt_m.inf"
+#define VBOX_NETFLT_RETRIES 10
+
+
+static VOID winNetCfgLogger (LPCWSTR szString)
+{
+    wprintf(L"%s", szString);
+}
+
+static int InstallNetFlt()
+{
+    WCHAR PtInf[MAX_PATH];
+    WCHAR MpInf[MAX_PATH];
+    INetCfg *pnc;
+    LPWSTR lpszLockedBy = NULL;
+    int r = 1;
+
+    VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+    HRESULT hr = CoInitialize(NULL);
+    if(hr == S_OK)
+    {
+        int i = 0;
+        do
+        {
+            hr = VBoxNetCfgWinQueryINetCfg(TRUE, VBOX_NETCFG_APP_NAME, &pnc, &lpszLockedBy);
+            if(hr == S_OK)
+            {
+                DWORD WinEr;
+                GetFullPathNameW(VBOX_NETFLT_PT_INF, sizeof(PtInf)/sizeof(PtInf[0]), PtInf, NULL);
+                WinEr = GetLastError();
+                if(WinEr == ERROR_SUCCESS)
+                {
+                    GetFullPathNameW(VBOX_NETFLT_MP_INF, sizeof(MpInf)/sizeof(MpInf[0]), MpInf, NULL);
+                    WinEr = GetLastError();
+                    if(WinEr == ERROR_SUCCESS)
+                    {
+                        LPCWSTR aInfs[] = {PtInf, MpInf};
+                        hr = VBoxNetCfgWinNetFltInstall(pnc, aInfs, 2);
+                        if(hr == S_OK)
+                        {
+                            wprintf(L"installed successfully\n");
+                            r = 0;
+                        }
+                        else
+                        {
+                            wprintf(L"error installing VBoxNetFlt (0x%x)\n", hr);
+                        }
+                    }
+                    else
+                    {
+                        hr =  HRESULT_FROM_WIN32(WinEr);
+                        wprintf(L"error getting full inf path for VBoxNetFlt_m.inf (0x%x)\n", hr);
+                    }
+                }
+                else
+                {
+                    hr =  HRESULT_FROM_WIN32(WinEr);
+                    wprintf(L"error getting full inf path for VBoxNetFlt.inf (0x%x)\n", hr);
+                }
+
+
+                VBoxNetCfgWinReleaseINetCfg(pnc, TRUE);
+                break;
+            }
+            else if(hr == NETCFG_E_NO_WRITE_LOCK && lpszLockedBy)
+            {
+                if(i < VBOX_NETFLT_RETRIES && !wcscmp(lpszLockedBy, L"6to4svc.dll"))
+                {
+                    wprintf(L"6to4svc.dll is holding the lock, retrying %d out of %d\n", ++i, VBOX_NETFLT_RETRIES);
+                    CoTaskMemFree(lpszLockedBy);
+                }
+                else
+                {
+                    wprintf(L"Error: write lock is owned by another application (%s), close the application and retry installing\n", lpszLockedBy);
+                    r = 1;
+                    CoTaskMemFree(lpszLockedBy);
+                    break;
+                }
+            }
+            else
+            {
+                wprintf(L"Error getting the INetCfg interface (0x%x)\n", hr);
+                r = 1;
+                break;
+            }
+        } while(true);
+
+        CoUninitialize();
+    }
+    else
+    {
+        wprintf(L"Error initializing COM (0x%x)\n", hr);
+        r = 1;
+    }
+
+    VBoxNetCfgWinSetLogging(NULL);
+
+    return r;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+    return InstallNetFlt();
+}
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetFltUninstall.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetFltUninstall.cpp	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/NetFltUninstall.cpp	(revision 21333)
@@ -0,0 +1,98 @@
+/* $Id$ */
+/** @file
+ * NetFltUninstall - VBoxNetFlt uninstaller command line tool
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+
+#include <vbox/WinNetConfig.h>
+#include <stdio.h>
+
+#define NETFLT_ID  L"sun_VBoxNetFlt"
+#define VBOX_NETCFG_APP_NAME L"NetFltUninstall"
+#define VBOX_NETFLT_PT_INF L".\\VBoxNetFlt.inf"
+#define VBOX_NETFLT_MP_INF L".\\VBoxNetFlt_m.inf"
+#define VBOX_NETFLT_RETRIES 10
+
+static VOID winNetCfgLogger (LPCWSTR szString)
+{
+    wprintf(L"%s", szString);
+}
+
+static int UninstallNetFlt()
+{
+    INetCfg *pnc;
+    LPWSTR lpszLockedBy = NULL;
+    int r;
+
+    VBoxNetCfgWinSetLogging(winNetCfgLogger);
+
+    HRESULT hr = CoInitialize(NULL);
+    if(hr == S_OK)
+    {
+        int i = 0;
+        do
+        {
+            hr = VBoxNetCfgWinQueryINetCfg(TRUE, VBOX_NETCFG_APP_NAME, &pnc, &lpszLockedBy);
+            if(hr == S_OK)
+            {
+                hr = VBoxNetCfgWinNetFltUninstall(pnc);
+                if(hr != S_OK)
+                {
+                    wprintf(L"error uninstalling VBoxNetFlt (0x%x)\n", hr);
+                    r = 1;
+                }
+                else
+                {
+                    wprintf(L"uninstalled successfully\n");
+                    r = 0;
+                }
+
+                VBoxNetCfgWinReleaseINetCfg(pnc, TRUE);
+                break;
+            }
+            else if(hr == NETCFG_E_NO_WRITE_LOCK && lpszLockedBy)
+            {
+                if(i < VBOX_NETFLT_RETRIES && !wcscmp(lpszLockedBy, L"6to4svc.dll"))
+                {
+                    wprintf(L"6to4svc.dll is holding the lock, retrying %d out of %d\n", ++i, VBOX_NETFLT_RETRIES);
+                    CoTaskMemFree(lpszLockedBy);
+                }
+                else
+                {
+                    wprintf(L"Error: write lock is owned by another application (%s), close the application and retry uninstalling\n", lpszLockedBy);
+                    r = 1;
+                    CoTaskMemFree(lpszLockedBy);
+                    break;
+                }
+            }
+            else
+            {
+                wprintf(L"Error getting the INetCfg interface (0x%x)\n", hr);
+                r = 1;
+                break;
+            }
+        } while(true);
+
+        CoUninitialize();
+    }
+    else
+    {
+        wprintf(L"Error initializing COM (0x%x)\n", hr);
+        r = 1;
+    }
+
+    VBoxNetCfgWinSetLogging(NULL);
+
+    return r;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+    return UninstallNetFlt();
+}
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.c
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.c	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.c	(revision 21333)
@@ -0,0 +1,3671 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Integration with IntNet/NetFlt
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ * Copyright (c) 1993-1999, Microsoft Corporation
+ */
+
+#include "VBoxNetFltCommon-win.h"
+#include <iprt/thread.h>
+
+/** represents the job element of the job queue
+ * see comments for JOB_QUEUE */
+typedef struct _JOB
+{
+    /** link in the job queue */
+    LIST_ENTRY ListEntry;
+    /** job function to be executed */
+    JOB_ROUTINE pRoutine;
+    /** 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;
+} JOB, *PJOB;
+
+/**
+ * represents the queue of jobs processed by the worker thred
+ *
+ * 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 _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;
+} JOB_QUEUE, *PJOB_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
+{
+    JOB     Job;
+    bool    bInitialized;
+    volatile bool    bStop;
+    volatile int rc;
+    KEVENT hCompletionEvent;
+}INIT_IDC_INFO, *PINIT_IDC_INFO;
+
+
+/** globals */
+
+/** global lock */
+NDIS_SPIN_LOCK     g_GlobalLock;
+/** 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 JOB_QUEUE g_JobQueue;
+/**
+ * The (common) global data.
+ */
+static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
+volatile static bool g_bIdcInitialized;
+INIT_IDC_INFO g_InitIdcInfo;
+
+UINT g_fPacketDontLoopBack;
+UINT g_fPacketIsLoopedBack;
+
+#define LIST_ENTRY_2_JOB(pListEntry) \
+    ( (PJOB)((uint8_t *)(pListEntry) - RT_OFFSETOF(JOB, ListEntry)) )
+
+static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery);
+static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis);
+static int vboxNetFltWinTryFiniIdc();
+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(PADAPT_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)
+        {
+            DBGPRINT(("device not idle"));
+            Assert(0);
+            break;
+        }
+#endif
+    }
+}
+
+/**
+ * mem functions
+ */
+/* allocates and zeroes the nonpaged memory of a given size */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMemAlloc(PVOID* ppMemBuf, UINT cbLength)
+{
+    NDIS_STATUS fStatus = NdisAllocateMemoryWithTag(ppMemBuf, cbLength, MEM_TAG);
+    if(fStatus == NDIS_STATUS_SUCCESS)
+    {
+        NdisZeroMemory(*ppMemBuf, cbLength);
+    }
+    return fStatus;
+}
+
+/* frees memory allocated with vboxNetFltWinMemAlloc */
+DECLHIDDEN(void) vboxNetFltWinMemFree(PVOID pMemBuf)
+{
+    NdisFreeMemory(pMemBuf, 0, 0);
+}
+
+/* frees ndis buffers used on send/receive */
+static VOID vboxNetFltWinFiniBuffers(PADAPT pAdapt)
+{
+    /* NOTE: don't check for NULL since NULL is a valid handle */
+#ifndef VBOXNETADP
+    NdisFreeBufferPool(pAdapt->hSendBufferPoolHandle);
+#endif
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    NdisFreeBufferPool(pAdapt->hRecvBufferPoolHandle);
+#endif
+}
+
+/* initializes ndis buffers used on send/receive */
+static NDIS_STATUS vboxNetFltWinInitBuffers(PADAPT pAdapt)
+{
+    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+    do
+    {
+        /* NOTE: NULL is a valid handle !!! */
+#ifndef VBOXNETADP
+        NdisAllocateBufferPool(&Status,
+                &pAdapt->hSendBufferPoolHandle,
+                TX_BUFFER_POOL_SIZE);
+        Assert(Status == NDIS_STATUS_SUCCESS);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            break;
+        }
+#endif
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        /* NOTE: NULL is a valid handle !!! */
+        NdisAllocateBufferPool(&Status,
+                &pAdapt->hRecvBufferPoolHandle,
+                RX_BUFFER_POOL_SIZE);
+        Assert(Status == NDIS_STATUS_SUCCESS);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+#ifndef VBOXNETADP
+            NdisFreeBufferPool(pAdapt->hSendBufferPoolHandle);
+#endif
+            break;
+        }
+#endif
+    } while (FALSE);
+
+    return Status;
+}
+
+/* initializes packet info pool and allocates the cSize packet infos for the pool */
+static NDIS_STATUS vboxNetFltWinPpAllocatePacketInfoPool(PPACKET_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)
+    {
+        PPACKET_INFO pInfo;
+        pPool->pBuffer = pPacketInfos;
+
+        for(i = 0; i < cSize; i++)
+        {
+            pInfo = &pPacketInfos[i];
+            vboxNetFltWinQuEnqueueTail(&pPool->Queue.Queue, pInfo);
+            pInfo->pPool = pPool;
+        }
+    }
+    else
+    {
+        Assert(0);
+    }
+
+    return fStatus;
+}
+
+/* frees the packet info pool */
+VOID vboxNetFltWinPpFreePacketInfoPool(PPACKET_INFO_POOL pPool)
+{
+    vboxNetFltWinMemFree(pPool->pBuffer);
+
+    FINI_INTERLOCKED_PACKET_QUEUE(&pPool->Queue)
+}
+
+/**
+ * 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)
+        {
+            Assert(0);
+            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
+ ************************************************************************************/
+static void vboxNetFltWinReinitSG(PINTNETSG pSG)
+{
+    pSG->pvOwnerData = NULL;
+    pSG->pvUserData = NULL;
+    pSG->pvUserData2 = NULL;
+    pSG->cUsers = 1;
+    pSG->fFlags = INTNETSG_FLAGS_TEMP;
+    pSG->cSegsUsed = 0;
+    pSG->cbTotal = 0;
+}
+
+static void vboxNetFltWinInitSG(PINTNETSG pSG, UINT cBufferCount)
+{
+    pSG->pvOwnerData = NULL;
+    pSG->pvUserData = NULL;
+    pSG->pvUserData2 = NULL;
+    pSG->cUsers = 1;
+    pSG->fFlags = INTNETSG_FLAGS_TEMP;
+    pSG->cSegsAlloc = cBufferCount;
+    pSG->cSegsUsed = 0;
+    pSG->cbTotal = 0;
+}
+
+/* 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)
+{
+    UINT cbSeg = 0;
+    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 cbSeg = 0;
+    NDIS_STATUS fStatus = NDIS_STATUS_SUCCESS;
+    PVOID pVirtualAddress;
+    UINT cbCurrentLength;
+
+    while(pBuffer)
+    {
+        NdisQueryBufferSafe(
+                pBuffer,
+                &pVirtualAddress,
+                &cbCurrentLength,
+                NormalPagePriority);
+
+        if(!pVirtualAddress) {
+                fStatus = NDIS_STATUS_FAILURE;
+                break;
+        }
+
+        pSG->cbTotal += cbCurrentLength;
+        pSG->aSegs[cbSeg].cb = cbCurrentLength;
+        pSG->aSegs[cbSeg].pv = pVirtualAddress;
+        pSG->aSegs[cbSeg].Phys = NIL_RTHCPHYS;
+        cbSeg++;
+
+        NdisGetNextBuffer(
+                pBuffer,
+                &pBuffer);
+    }
+
+    AssertFatal(cbSeg <= pSG->cSegsAlloc);
+
+    if(fStatus == NDIS_STATUS_SUCCESS)
+    {
+        pSG->cSegsUsed = cbSeg;
+    }
+
+    return fStatus;
+}
+
+static void vboxNetFltWinDeleteSG(PINTNETSG pSG)
+{
+    vboxNetFltWinMemFree(pSG);
+}
+
+static PINTNETSG vboxNetFltWinCreateSG(uint32_t cSize)
+{
+    PINTNETSG pSG;
+    NTSTATUS Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, RT_OFFSETOF(INTNETSG, aSegs[cSize]));
+    if(Status == STATUS_SUCCESS)
+    {
+        vboxNetFltWinInitSG(pSG, cSize);
+        return pSG;
+    }
+
+    return NULL;
+}
+
+/************************************************************************************
+ * packet queue functions
+ ************************************************************************************/
+
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+static NDIS_STATUS vboxNetFltWinQuPostPacket(PADAPT pAdapt, PNDIS_PACKET pPacket, PINTNETSG pSG, uint32_t fFlags
+# ifdef DEBUG_NETFLT_PACKETS
+        , PNDIS_PACKET pTmpPacket
+# endif
+        )
+{
+    NDIS_STATUS fStatus;
+    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(pAdapt, /* PADAPT */
+                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)
+            {
+                fStatus = vboxNetFltWinPrepareSendPacket(pAdapt, pPacket, &pMyPacket/*, true*/);
+                LogFlow(("packet from wire, packet created (%p)\n", pMyPacket));
+            }
+            else
+            {
+                fStatus = vboxNetFltWinPrepareRecvPacket(pAdapt, 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 successfuly initialized our packet, post it to the host or to the wire */
+        if(bSrcHost)
+        {
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            SET_PACKET_TO_INFO(pInfo, pMyPacket);
+//            /* we are not using flags here, so they are not valid here */
+//            /* SET_FLAGS_TO_INFO(pInfo, 0); */
+//            LogFlow(("sending packet (%p)\n", pMyPacket));
+//            vboxNetFltWinDoSendViaInfo(&fStatus, pAdapt, pInfo);
+//            LogFlow(("done sending packet (%p), status (%d)\n", pMyPacket, fStatus));
+#else
+            NdisSend(&fStatus, pAdapt->hBindingHandle, pMyPacket);
+#endif
+
+            if (fStatus != NDIS_STATUS_PENDING)
+            {
+                /* the status is NOT pending, complete the packet */
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//                vboxNetFltWinDoCompleteSendViaInfo(pAdapt, pInfo);
+#endif
+                if(pPacket)
+                {
+                    LogFlow(("status is not pending, completing packet (%p)\n", pPacket));
+#ifndef WIN9X
+                    NdisIMCopySendCompletePerPacketInfo (pPacket, pMyPacket);
+#endif
+                    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 */
+                    Assert(0);
+                    LogFlow(("status is not pending, freeing myPacket (%p)\n", pMyPacket));
+                    vboxNetFltWinFreeSGNdisPacket(pMyPacket, false);
+                }
+            }
+        }
+        else
+        {
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            SET_PACKET_TO_INFO(pInfo, pMyPacket);
+//            /* we are not using flags here, so they are not valid here */
+//            /* SET_FLAGS_TO_INFO(pInfo, 0); */
+//
+//            LogFlow(("indicating receive packet (%p)\n", pMyPacket));
+//            vboxNetFltWinDoIndicateReceiveViaInfo(pAdapt, pInfo);
+//            /* the packet return will be processed in the vboxNetFltWinMpReturnPacket call-back unless
+//             * we specify NDIS_STATUS_RESOURCES as the packet status, which we are NOT doing currently */
+//            LogFlow(("done indicating receive packet (%p)\n", pMyPacket));
+#else
+            NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, &pMyPacket, 1);
+#endif
+
+            fStatus = NDIS_STATUS_PENDING;
+            /* the packet receive completion is always indicated via MiniportReturnPacket */
+        }
+    }
+    else
+    {
+        /*we failed to create our packet */
+        Assert(0);
+        fStatus = NDIS_STATUS_FAILURE;
+    }
+
+    return fStatus;
+}
+#endif
+
+static bool vboxNetFltWinQuProcessInfo(PVBOXNETFLTINS pNetFltIf, PPACKET_QUEUE_WORKER pWorker, PPACKET_INFO pInfo)
+{
+    PNDIS_PACKET pPacket = NULL;
+    PINTNETSG pSG = NULL;
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pNetFltIf);
+    UINT fFlags;
+    NDIS_STATUS Status;
+#ifndef VBOXNETADP
+    bool bSrcHost;
+    bool bPending;
+    bool bDropIt;
+#endif
+#ifdef DEBUG_NETFLT_PACKETS
+    /* packet used for matching */
+    PNDIS_PACKET pTmpPacket = NULL;
+#endif
+
+    fFlags = GET_FLAGS_FROM_INFO(pInfo);
+#ifndef VBOXNETADP
+    bSrcHost = (fFlags & 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 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 transfered to.
+     * If the enqueued packet is the one allocated by us the PACKET_MINE flag is set
+     * */
+    if((fFlags & 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           uBytesCopied = 0;
+        UINT           cbPacketLength;
+
+        pPacket = (PNDIS_PACKET)GET_PACKET_FROM_INFO(pInfo);
+        LogFlow(("ndis packet info, packet (%p)\n", pPacket));
+
+        LogFlow(("preparing pSG"));
+        NdisQueryPacket(pPacket,
+                                NULL,
+                                &cBufferCount,
+                                &pCurrentBuffer,
+                                &cbPacketLength);
+
+
+        Assert(cBufferCount);
+
+        /* 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 PADAPT */
+        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"));
+            }
+        }
+
+        if(pSG)
+        {
+            /* reinitialize */
+            vboxNetFltWinReinitSG(pSG);
+
+            /* 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 VBOX_NETFLT_ONDEMAND_BIND
+ #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
+#else
+        /* we have both host and wire in ProtocolReceive */
+#endif
+        pSG = (PINTNETSG)GET_PACKET_FROM_INFO(pInfo);
+
+        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(pAdapt, /* PADAPT */
+                    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*/
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        bDropIt =
+#endif
+        pSG ? pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, pSG,
+                    bSrcHost ? INTNETTRUNKDIR_HOST : INTNETTRUNKDIR_WIRE
+                            )
+              : false;
+#else
+        if(pSG)
+        {
+            pNetFltIf->pSwitchPort->pfnRecv(pNetFltIf->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
+            STATISTIC_INCREASE(pAdapt->cTxSuccess);
+        }
+        else
+        {
+            STATISTIC_INCREASE(pAdapt->cTxError);
+        }
+#endif
+
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+        if(!bDropIt)
+        {
+            Status = vboxNetFltWinQuPostPacket(pAdapt, 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(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+                /* complete the packets */
+                if(fFlags & PACKET_SRC_HOST)
+                {
+#endif
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+/*                    NDIS_SET_PACKET_STATUS(pPacket, Status); */
+                    NdisMSendComplete(pAdapt->hMiniportHandle, pPacket, Status);
+#endif
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+                }
+                else
+                {
+#endif
+#ifndef VBOXNETADP
+                    NdisReturnPackets(&pPacket, 1);
+#endif
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+                }
+#endif
+            }
+            else
+            {
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+                Assert(!(fFlags & PACKET_SRC_HOST));
+#endif
+                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
+}
+/*
+ * 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;
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pNetFltIf);
+    PPACKET_QUEUE_WORKER pWorker = &pNetFltIf->u.s.PacketQueueWorker;
+
+    /* two events we're waiting is "kill" and "notify" events
+     * the former is used for the thread termination
+     * the latter gets fired each time the packet is added to the queue */
+    PVOID pEvents[] = {
+      (PVOID) &pWorker->KillEvent,
+      (PVOID) &pWorker->NotifyEvent,
+      };
+
+    while(fResume)
+    {
+        uint32_t cNumProcessed;
+        uint32_t cNumPostedToHostWire;
+
+        fStatus = KeWaitForMultipleObjects(2, pEvents, 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
+        {
+            PPACKET_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 (%p)\n", pInfo));
+
+            if(vboxNetFltWinQuProcessInfo(pNetFltIf, pWorker, pInfo))
+            {
+                cNumPostedToHostWire++;
+            }
+
+            vboxNetFltWinPpFreePacketInfo(pInfo);
+
+            cNumProcessed++;
+        } while(TRUE);
+
+        if(cNumProcessed)
+        {
+            vboxNetFltWinDecReferenceNetFlt(pNetFltIf, cNumProcessed);
+
+            Assert(cNumProcessed >= cNumPostedToHostWire);
+
+            if(cNumProcessed != cNumPostedToHostWire)
+            {
+                vboxNetFltWinDecReferenceAdapt(pAdapt, cNumProcessed - cNumPostedToHostWire);
+            }
+        }
+    }
+
+    PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+/**
+ * thread start function for the job processing thread
+ *
+ * see comments for PJOB_QUEUE
+ */
+static VOID vboxNetFltWinJobWorkerThreadProc(PJOB_QUEUE pQueue)
+{
+    bool fResume = true;
+    NTSTATUS Status;
+
+    PVOID pEvents[] = {
+      (PVOID) &pQueue->KillEvent,
+      (PVOID) &pQueue->NotifyEvent,
+      };
+
+    do
+    {
+        Status = KeWaitForMultipleObjects(2, pEvents, 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);
+            PJOB pJob;
+
+            if(!pJobEntry)
+                break;
+
+            pJob = LIST_ENTRY_2_JOB(pJobEntry);
+
+            Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+            pJob->pRoutine(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 PJOB_QUEUE
+ */
+static VOID vboxNetFltWinJobEnqueueJob(PJOB_QUEUE pQueue, PJOB 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(PJOB pJob, JOB_ROUTINE pRoutine, PVOID pContext, bool bUseEvent)
+{
+    pJob->pRoutine = pRoutine;
+    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 PJOB_QUEUE
+ */
+static VOID vboxNetFltWinJobSynchExec(PJOB_QUEUE pQueue, JOB_ROUTINE pRoutine, PVOID pContext)
+{
+    JOB Job;
+
+    Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+    vboxNetFltWinJobInit(&Job, pRoutine, 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(JOB_ROUTINE pRoutine, PVOID pContext)
+{
+    vboxNetFltWinJobSynchExec(&g_JobQueue, pRoutine, pContext);
+}
+
+/**
+ * helper function used for system thread creation
+ */
+static NTSTATUS vboxNetFltWinQuCreateSystemThread(PKTHREAD * ppThread, PKSTART_ROUTINE  pStartRoutine, PVOID  pStartContext)
+{
+    NTSTATUS fStatus;
+    HANDLE hThread;
+    OBJECT_ATTRIBUTES fObjectAttributes;
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    InitializeObjectAttributes(&fObjectAttributes, NULL, OBJ_KERNEL_HANDLE,
+                        NULL, NULL);
+
+    fStatus = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS,
+                        &fObjectAttributes, NULL, NULL,
+                        (PKSTART_ROUTINE) pStartRoutine, pStartContext);
+    if (!NT_SUCCESS(fStatus))
+      return fStatus;
+
+    ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL,
+                        KernelMode, (PVOID*) ppThread, NULL);
+    ZwClose(hThread);
+    return STATUS_SUCCESS;
+}
+
+/**
+ * initialize the job queue
+ * see comments for PJOB_QUEUE
+ */
+static NTSTATUS vboxNetFltWinJobInitQueue(PJOB_QUEUE pQueue)
+{
+    NTSTATUS fStatus;
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    NdisZeroMemory(pQueue, sizeof(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 PJOB_QUEUE
+ */
+static void vboxNetFltWinJobFiniQueue(PJOB_QUEUE pQueue)
+{
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    if(pQueue->pThread)
+    {
+        KeSetEvent(&pQueue->KillEvent, 0, FALSE);
+
+        KeWaitForSingleObject(pQueue->pThread, Executive,
+                            KernelMode, FALSE, NULL);
+    }
+}
+
+/**
+ * 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, 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)
+{
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    PINTNETSG pSG;
+    PPACKET_QUEUE_WORKER pWorker = &pInstance->u.s.PacketQueueWorker;
+    Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+//    Assert(pAdapt->pPacketQueueSG);
+
+    /* using the pPacketQueueSG as an indicator that the packet queue is initialized */
+    RTSpinlockAcquire((pInstance)->hSpinlock, &Tmp);
+    if(pWorker->pSG)
+    {
+        pSG = pWorker->pSG;
+        pWorker->pSG = NULL;
+        RTSpinlockRelease((pInstance)->hSpinlock, &Tmp);
+        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, &Tmp);
+    }
+}
+
+/*
+ * 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 cbBufSize, PINTNETSG *ppSG)
+{
+    UINT cbBufferOffset;
+    UINT cbMemSize;
+    NDIS_STATUS Status;
+    PINTNETSG pSG;
+
+    /* allocation:
+     * 1. SG_PACKET - with one aSegs pointing to
+     * 2. buffer of cbPacketLength containing the entire packet */
+    cbBufferOffset = sizeof(INTNETSG);
+    /* make sure the buffer is aligned */
+    if((cbBufferOffset & (sizeof(PVOID) - 1)) != 0)
+    {
+        cbBufferOffset += sizeof(PVOID);
+        cbBufferOffset &= ~(sizeof(PVOID) - 1);
+    }
+
+    cbMemSize = cbBufferOffset + cbBufSize;
+    Status = vboxNetFltWinMemAlloc((PVOID*)&pSG, cbMemSize);
+    if(Status == NDIS_STATUS_SUCCESS)
+    {
+        vboxNetFltWinInitSG(pSG, 1);
+        pSG->aSegs[0].pv = (uint8_t *)pSG + cbBufferOffset;
+        pSG->aSegs[0].Phys = NIL_RTHCPHYS;
+        pSG->aSegs[0].cb = cbBufSize;
+        pSG->cbTotal = cbBufSize;
+        pSG->cSegsUsed = 1;
+
+        LogFlow(("pSG created  (%p)\n", pSG));
+
+        *ppSG = pSG;
+    }
+    return Status;
+}
+
+/**
+ * put the packet info to the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuEnqueueInfo(PPACKET_QUEUE_WORKER pWorker, PPACKET_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)
+{
+    PPACKET_INFO pInfo;
+    PPACKET_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)
+            {
+                Assert(0);
+                break;
+            }
+
+            pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
+
+            if(!pInfo)
+            {
+                Assert(0);
+                /* 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)
+            {
+                Assert(0);
+                vboxNetFltWinPpFreePacketInfo(pInfo);
+                vboxNetFltWinMemFree(pSG);
+                break;
+            }
+
+            DBG_CHECK_PACKET_AND_SG((PNDIS_PACKET)pPacket, pSG);
+        }
+        else
+        {
+            pInfo = vboxNetFltWinPpAllocPacketInfo(&pWorker->PacketInfoPool);
+
+            if(!pInfo)
+            {
+                Assert(0);
+                /* 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;
+}
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+/*
+ * ioctl i/f
+ */
+static NTSTATUS
+vboxNetFltWinPtDispatchIoctl(
+    IN PDEVICE_OBJECT    pDeviceObject,
+    IN PIO_STACK_LOCATION  pIrpStack)
+{
+#if 0
+    ULONG CtlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
+    NTSTATUS Status = STATUS_SUCCESS;
+    int rc;
+
+    switch(CtlCode)
+    {
+
+        case VBOXNETFLT_WIN_IOCTL_INIT:
+            rc = vboxNetFltWinInitIdc();
+            if(!RT_SUCCESS(rc))
+            {
+                Status = STATUS_UNSUCCESSFUL;
+            }
+            break;
+        case VBOXNETFLT_WIN_IOCTL_FINI:
+            /* we are finalizing during unload */
+            /* TODO: FIXME: need to prevent driver unload that can occur in case IntNet is connected to us,
+             * but we are  not bound to any adapters */
+/*            rc = vboxNetFltWinTryFiniIdc();
+            if(!RT_SUCCESS(rc))
+            {
+                Status = STATUS_UNSUCCESSFUL;
+            }
+            */
+            break;
+
+        default:
+            Status = STATUS_NOT_SUPPORTED;
+            break;
+    }
+
+    return Status;
+#else
+    return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/*
+Routine Description:
+
+    Process IRPs sent to this device.
+
+Arguments:
+
+    DeviceObject - pointer to a device object
+    Irp      - pointer to an I/O Request Packet
+
+Return Value:
+
+    NTSTATUS - STATUS_SUCCESS always - change this when adding
+    real code to handle ioctls.
+
+*/
+DECLHIDDEN(NTSTATUS)
+vboxNetFltWinPtDispatch(
+    IN PDEVICE_OBJECT    pDeviceObject,
+    IN PIRP              pIrp
+    )
+{
+    PIO_STACK_LOCATION  pIrpStack;
+    NTSTATUS            Status = STATUS_SUCCESS;
+
+    LogFlow(("==>Pt Dispatch\n"));
+    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
+
+
+    switch (pIrpStack->MajorFunction)
+    {
+        case IRP_MJ_CREATE:
+            break;
+
+        case IRP_MJ_CLEANUP:
+            break;
+
+        case IRP_MJ_CLOSE:
+            break;
+
+        case IRP_MJ_DEVICE_CONTROL:
+            Status = vboxNetFltWinPtDispatchIoctl(pDeviceObject, pIrpStack);
+            break;
+        default:
+            break;
+    }
+
+    pIrp->IoStatus.Status = Status;
+    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+
+    LogFlow(("<== Pt Dispatch\n"));
+
+    return Status;
+
+}
+#endif
+
+/*
+ * netflt
+ */
+#ifndef VBOXNETADP
+/*
+ * NOTE! the routine is NOT re-enterable for the given pAdapt
+ * the serialization is not implemented for performance reasons
+ * since we are assuming the caller serializes the requests as IntNet does
+ */
+static NDIS_STATUS vboxNetFltWinSynchNdisRequest(PADAPT pAdapt, PNDIS_REQUEST pRequest)
+{
+    int rc;
+
+    Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+    /* 1. serialize */
+    rc = RTSemFastMutexRequest(pAdapt->hSynchRequestMutex); AssertRC(rc);
+    if(RT_SUCCESS(rc))
+    {
+        NDIS_STATUS fRequestStatus = NDIS_STATUS_SUCCESS;
+
+        /* 2. set pAdapt->pSynchRequest */
+        Assert(!pAdapt->pSynchRequest);
+        pAdapt->pSynchRequest = pRequest;
+
+        /* 3. call NdisRequest */
+        NdisRequest(&fRequestStatus, pAdapt->hBindingHandle, pRequest);
+
+        if(fRequestStatus == NDIS_STATUS_PENDING)
+        {
+        /* 3.1 if pending wait and assign the resulting status */
+            KeWaitForSingleObject(&pAdapt->hSynchCompletionEvent, Executive,
+                            KernelMode, FALSE, NULL);
+
+            fRequestStatus = pAdapt->fSynchCompletionStatus;
+        }
+
+        /* 4. clear the pAdapt->pSynchRequest */
+        pAdapt->pSynchRequest = NULL;
+
+        RTSemFastMutexRelease(pAdapt->hSynchRequestMutex); AssertRC(rc);
+        return fRequestStatus;
+    }
+    return NDIS_STATUS_FAILURE;
+}
+
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinGetMacAddress(PADAPT pAdapt, 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(pAdapt, &request);
+    if(status != NDIS_STATUS_SUCCESS)
+    {
+        /* TODO */
+        Assert(0);
+    }
+
+    return status;
+
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PADAPT pAdapt, 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(pAdapt, &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));
+            Assert(0);
+        }
+    }
+    return Status;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinIsPromiscuous(PADAPT pAdapt)
+{
+    /** @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(pAdapt));
+    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(pAdapt, &request);
+    if(status != NDIS_STATUS_SUCCESS)
+    {
+        /* TODO */
+        Assert(0);
+        return false;
+    }
+    return (filter & NDIS_PACKET_TYPE_PROMISCUOUS) != 0;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinSetPromiscuous(PADAPT pAdapt, bool bYes)
+{
+    Assert(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
+    if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
+    {
+        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(pAdapt, &Request);
+        if(fStatus != NDIS_STATUS_SUCCESS)
+        {
+            /* TODO: */
+            Assert(0);
+            return fStatus;
+        }
+
+        if(!pAdapt->bUpperProtSetFilterInitialized)
+        {
+            /* the cache was not initialized yet, initiate it with the current filter value */
+            pAdapt->fUpperProtocolSetFilter = fFilter;
+            pAdapt->bUpperProtSetFilterInitialized = true;
+        }
+
+
+        if(bYes)
+        {
+            fExpectedFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
+            fOurFilter = NDIS_PACKET_TYPE_PROMISCUOUS;
+        }
+        else
+        {
+            fExpectedFilter = pAdapt->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(pAdapt, &Request);
+            if(fStatus != NDIS_STATUS_SUCCESS)
+            {
+                /* TODO */
+                Assert(0);
+                return fStatus;
+            }
+        }
+        pAdapt->fOurSetFilter = fOurFilter;
+        return fStatus;
+    }
+    return NDIS_STATUS_NOT_SUPPORTED;
+}
+#else /* if defined 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";
+    uint8_t u8;
+    int i;
+    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( i = 0; i < 6; i++)
+    {
+        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 vboxNetFltWinWchar2Int(WCHAR c, uint8_t * pv)
+{
+    if(c >= L'A' && c <= L'F')
+    {
+        *pv = (c - L'A') + 10;
+    }
+    else if(c >= L'a' && c <= L'f')
+    {
+        *pv = (c - L'a') + 10;
+    }
+    else if(c >= L'0' && c <= L'9')
+    {
+        *pv = (c - L'0');
+    }
+    else
+    {
+        return VERR_INVALID_PARAMETER;
+    }
+    return VINF_SUCCESS;
+}
+
+DECLHIDDEN(int) vboxNetFltWinMACFromNdisString(RTMAC *pMac, PNDIS_STRING pNdisString)
+{
+    int i, rc;
+    PWSTR pString;
+
+    /* validate parameters */
+    AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pNdisString, VERR_INVALID_PARAMETER);
+    AssertReturn(pNdisString->Length >= 12*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
+
+    pString = pNdisString->Buffer;
+
+    for(i = 0; i < 6; i++)
+    {
+        uint8_t v1, v2;
+        rc = vboxNetFltWinWchar2Int(pString[0], &v1);
+        if(RT_FAILURE(rc))
+        {
+            break;
+        }
+
+        rc = vboxNetFltWinWchar2Int(pString[1], &v2);
+        if(RT_FAILURE(rc))
+        {
+            break;
+        }
+
+        pMac->au8[i] = (v1 << 4) | v2;
+
+        pString += 2;
+    }
+
+    return rc;
+}
+
+#endif
+/**
+ * creates a NDIS_PACKET from the PINTNETSG
+ */
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+/* TODO: the bToWire parameter seems to be unneeded here, remove them*/
+#endif
+DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PADAPT pAdapt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory)
+{
+    NDIS_STATUS fStatus;
+    PNDIS_PACKET pPacket;
+
+    Assert(pSG->cSegsUsed == 1);
+    Assert(pSG->cbTotal == pSG->aSegs[0].cb);
+    Assert(pSG->aSegs[0].pv);
+    Assert(pSG->cbTotal >= sizeof(ETH_HEADER_SIZE));
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    NdisAllocatePacket(&fStatus, &pPacket, pAdapt->hSendPacketPoolHandle);
+#elif defined(VBOXNETADP)
+    NdisAllocatePacket(&fStatus, &pPacket, pAdapt->hRecvPacketPoolHandle);
+#else
+    NdisAllocatePacket(&fStatus, &pPacket, bToWire ? pAdapt->hSendPacketPoolHandle : pAdapt->hRecvPacketPoolHandle);
+#endif
+    if(fStatus == NDIS_STATUS_SUCCESS)
+    {
+        PNDIS_BUFFER pBuffer;
+        PVOID pMemBuf;
+
+        if(bCopyMemory)
+        {
+            fStatus = vboxNetFltWinMemAlloc(&pMemBuf, pSG->cbTotal);
+            if(fStatus == NDIS_STATUS_SUCCESS)
+            {
+                NdisMoveMemory(pMemBuf, pSG->aSegs[0].pv, pSG->cbTotal);
+            }
+            else
+            {
+                Assert(0);
+                NdisFreePacket(pPacket);
+                pPacket = NULL;
+            }
+        }
+        else
+        {
+            pMemBuf = pSG->aSegs[0].pv;
+        }
+        if(fStatus == NDIS_STATUS_SUCCESS)
+        {
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+            NdisAllocateBuffer(&fStatus, &pBuffer,
+                    pAdapt->hSendBufferPoolHandle,
+                    pMemBuf,
+                    pSG->cbTotal);
+#elif defined(VBOXNETADP)
+            NdisAllocateBuffer(&fStatus, &pBuffer,
+                    pAdapt->hRecvBufferPoolHandle,
+                    pMemBuf,
+                    pSG->cbTotal);
+#else
+            NdisAllocateBuffer(&fStatus, &pBuffer,
+                    bToWire ? pAdapt->hSendBufferPoolHandle : pAdapt->hRecvBufferPoolHandle,
+                    pMemBuf,
+                    pSG->cbTotal);
+#endif
+
+            if(fStatus == NDIS_STATUS_SUCCESS)
+            {
+                NdisChainBufferAtBack(pPacket, pBuffer);
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+                if(bToWire)
+#endif
+                {
+                    PSEND_RSVD        pSendRsvd;
+                    pSendRsvd = (PSEND_RSVD)(pPacket->ProtocolReserved);
+                    pSendRsvd->pOriginalPkt = NULL;
+                    pSendRsvd->pBufToFree = pBufToFree;
+
+                    /* set "don't loopback" flags */
+                    NdisSetPacketFlags(pPacket, g_fPacketDontLoopBack);
+                }
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+                else
+                {
+                    PRECV_RSVD      pRecvRsvd;
+                    pRecvRsvd = (PRECV_RSVD)(pPacket->MiniportReserved);
+                    pRecvRsvd->pOriginalPkt = NULL;
+                    pRecvRsvd->pBufToFree = pBufToFree;
+
+                    /* me must set the header size on receive */
+                    NDIS_SET_PACKET_HEADER_SIZE(pPacket, ETH_HEADER_SIZE);
+                    /* NdisAllocatePacket zero-initializes the OOB data,
+                     * but keeps the packet flags, clean them here */
+                    NdisSetPacketFlags(pPacket, 0);
+                }
+#endif
+                /* TODO: set out of bound data */
+            }
+            else
+            {
+                Assert(0);
+                if(bCopyMemory)
+                {
+                    vboxNetFltWinMemFree(pMemBuf);
+                }
+                NdisFreePacket(pPacket);
+                pPacket = NULL;
+            }
+        }
+        else
+        {
+            Assert(0);
+            NdisFreePacket(pPacket);
+            pPacket = NULL;
+        }
+    }
+    else
+    {
+        pPacket = NULL;
+    }
+
+    DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+
+    return pPacket;
+}
+
+/*
+ * frees NDIS_PACKET creaed 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 pMemBuf;
+            UINT cbLength;
+
+            NdisQueryBufferSafe(pBuffer, &pMemBuf, &cbLength, NormalPagePriority);
+            NdisFreeBuffer(pBuffer);
+            if(bFreeMem)
+            {
+                vboxNetFltWinMemFree(pMemBuf);
+            }
+        }
+        else
+        {
+            break;
+        }
+    } while(true);
+
+    NdisFreePacket(pPacket);
+}
+
+/*
+ * Free all packet pools on the specified adapter.
+ * @param pAdapt    - pointer to ADAPT structure
+ */
+static VOID
+vboxNetFltWinPtFreeAllPacketPools(
+    IN PADAPT                    pAdapt
+    )
+{
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    if (pAdapt->hRecvPacketPoolHandle != NULL)
+    {
+        /*
+         * Free the packet pool that is used to indicate receives
+         */
+        NdisFreePacketPool(pAdapt->hRecvPacketPoolHandle);
+
+        pAdapt->hRecvPacketPoolHandle = NULL;
+    }
+#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND*/
+#ifndef VBOXNETADP
+    if (pAdapt->hSendPacketPoolHandle != NULL)
+    {
+
+        /*
+         *  Free the packet pool that is used to send packets below
+         */
+
+        NdisFreePacketPool(pAdapt->hSendPacketPoolHandle);
+
+        pAdapt->hSendPacketPoolHandle = NULL;
+
+    }
+#endif
+}
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+static void vboxNetFltWinAssociateMiniportProtocol()
+{
+    NdisIMAssociateMiniport(vboxNetFltWinMpGetHandle(), vboxNetFltWinPtGetHandle());
+}
+#endif
+
+/*
+ * NetFlt driver unload function
+ */
+DECLHIDDEN(VOID)
+vboxNetFltWinUnload(
+    IN PDRIVER_OBJECT        DriverObject
+    )
+{
+    int rc;
+    UNREFERENCED_PARAMETER(DriverObject);
+
+    LogFlow(("vboxNetFltWinUnload: entered\n"));
+
+    rc = vboxNetFltWinTryFiniIdc();
+    if (RT_FAILURE(rc))
+    {
+        /* TODO: we can not prevent driver unload here */
+        Assert(0);
+
+        Log(("vboxNetFltWinTryFiniIdc - failed, busy.\n"));
+    }
+
+    vboxNetFltWinJobFiniQueue(&g_JobQueue);
+#ifndef VBOXNETADP
+    vboxNetFltWinPtDeregister();
+#endif
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    vboxNetFltWinMpDeregister();
+#endif
+
+    vboxNetFltWinFiniNetFltBase();
+    /* don't use logging or any RT after de-init */
+
+    NdisFreeSpinLock(&g_GlobalLock);
+}
+
+RT_C_DECLS_BEGIN
+
+NTSTATUS
+DriverEntry(
+    IN PDRIVER_OBJECT        DriverObject,
+    IN PUNICODE_STRING       RegistryPath
+    );
+
+RT_C_DECLS_END
+/*
+ * First entry point to be called, when this driver is loaded.
+ * Register with NDIS as an intermediate driver.
+ * @return  STATUS_SUCCESS if all initialization is successful, STATUS_XXX
+ *   error code if not.
+ */
+NTSTATUS
+DriverEntry(
+    IN PDRIVER_OBJECT        DriverObject,
+    IN PUNICODE_STRING       RegistryPath
+    )
+{
+    NDIS_STATUS                        Status = NDIS_STATUS_SUCCESS;
+    int rc;
+
+    NdisAllocateSpinLock(&g_GlobalLock);
+
+    do
+    {
+        ULONG MjVersion;
+        ULONG MnVersion;
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+        /* we are registering in the DriverEntry only when we are working as a protocol
+         * since in this case our driver is loaded after the VBoxDrv*/
+        rc = vboxNetFltWinInitNetFlt();
+#else
+        /* 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();
+#endif
+        if(!RT_SUCCESS(rc))
+        {
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+
+        PsGetVersion(&MjVersion, &MnVersion,
+          NULL, /* PULONG  BuildNumber  OPTIONAL */
+          NULL /* PUNICODE_STRING  CSDVersion  OPTIONAL */
+          );
+
+        g_fPacketDontLoopBack = NDIS_FLAGS_DONT_LOOPBACK;
+
+        if(MjVersion == 5 && MnVersion == 0)
+        {
+            /* this is Win2k*/
+            g_fPacketDontLoopBack |= NDIS_FLAGS_SKIP_LOOPBACK_W2K;
+        }
+
+        g_fPacketIsLoopedBack = NDIS_FLAGS_IS_LOOPBACK_PACKET;
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        Status = vboxNetFltWinMpRegister(DriverObject, RegistryPath);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            vboxNetFltWinFiniNetFlt();
+            break;
+        }
+#endif
+#ifndef VBOXNETADP
+        Status = vboxNetFltWinPtRegister(DriverObject, RegistryPath);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+            vboxNetFltWinMpDeregister();
+#endif
+            vboxNetFltWinFiniNetFlt();
+            break;
+        }
+#endif
+
+        Status = vboxNetFltWinJobInitQueue(&g_JobQueue);
+        if(Status != STATUS_SUCCESS)
+        {
+#ifndef VBOXNETADP
+            vboxNetFltWinPtDeregister();
+#endif
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+            vboxNetFltWinMpDeregister();
+#endif
+            vboxNetFltWinFiniNetFlt();
+            break;
+        }
+
+        /* note: we do it after we initialize the Job Queue */
+        vboxNetFltWinStartInitIdcProbing();
+
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+        vboxNetFltWinAssociateMiniportProtocol();
+#endif
+    } while (FALSE);
+
+    return(Status);
+}
+
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(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(
+    IN PADAPT             pAdapt,
+    IN PNDIS_PACKET           pPacket,
+    OUT PNDIS_PACKET         *ppMyPacket
+    /*,    IN bool bNetFltActive */
+    )
+{
+    NDIS_STATUS fStatus;
+
+    NdisAllocatePacket(&fStatus,
+                       ppMyPacket,
+                       pAdapt->hSendPacketPoolHandle);
+
+    if (fStatus == NDIS_STATUS_SUCCESS)
+    {
+        PSEND_RSVD        pSendRsvd;
+
+        pSendRsvd = (PSEND_RSVD)((*ppMyPacket)->ProtocolReserved);
+        pSendRsvd->pOriginalPkt = pPacket;
+        pSendRsvd->pBufToFree = NULL;
+
+        NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
+        NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
+
+        vboxNetFltWinCopyPacketInfoOnSend(*ppMyPacket, pPacket);
+
+//        if(bNetFltActive)
+//        {
+            NdisGetPacketFlags(*ppMyPacket) |= g_fPacketDontLoopBack;
+//        }
+    }
+    else
+    {
+        *ppMyPacket = NULL;
+    }
+
+    return fStatus;
+}
+
+/**
+ * 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(
+    IN PADAPT            pAdapt,
+    IN PNDIS_PACKET           pPacket,
+    OUT PNDIS_PACKET        *ppMyPacket,
+    IN bool bDpr
+    )
+{
+    NDIS_STATUS         fStatus;
+
+    /*
+     * Get a packet off the pool and indicate that up
+     */
+    if(bDpr)
+    {
+        Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+        NdisDprAllocatePacket(&fStatus,
+                               ppMyPacket,
+                               pAdapt->hRecvPacketPoolHandle);
+    }
+    else
+    {
+        NdisAllocatePacket(&fStatus,
+                               ppMyPacket,
+                               pAdapt->hRecvPacketPoolHandle);
+    }
+
+    if (fStatus == NDIS_STATUS_SUCCESS)
+    {
+        PRECV_RSVD            pRecvRsvd;
+
+        pRecvRsvd = (PRECV_RSVD)((*ppMyPacket)->MiniportReserved);
+        pRecvRsvd->pOriginalPkt = pPacket;
+        pRecvRsvd->pBufToFree = NULL;
+
+        NDIS_PACKET_FIRST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
+        NDIS_PACKET_LAST_NDIS_BUFFER(*ppMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
+
+        fStatus = vboxNetFltWinCopyPacketInfoOnRecv(*ppMyPacket, pPacket);
+    }
+    else
+    {
+        *ppMyPacket = NULL;
+    }
+    return fStatus;
+}
+#endif
+
+/**
+ * initializes the ADAPT (our context structure) and binds to the given adapter
+ */
+#if defined(VBOX_NETFLT_ONDEMAND_BIND)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT pAdapt)
+#elif defined(VBOXNETADP)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext)
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName)
+#endif
+{
+    NDIS_STATUS Status;
+    do
+    {
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        ANSI_STRING AnsiString;
+        int rc;
+        PVBOXNETFLTINS pInstance;
+        USHORT cbAnsiName = pBindToMiniportName->Length;/* the lenght is is bytes ; *2 ;RtlUnicodeStringToAnsiSize(pBindToMiniportName)*/
+        char* pAnsiName = alloca(cbAnsiName);
+        CREATE_INSTANCE_CONTEXT Context;
+        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+# ifndef VBOXNETADP
+        Context.pOurName = pOurMiniportName;
+        Context.pBindToName = pBindToMiniportName;
+# else
+        Context.hMiniportAdapter = hMiniportAdapter;
+        Context.hWrapperConfigurationContext = hWrapperConfigurationContext;
+# endif
+        Context.Status = NDIS_STATUS_SUCCESS;
+
+        AnsiString.Buffer = pAnsiName;
+        AnsiString.Length = 0;
+        AnsiString.MaximumLength = cbAnsiName;
+
+        Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+        Status = RtlUnicodeStringToAnsiString(&AnsiString, pBindToMiniportName, false);
+
+        if(Status != STATUS_SUCCESS)
+        {
+            break;
+        }
+
+        rc = vboxNetFltSearchCreateInstance(&g_VBoxNetFltGlobals, pAnsiName, &pInstance, &Context);
+        if(RT_FAILURE(rc))
+        {
+        	Assert(0);
+      		Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
+            break;
+        }
+
+        Assert(pInstance);
+
+        if(rc == VINF_ALREADY_INITIALIZED)
+        {
+            PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
+            /* 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*/
+
+            /* re-initialize PADAPT */
+            rc = vboxNetFltWinAttachToInterface(pInstance, &Context, true);
+            if(RT_FAILURE(rc))
+            {
+                Assert(0);
+          		Status = Context.Status != NDIS_STATUS_SUCCESS ? Context.Status : NDIS_STATUS_FAILURE;
+                /* release netflt */
+                vboxNetFltRelease(pInstance, false);
+
+                break;
+            }
+        }
+
+        *ppAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
+#else
+        Status = vboxNetFltWinPtAllocInitPADAPT(pAdapt);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            break;
+        }
+
+        Status = vboxNetFltWinPtDoBinding(pAdapt);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            vboxNetFltWinPtFiniPADAPT(pAdapt);
+            break;
+        }
+#endif
+    }while(FALSE);
+
+    return Status;
+}
+
+/**
+ * initializes the ADAPT
+ */
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtAllocInitPADAPT(PADAPT pAdapt)
+{
+    NDIS_STATUS Status;
+
+    do
+    {
+        Status = vboxNetFltWinPtInitPADAPT(pAdapt);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            break;
+        }
+        Status = NDIS_STATUS_SUCCESS;
+    } while(0);
+
+    return Status;
+}
+
+/**
+ * unbinds from the adapter we are bound to and deinitializes the ADAPT
+ */
+static NDIS_STATUS vboxNetFltWinPtFiniUnbind(PADAPT pAdapt)
+{
+    NDIS_STATUS Status;
+
+    LogFlow(("==> vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    do
+    {
+        Status = vboxNetFltWinPtDoUnbinding(pAdapt, true);
+        if(Status != NDIS_STATUS_SUCCESS)
+        {
+            Assert(0);
+            /* TODO: should we break ? */
+            /* break; */
+        }
+
+        vboxNetFltWinPtFiniPADAPT(pAdapt);
+    } while(0);
+    LogFlow(("<== vboxNetFltWinPtFiniUnbind: Adapt %p\n", pAdapt));
+
+    return Status;
+}
+#endif
+
+/*
+ * deinitializes the ADAPT
+ */
+DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt)
+{
+#ifndef VBOXNETADP
+    int rc;
+#endif
+
+    LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+#ifndef VBOXNETADP
+    if(pAdapt->DeviceName.Buffer)
+    {
+        vboxNetFltWinMemFree(pAdapt->DeviceName.Buffer);
+    }
+
+
+    FINI_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
+#endif
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "add list cleaning code here"
+#endif
+
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    /* moved to vboxNetFltWinDetachFromInterfaceWorker */
+#else
+    vboxNetFltWinQuFiniPacketQueue(pAdapt);
+#endif
+
+    vboxNetFltWinFiniBuffers(pAdapt);
+
+    /*
+     *    Free the memory here, if was not released earlier(by calling the HaltHandler)
+     */
+    vboxNetFltWinPtFreeAllPacketPools (pAdapt);
+#ifndef VBOXNETADP
+    rc = RTSemFastMutexDestroy(pAdapt->hSynchRequestMutex);  AssertRC(rc);
+#endif
+
+    LogFlow(("<== vboxNetFltWinPtFiniPADAPT : pAdapt %p\n", pAdapt));
+}
+
+DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt);
+#ifndef VBOXNETADP
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN  PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName)
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN  PADAPT pAdapt)
+#endif
+{
+    NDIS_STATUS                     Status;
+#ifndef VBOXNETADP
+    int rc;
+#endif
+    BOOLEAN                         bCallFiniOnFail = FALSE;
+
+    LogFlow(("==> vboxNetFltWinPtInitPADAPT : pAdapt %p\n", pAdapt));
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    do
+    {
+        NdisZeroMemory(pAdapt, sizeof(ADAPT));
+#ifndef VBOXNETADP
+        NdisInitializeEvent(&pAdapt->hEvent);
+
+        KeInitializeEvent(&pAdapt->hSynchCompletionEvent, SynchronizationEvent, FALSE);
+
+        /*
+         * Allocate a packet pool for sends. We need this to pass sends down.
+         * We cannot use the same packet descriptor that came down to our send
+         * handler (see also NDIS 5.1 packet stacking).
+         */
+        NdisAllocatePacketPoolEx(&Status,
+                                   &pAdapt->hSendPacketPoolHandle,
+                                   MIN_PACKET_POOL_SIZE,
+                                   MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
+                                   sizeof(PT_RSVD));
+
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            pAdapt->hSendPacketPoolHandle = NULL;
+            break;
+        }
+#else
+#endif
+
+        Status = vboxNetFltWinInitBuffers(pAdapt);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            break;
+        }
+
+        bCallFiniOnFail = TRUE;
+#ifndef VBOXNETADP
+        rc = RTSemFastMutexCreate(&pAdapt->hSynchRequestMutex);
+        if(RT_FAILURE(rc))
+        {
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+#endif
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+# ifndef VBOXNETADP
+        Status = vboxNetFltWinMemAlloc((PVOID*)&pAdapt->DeviceName.Buffer, pOurDeviceName->Length);
+        if(Status != NDIS_STATUS_SUCCESS)
+        {
+            Assert(0);
+            pAdapt->DeviceName.Buffer = NULL;
+            break;
+        }
+        pAdapt->DeviceName.MaximumLength = pOurDeviceName->Length;
+        pAdapt->DeviceName.Length = 0;
+        Status = vboxNetFltWinCopyString(&pAdapt->DeviceName, pOurDeviceName);
+        if(Status != NDIS_STATUS_SUCCESS)
+        {
+            Assert(0);
+            break;
+        }
+# endif
+
+        /*
+         * Allocate a packet pool for receives. We need this to indicate receives.
+         * Same consideration as sends (see also NDIS 5.1 packet stacking).
+         */
+        NdisAllocatePacketPoolEx(&Status,
+                                   &pAdapt->hRecvPacketPoolHandle,
+                                   MIN_PACKET_POOL_SIZE,
+                                   MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
+                                   PROTOCOL_RESERVED_SIZE_IN_PACKET);
+
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            pAdapt->hRecvPacketPoolHandle = NULL;
+            break;
+        }
+#ifndef VBOXNETADP
+        NdisInitializeEvent(&pAdapt->MiniportInitEvent);
+#endif
+#endif
+#ifndef VBOXNETADP
+        pAdapt->PTState.PowerState = NdisDeviceStateD3;
+        vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+
+        INIT_INTERLOCKED_SINGLE_LIST(&pAdapt->TransferDataList);
+#endif
+        /* TODO: do we need it here ?? */
+        pAdapt->MPState.PowerState = NdisDeviceStateD3;
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "add list initialization code here"
+#endif
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+        {
+            PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+            rc = vboxNetFltWinConnectIt(pNetFlt);
+            if(RT_FAILURE(rc))
+            {
+                Assert(0);
+                Status = NDIS_STATUS_FAILURE;
+                break;
+            }
+        }
+#endif
+
+        /* moved to vboxNetFltOsInitInstance */
+    } while(0);
+
+    if (Status != NDIS_STATUS_SUCCESS)
+    {
+        if(bCallFiniOnFail)
+        {
+            vboxNetFltWinPtFiniPADAPT(pAdapt);
+        }
+    }
+
+    LogFlow(("<== vboxNetFltWinPtInitPADAPT : pAdapt %p, Status %x\n", pAdapt, 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))
+
+#ifdef 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;
+    PVOID pMemBuf1;
+    UINT cbLength1 = 0;
+
+    UINT cBufCount2;
+    PNDIS_BUFFER pBuffer2;
+    UINT uTotalPacketLength2;
+    PVOID pMemBuf2;
+    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 ucbMatch;
+        if(cbMatch < 0 || (UINT)cbMatch > uTotalPacketLength1)
+        {
+            /* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
+            ucbMatch = uTotalPacketLength1;
+#ifdef DEBUG_NETFLT_PACKETS
+            bCompleteMatch = true;
+#endif
+        }
+        else
+        {
+            ucbMatch = (UINT)cbMatch;
+        }
+
+        do
+        {
+            UINT ucbLength2Match;
+            if(!cbLength1)
+            {
+                NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
+                NdisGetNextBuffer(pBuffer1, &pBuffer1);
+            }
+
+            if(!cbLength2)
+            {
+                NdisQueryBufferSafe(pBuffer2, &pMemBuf2, &cbLength2, NormalPagePriority);
+                NdisGetNextBuffer(pBuffer2, &pBuffer2);
+            }
+
+            ucbLength2Match = MIN(ucbMatch, cbLength1);
+            ucbLength2Match = MIN(ucbMatch, cbLength2);
+
+            if(memcmp(pMemBuf1, pMemBuf2, ucbLength2Match))
+            {
+                bMatch = false;
+                break;
+            }
+            ucbMatch -= ucbLength2Match;
+            cbLength1 -= ucbLength2Match;
+            cbLength2 -= ucbLength2Match;
+        } while (ucbMatch);
+    }
+
+#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;
+    PVOID pMemBuf1;
+    UINT cbLength1 = 0;
+    UINT uTotalPacketLength2 = pSG->cbTotal;
+    PVOID pMemBuf2;
+    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)
+    {
+        Assert(0);
+        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)
+            {
+                NdisQueryBufferSafe(pBuffer1, &pMemBuf1, &cbLength1, NormalPagePriority);
+                NdisGetNextBuffer(pBuffer1, &pBuffer1);
+            }
+
+            if(!cbLength2)
+            {
+                Assert(i < pSG->cSegsUsed);
+                pMemBuf2 = pSG->aSegs[i].pv;
+                cbLength2 = pSG->aSegs[i].cb;
+                i++;
+            }
+
+            ucbLength2Match = MIN(ucbMatch, cbLength1);
+            ucbLength2Match = MIN(ucbMatch, cbLength2);
+
+            if(memcmp(pMemBuf1, pMemBuf2, ucbLength2Match))
+            {
+                bMatch = false;
+                Assert(0);
+                break;
+            }
+            ucbMatch -= ucbLength2Match;
+            cbLength1 -= ucbLength2Match;
+            cbLength2 -= ucbLength2Match;
+        } while (ucbMatch);
+    }
+
+    if(bMatch && !bCompleteMatch)
+    {
+        /* check that the packets fully match */
+        DBG_CHECK_PACKET_AND_SG(pPacket, pSG);
+    }
+    return bMatch;
+}
+
+/*
+ * 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 pMemBuf1;
+    UINT cbLength1 = 0;
+    UINT i1 = 0;
+    UINT uTotalPacketLength2 = pSG2->cbTotal;
+    PVOID pMemBuf2;
+    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)
+    {
+        Assert(0);
+        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);
+                pMemBuf1 = pSG1->aSegs[i1].pv;
+                cbLength1 = pSG1->aSegs[i1].cb;
+                i1++;
+            }
+
+            if(!cbLength2)
+            {
+                Assert(i2 < pSG2->cSegsUsed);
+                pMemBuf2 = pSG2->aSegs[i2].pv;
+                cbLength2 = pSG2->aSegs[i2].cb;
+                i2++;
+            }
+
+            ucbLength2Match = MIN(ucbMatch, cbLength1);
+            ucbLength2Match = MIN(ucbMatch, cbLength2);
+
+            if(memcmp(pMemBuf1, pMemBuf2, ucbLength2Match))
+            {
+                bMatch = false;
+                Assert(0);
+                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
+
+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);
+}
+
+static int vboxNetFltWinTryFiniIdc()
+{
+    int rc;
+
+    vboxNetFltWinStopInitIdcProbing();
+
+    if(g_bIdcInitialized)
+    {
+        rc = vboxNetFltTryDeleteIdc(&g_VBoxNetFltGlobals);
+        if(RT_SUCCESS(rc))
+        {
+            g_bIdcInitialized = false;
+        }
+    }
+    else
+    {
+        rc = VINF_SUCCESS;
+    }
+    return rc;
+
+}
+
+static int vboxNetFltWinFiniNetFlt()
+{
+    int rc = vboxNetFltWinTryFiniIdc();
+    if(RT_SUCCESS(rc))
+    {
+        vboxNetFltWinFiniNetFltBase();
+    }
+    return rc;
+}
+
+/**
+ * base netflt initialization
+ */
+static int vboxNetFltWinInitNetFltBase()
+{
+    int rc;
+
+    do
+    {
+        Assert(!g_bIdcInitialized);
+
+        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_bIdcInitialized)
+        {
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+            Assert(0);
+#endif
+            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_bIdcInitialized = true;
+    } while (0);
+
+    return rc;
+}
+
+static void vboxNetFltWinInitIdcProbingWorker(PINIT_IDC_INFO pInitIdcInfo)
+{
+    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_JobQueue, &pInitIdcInfo->Job, false);
+                return;
+            }
+        }
+
+        /* it's interupted */
+        rc = VERR_INTERRUPTED;
+    }
+
+    ASMAtomicUoWriteU32(&pInitIdcInfo->rc, rc);
+    KeSetEvent(&pInitIdcInfo->hCompletionEvent, 0, FALSE);
+}
+
+static int vboxNetFltWinStopInitIdcProbing()
+{
+    if(!g_InitIdcInfo.bInitialized)
+        return VERR_INVALID_STATE;
+
+    ASMAtomicUoWriteBool(&g_InitIdcInfo.bStop, true);
+    KeWaitForSingleObject(&g_InitIdcInfo.hCompletionEvent, Executive, KernelMode, FALSE, NULL);
+
+    return g_InitIdcInfo.rc;
+}
+
+static int vboxNetFltWinStartInitIdcProbing()
+{
+    Assert(!g_bIdcInitialized);
+    KeInitializeEvent(&g_InitIdcInfo.hCompletionEvent, NotificationEvent, FALSE);
+    g_InitIdcInfo.bStop = false;
+    g_InitIdcInfo.bInitialized = true;
+    vboxNetFltWinJobInit(&g_InitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_InitIdcInfo, false);
+    vboxNetFltWinJobEnqueueJob(&g_JobQueue, &g_InitIdcInfo.Job, false);
+    return VINF_SUCCESS;
+}
+
+static int vboxNetFltWinInitNetFlt()
+{
+    int rc;
+
+    do
+    {
+        rc = vboxNetFltWinInitNetFltBase();
+        if(RT_FAILURE(rc))
+        {
+            Assert(0);
+            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))
+        {
+            Assert(0);
+            vboxNetFltWinFiniNetFltBase();
+            break;
+        }
+    } while (0);
+
+    return rc;
+}
+
+/* detach*/
+static int vboxNetFltWinDeleteInstance(PVBOXNETFLTINS pThis)
+{
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    NDIS_STATUS Status;
+    LogFlow(("vboxNetFltWinDeleteInstance: pThis=%p \n", pThis));
+
+    Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+    Assert(pAdapt);
+    Assert(pThis);
+    Assert(pThis->fDisconnectedFromHost);
+    Assert(!pThis->fRediscoveryPending);
+    Assert(!pThis->fActive);
+#ifndef VBOXNETADP
+    Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized);
+    Assert(!pAdapt->hBindingHandle);
+#endif
+    Assert(pAdapt->MPState.OpState == kVBoxNetDevOpState_Deinitialized);
+    Assert(!pThis->u.s.PacketQueueWorker.pSG);
+//    Assert(!pAdapt->hMiniportHandle);
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    Status = vboxNetFltWinMpDereferenceControlDevice();
+    Assert(Status == NDIS_STATUS_SUCCESS);
+#else
+    Status = vboxNetFltWinPtFiniUnbind(pAdapt);
+    if(Status != NDIS_STATUS_SUCCESS)
+    {
+        Assert(0);
+        /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
+    }
+#endif
+
+    RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
+
+    return VINF_SUCCESS;
+}
+
+static NDIS_STATUS vboxNetFltWinDisconnectIt(PVBOXNETFLTINS pInstance)
+{
+    vboxNetFltWinQuFiniPacketQueue(pInstance);
+    return NDIS_STATUS_SUCCESS;
+}
+
+/* detach*/
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinDetachFromInterface(PADAPT pAdapt, bool bOnUnbind)
+{
+    PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    NDIS_STATUS Status;
+    int rc;
+    LogFlow(("vboxNetFltWinDetachFromInterface: pThis=%p\n", pThis));
+
+    Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+    Assert(pAdapt);
+    Assert(pThis);
+/*    Assert(!pThis->fActive); */
+
+    /* paranoya to ensyre 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(pThis, false);
+
+    rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
+    if(RT_SUCCESS(rc))
+    {
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected);
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
+#ifndef VBOXNETADP
+        Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
+#endif
+//        if(
+//#ifdef VBOXNETADP
+//                vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
+//#else
+//                vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized
+////                    && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized
+//#endif
+//                )
+        if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Connected)
+        {
+            vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnecting);
+#ifndef VBOXNETADP
+            Status = vboxNetFltWinPtDoUnbinding(pAdapt, bOnUnbind);
+#else
+            Status = vboxNetFltWinMpDoDeinitialization(pAdapt);
+#endif
+            Assert(Status == NDIS_STATUS_SUCCESS);
+
+            vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
+            Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+            Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+//            /* paranoya */
+//            vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+//#ifndef VBOXNETADP
+//            vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+//#endif
+
+            vboxNetFltWinPtFiniPADAPT(pAdapt);
+
+            /* we're unbinding, make an unbind-related release */
+            vboxNetFltRelease(pThis, false);
+#else
+            Status = vboxNetFltWinPtFiniUnbind(pAdapt);
+            if(Status != NDIS_STATUS_SUCCESS)
+            {
+                Assert(0);
+                /* pDetachInfo->Status = VERR_GENERAL_FAILURE; */
+            }
+#endif
+        }
+        else
+        {
+            AssertBreakpoint();
+#ifndef VBOXNETADP
+            pAdapt->Status = NDIS_STATUS_FAILURE;
+#endif
+            if(!bOnUnbind)
+            {
+                vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+            }
+            Status = NDIS_STATUS_FAILURE;
+        }
+        RTSemMutexRelease(pThis->u.s.hAdaptMutex);
+    }
+    else
+    {
+        AssertBreakpoint();
+        Status = NDIS_STATUS_FAILURE;
+    }
+
+    /* release for the retain we made before waining on the mutex */
+    vboxNetFltRelease(pThis, false);
+
+    return Status;
+}
+
+/**
+ * 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;
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    /* to ensure we're not removed while we're here */
+    vboxNetFltRetain(pThis, false);
+
+    rc = RTSemMutexRequest(pThis->u.s.hAdaptMutex, RT_INDEFINITE_WAIT);
+    if(RT_SUCCESS(rc))
+    {
+        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+        Assert(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected);
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+        Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+//        if(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
+//#ifndef VBOXNETADP
+//                && vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized
+//#endif
+//                )
+        if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnected)
+        {
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+            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 = vboxNetFltWinPtInitPADAPT(pAdapt, pAttachInfo->pCreateContext->pOurName);
+#else
+            Status = vboxNetFltWinPtInitPADAPT(pAdapt);
+#endif
+            if(Status == NDIS_STATUS_SUCCESS)
+            {
+                vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connecting);
+
+#ifndef VBOXNETADP
+                Status = vboxNetFltWinPtDoBinding(pAdapt, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
+#else
+                Status = vboxNetFltWinMpDoInitialization(pAdapt, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
+#endif
+                if (Status == NDIS_STATUS_SUCCESS)
+                {
+                    if(pAttachInfo->fRediscovery || (Status = vboxNetFltWinMpReferenceControlDevice()) == NDIS_STATUS_SUCCESS)
+                    {
+#ifndef VBOXNETADP
+                        if(pAdapt->Status == NDIS_STATUS_SUCCESS)
+#endif
+                        {
+                            vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Connected);
+//                            Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
+#ifndef VBOXNETADP
+                            Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
+#endif
+//                            /* paranoya */
+////                            vboxNetFltWinSetAdaptState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
+//#ifndef VBOXNETADP
+//                            vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initialized);
+//#endif
+
+                            RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
+
+                            /* 4. mark as connected */
+                            ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false);
+
+                            RTSpinlockRelease(pThis->hSpinlock, &Tmp);
+
+                            pAttachInfo->Status = VINF_SUCCESS;
+                            pAttachInfo->pCreateContext->Status = NDIS_STATUS_SUCCESS;
+
+                            RTSemMutexRelease(pThis->u.s.hAdaptMutex);
+
+                            vboxNetFltRelease(pThis, false);
+
+                            return;
+                        }
+                        AssertBreakpoint();
+
+                        if(!pAttachInfo->fRediscovery)
+                        {
+                            vboxNetFltWinMpDereferenceControlDevice();
+                        }
+                    }
+                    AssertBreakpoint();
+#ifndef VBOXNETADP
+                    vboxNetFltWinPtDoUnbinding(pAdapt, true);
+#else
+                    vboxNetFltWinMpDoDeinitialization(pAdapt);
+#endif
+                }
+                AssertBreakpoint();
+                vboxNetFltWinPtFiniPADAPT(pAdapt);
+            }
+            AssertBreakpoint();
+            vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
+            Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+            Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
+#endif
+//            /* paranoya */
+//            vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+//#ifndef VBOXNETADP
+//            vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+//#endif
+        }
+        AssertBreakpoint();
+
+#else  /* VBOX_NETFLT_ONDEMAND_BIND */
+            Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+            Status = vboxNetFltWinPtInitBind(pAdapt);
+            if (Status != NDIS_STATUS_SUCCESS)
+            {
+                pAttachInfo->Status = VERR_GENERAL_FAILURE;
+                break;
+            }
+
+            Status = vboxNetFltWinGetMacAddress(pAdapt, &pThis->u.s.Mac);
+            if (Status != NDIS_STATUS_SUCCESS)
+            {
+                vboxNetFltWinPtFiniUnbind(pAdapt);
+                pAttachInfo->Status = VERR_GENERAL_FAILURE;
+                break;
+            }
+#endif /* VBOX_NETFLT_ONDEMAND_BIND */
+
+
+        pAttachInfo->Status = VERR_GENERAL_FAILURE;
+        pAttachInfo->pCreateContext->Status = Status;
+        RTSemMutexRelease(pThis->u.s.hAdaptMutex);
+    }
+    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;
+
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    /* packet queue worker thread gets created on attach interface, need to do it via job at passive level */
+    vboxNetFltWinJobSynchExecAtPassive((JOB_ROUTINE)vboxNetFltWinAttachToInterfaceWorker, &Info);
+#else
+    vboxNetFltWinAttachToInterfaceWorker(&Info);
+#endif
+    return Info.Status;
+}
+
+/*
+ *
+ * The OS specific interface definition
+ *
+ */
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+    /* AttachToInterface true if disconnected */
+    return !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
+}
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
+{
+    int rc = VINF_SUCCESS;
+    uint32_t cRefs = 0;
+    PADAPT pAdapt;
+#if !defined(VBOXNETADP) && !defined(VBOX_NETFLT_ONDEMAND_BIND)
+    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);
+
+    pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
+
+    if(!vboxNetFltWinIncReferenceAdapt(pAdapt, cRefs))
+    {
+        return VERR_GENERAL_FAILURE;
+    }
+#ifndef VBOXNETADP
+    if ((fDst & INTNETTRUNKDIR_WIRE)
+# ifdef VBOX_NETFLT_ONDEMAND_BIND
+         ||   (fDst & INTNETTRUNKDIR_HOST)
+# endif
+            )
+    {
+        PNDIS_PACKET pPacket;
+
+        pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
+                                                true /*fToWire*/, true /*fCopyMemory*/);
+
+        if (pPacket)
+        {
+            NDIS_STATUS fStatus;
+# ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            PPACKET_INFO pInfo = vboxNetFltWinDoSend(&fStatus, pAdapt, pPacket);
+# else
+            NdisSend(&fStatus, pAdapt->hBindingHandle, pPacket);
+# endif
+            if (fStatus != NDIS_STATUS_PENDING)
+            {
+                if(!NT_SUCCESS(fStatus))
+                {
+                    /* TODO: convert status to VERR_xxx */
+                    rc = VERR_GENERAL_FAILURE;
+                }
+# ifdef DEBUG_NETFLT_LOOPBACK
+#  error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//                if(pInfo)
+//                {
+//                    /* TODO: FIXME: remove this assert */
+//                    Assert(fStatus == NDIS_STATUS_SUCCESS);
+//
+//                    vboxNetFltWinDoCompleteSendViaInfo(pAdapt, pInfo);
+//                    vboxNetFltWinPpFreePacketInfo(pInfo);
+//                }
+//                else
+//                {
+//                    Assert(0);
+//                }
+# endif
+                vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+            }
+            else
+            {
+                /* pending, dereference on packet complete */
+                cRefs--;
+            }
+        }
+        else
+        {
+            Assert(0);
+            rc = VERR_NO_MEMORY;
+        }
+    }
+#endif
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+#ifndef VBOXNETADP
+    if (fDst & INTNETTRUNKDIR_HOST)
+#else
+    if(cRefs)
+#endif
+    {
+        PNDIS_PACKET pPacket = vboxNetFltWinNdisPacketFromSG(pAdapt, pSG, NULL /*pBufToFree*/,
+                                                             false /*fToWire*/, true /*fCopyMemory*/);
+        if (pPacket)
+        {
+# ifndef DEBUG_NETFLT_LOOPBACK
+            NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, &pPacket, 1);
+# else
+#  error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            PPACKET_INFO pInfo = vboxNetFltWinDoIndicateReceive(pAdapt, pPacket);
+//            if(!pInfo)
+//            {
+//                Assert(0);
+//                vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+//                rc = VERR_NO_MEMORY;
+//            }
+//            else
+# endif
+            {
+                cRefs--;
+            }
+#ifdef VBOXNETADP
+            STATISTIC_INCREASE(pAdapt->cRxSuccess);
+#endif
+        }
+        else
+        {
+            Assert(0);
+#ifdef VBOXNETADP
+            STATISTIC_INCREASE(pAdapt->cRxError);
+#endif
+            rc = VERR_NO_MEMORY;
+        }
+    }
+
+    Assert(cRefs <= 2);
+
+    if(cRefs)
+    {
+        vboxNetFltWinDecReferenceAdapt(pAdapt, cRefs);
+    }
+#endif
+
+    return rc;
+}
+
+bool vboxNetFltPortOsIsPromiscuous(PVBOXNETFLTINS pThis)
+{
+#ifndef VBOXNETADP
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
+    if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
+    {
+        bool bPromiscuous;
+        if(!vboxNetFltWinReferenceAdapt(pAdapt))
+            return false;
+
+        bPromiscuous = (pAdapt->fOurSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
+            /*vboxNetFltWinIsPromiscuous(pAdapt);*/
+
+        vboxNetFltWinDereferenceAdapt(pAdapt);
+        return bPromiscuous;
+    }
+    return false;
+#else
+    return true;
+#endif
+}
+
+void vboxNetFltPortOsGetMacAddress(PVBOXNETFLTINS pThis, PRTMAC pMac)
+{
+    *pMac = pThis->u.s.Mac;
+}
+
+bool vboxNetFltPortOsIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
+{
+    /* ASSUMES that the MAC address never changes. */
+    return pThis->u.s.Mac.au16[0] == pMac->au16[0]
+        && pThis->u.s.Mac.au16[1] == pMac->au16[1]
+        && pThis->u.s.Mac.au16[2] == pMac->au16[2];
+}
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+#ifndef VBOXNETADP
+    NDIS_STATUS Status;
+#endif
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
+    if(!vboxNetFltWinReferenceAdapt(pAdapt))
+        return;
+
+#ifndef VBOXNETADP
+# ifndef VBOX_NETFLT_ONDEMAND_BIND
+    if(fActive)
+    {
+        /*
+         * flush any pass-thru receive-queued packets
+         */
+        vboxNetFltWinPtFlushReceiveQueue(pAdapt, false /*fReturn*/);
+    }
+# endif
+
+
+    if(fActive)
+    {
+#ifdef DEBUG_misha
+        NDIS_PHYSICAL_MEDIUM           PhMedium;
+        bool bPromiscSupported;
+
+        Status = vboxNetFltWinQueryPhysicalMedium(pAdapt, &PhMedium);
+        if(Status != NDIS_STATUS_SUCCESS)
+        {
+
+            DBGPRINT(("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
+        {
+            DBGPRINT(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
+        }
+
+        bPromiscSupported =  (!(PhMedium == NdisPhysicalMediumWirelessWan
+                        || PhMedium == NdisPhysicalMediumWirelessLan
+                        || PhMedium == NdisPhysicalMediumNative802_11
+                        || PhMedium == NdisPhysicalMediumBluetooth
+                        /*|| PhMedium == NdisPhysicalMediumWiMax */
+                        ));
+
+        Assert(bPromiscSupported == VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt));
+#endif
+    }
+
+    if(VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
+    {
+        Status = vboxNetFltWinSetPromiscuous(pAdapt, fActive);
+        if(Status != NDIS_STATUS_SUCCESS)
+        {
+            DBGPRINT(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
+            Assert(0);
+            LogRel(("vboxNetFltWinSetPromiscuous failed, Status (0x%x), fActive (%d)\n", Status, fActive));
+        }
+    }
+#else
+# ifdef VBOXNETADP_REPORT_DISCONNECTED
+    if(fActive)
+    {
+        NdisMIndicateStatus(pAdapt->hMiniportHandle,
+                                 NDIS_STATUS_MEDIA_CONNECT,
+                                 (PVOID)NULL,
+                                 0);
+    }
+    else
+    {
+        NdisMIndicateStatus(pAdapt->hMiniportHandle,
+                                 NDIS_STATUS_MEDIA_DISCONNECT,
+                                 (PVOID)NULL,
+                                 0);
+    }
+#else
+    if(fActive)
+    {
+        /* indicate status change to make the ip settings be re-picked for dhcp */
+        NdisMIndicateStatus(pAdapt->hMiniportHandle,
+                                 NDIS_STATUS_MEDIA_DISCONNECT,
+                                 (PVOID)NULL,
+                                 0);
+
+        NdisMIndicateStatus(pAdapt->hMiniportHandle,
+                                 NDIS_STATUS_MEDIA_CONNECT,
+                                 (PVOID)NULL,
+                                 0);
+    }
+# endif
+#endif
+    vboxNetFltWinDereferenceAdapt(pAdapt);
+
+    return;
+}
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+    NDIS_STATUS Status = vboxNetFltWinDisconnectIt(pThis);
+    return Status == NDIS_STATUS_SUCCESS ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
+}
+
+static void vboxNetFltWinConnectItWorker(PWORKER_INFO pInfo)
+{
+    NDIS_STATUS Status;
+    PVBOXNETFLTINS pInstance = pInfo->pNetFltIf;
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pInstance);
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    /* this is not a rediscovery, initialize Mac cache */
+    if(vboxNetFltWinReferenceAdapt(pAdapt))
+    {
+#ifndef VBOXNETADP
+        Status = vboxNetFltWinGetMacAddress(pAdapt, &pInstance->u.s.Mac);
+        if (Status == NDIS_STATUS_SUCCESS)
+#endif
+        {
+            Status = vboxNetFltWinQuInitPacketQueue(pInstance);
+            if(Status == NDIS_STATUS_SUCCESS)
+            {
+                pInfo->Status = VINF_SUCCESS;
+            }
+            else
+            {
+                pInfo->Status = VERR_GENERAL_FAILURE;
+            }
+        }
+#ifndef VBOXNETADP
+        else
+        {
+            pInfo->Status = VERR_INTNET_FLT_IF_FAILED;
+        }
+#endif
+
+        vboxNetFltWinDereferenceAdapt(pAdapt);
+    }
+    else
+    {
+        pInfo->Status = VERR_INTNET_FLT_IF_NOT_FOUND;
+    }
+}
+
+static int vboxNetFltWinConnectIt(PVBOXNETFLTINS pThis)
+{
+    WORKER_INFO Info;
+    Info.pNetFltIf = pThis;
+
+    vboxNetFltWinJobSynchExecAtPassive(vboxNetFltWinConnectItWorker, &Info);
+
+    return Info.Status;
+}
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+    return vboxNetFltWinConnectIt(pThis);
+}
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+    vboxNetFltWinDeleteInstance(pThis);
+}
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
+{
+    int rc = RTSemMutexCreate(&pThis->u.s.hAdaptMutex);
+    if (RT_SUCCESS(rc))
+    {
+        rc = vboxNetFltWinAttachToInterface(pThis, pvContext, false /*fRediscovery*/ );
+        if (RT_SUCCESS(rc))
+        {
+            return rc;
+        }
+        RTSemMutexDestroy(pThis->u.s.hAdaptMutex);
+    }
+    return rc;
+}
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+    PADAPT pAdapt = PVBOXNETFLTINS_2_PADAPT(pThis);
+    vboxNetFltWinSetAdaptState(pAdapt, kVBoxAdaptState_Disconnected);
+    vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+    vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+#endif
+    return VINF_SUCCESS;
+}
+
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.h
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.h	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt-win.h	(revision 21333)
@@ -0,0 +1,935 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Integration with IntNet/NetFlt
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ * Copyright (c) 1993-1999, Microsoft Corporation
+ */
+
+#ifndef ___VBoxNetFlt_win_h___
+#define ___VBoxNetFlt_win_h___
+
+/*
+ * globals
+ */
+
+/** global lock */
+extern NDIS_SPIN_LOCK     g_GlobalLock;
+
+extern UINT g_fPacketDontLoopBack;
+extern UINT g_fPacketIsLoopedBack;
+
+/*
+ * Debug Print API
+ */
+#ifdef DEBUG
+
+#define DBGPRINT(Fmt) DbgPrint Fmt
+
+#else /* if DBG */
+
+#define DBGPRINT(Fmt)
+
+#endif /* if DBG */
+
+
+DECLHIDDEN(NTSTATUS) vboxNetFltWinPtDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
+DECLHIDDEN(VOID) vboxNetFltWinUnload(IN PDRIVER_OBJECT DriverObject);
+
+/*************************
+ * packet queue API      *
+ *************************/
+
+
+#define LIST_ENTRY_2_PACKET_INFO(pListEntry) \
+    ( (PPACKET_INFO)((uint8_t *)(pListEntry) - RT_OFFSETOF(PACKET_INFO, ListEntry)) )
+
+/**
+ * enqueus the packet info to the tail of the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuEnqueueTail(PPACKET_QUEUE pQueue, PPACKET_INFO pPacketInfo)
+{
+    InsertTailList(pQueue, &pPacketInfo->ListEntry);
+}
+
+DECLINLINE(void) vboxNetFltWinQuEnqueueHead(PPACKET_QUEUE pQueue, PPACKET_INFO pPacketInfo)
+{
+    Assert(pPacketInfo->pPool);
+    InsertHeadList(pQueue, &pPacketInfo->ListEntry);
+}
+
+/**
+ * enqueus the packet info to the tail of the queue
+ */
+DECLINLINE(void) vboxNetFltWinQuInterlockedEnqueueTail(PINTERLOCKED_PACKET_QUEUE pQueue, PPACKET_INFO pPacketInfo)
+{
+    Assert(pPacketInfo->pPool);
+    NdisAcquireSpinLock(&pQueue->Lock);
+    vboxNetFltWinQuEnqueueTail(&pQueue->Queue, pPacketInfo);
+    NdisReleaseSpinLock(&pQueue->Lock);
+}
+
+DECLINLINE(void) vboxNetFltWinQuInterlockedEnqueueHead(PINTERLOCKED_PACKET_QUEUE pQueue, PPACKET_INFO pPacketInfo)
+{
+    NdisAcquireSpinLock(&pQueue->Lock);
+    vboxNetFltWinQuEnqueueHead(&pQueue->Queue, pPacketInfo);
+    NdisReleaseSpinLock(&pQueue->Lock);
+}
+
+/**
+ * dequeus the packet info from the head of the queue
+ */
+DECLINLINE(PPACKET_INFO) vboxNetFltWinQuDequeueHead(PPACKET_QUEUE pQueue)
+{
+    PLIST_ENTRY pListEntry = RemoveHeadList(pQueue);
+    if(pListEntry != pQueue)
+    {
+        PPACKET_INFO pInfo = LIST_ENTRY_2_PACKET_INFO(pListEntry);
+        Assert(pInfo->pPool);
+        return pInfo;
+    }
+    return NULL;
+}
+
+DECLINLINE(PPACKET_INFO) vboxNetFltWinQuDequeueTail(PPACKET_QUEUE pQueue)
+{
+    PLIST_ENTRY pListEntry = RemoveTailList(pQueue);
+    if(pListEntry != pQueue)
+    {
+        PPACKET_INFO pInfo = LIST_ENTRY_2_PACKET_INFO(pListEntry);
+        Assert(pInfo->pPool);
+        return pInfo;
+    }
+    return NULL;
+}
+
+DECLINLINE(PPACKET_INFO) vboxNetFltWinQuInterlockedDequeueHead(PINTERLOCKED_PACKET_QUEUE pInterlockedQueue)
+{
+    PPACKET_INFO pInfo;
+    NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+    pInfo = vboxNetFltWinQuDequeueHead(&pInterlockedQueue->Queue);
+    NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+    return pInfo;
+}
+
+DECLINLINE(PPACKET_INFO) vboxNetFltWinQuInterlockedDequeueTail(PINTERLOCKED_PACKET_QUEUE pInterlockedQueue)
+{
+    PPACKET_INFO pInfo;
+    NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+    pInfo = vboxNetFltWinQuDequeueTail(&pInterlockedQueue->Queue);
+    NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+    return pInfo;
+}
+
+DECLINLINE(void) vboxNetFltWinQuDequeue(PPACKET_INFO pInfo)
+{
+    RemoveEntryList(&pInfo->ListEntry);
+}
+
+DECLINLINE(void) vboxNetFltWinQuInterlockedDequeue(PINTERLOCKED_PACKET_QUEUE pInterlockedQueue, PPACKET_INFO pInfo)
+{
+    NdisAcquireSpinLock(&pInterlockedQueue->Lock);
+    vboxNetFltWinQuDequeue(pInfo);
+    NdisReleaseSpinLock(&pInterlockedQueue->Lock);
+}
+
+/**
+ * allocates the packet info from the pool
+ */
+DECLINLINE(PPACKET_INFO) vboxNetFltWinPpAllocPacketInfo(PPACKET_INFO_POOL pPool)
+{
+    return vboxNetFltWinQuInterlockedDequeueHead(&pPool->Queue);
+}
+
+/**
+ * returns the packet info to the pool
+ */
+DECLINLINE(void) vboxNetFltWinPpFreePacketInfo(PPACKET_INFO pInfo)
+{
+    PPACKET_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((void * volatile *)&(_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)))
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQuEnqueuePacket(PVBOXNETFLTINS pInstance, PVOID pPacket, const UINT fPacketFlags);
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+DECLHIDDEN(void) vboxNetFltWinQuFiniPacketQueue(PVBOXNETFLTINS pInstance);
+
+DECLHIDDEN(NTSTATUS) vboxNetFltWinQuInitPacketQueue(PVBOXNETFLTINS pInstance);
+#endif
+
+
+/**
+ * searches the list entry in a single-linked list
+ */
+DECLINLINE(bool) vboxNetFltWinSearchListEntry(PSINGLE_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;
+}
+
+DECLINLINE(void) vboxNetFltWinPutTail(PSINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+    pList->pTail->Next = pEntry;
+    pList->pTail = pEntry;
+}
+
+DECLINLINE(PSINGLE_LIST_ENTRY) vboxNetFltWinGetHead(PSINGLE_LIST pList)
+{
+    PSINGLE_LIST_ENTRY pEntry = pList->Head.Next;
+    if(pEntry && pEntry == pList->pTail)
+    {
+        pList->pTail = &pList->Head;
+    }
+    return pEntry;
+}
+
+DECLINLINE(bool) vboxNetFltWinInterlockedSearchListEntry(PINTERLOCKED_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;
+}
+
+DECLINLINE(void) vboxNetFltWinInterlockedPutTail(PINTERLOCKED_SINGLE_LIST pList, PSINGLE_LIST_ENTRY pEntry)
+{
+    NdisAcquireSpinLock(&pList->Lock);
+    vboxNetFltWinPutTail(&pList->List, pEntry);
+    NdisReleaseSpinLock(&pList->Lock);
+}
+
+DECLINLINE(PSINGLE_LIST_ENTRY) vboxNetFltWinInterlockedGetHead(PINTERLOCKED_SINGLE_LIST pList)
+{
+    PSINGLE_LIST_ENTRY pEntry;
+    NdisAcquireSpinLock(&pList->Lock);
+    pEntry = vboxNetFltWinGetHead(&pList->List);
+    NdisReleaseSpinLock(&pList->Lock);
+    return pEntry;
+}
+
+/** 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) \
+    { \
+        INIT_SINGLE_LIST(&(_pList)->List); \
+        NdisAllocateSpinLock(&(_pList)->Lock); \
+    }
+
+/** delete the packet queue */
+#define FINI_INTERLOCKED_SINGLE_LIST(_pList) NdisFreeSpinLock(&(_pList)->Lock)
+
+/** obtains the PTRANSFERDATA_RSVD given a single list entry it contains */
+#define PT_SLE_2_TRANSFERDATA_RSVD(_pl) \
+    ( (PTRANSFERDATA_RSVD)((uint8_t *)(_pl) - RT_OFFSETOF(TRANSFERDATA_RSVD, ListEntry)))
+
+/** obtains the ndis packet given a single list entry assuming it is stored in ProtocolReserved field of the packet */
+#define PT_SLE_2_NDIS_PACKET(_pl) \
+   ( (PNDIS_PACKET)((uint8_t *)PT_SLE_2_TRANSFERDATA_RSVD(_pl) - RT_OFFSETOF(NDIS_PACKET, ProtocolReserved)))
+
+/**************************************************************************
+ * PADAPT, PVBOXNETFLTINS reference/dereference (i.e. retain/release) API *
+ **************************************************************************/
+
+/** get the PVBOXNETFLTINS from PADAPT */
+#define PADAPT_2_PVBOXNETFLTINS(_pAdapt)  ( (PVBOXNETFLTINS)((uint8_t *)(_pAdapt) - RT_OFFSETOF(VBOXNETFLTINS, u.s.IfAdaptor)) )
+/** get the PADAPT from PVBOXNETFLTINS */
+#define PVBOXNETFLTINS_2_PADAPT(_pNetFlt) ( &(_pNetFlt)->u.s.IfAdaptor )
+
+DECLHIDDEN(void) vboxNetFltWinWaitDereference(PADAPT_DEVICE pState);
+
+DECLINLINE(void) vboxNetFltWinSetPowerState(PADAPT_DEVICE pState, NDIS_DEVICE_POWER_STATE State)
+{
+    ASMAtomicUoWriteU32((volatile uint32_t *)&pState->PowerState, State);
+}
+
+DECLINLINE(NDIS_DEVICE_POWER_STATE) vboxNetFltWinGetPowerState(PADAPT_DEVICE pState)
+{
+    return (NDIS_DEVICE_POWER_STATE)ASMAtomicUoReadU32((volatile uint32_t *)&pState->PowerState);
+}
+
+DECLINLINE(void) vboxNetFltWinSetOpState(PADAPT_DEVICE pState, VBOXNETDEVOPSTATE State)
+{
+    ASMAtomicUoWriteU32((volatile uint32_t *)&pState->OpState, State);
+}
+
+DECLINLINE(VBOXNETDEVOPSTATE) vboxNetFltWinGetOpState(PADAPT_DEVICE pState)
+{
+    return (VBOXNETDEVOPSTATE)ASMAtomicUoReadU32((volatile uint32_t *)&pState->OpState);
+}
+
+DECLINLINE(bool) vboxNetFltWinDoReferenceDevice(PADAPT pAdapt, PADAPT_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(PADAPT pAdapt, PADAPT_DEVICE pState1, PADAPT_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(PADAPT pAdapt, PADAPT_DEVICE pState)
+{
+/*    NdisAcquireSpinLock(&pAdapt->Lock); */
+    ASMAtomicDecU32((uint32_t volatile *)&pState->cReferences);
+    /** @todo r=bird: Add comment explaining why these cannot hit 0 or why
+     *        reference are counted  */
+/*    NdisReleaseSpinLock(&pAdapt->Lock); */
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(void) vboxNetFltWinDereferenceDevices(PADAPT pAdapt, PADAPT_DEVICE pState1, PADAPT_DEVICE pState2)
+{
+/*    NdisAcquireSpinLock(&pAdapt->Lock); */
+    ASMAtomicDecU32((uint32_t volatile *)&pState1->cReferences);
+    ASMAtomicDecU32((uint32_t volatile *)&pState2->cReferences);
+/*    NdisReleaseSpinLock(&pAdapt->Lock); */
+}
+#endif
+
+DECLINLINE(void) vboxNetFltWinDecReferenceDevice(PADAPT pAdapt, PADAPT_DEVICE pState, uint32_t v)
+{
+    ASMAtomicAddU32((uint32_t volatile *)&pState->cReferences, (uint32_t)(-((int32_t)v)));
+}
+
+#ifndef VBOXNETADP
+DECLINLINE(void) vboxNetFltWinDecReferenceDevices(PADAPT pAdapt, PADAPT_DEVICE pState1, PADAPT_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(PADAPT pAdapt, PADAPT_DEVICE pState, uint32_t 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(PADAPT pAdapt, PADAPT_DEVICE pState1, PADAPT_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
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+DECLINLINE(PVBOXNETFLTINS) vboxNetFltWinReferenceAdaptNetFltFromAdapt(PADAPT pAdapt)
+{
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    PVBOXNETFLTINS pNetFlt;
+
+    pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+
+    RTSpinlockAcquire((pNetFlt)->hSpinlock, &Tmp);
+    if(!ASMAtomicUoReadBool(&(pNetFlt)->fActive))
+    {
+        RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+        return NULL;
+    }
+
+    if(!vboxNetFltWinDoReferenceDevice(pAdapt, &pAdapt->PTState))
+    {
+        RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+        return NULL;
+    }
+
+    vboxNetFltRetain((pNetFlt), true /* fBusy */);
+
+    RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+
+    return pNetFlt;
+}
+#else
+DECLINLINE(bool) vboxNetFltWinReferenceAdaptNetFltFromAdapt(PADAPT pAdapt, PVBOXNETFLTINS *ppNetFlt)
+{
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+
+    RTSpinlockAcquire((pNetFlt)->hSpinlock, &Tmp);
+#ifndef VBOXNETADP
+    if(!vboxNetFltWinDoReferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState))
+#else
+    if(!vboxNetFltWinDoReferenceDevice(pAdapt, &pAdapt->MPState))
+#endif
+    {
+        RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+        *ppNetFlt = NULL;
+        return false;
+    }
+
+    if(!ASMAtomicUoReadBool(&(pNetFlt)->fActive))
+    {
+        RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+        *ppNetFlt = NULL;
+        return true;
+    }
+
+    vboxNetFltRetain((pNetFlt), true /* fBusy */);
+
+    RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+
+    *ppNetFlt = pNetFlt;
+    return true;
+}
+#endif
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+DECLINLINE(PVBOXNETFLTINS) vboxNetFltWinIncReferenceAdaptNetFltFromAdapt(PADAPT pAdapt, uint32_t v)
+{
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    PVBOXNETFLTINS pNetFlt;
+    uint32_t i;
+
+    Assert(v);
+    if(!v)
+    {
+        return NULL;
+    }
+
+    pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+
+    RTSpinlockAcquire((pNetFlt)->hSpinlock, &Tmp);
+    if(!ASMAtomicUoReadBool(&(pNetFlt)->fActive))
+    {
+        RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+        return NULL;
+    }
+
+    if(!vboxNetFltWinDoIncReferenceDevice(pAdapt, &pAdapt->PTState, v))
+    {
+        RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+        return NULL;
+    }
+
+    vboxNetFltRetain((pNetFlt), true /* fBusy */);
+
+    RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+
+    /* 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 */);
+    }
+
+    return pNetFlt;
+}
+#else
+DECLINLINE(bool) vboxNetFltWinIncReferenceAdaptNetFltFromAdapt(PADAPT pAdapt, PVBOXNETFLTINS *ppNetFlt, uint32_t v)
+{
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    uint32_t i;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+
+    Assert(v);
+    if(!v)
+    {
+        *ppNetFlt = NULL;
+        return false;
+    }
+
+    RTSpinlockAcquire((pNetFlt)->hSpinlock, &Tmp);
+#ifndef VBOXNETADP
+    if(!vboxNetFltWinDoIncReferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState, v))
+#else
+    if(!vboxNetFltWinDoIncReferenceDevice(pAdapt, &pAdapt->MPState, v))
+#endif
+    {
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        *ppNetFlt = NULL;
+        return false;
+    }
+
+    if(!ASMAtomicUoReadBool(&(pNetFlt)->fActive))
+    {
+        RTSpinlockRelease((pNetFlt)->hSpinlock, &Tmp);
+        *ppNetFlt = NULL;
+        return true;
+    }
+
+    vboxNetFltRetain(pNetFlt, true /* fBusy */);
+    RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+
+    /* 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 */);
+    }
+
+    *ppNetFlt = pNetFlt;
+
+    return true;
+}
+
+#endif
+
+DECLINLINE(void) vboxNetFltWinDecReferenceNetFlt(PVBOXNETFLTINS pNetFlt, uint32_t n)
+{
+    uint32_t i;
+    for(i = 0; i < n; i++)
+    {
+        vboxNetFltRelease(pNetFlt, true);
+    }
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceNetFlt(PVBOXNETFLTINS pNetFlt)
+{
+    vboxNetFltRelease(pNetFlt, true);
+}
+
+DECLINLINE(void) vboxNetFltWinDecReferenceAdapt(PADAPT pAdapt, uint32_t v)
+{
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    vboxNetFltWinDecReferenceDevice(pAdapt, &pAdapt->PTState, v);
+#elif defined(VBOXNETADP)
+    vboxNetFltWinDecReferenceDevice(pAdapt, &pAdapt->MPState, v);
+#else
+    vboxNetFltWinDecReferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState, v);
+#endif
+}
+
+DECLINLINE(void) vboxNetFltWinDereferenceAdapt(PADAPT pAdapt)
+{
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    vboxNetFltWinDereferenceDevice(pAdapt, &pAdapt->PTState);
+#elif defined(VBOXNETADP)
+    vboxNetFltWinDereferenceDevice(pAdapt, &pAdapt->MPState);
+#else
+    vboxNetFltWinDereferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState);
+#endif
+}
+
+DECLINLINE(bool) vboxNetFltWinIncReferenceAdapt(PADAPT pAdapt, uint32_t v)
+{
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+    Assert(v);
+    if(!v)
+    {
+        return false;
+    }
+
+    RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    if(vboxNetFltWinDoIncReferenceDevice(pAdapt, &pAdapt->PTState))
+#elif defined(VBOXNETADP)
+    if(vboxNetFltWinDoIncReferenceDevice(pAdapt, &pAdapt->MPState, v))
+#else
+    if(vboxNetFltWinDoIncReferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState, v))
+#endif
+    {
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        return true;
+    }
+
+    RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+    return false;
+}
+
+DECLINLINE(bool) vboxNetFltWinReferenceAdapt(PADAPT pAdapt)
+{
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    if(vboxNetFltWinDoReferenceDevice(pAdapt, &pAdapt->PTState))
+#elif defined(VBOXNETADP)
+    if(vboxNetFltWinDoReferenceDevice(pAdapt, &pAdapt->MPState))
+#else
+    if(vboxNetFltWinDoReferenceDevices(pAdapt, &pAdapt->MPState, &pAdapt->PTState))
+#endif
+    {
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        return true;
+    }
+
+    RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+    return false;
+}
+
+/***********************************************
+ * methods for accessing the network card info *
+ ***********************************************/
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinGetMacAddress(PADAPT pAdapt, PRTMAC pMac);
+DECLHIDDEN(bool) vboxNetFltWinIsPromiscuous(PADAPT pAdapt);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinSetPromiscuous(PADAPT pAdapt, bool bYes);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PADAPT pAdapt, 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 refering 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);
+
+/************************
+ * PADAPT init/fini API *
+ ************************/
+
+#if defined(VBOX_NETFLT_ONDEMAND_BIND)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT pAdapt);
+#elif defined(VBOXNETADP)
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PADAPT *ppAdapt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName);
+#endif
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtAllocInitPADAPT(PADAPT pAdapt);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtAllocInitPADAPT(PADAPT *ppAdapt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName);
+#endif
+
+DECLHIDDEN(VOID) vboxNetFltWinPtFiniPADAPT(PADAPT pAdapt);
+#ifndef VBOXNETADP
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN  PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitPADAPT(IN  PADAPT pAdapt);
+#endif
+
+/************************************
+ * Execute Job at passive level API *
+ ************************************/
+
+typedef VOID (*JOB_ROUTINE) (PVOID pContext);
+
+DECLHIDDEN(VOID) vboxNetFltWinJobSynchExecAtPassive(JOB_ROUTINE pRoutine, PVOID pContext);
+
+/*******************************
+ * Ndis Packets processing API *
+ *******************************/
+
+#ifndef NDIS_PACKET_FIRST_NDIS_BUFFER
+#define NDIS_PACKET_FIRST_NDIS_BUFFER(_Packet)      ((_Packet)->Private.Head)
+#endif
+
+#ifndef NDIS_PACKET_LAST_NDIS_BUFFER
+#define NDIS_PACKET_LAST_NDIS_BUFFER(_Packet)       ((_Packet)->Private.Tail)
+#endif
+
+#ifndef NDIS_PACKET_VALID_COUNTS
+#define NDIS_PACKET_VALID_COUNTS(_Packet)           ((_Packet)->Private.ValidCounts)
+#endif
+
+
+DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PADAPT pAdapt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory);
+
+DECLHIDDEN(void) vboxNetFltWinFreeSGNdisPacket(PNDIS_PACKET pPacket, bool bFreeMem);
+
+#ifdef DEBUG_NETFLT_PACKETS
+DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch);
+
+DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch);
+
+#endif
+
+#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 DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//#ifdef VBOX_NETFLT_ONDEMAND_BIND
+//DECLHIDDEN(bool) vboxNetFltWinIsLoopedBackPacket(PADAPT pAdapt, PNDIS_PACKET pPacket);
+//#else
+//DECLHIDDEN(bool) vboxNetFltWinIsLoopedBackPacket(PADAPT pAdapt, PNDIS_PACKET pPacket, bool bOnRecv);
+//#endif
+//
+//#ifdef VBOX_NETFLT_ONDEMAND_BIND
+//DECLHIDDEN(bool) vboxNetFltWinIsLoopedBackPacketSG(PADAPT pAdapt, PINTNETSG pSG);
+//#else
+//DECLHIDDEN(bool) vboxNetFltWinIsLoopedBackPacketSG(PADAPT pAdapt, PINTNETSG pSG, bool bOnRecv);
+//#endif
+#else
+DECLINLINE(bool) vboxNetFltWinIsLoopedBackPacket(PNDIS_PACKET pPacket)
+{
+    return (NdisGetPacketFlags(pPacket) & g_fPacketIsLoopedBack) == g_fPacketIsLoopedBack;
+}
+#endif
+
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(VBOXNETADP)
+
+/**************************************************************
+ * utility methofs for ndis packet creation/initialization    *
+ **************************************************************/
+DECLINLINE(NDIS_STATUS) vboxNetFltWinCopyPacketInfoOnRecv(PNDIS_PACKET pDstPacket, PNDIS_PACKET pSrcPacket)
+{
+    NDIS_STATUS fStatus;
+
+    /*
+     * Get the original packet (it could be the same packet as the one
+     * received or a different one based on the number of layered miniports
+     * below) and set it on the indicated packet so the OOB data is visible
+     * correctly to protocols above us.
+     */
+    NDIS_SET_ORIGINAL_PACKET(pDstPacket, NDIS_GET_ORIGINAL_PACKET(pSrcPacket));
+
+     /*
+     * Set Packet Flags
+     */
+    NdisGetPacketFlags(pDstPacket) = NdisGetPacketFlags(pSrcPacket);
+
+    fStatus = NDIS_GET_PACKET_STATUS(pSrcPacket);
+
+    NDIS_SET_PACKET_STATUS(pDstPacket, fStatus);
+    NDIS_SET_PACKET_HEADER_SIZE(pDstPacket, NDIS_GET_PACKET_HEADER_SIZE(pSrcPacket));
+
+    return fStatus;
+}
+
+DECLINLINE(void) vboxNetFltWinCopyPacketInfoOnSend(PNDIS_PACKET pDstPacket, PNDIS_PACKET pSrcPacket)
+{
+    PVOID               pMediaSpecificInfo = NULL;
+    UINT                fMediaSpecificInfoSize = 0;
+
+    NdisGetPacketFlags(pDstPacket) = NdisGetPacketFlags(pSrcPacket);
+
+#ifdef WIN9X
+    /*
+     * Work around the fact that NDIS does not initialize this
+     * to FALSE on Win9x.
+     */
+    NDIS_PACKET_VALID_COUNTS(pDstPacket) = FALSE;
+#endif /* WIN9X */
+
+    /*
+     * Copy the OOB data from the original packet to the new
+     * packet.
+     */
+    NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(pDstPacket),
+                NDIS_OOB_DATA_FROM_PACKET(pSrcPacket),
+                sizeof(NDIS_PACKET_OOB_DATA));
+    /*
+     * Copy relevant parts of the per packet info into the new packet
+     */
+#ifndef WIN9X
+    NdisIMCopySendPerPacketInfo(pDstPacket, pSrcPacket);
+#endif
+
+    /*
+     * Copy the Media specific information
+     */
+    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(
+    IN PADAPT             pAdapt,
+    IN PNDIS_PACKET           pPacket,
+    OUT PNDIS_PACKET         *ppMyPacket
+    /*, IN bool bNetFltActive*/
+    );
+
+
+DECLHIDDEN(NDIS_STATUS)
+vboxNetFltWinPrepareRecvPacket(
+    IN PADAPT            pAdapt,
+    IN PNDIS_PACKET           pPacket,
+    OUT PNDIS_PACKET        *ppMyPacket,
+    IN 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(PADAPT pAdapt, 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) vboxNetFltWinSetAdaptState(PADAPT pAdapt, VBOXADAPTSTATE enmNewState)
+{
+    ASMAtomicWriteU32((uint32_t volatile *)&pAdapt->enmState, enmNewState);
+}
+
+/**
+ * Gets the enmState member atomically.
+ *
+ * Used for all reads.
+ *
+ * @returns The enmState value.
+ * @param   pThis           The instance.
+ */
+DECLINLINE(VBOXADAPTSTATE) vboxNetFltWinGetAdaptState(PADAPT pAdapt)
+{
+    return (VBOXADAPTSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pAdapt->enmState);
+}
+
+
+#ifndef VBOXNETADP
+# define VBOXNETFLT_PROMISCUOUS_SUPPORTED(_pAdapt) \
+    (!PADAPT_2_PVBOXNETFLTINS(_pAdapt)->fDisablePromiscuous)
+//    (!((_pAdapt)->PhMedium == NdisPhysicalMediumWirelessWan \
+//    || (_pAdapt)->PhMedium == NdisPhysicalMediumWirelessLan \
+//    || (_pAdapt)->PhMedium == NdisPhysicalMediumNative802_11 \
+//    || (_pAdapt)->PhMedium == NdisPhysicalMediumBluetooth \
+//    /*|| (_pAdapt)->PhMedium == NdisPhysicalMediumWiMax */ \
+//    ))
+#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
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt.inf
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt.inf	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt.inf	(revision 21333)
@@ -0,0 +1,146 @@
+;
+; VirtualBox Bridged Networking Driver
+;
+
+;
+; Copyright (C) 2008 Sun Microsystems, Inc.
+;
+; Sun Microsystems, Inc. confidential
+; All rights reserved
+;
+
+;
+; Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+; Copyright (c) 1993-1999, Microsoft Corporation
+;
+
+[Version]
+Signature  = "$Windows NT$"
+;cat   CatalogFile = VBoxNetFlt.cat
+Class      = NetService
+ClassGUID  = {4D36E974-E325-11CE-BFC1-08002BE10318}
+Provider   = %Provider%
+;DriverPackageType=Network
+;DriverPackageDisplayName=%VBoxNetFlt_Desc%
+;edit-DriverVer=08/13/2008,1.1.0.1
+
+
+[Manufacturer]
+%Provider% = VBox,NTx86,NTia64,NTamd64
+
+[ControlFlags]
+
+;=========================================================================
+;
+;=========================================================================
+
+; For Win2K
+[VBox]
+%VBoxNetFlt_Desc% = VBoxNetFlt.ndi, sun_VBoxNetFlt
+
+; For XP and later
+[VBox.NTx86]
+%VBoxNetFlt_Desc% = VBoxNetFlt.ndi, sun_VBoxNetFlt
+
+[VBox.NTia64]
+%VBoxNetFlt_Desc% = VBoxNetFlt.ndi, sun_VBoxNetFlt
+
+[VBox.NTamd64]
+%VBoxNetFlt_Desc% = VBoxNetFlt.ndi, sun_VBoxNetFlt
+
+[VBoxNetFlt.ndi]
+AddReg          = VBoxNetFlt.ndi.AddReg, VBoxNetFlt.AddReg
+Characteristics = 0x4410 ;  NCF_FILTER | NCF_NDIS_PROTOCOL !--Filter Specific--!!
+CopyFiles       = VBoxNetFlt.Files.DLL, VBoxNetFlt.Files.Sys
+CopyInf         = VBoxNetFlt_m.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]
+; ----------------------------------------------------------------------
+; Add any miniport-specific parameters here.  These are params that your
+; filter device is going to use.
+;
+;HKR, Parameters, ParameterName,  0x10000, "MultiSz", "Parameter", "Value"
+;HKR, Parameters, ParameterName2, 0x10001, 4
+
+
+; ----------------------------------------------------------------------
+; File copy
+;
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetFlt.sys=1
+VBoxNetFltNotify.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]
+VBoxNetFltNotify.dll,,,2
+
+; ----------------------------------------------------------------------
+; Filter Install
+;
+
+[VBoxNetFlt.ndi.AddReg]
+HKR, Ndi, HelpText, , %VBoxNetFlt_HELP%
+
+; ----------------------------------------------------------------------
+; !!--Filter Specific--!!
+;
+; Note:
+; 1. Other components may also have UpperRange/LowerRange but for filters
+;    the value of both of them must be noupper/nolower
+; 2. The value FilterClass is required.
+; 3. The value Service is required
+; 4. FilterDeviceInfId is the InfId of the filter device (miniport) that will
+;    be installed for each filtered adapter.
+;    In this case this is sun_VBoxNetFltmp (refer to VBoxNetFlt_m.inf)
+;
+HKR, Ndi,            ClsID,              0, {c631480a-acbe-4add-bb1d-3ed8aa52b5d9}
+HKR, Ndi,            ComponentDll,        , VBoxNetFltNotify.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, wan, nolower"
+
+[VBoxNetFlt.AddReg]
+; The following key is Required
+; The following key is VBoxNetFlt specific
+HKR, Parameters, Param1, 0, 4
+
+; ----------------------------------------------------------------------
+[Strings]
+Provider = "Sun Microsystems, Inc."
+DiskDescription = "VirtualBox Bridged Networking Driver"
+
+VBoxNetFlt_Desc = "VirtualBox Bridged Networking Driver"
+VBoxNetFlt_HELP = "VBoxNetFlt Driver"
+VBoxNetFltService_Desc = "VBoxNetFlt Service"
+
+
+
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltA-win.asm
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltA-win.asm	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltA-win.asm	(revision 21333)
@@ -0,0 +1,24 @@
+; $Id$
+;; @file
+; VBoxNetFlt - Unwind Wrappers for 64-bit NT.
+;
+
+;
+; Copyright (C) 2008 Sun Microsystems, Inc.
+;
+; Sun Microsystems, Inc. confidential
+; All rights reserved
+;
+
+%include "iprt/ntwrap.mac"
+
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortRetain
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortRelease
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortDisconnectAndRelease
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortSetActive
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortWaitForIdle
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortGetMacAddress
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortIsHostMac
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortIsPromiscuous
+NtWrapDyn2DrvFunctionWithAllRegParams netfltNtWrap, vboxNetFltPortXmit
+
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltCommon-win.h
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltCommon-win.h	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltCommon-win.h	(revision 21333)
@@ -0,0 +1,507 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFltCommon.h - Network Filter Driver (Host), Windows Specific Code. Common headeer with commonly used defines and decls
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ * Copyright (c) 1993-1999, Microsoft Corporation
+ */
+
+#ifndef ___VBoxNetFltCommon_win_h___
+#define ___VBoxNetFltCommon_win_h___
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+# define NDIS_MINIPORT_DRIVER
+# define NDIS50_MINIPORT 1
+#endif
+
+#define BINARY_COMPATIBLE 0
+#define NDIS_WDM 0
+#define NDIS50 1
+#define NTSTRSAFE_LIB
+
+#ifdef DEBUG
+//# define DEBUG_NETFLT_PACKETS
+# ifndef DEBUG_misha
+#  define DEBUG_NETFLT_NOASSERT
+# 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
+#endif
+
+#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
+
+#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>
+
+RT_C_DECLS_BEGIN
+#include <ndis.h>
+RT_C_DECLS_END
+
+
+
+#define VBOXNETFLT_OS_SPECFIC 1
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+# define VBOXNETFLT_PROTOCOL_NAME L"VBoxNetFltPt"
+#else
+# ifndef VBOXNETADP
+#  define VBOXNETFLT_PROTOCOL_NAME L"VBoxNetFlt"
+
+/** this is to support ioctl interface */
+#  define LINKNAME_STRING     L"\\DosDevices\\Global\\VBoxNetFlt"
+#  define NTDEVICE_STRING     L"\\Device\\VBoxNetFlt"
+# else
+#  define LINKNAME_STRING     L"\\DosDevices\\Global\\VBoxNetAdp"
+#  define NTDEVICE_STRING     L"\\Device\\VBoxNetAdp"
+# endif
+//# define VBOXNETFLT_WIN_IOCTL_INIT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_NEITHER,  FILE_WRITE_ACCESS)
+//# define VBOXNETFLT_WIN_IOCTL_FINI CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER,  FILE_WRITE_ACCESS)
+#endif
+
+/** version
+ * NOTE: we are NOT using NDIS 5.1 features now, the code under "#ifdef NDIS51xxx" is not tested and may not work and should be removed soon */
+#ifdef NDIS51_MINIPORT
+# define VBOXNETFLT_MAJOR_NDIS_VERSION            5
+# define VBOXNETFLT_MINOR_NDIS_VERSION            1
+#else
+# define VBOXNETFLT_MAJOR_NDIS_VERSION            5
+# define VBOXNETFLT_MINOR_NDIS_VERSION            0
+#endif
+
+#ifdef NDIS51
+# define VBOXNETFLT_PROT_MAJOR_NDIS_VERSION    5
+# define VBOXNETFLT_PROT_MINOR_NDIS_VERSION    0
+#else
+# define VBOXNETFLT_PROT_MAJOR_NDIS_VERSION    5
+# define VBOXNETFLT_PROT_MINOR_NDIS_VERSION    0
+#endif
+
+/** advance declaration */
+typedef struct _ADAPT ADAPT, *PADAPT;
+
+typedef struct VBOXNETFLTINS *PVBOXNETFLTINS;
+
+/** configuration */
+
+/** received packets queue size. the queue is used when the driver is working in a pass-thru mode */
+#define MAX_RECEIVE_PACKET_ARRAY_SIZE           40
+
+/** Ndis Packet pool settings
+ * these are applied to both receive and send packet pools */
+#define MAX_PACKET_POOL_SIZE 0x0000FFFF
+#define MIN_PACKET_POOL_SIZE 0x000000FF
+
+/** packet queue size used when the driver is working in the "active" mode */
+#define PACKET_INFO_POOL_SIZE 0x0000FFFF
+
+#ifndef VBOXNETADP
+/** memory tag used for memory allocations
+ * (VBNF stands for VBox NetFlt) */
+# define MEM_TAG 'FNBV'
+#else
+/** memory tag used for memory allocations
+ * (VBNA stands for VBox NetAdp) */
+# define MEM_TAG 'ANBV'
+#endif
+
+/** receive and transmit Ndis buffer pool size */
+#define TX_BUFFER_POOL_SIZE 128
+#define RX_BUFFER_POOL_SIZE 128
+
+#define ETH_HEADER_SIZE 14
+
+#define PACKET_QUEUE_SG_SEGS_ALLOC 32
+
+#define VBOX_NETFLT_PACKET_HEADER_MATCH_SIZE 24
+
+#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
+#define     VBOXNETADP_LINK_SPEED 1000000 //The unit of measurement is 100 bps, 100Mbps
+#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 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 PACKET_SRC_HOST             0x00000002
+
+/** 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 acket (the driver below us has called NdisM..IndicateReceive)
+ * this is supported for Ndis Packet only */
+#define PACKET_MINE                 0x00000004
+
+/** flag passed to vboxNetFltWinQuEnqueuePacket specifying that the packet should be copied
+ * this is supported for Ndis Packet only */
+#define PACKET_COPY                 0x00000008
+
+/** packet queue element containing the packet info */
+typedef struct _PACKET_INFO
+{
+    /** list entry used for enqueueing the info */
+    LIST_ENTRY ListEntry;
+    /** pointer to the pool containing this packet info */
+    struct _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;
+}PACKET_INFO, *PPACKET_INFO;
+
+/* paranoid check to make sure the elements in the packet info array are properly aligned */
+C_ASSERT((sizeof(PACKET_INFO) & (sizeof(PVOID) - 1)) == 0);
+
+/** represents the packet queue */
+typedef LIST_ENTRY PACKET_QUEUE, *PPACKET_QUEUE;
+
+/*
+ * we are using non-interlocked versions of LIST_ENTRY-related operations macros and synchronize
+ * access to the queue and its elements by aquiring/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 _INTERLOCKED_PACKET_QUEUE
+{
+    /** queue */
+    PACKET_QUEUE Queue;
+    /** queue lock */
+    NDIS_SPIN_LOCK Lock;
+}INTERLOCKED_PACKET_QUEUE, *PINTERLOCKED_PACKET_QUEUE;
+
+typedef struct _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;
+} SINGLE_LIST, *PSINGLE_LIST;
+
+typedef struct _INTERLOCKED_SINGLE_LIST
+{
+    /** queue */
+    SINGLE_LIST List;
+    /** queue lock */
+    NDIS_SPIN_LOCK Lock;
+} INTERLOCKED_SINGLE_LIST, *PINTERLOCKED_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 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 PACKET_INFO_POOL_SIZE = 0xffff which is
+ * the maximum size of packets the ndis packet pool supports */
+typedef struct _PACKET_INFO_POOL
+{
+    /** free packet info queue */
+    INTERLOCKED_PACKET_QUEUE Queue;
+    /** memory bugger used by the pool */
+    PVOID pBuffer;
+}PACKET_INFO_POOL, *PPACKET_INFO_POOL;
+
+typedef enum VBOXNETDEVOPSTATE
+{
+    kVBoxNetDevOpState_InvalidValue = 0,
+    kVBoxNetDevOpState_Initializing,
+    kVBoxNetDevOpState_Initialized,
+    kVBoxNetDevOpState_Deinitializing,
+    kVBoxNetDevOpState_Deinitialized,
+
+} VBOXNETDEVOPSTATE;
+
+typedef enum VBOXADAPTSTATE
+{
+   /** The usual invalid state. */
+    kVBoxAdaptState_Invalid = 0,
+    /** Initialization. */
+    kVBoxAdaptState_Connecting,
+    /** Connected fuly functional state */
+    kVBoxAdaptState_Connected,
+    /** Disconnecting  */
+    kVBoxAdaptState_Disconnecting,
+    /** Disconnected  */
+    kVBoxAdaptState_Disconnected,
+} VBOXADAPTSTATE;
+
+/** structure used to maintain the state and reference count of the miniport and protocol */
+typedef struct _ADAPT_DEVICE
+{
+    /** initialize state */
+    VBOXNETDEVOPSTATE              OpState;
+    /** ndis power state */
+    NDIS_DEVICE_POWER_STATE        PowerState;
+    /** reference count */
+    uint32_t                       cReferences;
+/*    NDIS_HANDLE                    hHandle; */
+} ADAPT_DEVICE, *PADAPT_DEVICE;
+
+/** represents filter driver device context*/
+typedef struct _ADAPT
+{
+#ifndef VBOXNETADP
+    /** handle the lower miniport */
+    NDIS_HANDLE                    hBindingHandle;
+    /** Protocol's Device state */
+    ADAPT_DEVICE             PTState;
+#endif
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    /** NDIS Handle to for miniport up-calls */
+    NDIS_HANDLE                    hMiniportHandle;
+    /** miniport device state */
+    ADAPT_DEVICE             MPState;
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+    /** Pending receive packet queue (i.e. packets that were indicated to the upperlying protocols, but not completed yet)*/
+//    INTERLOCKED_PACKET_QUEUE                   RecvPacketQueue;
+#endif
+    /** ndis packet pool used for receives */
+    NDIS_HANDLE                    hRecvPacketPoolHandle;
+    /** ndis buffer pool used for receives */
+    NDIS_HANDLE                    hRecvBufferPoolHandle;
+#ifndef VBOXNETADP
+    /** This is used to wrap a request coming down to us.
+     * This exploits the fact that requests are serialized down to us.*/
+    NDIS_REQUEST                   Request;
+    /** Ndis Request Bytes needed */
+    PULONG                         BytesNeeded;
+    /** Ndis Request Bytes Read or Written */
+    PULONG                         BytesReadOrWritten;
+#else
+    volatile ULONG cTxSuccess;
+    volatile ULONG cRxSuccess;
+    volatile ULONG cTxError;
+    volatile ULONG cRxError;
+#endif
+    /** driver bind adapter state. */
+    VBOXADAPTSTATE                 enmState;
+#ifndef VBOXNETADP
+    /** true if we should indicate the receive complete used by the ProtocolReceeive mechanism */
+    bool                        bIndicateRcvComplete;
+
+    /** TRUE iff a request is pending at the miniport below */
+    bool                        bOutstandingRequests;
+    /**  TRUE iff a request is queued at this IM miniport*/
+    bool                        bQueuedRequest;
+    /** @todo join all boolean states to one field treated as flags bitmap */
+    /** true iff we are processing Set packet filter OID */
+    bool                        bProcessingPacketFilter;
+    /** true iff the upper protocol filter cache was initialized */
+    bool                        bUpperProtSetFilterInitialized;
+    /** trus if the adapter is closing */
+    bool                        bClosingAdapter;
+    /** Pending transfer data packet queue (i.e. packets that were indicated as pending on NdisTransferData call */
+    INTERLOCKED_SINGLE_LIST     TransferDataList;
+    /* mac options initialized on OID_GEN_MAC_OPTIONS */
+    ULONG                          fMacOptions;
+    /** For initializing the miniport edge */
+    NDIS_STRING                    DeviceName;
+    /** For blocking UnbindAdapter while an IM Init is in progress.*/
+    NDIS_EVENT                     MiniportInitEvent;
+    /** The last indicated media status */
+    NDIS_STATUS                    LastIndicatedStatus;
+    /** The latest suppressed media status */
+    NDIS_STATUS                    LatestUnIndicateStatus;
+    /** when working in the passthru mode the driver puts the received packets to this array
+     * instead of passing them up immediately
+     * we are flushing the packets on ProtocolReceiveComplete or when the underlying miniport
+     * indicates NDIS_STATUS_RESOURCES or when this array is full */
+    PNDIS_PACKET                   aReceivedPackets[MAX_RECEIVE_PACKET_ARRAY_SIZE];
+    /** number of packets in the aReceivedPackets array*/
+    ULONG                          cReceivedPacketCount;
+    /** 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;
+#endif /* !VBOXNETADP */
+#endif /* !VBOX_NETFLT_ONDEMAND_BIND */
+
+#ifndef VBOXNETADP
+    /** 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         fSynchCompletionStatus;
+    /** pointer to the Ndis Request being executed by the vboxNetFltWinSynchNdisRequest */
+    PNDIS_REQUEST volatile         pSynchRequest;
+#endif
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+    /** Pending send packet queue (i.e. packets that were sent to the underlying miniport, but not completed yet)*/
+
+    INTERLOCKED_PACKET_QUEUE                   SendPacketQueue;
+    /** Packet info pool, i.e. the pool for the packet queue elements */
+#endif
+#ifndef VBOXNETADP
+    /** ndis packet pool used for sends */
+    NDIS_HANDLE                    hSendPacketPoolHandle;
+    /** ndis buffer pool used for sends */
+    NDIS_HANDLE                    hSendBufferPoolHandle;
+    /** open/close adapter status.
+     * Since ndis adapter open and close requests may complete assynchronously,
+     * we are using event mechanism to wait for open/close completion
+     * the status field is being set by the completion call-back */
+    NDIS_STATUS                    Status;
+    /** open/close adaptor completion event */
+    NDIS_EVENT                     hEvent;
+    /** medium we are attached to */
+    NDIS_MEDIUM                    Medium;
+//    /** physical medium we are attached to */
+//    NDIS_PHYSICAL_MEDIUM           PhMedium;
+    /** True - When the miniport or protocol is transitioning from a D0 to Standby (>D0) State
+     *  False - At all other times, - Flag is cleared after a transition to D0 */
+    BOOLEAN                        bStandingBy;
+#endif
+} ADAPT, *PADAPT;
+
+typedef struct _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 */
+    INTERLOCKED_PACKET_QUEUE       PacketQueue;
+    /** Packet info pool, i.e. the pool for the packet queue elements */
+    PACKET_INFO_POOL               PacketInfoPool;
+} PACKET_QUEUE_WORKER, *PPACKET_QUEUE_WORKER;
+
+/** Protocol reserved part of a sent packet that is allocated by us. */
+typedef struct _SEND_RSVD
+{
+    /** original packet receiver from the upperlying protocol
+     * can be null if the packet was originated by intnet */
+    PNDIS_PACKET    pOriginalPkt;
+
+    /** pointer to the buffer to be freed on send completion
+     * can be null if no buffer is to be freed */
+    PVOID           pBufToFree;
+} SEND_RSVD, *PSEND_RSVD;
+
+/** represents the data stored in the protocol recerved field of ndis packet on NdisTransferData processing*/
+typedef struct _TRANSFERDATA_RSVD
+{
+    /** next packet in a list */
+    SINGLE_LIST_ENTRY ListEntry;
+    /* packet buffer start */
+    PNDIS_BUFFER pOriginalBuffer;
+} TRANSFERDATA_RSVD, *PTRANSFERDATA_RSVD;
+
+typedef struct _PT_RSVD
+{
+    union
+    {
+        SEND_RSVD SendRsvd;
+        TRANSFERDATA_RSVD TransferDataRsvd;
+    };
+} PT_RSVD, *PPT_RSVD;
+
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+/** Miniport reserved part of a received packet that is allocated by
+ * us. Note that this should fit into the MiniportReserved space
+ * in an NDIS_PACKET. */
+typedef struct _RECV_RSVD
+{
+    /** original packet receiver from the underling miniport
+     * can be null if the packet was originated by intnet */
+    PNDIS_PACKET    pOriginalPkt;
+    /** pointer to the buffer to be freed on receive completion
+     * can be null if no buffer is to be freed */
+    PVOID           pBufToFree;
+} RECV_RSVD, *PRECV_RSVD;
+
+C_ASSERT(sizeof(RECV_RSVD) <= sizeof(((PNDIS_PACKET)0)->MiniportReserved));
+#endif
+
+C_ASSERT(sizeof(NDIS_DEVICE_POWER_STATE) == sizeof(uint32_t));
+C_ASSERT(sizeof(UINT) == sizeof(uint32_t));
+
+#define NDIS_FLAGS_SKIP_LOOPBACK_W2K    0x400
+
+#include "../VBoxNetFltInternal.h"
+#include "VBoxNetFlt-win.h"
+#ifndef VBOXNETADP
+#include "VBoxNetFltPt-win.h"
+#endif
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+# include "VBoxNetFltMp-win.h"
+#endif
+
+#ifdef DEBUG_NETFLT_NOASSERT
+# ifdef Assert
+#  undef Assert
+# endif
+
+# define Assert(_expr) do {} while (0)
+#endif /* #ifdef DEBUG_NETFLT_NOASSERT */
+
+#endif
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltMp-win.c
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltMp-win.c	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltMp-win.c	(revision 21333)
@@ -0,0 +1,2793 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Miniport edge of ndis filter driver
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ * Copyright (c) 1993-1999, Microsoft Corporation
+ */
+
+#include "VBoxNetFltCommon-win.h"
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+# error "unsupported (VBOX_NETFLT_ONDEMAND_BIND)"
+#else
+
+/** driver handle */
+static NDIS_HANDLE         g_hDriverHandle = NULL;
+/** Ndis wrapper handle */
+static NDIS_HANDLE        g_hNdisWrapperHandle;
+/** device handle for ioctl interface this is not used currently and should be removed soon */
+static NDIS_HANDLE     g_hNdisDeviceHandle = NULL;
+/** device object used for ioctl interface this is not used currently and should be removed soon */
+static PDEVICE_OBJECT  g_pControlDeviceObject = NULL;
+/** ioctl device ref count */
+static LONG               g_cControlDeviceRefs = 0;
+/** true if control device needs to be dereferenced before destroying */
+static bool g_bControlDeviceReferenced = false;
+
+enum _DEVICE_STATE
+{
+    /** ready for create/delete */
+    PS_DEVICE_STATE_READY = 0,
+    /** create operation in progress */
+    PS_DEVICE_STATE_CREATING,
+    /** delete operation in progress */
+    PS_DEVICE_STATE_DELETING
+} g_eControlDeviceState = PS_DEVICE_STATE_READY;
+
+/*
+ * miniport
+ */
+typedef struct {
+    PVOID aBuffer[8];
+}OUR_SECURITY_DESCRIPTOR_BUFFER;
+
+static PUCHAR vboxNetFltWinMpDbgGetOidName(ULONG oid);
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwSetSecurityObject(IN HANDLE hHandle,
+        IN SECURITY_INFORMATION SInfo,
+        IN PSECURITY_DESCRIPTOR pSDescriptor);
+/*
+ * makes our device object usable/accessible for non-privileged users
+ */
+static NTSTATUS vboxNetFltWinSetSecurity(PNDIS_STRING pDevName)
+{
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjAttr;
+    IO_STATUS_BLOCK IoStatus;
+    HANDLE hFile;
+    OUR_SECURITY_DESCRIPTOR_BUFFER SecurityDes;
+
+    /*obtain the handle first*/
+    NdisZeroMemory(&ObjAttr, sizeof(ObjAttr));
+    InitializeObjectAttributes(&ObjAttr, pDevName,
+                OBJ_KERNEL_HANDLE /* ULONG Attributes */,
+                NULL /*HANDLE  RootDirectory*/,
+                NULL /*PSECURITY_DESCRIPTOR  SecurityDescriptor */
+               );
+
+    NdisZeroMemory(&IoStatus, sizeof(IoStatus));
+    Status = ZwOpenFile(&hFile /* PHANDLE  FileHandle*/,
+                WRITE_DAC /*ACCESS_MASK  DesiredAccess - we want to change the ACL */,
+                &ObjAttr /*POBJECT_ATTRIBUTES */,
+                &IoStatus /*PIO_STATUS_BLOCK */,
+                0 /*ULONG  ShareAccess*/,
+                0 /*ULONG  OpenOptions*/
+                );
+    Assert(Status == STATUS_SUCCESS);
+    if(Status == STATUS_SUCCESS)
+    {
+        /* create and set security descriptor */
+        NdisZeroMemory(&SecurityDes, sizeof(SecurityDes));
+        Status = RtlCreateSecurityDescriptor(&SecurityDes, SECURITY_DESCRIPTOR_REVISION);
+        Assert(Status == STATUS_SUCCESS);
+        if(Status == STATUS_SUCCESS)
+        {
+            Status = ZwSetSecurityObject(hFile, DACL_SECURITY_INFORMATION, &SecurityDes);
+            Assert(Status == STATUS_SUCCESS);
+            if(Status != STATUS_SUCCESS)
+            {
+                LogRel(("ZwSetSecurityObject error: Status (0x%x)\n", Status));
+                DBGPRINT(("ZwSetSecurityObject error: Status (0x%x)\n", Status));
+            }
+        }
+        else
+        {
+            LogRel(("RtlCreateSecurityDescriptor error: Status (0x%x)\n", Status));
+            DBGPRINT(("RtlCreateSecurityDescriptor error: Status (0x%x)\n", Status));
+        }
+
+        {
+            NTSTATUS Tmp = ZwClose(hFile);
+            Assert(Tmp == STATUS_SUCCESS);
+            if(Tmp != STATUS_SUCCESS)
+            {
+                LogRel(("ZwClose error: Status (0x%x), ignoring\n", Status));
+                DBGPRINT(("ZwClose error: Status (0x%x), ignoring\n", Status));
+            }
+        }
+    }
+    else
+    {
+        LogRel(("ZwOpenFile error: Status (0x%x)\n", Status));
+        DBGPRINT(("ZwOpenFile error: Status (0x%x)\n", Status));
+    }
+
+    return Status;
+}
+/**
+ * Register an ioctl interface - a device object to be used for this
+ * purpose is created by NDIS when we call NdisMRegisterDevice.
+ *
+ * This routine is called whenever a new miniport instance is
+ * initialized. However, we only create one global device object,
+ * when the first miniport instance is initialized. This routine
+ * handles potential race conditions with vboxNetFltWinPtDeregisterDevice via
+ * the g_eControlDeviceState and g_cControlDeviceRefs variables.
+ *
+ * NOTE: do not call this from DriverEntry; it will prevent the driver
+ * from being unloaded (e.g. on uninstall).
+ *
+ * @return NDIS_STATUS_SUCCESS if we successfully register a device object. */
+static NDIS_STATUS
+vboxNetFltWinPtRegisterDevice(
+    VOID
+    )
+{
+    NDIS_STATUS            Status = NDIS_STATUS_SUCCESS;
+    UNICODE_STRING         DeviceName;
+    UNICODE_STRING         DeviceLinkUnicodeString;
+    PDRIVER_DISPATCH       DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
+
+    LogFlow(("==>vboxNetFltWinPtRegisterDevice\n"));
+
+    NdisAcquireSpinLock(&g_GlobalLock);
+
+    ++g_cControlDeviceRefs;
+
+    if (1 == g_cControlDeviceRefs)
+    {
+        Assert(g_eControlDeviceState != PS_DEVICE_STATE_CREATING);
+
+        /* Another thread could be running vboxNetFltWinPtDeregisterDevice on
+         * behalf of another miniport instance. If so, wait for
+         * it to exit. */
+        while (g_eControlDeviceState != PS_DEVICE_STATE_READY)
+        {
+            NdisReleaseSpinLock(&g_GlobalLock);
+            NdisMSleep(1);
+            NdisAcquireSpinLock(&g_GlobalLock);
+        }
+
+        g_eControlDeviceState = PS_DEVICE_STATE_CREATING;
+
+        NdisReleaseSpinLock(&g_GlobalLock);
+
+
+        NdisZeroMemory(DispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
+
+        DispatchTable[IRP_MJ_CREATE] = vboxNetFltWinPtDispatch;
+        DispatchTable[IRP_MJ_CLEANUP] = vboxNetFltWinPtDispatch;
+        DispatchTable[IRP_MJ_CLOSE] = vboxNetFltWinPtDispatch;
+        DispatchTable[IRP_MJ_DEVICE_CONTROL] = vboxNetFltWinPtDispatch;
+
+
+        NdisInitUnicodeString(&DeviceName, NTDEVICE_STRING);
+        NdisInitUnicodeString(&DeviceLinkUnicodeString, LINKNAME_STRING);
+
+        /* Create a device object and register our dispatch handlers */
+
+        Status = NdisMRegisterDevice(
+                    g_hNdisWrapperHandle,
+                    &DeviceName,
+                    &DeviceLinkUnicodeString,
+                    &DispatchTable[0],
+                    &g_pControlDeviceObject,
+                    &g_hNdisDeviceHandle
+                    );
+
+        Assert(Status == NDIS_STATUS_SUCCESS);
+        if(Status == NDIS_STATUS_SUCCESS)
+        {
+            /* NdisMRegisterDevice does not offers us the ability to set security attributes */
+            /* need to do this "manualy" for the device to be accessible by the non-privileged users */
+            Status = vboxNetFltWinSetSecurity(&DeviceLinkUnicodeString);
+            Assert(Status == STATUS_SUCCESS);
+            if(Status != STATUS_SUCCESS)
+            {
+                LogRel(("Failed to set security attributes for netflt control device, status (0x%x), ignoring\n", Status));
+                /* ignore the failure */
+                Status = NDIS_STATUS_SUCCESS;
+            }
+
+            Status = ObReferenceObjectByPointer(g_pControlDeviceObject, FILE_READ_DATA, *IoFileObjectType, KernelMode);
+            Assert(Status == NDIS_STATUS_SUCCESS);
+            if(Status == NDIS_STATUS_SUCCESS)
+            {
+                g_bControlDeviceReferenced = true;
+            }
+            else
+            {
+                LogRel(("Failed to reference netflt control device, status (0x%x), ignoring\n", Status));
+                /* ignore the failure */
+                Status = NDIS_STATUS_SUCCESS;
+                g_bControlDeviceReferenced = false;
+            }
+        }
+
+        NdisAcquireSpinLock(&g_GlobalLock);
+
+        g_eControlDeviceState = PS_DEVICE_STATE_READY;
+    }
+
+    NdisReleaseSpinLock(&g_GlobalLock);
+
+    LogFlow(("<==vboxNetFltWinPtRegisterDevice: %x\n", Status));
+
+    return (Status);
+}
+
+/**
+ * Deregister the ioctl interface. This is called whenever a miniport
+ * instance is halted. When the last miniport instance is halted, we
+ * request NDIS to delete the device object
+ *
+ * @return NDIS_STATUS_SUCCESS if everything worked ok
+ * */
+static NDIS_STATUS
+vboxNetFltWinPtDeregisterDevice(
+    VOID
+    )
+{
+    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+    LogFlow(("==>NetFltDeregisterDevice\n"));
+
+    NdisAcquireSpinLock(&g_GlobalLock);
+
+    Assert(g_cControlDeviceRefs > 0);
+
+    --g_cControlDeviceRefs;
+
+    if (0 == g_cControlDeviceRefs)
+    {
+        /* All miniport instances have been halted. Deregister
+         * the control device. */
+
+        Assert(g_eControlDeviceState == PS_DEVICE_STATE_READY);
+
+        /* Block vboxNetFltWinPtRegisterDevice() while we release the control
+         * device lock and deregister the device. */
+
+        g_eControlDeviceState = PS_DEVICE_STATE_DELETING;
+
+        NdisReleaseSpinLock(&g_GlobalLock);
+
+        if (g_hNdisDeviceHandle != NULL)
+        {
+            if(g_bControlDeviceReferenced)
+            {
+                g_bControlDeviceReferenced = false;
+                ObDereferenceObject(g_pControlDeviceObject);
+            }
+
+            Status = NdisMDeregisterDevice(g_hNdisDeviceHandle);
+            g_hNdisDeviceHandle = NULL;
+        }
+
+        NdisAcquireSpinLock(&g_GlobalLock);
+        g_eControlDeviceState = PS_DEVICE_STATE_READY;
+    }
+
+    NdisReleaseSpinLock(&g_GlobalLock);
+
+    LogFlow(("<== NetFltDeregisterDevice: %x\n", Status));
+    return Status;
+
+}
+#ifndef VBOXNETADP
+/**
+ * This is the initialize handler which gets called as a result of
+ * the BindAdapter handler calling NdisIMInitializeDeviceInstanceEx.
+ * The context parameter which we pass there is the adapter structure
+ * which we retrieve here.
+ *
+ * @param OpenErrorStatus            Not used by us.
+ * @param SelectedMediumIndex        Place-holder for what media we are using
+ * @param MediumArray                Array of ndis media passed down to us to pick from
+ * @param MediumArraySize            Size of the array
+ * @param MiniportAdapterHandle    The handle NDIS uses to refer to us
+ * @param WrapperConfigurationContext    For use by NdisOpenConfiguration
+ * @return NDIS_STATUS_SUCCESS unless something goes wrong
+ * */
+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
+    )
+{
+    UINT            i;
+    PADAPT          pAdapt;
+    NDIS_STATUS     Status = NDIS_STATUS_FAILURE;
+    NDIS_MEDIUM     Medium;
+
+    UNREFERENCED_PARAMETER(WrapperConfigurationContext);
+
+    do
+    {
+        /*
+         * Start off by retrieving our adapter context and storing
+         * the Miniport handle in it.
+         */
+        pAdapt = (PADAPT)NdisIMGetDeviceContext(MiniportAdapterHandle);
+        pAdapt->hMiniportHandle = MiniportAdapterHandle;
+
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initializing);
+        /* the MP state should be already set to kVBoxNetDevOpState_Initializing, just a paranoya
+         * in case NDIS for some reason calls us in some unregular way */
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Initializing);
+
+        LogFlow(("==> Miniport Initialize: Adapt %p\n", pAdapt));
+
+        /*
+         * Usually we export the medium type of the adapter below as our
+         * virtual miniport's medium type. However if the adapter below us
+         * is a WAN device, then we claim to be of medium type 802.3.
+         */
+        Medium = pAdapt->Medium;
+
+        if (Medium == NdisMediumWan)
+        {
+            Medium = NdisMedium802_3;
+        }
+
+        for (i = 0; i < MediumArraySize; i++)
+        {
+            if (MediumArray[i] == Medium)
+            {
+                *SelectedMediumIndex = i;
+                break;
+            }
+        }
+
+        if (i == MediumArraySize)
+        {
+            Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+            break;
+        }
+
+
+        /*
+         * Set the attributes now. NDIS_ATTRIBUTE_DESERIALIZE enables us
+         * to make up-calls to NDIS without having to call NdisIMSwitchToMiniport
+         * or NdisIMQueueCallBack. This also forces us to protect our data using
+         * spinlocks where appropriate. Also in this case NDIS does not queue
+         * packets on our behalf. Since this is a very simple pass-thru
+         * miniport, we do not have a need to protect anything. However in
+         * a general case there will be a need to use per-adapter spin-locks
+         * for the packet queues at the very least.
+         */
+        NdisMSetAttributesEx(MiniportAdapterHandle,
+                             pAdapt,
+                             0,                                        /* CheckForHangTimeInSeconds */
+                             NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT    |
+                                NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT|
+                                NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
+                                NDIS_ATTRIBUTE_DESERIALIZE |
+                                NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+                             (NDIS_INTERFACE_TYPE)0);
+
+        /*
+         * Initialize LastIndicatedStatus to be NDIS_STATUS_MEDIA_CONNECT
+         */
+        pAdapt->LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT;
+
+        /*
+         * Initialize the power states for both the lower binding (PTDeviceState)
+         * and our miniport edge to Powered On.
+         */
+        Assert(vboxNetFltWinGetPowerState(&pAdapt->MPState) == NdisDeviceStateD3);
+        vboxNetFltWinSetPowerState(&pAdapt->MPState, NdisDeviceStateD0);
+        Assert(pAdapt->MPState.OpState == kVBoxNetDevOpState_Initializing);
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
+
+        Status = NDIS_STATUS_SUCCESS;
+    }
+    while (FALSE);
+
+    /*
+     * If we had received an UnbindAdapter notification on the underlying
+     * adapter, we would have blocked that thread waiting for the IM Init
+     * process to complete. Wake up any such thread.
+     */
+    if(Status != NDIS_STATUS_SUCCESS)
+    {
+        Assert(vboxNetFltWinGetPowerState(&pAdapt->MPState) == NdisDeviceStateD3);
+        Assert(pAdapt->MPState.OpState == kVBoxNetDevOpState_Initializing);
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+    }
+    NdisSetEvent(&pAdapt->MiniportInitEvent);
+
+    LogFlow(("<== Miniport Initialize: Adapt %p, Status %x\n", pAdapt, Status));
+
+    *OpenErrorStatus = Status;
+
+    return Status;
+}
+
+/**
+ * process the packet send in a "passthru" mode
+ */
+static NDIS_STATUS
+vboxNetFltWinSendPassThru(
+    IN PADAPT             pAdapt,
+    IN PNDIS_PACKET           pPacket
+    )
+{
+    PNDIS_PACKET           pMyPacket;
+    NDIS_STATUS fStatus;
+
+    fStatus = vboxNetFltWinPrepareSendPacket(pAdapt, pPacket, &pMyPacket/*, false*/);
+
+    Assert(fStatus == NDIS_STATUS_SUCCESS);
+    if (fStatus == NDIS_STATUS_SUCCESS)
+    {
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+//        /* need to enqueue to enable callback discarding
+//         * since we now always discard all callbacks */
+//        PPACKET_INFO pInfo = vboxNetFltWinDoSend(&fStatus, pAdapt, pMyPacket);
+//
+//        Assert(pInfo);
+#else
+        NdisSend(&fStatus,
+                 pAdapt->hBindingHandle,
+                 pMyPacket);
+#endif
+        if (fStatus != NDIS_STATUS_PENDING)
+        {
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            vboxNetFltWinDoCompleteSendViaInfo(pAdapt, pInfo);
+//            vboxNetFltWinPpFreePacketInfo(pInfo);
+#endif
+
+#ifndef WIN9X
+            NdisIMCopySendCompletePerPacketInfo (pPacket, pMyPacket);
+#endif
+            NdisFreePacket(pMyPacket);
+        }
+    }
+    return fStatus;
+}
+
+#else /* defined VBOXNETADP */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoDeinitialization(PADAPT pAdapt)
+{
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    uint64_t NanoTS = RTTimeSystemNanoTS();
+
+    Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
+    /*
+     * Set the flag that the miniport below is unbinding, so the request handlers will
+     * fail any request comming later
+     */
+    RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+
+    ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true);
+    ASMAtomicUoWriteBool(&pNetFlt->fRediscoveryPending, false);
+    ASMAtomicUoWriteU64(&pNetFlt->NanoTSLastRediscovery, NanoTS);
+
+    vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitializing);
+
+    RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+
+    vboxNetFltWinWaitDereference(&pAdapt->MPState);
+
+    vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+
+//    pAdapt->hMiniportHandle = NULL;
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+static NDIS_STATUS vboxNetFltWinMpReadApplyConfig(PADAPT pAdapt, NDIS_HANDLE hMiniportAdapter, NDIS_HANDLE hWrapperConfigurationContext)
+{
+    NDIS_STATUS     Status = NDIS_STATUS_SUCCESS;
+    NDIS_HANDLE     hConfiguration;
+    PNDIS_CONFIGURATION_PARAMETER pParameterValue;
+    NDIS_STRING strMAC = NDIS_STRING_CONST("MAC");
+    PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTMAC mac;
+
+    //
+    // Open the registry for this adapter to read advanced
+    // configuration parameters stored by the INF file.
+    //
+    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);
+                Assert(RT_SUCCESS(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.Mac = mac;
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoInitialization(PADAPT pAdapt, NDIS_HANDLE hMiniportAdapter, NDIS_HANDLE hWrapperConfigurationContext)
+{
+    NDIS_STATUS Status;
+    pAdapt->hMiniportHandle = hMiniportAdapter;
+
+    LogFlow(("==> vboxNetFltWinMpDoInitialization: Adapt %p\n", pAdapt));
+
+    Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+    vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Initializing);
+
+    vboxNetFltWinMpReadApplyConfig(pAdapt, hMiniportAdapter, hWrapperConfigurationContext);
+
+    NdisMSetAttributesEx(hMiniportAdapter,
+                         pAdapt,
+                         0,                                        /* CheckForHangTimeInSeconds */
+                            NDIS_ATTRIBUTE_DESERIALIZE |
+                            NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+                            NdisInterfaceInternal/*(NDIS_INTERFACE_TYPE)0*/);
+
+    /*
+     * Initialize the power states for both the lower binding (PTDeviceState)
+     * and our miniport edge to Powered On.
+     */
+    Assert(vboxNetFltWinGetPowerState(&pAdapt->MPState) == NdisDeviceStateD3);
+    vboxNetFltWinSetPowerState(&pAdapt->MPState, NdisDeviceStateD0);
+    Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initializing);
+    vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
+
+    Status = NDIS_STATUS_SUCCESS;
+
+
+//    *OpenErrorStatus = Status;
+
+    LogFlow(("<== vboxNetFltWinMpDoInitialization: Adapt %p, Status %x\n", pAdapt, Status));
+
+    return Status;
+}
+
+/**
+ * This is the initialize handler which gets called as a result of
+ * the BindAdapter handler calling NdisIMInitializeDeviceInstanceEx.
+ * The context parameter which we pass there is the adapter structure
+ * which we retrieve here.
+ *
+ * @param OpenErrorStatus            Not used by us.
+ * @param SelectedMediumIndex        Place-holder for what media we are using
+ * @param MediumArray                Array of ndis media passed down to us to pick from
+ * @param MediumArraySize            Size of the array
+ * @param MiniportAdapterHandle    The handle NDIS uses to refer to us
+ * @param WrapperConfigurationContext    For use by NdisOpenConfiguration
+ * @return NDIS_STATUS_SUCCESS unless something goes wrong
+ * */
+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
+    )
+{
+    UINT            i;
+    PADAPT          pAdapt;
+    NDIS_STATUS     Status = NDIS_STATUS_FAILURE;
+    NDIS_MEDIUM     Medium;
+
+    UNREFERENCED_PARAMETER(WrapperConfigurationContext);
+
+    Medium = NdisMedium802_3;
+
+    if (Medium == NdisMediumWan)
+    {
+        Medium = NdisMedium802_3;
+    }
+
+    for (i = 0; i < MediumArraySize; i++)
+    {
+        if (MediumArray[i] == Medium)
+        {
+            *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(&pName, pInfo->DataLength + sizeof(NAME_PREFIX));
+                        if(Status == STATUS_SUCCESS)
+                        {
+                            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(&pAdapt, MiniportAdapterHandle, &RtlStr, WrapperConfigurationContext);
+
+                            if(Status == STATUS_SUCCESS)
+                            {
+                                Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
+                                vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
+
+                                NdisMIndicateStatus(pAdapt->hMiniportHandle,
+                                                         NDIS_STATUS_MEDIA_CONNECT,
+                                                         (PVOID)NULL,
+                                                         0);
+                            }
+                            else
+                            {
+                                Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+                                vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+                            }
+
+                            vboxNetFltWinMemFree(pName);
+
+                        }
+                    }
+                    else
+                    {
+                        Status = NDIS_STATUS_FAILURE;
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+    }
+
+    if(Status != NDIS_STATUS_SUCCESS)
+    {
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+    }
+
+    /* TODO: */
+    *OpenErrorStatus = Status;
+
+    return Status;
+}
+#endif
+
+
+/**
+ * Send Packet Array handler. Either this or our SendPacket handler is called
+ * based on which one is enabled in our Miniport Characteristics.
+ *
+ * @param MiniportAdapterContext     Pointer to our adapter
+ * @param PacketArray                Set of packets to send
+ * @param NumberOfPackets            Self-explanatory
+ * @return none */
+static VOID
+vboxNetFltWinMpSendPackets(
+    IN NDIS_HANDLE             fMiniportAdapterContext,
+    IN PPNDIS_PACKET           pPacketArray,
+    IN UINT                    cNumberOfPackets
+    )
+{
+    PADAPT pAdapt = (PADAPT)fMiniportAdapterContext;
+    NDIS_STATUS         fStatus;
+    UINT                i;
+    PVBOXNETFLTINS pNetFltIf;
+
+    Assert(cNumberOfPackets);
+
+    if(vboxNetFltWinIncReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf, cNumberOfPackets))
+    {
+        uint32_t cAdaptRefs = cNumberOfPackets;
+        uint32_t cNetFltRefs = pNetFltIf ? cNumberOfPackets : 0;
+
+        for (i = 0; i < cNumberOfPackets; i++)
+        {
+            PNDIS_PACKET    pPacket;
+
+            pPacket = pPacketArray[i];
+
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket, false))
+#else
+            if(vboxNetFltWinIsLoopedBackPacket(pPacket))
+#endif
+
+            {
+                /* we should not have loopbacks on send */
+                Assert(0);
+
+                NdisMSendComplete(pAdapt->hMiniportHandle,
+                                  pPacket,
+                                  NDIS_STATUS_SUCCESS);
+            }
+            else
+            {
+                if(!cNetFltRefs
+                    || (fStatus = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, PACKET_SRC_HOST)) != NDIS_STATUS_SUCCESS)
+                {
+#ifndef VBOXNETADP
+                    fStatus = vboxNetFltWinSendPassThru(pAdapt, pPacket);
+#else
+                    if(!cNetFltRefs)
+                    {
+# ifdef VBOXNETADP_REPORT_DISCONNECTED
+                        fStatus = NDIS_STATUS_MEDIA_DISCONNECT;
+                        STATISTIC_INCREASE(pAdapt->cTxError);
+# else
+                        fStatus = NDIS_STATUS_SUCCESS;
+# endif
+                    }
+#endif
+
+                    if (fStatus != NDIS_STATUS_PENDING)
+                    {
+                        NdisMSendComplete(pAdapt->hMiniportHandle,
+                                      pPacket,
+                                      fStatus);
+                    }
+                    else
+                    {
+                        cAdaptRefs--;
+                    }
+                }
+                else
+                {
+                    cAdaptRefs--;
+                    cNetFltRefs--;
+                }
+            }
+        }
+
+        if(cNetFltRefs)
+            vboxNetFltWinDecReferenceNetFlt(pNetFltIf, cNetFltRefs);
+        if(cAdaptRefs)
+            vboxNetFltWinDecReferenceAdapt(pAdapt, cAdaptRefs);
+    }
+    else
+    {
+        NDIS_HANDLE h = pAdapt->hMiniportHandle;
+        Assert(0);
+        if(h)
+        {
+            for (i = 0; i < cNumberOfPackets; i++)
+            {
+                PNDIS_PACKET    pPacket;
+                pPacket = pPacketArray[i];
+                NdisMSendComplete(h,
+                                    pPacket,
+                                    NDIS_STATUS_FAILURE);
+            }
+        }
+    }
+}
+#ifndef VBOXNETADP
+/**
+ * Entry point called by NDIS to query for the value of the specified OID.
+ * Typical processing is to forward the query down to the underlying miniport.
+ *
+ * The following OIDs are filtered here:
+ * OID_PNP_QUERY_POWER - return success right here
+ * OID_GEN_SUPPORTED_GUIDS - do not forward, otherwise we will show up
+ * multiple instances of private GUIDs supported by the underlying miniport.
+ * OID_PNP_CAPABILITIES - we do send this down to the lower miniport, but
+ * the values returned are postprocessed before we complete this request;
+ * see vboxNetFltWinPtRequestComplete.
+ *
+ * NOTE on OID_TCP_TASK_OFFLOAD - if this IM driver modifies the contents
+ * of data it passes through such that a lower miniport may not be able
+ * to perform TCP task offload, then it should not forward this OID down,
+ * but fail it here with the status NDIS_STATUS_NOT_SUPPORTED. This is to
+ * avoid performing incorrect transformations on data.
+ *
+ * If our miniport edge (upper edge) is at a low-power state, fail the request.
+ * If our protocol edge (lower edge) has been notified of a low-power state,
+ * we pend this request until the miniport below has been set to D0. Since
+ * requests to miniports are serialized always, at most a single request will
+ * be pended.
+ *
+ * @param MiniportAdapterContext    Pointer to the adapter structure
+ * @param Oid                       Oid for this query
+ * @param InformationBuffer         Buffer for information
+ * @param InformationBufferLength   Size of this buffer
+ * @param BytesWritten              Specifies how much info is written
+ * @param BytesNeeded               In case the buffer is smaller than what we need, tell them how much is needed
+ * @return    Return code from the NdisRequest below.
+ * */
+static NDIS_STATUS
+vboxNetFltWinMpQueryInformation(
+    IN NDIS_HANDLE                MiniportAdapterContext,
+    IN NDIS_OID                   Oid,
+    IN PVOID                      InformationBuffer,
+    IN ULONG                      InformationBufferLength,
+    OUT PULONG                    BytesWritten,
+    OUT PULONG                    BytesNeeded
+    )
+{
+    PADAPT        pAdapt = (PADAPT)MiniportAdapterContext;
+    NDIS_STATUS   Status = NDIS_STATUS_FAILURE;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+    do
+    {
+        if (Oid == OID_PNP_QUERY_POWER)
+        {
+            /*
+             *  Do not forward this.
+             */
+            Status = NDIS_STATUS_SUCCESS;
+            break;
+        }
+
+        if (Oid == OID_GEN_SUPPORTED_GUIDS)
+        {
+            /*
+             *  Do not forward this, otherwise we will end up with multiple
+             *  instances of private GUIDs that the underlying miniport
+             *  supports.
+             */
+            Status = NDIS_STATUS_NOT_SUPPORTED;
+            break;
+        }
+
+        if (Oid == OID_TCP_TASK_OFFLOAD)
+        {
+            /* we want to receive packets with checksums calculated
+             * since we are passing them to IntNet
+             */
+            Status = NDIS_STATUS_NOT_SUPPORTED;
+            break;
+        }
+
+        /*
+         * If the miniport below is unbinding, just fail any request
+         */
+        if (vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized) /* protocol unbind in progress */
+        {
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+
+        /*
+         * All other queries are failed, if the miniport is not at D0,
+         */
+        if (vboxNetFltWinGetPowerState(&pAdapt->MPState) > NdisDeviceStateD0)
+        {
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+
+        pAdapt->Request.RequestType = NdisRequestQueryInformation;
+        pAdapt->Request.DATA.QUERY_INFORMATION.Oid = Oid;
+        pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+        pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;
+        pAdapt->BytesNeeded = BytesNeeded;
+        pAdapt->BytesReadOrWritten = BytesWritten;
+
+        /*
+         * If the miniport below is binding, fail the request
+         */
+        RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+
+        if (vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized)
+        {
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+        /*
+         * If the Protocol device state is OFF, mark this request as being
+         * pended. We queue this until the device state is back to D0.
+         */
+        if ((vboxNetFltWinGetPowerState(&pAdapt->PTState) > NdisDeviceStateD0)
+                && (pAdapt->bStandingBy == FALSE))
+        {
+            pAdapt->bQueuedRequest = TRUE;
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            Status = NDIS_STATUS_PENDING;
+            break;
+        }
+        /*
+         * This is in the process of powering down the system, always fail the request
+         */
+        if (pAdapt->bStandingBy == TRUE)
+        {
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+        pAdapt->bOutstandingRequests = TRUE;
+
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
+        {
+            PVBOXNETFLTINS pNetFltIf;
+            const bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf);
+
+            Assert(InformationBuffer);
+            Assert(!pAdapt->bProcessingPacketFilter);
+
+            if(pNetFltIf)
+            {
+                /* netflt is active, simply return the cached value */
+                *((PULONG)InformationBuffer) = pAdapt->fUpperProtocolSetFilter;
+
+                Status = NDIS_STATUS_SUCCESS;
+                vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+                vboxNetFltWinDereferenceAdapt(pAdapt);
+
+                RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+                pAdapt->bOutstandingRequests = FALSE;
+                RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+                break;
+            }
+            else if(fAdaptActive)
+            {
+                vboxNetFltWinDereferenceAdapt(pAdapt);
+            }
+        }
+
+        /*
+         * default case, most requests will be passed to the miniport below
+         */
+        NdisRequest(&Status,
+                    pAdapt->hBindingHandle,
+                    &pAdapt->Request);
+
+
+        if (Status != NDIS_STATUS_PENDING)
+        {
+            vboxNetFltWinPtRequestComplete(pAdapt, &pAdapt->Request, Status);
+            Status = NDIS_STATUS_PENDING;
+        }
+
+    } while (FALSE);
+
+    return(Status);
+
+}
+/**
+ * Postprocess a request for OID_PNP_CAPABILITIES that was forwarded
+ * down to the underlying miniport, and has been completed by it.
+ *
+ * @param pAdapt - Pointer to the adapter structure
+ * @param pStatus - Place to return final status
+ * @return  None. */
+DECLHIDDEN(VOID)
+vboxNetFltWinMpQueryPNPCapabilities(
+    IN OUT PADAPT            pAdapt,
+    OUT PNDIS_STATUS         pStatus
+    )
+{
+    PNDIS_PNP_CAPABILITIES           pPNPCapabilities;
+    PNDIS_PM_WAKE_UP_CAPABILITIES    pPMstruct;
+
+    if (pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(NDIS_PNP_CAPABILITIES))
+    {
+        pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)(pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer);
+
+        /*
+         * The following fields must be overwritten by an IM driver.
+         */
+        pPMstruct= & pPNPCapabilities->WakeUpCapabilities;
+        pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+        pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
+        pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+        *pAdapt->BytesReadOrWritten = sizeof(NDIS_PNP_CAPABILITIES);
+        *pAdapt->BytesNeeded = 0;
+
+
+        *pStatus = NDIS_STATUS_SUCCESS;
+    }
+    else
+    {
+        *pAdapt->BytesNeeded= sizeof(NDIS_PNP_CAPABILITIES);
+        *pStatus = NDIS_STATUS_RESOURCES;
+    }
+}
+
+#endif /* ifndef VBOXNETADP*/
+
+/**
+ * This routine does all the procssing for a request with a SetPower Oid
+ * The miniport shoud accept  the Set Power and transition to the new state
+ *
+ * The Set Power should not be passed to the miniport below
+ *
+ * If the IM miniport is going into a low power state, then there is no guarantee if it will ever
+ * be asked go back to D0, before getting halted. No requests should be pended or queued.
+ *
+ * @param pNdisStatus           - Status of the operation
+ * @param pAdapt                - The Adapter structure
+ * @param InformationBuffer     - The New DeviceState
+ * @param InformationBufferLength
+ * @param BytesRead             - No of bytes read
+ * @param BytesNeeded           -  No of bytes needed
+ * @return    Status  - NDIS_STATUS_SUCCESS if all the wait events succeed. */
+static VOID
+vboxNetFltWinMpProcessSetPowerOid(
+    IN OUT PNDIS_STATUS          pNdisStatus,
+    IN PADAPT                    pAdapt,
+    IN PVOID                     InformationBuffer,
+    IN ULONG                     InformationBufferLength,
+    OUT PULONG                   BytesRead,
+    OUT PULONG                   BytesNeeded
+    )
+{
+
+
+    NDIS_DEVICE_POWER_STATE NewDeviceState;
+
+    LogFlow(("==>vboxNetFltWinMpProcessSetPowerOid: Adapt %p\n", pAdapt));
+
+    Assert (InformationBuffer != NULL);
+
+    *pNdisStatus = NDIS_STATUS_FAILURE;
+
+    do
+    {
+        /*
+         * Check for invalid length
+         */
+        if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
+        {
+            *pNdisStatus = NDIS_STATUS_INVALID_LENGTH;
+            break;
+        }
+
+        NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE)InformationBuffer);
+
+        /*
+         * Check for invalid device state
+         */
+        if ((vboxNetFltWinGetPowerState(&pAdapt->MPState) > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0))
+        {
+            /*
+             * If the miniport is in a non-D0 state, the miniport can only receive a Set Power to D0
+             */
+            Assert (!(vboxNetFltWinGetPowerState(&pAdapt->MPState) > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0));
+
+            *pNdisStatus = NDIS_STATUS_FAILURE;
+            break;
+        }
+
+#ifndef VBOXNETADP
+        /*
+         * Is the miniport transitioning from an On (D0) state to an Low Power State (>D0)
+         * If so, then set the bStandingBy Flag - (Block all incoming requests)
+         */
+        if (vboxNetFltWinGetPowerState(&pAdapt->MPState) == NdisDeviceStateD0 && NewDeviceState > NdisDeviceStateD0)
+        {
+            pAdapt->bStandingBy = TRUE;
+        }
+
+        /*
+         * If the miniport is transitioning from a low power state to ON (D0), then clear the bStandingBy flag
+         * All incoming requests will be pended until the physical miniport turns ON.
+         */
+        if (vboxNetFltWinGetPowerState(&pAdapt->MPState) > NdisDeviceStateD0 &&  NewDeviceState == NdisDeviceStateD0)
+        {
+            pAdapt->bStandingBy = FALSE;
+        }
+#endif
+        /*
+         * Now update the state in the pAdapt structure;
+         */
+        vboxNetFltWinSetPowerState(&pAdapt->MPState, NewDeviceState);
+#ifndef VBOXNETADP
+        if(NewDeviceState != NdisDeviceStateD0)
+        {
+            vboxNetFltWinPtFlushReceiveQueue(pAdapt,
+                    true ); /* just return */
+        }
+#endif
+        *pNdisStatus = NDIS_STATUS_SUCCESS;
+
+
+    } while (FALSE);
+
+    if (*pNdisStatus == NDIS_STATUS_SUCCESS)
+    {
+#ifndef VBOXNETADP
+        /*
+         * The miniport resume from low power state
+         */
+        if (pAdapt->bStandingBy == FALSE)
+        {
+            /*
+             * If we need to indicate the media connect state
+             */
+            if (pAdapt->LastIndicatedStatus != pAdapt->LatestUnIndicateStatus)
+            {
+               NdisMIndicateStatus(pAdapt->hMiniportHandle,
+                                        pAdapt->LatestUnIndicateStatus,
+                                        (PVOID)NULL,
+                                        0);
+               NdisMIndicateStatusComplete(pAdapt->hMiniportHandle);
+               pAdapt->LastIndicatedStatus = pAdapt->LatestUnIndicateStatus;
+            }
+        }
+        else
+        {
+            /*
+             * Initialize LatestUnIndicatedStatus
+             */
+            pAdapt->LatestUnIndicateStatus = pAdapt->LastIndicatedStatus;
+        }
+#endif
+        *BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
+        *BytesNeeded = 0;
+    }
+    else
+    {
+        *BytesRead = 0;
+        *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+    }
+
+    LogFlow(("<==vboxNetFltWinMpProcessSetPowerOid: Adapt %p\n", pAdapt));
+}
+#ifndef VBOXNETADP
+/**
+ * Miniport SetInfo handler.
+ *
+ * In the case of OID_PNP_SET_POWER, record the power state and return the OID.
+ * Do not pass below
+ * If the device is suspended, do not block the SET_POWER_OID
+ * as it is used to reactivate the NetFlt miniport
+ *
+ * PM- If the MP is not ON (DeviceState > D0) return immediately  (except for 'query power' and 'set power')
+ *       If MP is ON, but the PT is not at D0, then queue the queue the request for later processing
+ *
+ * Requests to miniports are always serialized
+ *
+ * @param MiniportAdapterContext    Pointer to the adapter structure
+ * @param Oid                       Oid for this query
+ * @param InformationBuffer         Buffer for information
+ * @param InformationBufferLength   Size of this buffer
+ * @param BytesRead                 Specifies how much info is read
+ * @param BytesNeeded               In case the buffer is smaller than what we need, tell them how much is needed
+ * @return Return code from the NdisRequest below. */
+static NDIS_STATUS
+vboxNetFltWinMpSetInformation(
+    IN NDIS_HANDLE             MiniportAdapterContext,
+    IN NDIS_OID                Oid,
+    IN PVOID                   InformationBuffer,
+    IN ULONG                   InformationBufferLength,
+    OUT PULONG                 BytesRead,
+    OUT PULONG                 BytesNeeded
+    )
+{
+    PADAPT        pAdapt = (PADAPT)MiniportAdapterContext;
+    NDIS_STATUS   Status;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+    Status = NDIS_STATUS_FAILURE;
+
+    do
+    {
+        /*
+         * The Set Power should not be sent to the miniport below the NetFlt, but is handled internally
+         */
+        if (Oid == OID_PNP_SET_POWER)
+        {
+            vboxNetFltWinMpProcessSetPowerOid(&Status,
+                                 pAdapt,
+                                 InformationBuffer,
+                                 InformationBufferLength,
+                                 BytesRead,
+                                 BytesNeeded);
+            break;
+
+        }
+
+        /*
+         * If the miniport below is unbinding, fail the request
+         */
+        if (vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized)
+        {
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+
+        /*
+         * All other Set Information requests are failed, if the miniport is
+         * not at D0 or is transitioning to a device state greater than D0.
+         */
+        if (vboxNetFltWinGetPowerState(&pAdapt->MPState) > NdisDeviceStateD0)
+        {
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+
+        /* Set up the Request and return the result */
+        pAdapt->Request.RequestType = NdisRequestSetInformation;
+        pAdapt->Request.DATA.SET_INFORMATION.Oid = Oid;
+        pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+        pAdapt->Request.DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;
+        pAdapt->BytesNeeded = BytesNeeded;
+        pAdapt->BytesReadOrWritten = BytesRead;
+
+        /*
+         * If the miniport below is unbinding, fail the request
+         */
+        RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+        if (vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized)
+        {
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+
+        /*
+         * If the device below is at a low power state, we cannot send it the
+         * request now, and must pend it.
+         */
+        if ((vboxNetFltWinGetPowerState(&pAdapt->PTState) > NdisDeviceStateD0)
+                && (pAdapt->bStandingBy == FALSE))
+        {
+            pAdapt->bQueuedRequest = TRUE;
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            Status = NDIS_STATUS_PENDING;
+            break;
+        }
+        /*
+         * This is in the process of powering down the system, always fail the request
+         */
+        if (pAdapt->bStandingBy == TRUE)
+        {
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            Status = NDIS_STATUS_FAILURE;
+            break;
+        }
+        pAdapt->bOutstandingRequests = TRUE;
+
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+
+        if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
+        {
+            /* need to disable cleaning promiscuous here ?? */
+            PVBOXNETFLTINS pNetFltIf;
+            const bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf);
+
+            Assert(InformationBuffer);
+            Assert(!pAdapt->bProcessingPacketFilter);
+
+            if(pNetFltIf)
+            {
+                Assert(fAdaptActive);
+
+                /* 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. */
+                pAdapt->fUpperProtocolSetFilter = *((PULONG)InformationBuffer);
+                pAdapt->bUpperProtSetFilterInitialized = true;
+
+                if(!(pAdapt->fOurSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS))
+                {
+                    pAdapt->fSetFilterBuffer = NDIS_PACKET_TYPE_PROMISCUOUS;
+                    pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer = &pAdapt->fSetFilterBuffer;
+                    pAdapt->Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(pAdapt->fSetFilterBuffer);
+                    pAdapt->bProcessingPacketFilter = true;
+                    /* we'll do dereferencing in request complete */
+                }
+                else
+                {
+                    Status = NDIS_STATUS_SUCCESS;
+                    vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+                    vboxNetFltWinDereferenceAdapt(pAdapt);
+
+                    RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+                    pAdapt->bOutstandingRequests = FALSE;
+                    RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+                    break;
+                }
+            }
+            else if(fAdaptActive)
+            {
+                vboxNetFltWinDereferenceAdapt(pAdapt);
+            }
+        }
+
+        /*
+         * Forward the request to the device below.
+         */
+        NdisRequest(&Status,
+                    pAdapt->hBindingHandle,
+                    &pAdapt->Request);
+
+        if (Status != NDIS_STATUS_PENDING)
+        {
+            vboxNetFltWinPtRequestComplete(pAdapt, &pAdapt->Request, Status);
+        }
+
+    } while (FALSE);
+
+    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_MAXIMUM_FRAME_SIZE,
+        OID_GEN_LINK_SPEED,
+        OID_GEN_TRANSMIT_BUFFER_SPACE,
+        OID_GEN_RECEIVE_BUFFER_SPACE,
+        OID_GEN_TRANSMIT_BLOCK_SIZE,
+        OID_GEN_RECEIVE_BLOCK_SIZE,
+        OID_GEN_VENDOR_ID,
+        OID_GEN_VENDOR_DESCRIPTION,
+        OID_GEN_VENDOR_DRIVER_VERSION,
+        OID_GEN_CURRENT_PACKET_FILTER,
+        OID_GEN_CURRENT_LOOKAHEAD,
+        OID_GEN_DRIVER_VERSION,
+        OID_GEN_MAXIMUM_TOTAL_SIZE,
+        OID_GEN_PROTOCOL_OPTIONS,
+        OID_GEN_MAC_OPTIONS,
+        OID_GEN_MEDIA_CONNECT_STATUS,
+        OID_GEN_MAXIMUM_SEND_PACKETS,
+        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_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
+#ifndef INTERFACE_WITH_NDISPROT
+        ,
+        OID_PNP_CAPABILITIES,
+        OID_PNP_SET_POWER,
+        OID_PNP_QUERY_POWER
+# if 0
+        ,
+        OID_PNP_ADD_WAKE_UP_PATTERN,
+        OID_PNP_REMOVE_WAKE_UP_PATTERN,
+        OID_PNP_ENABLE_WAKE_UP
+# endif
+#endif
+};
+
+static NDIS_STATUS
+vboxNetFltWinMpQueryInformation(
+    IN NDIS_HANDLE  MiniportAdapterContext,
+    IN NDIS_OID     Oid,
+    IN PVOID        InformationBuffer,
+    IN ULONG        InformationBufferLength,
+    OUT PULONG      BytesWritten,
+    OUT PULONG      BytesNeeded)
+/*++
+
+Routine Description:
+
+    Entry point called by NDIS to query for the value of the specified OID.
+    MiniportQueryInformation runs at IRQL = DISPATCH_LEVEL.
+
+Arguments:
+
+    MiniportAdapterContext      Pointer to the adapter structure
+    Oid                         Oid for this query
+    InformationBuffer           Buffer for information
+    InformationBufferLength     Size of this buffer
+    BytesWritten                Specifies how much info is written
+    BytesNeeded                 In case the buffer is smaller than
+                                what we need, tell them how much is needed
+
+
+Return Value:
+
+    Return code from the NdisRequest below.
+
+Notes: Read "Minimizing Miniport Driver Initialization Time" in the DDK
+    for more info on how to handle certain OIDs that affect the init of
+    a miniport.
+
+--*/
+{
+    NDIS_STATUS             Status = NDIS_STATUS_SUCCESS;
+    PADAPT             pAdapt = (PADAPT)MiniportAdapterContext;
+    NDIS_HARDWARE_STATUS    HardwareStatus = NdisHardwareStatusReady;
+    NDIS_MEDIUM             Medium = NdisMedium802_3;
+    UCHAR                   VendorDesc[] = VBOXNETADP_VENDOR_DESC;
+    ULONG                   ulInfo = 0;
+    USHORT                  usInfo = 0;
+    ULONG64                 ulInfo64 = 0;
+    PVOID                   pInfo = (PVOID) &ulInfo;
+    ULONG                   ulInfoLen = sizeof(ulInfo);
+    NDIS_PNP_CAPABILITIES   PMCaps;
+
+    LogFlow(("==> vboxNetFltWinMpQueryInformation %s\n", vboxNetFltWinMpDbgGetOidName(Oid)));
+
+    // Initialize the result
+    *BytesWritten = 0;
+    *BytesNeeded = 0;
+
+    switch(Oid)
+    {
+        case OID_GEN_SUPPORTED_LIST:
+            //
+            // The OID_GEN_SUPPORTED_LIST OID specifies an array of OIDs
+            // for objects that the underlying driver or its NIC supports.
+            // Objects include general, media-specific, and implementation-
+            // specific objects. NDIS forwards a subset of the returned
+            // list to protocols that make this query. That is, NDIS filters
+            // any supported statistics OIDs out of the list because
+            // protocols never make statistics queries.
+            //
+            pInfo = (PVOID) g_vboxNetFltWinMpSupportedOids;
+            ulInfoLen = sizeof(g_vboxNetFltWinMpSupportedOids);
+            break;
+
+        case OID_GEN_HARDWARE_STATUS:
+            //
+            // Specify the current hardware status of the underlying NIC as
+            // one of the following NDIS_HARDWARE_STATUS-type values.
+            //
+            pInfo = (PVOID) &HardwareStatus;
+            ulInfoLen = sizeof(NDIS_HARDWARE_STATUS);
+            break;
+
+        case OID_GEN_MEDIA_SUPPORTED:
+            //
+            // Specify the media types that the NIC can support but not
+            // necessarily the media types that the NIC currently uses.
+            // fallthrough:
+        case OID_GEN_MEDIA_IN_USE:
+            //
+            // Specifiy a complete list of the media types that the NIC
+            // currently uses.
+            //
+            pInfo = (PVOID) &Medium;
+            ulInfoLen = sizeof(NDIS_MEDIUM);
+            break;
+
+        case OID_GEN_CURRENT_LOOKAHEAD:
+        case OID_GEN_MAXIMUM_LOOKAHEAD:
+            //
+            // If the miniport driver indicates received data by calling
+            // NdisXxxIndicateReceive, it should respond to OID_GEN_MAXIMUM_LOOKAHEAD
+            // with the maximum number of bytes the NIC can provide as
+            // lookahead data. If that value is different from the size of the
+            // lookahead buffer supported by bound protocols, NDIS will call
+            // MiniportSetInformation to set the size of the lookahead buffer
+            // provided by the miniport driver to the minimum of the miniport
+            // driver and protocol(s) values. If the driver always indicates
+            // up full packets with NdisMIndicateReceivePacket, it should
+            // set this value to the maximum total packet size, which
+            // excludes the header.
+            // Upper-layer drivers examine lookahead data to determine whether
+            // a packet that is associated with the lookahead data is intended
+            // for one or more of their clients. If the underlying driver
+            // supports multipacket receive indications, bound protocols are
+            // given full net packets on every indication. Consequently,
+            // this value is identical to that returned for
+            // OID_GEN_RECEIVE_BLOCK_SIZE.
+            //
+            ulInfo = VBOXNETADP_MAX_LOOKAHEAD_SIZE;
+            break;
+
+        case OID_GEN_MAXIMUM_FRAME_SIZE:
+            //
+            // Specifiy the maximum network packet size, in bytes, that the
+            // NIC supports excluding the header. A NIC driver that emulates
+            // another medium type for binding to a transport must ensure that
+            // the maximum frame size for a protocol-supplied net packet does
+            // not exceed the size limitations for the true network medium.
+            //
+            ulInfo = VBOXNETADP_MAX_PACKET_SIZE - VBOXNETADP_HEADER_SIZE;
+            break;
+
+        case OID_GEN_MAXIMUM_TOTAL_SIZE:
+            //
+            // Specify the maximum total packet length, in bytes, the NIC
+            // supports including the header. A protocol driver might use
+            // this returned length as a gauge to determine the maximum
+            // size packet that a NIC driver could forward to the
+            // protocol driver. The miniport driver must never indicate
+            // up to the bound protocol driver packets received over the
+            // network that are longer than the packet size specified by
+            // OID_GEN_MAXIMUM_TOTAL_SIZE.
+            //
+        case OID_GEN_TRANSMIT_BLOCK_SIZE:
+            //
+            // The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum
+            // number of bytes that a single net packet occupies in the
+            // transmit buffer space of the NIC. For example, a NIC that
+            // has a transmit space divided into 256-byte pieces would have
+            // a transmit block size of 256 bytes. To calculate the total
+            // transmit buffer space on such a NIC, its driver multiplies
+            // the number of transmit buffers on the NIC by its transmit
+            // block size. In our case, the transmit block size is
+            // identical to its maximum packet size.
+
+        case OID_GEN_RECEIVE_BLOCK_SIZE:
+            //
+            // The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of
+            // storage, in bytes, that a single packet occupies in the receive
+            // buffer space of the NIC.
+            //
+            ulInfo = (ULONG) VBOXNETADP_MAX_PACKET_SIZE;
+            break;
+
+        case OID_GEN_MAC_OPTIONS:
+            //
+            // Specify a bitmask that defines optional properties of the NIC.
+            // This miniport indicates receive with NdisMIndicateReceivePacket
+            // function. It has no MiniportTransferData function. Such a driver
+            // should set this NDIS_MAC_OPTION_TRANSFERS_NOT_PEND flag.
+            //
+            // NDIS_MAC_OPTION_NO_LOOPBACK tells NDIS that NIC has no internal
+            // loopback support so NDIS will manage loopbacks on behalf of
+            // this driver.
+            //
+            // NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA tells the protocol that
+            // our receive buffer is not on a device-specific card. If
+            // NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA is not set, multi-buffer
+            // indications are copied to a single flat buffer.
+            //
+            ulInfo = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+                NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+                NDIS_MAC_OPTION_NO_LOOPBACK;
+            break;
+
+        case OID_GEN_LINK_SPEED:
+            //
+            // Specify the maximum speed of the NIC in kbps.
+            // The unit of measurement is 100 bps
+            //
+            ulInfo = VBOXNETADP_LINK_SPEED;
+            break;
+
+        case OID_GEN_TRANSMIT_BUFFER_SPACE:
+            //
+            // Specify the amount of memory, in bytes, on the NIC that
+            // is available for buffering transmit data. A protocol can
+            // use this OID as a guide for sizing the amount of transmit
+            // data per send.
+            //
+            ulInfo = VBOXNETADP_MAX_PACKET_SIZE * PACKET_INFO_POOL_SIZE;
+            break;
+
+        case OID_GEN_RECEIVE_BUFFER_SPACE:
+            //
+            // Specify the amount of memory on the NIC that is available
+            // for buffering receive data. A protocol driver can use this
+            // OID as a guide for advertising its receive window after it
+            // establishes sessions with remote nodes.
+            //
+
+            ulInfo = VBOXNETADP_MAX_PACKET_SIZE * PACKET_INFO_POOL_SIZE;
+            break;
+
+        case OID_GEN_VENDOR_ID:
+            //
+            // Specify a three-byte IEEE-registered vendor code, followed
+            // by a single byte that the vendor assigns to identify a
+            // particular NIC. The IEEE code uniquely identifies the vendor
+            // and is the same as the three bytes appearing at the beginning
+            // of the NIC hardware address. Vendors without an IEEE-registered
+            // code should use the value 0xFFFFFF.
+            //
+            ulInfo = VBOXNETADP_VENDOR_ID;
+            break;
+
+        case OID_GEN_VENDOR_DESCRIPTION:
+            //
+            // Specify a zero-terminated string describing the NIC vendor.
+            //
+            pInfo = VendorDesc;
+            ulInfoLen = sizeof(VendorDesc);
+            break;
+
+        case OID_GEN_VENDOR_DRIVER_VERSION:
+            //
+            // Specify the vendor-assigned version number of the NIC driver.
+            // The low-order half of the return value specifies the minor
+            // version; the high-order half specifies the major version.
+            //
+            ulInfo = VBOXNETADP_VENDOR_DRIVER_VERSION;
+            break;
+
+        case OID_GEN_DRIVER_VERSION:
+            //
+            // Specify the NDIS version in use by the NIC driver. The high
+            // byte is the major version number; the low byte is the minor
+            // version number.
+            //
+            usInfo = (USHORT) (VBOXNETFLT_MAJOR_NDIS_VERSION<<8) + VBOXNETFLT_MINOR_NDIS_VERSION;
+            pInfo = (PVOID) &usInfo;
+            ulInfoLen = sizeof(USHORT);
+            break;
+
+        case OID_GEN_MAXIMUM_SEND_PACKETS:
+            //
+            // If a miniport driver registers a MiniportSendPackets function,
+            // MiniportQueryInformation will be called with the
+            // OID_GEN_MAXIMUM_SEND_PACKETS request. The miniport driver must
+            // respond with the maximum number of packets it is prepared to
+            // handle on a single send request. The miniport driver should
+            // pick a maximum that minimizes the number of packets that it
+            // has to queue internally because it has no resources
+            // (its device is full). A miniport driver for a bus-master DMA
+            // NIC should attempt to pick a value that keeps its NIC filled
+            // under anticipated loads.
+            //
+            ulInfo = PACKET_INFO_POOL_SIZE;
+            break;
+
+        case OID_GEN_MEDIA_CONNECT_STATUS:
+            //
+            // Return the connection status of the NIC on the network as one
+            // of the following system-defined values: NdisMediaStateConnected
+            // or NdisMediaStateDisconnected.
+            //
+#ifdef VBOXNETADP_REPORT_DISCONNECTED
+            {
+                PVBOXNETFLTINS pNetFltIf = NULL;
+                bool bActive = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf);
+                if(bActive && pNetFltIf)
+                {
+                    ulInfo = NdisMediaStateConnected;
+                }
+                else
+                {
+                    ulInfo = NdisMediaStateDisconnected;
+                }
+
+                if(bActive)
+                {
+                    vboxNetFltWinDereferenceAdapt(pAdapt);
+                }
+                if(pNetFltIf)
+                {
+                    vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+                }
+            }
+#else
+            ulInfo = NdisMediaStateConnected;
+#endif
+            break;
+
+        case OID_GEN_CURRENT_PACKET_FILTER:
+            //
+            // Specifiy the types of net packets such as directed, broadcast
+            // multicast, for which a protocol receives indications from a
+            // NIC driver. After NIC is initialized, a protocol driver
+            // can send a set OID_GEN_CURRENT_PACKET_FILTER to a non-zero value,
+            // thereby enabling the miniport driver to indicate receive packets
+            // to that protocol.
+            //
+            ulInfo = (
+                      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:
+            //
+            // Return the wake-up capabilities of its NIC. If you return
+            // NDIS_STATUS_NOT_SUPPORTED, NDIS considers the miniport driver
+            // to be not Power management aware and doesn't send any power
+            // or wake-up related queries such as
+            // OID_PNP_SET_POWER, OID_PNP_QUERY_POWER,
+            // OID_PNP_ADD_WAKE_UP_PATTERN, OID_PNP_REMOVE_WAKE_UP_PATTERN,
+            // OID_PNP_ENABLE_WAKE_UP. Here, we are expecting the driver below
+            // us to do the right thing.
+            //
+            RtlZeroMemory (&PMCaps, sizeof(NDIS_PNP_CAPABILITIES));
+            ulInfoLen = sizeof (NDIS_PNP_CAPABILITIES);
+            pInfo = (PVOID) &PMCaps;
+            PMCaps.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+            PMCaps.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
+            break;
+
+        case OID_PNP_QUERY_POWER:
+            Status = NDIS_STATUS_SUCCESS;
+            break;
+
+            //
+            // Following 4 OIDs are for querying Ethernet Operational
+            // Characteristics.
+            //
+        case OID_802_3_PERMANENT_ADDRESS:
+            //
+            // Return the MAC address of the NIC burnt in the hardware.
+            //
+            {
+                PVBOXNETFLTINS pNetFlt = (PADAPT_2_PVBOXNETFLTINS(pAdapt));
+                pInfo = &pNetFlt->u.s.Mac;
+                ulInfoLen = VBOXNETADP_ETH_ADDRESS_LENGTH;
+            }
+            break;
+
+        case OID_802_3_CURRENT_ADDRESS:
+            //
+            // Return the MAC address the NIC is currently programmed to
+            // use. Note that this address could be different from the
+            // permananent address as the user can override using
+            // registry. Read NdisReadNetworkAddress doc for more info.
+            //
+            {
+                PVBOXNETFLTINS pNetFlt = (PADAPT_2_PVBOXNETFLTINS(pAdapt));
+                pInfo = &pNetFlt->u.s.Mac;
+                ulInfoLen = VBOXNETADP_ETH_ADDRESS_LENGTH;
+            }
+            break;
+
+        case OID_802_3_MAXIMUM_LIST_SIZE:
+            //
+            // The maximum number of multicast addresses the NIC driver
+            // can manage. This list is global for all protocols bound
+            // to (or above) the NIC. Consequently, a protocol can receive
+            // NDIS_STATUS_MULTICAST_FULL from the NIC driver when
+            // attempting to set the multicast address list, even if
+            // the number of elements in the given list is less than
+            // the number originally returned for this query.
+            //
+            ulInfo = VBOXNETADP_MAX_MCAST_LIST;
+            break;
+
+        case OID_802_3_MAC_OPTIONS:
+            //
+            // A protocol can use this OID to determine features supported
+            // by the underlying driver such as NDIS_802_3_MAC_OPTION_PRIORITY.
+            // Return zero indicating that it supports no options.
+            //
+            ulInfo = 0;
+            break;
+
+            //
+            // Following list  consists of both general and Ethernet
+            // specific statistical OIDs.
+            //
+
+        case OID_GEN_XMIT_OK:
+            ulInfo64 = pAdapt->cTxSuccess;
+            pInfo = &ulInfo64;
+            if (InformationBufferLength >= sizeof(ULONG64) ||
+                InformationBufferLength == 0)
+            {
+                ulInfoLen = sizeof(ULONG64);
+            }
+            else
+            {
+                ulInfoLen = sizeof(ULONG);
+            }
+            // We should always report that 8 bytes are required to keep ndistest happy
+            *BytesNeeded =  sizeof(ULONG64);
+            break;
+
+        case OID_GEN_RCV_OK:
+            ulInfo64 = pAdapt->cRxSuccess;
+            pInfo = &ulInfo64;
+            if (InformationBufferLength >= sizeof(ULONG64) ||
+                InformationBufferLength == 0)
+            {
+                ulInfoLen = sizeof(ULONG64);
+            }
+            else
+            {
+                ulInfoLen = sizeof(ULONG);
+            }
+            // We should always report that 8 bytes are required to keep ndistest happy
+            *BytesNeeded =  sizeof(ULONG64);
+            break;
+
+        case OID_GEN_XMIT_ERROR:
+
+            ulInfo = pAdapt->cTxError;
+            break;
+
+        case OID_GEN_RCV_ERROR:
+            ulInfo = pAdapt->cRxError;
+            break;
+
+        case OID_GEN_RCV_NO_BUFFER:
+            ulInfo = 0;
+            break;
+
+        case OID_GEN_RCV_CRC_ERROR:
+            ulInfo = 0;
+            break;
+
+        case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+            ulInfo = PACKET_INFO_POOL_SIZE;
+            break;
+
+        case OID_802_3_RCV_ERROR_ALIGNMENT:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_ONE_COLLISION:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_MORE_COLLISIONS:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_DEFERRED:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_MAX_COLLISIONS:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_RCV_OVERRUN:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_UNDERRUN:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_TIMES_CRS_LOST:
+            ulInfo = 0;
+            break;
+
+        case OID_802_3_XMIT_LATE_COLLISIONS:
+            ulInfo = 0;
+            break;
+
+        default:
+            Status = NDIS_STATUS_NOT_SUPPORTED;
+            break;
+    }
+
+    if(Status == NDIS_STATUS_SUCCESS)
+    {
+        if(ulInfoLen <= InformationBufferLength)
+        {
+            // Copy result into InformationBuffer
+            *BytesWritten = ulInfoLen;
+            if(ulInfoLen)
+            {
+                NdisMoveMemory(InformationBuffer, pInfo, ulInfoLen);
+            }
+        }
+        else
+        {
+            // too short
+            *BytesNeeded = ulInfoLen;
+            Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+        }
+    }
+
+
+    LogFlow(("<== vboxNetFltWinMpQueryInformation Status = 0x%08x\n",
+                                                Status));
+
+    return(Status);
+}
+
+NDIS_STATUS
+vboxNetFltWinMpSetMulticastList(
+    IN PADAPT              pAdapt,
+    IN PVOID               InformationBuffer,
+    IN ULONG               InformationBufferLength,
+    OUT PULONG             pBytesRead,
+    OUT PULONG             pBytesNeeded
+    )
+/*++
+Routine Description:
+    This routine will set up the adapter for a specified multicast
+    address list.
+
+Arguments:
+    IN PMP_ADAPTER Adapter - Pointer to adapter block
+    InformationBuffer       - Buffer for information
+    InformationBufferLength   Size of this buffer
+    pBytesRead                Specifies how much info is read
+    BytesNeeded               In case the buffer is smaller than
+
+Return Value:
+
+    NDIS_STATUS
+
+--*/
+{
+    NDIS_STATUS            Status = NDIS_STATUS_SUCCESS;
+#if 0
+    ULONG                  index;
+#endif
+
+    LogFlow(("==> vboxNetFltWinMpSetMulticastList\n"));
+
+    //
+    // Initialize.
+    //
+    *pBytesNeeded = 0;
+    *pBytesRead = InformationBufferLength;
+
+    do
+    {
+        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;
+            *pBytesNeeded = VBOXNETADP_MAX_MCAST_LIST * VBOXNETADP_ETH_ADDRESS_LENGTH;
+            break;
+        }
+#if 0
+        //
+        // Protect the list update with a lock if it can be updated by
+        // another thread simultaneously.
+        //
+
+        NdisZeroMemory(pAdapt->aMCList,
+                       sizeof(pAdapt->aMCList));
+
+        NdisMoveMemory(pAdapt->aMCList,
+                       InformationBuffer,
+                       InformationBufferLength);
+
+        pAdapt->cMCList =    InformationBufferLength / ETH_LENGTH_OF_ADDRESS;
+#endif
+
+    }
+    while (FALSE);
+
+    //
+    // Program the hardware to add suport for these muticast addresses
+    //
+
+    LogFlow(("<== vboxNetFltWinMpSetMulticastList\n"));
+
+    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)
+/*++
+
+Routine Description:
+
+    This is the handler for an OID set operation.
+    MiniportSetInformation runs at IRQL = DISPATCH_LEVEL.
+
+Arguments:
+
+    MiniportAdapterContext      Pointer to the adapter structure
+    Oid                         Oid for this query
+    InformationBuffer           Buffer for information
+    InformationBufferLength     Size of this buffer
+    BytesRead                   Specifies how much info is read
+    BytesNeeded                 In case the buffer is smaller than what
+                                we need, tell them how much is needed
+
+Return Value:
+
+    Return code from the NdisRequest below.
+
+--*/
+{
+    NDIS_STATUS             Status = NDIS_STATUS_SUCCESS;
+    PADAPT                  pAdapt = (PADAPT) MiniportAdapterContext;
+    PNDIS_PM_PACKET_PATTERN pPmPattern = NULL;
+
+    LogFlow(("==> vboxNetFltWinMpSetInformation %s\n", vboxNetFltWinMpDbgGetOidName(Oid)));
+
+    *BytesRead = 0;
+    *BytesNeeded = 0;
+
+    switch(Oid)
+    {
+        case OID_802_3_MULTICAST_LIST:
+            //
+            // Set the multicast address list on the NIC for packet reception.
+            // The NIC driver can set a limit on the number of multicast
+            // addresses bound protocol drivers can enable simultaneously.
+            // NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver
+            // exceeds this limit or if it specifies an invalid multicast
+            // address.
+            //
+            Status = vboxNetFltWinMpSetMulticastList(
+                            pAdapt,
+                            InformationBuffer,
+                            InformationBufferLength,
+                            BytesRead,
+                            BytesNeeded);
+            break;
+
+        case OID_GEN_CURRENT_PACKET_FILTER:
+            //
+            // Program the hardware to indicate the packets
+            // of certain filter types.
+            //
+            if(InformationBufferLength != sizeof(ULONG))
+            {
+                *BytesNeeded = sizeof(ULONG);
+                Status = NDIS_STATUS_INVALID_LENGTH;
+                break;
+            }
+
+            *BytesRead = InformationBufferLength;
+
+            break;
+
+        case OID_GEN_CURRENT_LOOKAHEAD:
+            //
+            // A protocol driver can set a suggested value for the number
+            // of bytes to be used in its binding; however, the underlying
+            // NIC driver is never required to limit its indications to
+            // the value set.
+            //
+            if(InformationBufferLength != sizeof(ULONG)){
+                *BytesNeeded = sizeof(ULONG);
+                Status = NDIS_STATUS_INVALID_LENGTH;
+                break;
+            }
+
+            break;
+
+        case OID_PNP_SET_POWER:
+            //
+            // This OID notifies a miniport driver that its NIC will be
+            // transitioning to the device power state specified in the
+            // InformationBuffer. The miniport driver must always return
+            // NDIS_STATUS_SUCCESS to an OID_PNP_SET_POWER request. An
+            // OID_PNP_SET_POWER request may or may not be preceded by an
+            // OID_PNP_QUERY_POWER request.
+            //
+            if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE ))
+            {
+                Status = NDIS_STATUS_INVALID_LENGTH;
+                break;
+            }
+
+            vboxNetFltWinMpProcessSetPowerOid(&Status, pAdapt, InformationBuffer, InformationBufferLength, BytesRead, BytesNeeded);
+            break;
+/*
+        case OID_PNP_ADD_WAKE_UP_PATTERN:
+            //
+            // This OID is sent by a protocol driver to a miniport driver to
+            // specify a wake-up pattern. The wake-up pattern, along with its mask,
+            // is described by an NDIS_PM_PACKET_PATTERN structure.
+            //
+            pPmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer;
+            if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
+            {
+                Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+
+                *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
+                break;
+            }
+            if (InformationBufferLength < pPmPattern->PatternOffset + pPmPattern->PatternSize)
+            {
+                Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+
+                *BytesNeeded = pPmPattern->PatternOffset + pPmPattern->PatternSize;
+                break;
+            }
+            *BytesRead = pPmPattern->PatternOffset + pPmPattern->PatternSize;
+            Status = NDIS_STATUS_SUCCESS;
+            bForwardRequest = TRUE;
+            break;
+
+        case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+            //
+            // This OID requests the miniport driver to delete a wake-up pattern
+            // that it previously received in an OID_PNP_ADD_WAKE_UP_PATTERN request.
+            // The wake-up pattern, along with its mask, is described by an
+            // NDIS_PM_PACKET_PATTERN structure.
+            //
+            pPmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer;
+            if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN))
+            {
+                Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+
+                *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN);
+                break;
+            }
+            if (InformationBufferLength < pPmPattern->PatternOffset + pPmPattern->PatternSize)
+            {
+                Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+
+                *BytesNeeded = pPmPattern->PatternOffset + pPmPattern->PatternSize;
+                break;
+            }
+            *BytesRead = pPmPattern->PatternOffset + pPmPattern->PatternSize;
+            Status = NDIS_STATUS_SUCCESS;
+            bForwardRequest = TRUE;
+
+            break;
+
+        case OID_PNP_ENABLE_WAKE_UP:
+            //
+            // This OID specifies which wake-up capabilities a miniport
+            // driver should enable in its NIC. Before the miniport
+            // transitions to a low-power state (that is, before NDIS
+            // sends the miniport driver an OID_PNP_SET_POWER request),
+            // NDIS sends the miniport an OID_PNP_ENABLE_WAKE_UP request to
+            // enable the appropriate wake-up capabilities.
+            //
+            DEBUGP(MP_INFO, ("--> OID_PNP_ENABLE_WAKE_UP\n"));
+            if(InformationBufferLength != sizeof(ULONG))
+            {
+                *BytesNeeded = sizeof(ULONG);
+                Status = NDIS_STATUS_INVALID_LENGTH;
+                break;
+            }
+            *BytesRead = sizeof(ULONG);
+            Status = NDIS_STATUS_SUCCESS;
+            bForwardRequest = TRUE;
+            break;
+*/
+        default:
+            Status = NDIS_STATUS_INVALID_OID;
+            break;
+
+    }
+
+
+    LogFlow(("<== vboxNetFltWinMpSetInformation Status = 0x%08x\n", Status));
+
+    return(Status);
+}
+
+static PUCHAR vboxNetFltWinMpDbgGetOidName(ULONG oid)
+{
+    PCHAR oidName;
+
+    switch (oid){
+
+        #undef MAKECASE
+        #define MAKECASE(oidx) case oidx: oidName = #oidx; break;
+
+        MAKECASE(OID_GEN_SUPPORTED_LIST)
+        MAKECASE(OID_GEN_HARDWARE_STATUS)
+        MAKECASE(OID_GEN_MEDIA_SUPPORTED)
+        MAKECASE(OID_GEN_MEDIA_IN_USE)
+        MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD)
+        MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE)
+        MAKECASE(OID_GEN_LINK_SPEED)
+        MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE)
+        MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE)
+        MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE)
+        MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE)
+        MAKECASE(OID_GEN_VENDOR_ID)
+        MAKECASE(OID_GEN_VENDOR_DESCRIPTION)
+        MAKECASE(OID_GEN_CURRENT_PACKET_FILTER)
+        MAKECASE(OID_GEN_CURRENT_LOOKAHEAD)
+        MAKECASE(OID_GEN_DRIVER_VERSION)
+        MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE)
+        MAKECASE(OID_GEN_PROTOCOL_OPTIONS)
+        MAKECASE(OID_GEN_MAC_OPTIONS)
+        MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS)
+        MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS)
+        MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION)
+        MAKECASE(OID_GEN_SUPPORTED_GUIDS)
+        MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES)
+        MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET)
+        MAKECASE(OID_GEN_MEDIA_CAPABILITIES)
+        MAKECASE(OID_GEN_PHYSICAL_MEDIUM)
+        MAKECASE(OID_GEN_XMIT_OK)
+        MAKECASE(OID_GEN_RCV_OK)
+        MAKECASE(OID_GEN_XMIT_ERROR)
+        MAKECASE(OID_GEN_RCV_ERROR)
+        MAKECASE(OID_GEN_RCV_NO_BUFFER)
+        MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT)
+        MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT)
+        MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT)
+        MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT)
+        MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT)
+        MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT)
+        MAKECASE(OID_GEN_DIRECTED_BYTES_RCV)
+        MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV)
+        MAKECASE(OID_GEN_MULTICAST_BYTES_RCV)
+        MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV)
+        MAKECASE(OID_GEN_BROADCAST_BYTES_RCV)
+        MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV)
+        MAKECASE(OID_GEN_RCV_CRC_ERROR)
+        MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH)
+        MAKECASE(OID_GEN_GET_TIME_CAPS)
+        MAKECASE(OID_GEN_GET_NETCARD_TIME)
+        MAKECASE(OID_GEN_NETCARD_LOAD)
+        MAKECASE(OID_GEN_DEVICE_PROFILE)
+        MAKECASE(OID_GEN_INIT_TIME_MS)
+        MAKECASE(OID_GEN_RESET_COUNTS)
+        MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS)
+        MAKECASE(OID_PNP_CAPABILITIES)
+        MAKECASE(OID_PNP_SET_POWER)
+        MAKECASE(OID_PNP_QUERY_POWER)
+        MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN)
+        MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN)
+        MAKECASE(OID_PNP_ENABLE_WAKE_UP)
+        MAKECASE(OID_802_3_PERMANENT_ADDRESS)
+        MAKECASE(OID_802_3_CURRENT_ADDRESS)
+        MAKECASE(OID_802_3_MULTICAST_LIST)
+        MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE)
+        MAKECASE(OID_802_3_MAC_OPTIONS)
+        MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT)
+        MAKECASE(OID_802_3_XMIT_ONE_COLLISION)
+        MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS)
+        MAKECASE(OID_802_3_XMIT_DEFERRED)
+        MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS)
+        MAKECASE(OID_802_3_RCV_OVERRUN)
+        MAKECASE(OID_802_3_XMIT_UNDERRUN)
+        MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE)
+        MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST)
+        MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS)
+
+        default:
+            oidName = "<** UNKNOWN OID **>";
+            break;
+    }
+
+    return oidName;
+}
+#endif
+
+/**
+ * NDIS Miniport entry point called whenever protocols are done with
+ * a packet that we had indicated up and they had queued up for returning
+ * later.
+ *
+ * @param MiniportAdapterContext    - pointer to ADAPT structure
+ * @param Packet    - packet being returned.
+ * @return None. */
+DECLHIDDEN(VOID)
+vboxNetFltWinMpReturnPacket(
+    IN NDIS_HANDLE             MiniportAdapterContext,
+    IN PNDIS_PACKET            Packet
+    )
+{
+    PADAPT            pAdapt = (PADAPT)MiniportAdapterContext;
+
+    {
+        /*
+         * This is a packet allocated from this IM's receive packet pool.
+         * Reclaim our packet, and return the original to the driver below.
+         */
+
+        PNDIS_PACKET    MyPacket;
+        PRECV_RSVD      RecvRsvd;
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//        PPACKET_INFO pInfo = vboxNetFltWinDoCompleteIndicateReceive(pAdapt, Packet);
+//
+//        if(pInfo)
+//        {
+//            vboxNetFltWinPpFreePacketInfo(pInfo);
+//        }
+#endif
+        RecvRsvd = (PRECV_RSVD)(Packet->MiniportReserved);
+        MyPacket = RecvRsvd->pOriginalPkt;
+
+        if(MyPacket)
+        {
+            /* the packet was sent from underlying miniport */
+            NdisFreePacket(Packet);
+            NdisReturnPackets(&MyPacket, 1);
+        }
+        else
+        {
+            PVOID pBufToFree = RecvRsvd->pBufToFree;
+
+            /* the packet was sent from NetFlt */
+            vboxNetFltWinFreeSGNdisPacket(Packet, !pBufToFree);
+            if(pBufToFree)
+            {
+                vboxNetFltWinMemFree(pBufToFree);
+            }
+        }
+
+        vboxNetFltWinDereferenceAdapt(pAdapt);
+    }
+}
+
+/** Miniport's transfer data handler.
+ *
+ * @param Packet                    Destination packet
+ * @param BytesTransferred          Place-holder for how much data was copied
+ * @param MiniportAdapterContext    Pointer to the adapter structure
+ * @param MiniportReceiveContext    Context
+ * @param ByteOffset                Offset into the packet for copying data
+ * @param BytesToTransfer           How much to copy.
+ * @return    Status of transfer */
+static NDIS_STATUS
+vboxNetFltWinMpTransferData(
+    OUT PNDIS_PACKET            Packet,
+    OUT PUINT                   BytesTransferred,
+    IN NDIS_HANDLE              MiniportAdapterContext,
+    IN NDIS_HANDLE              MiniportReceiveContext,
+    IN UINT                     ByteOffset,
+    IN UINT                     BytesToTransfer
+    )
+{
+#ifndef VBOXNETADP
+
+    PADAPT        pAdapt = (PADAPT)MiniportAdapterContext;
+    NDIS_STATUS   Status;
+
+    /*
+     * Return, if the device is OFF
+     */
+    if (vboxNetFltWinGetPowerState(&pAdapt->PTState) != NdisDeviceStateD0
+            || vboxNetFltWinGetPowerState(&pAdapt->MPState) != NdisDeviceStateD0)
+    {
+        return NDIS_STATUS_FAILURE;
+    }
+
+    NdisTransferData(&Status,
+                     pAdapt->hBindingHandle,
+                     MiniportReceiveContext,
+                     ByteOffset,
+                     BytesToTransfer,
+                     Packet,
+                     BytesTransferred);
+
+    return(Status);
+#else
+    /* should never be here */
+    Assert(0);
+    return NDIS_STATUS_FAILURE;
+#endif
+}
+
+/**
+ * Halt handler. All the hard-work for clean-up is done here.
+ *
+ * @param MiniportAdapterContext    Pointer to the Adapter
+ * @return    None. */
+static VOID
+vboxNetFltWinMpHalt(
+    IN NDIS_HANDLE                MiniportAdapterContext
+    )
+{
+    PADAPT             pAdapt = (PADAPT)MiniportAdapterContext;
+#ifndef VBOXNETADP
+    NDIS_STATUS        Status;
+#endif
+
+    LogFlow(("==>MiniportHalt: Adapt %p\n", pAdapt));
+
+#ifndef VBOXNETADP
+//    Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitializing);
+//    if(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitializing)
+    if(vboxNetFltWinGetAdaptState(pAdapt) == kVBoxAdaptState_Disconnecting)
+    {
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitializing);
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitializing);
+        /* we're called from protocolUnbinAdapter, do our job */
+        /*
+         * If we have a valid bind, close the miniport below the protocol
+         */
+        vboxNetFltWinPtCloseAdapter(pAdapt, &Status);
+
+        Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitializing);
+        vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+    }
+    else
+#endif
+    {
+        /* we're NOT called from protocolUnbinAdapter, perform a full disconnect */
+        NDIS_STATUS Status;
+
+        Assert(/*vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initializing
+                ||*/ vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
+#ifndef VBOXNETADP
+        AssertBreakpoint();
+#endif
+        Status = vboxNetFltWinDetachFromInterface(pAdapt, false);
+        Assert(Status == NDIS_STATUS_SUCCESS);
+/* you can not access the pAdapt after closure
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+#ifndef VBOXNETADP
+        Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Deinitialized);
+        vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+#endif
+*/
+    }
+
+    LogFlow(("<== MiniportHalt: pAdapt %p\n", pAdapt));
+}
+
+/**
+ * register the miniport edge
+ */
+DECLHIDDEN(NDIS_STATUS)
+vboxNetFltWinMpRegister(
+    IN PDRIVER_OBJECT        DriverObject,
+    IN PUNICODE_STRING       RegistryPath
+    )
+{
+    NDIS_MINIPORT_CHARACTERISTICS      MChars;
+    NDIS_STATUS Status;
+
+    NdisMInitializeWrapper(&g_hNdisWrapperHandle, DriverObject, RegistryPath, NULL);
+
+    /*
+     * Register the miniport with NDIS. Note that it is the miniport
+     * which was started as a driver and not the protocol. Also the miniport
+     * must be registered prior to the protocol since the protocol's BindAdapter
+     * handler can be initiated anytime and when it is, it must be ready to
+     * start driver instances.
+     */
+
+    NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));
+
+    MChars.MajorNdisVersion = VBOXNETFLT_MAJOR_NDIS_VERSION;
+    MChars.MinorNdisVersion = VBOXNETFLT_MINOR_NDIS_VERSION;
+
+    MChars.InitializeHandler = vboxNetFltWinMpInitialize;
+    MChars.QueryInformationHandler = vboxNetFltWinMpQueryInformation;
+    MChars.SetInformationHandler = vboxNetFltWinMpSetInformation;
+    MChars.ResetHandler = NULL;
+    MChars.TransferDataHandler = vboxNetFltWinMpTransferData;
+    MChars.HaltHandler = vboxNetFltWinMpHalt;
+
+    /*
+     * We will disable the check for hang timeout so we do not
+     * need a check for hang handler!
+     */
+    MChars.CheckForHangHandler = NULL;
+    MChars.ReturnPacketHandler = vboxNetFltWinMpReturnPacket;
+
+    /*
+     * Either the Send or the SendPackets handler should be specified.
+     * If SendPackets handler is specified, SendHandler is ignored
+     */
+    MChars.SendHandler = NULL;    /* vboxNetFltWinMpSend; */
+    MChars.SendPacketsHandler = vboxNetFltWinMpSendPackets;
+
+#ifndef VBOXNETADP
+    Status = NdisIMRegisterLayeredMiniport(g_hNdisWrapperHandle,
+                                              &MChars,
+                                              sizeof(MChars),
+                                              &g_hDriverHandle);
+#else
+    Status = NdisMRegisterMiniport(
+                    g_hNdisWrapperHandle,
+                    &MChars,
+                    sizeof(MChars));
+#endif
+    if(Status == NDIS_STATUS_SUCCESS)
+    {
+# ifndef WIN9X
+        NdisMRegisterUnloadHandler(g_hNdisWrapperHandle, vboxNetFltWinUnload);
+# endif
+    }
+
+    return Status;
+}
+
+/**
+ * deregister the miniport edge
+ */
+DECLHIDDEN(NDIS_STATUS)
+vboxNetFltWinMpDeregister()
+{
+#ifndef VBOXNETADP
+    NdisIMDeregisterLayeredMiniport(g_hDriverHandle);
+#else
+    /* don't need to do anything here */
+#endif
+    NdisTerminateWrapper(g_hNdisWrapperHandle, NULL);
+    return NDIS_STATUS_SUCCESS;
+}
+
+#ifndef VBOXNETADP
+/**
+ * return the miniport edge handle
+ */
+DECLHIDDEN(NDIS_HANDLE) vboxNetFltWinMpGetHandle()
+{
+    return g_hDriverHandle;
+}
+
+/**
+ * initialize the instance of a device used for ioctl handling
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpInitializeDevideInstance(PADAPT pAdapt)
+{
+    NDIS_STATUS Status;
+    /*
+     * Now ask NDIS to initialize our miniport (upper) edge.
+     * Set the flag below to synchronize with a possible call
+     * to our protocol Unbind handler that may come in before
+     * our miniport initialization happens.
+     */
+    Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+    vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Initializing);
+    /* this is doe in vboxNetFltWinPtInitPADAPT*/
+    /*        NdisInitializeEvent(&pAdapt->MiniportInitEvent); */
+
+    Status = NdisIMInitializeDeviceInstanceEx(g_hDriverHandle,
+                                       &pAdapt->DeviceName,
+                                       pAdapt);
+    /* ensure we're taking into account the pAdapt->Status if our miniport halt handler was called */
+    if(Status == NDIS_STATUS_SUCCESS)
+    {
+        if(pAdapt->Status == NDIS_STATUS_SUCCESS)
+        {
+//            Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized);
+//            vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Initialized);
+            return NDIS_STATUS_SUCCESS;
+        }
+        AssertBreakpoint();
+        vboxNetFltWinMpDeInitializeDevideInstance(pAdapt, &Status);
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+        return pAdapt->Status;
+    }
+    else
+    {
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+    }
+    return Status;
+}
+
+/**
+ * deinitialize the instance of a device used for ioctl handling
+ */
+DECLHIDDEN(bool) vboxNetFltWinMpDeInitializeDevideInstance(PADAPT pAdapt, PNDIS_STATUS pStatus)
+{
+# ifndef WIN9X
+    NDIS_STATUS LocalStatus;
+    /*
+     * Check if we had called NdisIMInitializeDeviceInstanceEx and
+     * we are awaiting a call to MiniportInitialize.
+     */
+    if (vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initializing)
+    {
+        /*
+         * Try to cancel the pending IMInit process.
+         */
+        LocalStatus = NdisIMCancelInitializeDeviceInstance(
+                        g_hDriverHandle,
+                        &pAdapt->DeviceName);
+
+        if (LocalStatus == NDIS_STATUS_SUCCESS)
+        {
+            /*
+             * Successfully cancelled IM Initialization; our
+             * Miniport Initialize routine will not be called
+             * for this device.
+             */
+            Assert(pAdapt->hMiniportHandle == NULL);
+        }
+        else
+        {
+            /*
+             * Our Miniport Initialize routine will be called
+             * (may be running on another thread at this time).
+             * Wait for it to finish.
+             */
+            NdisWaitEvent(&pAdapt->MiniportInitEvent, 0);
+        }
+
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+    }
+#endif
+
+    /*
+     * Call NDIS to remove our device-instance. We do most of the work
+     * inside the HaltHandler.
+     *
+     * The Handle will be NULL if our miniport Halt Handler has been called or
+     * if the IM device was never initialized
+     */
+
+    if (vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Initialized)
+    {
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitializing);
+
+        *pStatus = NdisIMDeInitializeDeviceInstance(pAdapt->hMiniportHandle);
+
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+
+        if (*pStatus != NDIS_STATUS_SUCCESS)
+        {
+            *pStatus = NDIS_STATUS_FAILURE;
+        }
+
+        return true;
+    }
+
+    vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+
+    return false;
+}
+#endif
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpReferenceControlDevice()
+{
+    return vboxNetFltWinPtRegisterDevice();
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDereferenceControlDevice()
+{
+    return vboxNetFltWinPtDeregisterDevice();
+}
+
+#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND*/
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltMp-win.h
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltMp-win.h	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltMp-win.h	(revision 21333)
@@ -0,0 +1,41 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Miniport edge of ndis filter driver
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ * Copyright (c) 1993-1999, Microsoft Corporation
+ */
+
+#ifndef ___VBoxNetFltMp_win_h___
+#define ___VBoxNetFltMp_win_h___
+
+ #ifdef VBOX_NETFLT_ONDEMAND_BIND
+  # error "unsupported (VBOX_NETFLT_ONDEMAND_BIND)"
+ #else
+
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpRegister(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDeregister();
+DECLHIDDEN(NDIS_HANDLE) vboxNetFltWinMpGetHandle();
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpInitializeDevideInstance(PADAPT pAdapt);
+DECLHIDDEN(VOID) vboxNetFltWinMpReturnPacket(IN NDIS_HANDLE MiniportAdapterContext, IN PNDIS_PACKET Packet);
+DECLHIDDEN(bool) vboxNetFltWinMpDeInitializeDevideInstance(PADAPT pAdapt, PNDIS_STATUS pStatus);
+DECLHIDDEN(VOID) vboxNetFltWinMpQueryPNPCapabilities(IN OUT PADAPT pAdapt, OUT PNDIS_STATUS pStatus);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpReferenceControlDevice();
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDereferenceControlDevice();
+
+  #ifdef VBOXNETADP
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoInitialization(PADAPT pAdapt, NDIS_HANDLE hMiniportAdapter, NDIS_HANDLE hWrapperConfigurationContext);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinMpDoDeinitialization(PADAPT pAdapt);
+  #endif
+
+ #endif
+
+#endif
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltPt-win.c
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltPt-win.c	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltPt-win.c	(revision 21333)
@@ -0,0 +1,2280 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Protocol edge of ndis filter driver
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ * Copyright (c) 1993-1999, Microsoft Corporation
+ */
+
+#include "VBoxNetFltCommon-win.h"
+
+#ifdef VBOXNETADP
+# error "No protocol edge"
+#endif
+
+/** protocol handle */
+static NDIS_HANDLE         g_hProtHandle = NULL;
+/** medium array used while opening underlying adaprot
+ * we are actually binding to NdisMedium802_3 and NdisMediumWan
+ * as specified in VBoxNetFlt.inf:
+ * HKR, Ndi\Interfaces, FilterMediaTypes,    , "ethernet, wan" */
+static NDIS_MEDIUM         g_aMediumArray[] =
+                    {
+                        /* Ethernet */
+                        NdisMedium802_3,
+                        /* Wan */
+                        NdisMediumWan
+                    };
+
+/**
+ * performs binding to the given adapter
+ */
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(IN PADAPT pAdapt)
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(IN PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName, IN PNDIS_STRING pBindToDeviceName)
+#endif
+{
+    UINT                            MediumIndex;
+    NDIS_STATUS Status, Sts;
+
+    Assert(pAdapt->PTState.PowerState == NdisDeviceStateD3);
+    Assert(pAdapt->PTState.OpState == kVBoxNetDevOpState_Deinitialized);
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+    vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initializing);
+
+    do
+    {
+//        NDIS_STATUS TmpStatus;
+        /* copy the bind to dev name to our buffer */
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+        NDIS_STRING BindToDeviceName;
+        PNDIS_STRING pBindToDeviceName;
+        PVBOXNETFLTINS pThis = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+        PWSTR pUnicode;
+        ULONG cbUnicode;
+        ANSI_STRING AnsiStr;
+
+        /* most Rtlxx functions we are using here require this */
+        Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+        RtlInitAnsiString(&AnsiStr, pThis->szName);
+        cbUnicode = RtlAnsiStringToUnicodeSize(&AnsiStr);
+
+        pUnicode = alloca(cbUnicode);
+        BindToDeviceName.Buffer = pUnicode;
+        BindToDeviceName.MaximumLength = (USHORT)cbUnicode;
+
+        Status = RtlAnsiStringToUnicodeString(&BindToDeviceName, &AnsiStr, FALSE);
+        if(!NT_SUCCESS(Status))
+        {
+            Assert(0);
+            break;
+        }
+
+        pBindToDeviceName = &BindToDeviceName;
+#else
+        Status = vboxNetFltWinCopyString(&pAdapt->DeviceName, pOurDeviceName);
+        if(Status != NDIS_STATUS_SUCCESS)
+        {
+            Assert(0);
+            break;
+        }
+#endif
+
+        vboxNetFltWinSetPowerState(&pAdapt->PTState, NdisDeviceStateD0);
+        pAdapt->Status = NDIS_STATUS_SUCCESS;
+
+        NdisResetEvent(&pAdapt->hEvent);
+
+        /*
+         * Now open the adapter below and complete the initialization
+         */
+        NdisOpenAdapter(&Status,
+                          &Sts,
+                          &pAdapt->hBindingHandle,
+                          &MediumIndex,
+                          g_aMediumArray,
+                          sizeof(g_aMediumArray)/sizeof(NDIS_MEDIUM),
+                          g_hProtHandle,
+                          pAdapt,
+                          pBindToDeviceName,
+                          0,
+                          NULL);
+
+        if (Status == NDIS_STATUS_PENDING)
+        {
+            NdisWaitEvent(&pAdapt->hEvent, 0);
+            Status = pAdapt->Status;
+        }
+
+        Assert(Status == NDIS_STATUS_SUCCESS);
+        if(Status != NDIS_STATUS_SUCCESS)
+        {
+            vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+            pAdapt->hBindingHandle = NULL;
+            LogRel(("NdisOpenAdapter failed, Status (0c%x)", Status));
+            break;
+        }
+
+        Assert(pAdapt->hBindingHandle);
+
+        pAdapt->Medium = g_aMediumArray[MediumIndex];
+        vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Initialized);
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        Status = vboxNetFltWinMpInitializeDevideInstance(pAdapt);
+        if (Status != NDIS_STATUS_SUCCESS)
+        {
+            Log(("BindAdapter: Adapt %p, IMInitializeDeviceInstance error %x\n",
+                pAdapt, Status));
+
+            vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitializing);
+            vboxNetFltWinPtCloseAdapter(pAdapt, &Sts);
+            vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+            break;
+        }
+#endif
+    } while(0);
+
+    return Status;
+}
+
+/**
+ * Called by NDIS to bind to a miniport below.
+ * @param Status            - Return status of bind here.
+ * @param BindContext        - Can be passed to NdisCompleteBindAdapter if this call is pended.
+ * @param DeviceName         - Device name to bind to. This is passed to NdisOpenAdapter.
+ * @param SystemSpecific1    - Can be passed to NdisOpenProtocolConfiguration to read per-binding information
+ * @paran SystemSpecific2    - Unused
+ * @return NDIS_STATUS_PENDING    if this call is pended. In this case call NdisCompleteBindAdapter to complete.
+ *                                Anything else          Completes this call synchronously */
+static VOID
+vboxNetFltWinPtBindAdapter(
+    OUT PNDIS_STATUS            pStatus,
+    IN  NDIS_HANDLE             BindContext,
+    IN  PNDIS_STRING            pDeviceName,
+    IN  PVOID                   SystemSpecific1,
+    IN  PVOID                   SystemSpecific2
+    )
+{
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    /* we initiate the binding ourselves by calling NdisOpenAdapter */
+    LogFlow(("==> Protocol BindAdapter\n"));
+    Assert(0);
+    *pStatus = NDIS_STATUS_OPEN_FAILED;
+    LogFlow(("<== Protocol BindAdapter\n"));
+    return;
+#else
+    NDIS_HANDLE                     ConfigHandle = NULL;
+    PNDIS_CONFIGURATION_PARAMETER   Param;
+    NDIS_STRING                     DeviceStr = NDIS_STRING_CONST("UpperBindings");
+    PADAPT                          pAdapt = NULL;
+
+    UNREFERENCED_PARAMETER(BindContext);
+    UNREFERENCED_PARAMETER(SystemSpecific2);
+
+    LogFlow(("==> Protocol BindAdapter\n"));
+
+    do
+    {
+        /* Access the configuration section for our binding-specific
+         * parameters. */
+
+        NdisOpenProtocolConfiguration(pStatus,
+                                       &ConfigHandle,
+                                       (PNDIS_STRING)SystemSpecific1);
+
+        if (*pStatus != NDIS_STATUS_SUCCESS)
+        {
+            break;
+        }
+
+        /* Read the "UpperBindings" reserved key that contains a list
+         * of device names representing our miniport instances corresponding
+         * to this lower binding. Since this is a 1:1 IM driver, this key
+         * contains exactly one name.
+         *
+         * If we want to implement a N:1 mux driver (N adapter instances
+         * over a single lower binding), then UpperBindings will be a
+         * MULTI_SZ containing a list of device names - we would loop through
+         * this list, calling NdisIMInitializeDeviceInstanceEx once for
+         * each name in it. */
+
+         NdisReadConfiguration(pStatus,
+                              &Param,
+                              ConfigHandle,
+                              &DeviceStr,
+                              NdisParameterString);
+        if (*pStatus != NDIS_STATUS_SUCCESS)
+        {
+            break;
+        }
+
+        *pStatus = vboxNetFltWinPtInitBind(&pAdapt, &Param->ParameterData.StringData, pDeviceName);
+        if (*pStatus != NDIS_STATUS_SUCCESS)
+        {
+            break;
+        }
+    } while(FALSE);
+
+    /*
+     * Close the configuration handle now - see comments above with
+     * the call to NdisIMInitializeDeviceInstanceEx.
+     */
+    if (ConfigHandle != NULL)
+    {
+        NdisCloseConfiguration(ConfigHandle);
+    }
+
+    LogFlow(("<== Protocol BindAdapter: pAdapt %p, Status %x\n", pAdapt, *pStatus));
+#endif
+}
+
+/**
+ * Completion routine for NdisOpenAdapter issued from within the vboxNetFltWinPtBindAdapter. Simply
+ * unblock the caller.
+ *
+ * @param ProtocolBindingContext    Pointer to the adapter
+ * @param Status                    Status of the NdisOpenAdapter call
+ * @param OpenErrorStatus            Secondary status(ignored by us).
+ * @return    None
+ * */
+static VOID
+vboxNetFltWinPtOpenAdapterComplete(
+    IN  NDIS_HANDLE             ProtocolBindingContext,
+    IN  NDIS_STATUS             Status,
+    IN  NDIS_STATUS             OpenErrorStatus
+    )
+{
+    PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
+
+    UNREFERENCED_PARAMETER(OpenErrorStatus);
+
+    LogFlow(("==> vboxNetFltWinPtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
+    if(pAdapt->Status == NDIS_STATUS_SUCCESS)
+    {
+        pAdapt->Status = Status;
+    }
+    NdisSetEvent(&pAdapt->hEvent);
+}
+
+DECLHIDDEN(NDIS_STATUS)
+vboxNetFltWinPtDoUnbinding(PADAPT pAdapt, bool bOnUnbind)
+{
+    NDIS_STATUS    Status;
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    PNDIS_PACKET   PacketArray[MAX_RECEIVE_PACKET_ARRAY_SIZE];
+    ULONG          NumberOfPackets = 0, i;
+    BOOLEAN        CompleteRequest = FALSE;
+    BOOLEAN        ReturnPackets = FALSE;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+    uint64_t NanoTS = RTTimeSystemNanoTS();
+#endif
+
+    LogFlow(("==> vboxNetFltWinPtDoUnbinding: Adapt %p\n", pAdapt));
+
+    Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    Assert(vboxNetFltWinGetOpState(&pAdapt->PTState) == kVBoxNetDevOpState_Initialized);
+    /*
+     * Set the flag that the miniport below is unbinding, so the request handlers will
+     * fail any request comming later
+     */
+    RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+
+    ASMAtomicUoWriteBool(&pNetFlt->fDisconnectedFromHost, true);
+    ASMAtomicUoWriteBool(&pNetFlt->fRediscoveryPending, false);
+    ASMAtomicUoWriteU64(&pNetFlt->NanoTSLastRediscovery, NanoTS);
+
+//    pAdapt->PTState.DeviceState = NdisDeviceStateD3;
+//    pAdapt->MPState.DeviceState = NdisDeviceStateD3;
+    vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitializing);
+    if(!bOnUnbind)
+    {
+        vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitializing);
+    }
+
+    if (pAdapt->bQueuedRequest == TRUE)
+    {
+        pAdapt->bQueuedRequest = FALSE;
+        CompleteRequest = TRUE;
+    }
+    if (pAdapt->cReceivedPacketCount > 0)
+    {
+
+        NdisMoveMemory(PacketArray,
+                      pAdapt->aReceivedPackets,
+                      pAdapt->cReceivedPacketCount * sizeof(PNDIS_PACKET));
+
+        NumberOfPackets = pAdapt->cReceivedPacketCount;
+
+        pAdapt->cReceivedPacketCount = 0;
+        ReturnPackets = TRUE;
+    }
+
+
+    RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+
+    if (CompleteRequest == TRUE)
+    {
+        vboxNetFltWinPtRequestComplete(pAdapt,
+                         &pAdapt->Request,
+                         NDIS_STATUS_FAILURE );
+
+    }
+    if (ReturnPackets == TRUE)
+    {
+        for (i = 0; i < NumberOfPackets; i++)
+        {
+            vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
+        }
+    }
+
+    vboxNetFltWinWaitDereference(&pAdapt->MPState);
+
+    vboxNetFltWinWaitDereference(&pAdapt->PTState);
+
+    while (ASMAtomicUoReadBool((volatile bool *)&pAdapt->bOutstandingRequests))
+    {
+        /*
+         * sleep till outstanding requests complete
+         */
+        vboxNetFltWinSleep(2);
+    }
+
+    if(!bOnUnbind || !vboxNetFltWinMpDeInitializeDevideInstance(pAdapt, &Status))
+#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
+    {
+        /*
+         * We need to do some work here.
+         * Close the binding below us
+         * and release the memory allocated.
+         */
+        vboxNetFltWinPtCloseAdapter(pAdapt, &Status);
+        vboxNetFltWinSetOpState(&pAdapt->PTState, kVBoxNetDevOpState_Deinitialized);
+
+        if(!bOnUnbind)
+        {
+            Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitializing);
+            vboxNetFltWinSetOpState(&pAdapt->MPState, kVBoxNetDevOpState_Deinitialized);
+        }
+        else
+        {
+            Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+        }
+    }
+    else
+    {
+        Assert(vboxNetFltWinGetOpState(&pAdapt->MPState) == kVBoxNetDevOpState_Deinitialized);
+    }
+
+    LogFlow(("<== vboxNetFltWinPtDoUnbinding: Adapt %p\n", pAdapt));
+
+    return Status;
+}
+
+/**
+ * Called by NDIS when we are required to unbind to the adapter below.
+ * This functions shares functionality with the miniport's HaltHandler.
+ * The code should ensure that NdisCloseAdapter and NdisFreeMemory is called
+ * only once between the two functions
+ *
+ * @param Status                    Placeholder for return status
+ * @param ProtocolBindingContext    Pointer to the adapter structure
+ * @param UnbindContext            Context for NdisUnbindComplete() if this pends
+ * @return NONE */
+static VOID
+vboxNetFltWinPtUnbindAdapter(
+    OUT PNDIS_STATUS        pStatus,
+    IN  NDIS_HANDLE            ProtocolBindingContext,
+    IN  NDIS_HANDLE            UnbindContext
+    )
+{
+    PADAPT         pAdapt =(PADAPT)ProtocolBindingContext;
+    PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+
+    LogFlow(("==> vboxNetFltWinPtUnbindAdapter: Adapt %p\n", pAdapt));
+
+    *pStatus = vboxNetFltWinDetachFromInterface(pAdapt, true);
+    Assert(*pStatus == NDIS_STATUS_SUCCESS);
+
+    LogFlow(("<== vboxNetFltWinPtUnbindAdapter: Adapt %p\n", pAdapt));
+}
+
+/**
+ * protocol unload handler
+ */
+static VOID
+vboxNetFltWinPtUnloadProtocol(
+    VOID
+)
+{
+    vboxNetFltWinPtDeregister();
+    LogFlow(("vboxNetFltWinPtUnloadProtocol: done!\n"));
+}
+
+
+/**
+ * Completion for the CloseAdapter call.
+ *
+ * @param ProtocolBindingContext    Pointer to the adapter structure
+ * @param Status                    Completion status
+ * @return None */
+static VOID
+vboxNetFltWinPtCloseAdapterComplete(
+    IN    NDIS_HANDLE            ProtocolBindingContext,
+    IN    NDIS_STATUS            Status
+    )
+{
+    PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
+
+    LogFlow(("CloseAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
+    if(pAdapt->Status == NDIS_STATUS_SUCCESS)
+    {
+        pAdapt->Status = Status;
+    }
+    NdisSetEvent(&pAdapt->hEvent);
+}
+
+
+/**
+ * Completion for the reset.
+ *
+ * @param ProtocolBindingContext    Pointer to the adapter structure
+ * @param Status                    Completion status
+ * @return None */
+static VOID
+vboxNetFltWinPtResetComplete(
+    IN  NDIS_HANDLE            ProtocolBindingContext,
+    IN  NDIS_STATUS            Status
+    )
+{
+
+    UNREFERENCED_PARAMETER(ProtocolBindingContext);
+    UNREFERENCED_PARAMETER(Status);
+    /*
+     * We never issue a reset, so we should not be here.
+     */
+    Assert(0);
+}
+
+/**
+ * Completion handler for the previously posted request. All OIDS
+ * are completed by and sent to the same miniport that they were requested for.
+ * If Oid == OID_PNP_QUERY_POWER then the data structure needs to returned with all entries =
+ * NdisDeviceStateUnspecified
+ * @param ProtocolBindingContext    Pointer to the adapter structure
+ * @param NdisRequest                The posted request
+ * @param Status                    Completion status
+ * @return None
+ *
+ */
+DECLHIDDEN(VOID)
+vboxNetFltWinPtRequestComplete(
+    IN  NDIS_HANDLE            ProtocolBindingContext,
+    IN  PNDIS_REQUEST          NdisRequest,
+    IN  NDIS_STATUS            Status
+    )
+{
+    PADAPT        pAdapt = (PADAPT)ProtocolBindingContext;
+    PNDIS_REQUEST pSynchRequest = pAdapt->pSynchRequest;
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    NDIS_OID      Oid = pAdapt->Request.DATA.SET_INFORMATION.Oid ;
+#endif
+
+    if(pSynchRequest == NdisRequest)
+    {
+        /* assynchronous completion of our synch request */
+
+        /*1.set the status */
+        pAdapt->fSynchCompletionStatus = Status;
+
+        /* 2. set event */
+        KeSetEvent(&pAdapt->hSynchCompletionEvent, 0, FALSE);
+
+        /* 3. return; */
+        return;
+    }
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    Assert(0);
+    return;
+#else
+
+    /*
+     * Since our request is not outstanding anymore
+     */
+    Assert(pAdapt->bOutstandingRequests == TRUE);
+
+    pAdapt->bOutstandingRequests = FALSE;
+
+    /*
+     * Complete the Set or Query, and fill in the buffer for OID_PNP_CAPABILITIES, if need be.
+     */
+    switch (NdisRequest->RequestType)
+    {
+      case NdisRequestQueryInformation:
+
+        /*
+         * We never pass OID_PNP_QUERY_POWER down.
+         */
+        Assert(Oid != OID_PNP_QUERY_POWER);
+
+        if ((Oid == OID_PNP_CAPABILITIES) && (Status == NDIS_STATUS_SUCCESS))
+        {
+            vboxNetFltWinMpQueryPNPCapabilities(pAdapt, &Status);
+        }
+        *pAdapt->BytesReadOrWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+        *pAdapt->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+
+        if ((Oid == OID_GEN_MAC_OPTIONS) && (Status == NDIS_STATUS_SUCCESS))
+        {
+            /* save mac options for adaptor below us to use it with the NdisCopyLookaheadData when our ProtocolReceive is called */
+            pAdapt->fMacOptions = *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+
+            /* 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)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer |= NDIS_MAC_OPTION_NO_LOOPBACK;
+        }
+        if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
+        {
+            if(Status == NDIS_STATUS_SUCCESS)
+            {
+                /* 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 */
+                pAdapt->fUpperProtocolSetFilter = *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+                pAdapt->bUpperProtSetFilterInitialized = true;
+            }
+        }
+
+
+        NdisMQueryInformationComplete(pAdapt->hMiniportHandle,
+                                      Status);
+        break;
+
+      case NdisRequestSetInformation:
+
+          Assert( Oid != OID_PNP_SET_POWER);
+
+          if(Oid == OID_GEN_CURRENT_PACKET_FILTER && VBOXNETFLT_PROMISCUOUS_SUPPORTED(pAdapt))
+          {
+              PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+              Assert(Status == NDIS_STATUS_SUCCESS);
+              if(pAdapt->bProcessingPacketFilter)
+              {
+                  if(Status == NDIS_STATUS_SUCCESS)
+                  {
+                      pAdapt->fOurSetFilter = *((PULONG)pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer);
+                      Assert(pAdapt->fOurSetFilter == NDIS_PACKET_TYPE_PROMISCUOUS);
+                  }
+                  vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+                  vboxNetFltWinDereferenceAdapt(pAdapt);
+                  pAdapt->bProcessingPacketFilter = false;
+              }
+              else
+              {
+                  if(Status == NDIS_STATUS_SUCCESS)
+                  {
+                      /* the request was issued when the netflt was not active, simply update the cache here */
+                      pAdapt->fUpperProtocolSetFilter = *((PULONG)pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer);
+                      pAdapt->bUpperProtSetFilterInitialized = true;
+                  }
+              }
+          }
+
+
+        *pAdapt->BytesReadOrWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead;
+        *pAdapt->BytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
+        NdisMSetInformationComplete(pAdapt->hMiniportHandle,
+                                    Status);
+        break;
+
+      default:
+        Assert(0);
+        break;
+    }
+#endif
+}
+
+/**
+ * Status handler for the lower-edge(protocol).
+ *
+ * @param ProtocolBindingContext    Pointer to the adapter structure
+ * @param GeneralStatus             Status code
+ * @param StatusBuffer              Status buffer
+ * @param StatusBufferSize          Size of the status buffer
+ * @return None
+ */
+static VOID
+vboxNetFltWinPtStatus(
+    IN  NDIS_HANDLE         ProtocolBindingContext,
+    IN  NDIS_STATUS         GeneralStatus,
+    IN  PVOID               StatusBuffer,
+    IN  UINT                StatusBufferSize
+    )
+{
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    PADAPT      pAdapt = (PADAPT)ProtocolBindingContext;
+
+    /*
+     * Pass up this indication only if the upper edge miniport is initialized
+     * and powered on. Also ignore indications that might be sent by the lower
+     * miniport when it isn't at D0.
+     */
+    if (vboxNetFltWinReferenceAdapt(pAdapt))
+    {
+        Assert(pAdapt->hMiniportHandle);
+
+        if ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) ||
+            (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT))
+        {
+
+            pAdapt->LastIndicatedStatus = GeneralStatus;
+        }
+        NdisMIndicateStatus(pAdapt->hMiniportHandle,
+                            GeneralStatus,
+                            StatusBuffer,
+                            StatusBufferSize);
+
+        vboxNetFltWinDereferenceAdapt(pAdapt);
+    }
+    /*
+     * Save the last indicated media status
+     */
+    else
+    {
+        if ((pAdapt->hMiniportHandle != NULL) &&
+        ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) ||
+            (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT)))
+        {
+            pAdapt->LatestUnIndicateStatus = GeneralStatus;
+        }
+    }
+#endif
+}
+
+/**
+ * status complete handler
+ */
+static VOID
+vboxNetFltWinPtStatusComplete(
+    IN NDIS_HANDLE            ProtocolBindingContext
+    )
+{
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    PADAPT      pAdapt = (PADAPT)ProtocolBindingContext;
+
+    /*
+     * Pass up this indication only if the upper edge miniport is initialized
+     * and powered on. Also ignore indications that might be sent by the lower
+     * miniport when it isn't at D0.
+     */
+    if (vboxNetFltWinReferenceAdapt(pAdapt))
+    {
+        NdisMIndicateStatusComplete(pAdapt->hMiniportHandle);
+
+        vboxNetFltWinDereferenceAdapt(pAdapt);
+    }
+#endif
+}
+
+/**
+ * Called by NDIS when the miniport below had completed a send. We should
+ * complete the corresponding upper-edge send this represents.
+ *
+ * @param ProtocolBindingContext - Points to ADAPT structure
+ * @param Packet - Low level packet being completed
+ * @param Status - status of send
+ * @return None
+ */
+static VOID
+vboxNetFltWinPtSendComplete(
+    IN  NDIS_HANDLE            ProtocolBindingContext,
+    IN  PNDIS_PACKET           Packet,
+    IN  NDIS_STATUS            Status
+    )
+{
+    PADAPT            pAdapt = (PADAPT)ProtocolBindingContext;
+    PNDIS_PACKET      Pkt;
+
+    {
+        PSEND_RSVD        SendRsvd;
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//        PPACKET_INFO pInfo = vboxNetFltWinDoCompleteSend(pAdapt, Packet);
+//
+//        if(pInfo)
+//        {
+//            vboxNetFltWinPpFreePacketInfo(pInfo);
+//        }
+#endif
+//        Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+        SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
+        Pkt = SendRsvd->pOriginalPkt;
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        if(Pkt)
+        {
+#ifndef WIN9X
+            NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
+#endif
+            NdisFreePacket(Packet);
+
+            /* the ptk was posted from the upperlying protocol */
+            NdisMSendComplete(pAdapt->hMiniportHandle,
+                                     Pkt,
+                                     Status);
+        }
+        else
+#else
+            /* TODO: should change the PSEND_RSVD structure as we no nolnger need  to handle original packets
+             * because all packets are originated by us */
+            Assert(!Pkt);
+#endif
+        {
+            /* if the ptk is zerro - the ptk was originated by netFlt send/receive
+             * need to free packet buffers */
+            PVOID pBufToFree = SendRsvd->pBufToFree;
+
+            vboxNetFltWinFreeSGNdisPacket(Packet, !pBufToFree);
+            if(pBufToFree)
+            {
+                vboxNetFltWinMemFree(pBufToFree);
+            }
+        }
+    }
+
+    vboxNetFltWinDereferenceAdapt(pAdapt);
+}
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+
+/**
+ * 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(PINTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket)
+{
+    PTRANSFERDATA_RSVD pTDR = &((PPT_RSVD)pPacket->ProtocolReserved)->TransferDataRsvd;
+    return vboxNetFltWinInterlockedSearchListEntry(pList, &pTDR->ListEntry,
+            true /* remove*/);
+}
+
+/**
+ * puts the packet to the tail of the list
+ */
+static void vboxNetFltWinPutPacketToList(PINTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket, PNDIS_BUFFER pOrigBuffer)
+{
+    PTRANSFERDATA_RSVD pTDR = &((PPT_RSVD)pPacket->ProtocolReserved)->TransferDataRsvd;
+    pTDR->pOriginalBuffer = pOrigBuffer;
+    vboxNetFltWinInterlockedPutTail(pList, &pTDR->ListEntry);
+}
+
+#endif
+
+static bool vboxNetFltWinPtTransferDataCompleteActive(IN PADAPT pAdapt,
+        IN PNDIS_PACKET pPacket,
+        IN NDIS_STATUS Status)
+{
+    PVBOXNETFLTINS pNetFltIf = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    PNDIS_BUFFER pBuffer;
+    PTRANSFERDATA_RSVD pTDR;
+
+    if(!vboxNetFltWinRemovePacketFromList(&pAdapt->TransferDataList, pPacket))
+        return false;
+
+    pTDR = &((PPT_RSVD)pPacket->ProtocolReserved)->TransferDataRsvd;
+    Assert(pTDR);
+    Assert(pTDR->pOriginalBuffer);
+
+    do
+    {
+        NdisUnchainBufferAtFront(pPacket, &pBuffer);
+
+        Assert(pBuffer);
+
+        NdisFreeBuffer(pBuffer);
+
+        pBuffer = pTDR->pOriginalBuffer;
+
+        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 DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+    /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+    instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+    similar to that used in TrasferData handling should be used;
+    */
+
+//                /* 1. if loopback then quit with  NDIS_STATUS_NOT_ACCEPTED */
+//#ifdef VBOX_NETFLT_ONDEMAND_BIND
+//                if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket))
+//#else
+//                if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket, true))
+//#endif
+#else
+            if(vboxNetFltWinIsLoopedBackPacket(pPacket))
+#endif
+            {
+                Assert(0);
+            }
+            else
+            {
+                PRECV_RSVD            pRecvRsvd;
+                /* 2. enqueue */
+                /* use the same packet info to put the packet in the processing packet queue */
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+                PNDIS_BUFFER pBuffer;
+                PVOID pVA;
+                UINT cbLength;
+                uint32_t fFlags;
+
+                NdisQueryPacket(pPacket, NULL, NULL, &pBuffer, NULL);
+                NdisQueryBufferSafe(pBuffer, &pVA, &cbLength, NormalPagePriority);
+
+                fFlags = MACS_EQUAL(((PRTNETETHERHDR)pVA)->SrcMac, pNetFltIf->u.s.Mac) ?
+                                                PACKET_MINE | PACKET_SRC_HOST : PACKET_MINE;
+                SET_FLAGS_TO_INFO(pInfo, fFlags);
+
+                pRecvRsvd = (PRECV_RSVD)(pPacket->MiniportReserved);
+                pRecvRsvd->pOriginalPkt = NULL;
+                pRecvRsvd->pBufToFree = NULL;
+
+                NdisSetPacketFlags(pPacket, 0);
+
+                Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, fFlags);
+#else
+                pRecvRsvd = (PRECV_RSVD)(pPacket->MiniportReserved);
+                pRecvRsvd->pOriginalPkt = NULL;
+                pRecvRsvd->pBufToFree = NULL;
+
+                NdisSetPacketFlags(pPacket, 0);
+
+                Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, PACKET_MINE);
+#endif
+                if(Status == NDIS_STATUS_SUCCESS)
+                {
+                    break;
+                }
+                Assert(0);
+            }
+        }
+        else
+        {
+            Assert(0);
+        }
+        /* we are here because of error either in data transfer or in enqueueing the packet */
+        vboxNetFltWinFreeSGNdisPacket(pPacket, true);
+        vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+        vboxNetFltWinDereferenceAdapt(pAdapt);
+    } while(0);
+
+    return true;
+}
+
+/**
+ * Entry point called by NDIS to indicate completion of a call by us
+ * to NdisTransferData.
+ *
+ * See notes under SendComplete.
+ */
+static VOID
+vboxNetFltWinPtTransferDataComplete(
+    IN  NDIS_HANDLE         ProtocolBindingContext,
+    IN  PNDIS_PACKET        pPacket,
+    IN  NDIS_STATUS         Status,
+    IN  UINT                BytesTransferred
+    )
+{
+    PADAPT      pAdapt =(PADAPT)ProtocolBindingContext;
+    if(!vboxNetFltWinPtTransferDataCompleteActive(pAdapt, pPacket, Status))
+    {
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        if(pAdapt->hMiniportHandle)
+        {
+            NdisMTransferDataComplete(pAdapt->hMiniportHandle,
+                                      pPacket,
+                                      Status,
+                                      BytesTransferred);
+        }
+
+        vboxNetFltWinDereferenceAdapt(pAdapt);
+#else
+        /* we are here because we've failed to allocate packet info */
+        Assert(0);
+#endif
+    }
+}
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+
+/**
+ * This is to queue the received packets and indicates them up if the given Packet
+ * status is NDIS_STATUS_RESOURCES, or the array is full.
+ *
+ * @param pAdapt   -    Pointer to the adpater structure.
+ * @param Packet   -    Pointer to the indicated packet.
+ * @param Indicate -  Do the indication now.
+ * @return NONE
+ */
+static VOID
+vboxNetFltWinPtQueueReceivedPacket(
+    IN PADAPT       pAdapt,
+    IN PNDIS_PACKET Packet,
+    IN BOOLEAN      DoIndicate
+    )
+{
+    PNDIS_PACKET    PacketArray[MAX_RECEIVE_PACKET_ARRAY_SIZE];
+    ULONG           NumberOfPackets = 0, i;
+    bool bReturn = false;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+    Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+    do{
+        RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+
+        if(vboxNetFltWinGetPowerState(&pAdapt->PTState) != NdisDeviceStateD0
+                || vboxNetFltWinGetPowerState(&pAdapt->MPState) != NdisDeviceStateD0
+                || vboxNetFltWinGetOpState(&pAdapt->PTState) > kVBoxNetDevOpState_Initialized
+                || vboxNetFltWinGetOpState(&pAdapt->MPState) > kVBoxNetDevOpState_Initialized)
+        {
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            bReturn = true;
+            break;
+        }
+
+        Assert(pAdapt->cReceivedPacketCount < MAX_RECEIVE_PACKET_ARRAY_SIZE);
+
+        /*
+         * pAdapt->ReceviePacketCount must be less than MAX_RECEIVE_PACKET_ARRAY_SIZE because
+         * the thread which held the pVElan->Lock before should already indicate the packet(s)
+         * up if pAdapt->ReceviePacketCount == MAX_RECEIVE_PACKET_ARRAY_SIZE.
+         */
+        pAdapt->aReceivedPackets[pAdapt->cReceivedPacketCount] = Packet;
+        pAdapt->cReceivedPacketCount++;
+
+        /*
+         *  If our receive packet array is full, or the miniport below indicated the packets
+         *  with resources, do the indicatin now.
+         */
+
+        if ((pAdapt->cReceivedPacketCount == MAX_RECEIVE_PACKET_ARRAY_SIZE) || DoIndicate)
+        {
+            NdisMoveMemory(PacketArray,
+                           pAdapt->aReceivedPackets,
+                           pAdapt->cReceivedPacketCount * sizeof(PNDIS_PACKET));
+
+            NumberOfPackets = pAdapt->cReceivedPacketCount;
+            /*
+             * So other thread can queue the received packets
+             */
+            pAdapt->cReceivedPacketCount = 0;
+            DoIndicate = TRUE;
+        }
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+    } while(0);
+
+    if(!bReturn)
+    {
+        if(DoIndicate)
+        {
+            NdisMIndicateReceivePacket(pAdapt->hMiniportHandle, PacketArray, NumberOfPackets);
+        }
+    }
+    else
+    {
+        if (DoIndicate)
+        {
+            NumberOfPackets  -= 1;
+        }
+        for (i = 0; i < NumberOfPackets; i++)
+        {
+            vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
+        }
+    }
+}
+
+/**
+ * This routine process the queued the packet, if anything is fine, indicate the packet
+ * up, otherwise, return the packet to the underlying miniports.
+ *
+ * @param pAdapt   -    Pointer to the adpater structure.
+ * @param bReturn - if true the packets should be returned without indication to the upper protocol
+ * @return None. */
+DECLHIDDEN(VOID)
+vboxNetFltWinPtFlushReceiveQueue(
+    IN PADAPT         pAdapt,
+    IN bool bReturn
+    )
+{
+
+    PNDIS_PACKET  PacketArray[MAX_RECEIVE_PACKET_ARRAY_SIZE];
+    ULONG         NumberOfPackets = 0, i;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+    do
+    {
+        RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+
+        if (pAdapt->cReceivedPacketCount > 0)
+        {
+            NdisMoveMemory(PacketArray,
+                            pAdapt->aReceivedPackets,
+                            pAdapt->cReceivedPacketCount * sizeof(PNDIS_PACKET));
+
+            NumberOfPackets = pAdapt->cReceivedPacketCount;
+            /*
+             * So other thread can queue the received packets
+             */
+            pAdapt->cReceivedPacketCount = 0;
+
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+
+            if(!bReturn)
+            {
+                if(NumberOfPackets > 0)
+                {
+                    Assert(pAdapt->hMiniportHandle);
+
+                    /* we are here because the NetFlt is NOT active,
+                     * so no need for packet queueing here, simply indicate */
+                    NdisMIndicateReceivePacket(pAdapt->hMiniportHandle,
+                                               PacketArray,
+                                               NumberOfPackets);
+                }
+                break;
+            }
+            /*
+             * We need return the packet here
+             */
+            for (i = 0; i < NumberOfPackets; i ++)
+            {
+                vboxNetFltWinMpReturnPacket(pAdapt, PacketArray[i]);
+            }
+
+            /* break to ensure we do not call RTSpinlockRelease extra time */
+            break;
+        }
+
+        /* we are here only in case pAdapt->cReceivedPacketCount == 0 */
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+    } while (FALSE);
+}
+
+/**
+ * ReceivePacket handler. Called by NDIS if the miniport below supports
+ * NDIS 4.0 style receives. Re-package the buffer chain in a new packet
+ * and indicate the new packet to protocols above us. Any context for
+ * packets indicated up must be kept in the MiniportReserved field.
+ *
+ * @param ProtocolBindingContext - Pointer to our adapter structure.
+ * @param Packet - Pointer to the packet
+ * @return INT  == 0 -> We are done with the packet
+ *  != 0 -> We will keep the packet and call NdisReturnPackets() this
+ *  many times when done. */
+static INT
+vboxNetFltWinRecvPacketPassThru(
+    IN PADAPT            pAdapt,
+    IN PNDIS_PACKET           pPacket
+    )
+{
+    NDIS_STATUS         fStatus;
+    PNDIS_PACKET        pMyPacket;
+
+    Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    fStatus = vboxNetFltWinPrepareRecvPacket(pAdapt, pPacket, &pMyPacket, true);
+
+    Assert(pMyPacket);
+
+    if(pMyPacket != NULL)
+    {
+        if (fStatus == NDIS_STATUS_RESOURCES)
+        {
+            vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, TRUE);
+
+            /*
+             * Our ReturnPackets handler will not be called for this packet.
+             * We should reclaim it right here.
+             */
+            NdisDprFreePacket(pMyPacket);
+
+            return 0;
+        }
+
+        vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, FALSE);
+
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * process the packet receive in a "passthru" mode
+ */
+static NDIS_STATUS
+vboxNetFltWinRecvPassThru(
+        IN PADAPT             pAdapt,
+        IN PNDIS_PACKET           pPacket)
+{
+
+    NDIS_STATUS fStatus;
+    PNDIS_PACKET pMyPacket;
+    /*
+     * The miniport below did indicate up a packet. Use information
+     * from that packet to construct a new packet to indicate up.
+     */
+
+    Assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /*
+     * Get a packet off the pool and indicate that up
+     */
+    NdisDprAllocatePacket(&fStatus,
+                            &pMyPacket,
+                            pAdapt->hRecvPacketPoolHandle);
+    Assert(fStatus == NDIS_STATUS_SUCCESS);
+    if (fStatus == NDIS_STATUS_SUCCESS)
+    {
+            /*
+             * Make our packet point to data from the original
+             * packet. NOTE: this works only because we are
+             * indicating a receive directly from the context of
+             * our receive indication. If we need to queue this
+             * packet and indicate it from another thread context,
+             * we will also have to allocate a new buffer and copy
+             * over the packet contents, OOB data and per-packet
+             * information. This is because the packet data
+             * is available only for the duration of this
+             * receive indication call.
+             */
+        NDIS_PACKET_FIRST_NDIS_BUFFER(pMyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(pPacket);
+        NDIS_PACKET_LAST_NDIS_BUFFER(pMyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(pPacket);
+
+            /*
+             * Get the original packet (it could be the same packet as the
+             * one received or a different one based on the number of layered
+             * miniports below) and set it on the indicated packet so the OOB
+             * data is visible correctly at protocols above.
+             */
+        NDIS_SET_ORIGINAL_PACKET(pMyPacket, NDIS_GET_ORIGINAL_PACKET(pPacket));
+        NDIS_SET_PACKET_HEADER_SIZE(pMyPacket, NDIS_GET_PACKET_HEADER_SIZE(pPacket));
+
+            /*
+             * Copy packet flags.
+             */
+        NdisGetPacketFlags(pMyPacket) = NdisGetPacketFlags(pPacket);
+
+            /*
+             * Force protocols above to make a copy if they want to hang
+             * on to data in this packet. This is because we are in our
+             * Receive handler (not ReceivePacket) and we can't return a
+             * ref count from here.
+             */
+        NDIS_SET_PACKET_STATUS(pMyPacket, NDIS_STATUS_RESOURCES);
+
+            /*
+             * By setting NDIS_STATUS_RESOURCES, we also know that we can reclaim
+             * this packet as soon as the call to NdisMIndicateReceivePacket
+             * returns.
+             *
+             * NOTE: we queue the packet and indicate this packet immediately with
+             * the already queued packets together. We have to the queue the packet
+             * first because some versions of NDIS might call protocols'
+             * ReceiveHandler(not ReceivePacketHandler) if the packet indicate status
+             * is NDIS_STATUS_RESOURCES. If the miniport below indicates an array of
+             * packets, some of them with status NDIS_STATUS_SUCCESS, some of them
+             * with status NDIS_STATUS_RESOURCES, vboxNetFltWinPtReceive might be called, by
+             * doing this way, we preserve the receive order of packets.
+             */
+        vboxNetFltWinPtQueueReceivedPacket(pAdapt, pMyPacket, TRUE);
+            /*
+             * Reclaim the indicated packet. Since we had set its status
+             * to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
+             * above are done with it.
+             */
+        NdisDprFreePacket(pMyPacket);
+
+    }
+    return fStatus;
+}
+
+#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
+
+
+
+
+/**
+ * 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(
+    IN PADAPT pAdapt,
+    IN NDIS_HANDLE                  MacReceiveContext,
+    IN PVOID                        pHeaderBuffer,
+    IN UINT                         cbHeaderBuffer,
+    IN PVOID                        pLookaheadBuffer,
+    IN UINT                         cbLookaheadBuffer,
+    IN UINT                         cbPacket
+    )
+{
+    NDIS_STATUS             Status = NDIS_STATUS_SUCCESS;
+
+    do
+    {
+        if (cbHeaderBuffer != ETH_HEADER_SIZE)
+        {
+            Status = NDIS_STATUS_NOT_ACCEPTED;
+            break;
+        }
+
+#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
+        /* can check for loopback? check it*/
+        if (cbPacket == cbLookaheadBuffer)
+        {
+            PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+            PINTNETSG pSG;
+            PUCHAR pRcvData;
+
+#ifdef DEBUG_NETFLT_LOOPBACK
+                /* TODO: can we check for loopback here ?
+                 * for now just get the complete SG and then decide if it is a loopback one */
+                /* if loopback then quit */
+#endif
+                /* allocate SG buffer */
+                Status = vboxNetFltWinAllocSG(cbPacket + cbHeaderBuffer, &pSG);
+                if(Status != NDIS_STATUS_SUCCESS)
+                {
+                    Assert(0);
+                    break;
+                }
+
+                pRcvData = (PUCHAR)pSG->aSegs[0].pv;
+
+                NdisMoveMappedMemory(pRcvData, pHeaderBuffer, cbHeaderBuffer);
+
+                NdisCopyLookaheadData(pRcvData+cbHeaderBuffer,
+                                                  pLookaheadBuffer,
+                                                  cbLookaheadBuffer,
+                                                  pAdapt->fMacOptions);
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//                /* check if it is a loopback */
+//# ifdef VBOX_NETFLT_ONDEMAND_BIND
+//                if(vboxNetFltWinIsLoopedBackPacketSG(pAdapt, pSG))
+//# else
+//                if(vboxNetFltWinIsLoopedBackPacketSG(pAdapt, pSG, true))
+//# endif
+//                {
+//                    Assert(0);
+//                    vboxNetFltWinMemFree(pSG);
+//                    Status = NDIS_STATUS_NOT_ACCEPTED;
+//                    break;
+//                }
+#endif
+                /* enqueue SG */
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+                {
+                    uint32_t fFlags = MACS_EQUAL(((PRTNETETHERHDR)pRcvData)->SrcMac, pNetFlt->u.s.Mac) ?
+                            PACKET_SG | PACKET_MINE | PACKET_SRC_HOST : PACKET_SG | PACKET_MINE;
+                    Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, fFlags);
+                }
+#else
+                Status = vboxNetFltWinQuEnqueuePacket(pNetFlt, pSG, PACKET_SG | PACKET_MINE);
+#endif
+                if(Status != NDIS_STATUS_SUCCESS)
+                {
+                    Assert(0);
+                    vboxNetFltWinMemFree(pSG);
+                    break;
+                }
+        }
+        else
+#endif /* #ifndef DEBUG_NETFLT_RECV_TRANSFERDATA */
+        {
+            PNDIS_PACKET            pPacket;
+            PNDIS_BUFFER pTransferBuffer;
+            PNDIS_BUFFER pOrigBuffer;
+            PUCHAR pMemBuf;
+            UINT cbBuf = cbPacket + cbHeaderBuffer;
+//            PPACKET_INFO pInfo;
+            UINT                    BytesTransferred;
+                /* TODO: can check for loopback here ? */
+                /* for now just get the complete complete packet and then decide if it is a looped back one */
+                /* if loopback then quit with  NDIS_STATUS_NOT_ACCEPTED
+                 * {
+                 *     Status = NDIS_STATUS_NOT_ACCEPTED;
+                 *     break;
+                 * }
+                 * */
+
+                /* allocate NDIS Packet buffer */
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+            /* use the Send packet pool for packet allocation */
+            NdisAllocatePacket(&Status, &pPacket, pAdapt->hSendPacketPoolHandle);
+#else
+            NdisAllocatePacket(&Status, &pPacket, pAdapt->hRecvPacketPoolHandle);
+#endif
+            if(Status != NDIS_STATUS_SUCCESS)
+            {
+                Assert(0);
+                break;
+            }
+
+            /* set "don't loopback" flags */
+            NdisSetPacketFlags(pPacket, g_fPacketDontLoopBack);
+
+            Status = vboxNetFltWinMemAlloc(&pMemBuf, cbBuf);
+            if(Status != NDIS_STATUS_SUCCESS)
+            {
+                Assert(0);
+                NdisFreePacket(pPacket);
+                break;
+            }
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+            /* use the Send buffer pool for buffer allocation */
+            NdisAllocateBuffer(&Status, &pTransferBuffer, pAdapt->hSendBufferPoolHandle, pMemBuf + cbHeaderBuffer, cbPacket);
+#else
+            NdisAllocateBuffer(&Status, &pTransferBuffer, pAdapt->hRecvBufferPoolHandle, pMemBuf + cbHeaderBuffer, cbPacket);
+#endif
+            if(Status != NDIS_STATUS_SUCCESS)
+            {
+                Assert(0);
+                Status = NDIS_STATUS_FAILURE;
+                NdisFreePacket(pPacket);
+                vboxNetFltWinMemFree(pMemBuf);
+                break;
+            }
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+            /* use the Send buffer pool for buffer allocation */
+            NdisAllocateBuffer(&Status, &pOrigBuffer, pAdapt->hSendBufferPoolHandle, pMemBuf, cbBuf);
+#else
+            NdisAllocateBuffer(&Status, &pOrigBuffer, pAdapt->hRecvBufferPoolHandle, pMemBuf, cbBuf);
+#endif
+            if(Status != NDIS_STATUS_SUCCESS)
+            {
+                Assert(0);
+                Status = NDIS_STATUS_FAILURE;
+                NdisFreeBuffer(pTransferBuffer);
+                NdisFreePacket(pPacket);
+                vboxNetFltWinMemFree(pMemBuf);
+                break;
+            }
+
+            NdisChainBufferAtBack(pPacket, pTransferBuffer);
+
+            NdisMoveMappedMemory(pMemBuf, pHeaderBuffer, cbHeaderBuffer);
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+            vboxNetFltWinPutPacketToList(&pAdapt->TransferDataList, pPacket, pOrigBuffer);
+#endif
+
+#ifdef DEBUG_NETFLT_RECV_TRANSFERDATA
+            if(cbPacket == cbLookaheadBuffer)
+            {
+                NdisCopyLookaheadData(pMemBuf+cbHeaderBuffer,
+                                                  pLookaheadBuffer,
+                                                  cbLookaheadBuffer,
+                                                  pAdapt->fMacOptions);
+            }
+            else
+#endif
+            {
+                Assert(cbPacket > cbLookaheadBuffer);
+
+                NdisTransferData(
+                        &Status,
+                        pAdapt->hBindingHandle,
+                        MacReceiveContext,
+                        0,  /* ByteOffset */
+                        cbPacket,
+                        pPacket,
+                        &BytesTransferred);
+            }
+            if(Status != NDIS_STATUS_PENDING)
+            {
+                vboxNetFltWinPtTransferDataComplete(pAdapt, pPacket, Status, BytesTransferred);
+            }
+        }
+    } while(0);
+
+    return Status;
+}
+
+
+/**
+ * Handle receive data indicated up by the miniport below. We pass
+ * it along to the protocol above us.
+ *
+ * If the miniport below indicates packets, NDIS would more
+ * likely call us at our ReceivePacket handler. However we
+ * might be called here in certain situations even though
+ * the miniport below has indicated a receive packet, e.g.
+ * if the miniport had set packet status to NDIS_STATUS_RESOURCES.
+ *
+ * @param ProtocolBindingContext
+ * @param MacReceiveContext
+ * @param pHeaderBuffer
+ * @param cbHeaderBuffer
+ * @param pLookAheadBuffer
+ * @param cbLookAheadBuffer
+ * @param cbPacket
+ * @return NDIS_STATUS_SUCCESS if we processed the receive successfully,
+ *      NDIS_STATUS_XXX error code if we discarded it. */
+static NDIS_STATUS
+vboxNetFltWinPtReceive(
+    IN  NDIS_HANDLE         ProtocolBindingContext,
+    IN  NDIS_HANDLE         MacReceiveContext,
+    IN  PVOID               pHeaderBuffer,
+    IN  UINT                cbHeaderBuffer,
+    IN  PVOID               pLookAheadBuffer,
+    IN  UINT                cbLookAheadBuffer,
+    IN  UINT                cbPacket
+    )
+{
+    PADAPT            pAdapt = (PADAPT)ProtocolBindingContext;
+    NDIS_STATUS       Status = NDIS_STATUS_SUCCESS;
+    PVBOXNETFLTINS pNetFltIf;
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+#if 0
+    uint32_t fFlags;
+#endif
+
+    pNetFltIf = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt);
+    if(pNetFltIf)
+    {
+        do
+        {
+#if 0
+            pPacket = NdisGetReceivedPacket(pAdapt->hBindingHandle, MacReceiveContext);
+            if(pPacket)
+            {
+# ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//                if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket))
+# else
+                if(vboxNetFltWinIsLoopedBackPacket(pPacket) || cbHeaderBuffer != ETH_HEADER_SIZE)
+# endif
+
+                {
+//                    Assert(0);
+                    /* nothing else to do here, just return the packet */
+//                    NdisReturnPackets(&pPacket, 1);
+//                    break;
+                }
+
+                fFlags = MACS_EQUAL(((PRTNETETHERHDR)pHeaderBuffer)->SrcMac, pNetFltIf->u.s.Mac) ?
+                        PACKET_COPY | PACKET_SRC_HOST : PACKET_COPY;
+                Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, fFlags);
+                if(Status == NDIS_STATUS_SUCCESS)
+                {
+                    NdisReturnPackets(&pPacket, 1);
+                    pAdapt = NULL;
+                    pNetFltIf = NULL;
+                    break;
+                }
+            }
+#endif
+            Status = vboxNetFltWinPtReceiveActive(pAdapt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
+                    pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
+            if(NT_SUCCESS(Status))
+            {
+                if(Status != NDIS_STATUS_NOT_ACCEPTED)
+                {
+                    pAdapt = NULL;
+                    pNetFltIf = NULL;
+                }
+                else
+                {
+                    /* this is a looopback packet, nothing to do here */
+                }
+                break;
+            }
+        } while(0);
+
+        if(pNetFltIf)
+            vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+        if(pAdapt)
+            vboxNetFltWinDereferenceAdapt(pAdapt);
+
+
+#if 0
+        if(pPacket)
+        {
+            NdisReturnPackets(&pPacket, 1);
+        }
+#endif
+        /* we are here because the vboxNetFltWinPtReceiveActive returned pending,
+         * which means our ProtocolDataTransferComplete we will called,
+         * so return SUCCESS instead of NOT_ACCEPTED ?? */
+//        return NDIS_STATUS_SUCCESS;
+    }
+    return NDIS_STATUS_NOT_ACCEPTED;
+#else /* if NOT defined VBOX_NETFLT_ONDEMAND_BIND */
+    PNDIS_PACKET      pPacket = NULL;
+    bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf);
+    if(fAdaptActive)
+    {
+        do
+        {
+#ifndef DEBUG_NETFLT_RECV_NOPACKET
+            /*
+             * Get at the packet, if any, indicated up by the miniport below.
+             */
+            pPacket = NdisGetReceivedPacket(pAdapt->hBindingHandle, MacReceiveContext);
+            if (pPacket != NULL)
+            {
+                do
+                {
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//                    if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket, true))
+#else
+                    if(vboxNetFltWinIsLoopedBackPacket(pPacket))
+#endif
+
+                    {
+                        Assert(0);
+                        /* nothing else to do here, just return the packet */
+                        //NdisReturnPackets(&pPacket, 1);
+                        Status = NDIS_STATUS_NOT_ACCEPTED;
+                        break;
+                    }
+
+                    if(pNetFltIf)
+                    {
+                        Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, PACKET_COPY);
+                        if(Status == NDIS_STATUS_SUCCESS)
+                        {
+                            //NdisReturnPackets(&pPacket, 1);
+                            fAdaptActive = false;
+                            pNetFltIf = NULL;
+                            break;
+                        }
+                    }
+
+                    Status = vboxNetFltWinRecvPassThru(pAdapt, pPacket);
+                    /* we are done with packet processing, and we will
+                     * not receive packet return event for this packet,
+                     * fAdaptActive should be true to ensure we release adapt*/
+                    Assert(fAdaptActive);
+                } while(FALSE);
+
+                if(Status == NDIS_STATUS_SUCCESS || Status == NDIS_STATUS_NOT_ACCEPTED)
+                {
+                    break;
+                }
+            }
+#endif /* todo: remove */
+            if(pNetFltIf)
+            {
+                Status = vboxNetFltWinPtReceiveActive(pAdapt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer,
+                        pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
+                if(NT_SUCCESS(Status))
+                {
+                    if(Status != NDIS_STATUS_NOT_ACCEPTED)
+                    {
+                        fAdaptActive = false;
+                        pNetFltIf = NULL;
+                    }
+                    else
+                    {
+                        /* this is a loopback packet, nothing to do here */
+                    }
+                    break;
+                }
+            }
+
+            /* Fall through if the miniport below us has either not
+             * indicated a packet or we could not allocate one */
+            if(pPacket != NULL)
+            {
+                /*
+                 * We are here because we failed to allocate packet
+                 */
+                vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
+            }
+
+            /* we are done with packet processing, and we will
+             * not receive packet return event for this packet,
+             * fAdaptActive should be true to ensure we release adapt*/
+            Assert(fAdaptActive);
+
+            pAdapt->bIndicateRcvComplete = TRUE;
+            switch (pAdapt->Medium)
+            {
+                case NdisMedium802_3:
+                case NdisMediumWan:
+                    NdisMEthIndicateReceive(pAdapt->hMiniportHandle,
+                                                 MacReceiveContext,
+                                                 (PCHAR)pHeaderBuffer,
+                                                 cbHeaderBuffer,
+                                                 pLookAheadBuffer,
+                                                 cbLookAheadBuffer,
+                                                 cbPacket);
+                    break;
+                default:
+                    Assert(FALSE);
+                    break;
+            }
+        } while(0);
+
+        if(pNetFltIf)
+            vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+        if(fAdaptActive)
+            vboxNetFltWinDereferenceAdapt(pAdapt);
+    }
+    else
+    {
+        Status = NDIS_STATUS_FAILURE;
+    }
+
+    return Status;
+#endif
+}
+
+/**
+ * Called by the adapter below us when it is done indicating a batch of
+ * received packets.
+ *
+ * @param ProtocolBindingContext    Pointer to our adapter structure.
+ * @return None */
+static VOID
+vboxNetFltWinPtReceiveComplete(
+    IN NDIS_HANDLE        ProtocolBindingContext
+    )
+{
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+    PADAPT        pAdapt =(PADAPT)ProtocolBindingContext;
+    ULONG         NumberOfPackets = 0;
+
+    vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
+
+    if ((pAdapt->hMiniportHandle != NULL)
+               /* && (pAdapt->MPDeviceState == NdisDeviceStateD0) */
+                && (pAdapt->bIndicateRcvComplete == TRUE))
+    {
+        switch (pAdapt->Medium)
+        {
+            case NdisMedium802_3:
+            case NdisMediumWan:
+                NdisMEthIndicateReceiveComplete(pAdapt->hMiniportHandle);
+                break;
+            default:
+                Assert(FALSE);
+                break;
+        }
+    }
+
+    pAdapt->bIndicateRcvComplete = FALSE;
+#endif
+}
+
+/**
+ * ReceivePacket handler. Called by NDIS if the miniport below supports
+ * NDIS 4.0 style receives. Re-package the buffer chain in a new packet
+ * and indicate the new packet to protocols above us. Any context for
+ * packets indicated up must be kept in the MiniportReserved field.
+ *
+ * @param ProtocolBindingContext - Pointer to our adapter structure.
+ * @param Packet - Pointer to the packet
+ * @return == 0 -> We are done with the packet,
+ *  != 0 -> We will keep the packet and call NdisReturnPackets() this many times when done.
+ */
+static INT
+vboxNetFltWinPtReceivePacket(
+    IN NDIS_HANDLE            ProtocolBindingContext,
+    IN PNDIS_PACKET           pPacket
+    )
+{
+    PADAPT              pAdapt =(PADAPT)ProtocolBindingContext;
+    INT         cRefCount = 0;
+    PVBOXNETFLTINS pNetFltIf;
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+    PNDIS_BUFFER pBuffer;
+    PVOID pVA;
+    UINT cbLength;
+    uint32_t fFlags;
+
+    pNetFltIf = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt);
+
+    if(pNetFltIf)
+    {
+        NDIS_STATUS Status;
+        bool bResources;
+        do
+        {
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket))
+#else
+            if(vboxNetFltWinIsLoopedBackPacket(pPacket))
+#endif
+
+            {
+                Assert(0);
+                NdisReturnPackets(&pPacket, 1);
+                break;
+            }
+            bResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES;
+
+            NdisQueryPacket(pPacket, NULL, NULL, &pBuffer, NULL);
+            if(!pBuffer)
+            {
+                Assert(0);
+                NdisReturnPackets(&pPacket, 1);
+                cRefCount = 0;
+                break;
+            }
+
+            NdisQueryBufferSafe(pBuffer, &pVA, &cbLength, NormalPagePriority);
+            if(!pVA || !cbLength)
+            {
+                Assert(0);
+                NdisReturnPackets(&pPacket, 1);
+                cRefCount = 0;
+                break;
+            }
+
+            fFlags = MACS_EQUAL(((PRTNETETHERHDR)pVA)->SrcMac, pNetFltIf->u.s.Mac) ? PACKET_SRC_HOST : 0;
+
+            Status = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, bResources ? fFlags | PACKET_COPY : fFlags);
+            if(Status == NDIS_STATUS_SUCCESS)
+            {
+                if(bResources)
+                {
+                    cRefCount = 0;
+                    NdisReturnPackets(&pPacket, 1);
+                }
+                else
+                {
+                    cRefCount = 1;
+                }
+                pNetFltIf = NULL;
+                pAdapt = NULL;
+                break;
+            }
+            else
+            {
+                Assert(0);
+                NdisReturnPackets(&pPacket, 1);
+                cRefCount = 0;
+                break;
+            }
+        } while (0);
+
+        if(pNetFltIf)
+            vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+        if(pAdapt)
+            vboxNetFltWinDereferenceAdapt(pAdapt);
+        return cRefCount;
+    }
+    /* we are here because we are inactive, simply return the packet */
+    NdisReturnPackets(&pPacket, 1);
+    return 0;
+#else
+    bool fAdaptActive = vboxNetFltWinReferenceAdaptNetFltFromAdapt(pAdapt, &pNetFltIf);
+    if(fAdaptActive)
+    {
+        do
+        {
+#ifdef DEBUG_NETFLT_LOOPBACK
+# error "implement (see comments in the sources below this #error:)"
+        /* @todo FIXME no need for the PPACKET_INFO mechanism here;
+        instead the the NDIS_PACKET.ProtocolReserved + INTERLOCKED_SINGLE_LIST mechanism \
+        similar to that used in TrasferData handling should be used;
+        */
+
+//            if(vboxNetFltWinIsLoopedBackPacket(pAdapt, pPacket, true))
+#else
+            if(vboxNetFltWinIsLoopedBackPacket(pPacket))
+#endif
+
+            {
+                Assert(0);
+                Log(("lb_rp"));
+
+                /* nothing else to do here, just return the packet */
+                cRefCount = 0;
+                //NdisReturnPackets(&pPacket, 1);
+                break;
+            }
+
+            if(pNetFltIf)
+            {
+                bool bResources = NDIS_GET_PACKET_STATUS(pPacket) == NDIS_STATUS_RESOURCES;
+                NDIS_STATUS fStatus;
+
+                /*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(!bResources);
+
+                fStatus = vboxNetFltWinQuEnqueuePacket(pNetFltIf, pPacket, bResources ? PACKET_COPY : 0);
+                if(fStatus == NDIS_STATUS_SUCCESS)
+                {
+                    pNetFltIf = NULL;
+                    fAdaptActive = false;
+                    if(bResources)
+                    {
+                        cRefCount = 0;
+                        //NdisReturnPackets(&pPacket, 1);
+                    }
+                    else
+                    {
+                        cRefCount = 1;
+                    }
+                    break;
+                }
+                else
+                {
+                    Assert(0);
+                }
+            }
+
+            cRefCount = vboxNetFltWinRecvPacketPassThru(pAdapt, pPacket);
+            if(cRefCount)
+            {
+                Assert(cRefCount == 1);
+                fAdaptActive = false;
+            }
+
+        } while(FALSE);
+
+        if(pNetFltIf)
+            vboxNetFltWinDereferenceNetFlt(pNetFltIf);
+        if(fAdaptActive)
+            vboxNetFltWinDereferenceAdapt(pAdapt);
+    }
+    else
+    {
+        cRefCount = 0;
+        //NdisReturnPackets(&pPacket, 1);
+    }
+
+    return cRefCount;
+#endif
+}
+
+/**
+ * This routine is called from NDIS to notify our protocol edge of a
+ * reconfiguration of parameters for either a specific binding (pAdapt
+ * is not NULL), or global parameters if any (pAdapt is NULL).
+ *
+ * @param pAdapt - Pointer to our adapter structure.
+ * @param pNetPnPEvent - the reconfigure event
+ * @return NDIS_STATUS_SUCCESS */
+static NDIS_STATUS
+vboxNetFltWinPtPnPNetEventReconfigure(
+    IN PADAPT            pAdapt,
+    IN PNET_PNP_EVENT    pNetPnPEvent
+    )
+{
+    NDIS_STATUS    ReconfigStatus = NDIS_STATUS_SUCCESS;
+    NDIS_STATUS    ReturnStatus = NDIS_STATUS_SUCCESS;
+
+    do
+    {
+        /*
+         * Is this is a global reconfiguration notification ?
+         */
+        if (pAdapt == NULL)
+        {
+            /*
+             * An important event that causes this notification to us is if
+             * one of our upper-edge miniport instances was enabled after being
+             * disabled earlier, e.g. from Device Manager in Win2000. Note that
+             * NDIS calls this because we had set up an association between our
+             * miniport and protocol entities by calling NdisIMAssociateMiniport.
+             *
+             * Since we would have torn down the lower binding for that miniport,
+             * we need NDIS' assistance to re-bind to the lower miniport. The
+             * call to NdisReEnumerateProtocolBindings does exactly that.
+             */
+            NdisReEnumerateProtocolBindings (g_hProtHandle);
+            break;
+        }
+
+        ReconfigStatus = NDIS_STATUS_SUCCESS;
+
+    } while(FALSE);
+
+    LogFlow(("<==PtPNPNetEventReconfigure: pAdapt %p\n", pAdapt));
+
+    return ReconfigStatus;
+}
+
+static NDIS_STATUS
+vboxNetFltWinPtPnPNetEventBindsComplete(
+    IN PADAPT            pAdapt,
+    IN PNET_PNP_EVENT    pNetPnPEvent
+    )
+{
+    return NDIS_STATUS_SUCCESS;
+}
+
+DECLHIDDEN(bool) vboxNetFltWinPtCloseAdapter(PADAPT pAdapt, PNDIS_STATUS pStatus)
+{
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+    RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+
+    if(pAdapt->bClosingAdapter)
+    {
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        Assert(0);
+        return false;
+    }
+    if (pAdapt->hBindingHandle == NULL)
+    {
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        Assert(0);
+        return false;
+    }
+
+    pAdapt->bClosingAdapter = true;
+    RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+
+    /*
+     * Close the binding below. and wait for it to complete
+     */
+    NdisResetEvent(&pAdapt->hEvent);
+
+    NdisCloseAdapter(pStatus, pAdapt->hBindingHandle);
+
+    if (*pStatus == NDIS_STATUS_PENDING)
+    {
+        NdisWaitEvent(&pAdapt->hEvent, 0);
+        *pStatus = pAdapt->Status;
+    }
+
+    Assert (*pStatus == NDIS_STATUS_SUCCESS);
+
+    pAdapt->hBindingHandle = NULL;
+
+    return true;
+}
+
+/**
+ * This is a notification to our protocol edge of the power state
+ * of the lower miniport. If it is going to a low-power state, we must
+ * wait here for all outstanding sends and requests to complete.
+ *
+ * @param pAdapt            -    Pointer to the adpater structure
+ * @param pNetPnPEvent    -    The Net Pnp Event. this contains the new device state
+ * @return  NDIS_STATUS_SUCCESS or the status returned by upper-layer protocols.
+ * */
+static NDIS_STATUS
+vboxNetFltWinPtPnPNetEventSetPower(
+    IN PADAPT            pAdapt,
+    IN PNET_PNP_EVENT    pNetPnPEvent
+    )
+{
+    PNDIS_DEVICE_POWER_STATE       pDeviceState  =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer);
+    NDIS_DEVICE_POWER_STATE        PrevDeviceState = vboxNetFltWinGetPowerState(&pAdapt->PTState);
+    NDIS_STATUS                    ReturnStatus;
+    PVBOXNETFLTINS pNetFlt = PADAPT_2_PVBOXNETFLTINS(pAdapt);
+    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
+
+    ReturnStatus = NDIS_STATUS_SUCCESS;
+
+    /*
+     * Set the Internal Device State, this blocks all new sends or receives
+     */
+    RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+
+    vboxNetFltWinSetPowerState(&pAdapt->PTState, *pDeviceState);
+
+    /*
+     * Check if the miniport below is going to a low power state.
+     */
+    if (vboxNetFltWinGetPowerState(&pAdapt->PTState) > NdisDeviceStateD0)
+    {
+        /*
+         * If the miniport below is going to standby, fail all incoming requests
+         */
+        if (PrevDeviceState == NdisDeviceStateD0)
+        {
+            pAdapt->bStandingBy = TRUE;
+        }
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+
+        vboxNetFltWinPtFlushReceiveQueue(pAdapt, false);
+
+        vboxNetFltWinWaitDereference(&pAdapt->MPState);
+#endif
+
+        /*
+         * Wait for outstanding sends and requests to complete.
+         */
+        vboxNetFltWinWaitDereference(&pAdapt->PTState);
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        while (ASMAtomicUoReadBool((volatile bool *)&pAdapt->bOutstandingRequests))
+        {
+            /*
+             * sleep till outstanding requests complete
+             */
+            vboxNetFltWinSleep(2);
+        }
+
+        /*
+         * If the below miniport is going to low power state, complete the queued request
+         */
+        RTSpinlockAcquire(pNetFlt->hSpinlock, &Tmp);
+        if (pAdapt->bQueuedRequest)
+        {
+            pAdapt->bQueuedRequest = FALSE;
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+            vboxNetFltWinPtRequestComplete(pAdapt, &pAdapt->Request, NDIS_STATUS_FAILURE);
+        }
+        else
+        {
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        }
+#endif
+
+        Assert(NdisPacketPoolUsage(pAdapt->hSendPacketPoolHandle) == 0);
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+        Assert(NdisPacketPoolUsage(pAdapt->hRecvPacketPoolHandle) == 0);
+        Assert(pAdapt->bOutstandingRequests == FALSE);
+#endif
+    }
+    else
+    {
+        /*
+         * If the physical miniport is powering up (from Low power state to D0),
+         * clear the flag
+         */
+        if (PrevDeviceState > NdisDeviceStateD0)
+        {
+            pAdapt->bStandingBy = FALSE;
+        }
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+        RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+#else
+        /*
+         * The device below is being turned on. If we had a request
+         * pending, send it down now.
+         */
+        if (pAdapt->bQueuedRequest == TRUE)
+        {
+            NDIS_STATUS Status;
+
+            pAdapt->bQueuedRequest = FALSE;
+
+            pAdapt->bOutstandingRequests = TRUE;
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+
+            NdisRequest(&Status,
+                        pAdapt->hBindingHandle,
+                        &pAdapt->Request);
+
+            if (Status != NDIS_STATUS_PENDING)
+            {
+                vboxNetFltWinPtRequestComplete(pAdapt,
+                                  &pAdapt->Request,
+                                  Status);
+
+            }
+        }
+        else
+        {
+            RTSpinlockRelease(pNetFlt->hSpinlock, &Tmp);
+        }
+
+#endif /* #ifndef VBOX_NETFLT_ONDEMAND_BIND */
+
+    }
+
+    return ReturnStatus;
+}
+
+/**
+ * This is called by NDIS to notify us of a PNP event related to a lower
+ * binding. Based on the event, this dispatches to other helper routines.
+ *
+ * @param ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
+ *              for "global" notifications
+ * @param pNetPnPEvent - Pointer to the PNP event to be processed.
+ * @return NDIS_STATUS code indicating status of event processing.
+ * */
+static NDIS_STATUS
+vboxNetFltWinPtPnPHandler(
+    IN NDIS_HANDLE        ProtocolBindingContext,
+    IN PNET_PNP_EVENT     pNetPnPEvent
+    )
+{
+    PADAPT            pAdapt  =(PADAPT)ProtocolBindingContext;
+    NDIS_STATUS       Status  = NDIS_STATUS_SUCCESS;
+
+    LogFlow(("vboxNetFltWinPtPnPHandler: Adapt %p, Event %d\n", pAdapt, pNetPnPEvent->NetEvent));
+
+    switch (pNetPnPEvent->NetEvent)
+    {
+        case NetEventSetPower:
+            Status = vboxNetFltWinPtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
+            break;
+
+         case NetEventReconfigure:
+             DBGPRINT(("NetEventReconfigure, pAdapt(%p)", pAdapt));
+            Status = vboxNetFltWinPtPnPNetEventReconfigure(pAdapt, pNetPnPEvent);
+            break;
+         case NetEventBindsComplete:
+             DBGPRINT(("NetEventBindsComplete"));
+             Status = vboxNetFltWinPtPnPNetEventBindsComplete(pAdapt, pNetPnPEvent);
+            break;
+         default:
+            Status = NDIS_STATUS_SUCCESS;
+            break;
+    }
+
+    return Status;
+}
+#ifdef __cplusplus
+# define PTCHARS_40(_p) ((_p).Ndis40Chars)
+#else
+# define PTCHARS_40(_p) (_p)
+#endif
+
+/**
+ * register the protocol edge
+ */
+DECLHIDDEN(NDIS_STATUS)
+vboxNetFltWinPtRegister(
+    IN PDRIVER_OBJECT        DriverObject,
+    IN PUNICODE_STRING       RegistryPath
+    )
+{
+    NDIS_STATUS Status;
+    NDIS_PROTOCOL_CHARACTERISTICS      PChars;
+    NDIS_STRING                        Name;
+
+    /*
+     * Now register the protocol.
+     */
+    NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+    PTCHARS_40(PChars).MajorNdisVersion = VBOXNETFLT_PROT_MAJOR_NDIS_VERSION;
+    PTCHARS_40(PChars).MinorNdisVersion = VBOXNETFLT_PROT_MINOR_NDIS_VERSION;
+
+    /*
+     * Make sure the protocol-name matches the service-name
+     * (from the INF) under which this protocol is installed.
+     * This is needed to ensure that NDIS can correctly determine
+     * the binding and call us to bind to miniports below.
+     */
+    NdisInitUnicodeString(&Name, VBOXNETFLT_PROTOCOL_NAME);    /* Protocol name */
+    PTCHARS_40(PChars).Name = Name;
+    PTCHARS_40(PChars).OpenAdapterCompleteHandler = vboxNetFltWinPtOpenAdapterComplete;
+    PTCHARS_40(PChars).CloseAdapterCompleteHandler = vboxNetFltWinPtCloseAdapterComplete;
+    PTCHARS_40(PChars).SendCompleteHandler = vboxNetFltWinPtSendComplete;
+    PTCHARS_40(PChars).TransferDataCompleteHandler = vboxNetFltWinPtTransferDataComplete;
+
+    PTCHARS_40(PChars).ResetCompleteHandler = vboxNetFltWinPtResetComplete;
+    PTCHARS_40(PChars).RequestCompleteHandler = vboxNetFltWinPtRequestComplete;
+    PTCHARS_40(PChars).ReceiveHandler = vboxNetFltWinPtReceive;
+    PTCHARS_40(PChars).ReceiveCompleteHandler = vboxNetFltWinPtReceiveComplete;
+    PTCHARS_40(PChars).StatusHandler = vboxNetFltWinPtStatus;
+    PTCHARS_40(PChars).StatusCompleteHandler = vboxNetFltWinPtStatusComplete;
+    PTCHARS_40(PChars).BindAdapterHandler = vboxNetFltWinPtBindAdapter;
+    PTCHARS_40(PChars).UnbindAdapterHandler = vboxNetFltWinPtUnbindAdapter;
+    PTCHARS_40(PChars).UnloadHandler = vboxNetFltWinPtUnloadProtocol;
+#if !defined(VBOX_NETFLT_ONDEMAND_BIND) && !defined(DEBUG_NETFLT_RECV)
+    PTCHARS_40(PChars).ReceivePacketHandler = vboxNetFltWinPtReceivePacket;
+#else
+    PTCHARS_40(PChars).ReceivePacketHandler = NULL;
+#endif
+    PTCHARS_40(PChars).PnPEventHandler= vboxNetFltWinPtPnPHandler;
+
+    NdisRegisterProtocol(&Status,
+                         &g_hProtHandle,
+                         &PChars,
+                         sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+
+    return Status;
+}
+
+/**
+ * deregister the protocol edge
+ */
+DECLHIDDEN(NDIS_STATUS)
+vboxNetFltWinPtDeregister()
+{
+    NDIS_STATUS Status;
+
+    if (g_hProtHandle != NULL)
+    {
+        NdisDeregisterProtocol(&Status, g_hProtHandle);
+        g_hProtHandle = NULL;
+    }
+
+    return Status;
+}
+
+#ifndef VBOX_NETFLT_ONDEMAND_BIND
+/**
+ * returns the protocol handle
+ */
+DECLHIDDEN(NDIS_HANDLE) vboxNetFltWinPtGetHandle()
+{
+    return g_hProtHandle;
+}
+#endif
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltPt-win.h
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltPt-win.h	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFltPt-win.h	(revision 21333)
@@ -0,0 +1,37 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Windows Specific Code. Protocol edge of ndis filter driver
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ * Copyright (c) 1993-1999, Microsoft Corporation
+ */
+
+#ifndef ___VBoxNetFltPt_win_h___
+#define ___VBoxNetFltPt_win_h___
+
+#ifdef VBOXNETADP
+# error "No protocol edge"
+#endif
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtRegister(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDeregister();
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoUnbinding(PADAPT pAdapt, bool bOnUnbind);
+DECLHIDDEN(VOID) vboxNetFltWinPtFlushReceiveQueue(IN PADAPT pAdapt, IN bool bReturn);
+DECLHIDDEN(VOID) vboxNetFltWinPtRequestComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status);
+DECLHIDDEN(bool) vboxNetFltWinPtCloseAdapter(PADAPT pAdapt, PNDIS_STATUS pStatus);
+
+#ifdef VBOX_NETFLT_ONDEMAND_BIND
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(IN PADAPT pAdapt);
+#else
+DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(IN PADAPT pAdapt, IN PNDIS_STRING pOurDeviceName, IN PNDIS_STRING pBindToDeviceName);
+DECLHIDDEN(NDIS_HANDLE) vboxNetFltWinPtGetHandle();
+#endif
+
+#endif
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt_m.inf
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt_m.inf	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/VBoxNetFlt_m.inf	(revision 21333)
@@ -0,0 +1,85 @@
+;
+; VirtualBox Bridged Networking Driver
+;
+
+;
+; Copyright (C) 2008 Sun Microsystems, Inc.
+;
+; Sun Microsystems, Inc. confidential
+; All rights reserved
+;
+
+;
+; Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+; Copyright (c) 1993-1999, Microsoft Corporation
+;
+
+[Version]
+signature  = "$Windows NT$"
+;cat   CatalogFile = VBoxNetFlt.cat
+Class      = Net
+ClassGUID  = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider   = %Provider%
+;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]
+%Provider% = VBox,NTx86,NTia64,NTamd64
+
+; For Win2K
+[VBox]
+%VBoxNetFltMP_Desc% = VBoxNetFltMP.ndi, sun_VBoxNetFltmp
+
+; For XP and later
+[VBox.NTx86]
+%VBoxNetFltMP_Desc% = VBoxNetFltMP.ndi, sun_VBoxNetFltmp
+
+[VBox.NTia64]
+%VBoxNetFltMP_Desc% = VBoxNetFltMP.ndi, sun_VBoxNetFltmp
+
+[VBox.NTamd64]
+%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]
+; ----------------------------------------------------------------------
+; Add any miniport-specific parameters here.  These are params that your
+; filter device is going to use.
+;
+;HKR, Parameters, ParameterName,  0x10000, "MultiSz", "Parameter", "Value"
+;HKR, Parameters, ParameterName2, 0x10001, 4
+
+[Strings]
+Provider = "Sun Microsystems, Inc."
+VBoxNetFltMP_Desc = "VirtualBox Bridged Networking Driver Miniport"
+
+[SourceDisksNames]
+;None
+
+[SourceDisksFiles]
+;None
+
+
+
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/WinNetConfig.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/WinNetConfig.cpp	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/WinNetConfig.cpp	(revision 21333)
@@ -0,0 +1,3985 @@
+/* $Id$ */
+/** @file
+ * VBoxNetCfgWin - Briefly describe this file, optionally with a longer description in a separate paragraph.
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Ndis Intermediate Miniport passthru driver sample.
+ *+---------------------------------------------------------------------------
+ *
+ *  Microsoft Windows
+ *  Copyright (C) Microsoft Corporation, 2001.
+ *
+ *  Author:     Alok Sinha    15-May-01
+ *
+ *----------------------------------------------------------------------------
+ */
+#include "VBox/WinNetConfig.h"
+
+#define _WIN32_DCOM
+
+
+#include <iphlpapi.h>
+
+#include <devguid.h>
+#include <stdio.h>
+#include <regstr.h>
+//#define INITGUID
+//#include <guiddef.h>
+//#include <devguid.h>
+//#include <objbase.h>
+//#include <setupapi.h>
+#include <shlobj.h>
+#include <cfgmgr32.h>
+#include <tchar.h>
+//#include <VBox/com/Guid.h>
+//#include <VBox/com/String.h>
+//#include <wtypes.h>
+#include <objbase.h>
+
+#include <crtdbg.h>
+#include <stdlib.h>
+
+#include <Wbemidl.h>
+#include <comdef.h>
+
+//#include <Winsock2.h>
+
+//using namespace com;
+
+#ifndef Assert
+//# ifdef DEBUG
+//#  define Assert(_expr) assert(_expr)
+//# else
+//#  define Assert(_expr) do{ }while(0)
+//# endif
+# define Assert _ASSERT
+# define AssertMsg(expr, msg) do{}while(0)
+#endif
+static LOG_ROUTINE g_Logger = NULL;
+
+static VOID DoLogging(LPCWSTR szString, ...);
+#define Log DoLogging
+
+#define DbgLog
+
+#define VBOX_NETCFG_LOCK_TIME_OUT     5000
+
+typedef bool (*ENUMERATION_CALLBACK) (LPWSTR pFileName, PVOID pContext);
+
+static HRESULT vboxNetCfgWinCollectInfs(LPCWSTR pPnPId)
+{
+    DWORD winEr = ERROR_SUCCESS;
+    HDEVINFO hDevInfo = SetupDiCreateDeviceInfoList(
+                            &GUID_DEVCLASS_NETSERVICE, /* IN LPGUID  ClassGuid,  OPTIONAL */
+                            NULL /*IN HWND  hwndParent  OPTIONAL */
+                            );
+    if(hDevInfo != INVALID_HANDLE_VALUE)
+    {
+        if(SetupDiBuildDriverInfoList(hDevInfo,
+                    NULL, /*IN OUT PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL*/
+                    SPDIT_CLASSDRIVER  /*IN DWORD  DriverType*/
+                    ))
+        {
+            SP_DRVINFO_DATA DrvInfo;
+            DrvInfo.cbSize = sizeof(SP_DRVINFO_DATA);
+            char DetailBuf[16384];
+            PSP_DRVINFO_DETAIL_DATA pDrvDetail = (PSP_DRVINFO_DETAIL_DATA)DetailBuf;
+
+            for(DWORD i = 0;;i++)
+            {
+                if(SetupDiEnumDriverInfo(hDevInfo,
+                        NULL, /* IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL*/
+                        SPDIT_CLASSDRIVER , /*IN DWORD  DriverType,*/
+                        i, /*IN DWORD  MemberIndex,*/
+                        &DrvInfo /*OUT PSP_DRVINFO_DATA  DriverInfoData*/
+                        ))
+                {
+                    DWORD dwReq;
+                    pDrvDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+                    if(SetupDiGetDriverInfoDetail(
+                            hDevInfo, /*IN HDEVINFO  DeviceInfoSet,*/
+                            NULL, /*IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL*/
+                            &DrvInfo, /*IN PSP_DRVINFO_DATA  DriverInfoData,*/
+                            pDrvDetail, /*OUT PSP_DRVINFO_DETAIL_DATA  DriverInfoDetailData,  OPTIONAL*/
+                            sizeof(DetailBuf), /*IN DWORD  DriverInfoDetailDataSize,*/
+                            &dwReq /*OUT PDWORD  RequiredSize  OPTIONAL*/
+                            ))
+                    {
+                        for(WCHAR * pHwId = pDrvDetail->HardwareID; pHwId && *pHwId && pHwId < (TCHAR*)(DetailBuf + sizeof(DetailBuf)/sizeof(DetailBuf[0])) ;pHwId += _tcslen(pHwId) + 1)
+                        {
+                            //TODO:
+                        }
+                    }
+                    else
+                    {
+                        DWORD winEr = GetLastError();
+                        Log(L"Err SetupDiGetDriverInfoDetail (%d), req = %d", winEr, dwReq);
+//                        Assert(0);
+                    }
+
+                }
+                else
+                {
+                    DWORD winEr = GetLastError();
+                    if(winEr == ERROR_NO_MORE_ITEMS)
+                    {
+                        break;
+                    }
+
+                    Assert(0);
+                }
+            }
+
+            SetupDiDestroyDriverInfoList(hDevInfo,
+                      NULL, /*IN PSP_DEVINFO_DATA  DeviceInfoData,  OPTIONAL*/
+                      SPDIT_CLASSDRIVER/*IN DWORD  DriverType*/
+                      );
+        }
+        else
+        {
+            winEr = GetLastError();
+            Assert(0);
+        }
+
+        SetupDiDestroyDeviceInfoList(hDevInfo);
+    }
+    else
+    {
+        winEr = GetLastError();
+        Assert(0);
+    }
+
+    return HRESULT_FROM_WIN32(winEr);
+}
+
+//
+// Function:  GetKeyValue
+//
+// Purpose:   Retrieve the value of a key from the inf file.
+//
+// Arguments:
+//    hInf        [in]  Inf file handle.
+//    lpszSection [in]  Section name.
+//    lpszKey     [in]  Key name.
+//    dwIndex     [in]  Key index.
+//    lppszValue  [out] Key value.
+//
+// Returns:   S_OK on success, otherwise and error code.
+//
+// Notes:
+//
+
+static HRESULT vboxNetCfgWinGetKeyValue (HINF hInf,
+                     LPCWSTR lpszSection,
+                     LPCWSTR lpszKey,
+                     DWORD  dwIndex,
+                     LPWSTR *lppszValue)
+{
+    INFCONTEXT  infCtx;
+    DWORD       dwSizeNeeded;
+    HRESULT     hr;
+
+    *lppszValue = NULL;
+
+    if ( SetupFindFirstLineW(hInf,
+                             lpszSection,
+                             lpszKey,
+                             &infCtx) == FALSE )
+    {
+        DWORD winEr = GetLastError();
+        DbgLog(L"vboxNetCfgWinGetKeyValue: SetupFindFirstLineW failed, winEr = (%d)\n", winEr);
+        //Assert(0);
+        return HRESULT_FROM_WIN32(winEr);
+    }
+
+    SetupGetStringFieldW( &infCtx,
+                          dwIndex,
+                          NULL,
+                          0,
+                          &dwSizeNeeded );
+
+    *lppszValue = (LPWSTR)CoTaskMemAlloc( sizeof(WCHAR) * dwSizeNeeded );
+
+    if ( !*lppszValue  )
+    {
+        Log(L"vboxNetCfgWinGetKeyValue: CoTaskMemAlloc failed\n");
+        Assert(0);
+        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+    }
+
+    if ( SetupGetStringFieldW(&infCtx,
+                              dwIndex,
+                              *lppszValue,
+                              dwSizeNeeded,
+                              NULL) == FALSE )
+    {
+        DWORD winEr = GetLastError();
+        DbgLog(L"vboxNetCfgWinGetKeyValue: SetupGetStringFieldW failed, winEr = (%d)\n", winEr);
+        hr = HRESULT_FROM_WIN32(winEr);
+        //Assert(0);
+        CoTaskMemFree( *lppszValue );
+        *lppszValue = NULL;
+    }
+    else
+    {
+        hr = S_OK;
+    }
+
+    return hr;
+}
+
+//
+// Function:  GetPnpID
+//
+// Purpose:   Retrieve PnpID from an inf file.
+//
+// Arguments:
+//    lpszInfFile [in]  Inf file to search.
+//    lppszPnpID  [out] PnpID found.
+//
+// Returns:   TRUE on success.
+//
+// Notes:
+//
+
+static HRESULT vboxNetCfgWinGetPnpID (LPCWSTR lpszInfFile,
+                  LPWSTR *lppszPnpID)
+{
+    HINF    hInf;
+    LPWSTR  lpszModelSection;
+    HRESULT hr;
+
+    *lppszPnpID = NULL;
+
+    hInf = SetupOpenInfFileW( lpszInfFile,
+                              NULL,
+                              INF_STYLE_WIN4,
+                              NULL );
+
+    if ( hInf == INVALID_HANDLE_VALUE )
+    {
+        DWORD winEr = GetLastError();
+        DbgLog(L"vboxNetCfgWinGetPnpID: SetupOpenInfFileW failed, winEr = (%d), for file (%s)\n", winEr, lpszInfFile);
+        //Assert(0);
+        return HRESULT_FROM_WIN32(winEr);
+    }
+
+    //
+    // Read the Model section name from Manufacturer section.
+    //
+
+    hr = vboxNetCfgWinGetKeyValue( hInf,
+                      L"Manufacturer",
+                      NULL,
+                      1,
+                      &lpszModelSection );
+    //Assert(hr == S_OK);
+    if ( hr == S_OK )
+    {
+
+        //
+        // Read PnpID from the Model section.
+        //
+
+        hr = vboxNetCfgWinGetKeyValue( hInf,
+                          lpszModelSection,
+                          NULL,
+                          2,
+                          lppszPnpID );
+        //Assert(hr == S_OK);
+        if ( hr != S_OK )
+        {
+            DbgLog(L"vboxNetCfgWinGetPnpID: vboxNetCfgWinGetKeyValue lpszModelSection failed, hr = (0x%x), for file (%s)\n", hr, lpszInfFile);
+        }
+
+        CoTaskMemFree( lpszModelSection );
+    }
+    else
+    {
+        DbgLog(L"vboxNetCfgWinGetPnpID: vboxNetCfgWinGetKeyValue Manufacturer failed, hr = (0x%x), for file (%s)\n", hr, lpszInfFile);
+    }
+
+    SetupCloseInfFile( hInf );
+
+    return hr;
+}
+
+//VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUninstallInfs (LPCWSTR pPnPId)
+//{
+//    std::list<std::wstring> InfList;
+//    HRESULT hr = vboxNetCfgWinCollectInfs(pPnPId, &InfList);
+//    if(hr == S_OK)
+//    {
+//        std::list <std::wstring>::iterator it;
+//        for (it = InfList.begin(); it != InfList.end(); ++it)
+//        {
+//            Log(L"inf : %s\n", (*it).c_str());
+//        }
+//    }
+//    return hr;
+//}
+
+static HRESULT vboxNetCfgWinEnumFiles(LPCWSTR pPattern, ENUMERATION_CALLBACK pCallback, PVOID pContext)
+{
+    WIN32_FIND_DATA Data;
+    memset(&Data, 0, sizeof(Data));
+    HRESULT hr = S_OK;
+
+    HANDLE hEnum = FindFirstFile(pPattern,&Data);
+    if(hEnum != INVALID_HANDLE_VALUE)
+    {
+
+        do
+        {
+            if(!pCallback(Data.cFileName, pContext))
+            {
+                break;
+            }
+
+            /* next iteration */
+            memset(&Data, 0, sizeof(Data));
+            BOOL bNext = FindNextFile(hEnum,&Data);
+            if(!bNext)
+            {
+                int winEr = GetLastError();
+                if(winEr != ERROR_NO_MORE_FILES)
+                {
+                    Log(L"vboxNetCfgWinEnumFiles: FindNextFile err winEr (%d)\n", winEr);
+                    Assert(0);
+                    hr = HRESULT_FROM_WIN32(winEr);
+                }
+                break;
+            }
+        }while(true);
+        FindClose(hEnum);
+    }
+    else
+    {
+        int winEr = GetLastError();
+        if(winEr != ERROR_NO_MORE_FILES)
+        {
+            Log(L"vboxNetCfgWinEnumFiles: FindFirstFile err winEr (%d)\n", winEr);
+            Assert(0);
+            hr = HRESULT_FROM_WIN32(winEr);
+        }
+    }
+
+    return hr;
+}
+
+typedef struct _INF_INFO
+{
+    LPCWSTR pPnPId;
+}INF_INFO, *PINF_INFO;
+
+typedef struct _INFENUM_CONTEXT
+{
+    INF_INFO InfInfo;
+    DWORD Flags;
+    HRESULT hr;
+} INFENUM_CONTEXT, *PINFENUM_CONTEXT;
+
+static bool vboxNetCfgWinInfEnumerationCallback(LPCWSTR pFileName, PINFENUM_CONTEXT pContext)
+{
+//    Log(L"vboxNetCfgWinInfEnumerationCallback: pFileName (%s)\n", pFileName);
+
+    LPWSTR lpszPnpID;
+    HRESULT hr = vboxNetCfgWinGetPnpID (pFileName,
+                      &lpszPnpID);
+//    Assert(hr == S_OK);
+    if(hr == S_OK)
+    {
+        if(!wcsicmp(pContext->InfInfo.pPnPId, lpszPnpID))
+        {
+            if(!SetupUninstallOEMInfW(pFileName,
+                        pContext->Flags, /*DWORD Flags could be SUOI_FORCEDELETE */
+                        NULL /*__in  PVOID Reserved == NULL */
+                        ))
+            {
+                DWORD dwError = GetLastError();
+
+                Log(L"vboxNetCfgWinInfEnumerationCallback: SetupUninstallOEMInf failed for file (%s), r (%d)\n", pFileName, dwError);
+                Assert(0);
+                hr = HRESULT_FROM_WIN32( dwError );
+            }
+        }
+        CoTaskMemFree(lpszPnpID);
+    }
+    else
+    {
+        DbgLog(L"vboxNetCfgWinInfEnumerationCallback: vboxNetCfgWinGetPnpID failed, hr = (0x%x)\n", hr);
+    }
+
+    return true;
+}
+
+
+static HRESULT VBoxNetCfgWinUninstallInfs(LPCWSTR pPnPId, DWORD Flags)
+{
+    WCHAR InfDirPath[MAX_PATH];
+    HRESULT hr = SHGetFolderPathW(NULL, /*          HWND hwndOwner*/
+            CSIDL_WINDOWS, /* int nFolder*/
+            NULL, /*HANDLE hToken*/
+            SHGFP_TYPE_CURRENT, /*DWORD dwFlags*/
+            InfDirPath);
+    Assert(hr == S_OK);
+    if(hr ==  S_OK)
+    {
+        wcscat(InfDirPath, L"\\inf\\oem*.inf");
+
+        INFENUM_CONTEXT Context;
+        Context.InfInfo.pPnPId = pPnPId;
+        Context.Flags = Flags;
+        Context.hr = S_OK;
+        hr = vboxNetCfgWinEnumFiles(InfDirPath, (ENUMERATION_CALLBACK)vboxNetCfgWinInfEnumerationCallback, (PVOID)&Context);
+        Assert(hr == S_OK);
+        if(hr == S_OK)
+        {
+            hr = Context.hr;
+        }
+        else
+        {
+            Log(L"VBoxNetCfgWinUninstallInfs: vboxNetCfgWinEnumFiles failed, hr = (0x%x)\n", hr);
+        }
+//
+//        HANDLE hInfDir = CreateFileW(InfDirPath,
+//                FILE_READ_DATA, /*      DWORD dwDesiredAccess*/
+//                FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, /*      DWORD dwShareMode */
+//                NULL, /* LPSECURITY_ATTRIBUTES lpSecurityAttributes */
+//                OPEN_EXISTING, /* DWORD dwCreationDisposition */
+//                0, /* DWORD dwFlagsAndAttributes */
+//                NULL);
+//        if(hInfDir != INVALID_HANDLE_VALUE)
+//        {
+//
+//            CloseHandle(hInfDir);
+//        }
+//        else
+//        {
+//            int winEr = GetLastError();
+//            hr = HRESULT_FROM_WIN32(winEr);
+//        }
+    }
+    else
+    {
+        Log(L"VBoxNetCfgWinUninstallInfs: SHGetFolderPathW failed, hr = (0x%x)\n", hr);
+    }
+
+    return hr;
+
+}
+
+
+
+/**
+ * Release reference
+ *
+ * @param   punk    Pointer to the interface to release reference to.
+ */
+VBOXNETCFGWIN_DECL(VOID)
+VBoxNetCfgWinReleaseRef(IN IUnknown* punk)
+{
+    if(punk)
+    {
+        punk->Release();
+    }
+
+    return;
+}
+
+/**
+ * Get a reference to INetCfg.
+ *
+ * @return HRESULT       S_OK on success, otherwise an error code
+ * @param fGetWriteLock  If TRUE, Write lock requested
+ * @param lpszAppName    Application name requesting the reference.
+ * @param ppnc           pointer the Reference to INetCfg to be stored to
+ * @param lpszLockedBy   pointer the Application name who holds the write lock to be stored to, optional
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinQueryINetCfgEx(IN BOOL fGetWriteLock,
+                          IN LPCWSTR lpszAppName,
+                          IN DWORD cmsTimeout,
+                          OUT INetCfg **ppnc,
+                          OUT LPWSTR *lpszLockedBy)
+{
+    INetCfg      *pnc = NULL;
+    INetCfgLock  *pncLock = NULL;
+    HRESULT      hr = S_OK;
+
+    /*
+    * Initialize the output parameters.
+    */
+    *ppnc = NULL;
+
+    if ( lpszLockedBy )
+    {
+        *lpszLockedBy = NULL;
+    }
+//    COM should be initialized before using the NetConfig API
+//    /*
+//    * Initialize COM
+//    */
+//    hr = CoInitialize( NULL );
+
+    if ( hr == S_OK )
+    {
+
+        /*
+        * Create the object implementing INetCfg.
+        */
+        hr = CoCreateInstance( CLSID_CNetCfg,
+                               NULL, CLSCTX_INPROC_SERVER,
+                               IID_INetCfg,
+                               (void**)&pnc );
+        Assert(hr == S_OK);
+        if ( hr == S_OK )
+        {
+
+            if ( fGetWriteLock )
+            {
+
+                /*
+                * Get the locking reference
+                */
+                hr = pnc->QueryInterface( IID_INetCfgLock,
+                                          (LPVOID *)&pncLock );
+                Assert(hr == S_OK);
+                if ( hr == S_OK )
+                {
+
+                    /*
+                    * Attempt to lock the INetCfg for read/write
+                    */
+                    hr = pncLock->AcquireWriteLock( cmsTimeout,
+                                                    lpszAppName,
+                                                    lpszLockedBy);
+                    if (hr == S_FALSE )
+                    {
+                        Log(L"VBoxNetCfgWinQueryINetCfg: WriteLock busy\n");
+                        hr = NETCFG_E_NO_WRITE_LOCK;
+                    }
+                    else if (hr != S_OK)
+                    {
+                        Log(L"VBoxNetCfgWinQueryINetCfg: AcquireWriteLock failed, hr (0x%x)\n", hr);
+                    }
+                }
+                else
+                {
+                    Log(L"VBoxNetCfgWinQueryINetCfg: QueryInterface for IID_INetCfgLock failed, hr (0x%x)\n", hr);
+                }
+            }
+
+            if ( hr == S_OK )
+            {
+
+                /*
+                * Initialize the INetCfg object.
+                */
+                hr = pnc->Initialize( NULL );
+                Assert(hr == S_OK);
+                if ( hr == S_OK )
+                {
+                    *ppnc = pnc;
+                    pnc->AddRef();
+                }
+                else
+                {
+                    Log(L"VBoxNetCfgWinQueryINetCfg: Initialize failed, hr (0x%x)\n", hr);
+
+                    /*
+                    * Initialize failed, if obtained lock, release it
+                    */
+                    if ( pncLock )
+                    {
+                        pncLock->ReleaseWriteLock();
+                    }
+                }
+            }
+
+            VBoxNetCfgWinReleaseRef( pncLock );
+            VBoxNetCfgWinReleaseRef( pnc );
+        }
+        else
+        {
+            Log(L"VBoxNetCfgWinQueryINetCfg: CoCreateInstance for CLSID_CNetCfg failed, hr (0x%x)\n", hr);
+        }
+
+//    COM should be initialized before using the NetConfig API
+//        /*
+//        * In case of error, uninitialize COM.
+//        */
+//        if ( hr != S_OK )
+//        {
+//            CoUninitialize();
+//        }
+    }
+
+    return hr;
+}
+
+/**
+ * Get a reference to INetCfg.
+ *
+ * @return HRESULT       S_OK on success, otherwise an error code
+ * @param fGetWriteLock  If TRUE, Write lock requested
+ * @param lpszAppName    Application name requesting the reference.
+ * @param ppnc           pointer the Reference to INetCfg to be stored to
+ * @param lpszLockedBy   pointer the Application name who holds the write lock to be stored to, optional
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinQueryINetCfg(IN BOOL fGetWriteLock,
+                          IN LPCWSTR lpszAppName,
+                          OUT INetCfg **ppnc,
+                          OUT LPWSTR *lpszLockedBy)
+{
+    return VBoxNetCfgWinQueryINetCfgEx(fGetWriteLock,
+            lpszAppName,
+            VBOX_NETCFG_LOCK_TIME_OUT,
+            ppnc,
+            lpszLockedBy);
+}
+/**
+ * Release a reference to INetCfg.
+ *
+ * @param pnc           Reference to INetCfg to release.
+ * @param fHasWriteLock If TRUE, reference was held with write lock.
+ * @return              S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pnc,
+                            IN BOOL fHasWriteLock)
+{
+    INetCfgLock    *pncLock = NULL;
+    HRESULT        hr = S_OK;
+
+    /*
+    * Uninitialize INetCfg
+    */
+    hr = pnc->Uninitialize();
+    Assert(hr == S_OK);
+    /*
+    * If write lock is present, unlock it
+    */
+    if ( hr == S_OK && fHasWriteLock )
+    {
+
+        /*
+        * Get the locking reference
+        */
+        hr = pnc->QueryInterface( IID_INetCfgLock,
+                                 (LPVOID *)&pncLock);
+        Assert(hr == S_OK);
+        if ( hr == S_OK )
+        {
+            hr = pncLock->ReleaseWriteLock();
+            VBoxNetCfgWinReleaseRef( pncLock );
+        }
+    }
+    else if(hr != S_OK)
+    {
+        Log(L"VBoxNetCfgWinReleaseINetCfg: Uninitialize failed, hr (0x%x)\n", hr);
+    }
+
+    VBoxNetCfgWinReleaseRef( pnc );
+
+//    COM should be initialized before using the NetConfig API
+//    /*
+//    * Uninitialize COM.
+//    */
+//    CoUninitialize();
+
+    return hr;
+}
+
+/**
+ * Get network component enumerator reference.
+ *
+ * @param pnc        Reference to INetCfg.
+ * @param pguidClass Class GUID of the network component.
+ * @param ppencc     address the Enumerator reference to be stored to.
+ * @return           S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetComponentEnum(INetCfg *pnc,
+                              IN const GUID *pguidClass,
+                              OUT IEnumNetCfgComponent **ppencc)
+{
+    INetCfgClass  *pncclass;
+    HRESULT       hr;
+
+    *ppencc = NULL;
+
+    /*
+    * Get the class reference.
+    */
+    hr = pnc->QueryNetCfgClass( pguidClass,
+                                IID_INetCfgClass,
+                                (PVOID *)&pncclass );
+    Assert(hr == S_OK);
+    if ( hr == S_OK )
+    {
+
+        /*
+        * Get the enumerator reference.
+        */
+        hr = pncclass->EnumComponents( ppencc );
+
+        /*
+        * We don't need the class reference any more.
+        */
+        VBoxNetCfgWinReleaseRef( pncclass );
+    }
+    else
+    {
+        Log(L"VBoxNetCfgWinGetComponentEnum: QueryNetCfgClass for IID_INetCfgClass failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+/**
+ * Enumerates the first network component.
+ *
+ * @param pencc Component enumerator reference.
+ * @param ppncc address the Network component reference to be stored to
+ * @return S_OK on success, otherwise an error code.
+ */
+/**
+ * Enumerate the next network component.
+ * The function behaves just like VBoxNetCfgWinGetFirstComponent if
+ * it is called right after VBoxNetCfgWinGetComponentEnum.
+ *
+ * @param pencc Component enumerator reference.
+ * @param ppncc address the Network component reference to be stored to.
+ * @return S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetNextComponent(IN IEnumNetCfgComponent *pencc,
+                              OUT INetCfgComponent **ppncc)
+{
+    HRESULT  hr;
+    ULONG    ulCount;
+
+    *ppncc = NULL;
+
+    hr = pencc->Next( 1,
+                     ppncc,
+                     &ulCount );
+    Assert(hr == S_OK || hr == S_FALSE);
+    if(hr != S_OK && hr != S_FALSE)
+    {
+        Log(L"VBoxNetCfgWinGetNextComponent: Next failed, hr (0x%x)\n", hr);
+    }
+    return hr;
+}
+
+/**
+ * Install a network component(protocols, clients and services)
+ *            given its INF file.
+ * @param pnc Reference to INetCfg.
+ * @param lpszComponentId PnpID of the network component.
+ * @param pguidClass Class GUID of the network component.
+ * @return S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinInstallComponent(IN INetCfg *pnc,
+                              IN LPCWSTR szComponentId,
+                              IN const GUID *pguidClass)
+{
+    INetCfgClassSetup   *pncClassSetup = NULL;
+    INetCfgComponent    *pncc = NULL;
+    OBO_TOKEN           OboToken;
+    HRESULT             hr = S_OK;
+
+    /*
+    * OBO_TOKEN specifies on whose behalf this
+    * component is being installed.
+    * Set it to OBO_USER so that szComponentId will be installed
+    * on behalf of the user.
+    */
+
+    ZeroMemory( &OboToken,
+                sizeof(OboToken) );
+    OboToken.Type = OBO_USER;
+
+    /*
+    * Get component's setup class reference.
+    */
+    hr = pnc->QueryNetCfgClass ( pguidClass,
+                                 IID_INetCfgClassSetup,
+                                 (void**)&pncClassSetup );
+    Assert(hr == S_OK);
+    if ( hr == S_OK )
+    {
+
+        hr = pncClassSetup->Install( szComponentId,
+                                     &OboToken,
+                                     0,
+                                     0,       /* Upgrade from build number. */
+                                     NULL,    /* Answerfile name */
+                                     NULL,    /* Answerfile section name */
+                                     &pncc ); /* Reference after the component */
+                                              /* is installed. */
+        Assert(hr == S_OK);
+        if ( S_OK == hr )
+        {
+
+            /*
+            * we don't need to use pncc (INetCfgComponent), release it
+            */
+            VBoxNetCfgWinReleaseRef( pncc );
+        }
+        else
+        {
+            Log(L"VBoxNetCfgWinInstallComponent: Install failed, hr (0x%x)\n", hr);
+        }
+
+        VBoxNetCfgWinReleaseRef( pncClassSetup );
+    }
+    else
+    {
+        Log(L"VBoxNetCfgWinInstallComponent: QueryNetCfgClass for IID_INetCfgClassSetup failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetCfgWinRemoveInf(IN LPCWSTR pInfFullPath, DWORD Flags)
+{
+    DWORD     dwError;
+    HRESULT   hr = S_OK;
+    WCHAR     Drive[_MAX_DRIVE];
+    WCHAR     Dir[_MAX_DIR];
+    WCHAR     DirWithDrive[_MAX_DRIVE+_MAX_DIR];
+    WCHAR     OemInfFullPath[MAX_PATH];
+    PWCHAR    pOemInfName;
+
+    /*
+    * Get the path where the INF file is.
+    */
+    _wsplitpath( pInfFullPath, Drive, Dir, NULL, NULL );
+
+    wcscpy( DirWithDrive, Drive );
+    wcscat( DirWithDrive, Dir );
+
+    /*
+     * get the oem file name.
+     */
+    if (SetupCopyOEMInfW( pInfFullPath,
+                                DirWithDrive,  /* Other files are in the */
+                                                /* same dir. as primary INF */
+                                SPOST_PATH,    /* First param is path to INF */
+                                SP_COPY_REPLACEONLY, /* we want to get the inf file name */
+                                OemInfFullPath,          /* Name of the INF after */
+                                                /* it's copied to %windir%\inf */
+                                sizeof(OemInfFullPath) / sizeof(OemInfFullPath[0]),             /* Max buf. size for the above */
+                                NULL,          /* Required size if non-null */
+                                &pOemInfName ) )       /* Optionally get the filename */
+    {
+        Log(L"vboxNetCfgWinRemoveInf: found inf file (%s) for (%s)\n", OemInfFullPath, pInfFullPath);
+
+        if(!SetupUninstallOEMInfW(pOemInfName,
+                    Flags, /*DWORD Flags could be SUOI_FORCEDELETE */
+                    NULL /*__in  PVOID Reserved == NULL */
+                    ))
+        {
+                dwError = GetLastError();
+
+                Log(L"vboxNetCfgWinRemoveInf: SetupUninstallOEMInf failed for file (%s), r (%d)\n", pInfFullPath, dwError);
+                Log(L"vboxNetCfgWinRemoveInf: DirWithDrive (%s)\n", DirWithDrive);
+
+                Assert(0);
+                hr = HRESULT_FROM_WIN32( dwError );
+        }
+    }
+    else
+    {
+        dwError = GetLastError();
+
+        Log(L"vboxNetCfgWinRemoveInf: SetupCopyOEMInfW failed for file (%s), r (%d)\n", pInfFullPath, dwError);
+        Log(L"vboxNetCfgWinRemoveInf: DirWithDrive (%s)\n", DirWithDrive);
+
+
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+    return hr;
+}
+
+static HRESULT vboxNetCfgWinCopyInf(IN LPCWSTR pInfFullPath)
+{
+    DWORD     dwError;
+    HRESULT   hr = S_OK;
+    WCHAR     Drive[_MAX_DRIVE];
+    WCHAR     Dir[_MAX_DIR];
+    WCHAR     DirWithDrive[_MAX_DRIVE+_MAX_DIR];
+    WCHAR     DirDestInf[_MAX_PATH] = { 0 };
+
+    /*
+    * Get the path where the INF file is.
+    */
+    _wsplitpath( pInfFullPath, Drive, Dir, NULL, NULL );
+
+    wcscpy( DirWithDrive, Drive );
+    wcscat( DirWithDrive, Dir );
+
+    /*
+    * Copy the INF file and other files referenced in the INF file.
+    */
+    if ( !SetupCopyOEMInfW( pInfFullPath,
+                            DirWithDrive,  /* Other files are in the */
+                                            /* same dir. as primary INF */
+                            SPOST_PATH,    /* First param is path to INF */
+                            0,             /* Default copy style */
+                            DirDestInf,    /* Name of the INF after */
+                                           /* it's copied to %windir%\inf */
+                            sizeof(DirDestInf), /* Max buf. size for the above */
+                            NULL,          /* Required size if non-null */
+                            NULL ) )       /* Optionally get the filename */
+    {
+        dwError = GetLastError();
+
+        Log(L"vboxNetCfgWinCopyInf: SetupCopyOEMInfW failed for file (%s), r (%d)\n", pInfFullPath, dwError);
+        Log(L"vboxNetCfgWinCopyInf: DirWithDrive (%s), DirDestInf(%s)\n", DirWithDrive, DirDestInf);
+
+        Assert(0);
+
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+
+    return hr;
+}
+
+/**
+ * Install a network component(protocols, clients and services)
+ *            given its INF file.
+ *
+ * @param pnc Reference to INetCfg.
+ * @param lpszComponentId PnpID of the network component.
+ * @param pguidClass Class GUID of the network component.
+ * @param lpszInfFullPath INF file to install from.
+ * @return S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinInstallNetComponent(IN INetCfg *pnc,
+                                 IN LPCWSTR lpszComponentId,
+                                 IN const GUID *pguidClass,
+                                 IN LPCWSTR * apInfFullPaths,
+                                 IN UINT cInfFullPaths)
+{
+    HRESULT   hr = S_OK;
+
+    /*
+    * If full path to INF has been specified, the INF
+    * needs to be copied using Setup API to ensure that any other files
+    * that the primary INF copies will be correctly found by Setup API
+    */
+    for(UINT i = 0; i < cInfFullPaths; i++)
+    {
+        hr = vboxNetCfgWinCopyInf(apInfFullPaths[i]);
+        Assert(hr == S_OK);
+        if(hr != S_OK)
+        {
+            Log(L"VBoxNetCfgWinInstallNetComponent: vboxNetCfgWinCopyInf failed, hr (0x%x)\n", hr);
+            if(i != 0)
+            {
+                /* remove infs already installed */
+                for(UINT j = i-1; j != 0; j--)
+                {
+                    vboxNetCfgWinRemoveInf(apInfFullPaths[j], 0);
+                }
+            }
+
+            break;
+        }
+    }
+
+    if (S_OK == hr)
+    {
+        /*
+        * Install the network component.
+        */
+        hr = VBoxNetCfgWinInstallComponent( pnc,
+                                            lpszComponentId,
+                                            pguidClass );
+        Assert(hr == S_OK);
+        if ( hr == S_OK )
+        {
+            /*
+            * On success, apply the changes
+            */
+            HRESULT tmpHr = pnc->Apply();
+            Assert(tmpHr == S_OK);
+            if(tmpHr != S_OK)
+            {
+                Log(L"VBoxNetCfgWinInstallNetComponent: Apply failed, hr (0x%x)\n", tmpHr);
+            }
+        }
+        else
+        {
+            Log(L"VBoxNetCfgWinInstallNetComponent: VBoxNetCfgWinInstallComponent failed, hr (0x%x)\n", hr);
+        }
+    }
+
+    return hr;
+}
+
+/**
+ * Uninstall a network component.
+ *
+ * @param pnc Reference to INetCfg.
+ * @param lpszInfId PnpID of the network component to uninstall
+ * @param apInfFiles array of null-terminated strings containing the inf file names describing drivers to be removed from the system
+ * @param cInfFiles the size of apInfFiles array
+ * @return S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinUninstallComponent(IN INetCfg *pnc,
+                                IN INetCfgComponent *pncc)
+{
+    INetCfgClass         *pncClass;
+    INetCfgClassSetup    *pncClassSetup;
+    GUID                 guidClass;
+    OBO_TOKEN            obo;
+    HRESULT              hr;
+
+        /*
+         * Get the class GUID.
+         */
+        hr = pncc->GetClassGuid( &guidClass );
+        Assert(hr == S_OK);
+        if ( hr == S_OK )
+        {
+
+            /*
+            * Get a reference to component's class.
+            */
+            hr = pnc->QueryNetCfgClass( &guidClass,
+                                        IID_INetCfgClass,
+                                        (PVOID *)&pncClass );
+            Assert(hr == S_OK);
+            if ( hr == S_OK )
+            {
+
+                /*
+                * Get the setup interface.
+                */
+                hr = pncClass->QueryInterface( IID_INetCfgClassSetup,
+                                               (LPVOID *)&pncClassSetup );
+                Assert(hr == S_OK);
+                if ( hr == S_OK )
+                {
+
+                    /*
+                    * Uninstall the component.
+                    */
+                    ZeroMemory( &obo,
+                                sizeof(OBO_TOKEN) );
+
+                    obo.Type = OBO_USER;
+
+                    hr = pncClassSetup->DeInstall( pncc,
+                                                   &obo,
+                                                   NULL );
+                    Assert(hr == S_OK);
+                    if ( (hr == S_OK) || (hr == NETCFG_S_REBOOT) )
+                    {
+                        HRESULT tmpHr = pnc->Apply();
+                        /* we ignore apply failures since they might occur on misconfigured systems*/
+                        Assert(tmpHr == S_OK);
+                        if ( (tmpHr != S_OK) )
+                        {
+                            Log(L"VBoxNetCfgWinUninstallComponent: Apply failed, hr (0x%x), ignoring\n", tmpHr);
+                        }
+                    }
+                    else
+                    {
+                        Log(L"VBoxNetCfgWinUninstallComponent: DeInstall failed, hr (0x%x)\n", hr);
+                    }
+
+                    VBoxNetCfgWinReleaseRef( pncClassSetup );
+                }
+                else
+                {
+                    Log(L"VBoxNetCfgWinUninstallComponent: QueryInterface for IID_INetCfgClassSetup failed, hr (0x%x)\n", hr);
+                }
+
+                VBoxNetCfgWinReleaseRef( pncClass );
+            }
+            else
+            {
+                Log(L"VBoxNetCfgWinUninstallComponent: QueryNetCfgClass failed, hr (0x%x)\n", hr);
+            }
+        }
+        else
+        {
+            Log(L"VBoxNetCfgWinUninstallComponent: GetClassGuid failed, hr (0x%x)\n", hr);
+        }
+
+    return hr;
+}
+
+#define VBOXNETCFGWIN_NETFLT_ID    L"sun_VBoxNetFlt"
+#define VBOXNETCFGWIN_NETFLT_MP_ID L"sun_VBoxNetFltmp"
+
+static HRESULT vboxNetCfgWinNetFltUninstall(IN INetCfg *pNc, DWORD InfRmFlags)
+{
+    INetCfgComponent * pNcc = NULL;
+    HRESULT hr = pNc->FindComponent(VBOXNETCFGWIN_NETFLT_ID, &pNcc);
+    if(hr == S_OK)
+    {
+        Log(L"NetFlt Is Installed currently\n");
+
+        hr = VBoxNetCfgWinUninstallComponent(pNc, pNcc);
+
+        VBoxNetCfgWinReleaseRef(pNcc);
+    }
+    else if(hr == S_FALSE)
+    {
+        Log(L"NetFlt Is Not Installed currently\n");
+        hr = S_OK;
+    }
+    else
+    {
+        Log(L"vboxNetCfgWinNetFltUninstall: FindComponent for NetFlt failed, hr (0x%x)\n", hr);
+        hr = S_OK;
+    }
+
+    VBoxNetCfgWinUninstallInfs(VBOXNETCFGWIN_NETFLT_ID, InfRmFlags);
+    VBoxNetCfgWinUninstallInfs(VBOXNETCFGWIN_NETFLT_MP_ID, InfRmFlags);
+
+    return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc)
+{
+    return vboxNetCfgWinNetFltUninstall(pNc, 0);
+}
+
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc, IN LPCWSTR * apInfFullPaths, IN UINT cInfFullPaths)
+{
+    HRESULT hr = vboxNetCfgWinNetFltUninstall(pNc, SUOI_FORCEDELETE);
+
+    hr = VBoxNetCfgWinInstallNetComponent(pNc, VBOXNETCFGWIN_NETFLT_ID,
+                                     &GUID_DEVCLASS_NETSERVICE,
+                                     apInfFullPaths,
+                                     cInfFullPaths);
+
+    return hr;
+}
+
+
+/**
+ * Get network component's binding path enumerator reference.
+ *
+ * @param pncc Network component reference.
+ * @param dwBindingType EBP_ABOVE or EBP_BELOW.
+ * @param ppencbp address the Enumerator reference to be stored to
+ * @return S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetBindingPathEnum(IN INetCfgComponent *pncc,
+                                IN DWORD dwBindingType,
+                                OUT IEnumNetCfgBindingPath **ppencbp)
+{
+    INetCfgComponentBindings *pnccb = NULL;
+    HRESULT                  hr;
+
+    *ppencbp = NULL;
+
+    /* Get component's binding. */
+    hr = pncc->QueryInterface( IID_INetCfgComponentBindings,
+                               (PVOID *)&pnccb );
+    Assert(hr == S_OK);
+    if ( hr == S_OK )
+    {
+
+        /* Get binding path enumerator reference. */
+        hr = pnccb->EnumBindingPaths( dwBindingType,
+                                      ppencbp );
+        if(hr != S_OK)
+        {
+            Log(L"VBoxNetCfgWinGetBindingPathEnum: EnumBindingPaths failed, hr (0x%x)\n", hr);
+        }
+
+        VBoxNetCfgWinReleaseRef( pnccb );
+    }
+    else
+    {
+        Log(L"VBoxNetCfgWinGetBindingPathEnum: QueryInterface for IID_INetCfgComponentBindings failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+/**
+ * Enumerates the first binding path.
+ *
+ * @param pencc Binding path enumerator reference.
+ * @param ppncc address the Binding path reference to be stored to
+ * @return S_OK on success, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetFirstComponent(IN IEnumNetCfgComponent *pencc,
+                               OUT INetCfgComponent **ppncc)
+{
+    HRESULT  hr;
+    ULONG    ulCount;
+
+    *ppncc = NULL;
+
+    pencc->Reset();
+
+    hr = pencc->Next( 1,
+                      ppncc,
+                      &ulCount );
+    Assert(hr == S_OK || hr == S_FALSE);
+    if(hr != S_OK && hr != S_FALSE)
+    {
+        Log(L"VBoxNetCfgWinGetFirstComponent: Next failed, hr (0x%x)\n", hr);
+    }
+    return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetFirstBindingPath(IN IEnumNetCfgBindingPath *pencbp,
+                                 OUT INetCfgBindingPath **ppncbp)
+{
+    ULONG   ulCount;
+    HRESULT hr;
+
+    *ppncbp = NULL;
+
+    pencbp->Reset();
+
+    hr = pencbp->Next( 1,
+                       ppncbp,
+                       &ulCount );
+    Assert(hr == S_OK || hr == S_FALSE);
+    if(hr != S_OK && hr != S_FALSE)
+    {
+        Log(L"VBoxNetCfgWinGetFirstBindingPath: Next failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+/**
+ * Get binding interface enumerator reference.
+ *
+ * @param pncbp Binding path reference.
+ * @param ppencbp address the Enumerator reference to be stored to
+ * @return S_OK on success, otherwise an error code
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetBindingInterfaceEnum(IN INetCfgBindingPath *pncbp,
+                                     OUT IEnumNetCfgBindingInterface **ppencbi)
+{
+    HRESULT hr;
+
+    *ppencbi = NULL;
+
+    hr = pncbp->EnumBindingInterfaces( ppencbi );
+    Assert(hr == S_OK);
+    if(hr != S_OK)
+    {
+        Log(L"VBoxNetCfgWinGetBindingInterfaceEnum: EnumBindingInterfaces failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+/**
+ * Enumerates the first binding interface.
+ *
+ * @param pencbi Binding interface enumerator reference.
+ * @param ppncbi address the Binding interface reference to be stored to
+ * @return S_OK on success, otherwise an error code
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetFirstBindingInterface(IN IEnumNetCfgBindingInterface *pencbi,
+                                      OUT INetCfgBindingInterface **ppncbi)
+{
+    ULONG   ulCount;
+    HRESULT hr;
+
+    *ppncbi = NULL;
+
+    pencbi->Reset();
+
+    hr = pencbi->Next( 1,
+                       ppncbi,
+                       &ulCount );
+    Assert(hr == S_OK || hr == S_FALSE);
+    if(hr != S_OK && hr != S_FALSE)
+    {
+        Log(L"VBoxNetCfgWinGetFirstBindingInterface: Next failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+/*@
+ * Enumerate the next binding interface.
+ * The function behaves just like VBoxNetCfgWinGetFirstBindingInterface if
+ * it is called right after VBoxNetCfgWinGetBindingInterfaceEnum.
+ *
+ * @param pencbi Binding interface enumerator reference.
+ * @param ppncbi address the Binding interface reference t be stored to
+ * @return S_OK on success, otherwise an error code
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetNextBindingInterface(IN IEnumNetCfgBindingInterface *pencbi,
+                                     OUT INetCfgBindingInterface **ppncbi)
+{
+    ULONG   ulCount;
+    HRESULT hr;
+
+    *ppncbi = NULL;
+
+    hr = pencbi->Next( 1,
+                       ppncbi,
+                       &ulCount );
+    Assert(hr == S_OK || hr == S_FALSE);
+    if(hr != S_OK && hr != S_FALSE)
+    {
+        Log(L"VBoxNetCfgWinGetNextBindingInterface: Next failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+/**
+ * Enumerate the next binding path.
+ * The function behaves just like VBoxNetCfgWinGetFirstBindingPath if
+ * it is called right after VBoxNetCfgWinGetBindingPathEnum.
+ *
+ * @param pencbp Binding path enumerator reference.
+ * @param ppncbp Address the Binding path reference to be stored to
+ * @return S_OK on sucess, otherwise an error code.
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetNextBindingPath(IN IEnumNetCfgBindingPath *pencbp,
+                                OUT INetCfgBindingPath **ppncbp)
+{
+    ULONG   ulCount;
+    HRESULT hr;
+
+    *ppncbp = NULL;
+
+    hr = pencbp->Next( 1,
+                       ppncbp,
+                       &ulCount );
+    Assert(hr == S_OK || hr == S_FALSE);
+    if(hr != S_OK && hr != S_FALSE)
+    {
+        Log(L"VBoxNetCfgWinGetNextBindingPath: Next failed, hr (0x%x)\n", hr);
+    }
+
+    return hr;
+}
+
+/*
+ * helper function to get the component by its guid given enum interface
+ */
+static HRESULT vboxNetCfgWinGetComponentByGuidEnum(IEnumNetCfgComponent *pEnumNcc, IN const GUID * pGuid, OUT INetCfgComponent ** ppNcc)
+{
+    INetCfgComponent * pNcc;
+    GUID NccGuid;
+    HRESULT hr;
+
+    hr = VBoxNetCfgWinGetFirstComponent( pEnumNcc, &pNcc );
+    Assert(hr == S_OK || hr == S_FALSE);
+    while(hr == S_OK)
+    {
+        ULONG uComponentStatus;
+        hr = pNcc->GetDeviceStatus(&uComponentStatus);
+        if(hr == S_OK)
+        {
+            if(uComponentStatus == 0)
+            {
+                hr = pNcc->GetInstanceGuid(&NccGuid);
+                Assert(hr == S_OK);
+                if(hr == S_OK)
+                {
+                    if(NccGuid == *pGuid)
+                    {
+                        /* found the needed device */
+                        *ppNcc = pNcc;
+                        break;
+                    }
+                }
+                else
+                {
+                    Log(L"vboxNetCfgWinGetComponentByGuidEnum: GetInstanceGuid failed, hr (0x%x)\n", hr);
+                }
+            }
+        }
+
+        VBoxNetCfgWinReleaseRef(pNcc);
+
+        hr = VBoxNetCfgWinGetNextComponent( pEnumNcc, &pNcc );
+    }
+
+    return hr;
+}
+
+/**
+ * get the component by its guid
+ */
+VBOXNETCFGWIN_DECL(HRESULT)
+VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc,
+                                IN const GUID *pguidClass,
+                                IN const GUID * pComponentGuid,
+                                OUT INetCfgComponent **ppncc)
+{
+    IEnumNetCfgComponent *pEnumNcc;
+    HRESULT hr = VBoxNetCfgWinGetComponentEnum( pNc, pguidClass, &pEnumNcc );
+    Assert(hr == S_OK);
+    if(hr == S_OK)
+    {
+        hr = vboxNetCfgWinGetComponentByGuidEnum(pEnumNcc, pComponentGuid, ppncc);
+        Assert(hr == S_OK || hr == S_FALSE);
+        if(hr == S_FALSE)
+        {
+            Log(L"VBoxNetCfgWinGetComponentByGuid: component not found \n");
+        }
+        else if(hr != S_OK)
+        {
+            Log(L"VBoxNetCfgWinGetComponentByGuid: vboxNetCfgWinGetComponentByGuidEnum failed, hr (0x%x)\n", hr);
+        }
+        VBoxNetCfgWinReleaseRef(pEnumNcc);
+    }
+    else
+    {
+        Log(L"VBoxNetCfgWinGetComponentByGuid: VBoxNetCfgWinGetComponentEnum failed, hr (0x%x)\n", hr);
+    }
+    return hr;
+}
+
+typedef BOOL (*VBOXNETCFGWIN_NETCFGENUM_CALLBACK) (IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext);
+
+static HRESULT vboxNetCfgWinEnumNetCfgComponents(IN INetCfg *pNc,
+        IN const GUID *pguidClass,
+        VBOXNETCFGWIN_NETCFGENUM_CALLBACK callback,
+        PVOID pContext)
+{
+    IEnumNetCfgComponent *pEnumComponent;
+    HRESULT hr = pNc->EnumComponents(pguidClass, &pEnumComponent);
+    bool bBreak = false;
+    Assert(hr == S_OK);
+    if(hr == S_OK)
+    {
+        INetCfgComponent *pNcc;
+        hr = pEnumComponent->Reset();
+        Assert(hr == S_OK);
+        do
+        {
+            hr = VBoxNetCfgWinGetNextComponent(pEnumComponent, &pNcc);
+            Assert(hr == S_OK || hr == S_FALSE);
+            if(hr == S_OK)
+            {
+                /* this is E_NOTIMPL for all components other than NET */
+//                ULONG uComponentStatus;
+//                hr = pNcc->GetDeviceStatus(&uComponentStatus);
+//                if(hr == S_OK)
+                {
+                    if(!callback(pNc, pNcc, pContext))
+                    {
+                        bBreak = true;
+                    }
+                }
+                VBoxNetCfgWinReleaseRef(pNcc);
+            }
+            else
+            {
+                if(hr ==S_FALSE)
+                {
+                    hr = S_OK;
+                }
+                else
+                {
+                    Log(L"vboxNetCfgWinEnumNetCfgComponents: VBoxNetCfgWinGetNextComponent failed, hr (0x%x)\n", hr);
+                }
+                break;
+            }
+        } while(!bBreak);
+
+        VBoxNetCfgWinReleaseRef(pEnumComponent);
+    }
+    return hr;
+}
+
+static VOID DoLogging(LPCWSTR szString, ...)
+{
+    LOG_ROUTINE pRoutine = (LOG_ROUTINE)(*((void * volatile *)&g_Logger));
+    if(pRoutine)
+    {
+        WCHAR szBuffer[1024] = {0};
+        va_list pArgList;
+        va_start(pArgList, szString);
+        _vsnwprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szString, pArgList);
+        va_end(pArgList);
+
+        pRoutine(szBuffer);
+    }
+}
+
+VBOXNETCFGWIN_DECL(VOID) VBoxNetCfgWinSetLogging(LOG_ROUTINE Log)
+{
+    *((void * volatile *)&g_Logger) = Log;
+}
+
+static BOOL vboxNetCfgWinRemoveAllNetDevicesOfIdCallback(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDev, PVOID pContext)
+{
+    DWORD winEr;
+    HRESULT hr = S_OK;
+    SP_REMOVEDEVICE_PARAMS rmdParams;
+    SP_DEVINSTALL_PARAMS devParams;
+    rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+    rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE;
+    rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL;
+    rmdParams.HwProfile = 0;
+    if(SetupDiSetClassInstallParams(hDevInfo,pDev,&rmdParams.ClassInstallHeader,sizeof(rmdParams)))
+    {
+        if(SetupDiCallClassInstaller(DIF_REMOVE,hDevInfo,pDev))
+        {
+            /*
+             * see if device needs reboot
+             */
+            devParams.cbSize = sizeof(devParams);
+            if(SetupDiGetDeviceInstallParams(hDevInfo,pDev,&devParams))
+            {
+                if(devParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT))
+                {
+                    //
+                    // reboot required
+                    //
+                    hr = S_FALSE;
+                }
+            }
+            else
+            {
+                //
+                // appears to have succeeded
+                //
+            }
+        }
+        else
+        {
+            winEr = GetLastError();
+            hr = HRESULT_FROM_WIN32(winEr);
+        }
+    }
+    else
+    {
+        winEr = GetLastError();
+        hr = HRESULT_FROM_WIN32(winEr);
+    }
+
+    return TRUE;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(LPWSTR pPnPId)
+{
+    return VBoxNetCfgWinEnumNetDevices(pPnPId, vboxNetCfgWinRemoveAllNetDevicesOfIdCallback, NULL);
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnumNetDevices(LPWSTR pPnPId, VBOXNETCFGWIN_NETENUM_CALLBACK callback, PVOID pContext)
+{
+    DWORD winEr;
+    HRESULT hr = S_OK;
+
+    HDEVINFO hDevInfo = SetupDiGetClassDevsExW(
+            &GUID_DEVCLASS_NET,
+            NULL, /* IN PCTSTR  Enumerator,  OPTIONAL*/
+            NULL, /*IN HWND  hwndParent,  OPTIONAL*/
+            DIGCF_PRESENT, /*IN DWORD  Flags,*/
+            NULL, /*IN HDEVINFO  DeviceInfoSet,  OPTIONAL*/
+            NULL, /*IN PCTSTR  MachineName,  OPTIONAL*/
+            NULL /*IN PVOID  Reserved*/
+        );
+    if(hDevInfo != INVALID_HANDLE_VALUE)
+    {
+        DWORD iDev = 0;
+        SP_DEVINFO_DATA Dev;
+        PBYTE pBuffer = NULL;
+        DWORD cbBuffer = 0;
+        DWORD cbRequired = 0;
+        BOOL bEnumCompleted;
+        size_t cPnPId = wcslen(pPnPId);
+
+        Dev.cbSize = sizeof(Dev);
+
+        for(; bEnumCompleted = SetupDiEnumDeviceInfo(hDevInfo, iDev, &Dev); iDev++)
+        {
+            if(!SetupDiGetDeviceRegistryPropertyW(hDevInfo,&Dev,
+                      SPDRP_HARDWAREID, /* IN DWORD  Property,*/
+                      NULL, /*OUT PDWORD  PropertyRegDataType,  OPTIONAL*/
+                      pBuffer, /*OUT PBYTE  PropertyBuffer,*/
+                      cbBuffer, /* IN DWORD  PropertyBufferSize,*/
+                      &cbRequired /*OUT PDWORD  RequiredSize  OPTIONAL*/
+                    ))
+            {
+                winEr = GetLastError();
+                if(winEr != ERROR_INSUFFICIENT_BUFFER)
+                {
+                    hr = HRESULT_FROM_WIN32(winEr);
+                    break;
+                }
+
+                if(pBuffer)
+                {
+                    free(pBuffer);
+                }
+
+                pBuffer = (PBYTE)malloc(cbRequired);
+                cbBuffer = cbRequired;
+
+                if(!SetupDiGetDeviceRegistryPropertyW(hDevInfo,&Dev,
+                          SPDRP_HARDWAREID, /* IN DWORD  Property,*/
+                          NULL, /*OUT PDWORD  PropertyRegDataType,  OPTIONAL*/
+                          pBuffer, /*OUT PBYTE  PropertyBuffer,*/
+                          cbBuffer, /* IN DWORD  PropertyBufferSize,*/
+                          &cbRequired /*OUT PDWORD  RequiredSize  OPTIONAL*/
+                        ))
+                {
+                    winEr = GetLastError();
+                    hr = HRESULT_FROM_WIN32(winEr);
+                    break;
+                }
+            }
+
+            PWCHAR pCurId = (PWCHAR)pBuffer;
+            size_t cCurId = wcslen(pCurId);
+            if(cCurId >= cPnPId)
+            {
+                pCurId += cCurId - cPnPId;
+                if(!wcsnicmp(pCurId, pPnPId, cPnPId))
+                {
+                    if(!callback(hDevInfo,&Dev,pContext))
+                        break;
+                }
+            }
+
+        }
+
+        if(pBuffer)
+            free(pBuffer);
+
+        if(bEnumCompleted)
+        {
+            winEr = GetLastError();
+            hr = winEr == ERROR_NO_MORE_ITEMS ? S_OK : HRESULT_FROM_WIN32(winEr);
+        }
+
+        SetupDiDestroyDeviceInfoList(hDevInfo);
+    }
+    return hr;
+}
+
+
+
+/* The original source of the VBoxNetAdp adapter creation/destruction code has the following copyright */
+/*
+   Copyright 2004 by the Massachusetts Institute of Technology
+
+   All rights reserved.
+
+   Permission to use, copy, modify, and distribute this software and its
+   documentation for any purpose and without fee is hereby granted,
+   provided that the above copyright notice appear in all copies and that
+   both that copyright notice and this permission notice appear in
+   supporting documentation, and that the name of the Massachusetts
+   Institute of Technology (M.I.T.) not be used in advertising or publicity
+   pertaining to distribution of the software without specific, written
+   prior permission.
+
+   M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+   M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+   ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+   WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+   ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+   SOFTWARE.
+*/
+
+
+#define NETSHELL_LIBRARY _T("netshell.dll")
+
+/**
+ *  Use the IShellFolder API to rename the connection.
+ */
+static HRESULT rename_shellfolder (PCWSTR wGuid, PCWSTR wNewName)
+{
+    /* This is the GUID for the network connections folder. It is constant.
+     * {7007ACC7-3202-11D1-AAD2-00805FC1270E} */
+    const GUID CLSID_NetworkConnections = {
+        0x7007ACC7, 0x3202, 0x11D1, {
+            0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E
+        }
+    };
+
+    LPITEMIDLIST pidl = NULL;
+    IShellFolder *pShellFolder = NULL;
+    HRESULT hr;
+
+    /* Build the display name in the form "::{GUID}". */
+    if (wcslen (wGuid) >= MAX_PATH)
+        return E_INVALIDARG;
+    WCHAR szAdapterGuid[MAX_PATH + 2] = {0};
+    swprintf (szAdapterGuid, L"::%ls", wGuid);
+
+    /* Create an instance of the network connections folder. */
+    hr = CoCreateInstance (CLSID_NetworkConnections, NULL,
+                           CLSCTX_INPROC_SERVER, IID_IShellFolder,
+                           reinterpret_cast <LPVOID *> (&pShellFolder));
+    /* Parse the display name. */
+    if (SUCCEEDED (hr))
+    {
+        hr = pShellFolder->ParseDisplayName (NULL, NULL, szAdapterGuid, NULL,
+                                             &pidl, NULL);
+    }
+    if (SUCCEEDED (hr))
+    {
+        hr = pShellFolder->SetNameOf (NULL, pidl, wNewName, SHGDN_NORMAL,
+                                      &pidl);
+    }
+
+    CoTaskMemFree (pidl);
+
+    if (pShellFolder)
+        pShellFolder->Release();
+
+    return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection (LPWSTR pGuid, PCWSTR NewName)
+{
+    typedef HRESULT (WINAPI *lpHrRenameConnection) (const GUID *, PCWSTR);
+    lpHrRenameConnection RenameConnectionFunc = NULL;
+    HRESULT status;
+//    Guid guid(*pDevInstanceGuid);
+//    Bstr bstr(guid.toString());
+//    BSTR GuidString = bstr.mutableRaw();
+//    WCHAR GuidString[50];
+//
+//    int length = StringFromGUID2(*pDevInstanceGuid, GuidString, sizeof(GuidString)/sizeof(GuidString[0]));
+//    if(!length)
+//        return E_FAIL;
+
+//    strString[wcslen(strString) - 1] = L'\0';
+//
+//    WCHAR * GuidString = strString + 1;
+
+    /* First try the IShellFolder interface, which was unimplemented
+     * for the network connections folder before XP. */
+    status = rename_shellfolder (pGuid, NewName);
+    if (status == E_NOTIMPL)
+    {
+/** @todo that code doesn't seem to work! */
+        /* The IShellFolder interface is not implemented on this platform.
+         * Try the (undocumented) HrRenameConnection API in the netshell
+         * library. */
+        CLSID clsid;
+        HINSTANCE hNetShell;
+        status = CLSIDFromString ((LPOLESTR) pGuid, &clsid);
+        if (FAILED(status))
+            return E_FAIL;
+        hNetShell = LoadLibrary (NETSHELL_LIBRARY);
+        if (hNetShell == NULL)
+            return E_FAIL;
+        RenameConnectionFunc =
+          (lpHrRenameConnection) GetProcAddress (hNetShell,
+                                                 "HrRenameConnection");
+        if (RenameConnectionFunc == NULL)
+        {
+            FreeLibrary (hNetShell);
+            return E_FAIL;
+        }
+        status = RenameConnectionFunc (&clsid, NewName);
+        FreeLibrary (hNetShell);
+    }
+    if (FAILED (status))
+        return status;
+
+    return S_OK;
+}
+
+#define DRIVERHWID _T("sun_VBoxNetAdp")
+
+#define SetErrBreak(strAndArgs) \
+    if (1) { \
+        hrc = E_FAIL; \
+        Log strAndArgs; \
+        Assert(0); \
+        break; \
+    } else do {} while (0)
+
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface (const GUID *pGUID, BSTR *pErrMsg)
+{
+//    LogFlowFuncEnter();
+//    LogFlowFunc (("Network connection GUID = {%RTuuid}\n", aGUID.raw()));
+
+//    AssertReturn (aClient, VERR_INVALID_POINTER);
+//    AssertReturn (!aGUID.isEmpty(), VERR_INVALID_PARAMETER);
+
+    HRESULT hrc = S_OK;
+
+    do
+    {
+        TCHAR lszPnPInstanceId [512] = {0};
+
+        /* We have to find the device instance ID through a registry search */
+
+        HKEY hkeyNetwork = 0;
+        HKEY hkeyConnection = 0;
+
+        do
+        {
+            WCHAR strRegLocation [256];
+            WCHAR GuidString[50];
+
+            int length = StringFromGUID2(*pGUID, GuidString, sizeof(GuidString)/sizeof(GuidString[0]));
+            if(!length)
+                SetErrBreak((L"Failed to create a Guid string"));
+
+            swprintf (strRegLocation,
+                     L"SYSTEM\\CurrentControlSet\\Control\\Network\\"
+                     L"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+                     GuidString);
+
+            LONG status;
+            status = RegOpenKeyExW (HKEY_LOCAL_MACHINE, strRegLocation, 0,
+                                    KEY_READ, &hkeyNetwork);
+            if ((status != ERROR_SUCCESS) || !hkeyNetwork)
+                SetErrBreak ((
+                        L"Host interface network is not found in registry (%s) [1]",
+                    strRegLocation));
+
+            status = RegOpenKeyExW (hkeyNetwork, L"Connection", 0,
+                                    KEY_READ, &hkeyConnection);
+            if ((status != ERROR_SUCCESS) || !hkeyConnection)
+                SetErrBreak ((
+                        L"Host interface network is not found in registry (%s) [2]",
+                    strRegLocation));
+
+            DWORD len = sizeof (lszPnPInstanceId);
+            DWORD dwKeyType;
+            status = RegQueryValueExW (hkeyConnection, L"PnPInstanceID", NULL,
+                                       &dwKeyType, (LPBYTE) lszPnPInstanceId, &len);
+            if ((status != ERROR_SUCCESS) || (dwKeyType != REG_SZ))
+                SetErrBreak ((
+                        L"Host interface network is not found in registry (%s) [3]",
+                    strRegLocation));
+        }
+        while (0);
+
+        if (hkeyConnection)
+            RegCloseKey (hkeyConnection);
+        if (hkeyNetwork)
+            RegCloseKey (hkeyNetwork);
+
+        if (FAILED (hrc))
+            break;
+
+        /*
+         * Now we are going to enumerate all network devices and
+         * wait until we encounter the right device instance ID
+         */
+
+        HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
+
+        do
+        {
+            BOOL ok;
+            DWORD ret = 0;
+            GUID netGuid;
+            SP_DEVINFO_DATA DeviceInfoData;
+            DWORD index = 0;
+            BOOL found = FALSE;
+            DWORD size = 0;
+
+            /* initialize the structure size */
+            DeviceInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
+
+            /* copy the net class GUID */
+            memcpy (&netGuid, &GUID_DEVCLASS_NET, sizeof (GUID_DEVCLASS_NET));
+
+            /* return a device info set contains all installed devices of the Net class */
+            hDeviceInfo = SetupDiGetClassDevs (&netGuid, NULL, NULL, DIGCF_PRESENT);
+
+            if (hDeviceInfo == INVALID_HANDLE_VALUE)
+                SetErrBreak ((L"SetupDiGetClassDevs failed (0x%08X)", GetLastError()));
+
+            /* enumerate the driver info list */
+            while (TRUE)
+            {
+                TCHAR *deviceHwid;
+
+                ok = SetupDiEnumDeviceInfo (hDeviceInfo, index, &DeviceInfoData);
+
+                if (!ok)
+                {
+                    if (GetLastError() == ERROR_NO_MORE_ITEMS)
+                        break;
+                    else
+                    {
+                        index++;
+                        continue;
+                    }
+                }
+
+                /* try to get the hardware ID registry property */
+                ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
+                                                       &DeviceInfoData,
+                                                       SPDRP_HARDWAREID,
+                                                       NULL,
+                                                       NULL,
+                                                       0,
+                                                       &size);
+                if (!ok)
+                {
+                    if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+                    {
+                        index++;
+                        continue;
+                    }
+
+                    deviceHwid = (TCHAR *) malloc (size);
+                    ok = SetupDiGetDeviceRegistryProperty (hDeviceInfo,
+                                                           &DeviceInfoData,
+                                                           SPDRP_HARDWAREID,
+                                                           NULL,
+                                                           (PBYTE)deviceHwid,
+                                                           size,
+                                                           NULL);
+                    if (!ok)
+                    {
+                        free (deviceHwid);
+                        deviceHwid = NULL;
+                        index++;
+                        continue;
+                    }
+                }
+                else
+                {
+                    /* something is wrong.  This shouldn't have worked with a NULL buffer */
+                    index++;
+                    continue;
+                }
+
+                for (TCHAR *t = deviceHwid;
+                     t && *t && t < &deviceHwid[size / sizeof(TCHAR)];
+                     t += _tcslen (t) + 1)
+                {
+                    if (!_tcsicmp (DRIVERHWID, t))
+                    {
+                          /* get the device instance ID */
+                          TCHAR devID [MAX_DEVICE_ID_LEN];
+                          if (CM_Get_Device_ID(DeviceInfoData.DevInst,
+                                               devID, MAX_DEVICE_ID_LEN, 0) == CR_SUCCESS)
+                          {
+                              /* compare to what we determined before */
+                              if (wcscmp(devID, lszPnPInstanceId) == 0)
+                              {
+                                  found = TRUE;
+                                  break;
+                              }
+                          }
+                    }
+                }
+
+                if (deviceHwid)
+                {
+                    free (deviceHwid);
+                    deviceHwid = NULL;
+                }
+
+                if (found)
+                    break;
+
+                index++;
+            }
+
+            if (found == FALSE)
+                SetErrBreak ((L"Host Interface Network driver not found (0x%08X)",
+                              GetLastError()));
+
+            ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
+            if (!ok)
+                SetErrBreak ((L"SetupDiSetSelectedDevice failed (0x%08X)",
+                              GetLastError()));
+
+            ok = SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
+            if (!ok)
+                SetErrBreak ((L"SetupDiCallClassInstaller (DIF_REMOVE) failed (0x%08X)",
+                              GetLastError()));
+        }
+        while (0);
+
+        /* clean up the device info set */
+        if (hDeviceInfo != INVALID_HANDLE_VALUE)
+            SetupDiDestroyDeviceInfoList (hDeviceInfo);
+
+        if (FAILED (hrc))
+            break;
+    }
+    while (0);
+
+//    LogFlowFunc (("vrc=%Rrc\n", vrc));
+//    LogFlowFuncLeave();
+    return hrc;
+}
+
+static UINT WINAPI vboxNetCfgWinPspFileCallback(
+        PVOID Context,
+        UINT Notification,
+        UINT_PTR Param1,
+        UINT_PTR Param2
+    )
+{
+    switch(Notification)
+    {
+        case SPFILENOTIFY_TARGETNEWER:
+        case SPFILENOTIFY_TARGETEXISTS:
+            return TRUE;
+    }
+    return SetupDefaultQueueCallback(Context, Notification, Param1, Param2);
+}
+
+static BOOL vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority (IN INetCfg *pNc, IN INetCfgComponent *pNcc, PVOID pContext)
+{
+    INetCfgComponentBindings *pNccb = NULL;
+    IEnumNetCfgBindingPath  *pEnumNccbp;
+    GUID *pGuid = (GUID*)pContext;
+    HRESULT                  hr;
+    bool bFound = false;
+
+    /* Get component's binding. */
+    hr = pNcc->QueryInterface( IID_INetCfgComponentBindings,
+                               (PVOID *)&pNccb );
+    Assert(hr == S_OK);
+    if ( hr == S_OK )
+    {
+        /* Get binding path enumerator reference. */
+        hr = pNccb->EnumBindingPaths(EBP_BELOW, &pEnumNccbp);
+        Assert(hr == S_OK);
+        if(hr == S_OK)
+        {
+            INetCfgBindingPath *pNccbp;
+            hr = pEnumNccbp->Reset();
+            Assert(hr == S_OK);
+            do
+            {
+                hr = VBoxNetCfgWinGetNextBindingPath(pEnumNccbp, &pNccbp);
+                Assert(hr == S_OK || hr == S_FALSE);
+                if(hr == S_OK)
+                {
+//                    if(pNccbp->IsEnabled() == S_OK)
+                     {
+                         IEnumNetCfgBindingInterface *pEnumNcbi;
+                         hr = VBoxNetCfgWinGetBindingInterfaceEnum(pNccbp, &pEnumNcbi);
+                         Assert(hr == S_OK);
+                         if ( hr == S_OK )
+                         {
+                             INetCfgBindingInterface *pNcbi;
+                             hr = pEnumNcbi->Reset();
+                             Assert(hr == S_OK);
+                             do
+                             {
+                                 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumNcbi, &pNcbi);
+                                 Assert(hr == S_OK || hr == S_FALSE);
+                                 if(hr == S_OK)
+                                 {
+                                     INetCfgComponent * pNccBoud;
+                                     hr = pNcbi->GetLowerComponent(&pNccBoud);
+                                     Assert(hr == S_OK);
+                                     if(hr == S_OK)
+                                     {
+                                         ULONG uComponentStatus;
+                                         hr = pNccBoud->GetDeviceStatus(&uComponentStatus);
+                                         if(hr == S_OK)
+                                         {
+//                                             if(uComponentStatus == 0)
+                                             {
+                                                 GUID guid;
+                                                 hr = pNccBoud->GetInstanceGuid(&guid);
+                                                 if(guid == *pGuid)
+                                                 {
+                                                     hr = pNccb->MoveAfter(pNccbp, NULL);
+                                                     Assert(hr == S_OK);
+                                                     bFound = true;
+                                                 }
+                                             }
+                                         }
+                                         VBoxNetCfgWinReleaseRef(pNccBoud);
+                                     }
+                                     VBoxNetCfgWinReleaseRef(pNcbi);
+                                 }
+                                 else
+                                 {
+                                     if(hr == S_FALSE)
+                                     {
+                                         hr = S_OK;
+                                     }
+                                     else
+                                     {
+                                         Log(L"vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority: VBoxNetCfgWinGetNextBindingInterface failed, hr (0x%x)\n", hr);
+                                     }
+                                     break;
+                                 }
+                             } while(!bFound);
+                             VBoxNetCfgWinReleaseRef(pEnumNcbi);
+                         }
+                         else
+                         {
+                             Log(L"vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority: VBoxNetCfgWinGetBindingInterfaceEnum failed, hr (0x%x)\n", hr);
+                         }
+                     }
+
+                    VBoxNetCfgWinReleaseRef(pNccbp);
+                }
+                else
+                {
+                    if(hr = S_FALSE)
+                    {
+                        hr = S_OK;
+                    }
+                    else
+                    {
+                        Log(L"vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority: VBoxNetCfgWinGetNextBindingPath failed, hr (0x%x)\n", hr);
+                    }
+                    break;
+                }
+            } while(!bFound);
+
+            VBoxNetCfgWinReleaseRef(pEnumNccbp);
+        }
+        else
+        {
+            Log(L"vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority: EnumBindingPaths failed, hr (0x%x)\n", hr);
+        }
+
+        VBoxNetCfgWinReleaseRef( pNccb );
+    }
+    else
+    {
+        Log(L"vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority: QueryInterface for IID_INetCfgComponentBindings failed, hr (0x%x)\n", hr);
+    }
+
+    return true;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface (GUID *pGuid, BSTR *lppszName, BSTR *pErrMsg)
+{
+    HRESULT hrc = S_OK;
+
+    HDEVINFO hDeviceInfo = INVALID_HANDLE_VALUE;
+    SP_DEVINFO_DATA DeviceInfoData;
+    PVOID pQueueCallbackContext = NULL;
+    DWORD ret = 0;
+    BOOL found = FALSE;
+    BOOL registered = FALSE;
+    BOOL destroyList = FALSE;
+    WCHAR pWCfgGuidString [50];
+    WCHAR DevName[256];
+
+    do
+    {
+        BOOL ok;
+        GUID netGuid;
+        SP_DRVINFO_DATA DriverInfoData;
+        SP_DEVINSTALL_PARAMS  DeviceInstallParams;
+        TCHAR className [MAX_PATH];
+        DWORD index = 0;
+        PSP_DRVINFO_DETAIL_DATA pDriverInfoDetail;
+        /* for our purposes, 2k buffer is more
+         * than enough to obtain the hardware ID
+         * of the VBoxNetAdp driver. */
+        DWORD detailBuf [2048];
+
+        HKEY hkey = NULL;
+        DWORD cbSize;
+        DWORD dwValueType;
+
+        /* initialize the structure size */
+        DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
+        DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
+
+        /* copy the net class GUID */
+        memcpy(&netGuid, &GUID_DEVCLASS_NET, sizeof(GUID_DEVCLASS_NET));
+
+        /* create an empty device info set associated with the net class GUID */
+        hDeviceInfo = SetupDiCreateDeviceInfoList (&netGuid, NULL);
+        if (hDeviceInfo == INVALID_HANDLE_VALUE)
+            SetErrBreak ((L"SetupDiCreateDeviceInfoList failed (0x%08X)",
+                          GetLastError()));
+
+        /* get the class name from GUID */
+        ok = SetupDiClassNameFromGuid (&netGuid, className, MAX_PATH, NULL);
+        if (!ok)
+            SetErrBreak ((L"SetupDiClassNameFromGuid failed (0x%08X)",
+                          GetLastError()));
+
+        /* create a device info element and add the new device instance
+         * key to registry */
+        ok = SetupDiCreateDeviceInfo (hDeviceInfo, className, &netGuid, NULL, NULL,
+                                     DICD_GENERATE_ID, &DeviceInfoData);
+        if (!ok)
+            SetErrBreak ((L"SetupDiCreateDeviceInfo failed (0x%08X)",
+                          GetLastError()));
+
+        /* select the newly created device info to be the currently
+           selected member */
+        ok = SetupDiSetSelectedDevice (hDeviceInfo, &DeviceInfoData);
+        if (!ok)
+            SetErrBreak ((L"SetupDiSetSelectedDevice failed (0x%08X)",
+                          GetLastError()));
+
+        /* build a list of class drivers */
+        ok = SetupDiBuildDriverInfoList (hDeviceInfo, &DeviceInfoData,
+                                        SPDIT_CLASSDRIVER);
+        if (!ok)
+            SetErrBreak ((L"SetupDiBuildDriverInfoList failed (0x%08X)",
+                          GetLastError()));
+
+        destroyList = TRUE;
+
+        /* enumerate the driver info list */
+        while (TRUE)
+        {
+            BOOL ret;
+
+            ret = SetupDiEnumDriverInfo (hDeviceInfo, &DeviceInfoData,
+                                         SPDIT_CLASSDRIVER, index, &DriverInfoData);
+
+            /* if the function failed and GetLastError() returned
+             * ERROR_NO_MORE_ITEMS, then we have reached the end of the
+             * list.  Othewise there was something wrong with this
+             * particular driver. */
+            if (!ret)
+            {
+                if(GetLastError() == ERROR_NO_MORE_ITEMS)
+                    break;
+                else
+                {
+                    index++;
+                    continue;
+                }
+            }
+
+            pDriverInfoDetail = (PSP_DRVINFO_DETAIL_DATA) detailBuf;
+            pDriverInfoDetail->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
+
+            /* if we successfully find the hardware ID and it turns out to
+             * be the one for the loopback driver, then we are done. */
+            if (SetupDiGetDriverInfoDetail (hDeviceInfo,
+                                            &DeviceInfoData,
+                                            &DriverInfoData,
+                                            pDriverInfoDetail,
+                                            sizeof (detailBuf),
+                                            NULL))
+            {
+                TCHAR * t;
+
+                /* pDriverInfoDetail->HardwareID is a MULTISZ string.  Go through the
+                 * whole list and see if there is a match somewhere. */
+                t = pDriverInfoDetail->HardwareID;
+                while (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
+                {
+                    if (!_tcsicmp(t, DRIVERHWID))
+                        break;
+
+                    t += _tcslen(t) + 1;
+                }
+
+                if (t && *t && t < (TCHAR *) &detailBuf [RT_ELEMENTS(detailBuf)])
+                {
+                    found = TRUE;
+                    break;
+                }
+            }
+
+            index ++;
+        }
+
+        if (!found)
+            SetErrBreak ((L"Could not find Host Interface Networking driver! "
+                              L"Please reinstall"));
+
+        /* set the loopback driver to be the currently selected */
+        ok = SetupDiSetSelectedDriver (hDeviceInfo, &DeviceInfoData,
+                                       &DriverInfoData);
+        if (!ok)
+            SetErrBreak ((L"SetupDiSetSelectedDriver failed (0x%08X)",
+                          GetLastError()));
+
+        /* register the phantom device to prepare for install */
+        ok = SetupDiCallClassInstaller (DIF_REGISTERDEVICE, hDeviceInfo,
+                                        &DeviceInfoData);
+        if (!ok)
+        {
+            DWORD err = GetLastError();
+            SetErrBreak ((L"SetupDiCallClassInstaller failed (0x%08X)",
+                          err));
+        }
+
+        /* registered, but remove if errors occur in the following code */
+        registered = TRUE;
+
+        /* ask the installer if we can install the device */
+        ok = SetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hDeviceInfo,
+                                        &DeviceInfoData);
+        if (!ok)
+        {
+            if (GetLastError() != ERROR_DI_DO_DEFAULT)
+                SetErrBreak ((L"SetupDiCallClassInstaller (DIF_ALLOW_INSTALL) failed (0x%08X)",
+                              GetLastError()));
+            /* that's fine */
+        }
+
+        /* get the device install parameters and disable filecopy */
+        DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+                                            &DeviceInstallParams);
+        if (ok)
+        {
+            pQueueCallbackContext = SetupInitDefaultQueueCallback(NULL);
+            if(pQueueCallbackContext)
+            {
+                DeviceInstallParams.InstallMsgHandlerContext = pQueueCallbackContext;
+                DeviceInstallParams.InstallMsgHandler = (PSP_FILE_CALLBACK)vboxNetCfgWinPspFileCallback;
+                ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+                                                    &DeviceInstallParams);
+                if(!ok)
+                {
+                    DWORD winEr = GetLastError();
+                    Assert(0);
+                    Log(L"SetupDiSetDeviceInstallParams: SetupDiSetDeviceInstallParams failed, winEr (%d)\n", winEr);
+                }
+                Assert(ok);
+            }
+            else
+            {
+                DWORD winEr = GetLastError();
+                Assert(0);
+                Log(L"VBoxNetCfgWinCreateHostOnlyNetworkInterface: SetupInitDefaultQueueCallback failed, winEr (%d)\n", winEr);
+            }
+        }
+        else
+        {
+            DWORD winEr = GetLastError();
+            Assert(0);
+            Log(L"VBoxNetCfgWinCreateHostOnlyNetworkInterface: SetupDiGetDeviceInstallParams failed, winEr (%d)\n", winEr);
+        }
+
+        /* install the files first */
+        ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hDeviceInfo,
+                                        &DeviceInfoData);
+        if (!ok)
+            SetErrBreak ((L"SetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES) failed (0x%08X)",
+                          GetLastError()));
+
+        /* get the device install parameters and disable filecopy */
+        DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
+        ok = SetupDiGetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+                                            &DeviceInstallParams);
+        if (ok)
+        {
+            DeviceInstallParams.Flags |= DI_NOFILECOPY;
+            ok = SetupDiSetDeviceInstallParams (hDeviceInfo, &DeviceInfoData,
+                                                &DeviceInstallParams);
+            if (!ok)
+                SetErrBreak ((L"SetupDiSetDeviceInstallParams failed (0x%08X)",
+                              GetLastError()));
+        }
+
+        /*
+         * Register any device-specific co-installers for this device,
+         */
+
+        ok = SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
+                                        hDeviceInfo,
+                                        &DeviceInfoData);
+        if (!ok)
+            SetErrBreak ((L"SetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS) failed (0x%08X)",
+                          GetLastError()));
+
+        /*
+         * install any  installer-specified interfaces.
+         * and then do the real install
+         */
+        ok = SetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
+                                        hDeviceInfo,
+                                        &DeviceInfoData);
+        if (!ok)
+            SetErrBreak ((L"SetupDiCallClassInstaller (DIF_INSTALLINTERFACES) failed (0x%08X)",
+                          GetLastError()));
+
+        ok = SetupDiCallClassInstaller (DIF_INSTALLDEVICE,
+                                        hDeviceInfo,
+                                        &DeviceInfoData);
+        if (!ok)
+            SetErrBreak ((L"SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
+                          GetLastError()));
+
+        /* Figure out NetCfgInstanceId */
+        hkey = SetupDiOpenDevRegKey (hDeviceInfo,
+                                     &DeviceInfoData,
+                                     DICS_FLAG_GLOBAL,
+                                     0,
+                                     DIREG_DRV,
+                                     KEY_READ);
+        if (hkey == INVALID_HANDLE_VALUE)
+            SetErrBreak ((L"SetupDiOpenDevRegKey failed (0x%08X)",
+                          GetLastError()));
+
+        cbSize = sizeof (pWCfgGuidString);
+        DWORD ret;
+        ret = RegQueryValueExW (hkey, L"NetCfgInstanceId", NULL,
+                               &dwValueType, (LPBYTE) pWCfgGuidString, &cbSize);
+
+        RegCloseKey (hkey);
+
+        if(!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
+                SPDRP_FRIENDLYNAME , /* IN DWORD  Property,*/
+                  NULL, /*OUT PDWORD  PropertyRegDataType,  OPTIONAL*/
+                  (PBYTE)DevName, /*OUT PBYTE  PropertyBuffer,*/
+                  sizeof(DevName), /* IN DWORD  PropertyBufferSize,*/
+                  NULL /*OUT PDWORD  RequiredSize  OPTIONAL*/
+                ))
+        {
+            int err = GetLastError();
+            if(err != ERROR_INVALID_DATA)
+            {
+                SetErrBreak ((L"SetupDiGetDeviceRegistryProperty failed (0x%08X)",
+                              err));
+            }
+
+            if(!SetupDiGetDeviceRegistryPropertyW(hDeviceInfo, &DeviceInfoData,
+                              SPDRP_DEVICEDESC  , /* IN DWORD  Property,*/
+                              NULL, /*OUT PDWORD  PropertyRegDataType,  OPTIONAL*/
+                              (PBYTE)DevName, /*OUT PBYTE  PropertyBuffer,*/
+                              sizeof(DevName), /* IN DWORD  PropertyBufferSize,*/
+                              NULL /*OUT PDWORD  RequiredSize  OPTIONAL*/
+                            ))
+            {
+                err = GetLastError();
+                SetErrBreak ((L"SetupDiGetDeviceRegistryProperty failed (0x%08X)",
+                                              err));
+            }
+        }
+    }
+    while (0);
+
+    /*
+     * cleanup
+     */
+    if(pQueueCallbackContext)
+    {
+        SetupTermDefaultQueueCallback(pQueueCallbackContext);
+    }
+
+    if (hDeviceInfo != INVALID_HANDLE_VALUE)
+    {
+        /* an error has occurred, but the device is registered, we must remove it */
+        if (ret != 0 && registered)
+            SetupDiCallClassInstaller (DIF_REMOVE, hDeviceInfo, &DeviceInfoData);
+
+        found = SetupDiDeleteDeviceInfo (hDeviceInfo, &DeviceInfoData);
+
+        /* destroy the driver info list */
+        if (destroyList)
+            SetupDiDestroyDriverInfoList (hDeviceInfo, &DeviceInfoData,
+                                          SPDIT_CLASSDRIVER);
+        /* clean up the device info set */
+        SetupDiDestroyDeviceInfoList (hDeviceInfo);
+    }
+
+    /* return the network connection GUID on success */
+    if (SUCCEEDED(hrc))
+    {
+//        Bstr str(DevName);
+//        str.detachTo(pName);
+        WCHAR ConnectoinName[128];
+        ULONG cbName = sizeof(ConnectoinName);
+
+        HRESULT hr = VBoxNetCfgWinGenHostonlyConnectionName (DevName, ConnectoinName, &cbName);
+        if(hr == S_OK)
+        {
+            hr = VBoxNetCfgWinRenameConnection (pWCfgGuidString, ConnectoinName);
+        }
+
+        if(lppszName)
+        {
+            *lppszName = ::SysAllocString ((const OLECHAR *) DevName);
+            if ( !*lppszName  )
+            {
+                Log(L"VBoxNetCfgWinCreateHostOnlyNetworkInterface: SysAllocString failed\n");
+                Assert(0);
+                hrc = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+            }
+        }
+
+        if(pGuid)
+        {
+            hrc = CLSIDFromString(pWCfgGuidString, (LPCLSID) pGuid);
+            if(hrc != S_OK)
+            {
+                Log(L"VBoxNetCfgWinCreateHostOnlyNetworkInterface: CLSIDFromString failed, hrc (0x%x)\n", hrc);
+                Assert(0);
+            }
+        }
+
+        INetCfg *pNc;
+        LPWSTR               lpszApp = NULL;
+
+
+
+        hr = VBoxNetCfgWinQueryINetCfgEx( TRUE,
+                           L"VirtualBox Host-Only Creation",
+                           30000, /* on Vista we often get 6to4svc.dll holding the lock, wait for 30 sec,  */
+                           &pNc,  /* TODO: special handling for 6to4svc.dll ???, i.e. several retrieves */
+                           &lpszApp );
+        Assert(hr == S_OK);
+        if(hr == S_OK)
+        {
+            hr = vboxNetCfgWinEnumNetCfgComponents(pNc,
+                    &GUID_DEVCLASS_NETSERVICE,
+                    vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
+                    pGuid);
+            Assert(hr == S_OK);
+
+            hr = vboxNetCfgWinEnumNetCfgComponents(pNc,
+                    &GUID_DEVCLASS_NETTRANS,
+                    vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
+                    pGuid);
+            Assert(hr == S_OK);
+
+            hr = vboxNetCfgWinEnumNetCfgComponents(pNc,
+                    &GUID_DEVCLASS_NETCLIENT,
+                    vboxNetCfgWinAdjustHostOnlyNetworkInterfacePriority,
+                    pGuid);
+            Assert(hr == S_OK);
+
+            if(hr == S_OK)
+            {
+                hr = pNc->Apply();
+                Assert(hr == S_OK);
+            }
+
+            VBoxNetCfgWinReleaseINetCfg(pNc, TRUE);
+        }
+        else if(hr == NETCFG_E_NO_WRITE_LOCK && lpszApp)
+        {
+            Log(L"VBoxNetCfgWinCreateHostOnlyNetworkInterface: app %s is holding the lock, failed\n", lpszApp);
+            CoTaskMemFree(lpszApp);
+        }
+        else
+        {
+            Log(L"VBoxNetCfgWinCreateHostOnlyNetworkInterface: VBoxNetCfgWinQueryINetCfgEx failed, hr 0x%x\n", hr);
+        }
+    }
+
+    return hrc;
+}
+
+#undef SetErrBreak
+
+#define VBOX_CONNECTION_NAME L"VirtualBox Host-Only Network"
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName (PCWSTR DevName, WCHAR *pBuf, PULONG pcbBuf)
+{
+    const WCHAR * pSuffix = wcsrchr( DevName, L'#' );
+    ULONG cbSize = sizeof(VBOX_CONNECTION_NAME);
+    ULONG cbSufSize = 0;
+
+    if(pSuffix)
+    {
+        cbSize += (ULONG)wcslen(pSuffix) * 2;
+        cbSize += 2; /* for space */
+    }
+
+    if(*pcbBuf < cbSize)
+    {
+        *pcbBuf = cbSize;
+        return E_FAIL;
+    }
+
+    wcscpy(pBuf, VBOX_CONNECTION_NAME);
+    if(pSuffix)
+    {
+        wcscat(pBuf, L" ");
+        wcscat(pBuf, pSuffix);
+    }
+
+    return S_OK;
+}
+
+/* network settings config */
+/**
+ *  Strong referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
+ */
+template <class C>
+class ComStrongRef
+{
+protected:
+
+    static void addref (C *p) { p->AddRef(); }
+    static void release (C *p) { p->Release(); }
+};
+
+/**
+ *  Weak referencing operators. Used as a second argument to ComPtr<>/ComObjPtr<>.
+ */
+template <class C>
+class ComWeakRef
+{
+protected:
+
+    static void addref  (C * /* p */) {}
+    static void release (C * /* p */) {}
+};
+
+/**
+ *  Base template for smart COM pointers. Not intended to be used directly.
+ */
+template <class C, template <class> class RefOps = ComStrongRef>
+class ComPtrBase : protected RefOps <C>
+{
+public:
+
+    /* special template to disable AddRef()/Release() */
+    template <class I>
+    class NoAddRefRelease : public I
+    {
+        private:
+#if !defined (VBOX_WITH_XPCOM)
+            STDMETHOD_(ULONG, AddRef)() = 0;
+            STDMETHOD_(ULONG, Release)() = 0;
+#else /* !defined (VBOX_WITH_XPCOM) */
+            NS_IMETHOD_(nsrefcnt) AddRef(void) = 0;
+            NS_IMETHOD_(nsrefcnt) Release(void) = 0;
+#endif /* !defined (VBOX_WITH_XPCOM) */
+    };
+
+protected:
+
+    ComPtrBase () : p (NULL) {}
+    ComPtrBase (const ComPtrBase &that) : p (that.p) { addref(); }
+    ComPtrBase (C *that_p) : p (that_p) { addref(); }
+
+    ~ComPtrBase() { release(); }
+
+    ComPtrBase &operator= (const ComPtrBase &that)
+    {
+        safe_assign (that.p);
+        return *this;
+    }
+
+    ComPtrBase &operator= (C *that_p)
+    {
+        safe_assign (that_p);
+        return *this;
+    }
+
+public:
+
+    void setNull()
+    {
+        release();
+        p = NULL;
+    }
+
+    bool isNull() const
+    {
+        return (p == NULL);
+    }
+
+    bool operator! () const { return isNull(); }
+
+    bool operator< (C* that_p) const { return p < that_p; }
+    bool operator== (C* that_p) const { return p == that_p; }
+
+    template <class I>
+    bool equalsTo (I *aThat) const
+    {
+        return ComPtrEquals (p, aThat);
+    }
+
+    template <class OC>
+    bool equalsTo (const ComPtrBase <OC> &oc) const
+    {
+        return equalsTo ((OC *) oc);
+    }
+
+    /** Intended to pass instances as in parameters to interface methods */
+    operator C* () const { return p; }
+
+    /**
+     *  Dereferences the instance (redirects the -> operator to the managed
+     *  pointer).
+     */
+    NoAddRefRelease <C> *operator-> () const
+    {
+        AssertMsg (p, ("Managed pointer must not be null\n"));
+        return (NoAddRefRelease <C> *) p;
+    }
+
+    template <class I>
+    HRESULT queryInterfaceTo (I **pp) const
+    {
+        if (pp)
+        {
+            if (p)
+            {
+                return p->QueryInterface (COM_IIDOF (I), (void **) pp);
+            }
+            else
+            {
+                *pp = NULL;
+                return S_OK;
+            }
+        }
+
+        return E_INVALIDARG;
+    }
+
+    /** Intended to pass instances as out parameters to interface methods */
+    C **asOutParam()
+    {
+        setNull();
+        return &p;
+    }
+
+private:
+
+    void addref()
+    {
+        if (p)
+            RefOps <C>::addref (p);
+    }
+
+    void release()
+    {
+        if (p)
+            RefOps <C>::release (p);
+    }
+
+    void safe_assign (C *that_p)
+    {
+        /* be aware of self-assignment */
+        if (that_p)
+            RefOps <C>::addref (that_p);
+        release();
+        p = that_p;
+    }
+
+    C *p;
+};
+
+/**
+ *  Smart COM pointer wrapper that automatically manages refcounting of
+ *  interface pointers.
+ *
+ *  @param I    COM interface class
+ */
+template <class I, template <class> class RefOps = ComStrongRef>
+class ComPtr : public ComPtrBase <I, RefOps>
+{
+    typedef ComPtrBase <I, RefOps> Base;
+
+public:
+
+    ComPtr () : Base() {}
+    ComPtr (const ComPtr &that) : Base (that) {}
+    ComPtr &operator= (const ComPtr &that)
+    {
+        Base::operator= (that);
+        return *this;
+    }
+
+    template <class OI>
+    ComPtr (OI *that_p) : Base () { operator= (that_p); }
+
+    /* specialization for I */
+    ComPtr (I *that_p) : Base (that_p) {}
+
+    template <class OC>
+    ComPtr (const ComPtr <OC, RefOps> &oc) : Base () { operator= ((OC *) oc); }
+
+    template <class OI>
+    ComPtr &operator= (OI *that_p)
+    {
+        if (that_p)
+            that_p->QueryInterface (COM_IIDOF (I), (void **) Base::asOutParam());
+        else
+            Base::setNull();
+        return *this;
+    }
+
+    /* specialization for I */
+    ComPtr &operator=(I *that_p)
+    {
+        Base::operator= (that_p);
+        return *this;
+    }
+
+    template <class OC>
+    ComPtr &operator= (const ComPtr <OC, RefOps> &oc)
+    {
+        return operator= ((OC *) oc);
+    }
+};
+
+static HRESULT netIfWinFindAdapterClassById(IWbemServices * pSvc, const GUID * pGuid, IWbemClassObject **pAdapterConfig)
+{
+    HRESULT hres;
+    WCHAR aQueryString[256];
+    WCHAR GuidString[50];
+
+    int length = StringFromGUID2(*pGuid, GuidString, sizeof(GuidString)/sizeof(GuidString[0]));
+    if(length)
+    {
+        swprintf(aQueryString, L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \"%s\"", GuidString);
+        // Step 6: --------------------------------------------------
+        // Use the IWbemServices pointer to make requests of WMI ----
+
+        IEnumWbemClassObject* pEnumerator = NULL;
+        hres = pSvc->ExecQuery(
+            bstr_t("WQL"),
+            bstr_t(aQueryString),
+            WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+            NULL,
+            &pEnumerator);
+        if(SUCCEEDED(hres))
+        {
+            // Step 7: -------------------------------------------------
+            // Get the data from the query in step 6 -------------------
+
+            IWbemClassObject *pclsObj;
+            ULONG uReturn = 0;
+
+            if (pEnumerator)
+            {
+                HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
+                    &pclsObj, &uReturn);
+
+                if(SUCCEEDED(hres))
+                {
+                    if(uReturn)
+                    {
+                        pEnumerator->Release();
+                        *pAdapterConfig = pclsObj;
+                        hres = S_OK;
+                        return hres;
+                    }
+                    else
+                    {
+                        hres = S_FALSE;
+                    }
+                }
+
+                pEnumerator->Release();
+            }
+        }
+        else
+        {
+            Log(L"Query for operating system name failed. Error code = 0x%x\n", hres);
+        }
+    }
+    else
+    {
+        DWORD winEr = GetLastError();
+        Log(L"Failed to create guid string from guid, winEr (%d)\n", winEr);
+        hres = HRESULT_FROM_WIN32( winEr );
+    }
+
+    return hres;
+}
+
+static HRESULT netIfWinIsHostOnly(IWbemClassObject * pAdapterConfig, BOOL * pbIsHostOnly)
+{
+    VARIANT vtServiceName;
+    BOOL bIsHostOnly = FALSE;
+    VariantInit(&vtServiceName);
+
+    HRESULT hr = pAdapterConfig->Get(L"ServiceName", 0, &vtServiceName, 0, 0);
+    if(SUCCEEDED(hr))
+    {
+        *pbIsHostOnly = (bstr_t(vtServiceName.bstrVal) == bstr_t("VBoxNetAdp"));
+
+        VariantClear(&vtServiceName);
+    }
+
+    return hr;
+}
+
+static HRESULT netIfWinGetIpSettings(IWbemClassObject * pAdapterConfig, ULONG *pIpv4, ULONG *pMaskv4)
+{
+    VARIANT vtIp;
+    HRESULT hr;
+    VariantInit(&vtIp);
+
+    *pIpv4 = 0;
+    *pMaskv4 = 0;
+
+    hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
+    if(SUCCEEDED(hr))
+    {
+        if(vtIp.vt == (VT_ARRAY | VT_BSTR))
+        {
+            VARIANT vtMask;
+            VariantInit(&vtMask);
+            hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
+            if(SUCCEEDED(hr))
+            {
+                if(vtMask.vt == (VT_ARRAY | VT_BSTR))
+                {
+                    SAFEARRAY * pIpArray = vtIp.parray;
+                    SAFEARRAY * pMaskArray = vtMask.parray;
+                    if(pIpArray && pMaskArray)
+                    {
+                        BSTR pCurIp;
+                        BSTR pCurMask;
+                        for(long index = 0;
+                            SafeArrayGetElement(pIpArray, &index, (PVOID)&pCurIp) == S_OK
+                            && SafeArrayGetElement(pMaskArray, &index, (PVOID)&pCurMask) == S_OK;
+                            index++)
+                        {
+                            _bstr_t ip(pCurIp);
+
+                            ULONG Ipv4 = inet_addr((char*)(ip));
+                            if(Ipv4 != INADDR_NONE)
+                            {
+                                *pIpv4 = Ipv4;
+                                _bstr_t mask(pCurMask);
+                                *pMaskv4 = inet_addr((char*)(mask));
+                                break;
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    *pIpv4 = 0;
+                    *pMaskv4 = 0;
+                }
+
+                VariantClear(&vtMask);
+            }
+        }
+        else
+        {
+            *pIpv4 = 0;
+            *pMaskv4 = 0;
+        }
+
+        VariantClear(&vtIp);
+    }
+
+    return hr;
+}
+
+
+static HRESULT netIfWinHasIpSettings(IWbemClassObject * pAdapterConfig, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, bool *pFound)
+{
+    VARIANT vtIp;
+    HRESULT hr;
+    VariantInit(&vtIp);
+
+    *pFound = false;
+
+    hr = pAdapterConfig->Get(L"IPAddress", 0, &vtIp, 0, 0);
+    if(SUCCEEDED(hr))
+    {
+        VARIANT vtMask;
+        VariantInit(&vtMask);
+        hr = pAdapterConfig->Get(L"IPSubnet", 0, &vtMask, 0, 0);
+        if(SUCCEEDED(hr))
+        {
+            SAFEARRAY * pIpArray = vtIp.parray;
+            SAFEARRAY * pMaskArray = vtMask.parray;
+            if(pIpArray && pMaskArray)
+            {
+                BSTR pIp, pMask;
+                for(long k = 0;
+                    SafeArrayGetElement(pCheckIp, &k, (PVOID)&pIp) == S_OK
+                    && SafeArrayGetElement(pCheckMask, &k, (PVOID)&pMask) == S_OK;
+                    k++)
+                {
+                    BSTR pCurIp;
+                    BSTR pCurMask;
+                    for(long index = 0;
+                        SafeArrayGetElement(pIpArray, &index, (PVOID)&pCurIp) == S_OK
+                        && SafeArrayGetElement(pMaskArray, &index, (PVOID)&pCurMask) == S_OK;
+                        index++)
+                    {
+                        if(!wcsicmp(pCurIp, pIp))
+                        {
+                            if(!wcsicmp(pCurMask, pMask))
+                            {
+                                *pFound = true;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+
+
+            VariantClear(&vtMask);
+        }
+
+        VariantClear(&vtIp);
+    }
+
+    return hr;
+}
+
+static HRESULT netIfWinWaitIpSettings(IWbemServices *pSvc, const GUID * pGuid, SAFEARRAY * pCheckIp, SAFEARRAY * pCheckMask, ULONG sec2Wait, bool *pFound)
+{
+    /* on Vista we need to wait for the address to get applied */
+    /* wait for the address to appear in the list */
+    HRESULT hr = S_OK;
+    ULONG i;
+    *pFound = false;
+    ComPtr <IWbemClassObject> pAdapterConfig;
+    for(i = 0;
+            (hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam())) == S_OK
+            && (hr = netIfWinHasIpSettings(pAdapterConfig, pCheckIp, pCheckMask, pFound)) == S_OK
+            && !(*pFound)
+            && i < sec2Wait/6;
+            i++)
+    {
+        Sleep(6000);
+    }
+
+    return hr;
+}
+
+static HRESULT netIfWinCreateIWbemServices(IWbemServices ** ppSvc)
+{
+    HRESULT hres;
+
+    // Step 3: ---------------------------------------------------
+    // Obtain the initial locator to WMI -------------------------
+
+    IWbemLocator *pLoc = NULL;
+
+    hres = CoCreateInstance(
+        CLSID_WbemLocator,
+        0,
+        CLSCTX_INPROC_SERVER,
+        IID_IWbemLocator, (LPVOID *) &pLoc);
+    if(SUCCEEDED(hres))
+    {
+        // Step 4: -----------------------------------------------------
+        // Connect to WMI through the IWbemLocator::ConnectServer method
+
+        IWbemServices *pSvc = NULL;
+
+        // Connect to the root\cimv2 namespace with
+        // the current user and obtain pointer pSvc
+        // to make IWbemServices calls.
+        hres = pLoc->ConnectServer(
+             _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
+             NULL,                    // User name. NULL = current user
+             NULL,                    // User password. NULL = current
+             0,                       // Locale. NULL indicates current
+             NULL,                    // Security flags.
+             0,                       // Authority (e.g. Kerberos)
+             0,                       // Context object
+             &pSvc                    // pointer to IWbemServices proxy
+             );
+        if(SUCCEEDED(hres))
+        {
+            Log(L"Connected to ROOT\\CIMV2 WMI namespace\n");
+
+            // Step 5: --------------------------------------------------
+            // Set security levels on the proxy -------------------------
+
+            hres = CoSetProxyBlanket(
+               pSvc,                        // Indicates the proxy to set
+               RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
+               RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
+               NULL,                        // Server principal name
+               RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx
+               RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
+               NULL,                        // client identity
+               EOAC_NONE                    // proxy capabilities
+            );
+            if(SUCCEEDED(hres))
+            {
+                *ppSvc = pSvc;
+                /* do not need it any more */
+                pLoc->Release();
+                return hres;
+            }
+            else
+            {
+                Log(L"Could not set proxy blanket. Error code = 0x%x\n", hres);
+            }
+
+            pSvc->Release();
+        }
+        else
+        {
+            Log(L"Could not connect. Error code = 0x%x\n", hres);
+        }
+
+        pLoc->Release();
+    }
+    else
+    {
+        Log(L"Failed to create IWbemLocator object. Err code = 0x%x\n", hres);
+//        CoUninitialize();
+    }
+
+    return hres;
+}
+
+static HRESULT netIfWinAdapterConfigPath(IWbemClassObject *pObj, BSTR * pStr)
+{
+    VARIANT index;
+
+    // Get the value of the key property
+    HRESULT hr = pObj->Get(L"Index", 0, &index, 0, 0);
+    if(SUCCEEDED(hr))
+    {
+        WCHAR strIndex[8];
+        swprintf(strIndex, L"%u", index.uintVal);
+        *pStr = (bstr_t(L"Win32_NetworkAdapterConfiguration.Index='") + strIndex + "'").copy();
+    }
+    else
+    {
+        DWORD dwError = GetLastError();
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+    return hr;
+}
+
+static HRESULT netIfExecMethod(IWbemServices * pSvc, IWbemClassObject *pClass, BSTR ObjPath,
+        BSTR MethodName, LPWSTR *pArgNames, LPVARIANT *pArgs, UINT cArgs,
+        IWbemClassObject** ppOutParams
+        )
+{
+    HRESULT hres = S_OK;
+    // Step 6: --------------------------------------------------
+    // Use the IWbemServices pointer to make requests of WMI ----
+
+    ComPtr<IWbemClassObject> pInParamsDefinition;
+    ComPtr<IWbemClassObject> pClassInstance;
+
+    if(cArgs)
+    {
+        hres = pClass->GetMethod(MethodName, 0,
+            pInParamsDefinition.asOutParam(), NULL);
+        if(SUCCEEDED(hres))
+        {
+            hres = pInParamsDefinition->SpawnInstance(0, pClassInstance.asOutParam());
+
+            if(SUCCEEDED(hres))
+            {
+                for(UINT i = 0; i < cArgs; i++)
+                {
+                    // Store the value for the in parameters
+                    hres = pClassInstance->Put(pArgNames[i], 0,
+                        pArgs[i], 0);
+                    if(FAILED(hres))
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    if(SUCCEEDED(hres))
+    {
+        IWbemClassObject* pOutParams = NULL;
+        hres = pSvc->ExecMethod(ObjPath, MethodName, 0,
+                        NULL, pClassInstance, &pOutParams, NULL);
+        if(SUCCEEDED(hres))
+        {
+            *ppOutParams = pOutParams;
+        }
+    }
+
+    return hres;
+}
+
+static HRESULT netIfWinCreateIpArray(SAFEARRAY **ppArray, in_addr* aIp, UINT cIp)
+{
+    HRESULT hr;
+    SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, cIp);
+    if(pIpArray)
+    {
+        for(UINT i = 0; i < cIp; i++)
+        {
+            char* addr = inet_ntoa(aIp[i]);
+            BSTR val = bstr_t(addr).copy();
+            long aIndex[1];
+            aIndex[0] = i;
+            hr = SafeArrayPutElement(pIpArray, aIndex, val);
+            if(FAILED(hr))
+            {
+                SysFreeString(val);
+                SafeArrayDestroy(pIpArray);
+                break;
+            }
+        }
+
+        if(SUCCEEDED(hr))
+        {
+            *ppArray = pIpArray;
+        }
+    }
+    else
+    {
+        DWORD dwError = GetLastError();
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+
+    return hr;
+}
+
+static HRESULT netIfWinCreateIpArrayV4V6(SAFEARRAY **ppArray, BSTR Ip)
+{
+    HRESULT hr;
+    SAFEARRAY * pIpArray = SafeArrayCreateVector(VT_BSTR, 0, 1);
+    if(pIpArray)
+    {
+        BSTR val = bstr_t(Ip, false).copy();
+        long aIndex[1];
+        aIndex[0] = 0;
+        hr = SafeArrayPutElement(pIpArray, aIndex, val);
+        if(FAILED(hr))
+        {
+            SysFreeString(val);
+            SafeArrayDestroy(pIpArray);
+        }
+
+        if(SUCCEEDED(hr))
+        {
+            *ppArray = pIpArray;
+        }
+    }
+    else
+    {
+        DWORD dwError = GetLastError();
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+
+    return hr;
+}
+
+
+static HRESULT netIfWinCreateIpArrayVariantV4(VARIANT * pIpAddresses, in_addr* aIp, UINT cIp)
+{
+    HRESULT hr;
+    VariantInit(pIpAddresses);
+    pIpAddresses->vt = VT_ARRAY | VT_BSTR;
+    SAFEARRAY *pIpArray;
+    hr = netIfWinCreateIpArray(&pIpArray, aIp, cIp);
+    if(SUCCEEDED(hr))
+    {
+        pIpAddresses->parray = pIpArray;
+    }
+    return hr;
+}
+
+static HRESULT netIfWinCreateIpArrayVariantV4V6(VARIANT * pIpAddresses, BSTR Ip)
+{
+    HRESULT hr;
+    VariantInit(pIpAddresses);
+    pIpAddresses->vt = VT_ARRAY | VT_BSTR;
+    SAFEARRAY *pIpArray;
+    hr = netIfWinCreateIpArrayV4V6(&pIpArray, Ip);
+    if(SUCCEEDED(hr))
+    {
+        pIpAddresses->parray = pIpArray;
+    }
+    return hr;
+}
+
+static HRESULT netIfWinEnableStatic(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, VARIANT * pIp, VARIANT * pMask)
+{
+    ComPtr<IWbemClassObject> pClass;
+    BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
+    HRESULT hr;
+    if(ClassName)
+    {
+        hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
+        if(SUCCEEDED(hr))
+        {
+            LPWSTR argNames[] = {L"IPAddress", L"SubnetMask"};
+            LPVARIANT args[] = {pIp, pMask};
+            ComPtr<IWbemClassObject> pOutParams;
+
+            hr = netIfExecMethod(pSvc, pClass, ObjPath,
+                                bstr_t(L"EnableStatic"), argNames, args, 2, pOutParams.asOutParam());
+            if(SUCCEEDED(hr))
+            {
+                VARIANT varReturnValue;
+                hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
+                    &varReturnValue, NULL, 0);
+                Assert(SUCCEEDED(hr));
+                if(SUCCEEDED(hr))
+                {
+//                    Assert(varReturnValue.vt == VT_UINT);
+                    int winEr = varReturnValue.uintVal;
+                    switch(winEr)
+                    {
+                    case 0:
+                        {
+                            hr = S_OK;
+//                            bool bFound;
+//                            HRESULT tmpHr = netIfWinWaitIpSettings(pSvc, pGuid, pIp->parray, pMask->parray, 180, &bFound);
+                        }
+                        break;
+                    default:
+                        hr = HRESULT_FROM_WIN32( winEr );
+                        break;
+                    }
+                }
+            }
+        }
+        SysFreeString(ClassName);
+    }
+    else
+    {
+        DWORD dwError = GetLastError();
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+
+    return hr;
+}
+
+
+static HRESULT netIfWinEnableStaticV4(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, in_addr* aIp, in_addr * aMask, UINT cIp)
+{
+    VARIANT ipAddresses;
+    HRESULT hr = netIfWinCreateIpArrayVariantV4(&ipAddresses, aIp, cIp);
+    if(SUCCEEDED(hr))
+    {
+        VARIANT ipMasks;
+        hr = netIfWinCreateIpArrayVariantV4(&ipMasks, aMask, cIp);
+        if(SUCCEEDED(hr))
+        {
+            hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
+            VariantClear(&ipMasks);
+        }
+        VariantClear(&ipAddresses);
+    }
+    return hr;
+}
+
+static HRESULT netIfWinEnableStaticV4V6(IWbemServices * pSvc, const GUID * pGuid, BSTR ObjPath, BSTR Ip, BSTR Mask)
+{
+    VARIANT ipAddresses;
+    HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&ipAddresses, Ip);
+    if(SUCCEEDED(hr))
+    {
+        VARIANT ipMasks;
+        hr = netIfWinCreateIpArrayVariantV4V6(&ipMasks, Mask);
+        if(SUCCEEDED(hr))
+        {
+            hr = netIfWinEnableStatic(pSvc, pGuid, ObjPath, &ipAddresses, &ipMasks);
+            VariantClear(&ipMasks);
+        }
+        VariantClear(&ipAddresses);
+    }
+    return hr;
+}
+
+/* win API allows to set gw metrics as well, we are not setting them */
+static HRESULT netIfWinSetGateways(IWbemServices * pSvc, BSTR ObjPath, VARIANT * pGw)
+{
+    ComPtr<IWbemClassObject> pClass;
+    BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
+    HRESULT hr;
+    if(ClassName)
+    {
+        hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
+        if(SUCCEEDED(hr))
+        {
+            LPWSTR argNames[] = {L"DefaultIPGateway"};
+            LPVARIANT args[] = {pGw};
+            ComPtr<IWbemClassObject> pOutParams;
+
+            hr = netIfExecMethod(pSvc, pClass, ObjPath,
+                                bstr_t(L"SetGateways"), argNames, args, 1, pOutParams.asOutParam());
+            if(SUCCEEDED(hr))
+            {
+                VARIANT varReturnValue;
+                hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
+                    &varReturnValue, NULL, 0);
+                Assert(SUCCEEDED(hr));
+                if(SUCCEEDED(hr))
+                {
+//                    Assert(varReturnValue.vt == VT_UINT);
+                    int winEr = varReturnValue.uintVal;
+                    switch(winEr)
+                    {
+                    case 0:
+                        hr = S_OK;
+                        break;
+                    default:
+                        hr = HRESULT_FROM_WIN32( winEr );
+                        break;
+                    }
+                }
+            }        }
+        SysFreeString(ClassName);
+    }
+    else
+    {
+        DWORD dwError = GetLastError();
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+
+    return hr;
+}
+
+/* win API allows to set gw metrics as well, we are not setting them */
+static HRESULT netIfWinSetGatewaysV4(IWbemServices * pSvc, BSTR ObjPath, in_addr* aGw, UINT cGw)
+{
+    VARIANT gwais;
+    HRESULT hr = netIfWinCreateIpArrayVariantV4(&gwais, aGw, cGw);
+    if(SUCCEEDED(hr))
+    {
+        netIfWinSetGateways(pSvc, ObjPath, &gwais);
+        VariantClear(&gwais);
+    }
+    return hr;
+}
+
+/* win API allows to set gw metrics as well, we are not setting them */
+static HRESULT netIfWinSetGatewaysV4V6(IWbemServices * pSvc, BSTR ObjPath, BSTR Gw)
+{
+    VARIANT vGw;
+    HRESULT hr = netIfWinCreateIpArrayVariantV4V6(&vGw, Gw);
+    if(SUCCEEDED(hr))
+    {
+        netIfWinSetGateways(pSvc, ObjPath, &vGw);
+        VariantClear(&vGw);
+    }
+    return hr;
+}
+
+static HRESULT netIfWinEnableDHCP(IWbemServices * pSvc, BSTR ObjPath)
+{
+    ComPtr<IWbemClassObject> pClass;
+    BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
+    HRESULT hr;
+    if(ClassName)
+    {
+        hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
+        if(SUCCEEDED(hr))
+        {
+            ComPtr<IWbemClassObject> pOutParams;
+
+            hr = netIfExecMethod(pSvc, pClass, ObjPath,
+                                bstr_t(L"EnableDHCP"), NULL, NULL, 0, pOutParams.asOutParam());
+            if(SUCCEEDED(hr))
+            {
+                VARIANT varReturnValue;
+                hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
+                    &varReturnValue, NULL, 0);
+                Assert(SUCCEEDED(hr));
+                if(SUCCEEDED(hr))
+                {
+//                    Assert(varReturnValue.vt == VT_UINT);
+                    int winEr = varReturnValue.uintVal;
+                    switch(winEr)
+                    {
+                    case 0:
+                        hr = S_OK;
+                        break;
+                    default:
+                        hr = HRESULT_FROM_WIN32( winEr );
+                        break;
+                    }
+                }
+            }
+        }
+        SysFreeString(ClassName);
+    }
+    else
+    {
+        DWORD dwError = GetLastError();
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+
+    return hr;
+}
+
+static HRESULT netIfWinDhcpRediscover(IWbemServices * pSvc, BSTR ObjPath)
+{
+    ComPtr<IWbemClassObject> pClass;
+    BSTR ClassName = SysAllocString(L"Win32_NetworkAdapterConfiguration");
+    HRESULT hr;
+    if(ClassName)
+    {
+        hr = pSvc->GetObject(ClassName, 0, NULL, pClass.asOutParam(), NULL);
+        if(SUCCEEDED(hr))
+        {
+            ComPtr<IWbemClassObject> pOutParams;
+
+            hr = netIfExecMethod(pSvc, pClass, ObjPath,
+                                bstr_t(L"ReleaseDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
+            if(SUCCEEDED(hr))
+            {
+                VARIANT varReturnValue;
+                hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
+                    &varReturnValue, NULL, 0);
+                Assert(SUCCEEDED(hr));
+                if(SUCCEEDED(hr))
+                {
+//                    Assert(varReturnValue.vt == VT_UINT);
+                    int winEr = varReturnValue.uintVal;
+                    if(winEr == 0)
+                    {
+                        hr = netIfExecMethod(pSvc, pClass, ObjPath,
+                                            bstr_t(L"RenewDHCPLease"), NULL, NULL, 0, pOutParams.asOutParam());
+                        if(SUCCEEDED(hr))
+                        {
+                            VARIANT varReturnValue;
+                            hr = pOutParams->Get(bstr_t(L"ReturnValue"), 0,
+                                &varReturnValue, NULL, 0);
+                            Assert(SUCCEEDED(hr));
+                            if(SUCCEEDED(hr))
+                            {
+            //                    Assert(varReturnValue.vt == VT_UINT);
+                                int winEr = varReturnValue.uintVal;
+                                if(winEr == 0)
+                                {
+                                    hr = S_OK;
+                                }
+                                else
+                                {
+                                    hr = HRESULT_FROM_WIN32( winEr );
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        hr = HRESULT_FROM_WIN32( winEr );
+                    }
+                }
+            }
+        }
+        SysFreeString(ClassName);
+    }
+    else
+    {
+        DWORD dwError = GetLastError();
+        Assert(0);
+        hr = HRESULT_FROM_WIN32( dwError );
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetCfgWinIsDhcpEnabled(IWbemClassObject * pAdapterConfig, BOOL *pEnabled)
+{
+    VARIANT vtEnabled;
+    HRESULT hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
+    if(SUCCEEDED(hr))
+    {
+        *pEnabled = vtEnabled.boolVal;
+    }
+    return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(const GUID * pGuid, PADAPTER_SETTINGS pSettings)
+{
+    HRESULT hr;
+    ComPtr <IWbemServices> pSvc;
+    hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+    if(SUCCEEDED(hr))
+    {
+        ComPtr <IWbemClassObject> pAdapterConfig;
+        hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+        if(hr == S_OK)
+        {
+            hr = vboxNetCfgWinIsDhcpEnabled(pAdapterConfig, &pSettings->bDhcp);
+            if(SUCCEEDED(hr))
+            {
+                hr = netIfWinGetIpSettings(pAdapterConfig, &pSettings->ip, &pSettings->mask);
+            }
+        }
+    }
+
+    return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinIsDhcpEnabled(const GUID * pGuid, BOOL *pEnabled)
+{
+    HRESULT hr;
+        ComPtr <IWbemServices> pSvc;
+        hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+        if(SUCCEEDED(hr))
+        {
+            ComPtr <IWbemClassObject> pAdapterConfig;
+            hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+            if(hr == S_OK)
+            {
+                VARIANT vtEnabled;
+                hr = pAdapterConfig->Get(L"DHCPEnabled", 0, &vtEnabled, 0, 0);
+                if(SUCCEEDED(hr))
+                {
+                    *pEnabled = vtEnabled.boolVal;
+                }
+            }
+        }
+
+    return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(const GUID *pGuid, ULONG ip, ULONG mask)
+{
+    HRESULT hr;
+        ComPtr <IWbemServices> pSvc;
+        hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+        if(SUCCEEDED(hr))
+        {
+            ComPtr <IWbemClassObject> pAdapterConfig;
+            hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+            if(hr == S_OK)
+            {
+                BOOL bIsHostOnly;
+                hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
+                if(SUCCEEDED(hr))
+                {
+                    if(bIsHostOnly)
+                    {
+                        in_addr aIp[1];
+                        in_addr aMask[1];
+                        aIp[0].S_un.S_addr = ip;
+                        aMask[0].S_un.S_addr = mask;
+
+                        BSTR ObjPath;
+                        hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+                        if(SUCCEEDED(hr))
+                        {
+                            hr = netIfWinEnableStaticV4(pSvc, pGuid, ObjPath, aIp, aMask, ip != 0 ? 1 : 0);
+                            if(SUCCEEDED(hr))
+                            {
+#if 0
+                                in_addr aGw[1];
+                                aGw[0].S_un.S_addr = gw;
+                                hr = netIfWinSetGatewaysV4(pSvc, ObjPath, aGw, 1);
+                                if(SUCCEEDED(hr))
+#endif
+                                {
+                                }
+                            }
+                            SysFreeString(ObjPath);
+                        }
+                    }
+                    else
+                    {
+                        hr = E_FAIL;
+                    }
+                }
+            }
+        }
+
+    return hr;
+}
+
+#if 0
+static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, IN_BSTR aIPV6Mask, IN_BSTR aIPV6DefaultGateway)
+{
+    HRESULT hr;
+        ComPtr <IWbemServices> pSvc;
+        hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+        if(SUCCEEDED(hr))
+        {
+            ComPtr <IWbemClassObject> pAdapterConfig;
+            hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+            if(hr == S_OK)
+            {
+                BSTR ObjPath;
+                hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+                if(SUCCEEDED(hr))
+                {
+                    hr = netIfWinEnableStaticV4V6(pSvc, pAdapterConfig, ObjPath, aIPV6Address, aIPV6Mask);
+                    if(SUCCEEDED(hr))
+                    {
+                        if(aIPV6DefaultGateway)
+                        {
+                            hr = netIfWinSetGatewaysV4V6(pSvc, ObjPath, aIPV6DefaultGateway);
+                        }
+                        if(SUCCEEDED(hr))
+                        {
+//                            hr = netIfWinUpdateConfig(pIf);
+                        }
+                    }
+                    SysFreeString(ObjPath);
+                }
+            }
+        }
+
+    return SUCCEEDED(hr) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
+}
+
+static HRESULT netIfEnableStaticIpConfigV6(const GUID *pGuid, IN_BSTR aIPV6Address, ULONG aIPV6MaskPrefixLength)
+{
+    RTNETADDRIPV6 Mask;
+    int rc = prefixLength2IPv6Address(aIPV6MaskPrefixLength, &Mask);
+    if(RT_SUCCESS(rc))
+    {
+        Bstr maskStr = composeIPv6Address(&Mask);
+        rc = netIfEnableStaticIpConfigV6(pGuid, aIPV6Address, maskStr, NULL);
+    }
+    return rc;
+}
+#endif
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(const GUID *pGuid)
+{
+    HRESULT hr;
+        ComPtr <IWbemServices> pSvc;
+        hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+        if(SUCCEEDED(hr))
+        {
+            ComPtr <IWbemClassObject> pAdapterConfig;
+            hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+            if(hr == S_OK)
+            {
+                BOOL bIsHostOnly;
+                hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
+                if(SUCCEEDED(hr))
+                {
+                    if(bIsHostOnly)
+                    {
+                        BSTR ObjPath;
+                        hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+                        if(SUCCEEDED(hr))
+                        {
+                            hr = netIfWinEnableDHCP(pSvc, ObjPath);
+                            if(SUCCEEDED(hr))
+                            {
+//                              hr = netIfWinUpdateConfig(pIf);
+                            }
+                            SysFreeString(ObjPath);
+                        }
+                    }
+                    else
+                    {
+                        hr = E_FAIL;
+                    }
+                }
+            }
+        }
+
+
+    return hr;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(const GUID *pGuid)
+{
+    HRESULT hr;
+        ComPtr <IWbemServices> pSvc;
+        hr = netIfWinCreateIWbemServices(pSvc.asOutParam());
+        if(SUCCEEDED(hr))
+        {
+            ComPtr <IWbemClassObject> pAdapterConfig;
+            hr = netIfWinFindAdapterClassById(pSvc, pGuid, pAdapterConfig.asOutParam());
+            if(hr == S_OK)
+            {
+                BOOL bIsHostOnly;
+                hr = netIfWinIsHostOnly(pAdapterConfig, &bIsHostOnly);
+                if(SUCCEEDED(hr))
+                {
+                    if(bIsHostOnly)
+                    {
+                        BSTR ObjPath;
+                        hr = netIfWinAdapterConfigPath(pAdapterConfig, &ObjPath);
+                        if(SUCCEEDED(hr))
+                        {
+                            hr = netIfWinDhcpRediscover(pSvc, ObjPath);
+                            if(SUCCEEDED(hr))
+                            {
+//                        hr = netIfWinUpdateConfig(pIf);
+                            }
+                            SysFreeString(ObjPath);
+                        }
+                    }
+                    else
+                    {
+                        hr = E_FAIL;
+                    }
+                }
+            }
+        }
+
+
+    return hr;
+}
+
+typedef bool (*IPSETTINGS_CALLBACK) (ULONG ip, ULONG mask, PVOID pContext);
+
+static void vboxNetCfgWinEnumIpConfig(PIP_ADAPTER_ADDRESSES pAddresses, IPSETTINGS_CALLBACK pCallback, PVOID pContext)
+{
+    PIP_ADAPTER_ADDRESSES pAdapter;
+    for (pAdapter = pAddresses; pAdapter; pAdapter = pAdapter->Next)
+    {
+        PIP_ADAPTER_UNICAST_ADDRESS pAddr = pAdapter->FirstUnicastAddress;
+        PIP_ADAPTER_PREFIX pPrefix = pAdapter->FirstPrefix;
+
+        if(pAddr && pPrefix)
+        {
+            do
+            {
+                bool fIPFound, fMaskFound;
+                fIPFound = fMaskFound = false;
+                ULONG ip, mask;
+                for (; pAddr && !fIPFound; pAddr = pAddr->Next)
+                {
+                    switch (pAddr->Address.lpSockaddr->sa_family)
+                    {
+                        case AF_INET:
+                            fIPFound = true;
+                            memcpy(&ip,
+                                    &((struct sockaddr_in *)pAddr->Address.lpSockaddr)->sin_addr.s_addr,
+                                    sizeof(ip));
+                            break;
+//                            case AF_INET6:
+//                                break;
+                    }
+                }
+
+                for (; pPrefix && !fMaskFound; pPrefix = pPrefix->Next)
+                {
+                    switch (pPrefix->Address.lpSockaddr->sa_family)
+                    {
+                        case AF_INET:
+                            if(!pPrefix->PrefixLength || pPrefix->PrefixLength > 31) /* in case the ip helper API is queried while NetCfg write lock is held */
+                                break;                                               /* the address values can contain illegal values */
+                            fMaskFound = true;
+                            mask = (~(((ULONG)~0) >> pPrefix->PrefixLength));
+                            mask = htonl(mask);
+                            break;
+//                            case AF_INET6:
+//                                break;
+                    }
+                }
+
+                if(!fIPFound || !fMaskFound)
+                    break;
+
+                if(!pCallback(ip, mask, pContext))
+                    return;
+            }while(true);
+        }
+    }
+}
+
+typedef struct _IPPROBE_CONTEXT
+{
+    ULONG Prefix;
+    bool bConflict;
+}IPPROBE_CONTEXT, *PIPPROBE_CONTEXT;
+
+#define IPPROBE_INIT(_pContext, _addr) \
+    ((_pContext)->bConflict = false, \
+     (_pContext)->Prefix = _addr)
+
+#define IPPROBE_INIT_STR(_pContext, _straddr) \
+    IPROBE_INIT(_pContext, inet_addr(_straddr))
+
+static bool vboxNetCfgWinIpProbeCallback (ULONG ip, ULONG mask, PVOID pContext)
+{
+    PIPPROBE_CONTEXT pProbe = (PIPPROBE_CONTEXT)pContext;
+
+    if((ip & mask) == (pProbe->Prefix & mask))
+    {
+        pProbe->bConflict = true;
+        return false;
+    }
+
+    return true;
+}
+
+VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(PULONG pNetIp, PULONG pNetMask)
+{
+    DWORD dwRc;
+    HRESULT hr = S_OK;
+    /*
+     * Most of the hosts probably have less than 10 adapters,
+     * so we'll mostly succeed from the first attempt.
+     */
+    ULONG uBufLen = sizeof(IP_ADAPTER_ADDRESSES) * 10;
+    PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
+    if (!pAddresses)
+        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+    dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
+    if (dwRc == ERROR_BUFFER_OVERFLOW)
+    {
+        /* Impressive! More than 10 adapters! Get more memory and try again. */
+        free(pAddresses);
+        pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(uBufLen);
+        if (!pAddresses)
+            return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+        dwRc = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &uBufLen);
+    }
+    if (dwRc == NO_ERROR)
+    {
+        IPPROBE_CONTEXT Context;
+        const ULONG ip192168 = inet_addr("192.168.0.0");
+        srand(GetTickCount());
+
+        *pNetIp = 0;
+        *pNetMask = 0;
+
+        for(int i = 0; i < 255; i++)
+        {
+            ULONG ipProbe = rand()*255/RAND_MAX;
+            ipProbe = ip192168 | (ipProbe << 16);
+            IPPROBE_INIT(&Context, ipProbe);
+            vboxNetCfgWinEnumIpConfig(pAddresses, vboxNetCfgWinIpProbeCallback, &Context);
+            if(!Context.bConflict)
+            {
+                *pNetIp = ipProbe;
+                *pNetMask = inet_addr("255.255.255.0");
+                break;
+            }
+        }
+        if(*pNetIp == 0)
+            dwRc = ERROR_DHCP_ADDRESS_CONFLICT;
+    }
+    else
+    {
+        Log(L"VBoxNetCfgWinGenHostOnlyNetworkNetworkIp: GetAdaptersAddresses err (%d)\n", dwRc);
+    }
+    free(pAddresses);
+
+    if(dwRc != NO_ERROR)
+    {
+        hr = HRESULT_FROM_WIN32(dwRc);
+    }
+
+    return hr;
+}
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.cpp
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.cpp	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.cpp	(revision 21333)
@@ -0,0 +1,766 @@
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Sample Notify Object
+ *+---------------------------------------------------------------------------
+ *
+ *  Microsoft Windows
+ *  Copyright (C) Microsoft Corporation, 1992-2001.
+ *
+ *  Author:     Alok Sinha
+ *
+ *----------------------------------------------------------------------------
+ */
+#include "VBoxNetFltNotify.h"
+#include <Ntddndis.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include <VBoxNetFltNotifyn_i.c>
+
+CComModule _Module;
+
+BEGIN_OBJECT_MAP(ObjectMap)
+    OBJECT_ENTRY(CLSID_VBoxNetFltNotify, VBoxNetFltNotify)
+END_OBJECT_MAP()
+
+#define ReleaseObj( x )  if ( x ) \
+                            ((IUnknown*)(x))->Release();
+
+//# define VBOXNETFLTNOTIFY_DEBUG_BIND true
+
+#ifdef DEBUG
+# define Assert(a) assert(a)
+# define AssertBreakpoint() assert(0)
+
+# define TraceMsg DbgTraceMsg
+#else
+# define Assert(a) do{}while(0)
+# define AssertBreakpoint() do{}while(0)
+
+# define TraceMsg
+#endif
+
+
+static void DbgTraceMsg (LPWSTR szFormat, ...)
+{
+    static WCHAR szTempBuf[4096];
+
+    va_list arglist;
+
+    va_start(arglist, szFormat);
+
+    vswprintf( szTempBuf, szFormat, arglist );
+
+    OutputDebugStringW( szTempBuf );
+
+    va_end(arglist);
+}
+
+VBoxNetFltNotify::VBoxNetFltNotify (VOID) : m_pncc (NULL),
+                                m_pnc(NULL)
+                                /*,
+                                m_eApplyAction(eActUnknown),
+                                m_pUnkContext(NULL)*/
+{
+    TraceMsg(L"VBoxNetFltNotify\n");
+}
+
+VBoxNetFltNotify::~VBoxNetFltNotify (VOID)
+{
+    TraceMsg(L"-->~VBoxNetFltNotify (destructor)\n");
+    ReleaseObj( m_pncc );
+    ReleaseObj( m_pnc );
+    TraceMsg(L"<--~VBoxNetFltNotify (destructor)\n");
+}
+
+/*
+ * NOTIFY OBJECT FUNCTIONS
+ */
+
+/*
+ * INetCfgComponentControl
+ *
+ * The following functions provide the INetCfgComponentControl interface.
+ */
+
+/**
+ * Initialize the notify object
+ *
+ * @param pnccItem   Pointer to INetCfgComponent object
+ * @param pnc        Pointer to INetCfg object
+ * @param fInstalling  TRUE if we are being installed
+ * @return S_OK on success, otherwise an error code
+ */
+STDMETHODIMP VBoxNetFltNotify::Initialize (INetCfgComponent* pncc,
+                                     INetCfg* pnc,
+                                     BOOL fInstalling)
+{
+    HRESULT hr = S_OK;
+
+    TraceMsg(L"-->Initialize\n");
+
+    m_pncc = pncc;
+    m_pnc = pnc;
+
+    if (m_pncc)
+    {
+        m_pncc->AddRef();
+    }
+
+    if (m_pnc)
+    {
+        m_pnc->AddRef();
+    }
+
+    TraceMsg(L"<--Initialize\n");
+
+    return hr;
+}
+
+/**
+ * Cancel any changes made to internal data
+ * @return S_OK on success, otherwise an error code
+ */
+STDMETHODIMP VBoxNetFltNotify::CancelChanges (VOID)
+{
+    TraceMsg(L"CancelChanges\n");
+    return S_OK;
+}
+
+/*
+ * Apply changes. We can make changes to registry etc. here.
+ * @return S_OK on success, otherwise an error code
+ */
+STDMETHODIMP VBoxNetFltNotify::ApplyRegistryChanges(VOID)
+{
+    TraceMsg(L"ApplyRegistryChanges\n");
+    return S_OK;
+}
+
+/**
+ * Apply changes.
+ * @param pfCallback PnPConfigCallback interface.
+ * @return S_OK on success, otherwise an error code
+ */
+STDMETHODIMP VBoxNetFltNotify::ApplyPnpChanges (
+                                       INetCfgPnpReconfigCallback* pfCallback)
+{
+    TraceMsg(L"ApplyPnpChanges\n");
+    return S_OK;
+}
+
+static HRESULT vboxNetFltWinQueryInstanceKey(IN INetCfgComponent *pComponent, OUT PHKEY phKey)
+{
+    LPWSTR pPnpId;
+    HRESULT hr = pComponent->GetPnpDevNodeId(&pPnpId);
+    if(hr == S_OK)
+    {
+        WCHAR KeyName[MAX_PATH];
+        wcscpy(KeyName, L"SYSTEM\\CurrentControlSet\\Enum\\");
+        wcscat(KeyName,pPnpId);
+
+        LONG winEr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyName,
+          0, /*__reserved  DWORD ulOptions*/
+          KEY_READ, /*__in        REGSAM samDesired*/
+          phKey);
+
+        if(winEr != ERROR_SUCCESS)
+        {
+            hr = HRESULT_FROM_WIN32(winEr);
+            TraceMsg(L"vboxNetFltWinQueryInstanceKey: RegOpenKeyExW error, hr (0x%x)\n", hr);
+            AssertBreakpoint();
+        }
+
+        CoTaskMemFree(pPnpId);
+    }
+    else
+    {
+        TraceMsg(L"vboxNetFltWinQueryInstanceKey: GetPnpDevNodeId error, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetFltWinQueryDriverKey(IN HKEY InstanceKey, OUT PHKEY phKey)
+{
+    DWORD Type = REG_SZ;
+    WCHAR Value[MAX_PATH];
+    DWORD cbValue = sizeof(Value);
+    HRESULT hr = S_OK;
+    LONG winEr = RegQueryValueExW(InstanceKey,
+            L"Driver", /*__in_opt     LPCTSTR lpValueName*/
+            0, /*__reserved   LPDWORD lpReserved*/
+            &Type, /*__out_opt    LPDWORD lpType*/
+            (LPBYTE)Value, /*__out_opt    LPBYTE lpData*/
+            &cbValue/*__inout_opt  LPDWORD lpcbData*/
+            );
+
+    if(winEr == ERROR_SUCCESS)
+    {
+        WCHAR KeyName[MAX_PATH];
+        wcscpy(KeyName, L"SYSTEM\\CurrentControlSet\\Control\\Class\\");
+        wcscat(KeyName,Value);
+
+        winEr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KeyName,
+          0, /*__reserved  DWORD ulOptions*/
+          KEY_READ, /*__in        REGSAM samDesired*/
+          phKey);
+
+        if(winEr != ERROR_SUCCESS)
+        {
+            hr = HRESULT_FROM_WIN32(winEr);
+            TraceMsg(L"vboxNetFltWinQueryDriverKey from instance key: RegOpenKeyExW error, hr (0x%x)\n", hr);
+            AssertBreakpoint();
+        }
+    }
+    else
+    {
+        hr = HRESULT_FROM_WIN32(winEr);
+        TraceMsg(L"vboxNetFltWinQueryDriverKey from instance key: RegQueryValueExW error, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetFltWinQueryDriverKey(IN INetCfgComponent *pComponent, OUT PHKEY phKey)
+{
+    HKEY InstanceKey;
+    HRESULT hr = vboxNetFltWinQueryInstanceKey(pComponent, &InstanceKey);
+    if(hr == S_OK)
+    {
+        hr = vboxNetFltWinQueryDriverKey(InstanceKey, phKey);
+        if(hr != S_OK)
+        {
+            TraceMsg(L"vboxNetFltWinQueryDriverKey from Component: vboxNetFltWinQueryDriverKey error, hr (0x%x)\n", hr);
+            AssertBreakpoint();
+        }
+        RegCloseKey(InstanceKey);
+    }
+    else
+    {
+        TraceMsg(L"vboxNetFltWinQueryDriverKey from Component: vboxNetFltWinQueryInstanceKey error, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckNetAdp(IN INetCfgComponent *pComponent, OUT bool * pbShouldBind)
+{
+    HRESULT hr;
+    LPWSTR pDevId;
+    hr = pComponent->GetId(&pDevId);
+    if(hr == S_OK)
+    {
+        if(!_wcsnicmp(pDevId, L"sun_VBoxNetAdp", sizeof(L"sun_VBoxNetAdp")/2))
+        {
+            *pbShouldBind = false;
+        }
+        else
+        {
+            hr = S_FALSE;
+        }
+        CoTaskMemFree(pDevId);
+    }
+    else
+    {
+        TraceMsg(L"vboxNetFltWinNotifyCheckNetAdp: GetId failed, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckMsLoop(IN INetCfgComponent *pComponent, OUT bool * pbShouldBind)
+{
+    HRESULT hr;
+    LPWSTR pDevId;
+    hr = pComponent->GetId(&pDevId);
+    if(hr == S_OK)
+    {
+        if(!_wcsnicmp(pDevId, L"*msloop", sizeof(L"*msloop")/2))
+        {
+            /* we need to detect the medium the adapter is presenting
+             * to do that we could examine in the registry the *msloop params */
+            HKEY DriverKey;
+            hr = vboxNetFltWinQueryDriverKey(pComponent, &DriverKey);
+            if(hr == S_OK)
+            {
+                DWORD Type = REG_SZ;
+                WCHAR Value[64]; /* 2 should be enough actually, paranoid check for extra spaces */
+                DWORD cbValue = sizeof(Value);
+                LONG winEr = RegQueryValueExW(DriverKey,
+                            L"Medium", /*__in_opt     LPCTSTR lpValueName*/
+                            0, /*__reserved   LPDWORD lpReserved*/
+                            &Type, /*__out_opt    LPDWORD lpType*/
+                            (LPBYTE)Value, /*__out_opt    LPBYTE lpData*/
+                            &cbValue/*__inout_opt  LPDWORD lpcbData*/
+                            );
+                if(winEr == ERROR_SUCCESS)
+                {
+                    PWCHAR endPrt;
+                    ULONG enmMedium = wcstoul(Value,
+                       &endPrt,
+                       0 /* base*/);
+
+                    winEr = errno;
+                    if(winEr == ERROR_SUCCESS)
+                    {
+                        if(enmMedium == 0) /* 0 is Ethernet */
+                        {
+                            TraceMsg(L"vboxNetFltWinNotifyCheckMsLoop: loopback is configured as ethernet, binding\n", winEr);
+                            *pbShouldBind = true;
+                        }
+                        else
+                        {
+                            TraceMsg(L"vboxNetFltWinNotifyCheckMsLoop: loopback is configured as NOT ethernet, NOT binding\n", winEr);
+                            *pbShouldBind = false;
+                        }
+                    }
+                    else
+                    {
+                        TraceMsg(L"vboxNetFltWinNotifyCheckMsLoop: wcstoul error, winEr (%d), ignoring and binding\n", winEr);
+                        AssertBreakpoint();
+                        *pbShouldBind = true;
+                    }
+                }
+                else
+                {
+                    TraceMsg(L"vboxNetFltWinNotifyCheckMsLoop: RegQueryValueExW failed, winEr (%d), ignoring, binding\n", hr);
+                    /* TODO: we should check the default medium in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002bE10318}\<driver_id>\Ndi\Params\Medium, REG_SZ "Default" value */
+                    AssertBreakpoint();
+                    *pbShouldBind = true;
+                }
+
+                RegCloseKey(DriverKey);
+            }
+            else
+            {
+                TraceMsg(L"vboxNetFltWinNotifyCheckMsLoop: vboxNetFltWinQueryDriverKey for msloop failed, hr (0x%x)\n", hr);
+                AssertBreakpoint();
+            }
+        }
+        else
+        {
+            hr = S_FALSE;
+        }
+        CoTaskMemFree(pDevId);
+    }
+    else
+    {
+        TraceMsg(L"vboxNetFltWinNotifyCheckMsLoop: GetId failed, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetFltWinNotifyCheckLowerRange(IN INetCfgComponent *pComponent, OUT bool * pbShouldBind)
+{
+    HKEY DriverKey;
+    HKEY InterfacesKey;
+    HRESULT hr = vboxNetFltWinQueryDriverKey(pComponent, &DriverKey);
+    if(hr == S_OK)
+    {
+        LONG winEr = RegOpenKeyExW(DriverKey, L"Ndi\\Interfaces",
+                        0, /*__reserved  DWORD ulOptions*/
+                        KEY_READ, /*__in        REGSAM samDesired*/
+                        &InterfacesKey);
+        if(winEr == ERROR_SUCCESS)
+        {
+            DWORD Type = REG_SZ;
+            WCHAR Value[MAX_PATH];
+            DWORD cbValue = sizeof(Value);
+            winEr = RegQueryValueExW(InterfacesKey,
+                    L"LowerRange", /*__in_opt     LPCTSTR lpValueName*/
+                    0, /*__reserved   LPDWORD lpReserved*/
+                    &Type, /*__out_opt    LPDWORD lpType*/
+                    (LPBYTE)Value, /*__out_opt    LPBYTE lpData*/
+                    &cbValue/*__inout_opt  LPDWORD lpcbData*/
+                    );
+            if(winEr == ERROR_SUCCESS)
+            {
+                if(wcsstr(Value,L"ethernet") || wcsstr(Value, L"wan"))
+                {
+                    *pbShouldBind = true;
+                }
+                else
+                {
+                    *pbShouldBind = false;
+                }
+            }
+            else
+            {
+                /* do not set err status to it */
+                *pbShouldBind = false;
+                TraceMsg(L"vboxNetFltWinNotifyCheckLowerRange: RegQueryValueExW for LowerRange error, winEr (%d), not binding\n", winEr);
+                AssertBreakpoint();
+            }
+
+            RegCloseKey(InterfacesKey);
+        }
+        else
+        {
+            hr = HRESULT_FROM_WIN32(winEr);
+            TraceMsg(L"vboxNetFltWinNotifyCheckLowerRange: RegOpenKeyExW error, hr (0x%x)\n", hr);
+            AssertBreakpoint();
+        }
+
+        RegCloseKey(DriverKey);
+    }
+    else
+    {
+        TraceMsg(L"vboxNetFltWinNotifyShouldBind for INetCfgComponen: vboxNetFltWinQueryDriverKey failed, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    return hr;
+}
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgComponent *pComponent, OUT bool *pbShouldBind)
+{
+    TraceMsg(L"-->vboxNetFltWinNotifyShouldBind for INetCfgComponent\n");
+    DWORD  fCharacteristics;
+    HRESULT hr;
+
+    do
+    {
+        /* filter out only physical adapters */
+        hr = pComponent->GetCharacteristics(&fCharacteristics);
+        if(hr != S_OK)
+        {
+            TraceMsg(L"vboxNetFltWinNotifyShouldBind for INetCfgComponen: GetCharacteristics failed, hr (0x%x)\n", hr);
+            AssertBreakpoint();
+            break;
+        }
+
+
+        if(fCharacteristics & NCF_HIDDEN)
+        {
+            /* we are not binding to hidden adapters */
+            *pbShouldBind = false;
+            break;
+        }
+
+        hr = vboxNetFltWinNotifyCheckMsLoop(pComponent, pbShouldBind);
+        if(hr == S_OK)
+        {
+            /* this is a loopback adapter,
+             * the pbShouldBind already contains the result */
+            break;
+        }
+        else if(hr != S_FALSE)
+        {
+            /* error occurred */
+            break;
+        }
+
+        hr = vboxNetFltWinNotifyCheckNetAdp(pComponent, pbShouldBind);
+        if(hr == S_OK)
+        {
+            /* this is a VBoxNetAdp adapter,
+             * the pbShouldBind already contains the result */
+            break;
+        }
+        else if(hr != S_FALSE)
+        {
+            /* error occurred */
+            break;
+        }
+
+        /* hr == S_FALSE means this is not a loopback adpater, set it to S_OK */
+        hr = S_OK;
+
+//        if(!(fCharacteristics & NCF_PHYSICAL))
+//        {
+//            /* we are binding to physical adapters only */
+//            *pbShouldBind = false;
+//            break;
+//        }
+
+        hr = vboxNetFltWinNotifyCheckLowerRange(pComponent, pbShouldBind);
+        if(hr == S_OK)
+        {
+            /* the vboxNetFltWinNotifyCheckLowerRange ccucceeded,
+             * the pbShouldBind already contains the result */
+            break;
+        }
+        /* we are here because of the fail, nothing else to do */
+    } while(0);
+
+    TraceMsg(L"<--vboxNetFltWinNotifyShouldBind for INetCfgComponent, hr (0x%x)\n", hr);
+
+    return hr;
+}
+
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgBindingInterface *pIf, OUT bool *pbShouldBind)
+{
+    TraceMsg(L"-->vboxNetFltWinNotifyShouldBind for INetCfgBindingInterface\n");
+
+    INetCfgComponent * pAdapterComponent;
+    HRESULT hr = pIf->GetLowerComponent(&pAdapterComponent);
+    if(hr == S_OK)
+    {
+        hr = vboxNetFltWinNotifyShouldBind(pAdapterComponent, pbShouldBind);
+
+        pAdapterComponent->Release();
+    }
+    else
+    {
+        TraceMsg(L"vboxNetFltWinNotifyShouldBind: GetLowerComponent failed, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    TraceMsg(L"<--vboxNetFltWinNotifyShouldBind for INetCfgBindingInterface, hr (0x%x)\n", hr);
+    return hr;
+}
+
+static HRESULT vboxNetFltWinNotifyShouldBind(IN INetCfgBindingPath *pPath, OUT bool * pbDoBind)
+{
+    TraceMsg(L"-->vboxNetFltWinNotifyShouldBind for INetCfgBindingPath\n");
+    IEnumNetCfgBindingInterface  *pEnumBindingIf;
+    HRESULT hr = pPath->EnumBindingInterfaces(&pEnumBindingIf);
+
+    if(hr == S_OK)
+    {
+        hr = pEnumBindingIf->Reset();
+        if(hr == S_OK)
+        {
+            ULONG    ulCount;
+            INetCfgBindingInterface  *pBindingIf;
+
+            do
+            {
+                hr = pEnumBindingIf->Next( 1,
+                                 &pBindingIf,
+                                 &ulCount );
+                if(hr == S_OK)
+                {
+                    hr = vboxNetFltWinNotifyShouldBind(pBindingIf, pbDoBind);
+
+                    pBindingIf->Release();
+
+                    if(hr == S_OK)
+                    {
+                        if(!(*pbDoBind))
+                        {
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        /* break on failure */
+                        break;
+                    }
+                }
+                else if(hr == S_FALSE)
+                {
+                    /* no more elements */
+                    hr = S_OK;
+                    break;
+                }
+                else
+                {
+                    TraceMsg(L"vboxNetFltWinNotifyShouldBind: Next failed, hr (0x%x)\n", hr);
+                    AssertBreakpoint();
+                    /* break on falure */
+                    break;
+                }
+            } while(true);
+        }
+        else
+        {
+            TraceMsg(L"vboxNetFltWinNotifyShouldBind: Reset failed, hr (0x%x)\n", hr);
+            AssertBreakpoint();
+        }
+
+        pEnumBindingIf->Release();
+    }
+    else
+    {
+        TraceMsg(L"vboxNetFltWinNotifyShouldBind: EnumBindingInterfaces failed, hr (0x%x)\n", hr);
+        AssertBreakpoint();
+    }
+
+    TraceMsg(L"<--vboxNetFltWinNotifyShouldBind for INetCfgBindingPath, hr (0x%x)\n", hr);
+    return hr;
+}
+
+static bool vboxNetFltWinNotifyShouldBind(IN INetCfgBindingPath *pPath)
+{
+#ifdef VBOXNETFLTNOTIFY_DEBUG_BIND
+    return VBOXNETFLTNOTIFY_DEBUG_BIND;
+#else
+    HRESULT hr;
+    bool bShouldBind;
+
+    TraceMsg( L"-->vboxNetFltWinNotifyShouldBind\n");
+
+    hr = vboxNetFltWinNotifyShouldBind(pPath, &bShouldBind) ;
+    if(hr != S_OK)
+    {
+        TraceMsg( L"vboxNetFltWinNotifyShouldBind: vboxNetFltWinNotifyShouldBind failed, hr (0x%x)\n", hr );
+        bShouldBind = VBOXNETFLTNOTIFY_ONFAIL_BINDDEFAULT;
+    }
+
+
+    TraceMsg( L"<--vboxNetFltWinNotifyShouldBind, bShouldBind (%d)\n", bShouldBind);
+    return bShouldBind;
+#endif
+}
+
+/*
+ * INetCfgComponentNotifyBinding
+ * The following functions provide the INetCfgComponentNotifyBinding interface.
+ */
+
+/**
+ * This is specific to the component being installed. This will
+ * ask us if we want to bind to the Item being passed into
+ * this routine. We can disable the binding by returning
+ * NETCFG_S_DISABLE_QUERY
+ *
+ * @param dwChangeFlag Type of binding change
+ * @param pncbpItem   Pointer to INetCfgBindingPath object
+ * @return S_OK on success, otherwise an error code.
+ */
+STDMETHODIMP VBoxNetFltNotify::QueryBindingPath (IN DWORD dwChangeFlag,
+                                           IN INetCfgBindingPath *pPath)
+{
+    HRESULT hr = S_OK;
+    TraceMsg( L"-->QueryBindingPath, flags (0x%x)\n", dwChangeFlag );
+
+    if(!vboxNetFltWinNotifyShouldBind(pPath))
+    {
+        TraceMsg( L"QueryBindingPath: we are NOT supporting the current component\n");
+        hr = NETCFG_S_DISABLE_QUERY;
+    }
+    else
+    {
+        TraceMsg( L"QueryBindingPath: we are supporting the current component\n");
+    }
+    TraceMsg( L"<--QueryBindingPath, hr (0x%x)\n", hr);
+    return hr;
+}
+
+/**
+ * bind to the component passed to us.
+ * @param dwChangeFlag Type of system change
+ * @param pncc Pointer to INetCfgComponent object
+ * @return S_OK on success, otherwise an error code
+ */
+STDMETHODIMP VBoxNetFltNotify::NotifyBindingPath (IN DWORD dwChangeFlag,
+                                            IN INetCfgBindingPath *pPath)
+{
+    HRESULT hr = S_OK;
+
+    TraceMsg( L"-->NotifyBindingPath, flags (0x%x)\n", dwChangeFlag );
+    /* NCN_ADD | NCN_ENABLE
+     * NCN_REMOVE | NCN_ENABLE
+     * NCN_ADD | NCN_DISABLE
+     * NCN_REMOVE | NCN_DISABLE
+     * */
+    if ( (dwChangeFlag & NCN_ENABLE) && !(dwChangeFlag & NCN_REMOVE))
+    {
+        if(!vboxNetFltWinNotifyShouldBind(pPath))
+        {
+            TraceMsg( L"NotifyBindingPath: binding enabled for the component we are not supporting\n");
+            AssertBreakpoint();
+            hr = NETCFG_S_DISABLE_QUERY;
+        }
+    }
+
+    TraceMsg( L"<--NotifyBindingPath, hr (0x%x)\n", hr);
+
+    return hr;
+}
+
+/*
+ * DLL Entry Point
+ */
+extern "C"
+BOOL WINAPI DllMain (HINSTANCE hInstance,
+                     DWORD dwReason,
+                     LPVOID /*lpReserved*/)
+{
+    TraceMsg( L"-->DllMain.\n");
+
+    if (dwReason == DLL_PROCESS_ATTACH) {
+
+        TraceMsg( L"   Reason: Attach.\n");
+
+        _Module.Init(ObjectMap, hInstance);
+
+        DisableThreadLibraryCalls(hInstance);
+    }
+    else if (dwReason == DLL_PROCESS_DETACH) {
+
+        TraceMsg( L"   Reason: Detach.\n");
+
+           _Module.Term();
+    }
+
+    TraceMsg( L"<--DllMain.\n");
+
+    return TRUE;
+}
+
+/*
+ * Used to determine whether the DLL can be unloaded by OLE
+ */
+STDAPI DllCanUnloadNow(void)
+{
+    HRESULT hr;
+
+    TraceMsg( L"-->DllCanUnloadNow.\n");
+
+    hr = (_Module.GetLockCount() == 0) ? S_OK : S_FALSE;
+
+    TraceMsg( L"<--DllCanUnloadNow, hr (0x%x).\n",
+            hr );
+
+    return hr;
+}
+
+/*
+ * Returns a class factory to create an object of the requested type
+ */
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
+{
+    TraceMsg( L"DllGetClassObject.\n");
+
+    return _Module.GetClassObject(rclsid, riid, ppv);
+}
+
+
+/*
+ * DllRegisterServer - Adds entries to the system registry
+ */
+STDAPI DllRegisterServer(void)
+{
+    /* Registers object, typelib and all interfaces in typelib */
+
+    TraceMsg( L"DllRegisterServer.\n");
+
+    return _Module.RegisterServer(TRUE);
+}
+
+/*
+ * DllUnregisterServer - Removes entries from the system registry
+ */
+STDAPI DllUnregisterServer(void)
+{
+    TraceMsg( L"DllUnregisterServer.\n");
+
+    _Module.UnregisterServer();
+
+    return S_OK;
+}
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.def
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.def	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.def	(revision 21333)
@@ -0,0 +1,6 @@
+LIBRARY      VBOXNETFLTNOTIFY
+EXPORTS
+    DllCanUnloadNow         PRIVATE
+    DllGetClassObject       PRIVATE
+    DllRegisterServer       PRIVATE
+    DllUnregisterServer     PRIVATE
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.h
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.h	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.h	(revision 21333)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Sample Notify Object
+ *+---------------------------------------------------------------------------
+ *
+ *  Microsoft Windows
+ *  Copyright (C) Microsoft Corporation, 1992-2001.
+ *
+ *  Author:     Alok Sinha
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifndef ___VboxNetFltNotify_h___
+#define ___VboxNetFltNotify_h___
+
+#include <windows.h>
+#include <atlbase.h>
+extern CComModule _Module;  // required by atlcom.h
+#include <atlcom.h>
+#include <VBoxNetFltNotifyn.h>
+//#include <Netcfgx.h>
+
+#include "VBoxNetFltNotifyRc.h"
+
+#define VBOXNETFLTNOTIFY_ONFAIL_BINDDEFAULT false
+
+/*
+ * VboxNetFlt Notify Object used to control bindings
+ */
+class VBoxNetFltNotify :
+
+               /*
+                * Must inherit from CComObjectRoot(Ex) for reference count
+                * management and default threading model.
+                */
+               public CComObjectRoot,
+
+               /*
+                * Define the default class factory and aggregation model.
+                */
+               public CComCoClass<VBoxNetFltNotify, &CLSID_VBoxNetFltNotify>,
+
+               /*
+                * Notify Object's interfaces.
+                */
+               public INetCfgComponentControl,
+               public INetCfgComponentNotifyBinding
+{
+
+   /*
+    * Public members.
+    */
+   public:
+
+      /*
+       * Constructor
+       */
+       VBoxNetFltNotify(VOID);
+
+      /*
+       * Destructors.
+       */
+      ~VBoxNetFltNotify(VOID);
+
+      /*
+       * Notify Object's interfaces.
+       */
+      BEGIN_COM_MAP(VBoxNetFltNotify)
+         COM_INTERFACE_ENTRY(INetCfgComponentControl)
+//         COM_INTERFACE_ENTRY(INetCfgComponentSetup)
+//         COM_INTERFACE_ENTRY(INetCfgComponentPropertyUi)
+         COM_INTERFACE_ENTRY(INetCfgComponentNotifyBinding)
+//         COM_INTERFACE_ENTRY(INetCfgComponentNotifyGlobal)
+      END_COM_MAP()
+
+      /*
+       * Uncomment the the line below if you don't want your object to
+       * support aggregation. The default is to support it
+       *
+       * DECLARE_NOT_AGGREGATABLE(CMuxNotify)
+       */
+
+      DECLARE_REGISTRY_RESOURCEID(IDR_REG_VBOXNETFLT_NOTIFY)
+
+      /*
+       * INetCfgComponentControl
+       */
+      STDMETHOD (Initialize) (
+                   IN INetCfgComponent  *pIComp,
+                   IN INetCfg           *pINetCfg,
+                   IN BOOL              fInstalling);
+
+      STDMETHOD (CancelChanges) ();
+
+      STDMETHOD (ApplyRegistryChanges) ();
+
+      STDMETHOD (ApplyPnpChanges) (
+                   IN INetCfgPnpReconfigCallback* pICallback);
+
+      /*
+       * INetCfgNotifyBinding
+       */
+      STDMETHOD (QueryBindingPath) (
+                   IN DWORD dwChangeFlag,
+                   IN INetCfgBindingPath* pncbp);
+
+      STDMETHOD (NotifyBindingPath) (
+                   IN DWORD dwChangeFlag,
+                   IN INetCfgBindingPath* pncbp);
+
+  /*
+   * Private members.
+   */
+  private:
+
+     /*
+      * Private member variables.
+      */
+     INetCfgComponent  *m_pncc;  /* Our Protocol's Net Config component */
+     INetCfg           *m_pnc;
+};
+
+#endif
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.rgs
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.rgs	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotify.rgs	(revision 21333)
@@ -0,0 +1,13 @@
+HKCR
+{
+    NoRemove CLSID
+    {
+        ForceRemove {c631480a-acbe-4add-bb1d-3ed8aa52b5d9} = s 'VirtualBox Bridged Networking Driver Notify Object'
+        {
+            InProcServer32 = s '%MODULE%'
+            {
+                val ThreadingModel = s 'Both'
+            }
+        }
+    }
+}
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotifyRc.h
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotifyRc.h	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotifyRc.h	(revision 21333)
@@ -0,0 +1,6 @@
+#ifndef ___VboxNetFltNotifyRc_h___
+#define ___VboxNetFltNotifyRc_h___
+
+#define IDR_REG_VBOXNETFLT_NOTIFY     40001
+
+#endif
Index: /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotifyn.idl
===================================================================
--- /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotifyn.idl	(revision 21333)
+++ /trunk/src/VBox/HostDrivers/VBoxNetFlt/win/notifyobj/VBoxNetFltNotifyn.idl	(revision 21333)
@@ -0,0 +1,39 @@
+/* $Id$ */
+/** @file
+ * VBoxNetFltNotify.idl - Network Filter Driver (Host), Windows Specific Code. Integration with IntNet/NetFlt
+ */
+
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc.
+ *
+ * Sun Microsystems, Inc. confidential
+ * All rights reserved
+ */
+/*
+ * Based in part on Microsoft DDK sample code for Sample Notify Object
+ *+---------------------------------------------------------------------------
+ *
+ *  Microsoft Windows
+ *  Copyright (C) Microsoft Corporation, 1992-2001.
+ * 
+ *----------------------------------------------------------------------------
+ */
+#include <netcfgn.idl>
+
+[
+    uuid(1ea703af-a150-4fdd-83dc-c07a7a460c7e),
+    version(1.0),
+    helpstring("VirtualBox Bridged Networking Driver Notify Object 1.0 Type Library")
+]
+library VBoxNetFltNotifyLib
+{
+    [
+        uuid(c631480a-acbe-4add-bb1d-3ed8aa52b5d9),
+        helpstring("VirtualBox Bridged Networking Driver Notify Object Class")
+    ]
+    coclass VBoxNetFltNotify
+    {
+       [restricted] interface INetCfgComponentControl;
+       [restricted] interface INetCfgComponentNotifyBinding;
+    };
+};
