Răsfoiți Sursa

NDIS6 driver with VS project to build -- builds correctly, not customized for ZT yet.

Adam Ierymenko 10 ani în urmă
părinte
comite
1ebe2ad920

+ 249 - 0
windows/TapDriver6/TapDriver6.vcxproj

@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Win8 Debug|Win32">
+      <Configuration>Win8 Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Win8 Release|Win32">
+      <Configuration>Win8 Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Win7 Debug|Win32">
+      <Configuration>Win7 Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Win7 Release|Win32">
+      <Configuration>Win7 Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Vista Debug|Win32">
+      <Configuration>Vista Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Vista Release|Win32">
+      <Configuration>Vista Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Win8 Debug|x64">
+      <Configuration>Win8 Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Win8 Release|x64">
+      <Configuration>Win8 Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Win7 Debug|x64">
+      <Configuration>Win7 Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Win7 Release|x64">
+      <Configuration>Win7 Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Vista Debug|x64">
+      <Configuration>Vista Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Vista Release|x64">
+      <Configuration>Vista Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}</ProjectGuid>
+    <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+    <Configuration>Win8 Debug</Configuration>
+    <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+  </PropertyGroup>
+  <PropertyGroup Label="Globals">
+    <RootNamespace>TapDriver6</RootNamespace>
+    <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VisualStudioVersion)' == '11.0'">$(VCTargetsPath11)</VCTargetsPath>
+  </PropertyGroup>
+  <PropertyGroup Label="PropertySheets">
+    <PlatformToolset>WindowsKernelModeDriver8.0</PlatformToolset>
+    <ConfigurationType>Driver</ConfigurationType>
+    <DriverType>KMDF</DriverType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'" Label="Configuration">
+    <TargetVersion>Windows8</TargetVersion>
+    <UseDebugLibraries>true</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'" Label="Configuration">
+    <TargetVersion>Windows8</TargetVersion>
+    <UseDebugLibraries>false</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'" Label="Configuration">
+    <TargetVersion>Windows7</TargetVersion>
+    <UseDebugLibraries>true</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'" Label="Configuration">
+    <TargetVersion>Windows7</TargetVersion>
+    <UseDebugLibraries>false</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'" Label="Configuration">
+    <TargetVersion>Vista</TargetVersion>
+    <UseDebugLibraries>true</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'" Label="Configuration">
+    <TargetVersion>Vista</TargetVersion>
+    <UseDebugLibraries>false</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'" Label="Configuration">
+    <TargetVersion>Windows8</TargetVersion>
+    <UseDebugLibraries>true</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'" Label="Configuration">
+    <TargetVersion>Windows8</TargetVersion>
+    <UseDebugLibraries>false</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'" Label="Configuration">
+    <TargetVersion>Windows7</TargetVersion>
+    <UseDebugLibraries>true</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'" Label="Configuration">
+    <TargetVersion>Windows7</TargetVersion>
+    <UseDebugLibraries>false</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'" Label="Configuration">
+    <TargetVersion>Vista</TargetVersion>
+    <UseDebugLibraries>true</UseDebugLibraries>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'" Label="Configuration">
+    <TargetVersion>Vista</TargetVersion>
+    <UseDebugLibraries>false</UseDebugLibraries>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup />
+  <PropertyGroup>
+    <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <WppEnabled>false</WppEnabled>
+      <WppScanConfigurationData Condition="'%(ClCompile. ScanConfigurationData)'  == ''">trace.h</WppScanConfigurationData>
+      <WppKernelMode>false</WppKernelMode>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</WppMinimalRebuildFromTracking>
+      <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</WppMinimalRebuildFromTracking>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">Level1</WarningLevel>
+      <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">Level1</WarningLevel>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">Default</CompileAs>
+      <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">Default</CompileAs>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <Link>
+      <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <FilesToPackage Include="$(TargetPath)" />
+    <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="adapter.c" />
+    <ClCompile Include="device.c" />
+    <ClCompile Include="dhcp.c" />
+    <ClCompile Include="error.c" />
+    <ClCompile Include="macinfo.c" />
+    <ClCompile Include="mem.c" />
+    <ClCompile Include="oidrequest.c" />
+    <ClCompile Include="rxpath.c" />
+    <ClCompile Include="tapdrvr.c" />
+    <ClCompile Include="txpath.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="adapter.h" />
+    <ClInclude Include="config.h" />
+    <ClInclude Include="constants.h" />
+    <ClInclude Include="device.h" />
+    <ClInclude Include="dhcp.h" />
+    <ClInclude Include="endian.h" />
+    <ClInclude Include="error.h" />
+    <ClInclude Include="hexdump.h" />
+    <ClInclude Include="lock.h" />
+    <ClInclude Include="macinfo.h" />
+    <ClInclude Include="mem.h" />
+    <ClInclude Include="proto.h" />
+    <ClInclude Include="prototypes.h" />
+    <ClInclude Include="tap-windows.h" />
+    <ClInclude Include="tap.h" />
+    <ClInclude Include="types.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="resource.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 108 - 0
windows/TapDriver6/TapDriver6.vcxproj.filters

@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Driver Files">
+      <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
+      <Extensions>inf;inv;inx;mof;mc;</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="adapter.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="device.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="dhcp.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="error.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="macinfo.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="mem.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="oidrequest.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="rxpath.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="tapdrvr.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="txpath.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="adapter.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="config.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="constants.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="device.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="dhcp.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="endian.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="error.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="hexdump.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="lock.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="macinfo.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="mem.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="proto.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="prototypes.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="tap.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="tap-windows.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="types.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="resource.rc">
+      <Filter>Resource Files</Filter>
+    </ResourceCompile>
+  </ItemGroup>
+</Project>

+ 1716 - 0
windows/TapDriver6/adapter.c

@@ -0,0 +1,1716 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+NDIS_OID TAPSupportedOids[] =
+{
+        OID_GEN_HARDWARE_STATUS,
+        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_XMIT_OK,
+        OID_GEN_RCV_OK,
+        OID_GEN_STATISTICS,
+#ifdef IMPLEMENT_OPTIONAL_OIDS
+        OID_GEN_TRANSMIT_QUEUE_LENGTH,       // Optional
+#endif // IMPLEMENT_OPTIONAL_OIDS
+        OID_GEN_LINK_PARAMETERS,
+        OID_GEN_INTERRUPT_MODERATION,
+        OID_GEN_MEDIA_SUPPORTED,
+        OID_GEN_MEDIA_IN_USE,
+        OID_GEN_MAXIMUM_SEND_PACKETS,
+        OID_GEN_XMIT_ERROR,
+        OID_GEN_RCV_ERROR,
+        OID_GEN_RCV_NO_BUFFER,
+        OID_802_3_PERMANENT_ADDRESS,
+        OID_802_3_CURRENT_ADDRESS,
+        OID_802_3_MULTICAST_LIST,
+        OID_802_3_MAXIMUM_LIST_SIZE,
+        OID_802_3_RCV_ERROR_ALIGNMENT,
+        OID_802_3_XMIT_ONE_COLLISION,
+        OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef IMPLEMENT_OPTIONAL_OIDS
+        OID_802_3_XMIT_DEFERRED,             // Optional
+        OID_802_3_XMIT_MAX_COLLISIONS,       // Optional
+        OID_802_3_RCV_OVERRUN,               // Optional
+        OID_802_3_XMIT_UNDERRUN,             // Optional
+        OID_802_3_XMIT_HEARTBEAT_FAILURE,    // Optional
+        OID_802_3_XMIT_TIMES_CRS_LOST,       // Optional
+        OID_802_3_XMIT_LATE_COLLISIONS,      // Optional
+        OID_PNP_CAPABILITIES,                // Optional
+#endif // IMPLEMENT_OPTIONAL_OIDS
+};
+
+//======================================================================
+// TAP NDIS 6 Miniport Callbacks
+//======================================================================
+
+// Returns with reference count initialized to one.
+PTAP_ADAPTER_CONTEXT
+tapAdapterContextAllocate(
+    __in NDIS_HANDLE        MiniportAdapterHandle
+)
+{
+    PTAP_ADAPTER_CONTEXT   adapter = NULL;
+
+    adapter = (PTAP_ADAPTER_CONTEXT )NdisAllocateMemoryWithTagPriority(
+        GlobalData.NdisDriverHandle,
+        sizeof(TAP_ADAPTER_CONTEXT),
+        TAP_ADAPTER_TAG,
+        NormalPoolPriority
+        );
+
+    if(adapter)
+    {
+        NET_BUFFER_LIST_POOL_PARAMETERS  nblPoolParameters = {0};
+
+        NdisZeroMemory(adapter,sizeof(TAP_ADAPTER_CONTEXT));
+
+        adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+        // Initialize cancel-safe IRP queue
+        tapIrpCsqInitialize(&adapter->PendingReadIrpQueue);
+
+        // Initialize TAP send packet queue.
+        tapPacketQueueInitialize(&adapter->SendPacketQueue);
+
+        // Allocate the adapter lock.
+        NdisAllocateSpinLock(&adapter->AdapterLock);
+
+        // NBL pool for making TAP receive indications.
+        NdisZeroMemory(&nblPoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));
+
+        // Initialize event used to determine when all receive NBLs have been returned.
+        NdisInitializeEvent(&adapter->ReceiveNblInFlightCountZeroEvent);
+
+        nblPoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+        nblPoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+        nblPoolParameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+        nblPoolParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
+        nblPoolParameters.ContextSize = 0;
+        //nblPoolParameters.ContextSize = sizeof(RX_NETBUFLIST_RSVD);
+        nblPoolParameters.fAllocateNetBuffer = TRUE;
+        nblPoolParameters.PoolTag = TAP_RX_NBL_TAG;
+
+#pragma warning( suppress : 28197 )
+        adapter->ReceiveNblPool = NdisAllocateNetBufferListPool(
+            adapter->MiniportAdapterHandle,
+            &nblPoolParameters); 
+
+        if (adapter->ReceiveNblPool == NULL)
+        {
+            DEBUGP (("[TAP] Couldn't allocate adapter receive NBL pool\n"));
+            NdisFreeMemory(adapter,0,0);
+        }
+
+        // Add initial reference. Normally removed in AdapterHalt.
+        adapter->RefCount = 1;
+
+        // Safe for multiple removes.
+        NdisInitializeListHead(&adapter->AdapterListLink);
+
+        //
+        // The miniport adapter is initially powered up
+        //
+        adapter->CurrentPowerState = NdisDeviceStateD0;
+    }
+
+    return adapter;
+}
+
+VOID
+tapReadPermanentAddress(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in NDIS_HANDLE            ConfigurationHandle,
+    __out MACADDR               PermanentAddress
+    )
+{
+    NDIS_STATUS status;
+    NDIS_CONFIGURATION_PARAMETER *configParameter;
+    NDIS_STRING macKey = NDIS_STRING_CONST("MAC");
+    ANSI_STRING macString;
+    BOOLEAN macFromRegistry = FALSE;
+
+    // Read MAC parameter from registry.
+    NdisReadConfiguration(
+        &status,
+        &configParameter,
+        ConfigurationHandle,
+        &macKey,
+        NdisParameterString
+        );
+
+    if (status == NDIS_STATUS_SUCCESS)
+    {
+        if( (configParameter->ParameterType == NdisParameterString)
+            && (configParameter->ParameterData.StringData.Length >= 12)
+            )
+        {
+            if (RtlUnicodeStringToAnsiString(
+                    &macString,
+                    &configParameter->ParameterData.StringData,
+                    TRUE) == STATUS_SUCCESS
+                    )
+            {
+                macFromRegistry = ParseMAC (PermanentAddress, macString.Buffer);
+                RtlFreeAnsiString (&macString);
+            }
+        }
+    }
+
+    if(!macFromRegistry)
+    {
+        //
+        // There is no (valid) address stashed in the registry parameter.
+        //
+        // Make up a dummy mac address based on the ANSI representation of the
+        // NetCfgInstanceId GUID.
+        //
+        GenerateRandomMac(PermanentAddress, MINIPORT_INSTANCE_ID(Adapter));
+    }
+}
+
+NDIS_STATUS
+tapReadConfiguration(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    )
+{
+    NDIS_STATUS                 status = NDIS_STATUS_SUCCESS;
+    NDIS_CONFIGURATION_OBJECT   configObject;
+    NDIS_HANDLE                 configHandle;
+
+    DEBUGP (("[TAP] --> tapReadConfiguration\n"));
+
+    //
+    // Setup defaults in case configuration cannot be opened.
+    //
+    Adapter->MtuSize = ETHERNET_MTU;
+    Adapter->MediaStateAlwaysConnected = FALSE;
+    Adapter->LogicalMediaState = FALSE;
+    Adapter->AllowNonAdmin = FALSE;
+    //
+    // Open the registry for this adapter to read advanced
+    // configuration parameters stored by the INF file.
+    //
+    NdisZeroMemory(&configObject, sizeof(configObject));
+
+    {C_ASSERT(sizeof(configObject) >= NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1);}
+    configObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+    configObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1;
+    configObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+
+    configObject.NdisHandle = Adapter->MiniportAdapterHandle;
+    configObject.Flags = 0;
+
+    status = NdisOpenConfigurationEx(
+                &configObject,
+                &configHandle
+                );
+
+    // Read on the opened configuration handle.
+    if(status == NDIS_STATUS_SUCCESS)
+    {
+        NDIS_CONFIGURATION_PARAMETER *configParameter;
+        NDIS_STRING mkey = NDIS_STRING_CONST("NetCfgInstanceId");
+
+        //
+        // Read NetCfgInstanceId from the registry.
+        // ------------------------------------
+        // NetCfgInstanceId is required to create device and associated
+        // symbolic link for the adapter device.
+        //
+        // NetCfgInstanceId is  a GUID string provided by NDIS that identifies
+        // the adapter instance. An example is:
+        // 
+        //    NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0}
+        //
+        // Other names are derived from NetCfgInstanceId. For example, MiniportName:
+        //
+        //    MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0}
+        //
+        NdisReadConfiguration (
+            &status,
+            &configParameter,
+            configHandle,
+            &mkey,
+            NdisParameterString
+            );
+
+        if (status == NDIS_STATUS_SUCCESS)
+        {
+            if (configParameter->ParameterType == NdisParameterString)
+            {
+                DEBUGP (("[TAP] NdisReadConfiguration (NetCfgInstanceId=%wZ)\n",
+                    &configParameter->ParameterData.StringData ));
+
+                // Save NetCfgInstanceId as UNICODE_STRING.
+                Adapter->NetCfgInstanceId.Length = Adapter->NetCfgInstanceId.MaximumLength
+                    = configParameter->ParameterData.StringData.Length;
+
+                Adapter->NetCfgInstanceId.Buffer = Adapter->NetCfgInstanceIdBuffer;
+
+                NdisMoveMemory(
+                    Adapter->NetCfgInstanceId.Buffer, 
+                    configParameter->ParameterData.StringData.Buffer,
+                    Adapter->NetCfgInstanceId.Length
+                    );
+
+                // Save NetCfgInstanceId as ANSI_STRING as well.
+                if (RtlUnicodeStringToAnsiString (
+                        &Adapter->NetCfgInstanceIdAnsi,
+                        &configParameter->ParameterData.StringData,
+                        TRUE) != STATUS_SUCCESS
+                    )
+                {
+                    DEBUGP (("[TAP] NetCfgInstanceId ANSI name conversion failed\n"));
+                    status = NDIS_STATUS_RESOURCES;
+                }
+            }
+            else
+            {
+                DEBUGP (("[TAP] NetCfgInstanceId has invalid type\n"));
+                status = NDIS_STATUS_INVALID_DATA;
+            }
+        }
+        else
+        {
+            DEBUGP (("[TAP] NetCfgInstanceId failed\n"));
+            status = NDIS_STATUS_INVALID_DATA;
+        }
+
+        if (status == NDIS_STATUS_SUCCESS)
+        {
+            NDIS_STATUS localStatus;    // Use default if these fail.
+            NDIS_CONFIGURATION_PARAMETER *configParameter;
+            NDIS_STRING mtuKey = NDIS_STRING_CONST("MTU");
+            NDIS_STRING mediaStatusKey = NDIS_STRING_CONST("MediaStatus");
+#if ENABLE_NONADMIN
+            NDIS_STRING allowNonAdminKey = NDIS_STRING_CONST("AllowNonAdmin");
+#endif
+
+            // Read MTU from the registry.
+            NdisReadConfiguration (
+                &localStatus,
+                &configParameter,
+                configHandle,
+                &mtuKey,
+                NdisParameterInteger
+                );
+
+            if (localStatus == NDIS_STATUS_SUCCESS)
+            {
+                if (configParameter->ParameterType == NdisParameterInteger)
+                {
+                    int mtu = configParameter->ParameterData.IntegerData;
+
+                    if(mtu == 0)
+                    {
+                        mtu = ETHERNET_MTU;
+                    }
+
+                    // Sanity check
+                    if (mtu < MINIMUM_MTU)
+                    {
+                        mtu = MINIMUM_MTU;
+                    }
+                    else if (mtu > MAXIMUM_MTU)
+                    {
+                        mtu = MAXIMUM_MTU;
+                    }
+
+                    Adapter->MtuSize = mtu;
+                }
+            }
+
+            DEBUGP (("[%s] Using MTU %d\n",
+                MINIPORT_INSTANCE_ID (Adapter),
+                Adapter->MtuSize
+                ));
+
+            // Read MediaStatus setting from registry.
+            NdisReadConfiguration (
+                &localStatus,
+                &configParameter,
+                configHandle,
+                &mediaStatusKey,
+                NdisParameterInteger
+                );
+
+            if (localStatus == NDIS_STATUS_SUCCESS)
+            {
+                if (configParameter->ParameterType == NdisParameterInteger)
+                {
+                    if(configParameter->ParameterData.IntegerData == 0)
+                    {
+                        // Connect state is appplication controlled.
+                        DEBUGP(("[%s] Initial MediaConnectState: Application Controlled\n",
+                            MINIPORT_INSTANCE_ID (Adapter)));
+
+                        Adapter->MediaStateAlwaysConnected = FALSE;
+                        Adapter->LogicalMediaState = FALSE;
+                    }
+                    else
+                    {
+                        // Connect state is always connected.
+                        DEBUGP(("[%s] Initial MediaConnectState: Always Connected\n",
+                            MINIPORT_INSTANCE_ID (Adapter)));
+
+                        Adapter->MediaStateAlwaysConnected = TRUE;
+                        Adapter->LogicalMediaState = TRUE;
+                    }
+                }
+            }
+
+            // Read MAC PermanentAddress setting from registry.
+            tapReadPermanentAddress(
+                Adapter,
+                configHandle,
+                Adapter->PermanentAddress
+                );
+
+            DEBUGP (("[%s] Using MAC PermanentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+                MINIPORT_INSTANCE_ID (Adapter),
+                Adapter->PermanentAddress[0],
+                Adapter->PermanentAddress[1],
+                Adapter->PermanentAddress[2],
+                Adapter->PermanentAddress[3],
+                Adapter->PermanentAddress[4],
+                Adapter->PermanentAddress[5])
+                );
+
+            // Now seed the current MAC address with the permanent address.
+            ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress);
+
+            DEBUGP (("[%s] Using MAC CurrentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+                MINIPORT_INSTANCE_ID (Adapter),
+                Adapter->CurrentAddress[0],
+                Adapter->CurrentAddress[1],
+                Adapter->CurrentAddress[2],
+                Adapter->CurrentAddress[3],
+                Adapter->CurrentAddress[4],
+                Adapter->CurrentAddress[5])
+                );
+
+            // Read optional AllowNonAdmin setting from registry.
+#if ENABLE_NONADMIN
+            NdisReadConfiguration (
+                &localStatus,
+                &configParameter,
+                configHandle,
+                &allowNonAdminKey,
+                NdisParameterInteger
+                );
+
+            if (localStatus == NDIS_STATUS_SUCCESS)
+            {
+                if (configParameter->ParameterType == NdisParameterInteger)
+                {
+                    Adapter->AllowNonAdmin = TRUE;
+                }
+            }
+#endif
+        }
+
+        // Close the configuration handle.
+        NdisCloseConfiguration(configHandle);
+    }
+    else
+    {
+        DEBUGP (("[TAP] Couldn't open adapter registry\n"));
+    }
+
+    DEBUGP (("[TAP] <-- tapReadConfiguration; status = %8.8X\n",status));
+
+    return status;
+}
+
+VOID
+tapAdapterContextAddToGlobalList(
+    __in PTAP_ADAPTER_CONTEXT       Adapter
+    )
+{
+    LOCK_STATE      lockState;
+    PLIST_ENTRY     listEntry = &Adapter->AdapterListLink;
+
+    // Acquire global adapter list lock.
+    NdisAcquireReadWriteLock(
+        &GlobalData.Lock,
+        TRUE,      // Acquire for write
+        &lockState
+        );
+
+    // Adapter context should NOT be in any list.
+    ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) );
+
+    // Add reference to persist until after removal.
+    tapAdapterContextReference(Adapter);
+
+    // Add the adapter context to the global list.
+    InsertTailList(&GlobalData.AdapterList,&Adapter->AdapterListLink);
+
+    // Release global adapter list lock.
+    NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+}
+
+VOID
+tapAdapterContextRemoveFromGlobalList(
+    __in PTAP_ADAPTER_CONTEXT       Adapter
+    )
+{
+    LOCK_STATE              lockState;
+
+    // Acquire global adapter list lock.
+    NdisAcquireReadWriteLock(
+        &GlobalData.Lock,
+        TRUE,      // Acquire for write
+        &lockState
+        );
+
+    // Remove the adapter context from the global list.
+    RemoveEntryList(&Adapter->AdapterListLink);
+
+    // Safe for multiple removes.
+    NdisInitializeListHead(&Adapter->AdapterListLink);
+
+    // Remove reference added in tapAdapterContextAddToGlobalList.
+    tapAdapterContextDereference(Adapter);
+
+    // Release global adapter list lock.
+    NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+}
+
+// Returns with added reference on adapter context.
+PTAP_ADAPTER_CONTEXT
+tapAdapterContextFromDeviceObject(
+    __in PDEVICE_OBJECT DeviceObject
+    )
+{
+    LOCK_STATE              lockState;
+
+    // Acquire global adapter list lock.
+    NdisAcquireReadWriteLock(
+        &GlobalData.Lock,
+        FALSE,      // Acquire for read
+        &lockState
+        );
+
+    if (!IsListEmpty(&GlobalData.AdapterList))
+    {
+        PLIST_ENTRY             entry = GlobalData.AdapterList.Flink;
+        PTAP_ADAPTER_CONTEXT    adapter;
+
+        while (entry != &GlobalData.AdapterList)
+        {
+            adapter = CONTAINING_RECORD(entry, TAP_ADAPTER_CONTEXT, AdapterListLink);
+
+            // Match on DeviceObject
+            if(adapter->DeviceObject == DeviceObject )
+            {
+                // Add reference to adapter context.
+                tapAdapterContextReference(adapter);
+
+                // Release global adapter list lock.
+                NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+
+                return adapter;
+            }
+
+            // Move to next entry
+            entry = entry->Flink;
+        }
+    }
+
+    // Release global adapter list lock.
+    NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+
+    return (PTAP_ADAPTER_CONTEXT )NULL;
+}
+
+NDIS_STATUS
+AdapterSetOptions(
+    __in  NDIS_HANDLE             NdisDriverHandle,
+    __in  NDIS_HANDLE             DriverContext
+    )
+/*++
+Routine Description:
+
+    The MiniportSetOptions function registers optional handlers.  For each
+    optional handler that should be registered, this function makes a call
+    to NdisSetOptionalHandlers.
+
+    MiniportSetOptions runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+    DriverContext  The context handle
+
+Return Value:
+
+    NDIS_STATUS_xxx code
+
+--*/
+{
+    NDIS_STATUS status;
+
+    DEBUGP (("[TAP] --> AdapterSetOptions\n"));
+
+    //
+    // Set any optional handlers by filling out the appropriate struct and
+    // calling NdisSetOptionalHandlers here.
+    //
+
+    status = NDIS_STATUS_SUCCESS;
+
+    DEBUGP (("[TAP] <-- AdapterSetOptions; status = %8.8X\n",status));
+
+    return status;
+}
+
+NDIS_STATUS
+AdapterCreate(
+    __in  NDIS_HANDLE                         MiniportAdapterHandle,
+    __in  NDIS_HANDLE                         MiniportDriverContext,
+    __in  PNDIS_MINIPORT_INIT_PARAMETERS      MiniportInitParameters
+    )
+{
+    PTAP_ADAPTER_CONTEXT    adapter = NULL;
+    NDIS_STATUS             status;
+
+    UNREFERENCED_PARAMETER(MiniportDriverContext);
+    UNREFERENCED_PARAMETER(MiniportInitParameters);
+
+    DEBUGP (("[TAP] --> AdapterCreate\n"));
+
+    do
+    {
+        NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES regAttributes = {0};
+        NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES genAttributes = {0};
+        NDIS_PNP_CAPABILITIES pnpCapabilities = {0};
+
+        //
+        // Allocate adapter context structure and initialize all the
+        // memory resources for sending and receiving packets.
+        //
+        // Returns with reference count initialized to one.
+        //
+        adapter = tapAdapterContextAllocate(MiniportAdapterHandle);
+
+        if(adapter == NULL)
+        {
+            DEBUGP (("[TAP] Couldn't allocate adapter memory\n"));
+            status = NDIS_STATUS_RESOURCES;
+            break;
+        }
+
+        // Enter the Initializing state.
+        DEBUGP (("[TAP] Miniport State: Initializing\n"));
+
+        tapAdapterAcquireLock(adapter,FALSE);
+        adapter->Locked.AdapterState = MiniportInitializingState;
+        tapAdapterReleaseLock(adapter,FALSE);
+
+        //
+        // First read adapter configuration from registry.
+        // -----------------------------------------------
+        // Subsequent device registration will fail if NetCfgInstanceId
+        // has not been successfully read.
+        //
+        status = tapReadConfiguration(adapter);
+
+        //
+        // Set the registration attributes.
+        //
+        {C_ASSERT(sizeof(regAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1);}
+        regAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
+        regAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+        regAttributes.Header.Revision = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+
+        regAttributes.MiniportAdapterContext = adapter;
+        regAttributes.AttributeFlags = TAP_ADAPTER_ATTRIBUTES_FLAGS;
+
+        regAttributes.CheckForHangTimeInSeconds = TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS;
+        regAttributes.InterfaceType = TAP_INTERFACE_TYPE;
+
+        //NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(TAP_ADAPTER_CONTEXT);
+        status = NdisMSetMiniportAttributes(
+                    MiniportAdapterHandle,
+                    (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&regAttributes
+                    );
+
+        if (status != NDIS_STATUS_SUCCESS)
+        {
+            DEBUGP (("[TAP] NdisSetOptionalHandlers failed; Status 0x%08x\n",status));
+            break;
+        }
+
+        //
+        // Next, set the general attributes.
+        //
+        {C_ASSERT(sizeof(genAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1);}
+        genAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
+        genAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+        genAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+
+        //
+        // Specify the medium type that the NIC can support but not
+        // necessarily the medium type that the NIC currently uses.
+        //
+        genAttributes.MediaType = TAP_MEDIUM_TYPE;
+
+        //
+        // Specifiy medium type that the NIC currently uses.
+        //
+        genAttributes.PhysicalMediumType = TAP_PHYSICAL_MEDIUM;
+
+        //
+        // Specifiy the maximum network frame size, in bytes, that the NIC
+        // supports excluding the header.
+        //
+        genAttributes.MtuSize = TAP_FRAME_MAX_DATA_SIZE;
+        genAttributes.MaxXmitLinkSpeed = TAP_XMIT_SPEED;
+        genAttributes.XmitLinkSpeed = TAP_XMIT_SPEED;
+        genAttributes.MaxRcvLinkSpeed = TAP_RECV_SPEED;
+        genAttributes.RcvLinkSpeed = TAP_RECV_SPEED;
+
+        if(adapter->MediaStateAlwaysConnected)
+        {
+            DEBUGP(("[%s] Initial MediaConnectState: Connected\n",
+                MINIPORT_INSTANCE_ID (adapter)));
+
+            genAttributes.MediaConnectState = MediaConnectStateConnected;
+        }
+        else
+        {
+            DEBUGP(("[%s] Initial MediaConnectState: Disconnected\n",
+                MINIPORT_INSTANCE_ID (adapter)));
+
+            genAttributes.MediaConnectState = MediaConnectStateDisconnected;
+        }
+
+        genAttributes.MediaDuplexState = MediaDuplexStateFull;
+
+        //
+        // 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 MiniportOidRequest 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
+        // NdisMIndicateReceiveNetBufferLists, it should set this value to the
+        // maximum total frame 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.
+        //
+        genAttributes.LookaheadSize = TAP_MAX_LOOKAHEAD;
+        genAttributes.MacOptions = TAP_MAC_OPTIONS;
+        genAttributes.SupportedPacketFilters = TAP_SUPPORTED_FILTERS;
+
+        //
+        // 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.
+        //
+        genAttributes.MaxMulticastListSize = TAP_MAX_MCAST_LIST;
+        genAttributes.MacAddressLength = MACADDR_SIZE;
+
+        //
+        // Return the MAC address of the NIC burnt in the hardware.
+        //
+        ETH_COPY_NETWORK_ADDRESS(genAttributes.PermanentMacAddress, adapter->PermanentAddress);
+
+        //
+        // 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.
+        //
+        ETH_COPY_NETWORK_ADDRESS(genAttributes.CurrentMacAddress, adapter->CurrentAddress);
+
+        genAttributes.RecvScaleCapabilities = NULL;
+        genAttributes.AccessType = TAP_ACCESS_TYPE;
+        genAttributes.DirectionType = TAP_DIRECTION_TYPE;
+        genAttributes.ConnectionType = TAP_CONNECTION_TYPE;
+        genAttributes.IfType = TAP_IFTYPE;
+        genAttributes.IfConnectorPresent = TAP_HAS_PHYSICAL_CONNECTOR;
+        genAttributes.SupportedStatistics = TAP_SUPPORTED_STATISTICS;
+        genAttributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported; // IEEE 802.3 pause frames 
+        genAttributes.DataBackFillSize = 0;
+        genAttributes.ContextBackFillSize = 0;
+
+        //
+        // The SupportedOidList is 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.
+        //
+        genAttributes.SupportedOidList = TAPSupportedOids;
+        genAttributes.SupportedOidListLength = sizeof(TAPSupportedOids);
+        genAttributes.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
+
+        //
+        // Set power management capabilities
+        //
+        NdisZeroMemory(&pnpCapabilities, sizeof(pnpCapabilities));
+        pnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+        pnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
+        genAttributes.PowerManagementCapabilities = &pnpCapabilities;
+
+        status = NdisMSetMiniportAttributes(
+                    MiniportAdapterHandle,
+                    (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&genAttributes
+                    );
+
+        if (status != NDIS_STATUS_SUCCESS)
+        {
+            DEBUGP (("[TAP] NdisMSetMiniportAttributes failed; Status 0x%08x\n",status));
+            break;
+        }
+
+        //
+        // Create the Win32 device I/O interface.
+        //
+        status = CreateTapDevice(adapter);
+
+        if (status == NDIS_STATUS_SUCCESS)
+        {
+            // Add this adapter to the global adapter list.
+            tapAdapterContextAddToGlobalList(adapter);
+        }
+        else
+        {
+            DEBUGP (("[TAP] CreateTapDevice failed; Status 0x%08x\n",status));
+            break;
+        }
+    } while(FALSE);
+
+    if(status == NDIS_STATUS_SUCCESS)
+    {
+        // Enter the Paused state if initialization is complete.
+        DEBUGP (("[TAP] Miniport State: Paused\n"));
+
+        tapAdapterAcquireLock(adapter,FALSE);
+        adapter->Locked.AdapterState = MiniportPausedState;
+        tapAdapterReleaseLock(adapter,FALSE);
+    }
+    else
+    {
+        if(adapter != NULL)
+        {
+            DEBUGP (("[TAP] Miniport State: Halted\n"));
+
+            //
+            // Remove reference when adapter context was allocated
+            // ---------------------------------------------------
+            // This should result in freeing adapter context memory
+            // and assiciated resources.
+            //
+            tapAdapterContextDereference(adapter);
+            adapter = NULL;
+        }
+    }
+
+    DEBUGP (("[TAP] <-- AdapterCreate; status = %8.8X\n",status));
+
+    return status;
+}
+
+VOID
+AdapterHalt(
+    __in  NDIS_HANDLE             MiniportAdapterContext,
+    __in  NDIS_HALT_ACTION        HaltAction
+    )
+/*++
+
+Routine Description:
+
+    Halt handler is called when NDIS receives IRP_MN_STOP_DEVICE,
+    IRP_MN_SUPRISE_REMOVE or IRP_MN_REMOVE_DEVICE requests from the PNP
+    manager. Here, the driver should free all the resources acquired in
+    MiniportInitialize and stop access to the hardware. NDIS will not submit
+    any further request once this handler is invoked.
+
+    1) Free and unmap all I/O resources.
+    2) Disable interrupt and deregister interrupt handler.
+    3) Deregister shutdown handler regsitered by
+        NdisMRegisterAdapterShutdownHandler .
+    4) Cancel all queued up timer callbacks.
+    5) Finally wait indefinitely for all the outstanding receive
+        packets indicated to the protocol to return.
+
+    MiniportHalt runs at IRQL = PASSIVE_LEVEL.
+
+
+Arguments:
+
+    MiniportAdapterContext  Pointer to the Adapter
+    HaltAction  The reason for halting the adapter
+
+Return Value:
+
+    None.
+
+--*/
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+    UNREFERENCED_PARAMETER(HaltAction);
+
+    DEBUGP (("[TAP] --> AdapterHalt\n"));
+
+    // Enter the Halted state.
+    DEBUGP (("[TAP] Miniport State: Halted\n"));
+
+    tapAdapterAcquireLock(adapter,FALSE);
+    adapter->Locked.AdapterState = MiniportHaltedState;
+    tapAdapterReleaseLock(adapter,FALSE);
+
+    // Remove this adapter from the global adapter list.
+    tapAdapterContextRemoveFromGlobalList(adapter);
+
+    // BUGBUG!!! Call AdapterShutdownEx to do some of the work of stopping.
+
+    // TODO!!! More...
+
+    //
+    // Destroy the TAP Win32 device.
+    //
+    DestroyTapDevice(adapter);
+
+    //
+    // Remove initial reference added in AdapterCreate.
+    // ------------------------------------------------
+    // This should result in freeing adapter context memory
+    // and resources allocated in AdapterCreate.
+    //
+    tapAdapterContextDereference(adapter);
+    adapter = NULL;
+
+    DEBUGP (("[TAP] <-- AdapterHalt\n"));
+}
+
+VOID
+tapWaitForReceiveNblInFlightCountZeroEvent(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    )
+{
+    LONG    nblCount;
+
+    //
+    // Wait until higher-level protocol has returned all NBLs
+    // to the driver.
+    //
+
+    // Add one NBL "bias" to insure allow event to be reset safely.
+    nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount);
+    ASSERT(nblCount > 0 );
+    NdisResetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent);
+
+    //
+    // Now remove the bias and wait for the ReceiveNblInFlightCountZeroEvent
+    // if the count returned is not zero.
+    //
+    nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount);
+    ASSERT(nblCount >= 0);
+
+    if(nblCount)
+    {
+        LARGE_INTEGER   startTime, currentTime;
+
+        NdisGetSystemUpTimeEx(&startTime);
+
+        for (;;)
+        {
+            BOOLEAN waitResult = NdisWaitEvent(
+                &Adapter->ReceiveNblInFlightCountZeroEvent, 
+                TAP_WAIT_POLL_LOOP_TIMEOUT
+                );
+
+            NdisGetSystemUpTimeEx(&currentTime);
+
+            if (waitResult)
+            {
+                break;
+            }
+
+            DEBUGP (("[%s] Waiting for %d in-flight receive NBLs to be returned.\n",
+                MINIPORT_INSTANCE_ID (Adapter),
+                Adapter->ReceiveNblInFlightCount
+                ));
+        }
+
+        DEBUGP (("[%s] Waited %d ms for all in-flight NBLs to be returned.\n",
+            MINIPORT_INSTANCE_ID (Adapter),
+            (currentTime.LowPart - startTime.LowPart)
+            ));
+    }
+}
+
+NDIS_STATUS
+AdapterPause(
+    __in  NDIS_HANDLE                       MiniportAdapterContext,
+    __in  PNDIS_MINIPORT_PAUSE_PARAMETERS   PauseParameters
+    )
+/*++
+
+Routine Description:
+
+    When a miniport receives a pause request, it enters into a Pausing state.
+    The miniport should not indicate up any more network data.  Any pending
+    send requests must be completed, and new requests must be rejected with
+    NDIS_STATUS_PAUSED.
+
+    Once all sends have been completed and all recieve NBLs have returned to
+    the miniport, the miniport enters the Paused state.
+
+    While paused, the miniport can still service interrupts from the hardware
+    (to, for example, continue to indicate NDIS_STATUS_MEDIA_CONNECT
+    notifications).
+
+    The miniport must continue to be able to handle status indications and OID
+    requests.  MiniportPause is different from MiniportHalt because, in
+    general, the MiniportPause operation won't release any resources.
+    MiniportPause must not attempt to acquire any resources where allocation
+    can fail, since MiniportPause itself must not fail.
+
+
+    MiniportPause runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+    MiniportAdapterContext  Pointer to the Adapter
+    MiniportPauseParameters  Additional information about the pause operation
+
+Return Value:
+
+    If the miniport is able to immediately enter the Paused state, it should
+    return NDIS_STATUS_SUCCESS.
+
+    If the miniport must wait for send completions or pending receive NBLs, it
+    should return NDIS_STATUS_PENDING now, and call NDISMPauseComplete when the
+    miniport has entered the Paused state.
+
+    No other return value is permitted.  The pause operation must not fail.
+
+--*/
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+    NDIS_STATUS    status;
+
+    UNREFERENCED_PARAMETER(PauseParameters);
+
+    DEBUGP (("[TAP] --> AdapterPause\n"));
+
+    // Enter the Pausing state.
+    DEBUGP (("[TAP] Miniport State: Pausing\n"));
+
+    tapAdapterAcquireLock(adapter,FALSE);
+    adapter->Locked.AdapterState = MiniportPausingState;
+    tapAdapterReleaseLock(adapter,FALSE);
+
+    //
+    // Stop the flow of network data through the receive path
+    // ------------------------------------------------------
+    // In the Pausing and Paused state tapAdapterSendAndReceiveReady
+    // will prevent new calls to NdisMIndicateReceiveNetBufferLists
+    // to indicate additional receive NBLs to the host.
+    //
+    // However, there may be some in-flight NBLs owned by the driver
+    // that have been indicated to the host but have not yet been
+    // returned.
+    //
+    // Wait here for all in-flight receive indications to be returned.
+    //
+    tapWaitForReceiveNblInFlightCountZeroEvent(adapter);
+
+    //
+    // Stop the flow of network data through the send path
+    // ---------------------------------------------------
+    // The initial implementation of the NDIS 6 send path follows the
+    // NDIS 5 pattern. Under this approach every send packet is copied
+    // into a driver-owned TAP_PACKET structure and the NBL owned by
+    // higher-level protocol is immediatly completed.
+    //
+    // With this deep-copy approach the driver never claims ownership
+    // of any send NBL.
+    //
+    // A future implementation may queue send NBLs and thereby eliminate
+    // the need for the unnecessary allocation and deep copy of each packet.
+    //
+    // So, nothing to do here for the send path for now...
+
+    status = NDIS_STATUS_SUCCESS;
+
+    // Enter the Paused state.
+    DEBUGP (("[TAP] Miniport State: Paused\n"));
+
+    tapAdapterAcquireLock(adapter,FALSE);
+    adapter->Locked.AdapterState = MiniportPausedState;
+    tapAdapterReleaseLock(adapter,FALSE);
+
+    DEBUGP (("[TAP] <-- AdapterPause; status = %8.8X\n",status));
+
+    return status;
+}
+
+NDIS_STATUS
+AdapterRestart(
+    __in  NDIS_HANDLE                             MiniportAdapterContext,
+    __in  PNDIS_MINIPORT_RESTART_PARAMETERS       RestartParameters
+    )
+/*++
+
+Routine Description:
+
+    When a miniport receives a restart request, it enters into a Restarting
+    state.  The miniport may begin indicating received data (e.g., using
+    NdisMIndicateReceiveNetBufferLists), handling status indications, and
+    processing OID requests in the Restarting state.  However, no sends will be
+    requested while the miniport is in the Restarting state.
+
+    Once the miniport is ready to send data, it has entered the Running state.
+    The miniport informs NDIS that it is in the Running state by returning
+    NDIS_STATUS_SUCCESS from this MiniportRestart function; or if this function
+    has already returned NDIS_STATUS_PENDING, by calling NdisMRestartComplete.
+
+
+    MiniportRestart runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+    MiniportAdapterContext  Pointer to the Adapter
+    RestartParameters  Additional information about the restart operation
+
+Return Value:
+
+    If the miniport is able to immediately enter the Running state, it should
+    return NDIS_STATUS_SUCCESS.
+
+    If the miniport is still in the Restarting state, it should return
+    NDIS_STATUS_PENDING now, and call NdisMRestartComplete when the miniport
+    has entered the Running state.
+
+    Other NDIS_STATUS codes indicate errors.  If an error is encountered, the
+    miniport must return to the Paused state (i.e., stop indicating receives).
+
+--*/
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+    NDIS_STATUS    status;
+
+    UNREFERENCED_PARAMETER(RestartParameters);
+
+    DEBUGP (("[TAP] --> AdapterRestart\n"));
+
+    // Enter the Restarting state.
+    DEBUGP (("[TAP] Miniport State: Restarting\n"));
+
+    tapAdapterAcquireLock(adapter,FALSE);
+    adapter->Locked.AdapterState = MiniportRestartingState;
+    tapAdapterReleaseLock(adapter,FALSE);
+
+    status = NDIS_STATUS_SUCCESS;
+
+    if(status == NDIS_STATUS_SUCCESS)
+    {
+        // Enter the Running state.
+        DEBUGP (("[TAP] Miniport State: Running\n"));
+
+        tapAdapterAcquireLock(adapter,FALSE);
+        adapter->Locked.AdapterState = MiniportRunning;
+        tapAdapterReleaseLock(adapter,FALSE);
+    }
+    else
+    {
+        // Enter the Paused state if restart failed.
+        DEBUGP (("[TAP] Miniport State: Paused\n"));
+
+        tapAdapterAcquireLock(adapter,FALSE);
+        adapter->Locked.AdapterState = MiniportPausedState;
+        tapAdapterReleaseLock(adapter,FALSE);
+    }
+
+    DEBUGP (("[TAP] <-- AdapterRestart; status = %8.8X\n",status));
+
+    return status;
+}
+
+BOOLEAN
+tapAdapterReadAndWriteReady(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    )
+/*++
+
+Routine Description:
+
+    This routine determines whether the adapter device interface can
+    accept read and write operations.
+
+Arguments:
+
+    Adapter              Pointer to our adapter context
+
+Return Value:
+
+    Returns TRUE if the adapter state allows it to queue IRPs passed to
+    the device read and write callbacks.
+--*/
+{
+    if(!Adapter->TapDeviceCreated)
+    {
+        // TAP device not created or is being destroyed.
+        return FALSE;
+    }
+
+    if(Adapter->TapFileObject == NULL)
+    {
+        // TAP application file object not open.
+        return FALSE;
+    }
+
+    if(!Adapter->TapFileIsOpen)
+    {
+        // TAP application file object may be closing.
+        return FALSE;
+    }
+
+    if(!Adapter->LogicalMediaState)
+    {
+        // Don't handle read/write if media not connected.
+        return FALSE;
+    }
+
+    if(Adapter->CurrentPowerState != NdisDeviceStateD0)
+    {
+        // Don't handle read/write if device is not fully powered.
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+NDIS_STATUS
+tapAdapterSendAndReceiveReady(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    )
+/*++
+
+Routine Description:
+
+    This routine determines whether the adapter NDIS send and receive
+    paths are ready.
+
+    This routine examines various adapter state variables and returns
+    a value that indicates whether the adapter NDIS interfaces can
+    accept send packets or indicate receive packets.
+
+    In normal operation the adapter may temporarily enter and then exit
+    a not-ready condition. In particular, the adapter becomes not-ready
+    when in the Pausing/Paused states, but may become ready again when
+    Restarted.
+
+    Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+    Adapter              Pointer to our adapter context
+
+Return Value:
+
+    Returns NDIS_STATUS_SUCCESS if the adapter state allows it to
+    accept send packets and indicate receive packets.
+
+    Otherwise it returns a NDIS_STATUS value other than NDIS_STATUS_SUCCESS.
+    These status values can be used directly as the completion status for
+    packets that must be completed immediatly in the send path.
+--*/
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+    //
+    // Check various state variables to insure adapter is ready.
+    //
+    tapAdapterAcquireLock(Adapter,FALSE);
+
+    if(!Adapter->LogicalMediaState)
+    {
+        status = NDIS_STATUS_MEDIA_DISCONNECTED;
+    }
+    else if(Adapter->CurrentPowerState != NdisDeviceStateD0)
+    {
+        status = NDIS_STATUS_LOW_POWER_STATE;
+    }
+    else if(Adapter->ResetInProgress)
+    {
+        status = NDIS_STATUS_RESET_IN_PROGRESS;
+    }
+    else
+    {
+        switch(Adapter->Locked.AdapterState)
+        {
+        case MiniportPausingState:
+        case MiniportPausedState:
+            status = NDIS_STATUS_PAUSED;
+            break;
+
+        case MiniportHaltedState:
+            status = NDIS_STATUS_INVALID_STATE;
+            break;
+
+        default:
+            status = NDIS_STATUS_SUCCESS;
+            break;
+        }
+    }
+
+    tapAdapterReleaseLock(Adapter,FALSE);
+
+    return status;
+}
+
+BOOLEAN
+AdapterCheckForHangEx(
+    __in  NDIS_HANDLE MiniportAdapterContext
+    )
+/*++
+
+Routine Description:
+
+    The MiniportCheckForHangEx handler is called to report the state of the
+    NIC, or to monitor the responsiveness of an underlying device driver.
+    This is an optional function. If this handler is not specified, NDIS
+    judges the driver unresponsive when the driver holds
+    MiniportQueryInformation or MiniportSetInformation requests for a
+    time-out interval (deafult 4 sec), and then calls the driver's
+    MiniportReset function. A NIC driver's MiniportInitialize function can
+    extend NDIS's time-out interval by calling NdisMSetAttributesEx to
+    avoid unnecessary resets.
+
+    MiniportCheckForHangEx runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+    MiniportAdapterContext  Pointer to our adapter
+
+Return Value:
+
+    TRUE    NDIS calls the driver's MiniportReset function.
+    FALSE   Everything is fine
+
+--*/
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+    //DEBUGP (("[TAP] --> AdapterCheckForHangEx\n"));
+
+    //DEBUGP (("[TAP] <-- AdapterCheckForHangEx; status = FALSE\n"));
+
+    return FALSE;   // Everything is fine
+}
+
+NDIS_STATUS
+AdapterReset(
+    __in   NDIS_HANDLE            MiniportAdapterContext,
+    __out PBOOLEAN                AddressingReset
+    )
+/*++
+
+Routine Description:
+
+    MiniportResetEx is a required to issue a hardware reset to the NIC
+    and/or to reset the driver's software state.
+
+    1) The miniport driver can optionally complete any pending
+        OID requests. NDIS will submit no further OID requests
+        to the miniport driver for the NIC being reset until
+        the reset operation has finished. After the reset,
+        NDIS will resubmit to the miniport driver any OID requests
+        that were pending but not completed by the miniport driver
+        before the reset.
+
+    2) A deserialized miniport driver must complete any pending send
+        operations. NDIS will not requeue pending send packets for
+        a deserialized driver since NDIS does not maintain the send
+        queue for such a driver.
+
+    3) If MiniportReset returns NDIS_STATUS_PENDING, the driver must
+        complete the original request subsequently with a call to
+        NdisMResetComplete.
+
+    MiniportReset runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+AddressingReset - If multicast or functional addressing information
+                  or the lookahead size, is changed by a reset,
+                  MiniportReset must set the variable at AddressingReset
+                  to TRUE before it returns control. This causes NDIS to
+                  call the MiniportSetInformation function to restore
+                  the information.
+
+MiniportAdapterContext - Pointer to our adapter
+
+Return Value:
+
+    NDIS_STATUS
+
+--*/
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+    NDIS_STATUS    status;
+
+    UNREFERENCED_PARAMETER(MiniportAdapterContext);
+    UNREFERENCED_PARAMETER(AddressingReset);
+
+    DEBUGP (("[TAP] --> AdapterReset\n"));
+
+    // Indicate that adapter reset is in progress.
+    adapter->ResetInProgress = TRUE;
+
+    // See note above...
+    *AddressingReset = FALSE;
+
+    // BUGBUG!!! TODO!!! Lots of work here...
+
+    // Indicate that adapter reset has completed.
+    adapter->ResetInProgress = FALSE;
+
+    status = NDIS_STATUS_SUCCESS;
+
+    DEBUGP (("[TAP] <-- AdapterReset; status = %8.8X\n",status));
+
+    return status;
+}
+
+VOID
+AdapterDevicePnpEventNotify(
+    __in  NDIS_HANDLE             MiniportAdapterContext,
+    __in  PNET_DEVICE_PNP_EVENT   NetDevicePnPEvent
+    )
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+    DEBUGP (("[TAP] --> AdapterDevicePnpEventNotify\n"));
+
+/*
+    switch (NetDevicePnPEvent->DevicePnPEvent)
+    {
+        case NdisDevicePnPEventSurpriseRemoved:
+            //
+            // Called when NDIS receives IRP_MN_SUPRISE_REMOVAL.
+            // NDIS calls MiniportHalt function after this call returns.
+            //
+            MP_SET_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED);
+            DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventSurpriseRemoved\n", Adapter);
+            break;
+
+        case NdisDevicePnPEventPowerProfileChanged:
+            //
+            // After initializing a miniport driver and after miniport driver
+            // receives an OID_PNP_SET_POWER notification that specifies
+            // a device power state of NdisDeviceStateD0 (the powered-on state),
+            // NDIS calls the miniport's MiniportPnPEventNotify function with
+            // PnPEvent set to NdisDevicePnPEventPowerProfileChanged.
+            //
+            DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventPowerProfileChanged\n", Adapter);
+
+            if (NetDevicePnPEvent->InformationBufferLength == sizeof(ULONG))
+            {
+                ULONG NdisPowerProfile = *((PULONG)NetDevicePnPEvent->InformationBuffer);
+
+                if (NdisPowerProfile == NdisPowerProfileBattery)
+                {
+                    DEBUGP(MP_INFO, "[%p] The host system is running on battery power\n", Adapter);
+                }
+                if (NdisPowerProfile == NdisPowerProfileAcOnLine)
+                {
+                    DEBUGP(MP_INFO, "[%p] The host system is running on AC power\n", Adapter);
+                }
+            }
+            break;
+
+        default:
+            DEBUGP(MP_ERROR, "[%p] MPDevicePnpEventNotify: unknown PnP event 0x%x\n", Adapter, NetDevicePnPEvent->DevicePnPEvent);
+    }
+*/
+    DEBUGP (("[TAP] <-- AdapterDevicePnpEventNotify\n"));
+}
+
+VOID
+AdapterShutdownEx(
+    __in  NDIS_HANDLE             MiniportAdapterContext,
+    __in  NDIS_SHUTDOWN_ACTION    ShutdownAction
+    )
+/*++
+
+Routine Description:
+
+    The MiniportShutdownEx handler restores hardware to its initial state when
+    the system is shut down, whether by the user or because an unrecoverable
+    system error occurred. This is to ensure that the NIC is in a known
+    state and ready to be reinitialized when the machine is rebooted after
+    a system shutdown occurs for any reason, including a crash dump.
+
+    Here just disable the interrupt and stop the DMA engine.  Do not free
+    memory resources or wait for any packet transfers to complete.  Do not call
+    into NDIS at this time.
+
+    This can be called at aribitrary IRQL, including in the context of a
+    bugcheck.
+
+Arguments:
+
+    MiniportAdapterContext  Pointer to our adapter
+    ShutdownAction  The reason why NDIS called the shutdown function
+
+Return Value:
+
+    None.
+
+--*/
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+    UNREFERENCED_PARAMETER(ShutdownAction);
+    UNREFERENCED_PARAMETER(MiniportAdapterContext);
+
+    DEBUGP (("[TAP] --> AdapterShutdownEx\n"));
+
+    // Enter the Shutdown state.
+    DEBUGP (("[TAP] Miniport State: Shutdown\n"));
+
+    tapAdapterAcquireLock(adapter,FALSE);
+    adapter->Locked.AdapterState = MiniportShutdownState;
+    tapAdapterReleaseLock(adapter,FALSE);
+
+    //
+    // BUGBUG!!! FlushIrpQueues???
+    //
+
+    DEBUGP (("[TAP] <-- AdapterShutdownEx\n"));
+}
+
+
+// Free adapter context memory and associated resources.
+VOID
+tapAdapterContextFree(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    )
+{
+    PLIST_ENTRY listEntry = &Adapter->AdapterListLink;
+
+    DEBUGP (("[TAP] --> tapAdapterContextFree\n"));
+
+    // Adapter context should already be removed.
+    ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) );
+
+    // Insure that adapter context has been removed from global adapter list.
+    RemoveEntryList(&Adapter->AdapterListLink);
+
+    // Free the adapter lock.
+    NdisFreeSpinLock(&Adapter->AdapterLock);
+
+    // Free the ANSI NetCfgInstanceId buffer.
+    if(Adapter->NetCfgInstanceIdAnsi.Buffer != NULL)
+    {
+        RtlFreeAnsiString(&Adapter->NetCfgInstanceIdAnsi);
+    }
+
+    Adapter->NetCfgInstanceIdAnsi.Buffer = NULL;
+
+    // Free the receive NBL pool.
+    if(Adapter->ReceiveNblPool != NULL )
+    {
+        NdisFreeNetBufferListPool(Adapter->ReceiveNblPool);
+    }
+
+    Adapter->ReceiveNblPool = NULL;
+
+    NdisFreeMemory(Adapter,0,0);
+
+    DEBUGP (("[TAP] <-- tapAdapterContextFree\n"));
+}
+ULONG
+tapGetNetBufferFrameType(
+    __in PNET_BUFFER       NetBuffer
+    )
+/*++
+
+Routine Description:
+
+    Reads the network frame's destination address to determine the type
+    (broadcast, multicast, etc)
+
+    Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+    NetBuffer                 The NB to examine
+
+Return Value:
+
+    NDIS_PACKET_TYPE_BROADCAST
+    NDIS_PACKET_TYPE_MULTICAST
+    NDIS_PACKET_TYPE_DIRECTED
+
+--*/
+{
+    PETH_HEADER ethernetHeader;
+
+    ethernetHeader = (PETH_HEADER )NdisGetDataBuffer(
+                        NetBuffer,
+                        sizeof(ETH_HEADER),
+                        NULL,
+                        1,
+                        0
+                        );
+
+    ASSERT(ethernetHeader);
+
+    if (ETH_IS_BROADCAST(ethernetHeader->dest))
+    {
+        return NDIS_PACKET_TYPE_BROADCAST;
+    }
+    else if(ETH_IS_MULTICAST(ethernetHeader->dest))
+    {
+        return NDIS_PACKET_TYPE_MULTICAST;
+    }
+    else
+    {
+        return NDIS_PACKET_TYPE_DIRECTED;
+    }
+
+}
+
+ULONG
+tapGetNetBufferCountsFromNetBufferList(
+    __in PNET_BUFFER_LIST   NetBufferList,
+    __inout_opt PULONG      TotalByteCount      // Of all linked NBs
+    )
+/*++
+
+Routine Description:
+
+    Returns the number of net buffers linked to the net buffer list.
+
+    Optionally retuens the total byte count of all net buffers linked
+    to the net buffer list
+
+    Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+    NetBufferList                 The NBL to examine
+
+Return Value:
+
+    The number of net buffers linked to the net buffer list.
+
+--*/
+{
+    ULONG       netBufferCount = 0;
+    PNET_BUFFER currentNb;
+
+    if(TotalByteCount)
+    {
+        *TotalByteCount = 0;
+    }
+
+    currentNb = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+
+    while(currentNb)
+    {
+        ++netBufferCount;
+
+        if(TotalByteCount)
+        {
+            *TotalByteCount += NET_BUFFER_DATA_LENGTH(currentNb);
+        }
+
+        // Move to next NB
+        currentNb = NET_BUFFER_NEXT_NB(currentNb);
+    }
+
+    return netBufferCount;
+}
+
+VOID
+tapAdapterAcquireLock(
+    __in    PTAP_ADAPTER_CONTEXT    Adapter,
+    __in    BOOLEAN                 DispatchLevel
+    )
+{
+    ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql()));
+   
+    if (DispatchLevel)
+    {
+        NdisDprAcquireSpinLock(&Adapter->AdapterLock);
+    }
+    else
+    {
+        NdisAcquireSpinLock(&Adapter->AdapterLock);
+    }
+}
+
+VOID
+tapAdapterReleaseLock(
+    __in    PTAP_ADAPTER_CONTEXT    Adapter,
+    __in    BOOLEAN                 DispatchLevel
+    )
+{
+    ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql()));
+   
+    if (DispatchLevel)
+    {
+        NdisDprReleaseSpinLock(&Adapter->AdapterLock);
+    }
+    else
+    {
+        NdisReleaseSpinLock(&Adapter->AdapterLock);
+    }
+}
+
+

+ 348 - 0
windows/TapDriver6/adapter.h

@@ -0,0 +1,348 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __TAP_ADAPTER_CONTEXT_H_
+#define __TAP_ADAPTER_CONTEXT_H_
+
+#include "tap.h"
+
+// Memory allocation tags.
+#define TAP_ADAPTER_TAG             ((ULONG)'ApaT')     // "TapA
+#define TAP_RX_NBL_TAG              ((ULONG)'RpaT')     // "TapR
+#define TAP_RX_INJECT_BUFFER_TAG    ((ULONG)'IpaT')     // "TapI
+
+#define TAP_MAX_NDIS_NAME_LENGTH     64     // 38 character GUID string plus extra..
+
+// TAP receive indication NBL flag definitions.
+#define TAP_RX_NBL_FLAGS                    NBL_FLAGS_MINIPORT_RESERVED
+#define TAP_RX_NBL_FLAGS_CLEAR_ALL(_NBL)    ((_NBL)->Flags &= ~TAP_RX_NBL_FLAGS)
+#define TAP_RX_NBL_FLAG_SET(_NBL, _F)       ((_NBL)->Flags |= ((_F) & TAP_RX_NBL_FLAGS))
+#define TAP_RX_NBL_FLAG_CLEAR(_NBL, _F)     ((_NBL)->Flags &= ~((_F) & TAP_RX_NBL_FLAGS))
+#define TAP_RX_NBL_FLAG_TEST(_NBL, _F)      (((_NBL)->Flags & ((_F) & TAP_RX_NBL_FLAGS)) != 0)
+
+#define TAP_RX_NBL_FLAGS_IS_P2P             0x00001000
+#define TAP_RX_NBL_FLAGS_IS_INJECTED        0x00002000
+
+// MSDN Ref: http://msdn.microsoft.com/en-us/library/windows/hardware/ff560490(v=vs.85).aspx
+typedef
+enum _TAP_MINIPORT_ADAPTER_STATE
+{
+    // The Halted state is the initial state of all adapters. When an
+    // adapter is in the Halted state, NDIS can call the driver's
+    // MiniportInitializeEx function to initialize the adapter.
+    MiniportHaltedState,
+
+    // In the Shutdown state, a system shutdown and restart must occur
+    // before the system can use the adapter again.
+    MiniportShutdownState,
+
+    // In the Initializing state, a miniport driver completes any
+    //operations that are required to initialize an adapter.
+    MiniportInitializingState,
+
+    // Entering the Paused state...
+    MiniportPausingState,
+
+    // In the Paused state, the adapter does not indicate received
+    // network data or accept send requests.
+    MiniportPausedState,
+
+    // In the Running state, a miniport driver performs send and
+    // receive processing for an adapter.
+    MiniportRunning,
+
+    // In the Restarting state, a miniport driver completes any
+    // operations that are required to restart send and receive
+    // operations for an adapter.
+    MiniportRestartingState
+} TAP_MINIPORT_ADAPTER_STATE, *PTAP_MINIPORT_ADAPTER_STATE;
+
+//
+// Each adapter managed by this driver has a TapAdapter struct.
+// ------------------------------------------------------------
+// Since there is a one-to-one relationship between adapter instances
+// and device instances this structure is the device extension as well.
+//
+typedef struct _TAP_ADAPTER_CONTEXT
+{
+    LIST_ENTRY                  AdapterListLink;
+
+    volatile LONG               RefCount;
+
+    NDIS_HANDLE                 MiniportAdapterHandle;
+
+    NDIS_SPIN_LOCK              AdapterLock;    // Lock for protection of state and outstanding sends and recvs
+
+    //
+    // All fields that are protected by the AdapterLock are included
+    // in the Locked structure to remind us to take the Lock
+    // before accessing them :)
+    //
+    struct
+    {
+        TAP_MINIPORT_ADAPTER_STATE  AdapterState;
+    } Locked;
+
+    BOOLEAN                     ResetInProgress;
+
+    //
+    // NetCfgInstanceId as UNICODE_STRING
+    // ----------------------------------
+    // This a GUID string provided by NDIS that identifies the adapter instance.
+    // An example is:
+    // 
+    //    NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0}
+    //
+    // Other names are derived from NetCfgInstanceId. For example, MiniportName:
+    //
+    //    MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0}
+    //
+    NDIS_STRING                 NetCfgInstanceId;
+    WCHAR                       NetCfgInstanceIdBuffer[TAP_MAX_NDIS_NAME_LENGTH];
+
+# define MINIPORT_INSTANCE_ID(a) ((a)->NetCfgInstanceIdAnsi.Buffer)
+    ANSI_STRING                 NetCfgInstanceIdAnsi;   // Used occasionally
+
+    ULONG                       MtuSize;        // 1500 byte (typical)
+
+    // TRUE if adapter should always be "connected" even when device node
+    // is not open by a userspace process.
+    //
+    // FALSE if connection state is application controlled.
+    BOOLEAN                     MediaStateAlwaysConnected;
+
+    // TRUE if device is "connected".
+    BOOLEAN                     LogicalMediaState;
+
+    NDIS_DEVICE_POWER_STATE     CurrentPowerState;
+
+    BOOLEAN                     AllowNonAdmin;
+
+    MACADDR                     PermanentAddress;   // From registry, if available
+    MACADDR                     CurrentAddress;
+
+    // Device registration parameters from NdisRegisterDeviceEx.
+    NDIS_STRING                 DeviceName;
+    WCHAR                       DeviceNameBuffer[TAP_MAX_NDIS_NAME_LENGTH];
+
+    NDIS_STRING                 LinkName;
+    WCHAR                       LinkNameBuffer[TAP_MAX_NDIS_NAME_LENGTH];
+
+    NDIS_HANDLE                 DeviceHandle;
+    PDEVICE_OBJECT              DeviceObject;
+    BOOLEAN                     TapDeviceCreated;   // WAS: m_TapIsRunning
+
+    PFILE_OBJECT                TapFileObject;      // Exclusive access
+    BOOLEAN                     TapFileIsOpen;      // WAS: m_TapOpens
+    LONG                        TapFileOpenCount;   // WAS: m_NumTapOpens
+
+    // Cancel-Safe read IRP queue.
+    TAP_IRP_CSQ                 PendingReadIrpQueue;
+
+    // Queue containing TAP packets representing host send NBs. These are
+    // waiting to be read by user-mode application.
+    TAP_PACKET_QUEUE            SendPacketQueue;
+
+    // NBL pool for making TAP receive indications.
+    NDIS_HANDLE                 ReceiveNblPool;
+
+    volatile LONG               ReceiveNblInFlightCount;
+#define TAP_WAIT_POLL_LOOP_TIMEOUT  3000    // 3 seconds
+    NDIS_EVENT                  ReceiveNblInFlightCountZeroEvent;
+
+    // Info for point-to-point mode
+    BOOLEAN                     m_tun;
+    IPADDR                      m_localIP;
+    IPADDR                      m_remoteNetwork;
+    IPADDR                      m_remoteNetmask;
+    ETH_HEADER                  m_TapToUser;
+    ETH_HEADER                  m_UserToTap;
+    ETH_HEADER                  m_UserToTap_IPv6; // same as UserToTap but proto=ipv6
+
+    // Info for DHCP server masquerade
+    BOOLEAN                     m_dhcp_enabled;
+    IPADDR                      m_dhcp_addr;
+    ULONG                       m_dhcp_netmask;
+    IPADDR                      m_dhcp_server_ip;
+    BOOLEAN                     m_dhcp_server_arp;
+    MACADDR                     m_dhcp_server_mac;
+    ULONG                       m_dhcp_lease_time;
+    UCHAR                       m_dhcp_user_supplied_options_buffer[DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE];
+    ULONG                       m_dhcp_user_supplied_options_buffer_len;
+    BOOLEAN                     m_dhcp_received_discover;
+    ULONG                       m_dhcp_bad_requests;
+
+    // Multicast list. Fixed size.
+    ULONG                       ulMCListSize;
+    UCHAR                       MCList[TAP_MAX_MCAST_LIST][MACADDR_SIZE];
+
+    ULONG                       PacketFilter;
+    ULONG                       ulLookahead;
+
+    //
+    // Statistics
+    // -------------------------------------------------------------------------
+    //
+
+    // Packet counts
+    ULONG64                     FramesRxDirected;
+    ULONG64                     FramesRxMulticast;
+    ULONG64                     FramesRxBroadcast;
+    ULONG64                     FramesTxDirected;
+    ULONG64                     FramesTxMulticast;
+    ULONG64                     FramesTxBroadcast;
+
+    // Byte counts
+    ULONG64                     BytesRxDirected;
+    ULONG64                     BytesRxMulticast;
+    ULONG64                     BytesRxBroadcast;
+    ULONG64                     BytesTxDirected;
+    ULONG64                     BytesTxMulticast;
+    ULONG64                     BytesTxBroadcast;
+
+    // Count of transmit errors
+    ULONG                       TxAbortExcessCollisions;
+    ULONG                       TxLateCollisions;
+    ULONG                       TxDmaUnderrun;
+    ULONG                       TxLostCRS;
+    ULONG                       TxOKButDeferred;
+    ULONG                       OneRetry;
+    ULONG                       MoreThanOneRetry;
+    ULONG                       TotalRetries;
+    ULONG                       TransmitFailuresOther;
+
+    // Count of receive errors
+    ULONG                       RxCrcErrors;
+    ULONG                       RxAlignmentErrors;
+    ULONG                       RxResourceErrors;
+    ULONG                       RxDmaOverrunErrors;
+    ULONG                       RxCdtFrames;
+    ULONG                       RxRuntErrors;
+
+#if PACKET_TRUNCATION_CHECK
+    LONG                        m_RxTrunc, m_TxTrunc;
+#endif
+
+  BOOLEAN m_InterfaceIsRunning;
+  LONG m_Rx, m_RxErr;
+  NDIS_MEDIUM m_Medium;
+
+  // Help to tear down the adapter by keeping
+  // some state information on allocated
+  // resources.
+  BOOLEAN m_CalledAdapterFreeResources;
+  BOOLEAN m_RegisteredAdapterShutdownHandler;
+
+} TAP_ADAPTER_CONTEXT, *PTAP_ADAPTER_CONTEXT;
+
+FORCEINLINE
+LONG
+tapAdapterContextReference(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    )
+{
+    LONG    refCount = NdisInterlockedIncrement(&Adapter->RefCount);
+
+    ASSERT(refCount>1);     // Cannot dereference a zombie.
+
+    return refCount;
+}
+
+VOID
+tapAdapterContextFree(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    );
+
+FORCEINLINE
+LONG
+tapAdapterContextDereference(
+    IN PTAP_ADAPTER_CONTEXT     Adapter
+    )
+{
+    LONG    refCount = NdisInterlockedDecrement(&Adapter->RefCount);
+    ASSERT(refCount >= 0);
+    if (!refCount)
+    {
+        tapAdapterContextFree(Adapter);
+    }
+
+    return refCount;
+}
+
+VOID
+tapAdapterAcquireLock(
+    __in    PTAP_ADAPTER_CONTEXT    Adapter,
+    __in    BOOLEAN                 DispatchLevel
+    );
+
+VOID
+tapAdapterReleaseLock(
+    __in    PTAP_ADAPTER_CONTEXT    Adapter,
+    __in    BOOLEAN                 DispatchLevel
+    );
+
+// Returns with added reference on adapter context.
+PTAP_ADAPTER_CONTEXT
+tapAdapterContextFromDeviceObject(
+    __in PDEVICE_OBJECT DeviceObject
+    );
+
+BOOLEAN
+tapAdapterReadAndWriteReady(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    );
+
+NDIS_STATUS
+tapAdapterSendAndReceiveReady(
+    __in PTAP_ADAPTER_CONTEXT     Adapter
+    );
+
+ULONG
+tapGetNetBufferFrameType(
+    __in PNET_BUFFER       NetBuffer
+    );
+
+ULONG
+tapGetNetBufferCountsFromNetBufferList(
+    __in PNET_BUFFER_LIST   NetBufferList,
+    __inout_opt PULONG      TotalByteCount      // Of all linked NBs
+    );
+
+// Prototypes for standard NDIS miniport entry points
+MINIPORT_SET_OPTIONS                AdapterSetOptions;
+MINIPORT_INITIALIZE                 AdapterCreate;
+MINIPORT_HALT                       AdapterHalt;
+MINIPORT_UNLOAD                     TapDriverUnload;
+MINIPORT_PAUSE                      AdapterPause;
+MINIPORT_RESTART                    AdapterRestart;
+MINIPORT_OID_REQUEST                AdapterOidRequest;
+MINIPORT_SEND_NET_BUFFER_LISTS      AdapterSendNetBufferLists;
+MINIPORT_RETURN_NET_BUFFER_LISTS    AdapterReturnNetBufferLists;
+MINIPORT_CANCEL_SEND                AdapterCancelSend;
+MINIPORT_CHECK_FOR_HANG             AdapterCheckForHangEx;
+MINIPORT_RESET                      AdapterReset;
+MINIPORT_DEVICE_PNP_EVENT_NOTIFY    AdapterDevicePnpEventNotify;
+MINIPORT_SHUTDOWN                   AdapterShutdownEx;
+MINIPORT_CANCEL_OID_REQUEST         AdapterCancelOidRequest;
+
+#endif // __TAP_ADAPTER_CONTEXT_H_

+ 20 - 0
windows/TapDriver6/config.h

@@ -0,0 +1,20 @@
+/*
+#define PRODUCT_NAME			"@PRODUCT_NAME@"
+#define PRODUCT_VERSION			"@PRODUCT_VERSION@"
+#define PRODUCT_VERSION_RESOURCE	@PRODUCT_VERSION_RESOURCE@
+#define PRODUCT_TAP_WIN_COMPONENT_ID	"@PRODUCT_TAP_WIN_COMPONENT_ID@"
+#define PRODUCT_TAP_WIN_MAJOR		@PRODUCT_TAP_WIN_MAJOR@
+#define PRODUCT_TAP_WIN_MINOR		@PRODUCT_TAP_WIN_MINOR@
+#define PRODUCT_TAP_WIN_PROVIDER		"@PRODUCT_TAP_WIN_PROVIDER@"
+#define PRODUCT_TAP_WIN_DEVICE_DESCRIPTION	"@PRODUCT_TAP_WIN_DEVICE_DESCRIPTION@"
+#define PRODUCT_TAP_WIN_RELDATE		"@PRODUCT_TAP_WIN_RELDATE@"
+*/
+#define PRODUCT_NAME			"ZeroTier One Virtual Network Port"
+#define PRODUCT_VERSION			"3.0.0"
+#define PRODUCT_VERSION_RESOURCE	3,0,0,1
+#define PRODUCT_TAP_WIN_COMPONENT_ID	"zttap300"
+#define PRODUCT_TAP_WIN_MAJOR		3
+#define PRODUCT_TAP_WIN_MINOR		0
+#define PRODUCT_TAP_WIN_PROVIDER		"ZeroTier Networks"
+#define PRODUCT_TAP_WIN_DEVICE_DESCRIPTION	PRODUCT_NAME
+#define PRODUCT_TAP_WIN_RELDATE		"04/24/2015"

+ 195 - 0
windows/TapDriver6/constants.h

@@ -0,0 +1,195 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//====================================================================
+//                        Product and Version public settings
+//====================================================================
+
+#define PRODUCT_STRING PRODUCT_TAP_DEVICE_DESCRIPTION
+
+
+//
+// Update the driver version number every time you release a new driver
+// The high word is the major version. The low word is the minor version.
+// Also make sure that VER_FILEVERSION specified in the .RC file also
+// matches with the driver version because NDISTESTER checks for that.
+//
+#ifndef TAP_DRIVER_MAJOR_VERSION
+
+#define TAP_DRIVER_MAJOR_VERSION           0x04
+#define TAP_DRIVER_MINOR_VERSION           0x02
+
+#endif
+
+#define TAP_DRIVER_VENDOR_VERSION          ((TAP_DRIVER_MAJOR_VERSION << 16) | TAP_DRIVER_MINOR_VERSION)
+
+//
+// Define the NDIS miniport interface version that this driver targets.
+//
+#if defined(NDIS60_MINIPORT)
+#  define TAP_NDIS_MAJOR_VERSION    6
+#  define TAP_NDIS_MINOR_VERSION    0
+#elif defined(NDIS61_MINIPORT)
+#  define TAP_NDIS_MAJOR_VERSION    6
+#  define TAP_NDIS_MINOR_VERSION    1
+#elif defined(NDIS620_MINIPORT)
+#  define TAP_NDIS_MAJOR_VERSION    6
+#  define TAP_NDIS_MINOR_VERSION    20
+#elif defined(NDIS630_MINIPORT)
+#  define TAP_NDIS_MAJOR_VERSION    6
+#  define TAP_NDIS_MINOR_VERSION    30
+#else
+#define TAP_NDIS_MAJOR_VERSION      5
+#define TAP_NDIS_MINOR_VERSION      0
+#endif
+
+//===========================================================
+// Driver constants
+//===========================================================
+
+#define ETHERNET_HEADER_SIZE        (sizeof (ETH_HEADER))
+#define ETHERNET_MTU                1500
+#define ETHERNET_PACKET_SIZE        (ETHERNET_MTU + ETHERNET_HEADER_SIZE)
+#define DEFAULT_PACKET_LOOKAHEAD    (ETHERNET_PACKET_SIZE)
+#define VLAN_TAG_SIZE               4
+
+//===========================================================
+// Medium properties
+//===========================================================
+
+#define TAP_FRAME_HEADER_SIZE       ETHERNET_HEADER_SIZE
+#define TAP_FRAME_MAX_DATA_SIZE     ETHERNET_MTU
+#define TAP_MAX_FRAME_SIZE          (TAP_FRAME_HEADER_SIZE + TAP_FRAME_MAX_DATA_SIZE)
+#define TAP_MIN_FRAME_SIZE          60
+
+#define TAP_MEDIUM_TYPE             NdisMedium802_3
+
+//===========================================================
+// Physical adapter properties
+//===========================================================
+
+// The bus that connects the adapter to the PC.
+// (Example: PCI adapters should use NdisInterfacePci).
+#define TAP_INTERFACE_TYPE          NdisInterfaceInternal
+
+#define TAP_VENDOR_DESC             PRODUCT_TAP_WIN_DEVICE_DESCRIPTION
+
+// Highest byte is the NIC byte plus three vendor bytes. This is normally
+// obtained from the NIC.
+#define TAP_VENDOR_ID               0x00FFFFFF
+
+// If you have physical hardware on 802.3, use NdisPhysicalMedium802_3.
+#define TAP_PHYSICAL_MEDIUM         NdisPhysicalMediumUnspecified
+
+// Claim to be 100mbps duplex
+#define MEGABITS_PER_SECOND                1000000ULL
+#define TAP_XMIT_SPEED                     (100ULL*MEGABITS_PER_SECOND)
+#define TAP_RECV_SPEED                     (100ULL*MEGABITS_PER_SECOND)
+
+// Max number of multicast addresses supported in hardware
+#define TAP_MAX_MCAST_LIST                 32
+
+#define TAP_MAX_LOOKAHEAD                  TAP_FRAME_MAX_DATA_SIZE
+#define TAP_BUFFER_SIZE                    TAP_MAX_FRAME_SIZE
+
+// Set this value to TRUE if there is a physical adapter.
+#define TAP_HAS_PHYSICAL_CONNECTOR         FALSE
+#define TAP_ACCESS_TYPE                    NET_IF_ACCESS_BROADCAST
+#define TAP_DIRECTION_TYPE                 NET_IF_DIRECTION_SENDRECEIVE
+#define TAP_CONNECTION_TYPE                NET_IF_CONNECTION_DEDICATED
+
+// This value must match the *IfType in the driver .inf file
+#define TAP_IFTYPE                         IF_TYPE_ETHERNET_CSMACD
+
+//
+// This is a virtual device, so it can tolerate surprise removal and
+// suspend.  Ensure the correct flags are set for your hardware.
+//
+#define TAP_ADAPTER_ATTRIBUTES_FLAGS (\
+                NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK | NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM)
+
+#define TAP_SUPPORTED_FILTERS ( \
+                NDIS_PACKET_TYPE_DIRECTED   | \
+                NDIS_PACKET_TYPE_MULTICAST  | \
+                NDIS_PACKET_TYPE_BROADCAST  | \
+                NDIS_PACKET_TYPE_ALL_LOCAL  | \
+                NDIS_PACKET_TYPE_PROMISCUOUS | \
+                NDIS_PACKET_TYPE_ALL_MULTICAST)
+
+#define TAP_MAX_MCAST_LIST          32  // Max length of multicast address list
+
+//
+// Specify a bitmask that defines optional properties of the NIC.
+// This miniport indicates receive with NdisMIndicateReceiveNetBufferLists
+// 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.
+//
+
+#define TAP_MAC_OPTIONS (\
+                NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \
+                NDIS_MAC_OPTION_TRANSFERS_NOT_PEND  | \
+                NDIS_MAC_OPTION_NO_LOOPBACK)
+
+#define TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS 4
+
+
+// NDIS 6.x miniports must support all counters in OID_GEN_STATISTICS.
+#define TAP_SUPPORTED_STATISTICS (\
+                NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV    | \
+                NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV   | \
+                NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV   | \
+                NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV              | \
+                NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS           | \
+                NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR              | \
+                NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT   | \
+                NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT  | \
+                NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT  | \
+                NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT             | \
+                NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR             | \
+                NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS          | \
+                NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV     | \
+                NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV    | \
+                NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV    | \
+                NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT    | \
+                NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT   | \
+                NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT)
+
+
+#define MINIMUM_MTU                 576        // USE TCP Minimum MTU
+#define MAXIMUM_MTU                 65536      // IP maximum MTU
+
+#define PACKET_QUEUE_SIZE           64 // tap -> userspace queue size
+#define IRP_QUEUE_SIZE              16 // max number of simultaneous i/o operations from userspace
+#define INJECT_QUEUE_SIZE           16 // DHCP/ARP -> tap injection queue
+
+#define TAP_LITTLE_ENDIAN      // affects ntohs, htonl, etc. functions

+ 1169 - 0
windows/TapDriver6/device.c

@@ -0,0 +1,1169 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+#include <wdmsec.h> // for SDDLs
+
+//======================================================================
+// TAP Win32 Device I/O Callbacks
+//======================================================================
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, TapDeviceCreate)
+#pragma alloc_text( PAGE, TapDeviceControl)
+#pragma alloc_text( PAGE, TapDeviceCleanup)
+#pragma alloc_text( PAGE, TapDeviceClose)
+#endif // ALLOC_PRAGMA
+
+//===================================================================
+// Go back to default TAP mode from Point-To-Point mode.
+// Also reset (i.e. disable) DHCP Masq mode.
+//===================================================================
+VOID tapResetAdapterState(
+    __in PTAP_ADAPTER_CONTEXT Adapter
+    )
+{
+  // Point-To-Point
+  Adapter->m_tun = FALSE;
+  Adapter->m_localIP = 0;
+  Adapter->m_remoteNetwork = 0;
+  Adapter->m_remoteNetmask = 0;
+  NdisZeroMemory (&Adapter->m_TapToUser, sizeof (Adapter->m_TapToUser));
+  NdisZeroMemory (&Adapter->m_UserToTap, sizeof (Adapter->m_UserToTap));
+  NdisZeroMemory (&Adapter->m_UserToTap_IPv6, sizeof (Adapter->m_UserToTap_IPv6));
+
+  // DHCP Masq
+  Adapter->m_dhcp_enabled = FALSE;
+  Adapter->m_dhcp_server_arp = FALSE;
+  Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+  Adapter->m_dhcp_addr = 0;
+  Adapter->m_dhcp_netmask = 0;
+  Adapter->m_dhcp_server_ip = 0;
+  Adapter->m_dhcp_lease_time = 0;
+  Adapter->m_dhcp_received_discover = FALSE;
+  Adapter->m_dhcp_bad_requests = 0;
+  NdisZeroMemory (Adapter->m_dhcp_server_mac, MACADDR_SIZE);
+}
+
+// IRP_MJ_CREATE
+NTSTATUS
+TapDeviceCreate(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp
+    )
+/*++
+
+Routine Description:
+
+    This routine is called by the I/O system when the device is opened.
+
+    No action is performed other than completing the request successfully.
+
+Arguments:
+
+    DeviceObject - a pointer to the object that represents the device
+    that I/O is to be done on.
+
+    Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+    NT status code
+
+--*/
+{
+    NDIS_STATUS             status;
+    PIO_STACK_LOCATION      irpSp;// Pointer to current stack location
+    PTAP_ADAPTER_CONTEXT    adapter = NULL;
+    PFILE_OBJECT            originalFileObject;
+
+    PAGED_CODE();
+
+    DEBUGP (("[TAP] --> TapDeviceCreate\n"));
+
+    irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // Invalidate file context
+    //
+    irpSp->FileObject->FsContext = NULL;
+    irpSp->FileObject->FsContext2 = NULL;
+
+    //
+    // Find adapter context for this device.
+    // -------------------------------------
+    // Returns with added reference on adapter context.
+    //
+    adapter = tapAdapterContextFromDeviceObject(DeviceObject);
+
+    // Insure that adapter exists.
+    ASSERT(adapter);
+
+    if(adapter == NULL )
+    {
+        DEBUGP (("[TAP] release [%d.%d] open request; adapter not found\n",
+            TAP_DRIVER_MAJOR_VERSION,
+            TAP_DRIVER_MINOR_VERSION
+            ));
+
+        Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
+        Irp->IoStatus.Information = 0;
+
+        IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+        return STATUS_DEVICE_DOES_NOT_EXIST;
+    }
+
+    DEBUGP(("[%s] [TAP] release [%d.%d] open request (TapFileIsOpen=%d)\n",
+        MINIPORT_INSTANCE_ID(adapter),
+        TAP_DRIVER_MAJOR_VERSION,
+        TAP_DRIVER_MINOR_VERSION,
+        adapter->TapFileIsOpen
+        ));
+
+    // Enforce exclusive access
+    originalFileObject = InterlockedCompareExchangePointer(
+                    &adapter->TapFileObject,
+                    irpSp->FileObject,
+                    NULL
+                    );
+
+    if(originalFileObject == NULL)
+    {
+        irpSp->FileObject->FsContext = adapter; // Quick reference
+
+        status = STATUS_SUCCESS;
+    }
+    else
+    {
+        status = STATUS_UNSUCCESSFUL;
+    }
+
+    // Release the lock.
+    //tapAdapterReleaseLock(adapter,FALSE);
+
+    if(status == STATUS_SUCCESS)
+    {
+        // Reset adapter state on successful open.
+        tapResetAdapterState(adapter);
+
+        adapter->TapFileIsOpen = 1;    // Legacy...
+
+        // NOTE!!! Reference added by tapAdapterContextFromDeviceObject
+        // will be removed when file is closed.
+    }
+    else
+    {
+        DEBUGP (("[%s] TAP is presently unavailable (TapFileIsOpen=%d)\n",
+            MINIPORT_INSTANCE_ID(adapter), adapter->TapFileIsOpen
+            ));
+
+        NOTE_ERROR();
+
+        // Remove reference added by tapAdapterContextFromDeviceObject.
+        tapAdapterContextDereference(adapter);
+    }
+
+    // Complete the IRP.
+    Irp->IoStatus.Status = status;
+    Irp->IoStatus.Information = 0;
+
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+    DEBUGP (("[TAP] <-- TapDeviceCreate; status = %8.8X\n",status));
+
+    return status;
+}
+
+//===================================================
+// Tell Windows whether the TAP device should be
+// considered "connected" or "disconnected".
+//
+// Allows application control of media connect state.
+//===================================================
+VOID
+tapSetMediaConnectStatus(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in BOOLEAN                LogicalMediaState
+    )
+{
+    NDIS_STATUS_INDICATION  statusIndication;
+    NDIS_LINK_STATE         linkState;
+
+    NdisZeroMemory(&statusIndication, sizeof(NDIS_STATUS_INDICATION));
+    NdisZeroMemory(&linkState, sizeof(NDIS_LINK_STATE));
+
+    //
+    // Fill in object headers
+    //
+    statusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+    statusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+    statusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION);
+
+    linkState.Header.Revision = NDIS_LINK_STATE_REVISION_1;
+    linkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+    linkState.Header.Size = sizeof(NDIS_LINK_STATE);
+
+    //
+    // Link state buffer
+    //
+    if(Adapter->LogicalMediaState == TRUE)
+    {
+        linkState.MediaConnectState = MediaConnectStateConnected;
+    }
+
+    linkState.MediaDuplexState = MediaDuplexStateFull;
+    linkState.RcvLinkSpeed = TAP_RECV_SPEED;
+    linkState.XmitLinkSpeed = TAP_XMIT_SPEED;
+
+    //
+    // Fill in the status buffer
+    // 
+    statusIndication.StatusCode = NDIS_STATUS_LINK_STATE;
+    statusIndication.SourceHandle = Adapter->MiniportAdapterHandle;
+    statusIndication.DestinationHandle = NULL;
+    statusIndication.RequestId = 0;
+
+    statusIndication.StatusBuffer = &linkState;
+    statusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE);
+
+    // Fill in new media connect state.
+    if ( (Adapter->LogicalMediaState != LogicalMediaState) && !Adapter->MediaStateAlwaysConnected)
+    {
+        Adapter->LogicalMediaState = LogicalMediaState;
+
+        if (LogicalMediaState == TRUE)
+        {
+            linkState.MediaConnectState = MediaConnectStateConnected;
+
+            DEBUGP (("[TAP] Set MediaConnectState: Connected.\n"));
+        }
+        else
+        {
+            linkState.MediaConnectState = MediaConnectStateDisconnected;
+
+            DEBUGP (("[TAP] Set MediaConnectState: Disconnected.\n"));
+        }
+    }
+
+    // Make the status indication.
+    if(Adapter->Locked.AdapterState != MiniportHaltedState)
+    {
+        NdisMIndicateStatusEx(Adapter->MiniportAdapterHandle, &statusIndication);
+    }
+}
+
+//======================================================
+// If DHCP mode is used together with tun
+// mode, consider the fact that the P2P remote subnet
+// might enclose the DHCP masq server address.
+//======================================================
+VOID
+CheckIfDhcpAndTunMode (
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    )
+{
+    if (Adapter->m_tun && Adapter->m_dhcp_enabled)
+    {
+        if ((Adapter->m_dhcp_server_ip & Adapter->m_remoteNetmask) == Adapter->m_remoteNetwork)
+        {
+            ETH_COPY_NETWORK_ADDRESS (Adapter->m_dhcp_server_mac, Adapter->m_TapToUser.dest);
+            Adapter->m_dhcp_server_arp = FALSE;
+        }
+    }
+}
+
+// IRP_MJ_DEVICE_CONTROL callback.
+NTSTATUS
+TapDeviceControl(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called by the I/O system to perform a device I/O
+    control function.
+
+Arguments:
+
+    DeviceObject - a pointer to the object that represents the device
+        that I/O is to be done on.
+
+    Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+    NT status code
+
+--*/
+
+{
+    NTSTATUS                ntStatus = STATUS_SUCCESS; // Assume success
+    PIO_STACK_LOCATION      irpSp; // Pointer to current stack location
+    PTAP_ADAPTER_CONTEXT    adapter = NULL;
+    ULONG                   inBufLength; // Input buffer length
+    ULONG                   outBufLength; // Output buffer length
+    PCHAR                   inBuf, outBuf; // pointer to Input and output buffer
+    PMDL                    mdl = NULL;
+    PCHAR                   buffer = NULL;
+
+    PAGED_CODE();
+
+    irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    //
+    // Fetch adapter context for this device.
+    // --------------------------------------
+    // Adapter pointer was stashed in FsContext when handle was opened.
+    //
+    adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+    ASSERT(adapter);
+
+    inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
+    outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (!inBufLength || !outBufLength)
+    {
+        ntStatus = STATUS_INVALID_PARAMETER;
+        goto End;
+    }
+
+    //
+    // Determine which I/O control code was specified.
+    //
+    switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
+    {
+    case TAP_WIN_IOCTL_GET_MAC:
+        {
+            if (outBufLength >= MACADDR_SIZE )
+            {
+                ETH_COPY_NETWORK_ADDRESS(
+                    Irp->AssociatedIrp.SystemBuffer,
+                    adapter->CurrentAddress
+                    );
+
+                Irp->IoStatus.Information = MACADDR_SIZE;
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+            }
+        }
+        break;
+
+    case TAP_WIN_IOCTL_GET_VERSION:
+        {
+            const ULONG size = sizeof (ULONG) * 3;
+
+            if (outBufLength >= size)
+            {
+                ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]
+                    = TAP_DRIVER_MAJOR_VERSION;
+
+                ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[1]
+                    = TAP_DRIVER_MINOR_VERSION;
+
+                ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[2]
+#if DBG
+                    = 1;
+#else
+                    = 0;
+#endif
+                Irp->IoStatus.Information = size;
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+            }
+        }
+        break;
+
+    case TAP_WIN_IOCTL_GET_MTU:
+        {
+            const ULONG size = sizeof (ULONG) * 1;
+
+            if (outBufLength >= size)
+            {
+                ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]
+                    = adapter->MtuSize;
+
+                Irp->IoStatus.Information = size;
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+            }
+        }
+        break;
+
+    case TAP_WIN_IOCTL_CONFIG_TUN:
+        {
+            if(inBufLength >= sizeof(IPADDR)*3)
+            {
+                MACADDR dest;
+
+                adapter->m_tun = FALSE;
+
+                GenerateRelatedMAC (dest, adapter->CurrentAddress, 1);
+
+                adapter->m_localIP =       ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0];
+                adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1];
+                adapter->m_remoteNetmask = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2];
+
+                // Sanity check on network/netmask
+                if ((adapter->m_remoteNetwork & adapter->m_remoteNetmask) != adapter->m_remoteNetwork)
+                {
+                    NOTE_ERROR();
+                    Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress);
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest);
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest);
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress);
+
+                adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4);
+                adapter->m_UserToTap_IPv6 = adapter->m_UserToTap;
+                adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6);
+
+                adapter->m_tun = TRUE;
+
+                CheckIfDhcpAndTunMode (adapter);
+
+                Irp->IoStatus.Information = 1; // Simple boolean value
+
+                DEBUGP (("[TAP] Set TUN mode.\n"));
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+            }
+        }
+        break;
+
+    case TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT:
+        {
+            if(inBufLength >= sizeof(IPADDR)*2)
+            {
+                MACADDR dest;
+
+                adapter->m_tun = FALSE;
+
+                GenerateRelatedMAC (dest, adapter->CurrentAddress, 1);
+
+                adapter->m_localIP =       ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0];
+                adapter->m_remoteNetwork = ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1];
+                adapter->m_remoteNetmask = ~0;
+
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.src, adapter->CurrentAddress);
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_TapToUser.dest, dest);
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.src, dest);
+                ETH_COPY_NETWORK_ADDRESS (adapter->m_UserToTap.dest, adapter->CurrentAddress);
+
+                adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons (NDIS_ETH_TYPE_IPV4);
+                adapter->m_UserToTap_IPv6 = adapter->m_UserToTap;
+                adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6);
+
+                adapter->m_tun = TRUE;
+
+                CheckIfDhcpAndTunMode (adapter);
+
+                Irp->IoStatus.Information = 1; // Simple boolean value
+
+                DEBUGP (("[TAP] Set P2P mode.\n"));
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+            }
+        }
+        break;
+
+    case TAP_WIN_IOCTL_CONFIG_DHCP_MASQ:
+        {
+            if(inBufLength >= sizeof(IPADDR)*4)
+            {
+                adapter->m_dhcp_enabled = FALSE;
+                adapter->m_dhcp_server_arp = FALSE;
+                adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+
+                // Adapter IP addr / netmask
+                adapter->m_dhcp_addr =
+                    ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[0];
+                adapter->m_dhcp_netmask =
+                    ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[1];
+
+                // IP addr of DHCP masq server
+                adapter->m_dhcp_server_ip =
+                    ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[2];
+
+                // Lease time in seconds
+                adapter->m_dhcp_lease_time =
+                    ((IPADDR*) (Irp->AssociatedIrp.SystemBuffer))[3];
+
+                GenerateRelatedMAC(
+                    adapter->m_dhcp_server_mac,
+                    adapter->CurrentAddress,
+                    2
+                    );
+
+                adapter->m_dhcp_enabled = TRUE;
+                adapter->m_dhcp_server_arp = TRUE;
+
+                CheckIfDhcpAndTunMode (adapter);
+
+                Irp->IoStatus.Information = 1; // Simple boolean value
+
+                DEBUGP (("[TAP] Configured DHCP MASQ.\n"));
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+            }
+        }
+        break;
+
+    case TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT:
+        {
+            if (inBufLength <=  DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE
+                && adapter->m_dhcp_enabled)
+            {
+                adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+
+                NdisMoveMemory(
+                    adapter->m_dhcp_user_supplied_options_buffer,
+                    Irp->AssociatedIrp.SystemBuffer,
+                    inBufLength
+                    );
+
+                adapter->m_dhcp_user_supplied_options_buffer_len = 
+                    inBufLength;
+
+                Irp->IoStatus.Information = 1; // Simple boolean value
+
+                DEBUGP (("[TAP] Set DHCP OPT.\n"));
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+            }
+        }
+        break;
+
+    case TAP_WIN_IOCTL_GET_INFO:
+        {
+            char state[16];
+
+            // Fetch adapter (miniport) state.
+            if (tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS)
+                state[0] = 'A';
+            else
+                state[0] = 'a';
+
+            if (tapAdapterReadAndWriteReady(adapter))
+                state[1] = 'T';
+            else
+                state[1] = 't';
+
+            state[2] = '0' + adapter->CurrentPowerState;
+
+            if (adapter->MediaStateAlwaysConnected)
+                state[3] = 'C';
+            else
+                state[3] = 'c';
+
+            state[4] = '\0';
+
+            // BUGBUG!!! What follows, and is not yet implemented, is a real mess.
+            // BUGBUG!!! Tied closely to the NDIS 5 implementation. Need to map
+            //    as much as possible to the NDIS 6 implementation.
+            Irp->IoStatus.Status = ntStatus = RtlStringCchPrintfExA (
+                ((LPTSTR) (Irp->AssociatedIrp.SystemBuffer)),
+                outBufLength,
+                NULL,
+                NULL,
+                STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
+#if PACKET_TRUNCATION_CHECK
+                "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]",
+#else
+                "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]",
+#endif
+                state,
+                g_LastErrorFilename,
+                g_LastErrorLineNumber,
+                (int)adapter->TapFileOpenCount,
+                (int)(adapter->FramesTxDirected + adapter->FramesTxMulticast + adapter->FramesTxBroadcast),
+                (int)adapter->TransmitFailuresOther,
+#if PACKET_TRUNCATION_CHECK
+                (int)adapter->m_TxTrunc,
+#endif
+                (int)adapter->m_Rx,
+                (int)adapter->m_RxErr,
+#if PACKET_TRUNCATION_CHECK
+                (int)adapter->m_RxTrunc,
+#endif
+                (int)adapter->PendingReadIrpQueue.Count,
+                (int)adapter->PendingReadIrpQueue.MaxCount,
+                (int)IRP_QUEUE_SIZE,        // Ignored in NDIS 6 driver...
+
+                (int)adapter->SendPacketQueue.Count,
+                (int)adapter->SendPacketQueue.MaxCount,
+                (int)PACKET_QUEUE_SIZE,
+
+                (int)0,         // adapter->InjectPacketQueue.Count - Unused
+                (int)0,         // adapter->InjectPacketQueue.MaxCount - Unused
+                (int)INJECT_QUEUE_SIZE
+                );
+
+            Irp->IoStatus.Information = outBufLength;
+
+            // BUGBUG!!! Fail because this is not completely implemented.
+            ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+        }
+        break;
+
+#if DBG
+    case TAP_WIN_IOCTL_GET_LOG_LINE:
+        {
+            if (GetDebugLine( (LPTSTR)Irp->AssociatedIrp.SystemBuffer,outBufLength))
+            {
+                Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
+            }
+            else
+            {
+                Irp->IoStatus.Status = ntStatus = STATUS_UNSUCCESSFUL;
+            }
+
+            Irp->IoStatus.Information = outBufLength;
+
+            break;
+        }
+#endif
+
+    case TAP_WIN_IOCTL_SET_MEDIA_STATUS:
+        {
+            if(inBufLength >= sizeof(ULONG))
+            {
+                ULONG parm = ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0];
+                tapSetMediaConnectStatus (adapter, (BOOLEAN) parm);
+                Irp->IoStatus.Information = 1;
+            }
+            else
+            {
+                NOTE_ERROR();
+                Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+            }
+        }
+        break;
+
+    default:
+
+        //
+        // The specified I/O control code is unrecognized by this driver.
+        //
+        ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+        break;
+    }
+
+End:
+
+    //
+    // Finish the I/O operation by simply completing the packet and returning
+    // the same status as in the packet itself.
+    //
+    Irp->IoStatus.Status = ntStatus;
+
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+    return ntStatus;
+}
+
+// Flush the pending read IRP queue.
+VOID
+tapFlushIrpQueues(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    )
+{
+
+    DEBUGP (("[TAP] tapFlushIrpQueues: Flushing %d pending read IRPs\n",
+        Adapter->PendingReadIrpQueue.Count));
+
+    tapIrpCsqFlush(&Adapter->PendingReadIrpQueue);
+}
+
+// IRP_MJ_CLEANUP
+NTSTATUS
+TapDeviceCleanup(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp
+    )
+/*++
+
+Routine Description:
+
+    Receipt of this request indicates that the last handle for a file
+    object that is associated with the target device object has been closed
+    (but, due to outstanding I/O requests, might not have been released).
+
+    A driver that holds pending IRPs internally must implement a routine for
+    IRP_MJ_CLEANUP. When the routine is called, the driver should cancel all
+    the pending IRPs that belong to the file object identified by the IRP_MJ_CLEANUP
+    call.
+    
+    In other words, it should cancel all the IRPs that have the same file-object
+    pointer as the one supplied in the current I/O stack location of the IRP for the
+    IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should
+    not be canceled. Also, if an outstanding IRP is completed immediately, the
+    driver does not have to cancel it.
+
+Arguments:
+
+    DeviceObject - a pointer to the object that represents the device
+    to be cleaned up.
+
+    Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+    NT status code
+
+--*/
+
+{
+    NDIS_STATUS             status = NDIS_STATUS_SUCCESS;   // Always succeed.
+    PIO_STACK_LOCATION      irpSp;  // Pointer to current stack location
+    PTAP_ADAPTER_CONTEXT    adapter = NULL;
+
+    PAGED_CODE();
+
+    DEBUGP (("[TAP] --> TapDeviceCleanup\n"));
+
+    irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // Fetch adapter context for this device.
+    // --------------------------------------
+    // Adapter pointer was stashed in FsContext when handle was opened.
+    //
+    adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+    // Insure that adapter exists.
+    ASSERT(adapter);
+
+    if(adapter == NULL )
+    {
+        DEBUGP (("[TAP] release [%d.%d] cleanup request; adapter not found\n",
+            TAP_DRIVER_MAJOR_VERSION,
+            TAP_DRIVER_MINOR_VERSION
+            ));
+    }
+
+    if(adapter != NULL )
+    {
+        adapter->TapFileIsOpen = 0;    // Legacy...
+
+        // Disconnect from media.
+        tapSetMediaConnectStatus(adapter,FALSE);
+
+        // Reset adapter state when cleaning up;
+        tapResetAdapterState(adapter);
+
+        // BUGBUG!!! Use RemoveLock???
+
+        //
+        // Flush pending send TAP packet queue.
+        //
+        tapFlushSendPacketQueue(adapter);
+
+        ASSERT(adapter->SendPacketQueue.Count == 0);
+
+        //
+        // Flush the pending IRP queues
+        //
+        tapFlushIrpQueues(adapter);
+
+        ASSERT(adapter->PendingReadIrpQueue.Count == 0);
+    }
+
+    // Complete the IRP.
+    Irp->IoStatus.Status = status;
+    Irp->IoStatus.Information = 0;
+
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+    DEBUGP (("[TAP] <-- TapDeviceCleanup; status = %8.8X\n",status));
+
+    return status;
+}
+
+// IRP_MJ_CLOSE
+NTSTATUS
+TapDeviceClose(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp
+    )
+/*++
+
+Routine Description:
+
+    Receipt of this request indicates that the last handle of the file
+    object that is associated with the target device object has been closed
+    and released.
+    
+    All outstanding I/O requests have been completed or canceled.
+
+Arguments:
+
+    DeviceObject - a pointer to the object that represents the device
+    to be closed.
+
+    Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+    NT status code
+
+--*/
+
+{
+    NDIS_STATUS             status = NDIS_STATUS_SUCCESS;   // Always succeed.
+    PIO_STACK_LOCATION      irpSp;  // Pointer to current stack location
+    PTAP_ADAPTER_CONTEXT    adapter = NULL;
+
+    PAGED_CODE();
+
+    DEBUGP (("[TAP] --> TapDeviceClose\n"));
+
+    irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // Fetch adapter context for this device.
+    // --------------------------------------
+    // Adapter pointer was stashed in FsContext when handle was opened.
+    //
+    adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+    // Insure that adapter exists.
+    ASSERT(adapter);
+
+    if(adapter == NULL )
+    {
+        DEBUGP (("[TAP] release [%d.%d] close request; adapter not found\n",
+            TAP_DRIVER_MAJOR_VERSION,
+            TAP_DRIVER_MINOR_VERSION
+            ));
+    }
+
+    if(adapter != NULL )
+    {
+        if(adapter->TapFileObject == NULL)
+        {
+            // Should never happen!!!
+            ASSERT(FALSE);
+        }
+        else
+        {
+            ASSERT(irpSp->FileObject->FsContext == adapter);
+
+            ASSERT(adapter->TapFileObject == irpSp->FileObject);
+        }
+
+        adapter->TapFileObject = NULL;
+        irpSp->FileObject = NULL;
+
+        // Remove reference added by when handle was opened.
+        tapAdapterContextDereference(adapter);
+    }
+
+    // Complete the IRP.
+    Irp->IoStatus.Status = status;
+    Irp->IoStatus.Information = 0;
+
+    IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+    DEBUGP (("[TAP] <-- TapDeviceClose; status = %8.8X\n",status));
+
+    return status;
+}
+
+NTSTATUS
+tapConcatenateNdisStrings(
+    __inout     PNDIS_STRING    DestinationString,
+    __in_opt    PNDIS_STRING    SourceString1,
+    __in_opt    PNDIS_STRING    SourceString2,
+    __in_opt    PNDIS_STRING    SourceString3
+    )
+{
+    NTSTATUS status;
+
+    ASSERT(SourceString1 && SourceString2 && SourceString3);
+
+    status = RtlAppendUnicodeStringToString(
+                DestinationString,
+                SourceString1
+                );
+
+    if(status == STATUS_SUCCESS)
+    {
+        status = RtlAppendUnicodeStringToString(
+                    DestinationString,
+                    SourceString2
+                    );
+
+        if(status == STATUS_SUCCESS)
+        {
+            status = RtlAppendUnicodeStringToString(
+                        DestinationString,
+                        SourceString3
+                        );
+        }
+    }
+
+    return status;
+}
+
+NTSTATUS
+tapMakeDeviceNames(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    )
+{
+    NDIS_STATUS     status;
+    NDIS_STRING     deviceNamePrefix = NDIS_STRING_CONST("\\Device\\");
+    NDIS_STRING     tapNameSuffix = NDIS_STRING_CONST(".tap");
+
+    // Generate DeviceName from NetCfgInstanceId.
+    Adapter->DeviceName.Buffer = Adapter->DeviceNameBuffer;
+    Adapter->DeviceName.MaximumLength = sizeof(Adapter->DeviceNameBuffer);
+
+    status = tapConcatenateNdisStrings(
+                &Adapter->DeviceName,
+                &deviceNamePrefix,
+                &Adapter->NetCfgInstanceId,
+                &tapNameSuffix
+                );
+
+    if(status == STATUS_SUCCESS)
+    {
+        NDIS_STRING     linkNamePrefix = NDIS_STRING_CONST("\\DosDevices\\Global\\");
+
+        Adapter->LinkName.Buffer = Adapter->LinkNameBuffer;
+        Adapter->LinkName.MaximumLength = sizeof(Adapter->LinkNameBuffer);
+
+        status = tapConcatenateNdisStrings(
+                    &Adapter->LinkName,
+                    &linkNamePrefix,
+                    &Adapter->NetCfgInstanceId,
+                    &tapNameSuffix
+                    );
+    }
+
+    return status;
+}
+
+NDIS_STATUS
+CreateTapDevice(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+   )
+{
+    NDIS_STATUS                     status;
+    NDIS_DEVICE_OBJECT_ATTRIBUTES   deviceAttribute;
+    PDRIVER_DISPATCH                dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
+
+    DEBUGP (("[TAP] version [%d.%d] creating tap device: %wZ\n",
+        TAP_DRIVER_MAJOR_VERSION,
+        TAP_DRIVER_MINOR_VERSION,
+        &Adapter->NetCfgInstanceId));
+
+    // Generate DeviceName and LinkName from NetCfgInstanceId.
+    status = tapMakeDeviceNames(Adapter);
+
+    if (NT_SUCCESS(status))
+    {
+        DEBUGP (("[TAP] DeviceName: %wZ\n",&Adapter->DeviceName));
+        DEBUGP (("[TAP] LinkName: %wZ\n",&Adapter->LinkName));
+
+        // Initialize dispatch table.
+        NdisZeroMemory(dispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
+
+        dispatchTable[IRP_MJ_CREATE] = TapDeviceCreate;
+        dispatchTable[IRP_MJ_CLEANUP] = TapDeviceCleanup;
+        dispatchTable[IRP_MJ_CLOSE] = TapDeviceClose;
+        dispatchTable[IRP_MJ_READ] = TapDeviceRead;
+        dispatchTable[IRP_MJ_WRITE] = TapDeviceWrite;
+        dispatchTable[IRP_MJ_DEVICE_CONTROL] = TapDeviceControl;
+
+        //
+        // Create a device object and register dispatch handlers
+        //
+        NdisZeroMemory(&deviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));
+
+        deviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
+        deviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
+        deviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES);
+
+        deviceAttribute.DeviceName = &Adapter->DeviceName;
+        deviceAttribute.SymbolicName = &Adapter->LinkName;
+        deviceAttribute.MajorFunctions = &dispatchTable[0];
+        //deviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
+
+#if ENABLE_NONADMIN
+        if(Adapter->AllowNonAdmin)
+        {
+            //
+            // SDDL_DEVOBJ_SYS_ALL_WORLD_RWX_RES_RWX allows the kernel and system complete
+            // control over the device. By default the admin can access the entire device,
+            // but cannot change the ACL (the admin must take control of the device first)
+            //
+            // Everyone else, including "restricted" or "untrusted" code can read or write
+            // to the device. Traversal beneath the device is also granted (removing it
+            // would only effect storage devices, except if the "bypass-traversal"
+            // privilege was revoked).
+            //
+            deviceAttribute.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX;
+        }
+#endif
+
+        status = NdisRegisterDeviceEx(
+                    Adapter->MiniportAdapterHandle,
+                    &deviceAttribute,
+                    &Adapter->DeviceObject,
+                    &Adapter->DeviceHandle
+                    );
+    }
+
+    ASSERT(NT_SUCCESS(status));
+
+    if (NT_SUCCESS(status))
+    {
+        // Set TAP device flags.
+        (Adapter->DeviceObject)->Flags &= ~DO_BUFFERED_IO;
+        (Adapter->DeviceObject)->Flags |= DO_DIRECT_IO;;
+
+      //========================
+      // Finalize initialization
+      //========================
+
+      Adapter->TapDeviceCreated = TRUE;
+
+      DEBUGP (("[%wZ] successfully created TAP device [%wZ]\n",
+	        &Adapter->NetCfgInstanceId,
+            &Adapter->DeviceName
+            ));
+    }
+
+    DEBUGP (("[TAP] <-- CreateTapDevice; status = %8.8X\n",status));
+
+    return status;
+}
+
+//
+// DestroyTapDevice is called from AdapterHalt and NDIS miniport
+// is in Halted state. Prior to entering the Halted state the
+// miniport would have passed through the Pausing and Paused
+// states. These miniport states have responsibility for waiting
+// until NDIS network operations have completed.
+//
+VOID
+DestroyTapDevice(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+   )
+{
+    DEBUGP (("[TAP] --> DestroyTapDevice; Adapter: %wZ\n",
+        &Adapter->NetCfgInstanceId));
+
+    //
+    // Let clients know we are shutting down
+    //
+    Adapter->TapDeviceCreated = FALSE;
+
+    //
+    // Flush pending send TAP packet queue.
+    //
+    tapFlushSendPacketQueue(Adapter);
+
+    ASSERT(Adapter->SendPacketQueue.Count == 0);
+
+    //
+    // Flush IRP queues. Wait for pending I/O. Etc.
+    // --------------------------------------------
+    // Exhaust IRP and packet queues. Any pending IRPs will
+    // be cancelled, causing user-space to get this error
+    // on overlapped reads:
+    //
+    //   ERROR_OPERATION_ABORTED, code=995
+    //
+    //   "The I/O operation has been aborted because of either a
+    //   thread exit or an application request."
+    //
+    // It's important that user-space close the device handle
+    // when this code is returned, so that when we finally
+    // do a NdisMDeregisterDeviceEx, the device reference count
+    // is 0.  Otherwise the driver will not unload even if the
+    // the last adapter has been halted.
+    //
+    // The act of flushing the queues at this point should result in the user-mode
+    // application closing the adapter's device handle. Closing the handle will
+    // result in the TapDeviceCleanup call being made, followed by the a call to
+    // the TapDeviceClose callback.
+    //
+    tapFlushIrpQueues(Adapter);
+
+    ASSERT(Adapter->PendingReadIrpQueue.Count == 0);
+
+    //
+    // Deregister the Win32 device.
+    // ----------------------------
+    // When a driver calls NdisDeregisterDeviceEx, the I/O manager deletes the
+    // target device object if there are no outstanding references to it. However,
+    // if any outstanding references remain, the I/O manager marks the device
+    // object as "delete pending" and deletes the device object when the references
+    // are finally released.
+    //
+    if(Adapter->DeviceHandle)
+    {
+        DEBUGP (("[TAP] Calling NdisDeregisterDeviceEx\n"));
+        NdisDeregisterDeviceEx(Adapter->DeviceHandle);
+    }
+
+    Adapter->DeviceHandle = NULL;
+
+    DEBUGP (("[TAP] <-- DestroyTapDevice\n"));
+}
+

+ 50 - 0
windows/TapDriver6/device.h

@@ -0,0 +1,50 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __TAP_DEVICE_H_
+#define __TAP_DEVICE_H_
+
+//======================================================================
+// TAP Prototypes for standard Win32 device I/O entry points
+//======================================================================
+
+__drv_dispatchType(IRP_MJ_CREATE)
+DRIVER_DISPATCH TapDeviceCreate;
+
+__drv_dispatchType(IRP_MJ_READ)
+DRIVER_DISPATCH TapDeviceRead;
+
+__drv_dispatchType(IRP_MJ_WRITE)
+DRIVER_DISPATCH TapDeviceWrite;
+
+__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
+DRIVER_DISPATCH TapDeviceControl;
+
+__drv_dispatchType(IRP_MJ_CLEANUP)
+DRIVER_DISPATCH TapDeviceCleanup;
+
+__drv_dispatchType(IRP_MJ_CLOSE)
+DRIVER_DISPATCH TapDeviceClose;
+
+#endif // __TAP_DEVICE_H_

+ 710 - 0
windows/TapDriver6/dhcp.c

@@ -0,0 +1,710 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "tap.h"
+
+//=========================
+// Code to set DHCP options
+//=========================
+
+VOID
+SetDHCPOpt(
+    __in DHCPMsg *m,
+    __in void *data,
+    __in unsigned int len
+    )
+{
+    if (!m->overflow)
+    {
+        if (m->optlen + len <= DHCP_OPTIONS_BUFFER_SIZE)
+        {
+            if (len)
+            {
+                NdisMoveMemory (m->msg.options + m->optlen, data, len);
+                m->optlen += len;
+            }
+        }
+        else
+        {
+            m->overflow = TRUE;
+        }
+    }
+}
+
+VOID
+SetDHCPOpt0(
+    __in DHCPMsg *msg,
+    __in int type
+    )
+{
+    DHCPOPT0 opt;
+    opt.type = (UCHAR) type;
+    SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+VOID
+SetDHCPOpt8(
+    __in DHCPMsg *msg,
+    __in int type,
+    __in ULONG data
+    )
+{
+    DHCPOPT8 opt;
+    opt.type = (UCHAR) type;
+    opt.len = sizeof (opt.data);
+    opt.data = (UCHAR) data;
+    SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+VOID
+SetDHCPOpt32(
+    __in DHCPMsg *msg,
+    __in int type,
+    __in ULONG data
+    )
+{
+    DHCPOPT32 opt;
+    opt.type = (UCHAR) type;
+    opt.len = sizeof (opt.data);
+    opt.data = data;
+    SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+//==============
+// Checksum code
+//==============
+
+USHORT
+ip_checksum(
+    __in const UCHAR *buf,
+    __in const int len_ip_header
+    )
+{
+    USHORT word16;
+    ULONG sum = 0;
+    int i;
+
+    // make 16 bit words out of every two adjacent 8 bit words in the packet
+    // and add them up
+    for (i = 0; i < len_ip_header - 1; i += 2)
+    {
+        word16 = ((buf[i] << 8) & 0xFF00) + (buf[i+1] & 0xFF);
+        sum += (ULONG) word16;
+    }
+
+    // take only 16 bits out of the 32 bit sum and add up the carries
+    while (sum >> 16)
+    {
+        sum = (sum & 0xFFFF) + (sum >> 16);
+    }
+
+    // one's complement the result
+    return ((USHORT) ~sum);
+}
+
+USHORT
+udp_checksum (
+    __in const UCHAR *buf,
+    __in const int len_udp,
+    __in const UCHAR *src_addr,
+    __in const UCHAR *dest_addr
+    )
+{
+    USHORT word16;
+    ULONG sum = 0;
+    int i;
+
+    // make 16 bit words out of every two adjacent 8 bit words and 
+    // calculate the sum of all 16 bit words
+    for (i = 0; i < len_udp; i += 2)
+    {
+        word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
+        sum += word16;
+    }
+
+    // add the UDP pseudo header which contains the IP source and destination addresses
+    for (i = 0; i < 4; i += 2)
+    {
+        word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
+        sum += word16;
+    }
+
+    for (i = 0; i < 4; i += 2)
+    {
+        word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
+        sum += word16; 	
+    }
+
+    // the protocol number and the length of the UDP packet
+    sum += (USHORT) IPPROTO_UDP + (USHORT) len_udp;
+
+    // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+    while (sum >> 16)
+    {
+        sum = (sum & 0xFFFF) + (sum >> 16);
+    }
+
+    // Take the one's complement of sum
+    return ((USHORT) ~sum);
+}
+
+//================================
+// Set IP and UDP packet checksums
+//================================
+
+VOID
+SetChecksumDHCPMsg(
+    __in DHCPMsg *m
+    )
+{
+    // Set IP checksum
+    m->msg.pre.ip.check = htons (ip_checksum ((UCHAR *) &m->msg.pre.ip, sizeof (IPHDR)));
+
+    // Set UDP Checksum
+    m->msg.pre.udp.check = htons (udp_checksum ((UCHAR *) &m->msg.pre.udp, 
+        sizeof (UDPHDR) + sizeof (DHCP) + m->optlen,
+        (UCHAR *)&m->msg.pre.ip.saddr,
+        (UCHAR *)&m->msg.pre.ip.daddr));
+}
+
+//===================
+// DHCP message tests
+//===================
+
+int
+GetDHCPMessageType(
+    __in const DHCP *dhcp,
+    __in const int optlen
+    )
+{
+    const UCHAR *p = (UCHAR *) (dhcp + 1);
+    int i;
+
+    for (i = 0; i < optlen; ++i)
+    {
+        const UCHAR type = p[i];
+        const int room = optlen - i - 1;
+
+        if (type == DHCP_END)           // didn't find what we were looking for
+            return -1;
+        else if (type == DHCP_PAD)      // no-operation
+            ;
+        else if (type == DHCP_MSG_TYPE) // what we are looking for
+        {
+            if (room >= 2)
+            {
+                if (p[i+1] == 1)        // message length should be 1
+                    return p[i+2];        // return message type
+            }
+            return -1;
+        }
+        else                            // some other message
+        {
+            if (room >= 1)
+            {
+                const int len = p[i+1]; // get message length
+                i += (len + 1);         // advance to next message
+            }
+        }
+    }
+    return -1;
+}
+
+BOOLEAN
+DHCPMessageOurs (
+    __in const PTAP_ADAPTER_CONTEXT Adapter,
+    __in const ETH_HEADER *eth,
+    __in const IPHDR *ip,
+    __in const UDPHDR *udp,
+    __in const DHCP *dhcp
+    )
+{
+    // Must be UDPv4 protocol
+    if (!(eth->proto == htons (NDIS_ETH_TYPE_IPV4) && ip->protocol == IPPROTO_UDP))
+    {
+        return FALSE;
+    }
+
+    // Source MAC must be our adapter
+    if (!MAC_EQUAL (eth->src, Adapter->CurrentAddress))
+    {
+        return FALSE;
+    }
+
+    // Dest MAC must be either broadcast or our virtual DHCP server
+    if (!(ETH_IS_BROADCAST(eth->dest)
+        || MAC_EQUAL (eth->dest, Adapter->m_dhcp_server_mac)))
+    {
+        return FALSE;
+    }
+
+    // Port numbers must be correct
+    if (!(udp->dest == htons (BOOTPS_PORT)
+        && udp->source == htons (BOOTPC_PORT)))
+    {
+        return FALSE;
+    }
+
+    // Hardware address must be MAC addr sized
+    if (!(dhcp->hlen == sizeof (MACADDR)))
+    {
+        return FALSE;
+    }
+
+    // Hardware address must match our adapter
+    if (!MAC_EQUAL (eth->src, dhcp->chaddr))
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+//=====================================================
+// Build all of DHCP packet except for DHCP options.
+// Assume that *p has been zeroed before we are called.
+//=====================================================
+
+VOID
+BuildDHCPPre (
+    __in const PTAP_ADAPTER_CONTEXT Adapter,
+    __inout DHCPPre *p,
+    __in const ETH_HEADER *eth,
+    __in const IPHDR *ip,
+    __in const UDPHDR *udp,
+    __in const DHCP *dhcp,
+    __in const int optlen,
+    __in const int type)
+{
+    // Should we broadcast or direct to a specific MAC / IP address?
+    const BOOLEAN broadcast = (type == DHCPNAK
+        || ETH_IS_BROADCAST(eth->dest));
+
+    //
+    // Build ethernet header
+    //
+    ETH_COPY_NETWORK_ADDRESS (p->eth.src, Adapter->m_dhcp_server_mac);
+
+    if (broadcast)
+    {
+        memset(p->eth.dest,0xFF,ETH_LENGTH_OF_ADDRESS);
+    }
+    else
+    {
+        ETH_COPY_NETWORK_ADDRESS (p->eth.dest, eth->src);
+    }
+
+    p->eth.proto = htons (NDIS_ETH_TYPE_IPV4);
+
+    //
+    // Build IP header
+    //
+    p->ip.version_len = (4 << 4) | (sizeof (IPHDR) >> 2);
+    p->ip.tos = 0;
+    p->ip.tot_len = htons (sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen);
+    p->ip.id = 0;
+    p->ip.frag_off = 0;
+    p->ip.ttl = 16;
+    p->ip.protocol = IPPROTO_UDP;
+    p->ip.check = 0;
+    p->ip.saddr = Adapter->m_dhcp_server_ip;
+
+    if (broadcast)
+    {
+        p->ip.daddr = ~0;
+    }
+    else
+    {
+        p->ip.daddr = Adapter->m_dhcp_addr;
+    }
+
+    //
+    // Build UDP header
+    //
+    p->udp.source = htons (BOOTPS_PORT);
+    p->udp.dest = htons (BOOTPC_PORT);
+    p->udp.len = htons (sizeof (UDPHDR) + sizeof (DHCP) + optlen);
+    p->udp.check = 0;
+
+    // Build DHCP response
+
+    p->dhcp.op = BOOTREPLY;
+    p->dhcp.htype = 1;
+    p->dhcp.hlen = sizeof (MACADDR);
+    p->dhcp.hops = 0;
+    p->dhcp.xid = dhcp->xid;
+    p->dhcp.secs = 0;
+    p->dhcp.flags = 0;
+    p->dhcp.ciaddr = 0;
+
+    if (type == DHCPNAK)
+    {
+        p->dhcp.yiaddr = 0;
+    }
+    else
+    {
+        p->dhcp.yiaddr = Adapter->m_dhcp_addr;
+    }
+
+    p->dhcp.siaddr = Adapter->m_dhcp_server_ip;
+    p->dhcp.giaddr = 0;
+    ETH_COPY_NETWORK_ADDRESS (p->dhcp.chaddr, eth->src);
+    p->dhcp.magic = htonl (0x63825363);
+}
+
+//=============================
+// Build specific DHCP messages
+//=============================
+
+VOID
+SendDHCPMsg(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in const int type,
+    __in const ETH_HEADER *eth,
+    __in const IPHDR *ip,
+    __in const UDPHDR *udp,
+    __in const DHCP *dhcp
+    )
+{
+    DHCPMsg *pkt;
+
+    if (!(type == DHCPOFFER || type == DHCPACK || type == DHCPNAK))
+    {
+        DEBUGP (("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type));
+        return;
+    }
+
+    pkt = (DHCPMsg *) MemAlloc (sizeof (DHCPMsg), TRUE);
+
+    if(pkt)
+    {
+        //-----------------------
+        // Build DHCP options
+        //-----------------------
+
+        // Message Type
+        SetDHCPOpt8 (pkt, DHCP_MSG_TYPE, type);
+
+        // Server ID
+        SetDHCPOpt32 (pkt, DHCP_SERVER_ID, Adapter->m_dhcp_server_ip);
+
+        if (type == DHCPOFFER || type == DHCPACK)
+        {
+            // Lease Time
+            SetDHCPOpt32 (pkt, DHCP_LEASE_TIME, htonl (Adapter->m_dhcp_lease_time));
+
+            // Netmask
+            SetDHCPOpt32 (pkt, DHCP_NETMASK, Adapter->m_dhcp_netmask);
+
+            // Other user-defined options
+            SetDHCPOpt (
+                pkt,
+                Adapter->m_dhcp_user_supplied_options_buffer,
+                Adapter->m_dhcp_user_supplied_options_buffer_len);
+        }
+
+        // End
+        SetDHCPOpt0 (pkt, DHCP_END);
+
+        if (!DHCPMSG_OVERFLOW (pkt))
+        {
+            // The initial part of the DHCP message (not including options) gets built here
+            BuildDHCPPre (
+                Adapter,
+                &pkt->msg.pre,
+                eth,
+                ip,
+                udp,
+                dhcp,
+                DHCPMSG_LEN_OPT (pkt),
+                type);
+
+            SetChecksumDHCPMsg (pkt);
+
+            DUMP_PACKET ("DHCPMsg",
+                DHCPMSG_BUF (pkt),
+                DHCPMSG_LEN_FULL (pkt));
+
+            // Return DHCP response to kernel
+            IndicateReceivePacket(
+                Adapter,
+                DHCPMSG_BUF (pkt),
+                DHCPMSG_LEN_FULL (pkt)
+                );
+        }
+        else
+        {
+            DEBUGP (("[TAP] SendDHCPMsg: DHCP buffer overflow\n"));
+        }
+
+        MemFree (pkt, sizeof (DHCPMsg));
+    }
+}
+
+//===================================================================
+// Handle a BOOTPS packet produced by the local system to
+// resolve the address/netmask of this adapter.
+// If we are in TAP_WIN_IOCTL_CONFIG_DHCP_MASQ mode, reply
+// to the message.  Return TRUE if we processed the passed
+// message, so that downstream stages can ignore it.
+//===================================================================
+
+BOOLEAN
+ProcessDHCP(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in const ETH_HEADER *eth,
+    __in const IPHDR *ip,
+    __in const UDPHDR *udp,
+    __in const DHCP *dhcp,
+    __in int optlen
+    )
+{
+    int msg_type;
+
+    // Sanity check IP header
+    if (!(ntohs (ip->tot_len) == sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen
+        && (ntohs (ip->frag_off) & IP_OFFMASK) == 0))
+    {
+        return TRUE;
+    }
+
+    // Does this message belong to us?
+    if (!DHCPMessageOurs (Adapter, eth, ip, udp, dhcp))
+    {
+        return FALSE;
+    }
+
+    msg_type = GetDHCPMessageType (dhcp, optlen);
+
+    // Drop non-BOOTREQUEST messages
+    if (dhcp->op != BOOTREQUEST)
+    {
+        return TRUE;
+    }
+
+    // Drop any messages except DHCPDISCOVER or DHCPREQUEST
+    if (!(msg_type == DHCPDISCOVER || msg_type == DHCPREQUEST))
+    {
+        return TRUE;
+    }
+
+    // Should we reply with DHCPOFFER, DHCPACK, or DHCPNAK?
+    if (msg_type == DHCPREQUEST
+        && ((dhcp->ciaddr && dhcp->ciaddr != Adapter->m_dhcp_addr)
+        || !Adapter->m_dhcp_received_discover
+        || Adapter->m_dhcp_bad_requests >= BAD_DHCPREQUEST_NAK_THRESHOLD))
+    {
+        SendDHCPMsg(
+            Adapter,
+            DHCPNAK,
+            eth, ip, udp, dhcp
+            );
+    }
+    else
+    {
+        SendDHCPMsg(
+            Adapter,
+            (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK),
+            eth, ip, udp, dhcp
+            );
+    }
+
+    // Remember if we received a DHCPDISCOVER
+    if (msg_type == DHCPDISCOVER)
+    {
+        Adapter->m_dhcp_received_discover = TRUE;
+    }
+
+    // Is this a bad DHCPREQUEST?
+    if (msg_type == DHCPREQUEST && dhcp->ciaddr && dhcp->ciaddr != Adapter->m_dhcp_addr)
+    {
+        ++Adapter->m_dhcp_bad_requests;
+    }
+
+    return TRUE;
+}
+
+#if DBG
+
+const char *
+    message_op_text (int op)
+{
+    switch (op)
+    {
+    case BOOTREQUEST:
+        return "BOOTREQUEST";
+
+    case BOOTREPLY:
+        return "BOOTREPLY";
+
+    default:
+        return "???";
+    }
+}
+
+const char *
+    message_type_text (int type)
+{
+    switch (type)
+    {
+    case DHCPDISCOVER:
+        return "DHCPDISCOVER";
+
+    case DHCPOFFER:
+        return "DHCPOFFER";
+
+    case DHCPREQUEST:
+        return "DHCPREQUEST";
+
+    case DHCPDECLINE:
+        return "DHCPDECLINE";
+
+    case DHCPACK:
+        return "DHCPACK";
+
+    case DHCPNAK:
+        return "DHCPNAK";
+
+    case DHCPRELEASE:
+        return "DHCPRELEASE";
+
+    case DHCPINFORM:
+        return "DHCPINFORM";
+
+    default:
+        return "???";
+    }
+}
+
+const char *
+port_name (int port)
+{
+    switch (port)
+    {
+    case BOOTPS_PORT:
+        return "BOOTPS";
+
+    case BOOTPC_PORT:
+        return "BOOTPC";
+
+    default:
+        return "unknown";
+    }
+}
+
+VOID
+DumpDHCP (
+    const ETH_HEADER *eth,
+    const IPHDR *ip,
+    const UDPHDR *udp,
+    const DHCP *dhcp,
+    const int optlen
+    )
+{
+    DEBUGP ((" %s", message_op_text (dhcp->op)));
+    DEBUGP ((" %s ", message_type_text (GetDHCPMessageType (dhcp, optlen))));
+    PrIP (ip->saddr);
+    DEBUGP ((":%s[", port_name (ntohs (udp->source))));
+    PrMac (eth->src);
+    DEBUGP (("] -> "));
+    PrIP (ip->daddr);
+    DEBUGP ((":%s[", port_name (ntohs (udp->dest))));
+    PrMac (eth->dest);
+    DEBUGP (("]"));
+    if (dhcp->ciaddr)
+    {
+        DEBUGP ((" ci="));
+        PrIP (dhcp->ciaddr);
+    }
+    if (dhcp->yiaddr)
+    {
+        DEBUGP ((" yi="));
+        PrIP (dhcp->yiaddr);
+    }
+    if (dhcp->siaddr)
+    {
+        DEBUGP ((" si="));
+        PrIP (dhcp->siaddr);
+    }
+    if (dhcp->hlen == sizeof (MACADDR))
+    {
+        DEBUGP ((" ch="));
+        PrMac (dhcp->chaddr);
+    }
+
+    DEBUGP ((" xid=0x%08x", ntohl (dhcp->xid)));
+
+    if (ntohl (dhcp->magic) != 0x63825363)
+        DEBUGP ((" ma=0x%08x", ntohl (dhcp->magic)));
+    if (dhcp->htype != 1)
+        DEBUGP ((" htype=%d", dhcp->htype));
+    if (dhcp->hops)
+        DEBUGP ((" hops=%d", dhcp->hops));
+    if (ntohs (dhcp->secs))
+        DEBUGP ((" secs=%d", ntohs (dhcp->secs)));
+    if (ntohs (dhcp->flags))
+        DEBUGP ((" flags=0x%04x", ntohs (dhcp->flags)));
+
+    // extra stuff
+
+    if (ip->version_len != 0x45)
+        DEBUGP ((" vl=0x%02x", ip->version_len));
+    if (ntohs (ip->tot_len) != sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen)
+        DEBUGP ((" tl=%d", ntohs (ip->tot_len)));
+    if (ntohs (udp->len) != sizeof (UDPHDR) + sizeof (DHCP) + optlen)
+        DEBUGP ((" ul=%d", ntohs (udp->len)));
+
+    if (ip->tos)
+        DEBUGP ((" tos=0x%02x", ip->tos));
+    if (ntohs (ip->id))
+        DEBUGP ((" id=0x%04x", ntohs (ip->id)));
+    if (ntohs (ip->frag_off))
+        DEBUGP ((" frag_off=0x%04x", ntohs (ip->frag_off)));
+
+    DEBUGP ((" ttl=%d", ip->ttl));
+    DEBUGP ((" ic=0x%04x [0x%04x]", ntohs (ip->check),
+        ip_checksum ((UCHAR*)ip, sizeof (IPHDR))));
+    DEBUGP ((" uc=0x%04x [0x%04x/%d]", ntohs (udp->check),
+        udp_checksum ((UCHAR *) udp,
+        sizeof (UDPHDR) + sizeof (DHCP) + optlen,
+        (UCHAR *) &ip->saddr,
+        (UCHAR *) &ip->daddr),
+        optlen));
+
+    // Options
+    {
+        const UCHAR *opt = (UCHAR *) (dhcp + 1);
+        int i;
+
+        DEBUGP ((" OPT"));
+        for (i = 0; i < optlen; ++i)
+        {
+            const UCHAR data = opt[i];
+            DEBUGP ((".%d", data));
+        }
+    }
+}
+
+#endif /* DBG */

+ 165 - 0
windows/TapDriver6/dhcp.h

@@ -0,0 +1,165 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#pragma once
+
+#pragma pack(1)
+
+//===================================================
+// How many bad DHCPREQUESTs do we receive before we
+// return a NAK?
+//
+// A bad DHCPREQUEST is defined to be one where the
+// requestor doesn't know its IP address.
+//===================================================
+
+#define BAD_DHCPREQUEST_NAK_THRESHOLD 3
+
+//==============================================
+// Maximum number of DHCP options bytes supplied
+//==============================================
+
+#define DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE 256
+#define DHCP_OPTIONS_BUFFER_SIZE               256
+
+//===================================
+// UDP port numbers of DHCP messages.
+//===================================
+
+#define BOOTPS_PORT 67
+#define BOOTPC_PORT 68
+
+//===========================
+// The DHCP message structure
+//===========================
+
+typedef struct {
+# define BOOTREQUEST 1
+# define BOOTREPLY   2
+  UCHAR op;          /* message op */
+
+  UCHAR  htype;      /* hardware address type (e.g. '1' = 10Mb Ethernet) */
+  UCHAR  hlen;       /* hardware address length (e.g. '6' for 10Mb Ethernet) */
+  UCHAR  hops;       /* client sets to 0, may be used by relay agents */
+  ULONG  xid;        /* transaction ID, chosen by client */
+  USHORT secs;       /* seconds since request process began, set by client */
+  USHORT flags;
+  ULONG  ciaddr;     /* client IP address, client sets if known */
+  ULONG  yiaddr;     /* 'your' IP address -- server's response to client */
+  ULONG  siaddr;     /* server IP address */
+  ULONG  giaddr;     /* relay agent IP address */
+  UCHAR  chaddr[16]; /* client hardware address */
+  UCHAR  sname[64];  /* optional server host name */
+  UCHAR  file[128];  /* boot file name */
+  ULONG  magic;      /* must be 0x63825363 (network order) */
+} DHCP;
+
+typedef struct {
+  ETH_HEADER eth;
+  IPHDR ip;
+  UDPHDR udp;
+  DHCP dhcp;
+} DHCPPre;
+
+typedef struct {
+  DHCPPre pre;
+  UCHAR options[DHCP_OPTIONS_BUFFER_SIZE];
+} DHCPFull;
+
+typedef struct {
+  unsigned int optlen;
+  BOOLEAN overflow;
+  DHCPFull msg;
+} DHCPMsg;
+
+//===================
+// Macros for DHCPMSG
+//===================
+
+#define DHCPMSG_LEN_BASE(p) (sizeof (DHCPPre))
+#define DHCPMSG_LEN_OPT(p)  ((p)->optlen)
+#define DHCPMSG_LEN_FULL(p) (DHCPMSG_LEN_BASE(p) + DHCPMSG_LEN_OPT(p))
+#define DHCPMSG_BUF(p)      ((UCHAR*) &(p)->msg)
+#define DHCPMSG_OVERFLOW(p) ((p)->overflow)
+
+//========================================
+// structs to hold individual DHCP options
+//========================================
+
+typedef struct {
+  UCHAR type;
+} DHCPOPT0;
+
+typedef struct {
+  UCHAR type;
+  UCHAR len;
+  UCHAR data;
+} DHCPOPT8;
+
+typedef struct {
+  UCHAR type;
+  UCHAR len;
+  ULONG data;
+} DHCPOPT32;
+
+#pragma pack()
+
+//==================
+// DHCP Option types
+//==================
+
+#define DHCP_MSG_TYPE    53  /* message type (u8) */
+#define DHCP_PARM_REQ    55  /* parameter request list: c1 (u8), ... */
+#define DHCP_CLIENT_ID   61  /* client ID: type (u8), i1 (u8), ... */
+#define DHCP_IP          50  /* requested IP addr (u32) */
+#define DHCP_NETMASK      1  /* subnet mask (u32) */
+#define DHCP_LEASE_TIME  51  /* lease time sec (u32) */
+#define DHCP_RENEW_TIME  58  /* renewal time sec (u32) */
+#define DHCP_REBIND_TIME 59  /* rebind time sec (u32) */
+#define DHCP_SERVER_ID   54  /* server ID: IP addr (u32) */
+#define DHCP_PAD          0
+#define DHCP_END        255
+
+//====================
+// DHCP Messages types
+//====================
+
+#define DHCPDISCOVER 1
+#define DHCPOFFER    2
+#define DHCPREQUEST  3
+#define DHCPDECLINE  4
+#define DHCPACK      5
+#define DHCPNAK      6
+#define DHCPRELEASE  7
+#define DHCPINFORM   8
+
+#if DBG
+
+VOID
+DumpDHCP (const ETH_HEADER *eth,
+	  const IPHDR *ip,
+	  const UDPHDR *udp,
+	  const DHCP *dhcp,
+	  const int optlen);
+
+#endif

+ 35 - 0
windows/TapDriver6/endian.h

@@ -0,0 +1,35 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef TAP_LITTLE_ENDIAN
+#define ntohs(x) RtlUshortByteSwap(x)
+#define htons(x) RtlUshortByteSwap(x)
+#define ntohl(x) RtlUlongByteSwap(x)
+#define htonl(x) RtlUlongByteSwap(x)
+#else
+#define ntohs(x) ((USHORT)(x))
+#define htons(x) ((USHORT)(x))
+#define ntohl(x) ((ULONG)(x))
+#define htonl(x) ((ULONG)(x))
+#endif

+ 398 - 0
windows/TapDriver6/error.c

@@ -0,0 +1,398 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "tap.h"
+
+//-----------------
+// DEBUGGING OUTPUT
+//-----------------
+
+const char *g_LastErrorFilename;
+int g_LastErrorLineNumber;
+
+#if DBG
+
+DebugOutput g_Debug;
+
+BOOLEAN
+NewlineExists (const char *str, int len)
+{
+    while (len-- > 0)
+    {
+        const char c = *str++;
+        if (c == '\n')
+            return TRUE;
+        else if (c == '\0')
+            break;
+    }
+    return FALSE;
+}
+
+VOID
+MyDebugInit (unsigned int bufsiz)
+{
+    NdisZeroMemory (&g_Debug, sizeof (g_Debug));
+    g_Debug.text = (char *) MemAlloc (bufsiz, FALSE);
+
+    if (g_Debug.text)
+    {
+        g_Debug.capacity = bufsiz;
+    }
+}
+
+VOID
+MyDebugFree ()
+{
+    if (g_Debug.text)
+    {
+        MemFree (g_Debug.text, g_Debug.capacity);
+    }
+
+    NdisZeroMemory (&g_Debug, sizeof (g_Debug));
+}
+
+VOID
+MyDebugPrint (const unsigned char* format, ...)
+{
+    if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT)
+    {
+        BOOLEAN owned;
+        ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
+        if (owned)
+        {
+            const int remaining = (int)g_Debug.capacity - (int)g_Debug.out;
+
+            if (remaining > 0)
+            {
+                va_list args;
+                NTSTATUS status;
+                char *end;
+
+#ifdef DBG_PRINT
+                va_start (args, format);
+                vDbgPrintEx (DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, format, args);
+                va_end (args);
+#endif
+                va_start (args, format);
+                status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out,
+                    remaining,
+                    &end,
+                    NULL,
+                    STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS,
+                    format,
+                    args);
+                va_end (args);
+                va_start (args, format);
+                vDbgPrintEx(DPFLTR_IHVDRIVER_ID , 1, format, args);
+                va_end (args);
+                if (status == STATUS_SUCCESS)
+                    g_Debug.out = (unsigned int) (end - g_Debug.text);
+                else
+                    g_Debug.error = TRUE;
+            }
+            else
+                g_Debug.error = TRUE;
+
+            RELEASE_MUTEX (&g_Debug.lock);
+        }
+        else
+            g_Debug.error = TRUE;
+    }
+}
+
+BOOLEAN
+GetDebugLine (
+    __in char *buf,
+    __in const int len
+    )
+{
+    static const char *truncated = "[OUTPUT TRUNCATED]\n";
+    BOOLEAN ret = FALSE;
+
+    NdisZeroMemory (buf, len);
+
+    if (g_Debug.text && g_Debug.capacity > 0)
+    {
+        BOOLEAN owned;
+        ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
+        if (owned)
+        {
+            int i = 0;
+
+            if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in))
+            {
+                while (i < (len - 1) && g_Debug.in < g_Debug.out)
+                {
+                    const char c = g_Debug.text[g_Debug.in++];
+                    if (c == '\n')
+                        break;
+                    buf[i++] = c;
+                }
+                if (i < len)
+                    buf[i] = '\0';
+            }
+
+            if (!i)
+            {
+                if (g_Debug.in == g_Debug.out)
+                {
+                    g_Debug.in = g_Debug.out = 0;
+                    if (g_Debug.error)
+                    {
+                        const unsigned int tlen = strlen (truncated);
+                        if (tlen < g_Debug.capacity)
+                        {
+                            NdisMoveMemory (g_Debug.text, truncated, tlen+1);
+                            g_Debug.out = tlen;
+                        }
+                        g_Debug.error = FALSE;
+                    }
+                }
+            }
+            else
+                ret = TRUE;
+
+            RELEASE_MUTEX (&g_Debug.lock);
+        }      
+    }
+    return ret;
+}
+
+VOID
+PrMac (const MACADDR mac)
+{
+  DEBUGP (("%x:%x:%x:%x:%x:%x",
+	    mac[0], mac[1], mac[2],
+	    mac[3], mac[4], mac[5]));
+}
+
+VOID
+PrIP (IPADDR ip_addr)
+{
+  const unsigned char *ip = (const unsigned char *) &ip_addr;
+
+  DEBUGP (("%d.%d.%d.%d",
+	    ip[0], ip[1], ip[2], ip[3]));
+}
+
+const char *
+PrIPProto (int proto)
+{
+    switch (proto)
+    {
+    case IPPROTO_UDP:
+        return "UDP";
+
+    case IPPROTO_TCP:
+        return "TCP";
+
+    case IPPROTO_ICMP:
+        return "ICMP";
+
+    case IPPROTO_IGMP:
+        return "IGMP";
+
+    default:
+        return "???";
+    }
+}
+
+VOID
+DumpARP (const char *prefix, const ARP_PACKET *arp)
+{
+  DEBUGP (("%s ARP src=", prefix));
+  PrMac (arp->m_MAC_Source);
+  DEBUGP ((" dest="));
+  PrMac (arp->m_MAC_Destination);
+  DEBUGP ((" OP=0x%04x",
+	    (int)ntohs(arp->m_ARP_Operation)));
+  DEBUGP ((" M=0x%04x(%d)",
+	    (int)ntohs(arp->m_MAC_AddressType),
+	    (int)arp->m_MAC_AddressSize));
+  DEBUGP ((" P=0x%04x(%d)",
+	    (int)ntohs(arp->m_PROTO_AddressType),
+	    (int)arp->m_PROTO_AddressSize));
+
+  DEBUGP ((" MacSrc="));
+  PrMac (arp->m_ARP_MAC_Source);
+  DEBUGP ((" MacDest="));
+  PrMac (arp->m_ARP_MAC_Destination);
+
+  DEBUGP ((" IPSrc="));
+  PrIP (arp->m_ARP_IP_Source);
+  DEBUGP ((" IPDest="));
+  PrIP (arp->m_ARP_IP_Destination);
+
+  DEBUGP (("\n"));
+}
+
+struct ethpayload
+{
+  ETH_HEADER eth;
+  UCHAR payload[DEFAULT_PACKET_LOOKAHEAD];
+};
+
+#ifdef ALLOW_PACKET_DUMP
+
+VOID
+DumpPacket2(
+    __in const char *prefix,
+    __in const ETH_HEADER *eth,
+    __in const unsigned char *data,
+    __in unsigned int len
+    )
+{
+    struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE);
+    if (ep)
+    {
+        if (len > DEFAULT_PACKET_LOOKAHEAD)
+            len = DEFAULT_PACKET_LOOKAHEAD;
+        ep->eth = *eth;
+        NdisMoveMemory (ep->payload, data, len);
+        DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len);
+        MemFree (ep, sizeof (struct ethpayload));
+    }
+}
+
+VOID
+DumpPacket(
+    __in const char *prefix,
+    __in const unsigned char *data,
+    __in unsigned int len
+    )
+{
+    const ETH_HEADER *eth = (const ETH_HEADER *) data;
+    const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER));
+
+    if (len < sizeof (ETH_HEADER))
+    {
+        DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len));
+        return;
+    }
+
+    // ARP Packet?
+    if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP))
+    {
+        DumpARP (prefix, (const ARP_PACKET *) data);
+        return;
+    }
+
+    // IPv4 packet?
+    if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER))
+        && eth->proto == htons (ETH_P_IP)
+        && IPH_GET_VER (ip->version_len) == 4)
+    {
+        const int hlen = IPH_GET_LEN (ip->version_len);
+        const int blen = len - sizeof (ETH_HEADER);
+        BOOLEAN did = FALSE;
+
+        DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len));
+
+        if (!(ntohs (ip->tot_len) == blen && hlen <= blen))
+        {
+            DEBUGP ((" XXX"));
+            return;
+        }
+
+        // TCP packet?
+        if (ip->protocol == IPPROTO_TCP
+            && blen - hlen >= (sizeof (TCPHDR)))
+        {
+            const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen);
+            DEBUGP ((" "));
+            PrIP (ip->saddr);
+            DEBUGP ((":%d", ntohs (tcp->source)));
+            DEBUGP ((" -> "));
+            PrIP (ip->daddr);
+            DEBUGP ((":%d", ntohs (tcp->dest)));
+            did = TRUE;
+        }
+
+        // UDP packet?
+        else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0
+            && ip->protocol == IPPROTO_UDP
+            && blen - hlen >= (sizeof (UDPHDR)))
+        {
+            const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen);
+
+            // DHCP packet?
+            if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT))
+                && blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP)))
+            {
+                const DHCP *dhcp = (DHCP *) (data
+                    + hlen
+                    + sizeof (ETH_HEADER)
+                    + sizeof (UDPHDR));
+
+                int optlen = len
+                    - sizeof (ETH_HEADER)
+                    - hlen
+                    - sizeof (UDPHDR)
+                    - sizeof (DHCP);
+
+                if (optlen < 0)
+                    optlen = 0;
+
+                DumpDHCP (eth, ip, udp, dhcp, optlen);
+                did = TRUE;
+            }
+
+            if (!did)
+            {
+                DEBUGP ((" "));
+                PrIP (ip->saddr);
+                DEBUGP ((":%d", ntohs (udp->source)));
+                DEBUGP ((" -> "));
+                PrIP (ip->daddr);
+                DEBUGP ((":%d", ntohs (udp->dest)));
+                did = TRUE;
+            }
+        }
+
+        if (!did)
+        {
+            DEBUGP ((" ipproto=%d ", ip->protocol));
+            PrIP (ip->saddr);
+            DEBUGP ((" -> "));
+            PrIP (ip->daddr);
+        }
+
+        DEBUGP (("\n"));
+        return;
+    }
+
+    {
+        DEBUGP (("%s ??? src=", prefix));
+        PrMac (eth->src);
+        DEBUGP ((" dest="));
+        PrMac (eth->dest);
+        DEBUGP ((" proto=0x%04x len=%d\n",
+            (int) ntohs(eth->proto),
+            len));
+    }
+}
+
+#endif // ALLOW_PACKET_DUMP
+
+#endif

+ 114 - 0
windows/TapDriver6/error.h

@@ -0,0 +1,114 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//-----------------
+// DEBUGGING OUTPUT
+//-----------------
+
+extern const char *g_LastErrorFilename;
+extern int g_LastErrorLineNumber;
+
+// Debug info output
+#define ALSO_DBGPRINT           1
+#define DEBUGP_AT_DISPATCH      1
+
+// Uncomment line below to allow packet dumps
+//#define ALLOW_PACKET_DUMP       1
+
+#define NOTE_ERROR() \
+{ \
+  g_LastErrorFilename = __FILE__; \
+  g_LastErrorLineNumber = __LINE__; \
+}
+
+#if DBG
+
+typedef struct
+{
+    unsigned int in;
+    unsigned int out;
+    unsigned int capacity;
+    char *text;
+    BOOLEAN error;
+    MUTEX lock;
+} DebugOutput;
+
+VOID MyDebugPrint (const unsigned char* format, ...);
+
+VOID PrMac (const MACADDR mac);
+
+VOID PrIP (IPADDR ip_addr);
+
+#ifdef ALLOW_PACKET_DUMP
+
+VOID
+DumpPacket(
+    __in const char *prefix,
+    __in const unsigned char *data,
+    __in unsigned int len
+    );
+
+DumpPacket2(
+    __in const char *prefix,
+    __in const ETH_HEADER *eth,
+    __in const unsigned char *data,
+    __in unsigned int len
+    );
+
+#else
+#define DUMP_PACKET(prefix, data, len)
+#define DUMP_PACKET2(prefix, eth, data, len)
+#endif
+
+#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql () < DISPATCH_LEVEL)
+
+#if ALSO_DBGPRINT
+#define DEBUGP(fmt) { MyDebugPrint fmt; if (CAN_WE_PRINT) DbgPrint fmt; }
+#else
+#define DEBUGP(fmt) { MyDebugPrint fmt; }
+#endif
+
+#ifdef ALLOW_PACKET_DUMP
+
+#define DUMP_PACKET(prefix, data, len) \
+  DumpPacket (prefix, data, len)
+
+#define DUMP_PACKET2(prefix, eth, data, len) \
+  DumpPacket2 (prefix, eth, data, len)
+
+#endif
+
+BOOLEAN
+GetDebugLine (
+    __in char *buf,
+    __in const int len
+    );
+
+#else 
+
+#define DEBUGP(fmt)
+#define DUMP_PACKET(prefix, data, len)
+#define DUMP_PACKET2(prefix, eth, data, len)
+
+#endif

+ 63 - 0
windows/TapDriver6/hexdump.h

@@ -0,0 +1,63 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef HEXDUMP_DEFINED
+#define HEXDUMP_DEFINED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//=====================================================================================
+//                                   Debug Routines
+//=====================================================================================
+
+#ifndef NDIS_MINIPORT_DRIVER
+#   include <stdio.h>
+#   include <ctype.h>
+#   include <windows.h>
+#   include <winnt.h>
+#   include <memory.h>
+
+#   ifndef DEBUGP
+#      define DEBUGP(fmt) { DbgMessage fmt; }
+#   endif
+
+    extern VOID (*DbgMessage)(char *p_Format, ...);
+
+    VOID DisplayDebugString (char *p_Format, ...);
+#endif
+
+//===================================================================================
+//                              Reporting / Debugging
+//===================================================================================
+#define IfPrint(c) (c >= 32 && c < 127 ? c : '.')
+
+VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 75 - 0
windows/TapDriver6/lock.h

@@ -0,0 +1,75 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+typedef struct
+{
+  volatile long count;
+} MUTEX;
+
+#define MUTEX_SLEEP_TIME  10000 // microseconds
+
+#define INIT_MUTEX(m) { (m)->count = 0; }
+
+#define ACQUIRE_MUTEX_BLOCKING(m)                         \
+{                                                         \
+    while (NdisInterlockedIncrement (&((m)->count)) != 1) \
+    {                                                     \
+        NdisInterlockedDecrement(&((m)->count));          \
+        NdisMSleep(MUTEX_SLEEP_TIME);                     \
+    }                                                     \
+}
+
+#define RELEASE_MUTEX(m)                                  \
+{                                                         \
+        NdisInterlockedDecrement(&((m)->count));          \
+}
+
+#define ACQUIRE_MUTEX_NONBLOCKING(m, result)              \
+{                                                         \
+    if (NdisInterlockedIncrement (&((m)->count)) != 1)    \
+    {                                                     \
+        NdisInterlockedDecrement(&((m)->count));          \
+        result = FALSE;                                   \
+    }                                                     \
+    else                                                  \
+    {                                                     \
+	result = TRUE;                                    \
+    }                                                     \
+}
+
+#define ACQUIRE_MUTEX_ADAPTIVE(m, result)                 \
+{                                                         \
+    result = TRUE;                                        \
+    while (NdisInterlockedIncrement (&((m)->count)) != 1) \
+    {                                                     \
+        NdisInterlockedDecrement(&((m)->count));          \
+        if (KeGetCurrentIrql () < DISPATCH_LEVEL)         \
+            NdisMSleep(MUTEX_SLEEP_TIME);                 \
+        else                                              \
+        {                                                 \
+	    result = FALSE;                               \
+	    break;                                        \
+        }                                                 \
+    }                                                     \
+}

+ 164 - 0
windows/TapDriver6/macinfo.c

@@ -0,0 +1,164 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "tap.h"
+
+int
+HexStringToDecimalInt (const int p_Character)
+{
+    int l_Value = 0;
+
+    if (p_Character >= 'A' && p_Character <= 'F')
+        l_Value = (p_Character - 'A') + 10;
+    else if (p_Character >= 'a' && p_Character <= 'f')
+        l_Value = (p_Character - 'a') + 10;
+    else if (p_Character >= '0' && p_Character <= '9')
+        l_Value = p_Character - '0';
+
+    return l_Value;
+}
+
+BOOLEAN
+ParseMAC (MACADDR dest, const char *src)
+{
+    int c;
+    int mac_index = 0;
+    BOOLEAN high_digit = FALSE;
+    int delim_action = 1;
+
+    ASSERT (src);
+    ASSERT (dest);
+
+    CLEAR_MAC (dest);
+
+    while (c = *src++)
+    {
+        if (IsMacDelimiter (c))
+        {
+            mac_index += delim_action;
+            high_digit = FALSE;
+            delim_action = 1;
+        }
+        else if (IsHexDigit (c))
+        {
+            const int digit = HexStringToDecimalInt (c);
+            if (mac_index < sizeof (MACADDR))
+            {
+                if (!high_digit)
+                {
+                    dest[mac_index] = (char)(digit);
+                    high_digit = TRUE;
+                    delim_action = 1;
+                }
+                else
+                {
+                    dest[mac_index] = (char)(dest[mac_index] * 16 + digit);
+                    ++mac_index;
+                    high_digit = FALSE;
+                    delim_action = 0;
+                }
+            }
+            else
+                return FALSE;
+        }
+        else
+            return FALSE;
+    }
+
+    return (mac_index + delim_action) >= sizeof (MACADDR);
+}
+
+/*
+ * Generate a MAC using the GUID in the adapter name.
+ *
+ * The mac is constructed as 00:FF:xx:xx:xx:xx where
+ * the Xs are taken from the first 32 bits of the GUID in the
+ * adapter name.  This is similar to the Linux 2.4 tap MAC
+ * generator, except linux uses 32 random bits for the Xs.
+ *
+ * In general, this solution is reasonable for most
+ * applications except for very large bridged TAP networks,
+ * where the probability of address collisions becomes more
+ * than infintesimal.
+ *
+ * Using the well-known "birthday paradox", on a 1000 node
+ * network the probability of collision would be
+ * 0.000116292153.  On a 10,000 node network, the probability
+ * of collision would be 0.01157288998621678766.
+ */
+
+VOID
+GenerateRandomMac(
+    __in MACADDR mac,
+    __in const unsigned char *adapter_name
+    )
+{
+    unsigned const char *cp = adapter_name;
+    unsigned char c;
+    unsigned int i = 2;
+    unsigned int byte = 0;
+    int brace = 0;
+    int state = 0;
+
+    CLEAR_MAC (mac);
+
+    mac[0] = 0x00;
+    mac[1] = 0xFF;
+
+    while (c = *cp++)
+    {
+        if (i >= sizeof (MACADDR))
+            break;
+        if (c == '{')
+            brace = 1;
+        if (IsHexDigit (c) && brace)
+        {
+            const unsigned int digit = HexStringToDecimalInt (c);
+            if (state)
+            {
+                byte <<= 4;
+                byte |= digit;
+                mac[i++] = (unsigned char) byte;
+                state = 0;
+            }
+            else
+            {
+                byte = digit;
+                state = 1;
+            }
+        }
+    }
+}
+
+VOID
+GenerateRelatedMAC(
+    __in MACADDR dest,
+    __in const MACADDR src,
+    __in const int delta
+    )
+{
+    ETH_COPY_NETWORK_ADDRESS (dest, src);
+    dest[2] += (UCHAR) delta;
+}

+ 53 - 0
windows/TapDriver6/macinfo.h

@@ -0,0 +1,53 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef MacInfoDefined
+#define MacInfoDefined
+
+//===================================================================================
+//                                      Macros
+//===================================================================================
+#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.')
+#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
+
+#define CLEAR_MAC(dest)     NdisZeroMemory ((dest), sizeof (MACADDR))
+#define MAC_EQUAL(a,b)      (memcmp ((a), (b), sizeof (MACADDR)) == 0)
+
+BOOLEAN
+ParseMAC (MACADDR dest, const char *src);
+
+VOID
+GenerateRandomMac(
+    __in MACADDR mac,
+    __in const unsigned char *adapter_name
+    );
+
+VOID
+GenerateRelatedMAC(
+    __in MACADDR dest,
+    __in const MACADDR src,
+    __in const int delta
+    );
+
+#endif

+ 401 - 0
windows/TapDriver6/mem.c

@@ -0,0 +1,401 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//------------------
+// Memory Management
+//------------------
+
+#include "tap.h"
+
+PVOID
+MemAlloc(
+    __in ULONG p_Size,
+    __in BOOLEAN zero
+    )
+{
+    PVOID l_Return = NULL;
+
+    if (p_Size)
+    {
+        __try
+        {
+            if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT')
+                == NDIS_STATUS_SUCCESS)
+            {
+                if (zero)
+                {
+                    NdisZeroMemory (l_Return, p_Size);
+                }
+            }
+            else
+            {
+                l_Return = NULL;
+            }
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+            l_Return = NULL;
+        }
+    }
+
+    return l_Return;
+}
+
+VOID
+MemFree(
+    __in PVOID p_Addr,
+    __in ULONG p_Size
+    )
+{
+    if (p_Addr && p_Size)
+    {
+        __try
+        {
+#if DBG
+            NdisZeroMemory (p_Addr, p_Size);
+#endif
+            NdisFreeMemory (p_Addr, p_Size, 0);
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+        }
+    }
+}
+
+//======================================================================
+// TAP Packet Queue Support
+//======================================================================
+
+VOID
+tapPacketQueueInsertTail(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue,
+    __in PTAP_PACKET        TapPacket
+    )
+{
+    KIRQL  irql;
+
+    KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql);
+
+    InsertTailList(&TapPacketQueue->Queue,&TapPacket->QueueLink);
+
+    // BUGBUG!!! Enforce PACKET_QUEUE_SIZE queue count limit???
+    // For NDIS 6 there is no per-packet status, so this will need to
+    // be handled on per-NBL basis in AdapterSendNetBufferLists...
+
+    // Update counts
+    ++TapPacketQueue->Count;
+
+    if(TapPacketQueue->Count > TapPacketQueue->MaxCount)
+    {
+        TapPacketQueue->MaxCount = TapPacketQueue->Count;
+
+        DEBUGP (("[TAP] tapPacketQueueInsertTail: New MAX queued packet count = %d\n",
+            TapPacketQueue->MaxCount));
+    }
+
+    KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql);
+}
+
+// Call with QueueLock held
+PTAP_PACKET
+tapPacketRemoveHeadLocked(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue
+    )
+{
+    PTAP_PACKET     tapPacket = NULL;
+    PLIST_ENTRY     listEntry;
+
+    listEntry = RemoveHeadList(&TapPacketQueue->Queue);
+
+    if(listEntry != &TapPacketQueue->Queue)
+    {
+        tapPacket = CONTAINING_RECORD(listEntry, TAP_PACKET, QueueLink);
+
+        // Update counts
+        --TapPacketQueue->Count;
+    }
+
+    return tapPacket;
+}
+
+PTAP_PACKET
+tapPacketRemoveHead(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue
+    )
+{
+    PTAP_PACKET     tapPacket = NULL;
+    KIRQL           irql;
+
+    KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql);
+
+    tapPacket = tapPacketRemoveHeadLocked(TapPacketQueue);
+
+    KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql);
+
+    return tapPacket;
+}
+
+VOID
+tapPacketQueueInitialize(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue
+    )
+{
+    KeInitializeSpinLock(&TapPacketQueue->QueueLock);
+
+    NdisInitializeListHead(&TapPacketQueue->Queue);
+}
+
+//======================================================================
+// TAP Cancel-Safe Queue Support
+//======================================================================
+
+VOID
+tapIrpCsqInsert (
+    __in struct _IO_CSQ    *Csq,
+    __in PIRP              Irp
+    )
+{
+    PTAP_IRP_CSQ          tapIrpCsq;
+
+    tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+    InsertTailList(
+        &tapIrpCsq->Queue,
+        &Irp->Tail.Overlay.ListEntry
+        );
+
+    // Update counts
+    ++tapIrpCsq->Count;
+
+    if(tapIrpCsq->Count > tapIrpCsq->MaxCount)
+    {
+        tapIrpCsq->MaxCount = tapIrpCsq->Count;
+
+        DEBUGP (("[TAP] tapIrpCsqInsert: New MAX queued IRP count = %d\n",
+            tapIrpCsq->MaxCount));
+    }
+}
+
+VOID
+tapIrpCsqRemoveIrp(
+    __in PIO_CSQ Csq,
+    __in PIRP    Irp
+    )
+{
+    PTAP_IRP_CSQ          tapIrpCsq;
+
+    tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+    // Update counts
+    --tapIrpCsq->Count;
+
+    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+}
+
+
+PIRP
+tapIrpCsqPeekNextIrp(
+    __in PIO_CSQ Csq,
+    __in PIRP    Irp,
+    __in PVOID   PeekContext
+    )
+{
+    PTAP_IRP_CSQ          tapIrpCsq;
+    PIRP                    nextIrp = NULL;
+    PLIST_ENTRY             nextEntry;
+    PLIST_ENTRY             listHead;
+    PIO_STACK_LOCATION      irpStack;
+
+    tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+    listHead = &tapIrpCsq->Queue;
+
+    //
+    // If the IRP is NULL, we will start peeking from the listhead, else
+    // we will start from that IRP onwards. This is done under the
+    // assumption that new IRPs are always inserted at the tail.
+    //
+
+    if (Irp == NULL)
+    {
+        nextEntry = listHead->Flink;
+    }
+    else
+    {
+        nextEntry = Irp->Tail.Overlay.ListEntry.Flink;
+    }
+
+    while(nextEntry != listHead)
+    {
+        nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry);
+
+        irpStack = IoGetCurrentIrpStackLocation(nextIrp);
+
+        //
+        // If context is present, continue until you find a matching one.
+        // Else you break out as you got next one.
+        //
+        if (PeekContext)
+        {
+            if (irpStack->FileObject == (PFILE_OBJECT) PeekContext)
+            {
+                break;
+            }
+        }
+        else
+        {
+            break;
+        }
+
+        nextIrp = NULL;
+        nextEntry = nextEntry->Flink;
+    }
+
+    return nextIrp;
+}
+
+//
+// tapIrpCsqAcquireQueueLock modifies the execution level of the current processor.
+// 
+// KeAcquireSpinLock raises the execution level to Dispatch Level and stores
+// the current execution level in the Irql parameter to be restored at a later
+// time.  KeAcqurieSpinLock also requires us to be running at no higher than
+// Dispatch level when it is called.
+//
+// The annotations reflect these changes and requirments.
+//
+
+__drv_raisesIRQL(DISPATCH_LEVEL)
+__drv_maxIRQL(DISPATCH_LEVEL)
+VOID
+tapIrpCsqAcquireQueueLock(
+     __in PIO_CSQ Csq,
+     __out PKIRQL  Irql
+    )
+{
+    PTAP_IRP_CSQ          tapIrpCsq;
+
+    tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+    //
+    // Suppressing because the address below csq is valid since it's
+    // part of TAP_ADAPTER_CONTEXT structure.
+    //
+#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'")
+    KeAcquireSpinLock(&tapIrpCsq->QueueLock, Irql);
+}
+
+//
+// tapIrpCsqReleaseQueueLock modifies the execution level of the current processor.
+// 
+// KeReleaseSpinLock assumes we already hold the spin lock and are therefore
+// running at Dispatch level.  It will use the Irql parameter saved in a
+// previous call to KeAcquireSpinLock to return the thread back to it's original
+// execution level.
+//
+// The annotations reflect these changes and requirments.
+//
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+VOID
+tapIrpCsqReleaseQueueLock(
+     __in PIO_CSQ Csq,
+     __in KIRQL   Irql
+    )
+{
+    PTAP_IRP_CSQ          tapIrpCsq;
+
+    tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+    //
+    // Suppressing because the address below csq is valid since it's
+    // part of TAP_ADAPTER_CONTEXT structure.
+    //
+#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'")
+    KeReleaseSpinLock(&tapIrpCsq->QueueLock, Irql);
+}
+
+VOID
+tapIrpCsqCompleteCanceledIrp(
+    __in  PIO_CSQ             pCsq,
+    __in  PIRP                Irp
+    )
+{
+    UNREFERENCED_PARAMETER(pCsq);
+
+    Irp->IoStatus.Status = STATUS_CANCELLED;
+    Irp->IoStatus.Information = 0;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+tapIrpCsqInitialize(
+    __in PTAP_IRP_CSQ  TapIrpCsq
+    )
+{
+    KeInitializeSpinLock(&TapIrpCsq->QueueLock);
+
+    NdisInitializeListHead(&TapIrpCsq->Queue);
+
+    IoCsqInitialize(
+        &TapIrpCsq->CsqQueue,
+        tapIrpCsqInsert,
+        tapIrpCsqRemoveIrp,
+        tapIrpCsqPeekNextIrp,
+        tapIrpCsqAcquireQueueLock,
+        tapIrpCsqReleaseQueueLock,
+        tapIrpCsqCompleteCanceledIrp
+        );
+}
+
+VOID
+tapIrpCsqFlush(
+    __in PTAP_IRP_CSQ  TapIrpCsq
+    )
+{
+    PIRP    pendingIrp;
+
+    //
+    // Flush the pending read IRP queue.
+    //
+    pendingIrp = IoCsqRemoveNextIrp(
+                    &TapIrpCsq->CsqQueue,
+                    NULL
+                    );
+
+    while(pendingIrp) 
+    {
+        // Cancel the IRP
+        pendingIrp->IoStatus.Information = 0;
+        pendingIrp->IoStatus.Status = STATUS_CANCELLED;
+        IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
+
+        pendingIrp = IoCsqRemoveNextIrp(
+                        &TapIrpCsq->CsqQueue,
+                        NULL
+                        );
+    }
+
+    ASSERT(IsListEmpty(&TapIrpCsq->Queue));
+}

+ 113 - 0
windows/TapDriver6/mem.h

@@ -0,0 +1,113 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//------------------
+// Memory Management
+//------------------
+
+PVOID
+MemAlloc(
+    __in ULONG p_Size,
+    __in BOOLEAN zero
+    );
+
+VOID
+MemFree(
+    __in PVOID p_Addr,
+    __in ULONG p_Size
+    );
+
+//======================================================================
+// TAP Packet Queue
+//======================================================================
+
+typedef
+struct _TAP_PACKET
+{
+    LIST_ENTRY                  QueueLink;
+
+#   define TAP_PACKET_SIZE(data_size) (sizeof (TAP_PACKET) + (data_size))
+#   define TP_TUN 0x80000000
+#   define TP_SIZE_MASK      (~TP_TUN)
+    ULONG                       m_SizeFlags;
+
+    // m_Data must be the last struct member
+    UCHAR                       m_Data [];
+} TAP_PACKET, *PTAP_PACKET;
+
+#define TAP_PACKET_TAG      '6PAT'  // "TAP6"
+
+typedef struct _TAP_PACKET_QUEUE
+{
+    KSPIN_LOCK      QueueLock;
+    LIST_ENTRY      Queue;
+    ULONG           Count;   // Count of currently queued items
+    ULONG           MaxCount;
+} TAP_PACKET_QUEUE, *PTAP_PACKET_QUEUE;
+
+VOID
+tapPacketQueueInsertTail(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue,
+    __in PTAP_PACKET        TapPacket
+    );
+
+
+// Call with QueueLock held
+PTAP_PACKET
+tapPacketRemoveHeadLocked(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue
+    );
+
+PTAP_PACKET
+tapPacketRemoveHead(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue
+    );
+
+VOID
+tapPacketQueueInitialize(
+    __in PTAP_PACKET_QUEUE  TapPacketQueue
+    );
+
+//----------------------
+// Cancel-Safe IRP Queue
+//----------------------
+
+typedef struct _TAP_IRP_CSQ
+{
+    IO_CSQ          CsqQueue;
+    KSPIN_LOCK      QueueLock;
+    LIST_ENTRY      Queue;
+    ULONG           Count;   // Count of currently queued items
+    ULONG           MaxCount;
+} TAP_IRP_CSQ, *PTAP_IRP_CSQ;
+
+VOID
+tapIrpCsqInitialize(
+    __in PTAP_IRP_CSQ  TapIrpCsq
+    );
+
+VOID
+tapIrpCsqFlush(
+    __in PTAP_IRP_CSQ  TapIrpCsq
+    );

+ 1028 - 0
windows/TapDriver6/oidrequest.c

@@ -0,0 +1,1028 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+#ifndef DBG
+
+#define DBG_PRINT_OID_NAME
+
+#else
+
+VOID
+DBG_PRINT_OID_NAME(
+    __in  NDIS_OID  Oid
+    )
+{
+    PCHAR oidName = NULL;
+
+    switch (Oid){
+
+        #undef MAKECASE
+        #define MAKECASE(oidx) case oidx: oidName = #oidx "\n"; break;
+
+        /* Operational OIDs */
+        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_VENDOR_DRIVER_VERSION)
+        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_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_MACHINE_NAME)
+        MAKECASE(OID_GEN_VLAN_ID)
+        MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER)
+
+        /* Operational OIDs for NDIS 6.0 */
+        MAKECASE(OID_GEN_MAX_LINK_SPEED)
+        MAKECASE(OID_GEN_LINK_STATE)
+        MAKECASE(OID_GEN_LINK_PARAMETERS)
+        MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES)
+        MAKECASE(OID_GEN_ENUMERATE_PORTS)
+        MAKECASE(OID_GEN_PORT_STATE)
+        MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS)
+        MAKECASE(OID_GEN_INTERRUPT_MODERATION)
+        MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX)
+
+        /* Statistical OIDs */
+        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)
+
+        /* Statistical OIDs for NDIS 6.0 */
+        MAKECASE(OID_GEN_STATISTICS)
+        MAKECASE(OID_GEN_BYTES_RCV)
+        MAKECASE(OID_GEN_BYTES_XMIT)
+        MAKECASE(OID_GEN_RCV_DISCARDS)
+        MAKECASE(OID_GEN_XMIT_DISCARDS)
+
+        /* Misc OIDs */
+        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)
+
+        /* PnP power management operational OIDs */
+        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_PNP_WAKE_UP_PATTERN_LIST)
+
+        /* PnP power management statistical OIDs */
+        MAKECASE(OID_PNP_WAKE_UP_ERROR)
+        MAKECASE(OID_PNP_WAKE_UP_OK)
+
+        /* Ethernet operational OIDs */
+        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)
+
+        /* Ethernet operational OIDs for NDIS 6.0 */
+        MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS)
+        MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS)
+
+        /* Ethernet statistical OIDs */
+        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)
+
+        /*  TCP/IP OIDs */
+        MAKECASE(OID_TCP_TASK_OFFLOAD)
+        MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA)
+        MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA)
+        MAKECASE(OID_TCP_SAN_SUPPORT)
+        MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA)
+        MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA)
+        MAKECASE(OID_TCP4_OFFLOAD_STATS)
+        MAKECASE(OID_TCP6_OFFLOAD_STATS)
+        MAKECASE(OID_IP4_OFFLOAD_STATS)
+        MAKECASE(OID_IP6_OFFLOAD_STATS)
+
+        /* TCP offload OIDs for NDIS 6 */
+        MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG)
+        MAKECASE(OID_TCP_OFFLOAD_PARAMETERS)
+        MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES)
+        MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG)
+        MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES)
+        MAKECASE(OID_OFFLOAD_ENCAPSULATION)
+
+#if (NDIS_SUPPORT_NDIS620)
+        /* VMQ OIDs for NDIS 6.20 */
+        MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE)
+        MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER)
+        MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE)
+        MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE)
+        MAKECASE(OID_RECEIVE_FILTER_SET_FILTER)
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+        /* NDIS QoS OIDs for NDIS 6.30 */
+        MAKECASE(OID_QOS_PARAMETERS)
+#endif
+    }
+
+    if (oidName)
+    {
+        DEBUGP(("OID: %s", oidName));
+    }
+    else
+    {
+        DEBUGP(("<** Unknown OID 0x%08x **>\n", Oid));
+    }
+}
+
+#endif // DBG
+
+//======================================================================
+// TAP NDIS 6 OID Request Callbacks
+//======================================================================
+
+NDIS_STATUS
+tapSetMulticastList(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in PNDIS_OID_REQUEST      OidRequest
+    )
+{
+    NDIS_STATUS   status = NDIS_STATUS_SUCCESS;
+
+    //
+    // Initialize.
+    //
+    OidRequest->DATA.SET_INFORMATION.BytesNeeded = MACADDR_SIZE;
+    OidRequest->DATA.SET_INFORMATION.BytesRead
+        = OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+
+    do
+    {
+        if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength % MACADDR_SIZE)
+        {
+            status = NDIS_STATUS_INVALID_LENGTH;
+            break;
+        }
+
+        if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength > (TAP_MAX_MCAST_LIST * MACADDR_SIZE))
+        {
+            status = NDIS_STATUS_MULTICAST_FULL;
+            OidRequest->DATA.SET_INFORMATION.BytesNeeded = TAP_MAX_MCAST_LIST * MACADDR_SIZE;
+            break;
+        }
+
+        // BUGBUG!!! Is lock needed??? If so, use NDIS_RW_LOCK. Also apply to packet filter.
+
+        NdisZeroMemory(Adapter->MCList,
+                       TAP_MAX_MCAST_LIST * MACADDR_SIZE);
+
+        NdisMoveMemory(Adapter->MCList,
+                       OidRequest->DATA.SET_INFORMATION.InformationBuffer,
+                       OidRequest->DATA.SET_INFORMATION.InformationBufferLength);
+
+        Adapter->ulMCListSize = OidRequest->DATA.SET_INFORMATION.InformationBufferLength / MACADDR_SIZE;
+
+    } while(FALSE);
+    return status;
+}
+
+NDIS_STATUS
+tapSetPacketFilter(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in ULONG                  PacketFilter
+    )
+{
+    NDIS_STATUS   status = NDIS_STATUS_SUCCESS;
+
+    // any bits not supported?
+    if (PacketFilter & ~(TAP_SUPPORTED_FILTERS))
+    {
+        DEBUGP (("[TAP] Unsupported packet filter: 0x%08x\n", PacketFilter));
+        status = NDIS_STATUS_NOT_SUPPORTED;
+    }
+    else
+    {
+        // Any actual filtering changes?
+        if (PacketFilter != Adapter->PacketFilter)
+        {
+            //
+            // Change the filtering modes on hardware
+            //
+
+            // Save the new packet filter value
+            Adapter->PacketFilter = PacketFilter;
+        }
+    }
+
+    return status;
+}
+
+NDIS_STATUS
+AdapterSetPowerD0(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    )
+/*++
+Routine Description:
+
+    NIC power has been restored to the working power state (D0).
+    Prepare the NIC for normal operation:
+        - Restore hardware context (packet filters, multicast addresses, MAC address, etc.)
+        - Enable interrupts and the NIC's DMA engine.
+
+Arguments:
+
+    Adapter     - Pointer to adapter block
+
+Return Value:
+
+    NDIS_STATUS   
+
+--*/      
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+    DEBUGP (("[TAP] PowerState: Fully powered\n"));
+
+    // Start data path...
+
+    return status;
+}
+
+NDIS_STATUS
+AdapterSetPowerLow(
+    __in PTAP_ADAPTER_CONTEXT       Adapter,
+    __in NDIS_DEVICE_POWER_STATE    PowerState
+    )
+/*++
+Routine Description:
+
+    The NIC is about to be transitioned to a low power state. 
+    Prepare the NIC for the sleeping state:
+        - Disable interrupts and the NIC's DMA engine, cancel timers.  
+        - Save any hardware context that the NIC cannot preserve in 
+          a sleeping state (packet filters, multicast addresses, 
+          the current MAC address, etc.)
+    A miniport driver cannot access the NIC hardware after 
+    the NIC has been set to the D3 state by the bus driver.
+
+    Miniport drivers NDIS v6.30 and above 
+        Do NOT wait for NDIS to return the ownership of all 
+        NBLs from outstanding receive indications
+        Retain ownership of all the receive descriptors and 
+        packet buffers previously owned by the hardware.
+
+Arguments:
+
+    Adapter         - Pointer to adapter block
+    PowerState      - New power state
+
+Return Value:
+
+    NDIS_STATUS   
+
+--*/      
+{
+    NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+    DEBUGP (("[TAP] PowerState: Low-power\n"));
+
+    //
+    // Miniport drivers NDIS v6.20 and below are 
+    // paused prior the low power transition 
+    //
+
+    // Check for paused state...
+    // Verify data path stopped...
+
+    return status;
+}
+
+NDIS_STATUS
+tapSetInformation(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in PNDIS_OID_REQUEST      OidRequest
+    )
+/*++
+
+Routine Description:
+
+    Helper function to perform a set OID request
+
+Arguments:
+
+    Adapter         -
+    NdisSetRequest  - The OID to set
+
+Return Value:
+
+    NDIS_STATUS
+
+--*/
+{
+    NDIS_STATUS    status = NDIS_STATUS_SUCCESS;
+
+    DBG_PRINT_OID_NAME(OidRequest->DATA.SET_INFORMATION.Oid);
+
+    switch(OidRequest->DATA.SET_INFORMATION.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 = tapSetMulticastList(Adapter,OidRequest);
+        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 (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG))
+        {
+            OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG);
+            status = NDIS_STATUS_INVALID_LENGTH;
+            break;
+        }
+
+        Adapter->ulLookahead = *(PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
+
+        OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG);
+        status = NDIS_STATUS_SUCCESS;
+        break;
+
+    case OID_GEN_CURRENT_PACKET_FILTER:
+            //
+            // Program the hardware to indicate the packets
+            // of certain filter types.
+            //
+            if(OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG))
+            {
+                OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG);
+                status = NDIS_STATUS_INVALID_LENGTH;
+                break;
+            }
+
+            OidRequest->DATA.SET_INFORMATION.BytesRead
+                = OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+            status = tapSetPacketFilter(
+                            Adapter,
+                            *((PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer)
+                            );
+
+            break;
+
+    case OID_PNP_SET_POWER:
+        {
+            // Sanity check.
+            if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength
+                < sizeof(NDIS_DEVICE_POWER_STATE)
+                )
+            {
+                status = NDIS_STATUS_INVALID_LENGTH;
+            }
+            else
+            {
+                NDIS_DEVICE_POWER_STATE     PowerState;
+
+                PowerState = *(PNDIS_DEVICE_POWER_STATE UNALIGNED)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
+                OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
+
+                if(PowerState < NdisDeviceStateD0  ||
+                    PowerState > NdisDeviceStateD3)
+                {
+                    status = NDIS_STATUS_INVALID_DATA;
+                }
+                else
+                {
+                    Adapter->CurrentPowerState = PowerState;
+
+                    if (PowerState == NdisDeviceStateD0)
+                    {
+                        status = AdapterSetPowerD0(Adapter);
+                    }
+                    else
+                    {
+                        status = AdapterSetPowerLow(Adapter, PowerState);
+                    }
+                }
+            }
+        }
+        break;
+
+#if (NDIS_SUPPORT_NDIS61)
+    case OID_PNP_ADD_WAKE_UP_PATTERN:
+    case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+    case OID_PNP_ENABLE_WAKE_UP:
+#endif
+        ASSERT(!"NIC does not support wake on LAN OIDs"); 
+    default:
+        //
+        // The entry point may by used by other requests
+        //
+        status = NDIS_STATUS_NOT_SUPPORTED;
+        break;
+    }
+
+    return status;
+}
+
+NDIS_STATUS
+tapQueryInformation(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in PNDIS_OID_REQUEST      OidRequest
+    )
+/*++
+
+Routine Description:
+
+    Helper function to perform a query OID request
+
+Arguments:
+
+    Adapter         -
+    OidRequest  - The OID request that is being queried
+
+Return Value:
+
+    NDIS_STATUS
+
+--*/
+{
+    NDIS_STATUS             status = NDIS_STATUS_SUCCESS;
+    NDIS_MEDIUM             Medium = TAP_MEDIUM_TYPE;
+    NDIS_HARDWARE_STATUS    HardwareStatus = NdisHardwareStatusReady;
+    UCHAR                   VendorDesc[] = TAP_VENDOR_DESC;
+    ULONG                   ulInfo;
+    USHORT                  usInfo;
+    ULONG64                 ulInfo64;
+
+    // Default to returning the ULONG value
+    PVOID                   pInfo=NULL;
+    ULONG                   ulInfoLen = sizeof(ulInfo);
+
+    // ATTENTION!!! Ignore OIDs to noisy to print...
+    if((OidRequest->DATA.QUERY_INFORMATION.Oid != OID_GEN_STATISTICS)
+        && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP4_OFFLOAD_STATS)
+        && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP6_OFFLOAD_STATS)
+        )
+    {
+        DBG_PRINT_OID_NAME(OidRequest->DATA.QUERY_INFORMATION.Oid);
+    }
+
+    // Dispatch based on object identifier (OID).
+    switch(OidRequest->DATA.QUERY_INFORMATION.Oid)
+    {
+    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_802_3_PERMANENT_ADDRESS:
+        //
+        // Return the MAC address of the NIC burnt in the hardware.
+        //
+        pInfo = Adapter->PermanentAddress;
+        ulInfoLen = MACADDR_SIZE;
+        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.
+        //
+        pInfo = Adapter->CurrentAddress;
+        ulInfoLen = MACADDR_SIZE;
+        break;
+
+    case OID_GEN_MEDIA_SUPPORTED:
+        //
+        // Return an array of media that are supported by the miniport.
+        // This miniport only supports one medium (Ethernet), so the OID
+        // returns identical results to OID_GEN_MEDIA_IN_USE.
+        //
+
+        __fallthrough;
+
+    case OID_GEN_MEDIA_IN_USE:
+        //
+        // Return an array of media that are currently in use by the
+        // miniport.  This array should be a subset of the array returned
+        // by OID_GEN_MEDIA_SUPPORTED.
+        //
+        pInfo = &Medium;
+        ulInfoLen = sizeof(Medium);
+        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.
+        //
+
+        __fallthrough;
+
+    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. In our case, the transmit
+        // block size is identical to its maximum packet size.
+        __fallthrough;
+
+    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) TAP_MAX_FRAME_SIZE;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_GEN_INTERRUPT_MODERATION:
+        {
+            PNDIS_INTERRUPT_MODERATION_PARAMETERS moderationParams
+                = (PNDIS_INTERRUPT_MODERATION_PARAMETERS)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+
+            moderationParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; 
+            moderationParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+            moderationParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+            moderationParams->Flags = 0;
+            moderationParams->InterruptModeration = NdisInterruptModerationNotSupported;
+            ulInfoLen = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+        }
+        break;
+
+    case OID_PNP_QUERY_POWER:
+        // Simply succeed this.
+        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 = TAP_VENDOR_ID;
+        pInfo = &ulInfo;
+        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 = TAP_DRIVER_VENDOR_VERSION;
+        pInfo = &ulInfo;
+        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) (TAP_NDIS_MAJOR_VERSION<<8) + TAP_NDIS_MINOR_VERSION;
+        pInfo = (PVOID) &usInfo;
+        ulInfoLen = sizeof(USHORT);
+        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 = TAP_MAX_MCAST_LIST;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_GEN_XMIT_ERROR:
+        ulInfo = (ULONG)
+            (Adapter->TxAbortExcessCollisions +
+            Adapter->TxDmaUnderrun +
+            Adapter->TxLostCRS +
+            Adapter->TxLateCollisions+
+            Adapter->TransmitFailuresOther);
+        pInfo = &ulInfo;
+        break;
+
+    case OID_GEN_RCV_ERROR:
+        ulInfo = (ULONG)
+            (Adapter->RxCrcErrors +
+            Adapter->RxAlignmentErrors +
+            Adapter->RxDmaOverrunErrors +
+            Adapter->RxRuntErrors);
+        pInfo = &ulInfo;
+        break;
+
+    case OID_GEN_RCV_DISCARDS:
+        ulInfo = (ULONG)Adapter->RxResourceErrors;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_GEN_RCV_NO_BUFFER:
+        ulInfo = (ULONG)Adapter->RxResourceErrors;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_GEN_XMIT_OK:
+        ulInfo64 = Adapter->FramesTxBroadcast
+            + Adapter->FramesTxMulticast
+            + Adapter->FramesTxDirected;
+        pInfo = &ulInfo64;
+        if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) ||
+            OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0)
+        {
+            ulInfoLen = sizeof(ULONG64);
+        }
+        else
+        {
+            ulInfoLen = sizeof(ULONG);
+        }
+
+        // We should always report that only 8 bytes are required to keep ndistest happy
+        OidRequest->DATA.QUERY_INFORMATION.BytesNeeded =  sizeof(ULONG64);
+        break;
+
+    case OID_GEN_RCV_OK:
+        ulInfo64 = Adapter->FramesRxBroadcast
+            + Adapter->FramesRxMulticast
+            + Adapter->FramesRxDirected;
+
+        pInfo = &ulInfo64;
+
+        if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) ||
+            OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0)
+        {
+            ulInfoLen = sizeof(ULONG64);
+        }
+        else
+        {
+            ulInfoLen = sizeof(ULONG);
+        }
+
+        // We should always report that only 8 bytes are required to keep ndistest happy
+        OidRequest->DATA.QUERY_INFORMATION.BytesNeeded =  sizeof(ULONG64);
+        break;
+
+    case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+        ulInfo = Adapter->RxAlignmentErrors;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_802_3_XMIT_ONE_COLLISION:
+
+        ulInfo = Adapter->OneRetry;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_802_3_XMIT_MORE_COLLISIONS:
+
+        ulInfo = Adapter->MoreThanOneRetry;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_802_3_XMIT_DEFERRED:
+
+        ulInfo = Adapter->TxOKButDeferred;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_802_3_XMIT_MAX_COLLISIONS:
+
+        ulInfo = Adapter->TxAbortExcessCollisions;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_802_3_RCV_OVERRUN:
+
+        ulInfo = Adapter->RxDmaOverrunErrors;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_802_3_XMIT_UNDERRUN:
+
+        ulInfo = Adapter->TxDmaUnderrun;
+        pInfo = &ulInfo;
+        break;
+
+    case OID_GEN_STATISTICS:
+
+        if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(NDIS_STATISTICS_INFO))
+        {
+            status = NDIS_STATUS_INVALID_LENGTH;
+            OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(NDIS_STATISTICS_INFO);
+            break;
+        }
+        else
+        {
+            PNDIS_STATISTICS_INFO Statistics
+                = (PNDIS_STATISTICS_INFO)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+
+            {C_ASSERT(sizeof(NDIS_STATISTICS_INFO) >= NDIS_SIZEOF_STATISTICS_INFO_REVISION_1);}
+            Statistics->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+            Statistics->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+            Statistics->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
+
+            Statistics->SupportedStatistics = TAP_SUPPORTED_STATISTICS;
+
+            /* Bytes in */
+            Statistics->ifHCInOctets =
+                Adapter->BytesRxDirected +
+                Adapter->BytesRxMulticast +
+                Adapter->BytesRxBroadcast;
+
+            Statistics->ifHCInUcastOctets =
+                Adapter->BytesRxDirected;
+
+            Statistics->ifHCInMulticastOctets =
+                Adapter->BytesRxMulticast;
+
+            Statistics->ifHCInBroadcastOctets =
+                Adapter->BytesRxBroadcast;
+
+            /* Packets in */
+            Statistics->ifHCInUcastPkts =
+                Adapter->FramesRxDirected;
+
+            Statistics->ifHCInMulticastPkts =
+                Adapter->FramesRxMulticast;
+
+            Statistics->ifHCInBroadcastPkts =
+                Adapter->FramesRxBroadcast;
+
+            /* Errors in */
+            Statistics->ifInErrors =
+                Adapter->RxCrcErrors +
+                Adapter->RxAlignmentErrors +
+                Adapter->RxDmaOverrunErrors +
+                Adapter->RxRuntErrors;
+
+            Statistics->ifInDiscards =
+                Adapter->RxResourceErrors;
+
+
+            /* Bytes out */
+            Statistics->ifHCOutOctets =
+                Adapter->BytesTxDirected +
+                Adapter->BytesTxMulticast +
+                Adapter->BytesTxBroadcast;
+
+            Statistics->ifHCOutUcastOctets =
+                Adapter->BytesTxDirected;
+
+            Statistics->ifHCOutMulticastOctets =
+                Adapter->BytesTxMulticast;
+
+            Statistics->ifHCOutBroadcastOctets =
+                Adapter->BytesTxBroadcast;
+
+            /* Packets out */
+            Statistics->ifHCOutUcastPkts =
+                Adapter->FramesTxDirected;
+
+            Statistics->ifHCOutMulticastPkts =
+                Adapter->FramesTxMulticast;
+
+            Statistics->ifHCOutBroadcastPkts =
+                Adapter->FramesTxBroadcast;
+
+            /* Errors out */
+            Statistics->ifOutErrors =
+                Adapter->TxAbortExcessCollisions +
+                Adapter->TxDmaUnderrun +
+                Adapter->TxLostCRS +
+                Adapter->TxLateCollisions+
+                Adapter->TransmitFailuresOther;
+
+            Statistics->ifOutDiscards = 0ULL;
+
+            ulInfoLen = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+        }
+
+        break;
+
+        // TODO: Inplement these query information requests.
+    case OID_GEN_RECEIVE_BUFFER_SPACE:
+    case OID_GEN_MAXIMUM_SEND_PACKETS:
+    case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+    case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+    case OID_802_3_XMIT_TIMES_CRS_LOST:
+    case OID_802_3_XMIT_LATE_COLLISIONS:
+
+    default:
+        //
+        // The entry point may by used by other requests
+        //
+        status = NDIS_STATUS_NOT_SUPPORTED;
+        break;
+    }
+
+    if (status == NDIS_STATUS_SUCCESS)
+    {
+        ASSERT(ulInfoLen > 0);
+
+        if (ulInfoLen <= OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength)
+        {
+            if(pInfo)
+            {
+                // Copy result into InformationBuffer
+                NdisMoveMemory(
+                    OidRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+                    pInfo,
+                    ulInfoLen
+                    );
+            }
+
+            OidRequest->DATA.QUERY_INFORMATION.BytesWritten = ulInfoLen;
+        }
+        else
+        {
+            // too short
+            OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = ulInfoLen;
+            status = NDIS_STATUS_BUFFER_TOO_SHORT;
+        }
+    }
+
+    return status;
+}
+
+NDIS_STATUS
+AdapterOidRequest(
+    __in  NDIS_HANDLE             MiniportAdapterContext,
+    __in  PNDIS_OID_REQUEST       OidRequest
+    )
+/*++
+
+Routine Description:
+
+    Entry point called by NDIS to get or set the value of a specified OID.
+
+Arguments:
+
+    MiniportAdapterContext  - Our adapter handle
+    NdisRequest             - The OID request to handle
+
+Return Value:
+
+    Return code from the NdisRequest below.
+
+--*/
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+    NDIS_STATUS    status;
+
+    // Dispatch based on request type.
+    switch (OidRequest->RequestType)
+    {
+    case NdisRequestSetInformation:
+        status = tapSetInformation(adapter,OidRequest);
+        break;
+
+    case NdisRequestQueryInformation:
+    case NdisRequestQueryStatistics:
+        status = tapQueryInformation(adapter,OidRequest);
+        break;
+
+    case NdisRequestMethod: // TAP doesn't need to respond to this request type.
+    default:
+        //
+        // The entry point may by used by other requests
+        //
+        status = NDIS_STATUS_NOT_SUPPORTED;
+        break;
+    }
+
+    return status;
+}
+
+VOID
+AdapterCancelOidRequest(
+    __in NDIS_HANDLE              MiniportAdapterContext,
+    __in PVOID                    RequestId
+    )
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+    UNREFERENCED_PARAMETER(RequestId);
+
+    //
+    // This miniport sample does not pend any OID requests, so we don't have
+    // to worry about cancelling them.
+    //
+}
+

+ 224 - 0
windows/TapDriver6/proto.h

@@ -0,0 +1,224 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//============================================================
+// MAC address, Ethernet header, and ARP
+//============================================================
+
+#pragma pack(1)
+
+#define IP_HEADER_SIZE 20
+#define IPV6_HEADER_SIZE 40
+
+#define MACADDR_SIZE    6
+typedef unsigned char MACADDR[MACADDR_SIZE];
+
+typedef unsigned long IPADDR;
+typedef unsigned char IPV6ADDR[16];
+
+//-----------------
+// Ethernet address
+//-----------------
+
+typedef struct {
+  MACADDR addr;
+} ETH_ADDR;
+
+typedef struct {
+  ETH_ADDR list[TAP_MAX_MCAST_LIST];
+} MC_LIST;
+
+
+// BUGBUG!!! Consider using ststem defines in netiodef.h!!!
+
+//----------------
+// Ethernet header
+//----------------
+typedef struct
+{
+    MACADDR dest;               /* destination eth addr	*/
+    MACADDR src;                /* source ether addr	*/
+    USHORT proto;               /* packet type ID field	*/
+} ETH_HEADER, *PETH_HEADER;
+
+//----------------
+// ARP packet
+//----------------
+
+typedef struct
+   {
+    MACADDR        m_MAC_Destination;        // Reverse these two
+    MACADDR        m_MAC_Source;             // to answer ARP requests
+    USHORT         m_Proto;                  // 0x0806
+
+#   define MAC_ADDR_TYPE 0x0001
+    USHORT         m_MAC_AddressType;        // 0x0001
+
+    USHORT         m_PROTO_AddressType;      // 0x0800
+    UCHAR          m_MAC_AddressSize;        // 0x06
+    UCHAR          m_PROTO_AddressSize;      // 0x04
+
+#   define ARP_REQUEST 0x0001
+#   define ARP_REPLY   0x0002
+    USHORT         m_ARP_Operation;          // 0x0001 for ARP request, 0x0002 for ARP reply
+
+    MACADDR        m_ARP_MAC_Source;
+    IPADDR         m_ARP_IP_Source;
+    MACADDR        m_ARP_MAC_Destination;
+    IPADDR         m_ARP_IP_Destination;
+   }
+ARP_PACKET, *PARP_PACKET;
+
+//----------
+// IP Header
+//----------
+
+typedef struct {
+# define IPH_GET_VER(v) (((v) >> 4) & 0x0F)
+# define IPH_GET_LEN(v) (((v) & 0x0F) << 2)
+  UCHAR    version_len;
+
+  UCHAR    tos;
+  USHORT   tot_len;
+  USHORT   id;
+
+# define IP_OFFMASK 0x1fff
+  USHORT   frag_off;
+
+  UCHAR    ttl;
+
+# define IPPROTO_UDP  17  /* UDP protocol */
+# define IPPROTO_TCP   6  /* TCP protocol */
+# define IPPROTO_ICMP  1  /* ICMP protocol */
+# define IPPROTO_IGMP  2  /* IGMP protocol */
+  UCHAR    protocol;
+
+  USHORT   check;
+  ULONG    saddr;
+  ULONG    daddr;
+  /* The options start here. */
+} IPHDR;
+
+//-----------
+// UDP header
+//-----------
+
+typedef struct {
+  USHORT   source;
+  USHORT   dest;
+  USHORT   len;
+  USHORT   check;
+} UDPHDR;
+
+//--------------------------
+// TCP header, per RFC 793.
+//--------------------------
+
+typedef struct {
+  USHORT      source;    /* source port */
+  USHORT      dest;      /* destination port */
+  ULONG       seq;       /* sequence number */
+  ULONG       ack_seq;   /* acknowledgement number */
+
+# define TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2)
+  UCHAR       doff_res;
+
+# define TCPH_FIN_MASK (1<<0)
+# define TCPH_SYN_MASK (1<<1)
+# define TCPH_RST_MASK (1<<2)
+# define TCPH_PSH_MASK (1<<3)
+# define TCPH_ACK_MASK (1<<4)
+# define TCPH_URG_MASK (1<<5)
+# define TCPH_ECE_MASK (1<<6)
+# define TCPH_CWR_MASK (1<<7)
+  UCHAR       flags;
+
+  USHORT      window;
+  USHORT      check;
+  USHORT      urg_ptr;
+} TCPHDR;
+
+#define	TCPOPT_EOL     0
+#define	TCPOPT_NOP     1
+#define	TCPOPT_MAXSEG  2
+#define TCPOLEN_MAXSEG 4
+
+//------------
+// IPv6 Header
+//------------
+
+typedef struct {
+  UCHAR    version_prio;
+  UCHAR    flow_lbl[3];
+  USHORT   payload_len;
+# define IPPROTO_ICMPV6  0x3a  /* ICMP protocol v6 */
+  UCHAR    nexthdr;
+  UCHAR    hop_limit;
+  IPV6ADDR saddr;
+  IPV6ADDR daddr;
+} IPV6HDR;
+
+//--------------------------------------------
+// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861)
+//--------------------------------------------
+
+// Neighbor Solictiation - RFC 4861, 4.3
+// (this is just the ICMPv6 part of the packet)
+typedef struct {
+  UCHAR    type;
+# define ICMPV6_TYPE_NS	135		// neighbour solicitation
+  UCHAR    code;
+# define ICMPV6_CODE_0	0		// no specific sub-code for NS/NA
+  USHORT   checksum;
+  ULONG    reserved;
+  IPV6ADDR target_addr;
+} ICMPV6_NS;
+
+// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1
+// (this is just the ICMPv6 payload)
+typedef struct {
+  UCHAR    type;
+# define ICMPV6_TYPE_NA	136		// neighbour advertisement
+  UCHAR    code;
+# define ICMPV6_CODE_0	0		// no specific sub-code for NS/NA
+  USHORT   checksum;
+  UCHAR    rso_bits;			// Router(0), Solicited(2), Ovrrd(4)
+  UCHAR	   reserved[3];
+  IPV6ADDR target_addr;
+// always include "Target Link-layer Address" option (RFC 4861 4.6.1)
+  UCHAR    opt_type;
+#define ICMPV6_OPTION_TLLA 2
+  UCHAR    opt_length;
+#define ICMPV6_LENGTH_TLLA 1		// multiplied by 8 -> 1 = 8 bytes
+  MACADDR  target_macaddr;
+} ICMPV6_NA;
+
+// this is the complete packet with Ethernet and IPv6 headers
+typedef struct {
+  ETH_HEADER eth;
+  IPV6HDR    ipv6;
+  ICMPV6_NA  icmpv6;
+} ICMPV6_NA_PKT;
+
+#pragma pack()

+ 87 - 0
windows/TapDriver6/prototypes.h

@@ -0,0 +1,87 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef TAP_PROTOTYPES_DEFINED
+#define TAP_PROTOTYPES_DEFINED
+
+DRIVER_INITIALIZE   DriverEntry;
+
+//VOID AdapterFreeResources
+//   (
+//    TapAdapterPointer p_Adapter
+//   );
+//
+
+//
+//NTSTATUS TapDeviceHook
+//   (
+//    IN PDEVICE_OBJECT p_DeviceObject,
+//    IN PIRP p_IRP
+//   );
+//
+
+NDIS_STATUS
+CreateTapDevice(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+   );
+
+VOID
+DestroyTapDevice(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+   );
+
+// Flush the pending send TAP packet queue.
+VOID
+tapFlushSendPacketQueue(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    );
+
+VOID
+IndicateReceivePacket(
+    __in PTAP_ADAPTER_CONTEXT  Adapter,
+    __in PUCHAR packetData,
+    __in const unsigned int packetLength
+    );
+
+BOOLEAN
+ProcessDHCP(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in const ETH_HEADER *eth,
+    __in const IPHDR *ip,
+    __in const UDPHDR *udp,
+    __in const DHCP *dhcp,
+    __in int optlen
+    );
+
+BOOLEAN
+ProcessARP(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in const PARP_PACKET src,
+    __in const IPADDR adapter_ip,
+    __in const IPADDR ip_network,
+    __in const IPADDR ip_netmask,
+    __in const MACADDR mac
+   );
+
+#endif

BIN
windows/TapDriver6/resource.aps


+ 62 - 0
windows/TapDriver6/resource.rc

@@ -0,0 +1,62 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#include "config.h"
+
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+
+#define	VER_FILETYPE	VFT_DRV
+/* possible values:		VFT_UNKNOWN
+				VFT_APP
+				VFT_DLL
+				VFT_DRV
+				VFT_FONT
+				VFT_VXD
+				VFT_STATIC_LIB
+*/
+#define	VER_FILESUBTYPE	VFT2_DRV_NETWORK
+/* possible values		VFT2_UNKNOWN
+				VFT2_DRV_PRINTER
+				VFT2_DRV_KEYBOARD
+				VFT2_DRV_LANGUAGE
+				VFT2_DRV_DISPLAY
+				VFT2_DRV_MOUSE
+				VFT2_DRV_NETWORK
+				VFT2_DRV_SYSTEM
+				VFT2_DRV_INSTALLABLE
+				VFT2_DRV_SOUND
+				VFT2_DRV_COMM
+*/
+
+#define VER_COMPANYNAME_STR         "The OpenVPN Project"
+#define VER_FILEDESCRIPTION_STR     "TAP-Windows Virtual Network Driver (NDIS 6.0)"
+#define VER_ORIGINALFILENAME_STR    PRODUCT_TAP_WIN_COMPONENT_ID ".sys"
+#define VER_LEGALCOPYRIGHT_YEARS    "2003-2014"
+#define VER_LEGALCOPYRIGHT_STR      "OpenVPN Technologies, Inc."
+
+
+#define VER_PRODUCTNAME_STR         VER_FILEDESCRIPTION_STR
+#define VER_PRODUCTVERSION	    PRODUCT_TAP_WIN_MAJOR,00,00,PRODUCT_TAP_WIN_MINOR
+
+#define XSTR(s) STR(s)
+#define STR(s) #s
+
+#define VSTRING PRODUCT_VERSION " " XSTR(PRODUCT_TAP_WIN_MAJOR) "/" XSTR(PRODUCT_TAP_WIN_MINOR)
+
+#ifdef DBG
+#define VER_PRODUCTVERSION_STR      VSTRING " (DEBUG)"
+#else
+#define VER_PRODUCTVERSION_STR      VSTRING
+#endif
+
+#define VER_INTERNALNAME_STR        VER_ORIGINALFILENAME_STR
+
+#include "common.ver"

+ 667 - 0
windows/TapDriver6/rxpath.c

@@ -0,0 +1,667 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+//======================================================================
+// TAP Receive Path Support
+//======================================================================
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, TapDeviceWrite)
+#endif // ALLOC_PRAGMA
+
+//===============================================================
+// Used in cases where internally generated packets such as
+// ARP or DHCP replies must be returned to the kernel, to be
+// seen as an incoming packet "arriving" on the interface.
+//===============================================================
+
+VOID
+IndicateReceivePacket(
+    __in PTAP_ADAPTER_CONTEXT  Adapter,
+    __in PUCHAR packetData,
+    __in const unsigned int packetLength
+    )
+{
+    PUCHAR  injectBuffer;
+
+    //
+    // Handle miniport Pause
+    // ---------------------
+    // NDIS 6 miniports implement a temporary "Pause" state normally followed
+    // by the Restart. While in the Pause state it is forbidden for the miniport
+    // to indicate receive NBLs.
+    //
+    // That is: The device interface may be "up", but the NDIS miniport send/receive
+    // interface may be temporarily "down".
+    //
+    // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path
+    // the code below will simply ignore inject packets passed to the driver while
+    // the miniport is in the Paused state.
+    //
+    // The correct implementation is to go ahead and build the NBLs corresponding
+    // to the inject packet - but queue them. When Restart is entered the
+    // queued NBLs would be dequeued and indicated to the host.
+    //
+    if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS)
+    {
+        DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n",
+            MINIPORT_INSTANCE_ID (Adapter)));
+
+        return;
+    }
+
+    // Allocate flat buffer for packet data.
+    injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority(
+                        Adapter->MiniportAdapterHandle,
+                        packetLength,
+                        TAP_RX_INJECT_BUFFER_TAG,
+                        NormalPoolPriority
+                        );
+
+    if( injectBuffer)
+    {
+        PMDL    mdl;
+
+        // Copy packet data to flat buffer.
+        NdisMoveMemory (injectBuffer, packetData, packetLength);
+
+        // Allocate MDL for flat buffer.
+        mdl = NdisAllocateMdl(
+                Adapter->MiniportAdapterHandle,
+                injectBuffer,
+                packetLength
+                );
+
+        if( mdl )
+        {
+            PNET_BUFFER_LIST    netBufferList;
+
+            mdl->Next = NULL;   // No next MDL
+
+            // Allocate the NBL and NB. Link MDL chain to NB.
+            netBufferList = NdisAllocateNetBufferAndNetBufferList(
+                                Adapter->ReceiveNblPool,
+                                0,                  // ContextSize
+                                0,                  // ContextBackFill
+                                mdl,                // MDL chain
+                                0,
+                                packetLength
+                                );
+
+            if(netBufferList != NULL)
+            {
+                ULONG       receiveFlags = 0;
+                LONG        nblCount;
+
+                NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+                if(KeGetCurrentIrql() == DISPATCH_LEVEL)
+                {
+                    receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL;
+                }
+
+                // Set flag indicating that this is an injected packet
+                TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+                TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED);
+
+                netBufferList->MiniportReserved[0] = NULL;
+                netBufferList->MiniportReserved[1] = NULL;
+
+                // Increment in-flight receive NBL count.
+                nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount);
+                ASSERT(nblCount > 0 );
+
+                netBufferList->SourceHandle = Adapter->MiniportAdapterHandle;
+
+                //
+                // Indicate the packet
+                // -------------------
+                // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+                // contains the complete packet including Ethernet header and payload.
+                //
+                NdisMIndicateReceiveNetBufferLists(
+                    Adapter->MiniportAdapterHandle,
+                    netBufferList,
+                    NDIS_DEFAULT_PORT_NUMBER,
+                    1,      // NumberOfNetBufferLists
+                    receiveFlags
+                    );
+
+                return;
+            }
+            else
+            {
+                DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n",
+                    MINIPORT_INSTANCE_ID (Adapter)));
+                NOTE_ERROR ();
+
+                NdisFreeMdl(mdl);
+                NdisFreeMemory(injectBuffer,0,0);
+            }
+        }
+        else
+        {
+            DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n",
+                MINIPORT_INSTANCE_ID (Adapter)));
+            NOTE_ERROR ();
+
+            NdisFreeMemory(injectBuffer,0,0);
+        }
+    }
+    else
+    {
+        DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n",
+            MINIPORT_INSTANCE_ID (Adapter)));
+        NOTE_ERROR ();
+    }
+}
+
+VOID
+tapCompleteIrpAndFreeReceiveNetBufferList(
+    __in  PTAP_ADAPTER_CONTEXT  Adapter,
+    __in  PNET_BUFFER_LIST      NetBufferList,  // Only one NB here...
+    __in  NTSTATUS              IoCompletionStatus
+    )
+{
+    PIRP    irp;
+    ULONG   frameType, netBufferCount, byteCount;
+    LONG    nblCount;
+
+    // Fetch NB frame type.
+    frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList));
+
+    // Fetch statistics for all NBs linked to the NB.
+    netBufferCount = tapGetNetBufferCountsFromNetBufferList(
+                        NetBufferList,
+                        &byteCount
+                        );
+
+    // Update statistics by frame type
+    if(IoCompletionStatus == STATUS_SUCCESS)
+    {
+        switch(frameType)
+        {
+        case NDIS_PACKET_TYPE_DIRECTED:
+            Adapter->FramesRxDirected += netBufferCount;
+            Adapter->BytesRxDirected += byteCount;
+            break;
+
+        case NDIS_PACKET_TYPE_BROADCAST:
+            Adapter->FramesRxBroadcast += netBufferCount;
+            Adapter->BytesRxBroadcast += byteCount;
+            break;
+
+        case NDIS_PACKET_TYPE_MULTICAST:
+            Adapter->FramesRxMulticast += netBufferCount;
+            Adapter->BytesRxMulticast += byteCount;
+            break;
+
+        default:
+            ASSERT(FALSE);
+            break;
+        }
+    }
+
+    //
+    // Handle P2P Packet
+    // -----------------
+    // Free MDL allocated for P2P Ethernet header.
+    //
+    if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_P2P))
+    {
+        PNET_BUFFER     netBuffer;
+        PMDL            mdl;
+
+        netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+        mdl = NET_BUFFER_FIRST_MDL(netBuffer);
+        mdl->Next = NULL;
+
+        NdisFreeMdl(mdl);
+    }
+
+    //
+    // Handle Injected Packet
+    // -----------------------
+    // Free MDL and data buffer allocated for injected packet.
+    //
+    if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED))
+    {
+        PNET_BUFFER     netBuffer;
+        PMDL            mdl;
+        PUCHAR          injectBuffer;
+
+        netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+        mdl = NET_BUFFER_FIRST_MDL(netBuffer);
+
+        injectBuffer = (PUCHAR )MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority);
+
+        if(injectBuffer)
+        {
+            NdisFreeMemory(injectBuffer,0,0);
+        }
+
+        NdisFreeMdl(mdl);
+    }
+
+    //
+    // Complete the IRP
+    //
+    irp = (PIRP )NetBufferList->MiniportReserved[0];
+
+    if(irp)
+    {
+        irp->IoStatus.Status = IoCompletionStatus;
+        IoCompleteRequest(irp, IO_NO_INCREMENT);
+    }
+
+    // Decrement in-flight receive NBL count.
+    nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount);
+    ASSERT(nblCount >= 0 );
+    if (0 == nblCount)
+    {
+        NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent);
+    }
+
+    // Free the NBL
+    NdisFreeNetBufferList(NetBufferList);
+}
+
+VOID
+AdapterReturnNetBufferLists(
+    __in  NDIS_HANDLE             MiniportAdapterContext,
+    __in  PNET_BUFFER_LIST        NetBufferLists,
+    __in  ULONG                   ReturnFlags
+    )
+{
+    PTAP_ADAPTER_CONTEXT    adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+    PNET_BUFFER_LIST        currentNbl, nextNbl;
+
+    UNREFERENCED_PARAMETER(ReturnFlags);
+
+    //
+    // Process each NBL individually
+    //
+    currentNbl = NetBufferLists;
+    while (currentNbl)
+    {
+        PNET_BUFFER_LIST    nextNbl;
+
+        nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+        NET_BUFFER_LIST_NEXT_NBL(currentNbl) = NULL;
+
+        // Complete write IRP and free NBL and associated resources.
+        tapCompleteIrpAndFreeReceiveNetBufferList(
+            adapter,
+            currentNbl,
+            STATUS_SUCCESS
+            );
+
+        // Move to next NBL
+        currentNbl = nextNbl;
+    }
+}
+
+// IRP_MJ_WRITE callback.
+NTSTATUS
+TapDeviceWrite(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp
+    )
+{
+    NTSTATUS                ntStatus = STATUS_SUCCESS;// Assume success
+    PIO_STACK_LOCATION      irpSp;// Pointer to current stack location
+    PTAP_ADAPTER_CONTEXT    adapter = NULL;
+    ULONG                   dataLength;
+
+    PAGED_CODE();
+
+    irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    //
+    // Fetch adapter context for this device.
+    // --------------------------------------
+    // Adapter pointer was stashed in FsContext when handle was opened.
+    //
+    adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+    ASSERT(adapter);
+
+    //
+    // Sanity checks on state variables
+    //
+    if (!tapAdapterReadAndWriteReady(adapter))
+    {
+        //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
+        //    MINIPORT_INSTANCE_ID (adapter)));
+        //NOTE_ERROR();
+
+        Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+        return ntStatus;
+    }
+
+    // Save IRP-accessible copy of buffer length
+    Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
+
+    if (Irp->MdlAddress == NULL)
+    {
+        DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
+            MINIPORT_INSTANCE_ID (adapter)));
+
+        NOTE_ERROR();
+        Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+        return ntStatus;
+    }
+
+    //
+    // Try to get a virtual address for the MDL.
+    //
+    NdisQueryMdl(
+        Irp->MdlAddress,
+        &Irp->AssociatedIrp.SystemBuffer,
+        &dataLength,
+        NormalPagePriority
+        );
+
+    if (Irp->AssociatedIrp.SystemBuffer == NULL)
+    {
+        DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
+            MINIPORT_INSTANCE_ID (adapter)));
+
+        NOTE_ERROR();
+        Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+        return ntStatus;
+    }
+
+    ASSERT(dataLength == irpSp->Parameters.Write.Length);
+
+    Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
+
+    //
+    // Handle miniport Pause
+    // ---------------------
+    // NDIS 6 miniports implement a temporary "Pause" state normally followed
+    // by the Restart. While in the Pause state it is forbidden for the miniport
+    // to indicate receive NBLs.
+    //
+    // That is: The device interface may be "up", but the NDIS miniport send/receive
+    // interface may be temporarily "down".
+    //
+    // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path
+    // the code below will perform a "lying send" for write IRPs passed to the
+    // driver while the miniport is in the Paused state.
+    //
+    // The correct implementation is to go ahead and build the NBLs corresponding
+    // to the user-mode write - but queue them. When Restart is entered the
+    // queued NBLs would be dequeued and indicated to the host.
+    //
+    if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS)
+    {
+        if (!adapter->m_tun && ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
+        {
+            PNET_BUFFER_LIST    netBufferList;
+
+            DUMP_PACKET ("IRP_MJ_WRITE ETH",
+                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+                irpSp->Parameters.Write.Length);
+
+            //=====================================================
+            // If IPv4 packet, check whether or not packet
+            // was truncated.
+            //=====================================================
+#if PACKET_TRUNCATION_CHECK
+            IPv4PacketSizeVerify (
+                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+                irpSp->Parameters.Write.Length,
+                FALSE,
+                "RX",
+                &adapter->m_RxTrunc
+                );
+#endif
+            (Irp->MdlAddress)->Next = NULL; // No next MDL
+
+            // Allocate the NBL and NB. Link MDL chain to NB.
+            netBufferList = NdisAllocateNetBufferAndNetBufferList(
+                adapter->ReceiveNblPool,
+                0,                  // ContextSize
+                0,                  // ContextBackFill
+                Irp->MdlAddress,    // MDL chain
+                0,
+                dataLength
+                );
+
+            if(netBufferList != NULL)
+            {
+                LONG    nblCount;
+
+                NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+                // Stash IRP pointer in NBL MiniportReserved[0] field.
+                netBufferList->MiniportReserved[0] = Irp;
+                netBufferList->MiniportReserved[1] = NULL;
+
+                // This IRP is pended.
+                IoMarkIrpPending(Irp);
+
+                // This IRP cannot be cancelled while in-flight.
+                IoSetCancelRoutine(Irp,NULL);
+
+                TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+
+                // Increment in-flight receive NBL count.
+                nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
+                ASSERT(nblCount > 0 );
+
+                //
+                // Indicate the packet
+                // -------------------
+                // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+                // contains the complete packet including Ethernet header and payload.
+                //
+                NdisMIndicateReceiveNetBufferLists(
+                    adapter->MiniportAdapterHandle,
+                    netBufferList,
+                    NDIS_DEFAULT_PORT_NUMBER,
+                    1,      // NumberOfNetBufferLists
+                    0       // ReceiveFlags
+                    );
+
+                ntStatus = STATUS_PENDING;
+            }
+            else
+            {
+                DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
+                    MINIPORT_INSTANCE_ID (adapter)));
+                NOTE_ERROR ();
+
+                // Fail the IRP
+                Irp->IoStatus.Information = 0;
+                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+            }
+        }
+        else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
+        {
+            PETH_HEADER         p_UserToTap = &adapter->m_UserToTap;
+            PMDL                mdl;    // Head of MDL chain.
+
+            // For IPv6, need to use Ethernet header with IPv6 proto
+            if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 )
+            {
+                p_UserToTap = &adapter->m_UserToTap_IPv6;
+            }
+
+            DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
+                p_UserToTap,
+                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+                irpSp->Parameters.Write.Length);
+
+            //=====================================================
+            // If IPv4 packet, check whether or not packet
+            // was truncated.
+            //=====================================================
+#if PACKET_TRUNCATION_CHECK
+            IPv4PacketSizeVerify (
+                (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+                irpSp->Parameters.Write.Length,
+                TRUE,
+                "RX",
+                &adapter->m_RxTrunc
+                );
+#endif
+
+            //
+            // Allocate MDL for Ethernet header
+            // --------------------------------
+            // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+            // contains the only the Ethernet payload. Prepend the user-mode provided
+            // payload with the Ethernet header pointed to by p_UserToTap.
+            //
+            mdl = NdisAllocateMdl(
+                adapter->MiniportAdapterHandle,
+                p_UserToTap,
+                sizeof(ETH_HEADER)
+                );
+
+            if(mdl != NULL)
+            {
+                PNET_BUFFER_LIST    netBufferList;
+
+                // Chain user's Ethernet payload behind Ethernet header.
+                mdl->Next = Irp->MdlAddress;
+                (Irp->MdlAddress)->Next = NULL; // No next MDL
+
+                // Allocate the NBL and NB. Link MDL chain to NB.
+                netBufferList = NdisAllocateNetBufferAndNetBufferList(
+                    adapter->ReceiveNblPool,
+                    0,          // ContextSize
+                    0,          // ContextBackFill
+                    mdl,        // MDL chain
+                    0,
+                    sizeof(ETH_HEADER) + dataLength
+                    );
+
+                if(netBufferList != NULL)
+                {
+                    LONG        nblCount;
+
+                    NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+                    // This IRP is pended.
+                    IoMarkIrpPending(Irp);
+
+                    // This IRP cannot be cancelled while in-flight.
+                    IoSetCancelRoutine(Irp,NULL);
+
+                    // Stash IRP pointer in NBL MiniportReserved[0] field.
+                    netBufferList->MiniportReserved[0] = Irp;
+                    netBufferList->MiniportReserved[1] = NULL;
+
+                    // Set flag indicating that this is P2P packet
+                    TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+                    TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P);
+
+                    // Increment in-flight receive NBL count.
+                    nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
+                    ASSERT(nblCount > 0 );
+
+                    //
+                    // Indicate the packet
+                    //
+                    NdisMIndicateReceiveNetBufferLists(
+                        adapter->MiniportAdapterHandle,
+                        netBufferList,
+                        NDIS_DEFAULT_PORT_NUMBER,
+                        1,      // NumberOfNetBufferLists
+                        0       // ReceiveFlags
+                        );
+
+                    ntStatus = STATUS_PENDING;
+                }
+                else
+                {
+                    mdl->Next = NULL;
+                    NdisFreeMdl(mdl);
+
+                    DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
+                        MINIPORT_INSTANCE_ID (adapter)));
+                    NOTE_ERROR ();
+
+                    // Fail the IRP
+                    Irp->IoStatus.Information = 0;
+                    ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+                }
+            }
+            else
+            {
+                DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n",
+                    MINIPORT_INSTANCE_ID (adapter)));
+                NOTE_ERROR ();
+
+                // Fail the IRP
+                Irp->IoStatus.Information = 0;
+                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+            }
+        }
+        else
+        {
+            DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
+                MINIPORT_INSTANCE_ID (adapter),
+                irpSp->Parameters.Write.Length));
+            NOTE_ERROR ();
+
+            Irp->IoStatus.Information = 0;	// ETHERNET_HEADER_SIZE;
+            Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+        }
+    }
+    else
+    {
+        DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n",
+            MINIPORT_INSTANCE_ID (adapter)));
+
+        ntStatus = STATUS_SUCCESS;
+    }
+
+    if (ntStatus != STATUS_PENDING)
+    {
+        Irp->IoStatus.Status = ntStatus;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    return ntStatus;
+}
+

+ 74 - 0
windows/TapDriver6/tap-windows.h

@@ -0,0 +1,74 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __TAP_WIN_H
+#define __TAP_WIN_H
+
+/*
+ * =============
+ * TAP IOCTLs
+ * =============
+ */
+
+#define TAP_WIN_CONTROL_CODE(request,method) \
+  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
+
+/* Present in 8.1 */
+
+#define TAP_WIN_IOCTL_GET_MAC               TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_VERSION           TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_MTU               TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_INFO              TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_SET_MEDIA_STATUS      TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ      TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_LOG_LINE          TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT   TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED)
+
+/* Added in 8.2 */
+
+/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
+#define TAP_WIN_IOCTL_CONFIG_TUN            TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED)
+
+/*
+ * =================
+ * Registry keys
+ * =================
+ */
+
+#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+/*
+ * ======================
+ * Filesystem prefixes
+ * ======================
+ */
+
+#define USERMODEDEVICEDIR "\\\\.\\Global\\"
+#define SYSDEVICEDIR      "\\Device\\"
+#define USERDEVICEDIR     "\\DosDevices\\Global\\"
+#define TAP_WIN_SUFFIX    ".tap"
+
+#endif // __TAP_WIN_H

+ 90 - 0
windows/TapDriver6/tap.h

@@ -0,0 +1,90 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __TAP_H
+#define __TAP_H
+
+#ifndef NDIS_SUPPORT_NDIS6
+#define NDIS_SUPPORT_NDIS6 1
+#define NDIS_SUPPORT_NDIS61 1
+#define NDIS_WDM1 1
+#define NDIS61_MINIPORT 1
+#endif
+
+#include <ntifs.h>
+#include <ndis.h>
+#include <ntstrsafe.h>
+#include <netioapi.h>
+
+#include "config.h"
+#include "lock.h"
+#include "constants.h"
+#include "proto.h"
+#include "mem.h"
+#include "macinfo.h"
+#include "dhcp.h"
+#include "error.h"
+#include "endian.h"
+#include "dhcp.h"
+#include "types.h"
+#include "adapter.h"
+#include "device.h"
+#include "prototypes.h"
+#include "tap-windows.h"
+
+//========================================================
+// Check for truncated IPv4 packets, log errors if found.
+//========================================================
+#define PACKET_TRUNCATION_CHECK 0
+
+//========================================================
+// EXPERIMENTAL -- Configure TAP device object to be
+// accessible from non-administrative accounts, based
+// on an advanced properties setting.
+//
+// Duplicates the functionality of OpenVPN's
+// --allow-nonadmin directive.
+//========================================================
+#define ENABLE_NONADMIN 1
+
+//
+// The driver has exactly one instance of the TAP_GLOBAL structure.  NDIS keeps
+// an opaque handle to this data, (it doesn't attempt to read or interpret this
+// data), and it passes the handle back to the miniport in MiniportSetOptions
+// and MiniportInitializeEx.
+//
+typedef struct _TAP_GLOBAL
+{
+    LIST_ENTRY          AdapterList;
+
+    NDIS_RW_LOCK        Lock;
+
+    NDIS_HANDLE         NdisDriverHandle;   // From NdisMRegisterMiniportDriver
+
+} TAP_GLOBAL, *PTAP_GLOBAL;
+
+
+// Global data
+extern TAP_GLOBAL      GlobalData;
+
+#endif // __TAP_H

+ 232 - 0
windows/TapDriver6/tapdrvr.c

@@ -0,0 +1,232 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//======================================================
+// This driver is designed to work on Windows Vista or higher
+// versions of Windows.
+//
+// It is SMP-safe and handles power management.
+//
+// By default we operate as a "tap" virtual ethernet
+// 802.3 interface, but we can emulate a "tun"
+// interface (point-to-point IPv4) through the
+// TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT or
+// TAP_WIN_IOCTL_CONFIG_TUN ioctl.
+//======================================================
+
+//
+// Include files.
+//
+
+#include <string.h>
+
+#include "tap.h"
+
+
+// Global data
+TAP_GLOBAL      GlobalData;
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( INIT, DriverEntry )
+#pragma alloc_text( PAGE, TapDriverUnload)
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+DriverEntry(
+    __in PDRIVER_OBJECT   DriverObject,
+    __in PUNICODE_STRING  RegistryPath
+    )
+/*++
+Routine Description:
+
+    In the context of its DriverEntry function, a miniport driver associates
+    itself with NDIS, specifies the NDIS version that it is using, and
+    registers its entry points.
+
+
+Arguments:
+    PVOID DriverObject - pointer to the driver object.
+    PVOID RegistryPath - pointer to the driver registry path.
+
+    Return Value:
+
+    NTSTATUS code
+
+--*/
+{
+    NTSTATUS                                status;
+
+    UNREFERENCED_PARAMETER(RegistryPath);
+
+    DEBUGP (("[TAP] --> DriverEntry; version [%d.%d] %s %s\n",
+        TAP_DRIVER_MAJOR_VERSION,
+        TAP_DRIVER_MINOR_VERSION,
+        __DATE__,
+        __TIME__));
+
+    DEBUGP (("[TAP] Registry Path: '%wZ'\n", RegistryPath));
+
+    //
+    // Initialize any driver-global variables here.
+    //
+    NdisZeroMemory(&GlobalData, sizeof(GlobalData));
+
+    //
+    // The ApaterList in the GlobalData structure is used to track multiple
+    // adapters controlled by this miniport.
+    //
+    NdisInitializeListHead(&GlobalData.AdapterList);
+
+    //
+    // This lock protects the AdapterList.
+    //
+    NdisInitializeReadWriteLock(&GlobalData.Lock);
+
+    do
+    {
+        NDIS_MINIPORT_DRIVER_CHARACTERISTICS    miniportCharacteristics;
+
+        NdisZeroMemory(&miniportCharacteristics, sizeof(miniportCharacteristics));
+
+        {C_ASSERT(sizeof(miniportCharacteristics) >= NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2);}
+        miniportCharacteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
+        miniportCharacteristics.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
+        miniportCharacteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
+
+        miniportCharacteristics.MajorNdisVersion = TAP_NDIS_MAJOR_VERSION;
+        miniportCharacteristics.MinorNdisVersion = TAP_NDIS_MINOR_VERSION;
+
+        miniportCharacteristics.MajorDriverVersion = TAP_DRIVER_MAJOR_VERSION;
+        miniportCharacteristics.MinorDriverVersion = TAP_DRIVER_MINOR_VERSION;
+
+        miniportCharacteristics.Flags = 0;
+
+        //miniportCharacteristics.SetOptionsHandler = MPSetOptions; // Optional
+        miniportCharacteristics.InitializeHandlerEx = AdapterCreate;
+        miniportCharacteristics.HaltHandlerEx = AdapterHalt;
+        miniportCharacteristics.UnloadHandler = TapDriverUnload;
+        miniportCharacteristics.PauseHandler = AdapterPause;
+        miniportCharacteristics.RestartHandler = AdapterRestart;
+        miniportCharacteristics.OidRequestHandler = AdapterOidRequest;
+        miniportCharacteristics.SendNetBufferListsHandler = AdapterSendNetBufferLists;
+        miniportCharacteristics.ReturnNetBufferListsHandler = AdapterReturnNetBufferLists;
+        miniportCharacteristics.CancelSendHandler = AdapterCancelSend;
+        miniportCharacteristics.CheckForHangHandlerEx = AdapterCheckForHangEx;
+        miniportCharacteristics.ResetHandlerEx = AdapterReset;
+        miniportCharacteristics.DevicePnPEventNotifyHandler = AdapterDevicePnpEventNotify;
+        miniportCharacteristics.ShutdownHandlerEx = AdapterShutdownEx;
+        miniportCharacteristics.CancelOidRequestHandler = AdapterCancelOidRequest;
+
+        //
+        // Associate the miniport driver with NDIS by calling the
+        // NdisMRegisterMiniportDriver. This function returns an NdisDriverHandle.
+        // The miniport driver must retain this handle but it should never attempt
+        // to access or interpret this handle.
+        //
+        // By calling NdisMRegisterMiniportDriver, the driver indicates that it
+        // is ready for NDIS to call the driver's MiniportSetOptions and
+        // MiniportInitializeEx handlers.
+        //
+        DEBUGP (("[TAP] Calling NdisMRegisterMiniportDriver...\n"));
+        //NDIS_DECLARE_MINIPORT_DRIVER_CONTEXT(TAP_GLOBAL);
+        status = NdisMRegisterMiniportDriver(
+                    DriverObject,
+                    RegistryPath,
+                    &GlobalData,
+                    &miniportCharacteristics,
+                    &GlobalData.NdisDriverHandle
+                    );
+
+        if (NDIS_STATUS_SUCCESS == status)
+        {
+            DEBUGP (("[TAP] Registered miniport successfully\n"));
+        }
+        else
+        {
+            DEBUGP(("[TAP] NdisMRegisterMiniportDriver failed: %8.8X\n", status));
+            TapDriverUnload(DriverObject);
+            status = NDIS_STATUS_FAILURE;
+            break;
+        }
+    } while(FALSE);
+
+    DEBUGP (("[TAP] <-- DriverEntry; status = %8.8X\n",status));
+
+    return status;
+}
+
+VOID
+TapDriverUnload(
+    __in PDRIVER_OBJECT DriverObject
+    )
+/*++
+
+Routine Description:
+
+    The unload handler is called during driver unload to free up resources
+    acquired in DriverEntry. This handler is registered in DriverEntry through
+    NdisMRegisterMiniportDriver. Note that an unload handler differs from
+    a MiniportHalt function in that this unload handler releases resources that
+    are global to the driver, while the halt handler releases resource for a
+    particular adapter.
+
+    Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+    DriverObject        Not used
+
+Return Value:
+
+    None.
+
+--*/
+{
+    PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
+    UNICODE_STRING uniWin32NameString;
+
+    DEBUGP (("[TAP] --> TapDriverUnload; version [%d.%d] %s %s unloaded\n",
+        TAP_DRIVER_MAJOR_VERSION,
+        TAP_DRIVER_MINOR_VERSION,
+        __DATE__,
+        __TIME__
+        ));
+
+    PAGED_CODE();
+
+    //
+    // Clean up all globals that were allocated in DriverEntry
+    //
+
+    ASSERT(IsListEmpty(&GlobalData.AdapterList));
+
+    if(GlobalData.NdisDriverHandle != NULL )
+    {
+        NdisMDeregisterMiniportDriver(GlobalData.NdisDriverHandle);
+    }
+
+    DEBUGP (("[TAP] <-- TapDriverUnload\n"));
+}
+

+ 1168 - 0
windows/TapDriver6/txpath.c

@@ -0,0 +1,1168 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+//======================================================================
+// TAP Send Path Support
+//======================================================================
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, TapDeviceRead)
+#endif // ALLOC_PRAGMA
+
+// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum
+// see RFC 4443, 2.3, and RFC 2460, 8.1
+USHORT
+icmpv6_checksum(
+    __in const UCHAR *buf,
+    __in const int len_icmpv6,
+    __in const UCHAR *saddr6,
+    __in const UCHAR *daddr6
+    )
+{
+    USHORT word16;
+    ULONG sum = 0;
+    int i;
+
+    // make 16 bit words out of every two adjacent 8 bit words and
+    // calculate the sum of all 16 bit words
+    for (i = 0; i < len_icmpv6; i += 2)
+    {
+        word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i+1] & 0xFF) : 0);
+        sum += word16;
+    }
+
+    // add the IPv6 pseudo header which contains the IP source and destination addresses
+    for (i = 0; i < 16; i += 2)
+    {
+        word16 =((saddr6[i] << 8) & 0xFF00) + (saddr6[i+1] & 0xFF);
+        sum += word16;
+    }
+
+    for (i = 0; i < 16; i += 2)
+    {
+        word16 =((daddr6[i] << 8) & 0xFF00) + (daddr6[i+1] & 0xFF);
+        sum += word16;
+    }
+
+    // the next-header number and the length of the ICMPv6 packet
+    sum += (USHORT) IPPROTO_ICMPV6 + (USHORT) len_icmpv6;
+
+    // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+    while (sum >> 16)
+        sum = (sum & 0xFFFF) + (sum >> 16);
+
+    // Take the one's complement of sum
+    return ((USHORT) ~sum);
+}
+
+// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that
+// the tap driver needs to answer?"
+// see RFC 4861 4.3 for the different cases
+static IPV6ADDR IPV6_NS_TARGET_MCAST =
+	{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+          0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08 };
+static IPV6ADDR IPV6_NS_TARGET_UNICAST =
+	{ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };
+
+BOOLEAN
+HandleIPv6NeighborDiscovery(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in UCHAR * m_Data
+    )
+{
+    const ETH_HEADER * e = (ETH_HEADER *) m_Data;
+    const IPV6HDR *ipv6 = (IPV6HDR *) (m_Data + sizeof (ETH_HEADER));
+    const ICMPV6_NS * icmpv6_ns = (ICMPV6_NS *) (m_Data + sizeof (ETH_HEADER) + sizeof (IPV6HDR));
+    ICMPV6_NA_PKT *na;
+    USHORT icmpv6_len, icmpv6_csum;
+
+    // we don't really care about the destination MAC address here
+    // - it's either a multicast MAC, or the userland destination MAC
+    // but since the TAP driver is point-to-point, all packets are "for us"
+
+    // IPv6 target address must be ff02::1::ff00:8 (multicast for
+    // initial NS) or fe80::1 (unicast for recurrent NUD)
+    if ( memcmp( ipv6->daddr, IPV6_NS_TARGET_MCAST,
+        sizeof(IPV6ADDR) ) != 0 &&
+        memcmp( ipv6->daddr, IPV6_NS_TARGET_UNICAST,
+        sizeof(IPV6ADDR) ) != 0 )
+    {
+        return FALSE;				// wrong target address
+    }
+
+    // IPv6 Next-Header must be ICMPv6
+    if ( ipv6->nexthdr != IPPROTO_ICMPV6 )
+    {
+        return FALSE;				// wrong next-header
+    }
+
+    // ICMPv6 type+code must be 135/0 for NS
+    if ( icmpv6_ns->type != ICMPV6_TYPE_NS ||
+        icmpv6_ns->code != ICMPV6_CODE_0 )
+    {
+        return FALSE;				// wrong ICMPv6 type
+    }
+
+    // ICMPv6 target address must be fe80::8 (magic)
+    if ( memcmp( icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST,
+        sizeof(IPV6ADDR) ) != 0 )
+    {
+        return FALSE;				// not for us
+    }
+
+    // packet identified, build magic response packet
+
+    na = (ICMPV6_NA_PKT *) MemAlloc (sizeof (ICMPV6_NA_PKT), TRUE);
+    if ( !na ) return FALSE;
+
+    //------------------------------------------------
+    // Initialize Neighbour Advertisement reply packet
+    //------------------------------------------------
+
+    // ethernet header
+    na->eth.proto = htons(NDIS_ETH_TYPE_IPV6);
+    ETH_COPY_NETWORK_ADDRESS(na->eth.dest, Adapter->PermanentAddress);
+    ETH_COPY_NETWORK_ADDRESS(na->eth.src, Adapter->m_TapToUser.dest);
+
+    // IPv6 header
+    na->ipv6.version_prio = ipv6->version_prio;
+    NdisMoveMemory( na->ipv6.flow_lbl, ipv6->flow_lbl,
+        sizeof(na->ipv6.flow_lbl) );
+    icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR);
+    na->ipv6.payload_len = htons(icmpv6_len);
+    na->ipv6.nexthdr = IPPROTO_ICMPV6;
+    na->ipv6.hop_limit = 255;
+    NdisMoveMemory( na->ipv6.saddr, IPV6_NS_TARGET_UNICAST,
+        sizeof(IPV6ADDR) );
+    NdisMoveMemory( na->ipv6.daddr, ipv6->saddr,
+        sizeof(IPV6ADDR) );
+
+    // ICMPv6
+    na->icmpv6.type = ICMPV6_TYPE_NA;
+    na->icmpv6.code = ICMPV6_CODE_0;
+    na->icmpv6.checksum = 0;
+    na->icmpv6.rso_bits = 0x60;		// Solicited + Override
+    NdisZeroMemory( na->icmpv6.reserved, sizeof(na->icmpv6.reserved) );
+    NdisMoveMemory( na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST,
+        sizeof(IPV6ADDR) );
+
+    // ICMPv6 option "Target Link Layer Address"
+    na->icmpv6.opt_type = ICMPV6_OPTION_TLLA;
+    na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA;
+    ETH_COPY_NETWORK_ADDRESS( na->icmpv6.target_macaddr, Adapter->m_TapToUser.dest );
+
+    // calculate and set checksum
+    icmpv6_csum = icmpv6_checksum (
+                    (UCHAR*) &(na->icmpv6),
+                    icmpv6_len,
+                    na->ipv6.saddr,
+                    na->ipv6.daddr
+                    );
+
+    na->icmpv6.checksum = htons( icmpv6_csum );
+
+    DUMP_PACKET ("HandleIPv6NeighborDiscovery",
+        (unsigned char *) na,
+        sizeof (ICMPV6_NA_PKT));
+
+    IndicateReceivePacket (Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT));
+
+    MemFree (na, sizeof (ICMPV6_NA_PKT));
+
+    return TRUE;				// all fine
+}
+
+//===================================================
+// Generate an ARP reply message for specific kinds
+// ARP queries.
+//===================================================
+BOOLEAN
+ProcessARP(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in const PARP_PACKET src,
+    __in const IPADDR adapter_ip,
+    __in const IPADDR ip_network,
+    __in const IPADDR ip_netmask,
+    __in const MACADDR mac
+    )
+{
+    //-----------------------------------------------
+    // Is this the kind of packet we are looking for?
+    //-----------------------------------------------
+    if (src->m_Proto == htons (NDIS_ETH_TYPE_ARP)
+        && MAC_EQUAL (src->m_MAC_Source, Adapter->PermanentAddress)
+        && MAC_EQUAL (src->m_ARP_MAC_Source, Adapter->PermanentAddress)
+        && ETH_IS_BROADCAST(src->m_MAC_Destination)
+        && src->m_ARP_Operation == htons (ARP_REQUEST)
+        && src->m_MAC_AddressType == htons (MAC_ADDR_TYPE)
+        && src->m_MAC_AddressSize == sizeof (MACADDR)
+        && src->m_PROTO_AddressType == htons (NDIS_ETH_TYPE_IPV4)
+        && src->m_PROTO_AddressSize == sizeof (IPADDR)
+        && src->m_ARP_IP_Source == adapter_ip
+        && (src->m_ARP_IP_Destination & ip_netmask) == ip_network
+        && src->m_ARP_IP_Destination != adapter_ip)
+    {
+        ARP_PACKET *arp = (ARP_PACKET *) MemAlloc (sizeof (ARP_PACKET), TRUE);
+        if (arp)
+        {
+            //----------------------------------------------
+            // Initialize ARP reply fields
+            //----------------------------------------------
+            arp->m_Proto = htons (NDIS_ETH_TYPE_ARP);
+            arp->m_MAC_AddressType = htons (MAC_ADDR_TYPE);
+            arp->m_PROTO_AddressType = htons (NDIS_ETH_TYPE_IPV4);
+            arp->m_MAC_AddressSize = sizeof (MACADDR);
+            arp->m_PROTO_AddressSize = sizeof (IPADDR);
+            arp->m_ARP_Operation = htons (ARP_REPLY);
+
+            //----------------------------------------------
+            // ARP addresses
+            //----------------------------------------------      
+            ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Source, mac);
+            ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Destination, Adapter->PermanentAddress);
+            ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Source, mac);
+            ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Destination, Adapter->PermanentAddress);
+            arp->m_ARP_IP_Source = src->m_ARP_IP_Destination;
+            arp->m_ARP_IP_Destination = adapter_ip;
+
+            DUMP_PACKET ("ProcessARP",
+                (unsigned char *) arp,
+                sizeof (ARP_PACKET));
+
+            IndicateReceivePacket (Adapter, (UCHAR *) arp, sizeof (ARP_PACKET));
+
+            MemFree (arp, sizeof (ARP_PACKET));
+        }
+
+        return TRUE;
+    }
+    else
+        return FALSE;
+}
+
+//=============================================================
+// CompleteIRP is normally called with an adapter -> userspace
+// network packet and an IRP (Pending I/O request) from userspace.
+//
+// The IRP will normally represent a queued overlapped read
+// operation from userspace that is in a wait state.
+//
+// Use the ethernet packet to satisfy the IRP.
+//=============================================================
+
+VOID
+tapCompletePendingReadIrp(
+    __in PIRP Irp,
+    __in PTAP_PACKET TapPacket
+    )
+{
+    int offset;
+    int len;
+    NTSTATUS    status = STATUS_UNSUCCESSFUL;
+
+    ASSERT(Irp);
+    ASSERT(TapPacket);
+
+    //-------------------------------------------
+    // While TapPacket always contains a
+    // full ethernet packet, including the
+    // ethernet header, in point-to-point mode,
+    // we only want to return the IPv4
+    // component.
+    //-------------------------------------------
+
+    if (TapPacket->m_SizeFlags & TP_TUN)
+    {
+        offset = ETHERNET_HEADER_SIZE;
+        len = (int) (TapPacket->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE;
+    }
+    else
+    {
+        offset = 0;
+        len = (TapPacket->m_SizeFlags & TP_SIZE_MASK);
+    }
+
+    if (len < 0 || (int) Irp->IoStatus.Information < len)
+    {
+        Irp->IoStatus.Information = 0;
+        Irp->IoStatus.Status = status = STATUS_BUFFER_OVERFLOW;
+        NOTE_ERROR ();
+    }
+    else
+    {
+        Irp->IoStatus.Information = len;
+        Irp->IoStatus.Status = status = STATUS_SUCCESS;
+
+        // Copy packet data
+        NdisMoveMemory(
+            Irp->AssociatedIrp.SystemBuffer,
+            TapPacket->m_Data + offset,
+            len
+            );
+    }
+
+    // Free the TAP packet
+    NdisFreeMemory(TapPacket,0,0);
+
+    // Complete the IRP
+    IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+}
+
+VOID
+tapProcessSendPacketQueue(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    )
+{
+    KIRQL  irql;
+
+    // Process the send packet queue
+    KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql);
+
+    while(Adapter->SendPacketQueue.Count > 0 )
+    {
+        PIRP            irp;
+        PTAP_PACKET     tapPacket;
+
+        // Fetch a read IRP
+        irp = IoCsqRemoveNextIrp(
+                &Adapter->PendingReadIrpQueue.CsqQueue,
+                NULL
+                );
+
+        if( irp == NULL )
+        {
+            // No IRP to satisfy
+            break;
+        }
+
+        // Fetch a queued TAP send packet
+        tapPacket = tapPacketRemoveHeadLocked(
+                        &Adapter->SendPacketQueue
+                        );
+
+        ASSERT(tapPacket);
+
+        // BUGBUG!!! Investigate whether release/reacquire can cause
+        // out-of-order IRP completion. Also, whether user-mode can
+        // tolerate out-of-order packets.
+
+        // Release packet queue lock while completing the IRP
+        //KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql);
+
+        // Complete the read IRP from queued TAP send packet.
+        tapCompletePendingReadIrp(irp,tapPacket);
+
+        // Reqcquire packet queue lock after completing the IRP
+        //KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql);
+    }
+
+    KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql);
+}
+
+// Flush the pending send TAP packet queue.
+VOID
+tapFlushSendPacketQueue(
+    __in PTAP_ADAPTER_CONTEXT   Adapter
+    )
+{
+    KIRQL  irql;
+
+    // Process the send packet queue
+    KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql);
+
+    DEBUGP (("[TAP] tapFlushSendPacketQueue: Flushing %d TAP packets\n",
+        Adapter->SendPacketQueue.Count));
+
+    while(Adapter->SendPacketQueue.Count > 0 )
+    {
+        PTAP_PACKET     tapPacket;
+
+        // Fetch a queued TAP send packet
+        tapPacket = tapPacketRemoveHeadLocked(
+                        &Adapter->SendPacketQueue
+                        );
+
+        ASSERT(tapPacket);
+
+        // Free the TAP packet
+        NdisFreeMemory(tapPacket,0,0);
+    }
+
+    KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql);
+}
+
+VOID
+tapAdapterTransmit(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in PNET_BUFFER            NetBuffer,
+    __in  BOOLEAN               DispatchLevel
+    )
+/*++
+
+Routine Description:
+
+    This routine is called to transmit an individual net buffer using a
+    style similar to the previous NDIS 5 AdapterTransmit function.
+
+    In this implementation adapter state and NB length checks have already
+    been done before this function has been called.
+
+    The net buffer will be completed by the calling routine after this
+    routine exits. So, under this design it is necessary to make a deep
+    copy of frame data in the net buffer.
+
+    This routine creates a flat buffer copy of NB frame data. This is an
+    unnecessary performance bottleneck. However, the bottleneck is probably
+    not significant or measurable except for adapters running at 1Gbps or
+    greater speeds. Since this adapter is currently running at 100Mbps this
+    defect can be ignored.
+
+    Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+    Adapter                     Pointer to our adapter context
+    NetBuffer                   Pointer to the net buffer to transmit
+    DispatchLevel               TRUE if called at IRQL == DISPATCH_LEVEL
+
+Return Value:
+
+    None.
+
+    In the Microsoft NDIS 6 architecture there is no per-packet status.
+
+--*/
+{
+    NDIS_STATUS     status;
+    ULONG           packetLength;
+    PTAP_PACKET     tapPacket;
+    PVOID           packetData;
+
+    packetLength = NET_BUFFER_DATA_LENGTH(NetBuffer);
+
+    // Allocate TAP packet memory
+    tapPacket = (PTAP_PACKET )NdisAllocateMemoryWithTagPriority(
+                    Adapter->MiniportAdapterHandle,
+                    TAP_PACKET_SIZE (packetLength),
+                    TAP_PACKET_TAG,
+                    NormalPoolPriority
+                    );
+
+    if(tapPacket == NULL)
+    {
+        DEBUGP (("[TAP] tapAdapterTransmit: TAP packet allocation failed\n"));
+        return;
+    }
+
+    tapPacket->m_SizeFlags = (packetLength & TP_SIZE_MASK);
+
+    //
+    // Reassemble packet contents
+    // --------------------------
+    // NdisGetDataBuffer does most of the work. There are two cases:
+    //
+    //    1.) If the NB data was not contiguous it will copy the entire
+    //        NB's data to m_data and return pointer to m_data.
+    //    2.) If the NB data was contiguous it returns a pointer to the
+    //        first byte of the contiguous data instead of a pointer to m_Data.
+    //        In this case the data will not have been copied to m_Data. Copy
+    //        to m_Data will need to be done in an extra step.
+    //
+    // Case 1.) is the most likely in normal operation.
+    //
+    packetData = NdisGetDataBuffer(NetBuffer,packetLength,tapPacket->m_Data,1,0);
+
+    if(packetData == NULL)
+    {
+        DEBUGP (("[TAP] tapAdapterTransmit: Could not get packet data\n"));
+
+        NdisFreeMemory(tapPacket,0,0);
+
+        return;
+    }
+
+    if(packetData != tapPacket->m_Data)
+    {
+        // Packet data was contiguous and not yet copied to m_Data.
+        NdisMoveMemory(tapPacket->m_Data,packetData,packetLength);
+    }
+    
+    DUMP_PACKET ("AdapterTransmit", tapPacket->m_Data, packetLength);
+
+    //=====================================================
+    // If IPv4 packet, check whether or not packet
+    // was truncated.
+    //=====================================================
+#if PACKET_TRUNCATION_CHECK
+    IPv4PacketSizeVerify(
+        tapPacket->m_Data,
+        packetLength,
+        FALSE,
+        "TX",
+        &Adapter->m_TxTrunc
+        );
+#endif
+
+    //=====================================================
+    // Are we running in DHCP server masquerade mode?
+    //
+    // If so, catch both DHCP requests and ARP queries
+    // to resolve the address of our virtual DHCP server.
+    //=====================================================
+    if (Adapter->m_dhcp_enabled)
+    {
+        const ETH_HEADER *eth = (ETH_HEADER *) tapPacket->m_Data;
+        const IPHDR *ip = (IPHDR *) (tapPacket->m_Data + sizeof (ETH_HEADER));
+        const UDPHDR *udp = (UDPHDR *) (tapPacket->m_Data + sizeof (ETH_HEADER) + sizeof (IPHDR));
+
+        // ARP packet?
+        if (packetLength == sizeof (ARP_PACKET)
+            && eth->proto == htons (NDIS_ETH_TYPE_ARP)
+            && Adapter->m_dhcp_server_arp
+            )
+        {
+            if (ProcessARP(
+                    Adapter,
+                    (PARP_PACKET) tapPacket->m_Data,
+                    Adapter->m_dhcp_addr,
+                    Adapter->m_dhcp_server_ip,
+                    ~0,
+                    Adapter->m_dhcp_server_mac)
+                    )
+            {
+                goto no_queue;
+            }
+        }
+
+        // DHCP packet?
+        else if (packetLength >= sizeof (ETH_HEADER) + sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP)
+            && eth->proto == htons (NDIS_ETH_TYPE_IPV4)
+            && ip->version_len == 0x45 // IPv4, 20 byte header
+            && ip->protocol == IPPROTO_UDP
+            && udp->dest == htons (BOOTPS_PORT)
+            )
+        {
+            const DHCP *dhcp = (DHCP *) (tapPacket->m_Data
+                + sizeof (ETH_HEADER)
+                + sizeof (IPHDR)
+                + sizeof (UDPHDR));
+
+            const int optlen = packetLength
+                - sizeof (ETH_HEADER)
+                - sizeof (IPHDR)
+                - sizeof (UDPHDR)
+                - sizeof (DHCP);
+
+            if (optlen > 0) // we must have at least one DHCP option
+            {
+                if (ProcessDHCP (Adapter, eth, ip, udp, dhcp, optlen))
+                {
+                    goto no_queue;
+                }
+            }
+            else
+            {
+                goto no_queue;
+            }
+        }
+    }
+
+    //===============================================
+    // In Point-To-Point mode, check to see whether
+    // packet is ARP (handled) or IPv4 (sent to app).
+    // IPv6 packets are inspected for neighbour discovery
+    // (to be handled locally), and the rest is forwarded
+    // all other protocols are dropped
+    //===============================================
+    if (Adapter->m_tun)
+    {
+        ETH_HEADER *e;
+
+        e = (ETH_HEADER *) tapPacket->m_Data;
+
+        switch (ntohs (e->proto))
+        {
+        case NDIS_ETH_TYPE_ARP:
+
+            // Make sure that packet is the right size for ARP.
+            if (packetLength != sizeof (ARP_PACKET))
+            {
+                goto no_queue;
+            }
+
+            ProcessARP (
+                Adapter,
+                (PARP_PACKET) tapPacket->m_Data,
+                Adapter->m_localIP,
+                Adapter->m_remoteNetwork,
+                Adapter->m_remoteNetmask,
+                Adapter->m_TapToUser.dest
+                );
+
+        default:
+            goto no_queue;
+
+        case NDIS_ETH_TYPE_IPV4:
+
+            // Make sure that packet is large enough to be IPv4.
+            if (packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE))
+            {
+                goto no_queue;
+            }
+
+            // Only accept directed packets, not broadcasts.
+            if (memcmp (e, &Adapter->m_TapToUser, ETHERNET_HEADER_SIZE))
+            {
+                goto no_queue;
+            }
+
+            // Packet looks like IPv4, queue it. :-)
+            tapPacket->m_SizeFlags |= TP_TUN;
+            break;
+
+        case NDIS_ETH_TYPE_IPV6:
+            // Make sure that packet is large enough to be IPv6.
+            if (packetLength < (ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE))
+            {
+                goto no_queue;
+            }
+
+            // Broadcasts and multicasts are handled specially
+            // (to be implemented)
+
+            // Neighbor discovery packets to fe80::8 are special
+            // OpenVPN sets this next-hop to signal "handled by tapdrv"
+            if ( HandleIPv6NeighborDiscovery(Adapter,tapPacket->m_Data) )
+            {
+                goto no_queue;
+            }
+
+            // Packet looks like IPv6, queue it. :-)
+            tapPacket->m_SizeFlags |= TP_TUN;
+        }
+    }
+
+    //===============================================
+    // Push packet onto queue to wait for read from
+    // userspace.
+    //===============================================
+    if(tapAdapterReadAndWriteReady(Adapter))
+    {
+        tapPacketQueueInsertTail(&Adapter->SendPacketQueue,tapPacket);
+    }
+    else
+    {
+        //
+        // Tragedy. All this work and the packet is of no use... 
+        //
+        NdisFreeMemory(tapPacket,0,0);
+    }
+
+    // Return after queuing or freeing TAP packet.
+    return;
+
+    // Free TAP packet without queuing.
+no_queue:
+    if(tapPacket != NULL )
+    {
+        NdisFreeMemory(tapPacket,0,0);
+    }
+  
+exit_success:
+    return;
+}
+
+VOID
+tapSendNetBufferListsComplete(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in PNET_BUFFER_LIST       NetBufferLists,
+    __in NDIS_STATUS            SendCompletionStatus,
+    __in BOOLEAN                DispatchLevel
+    )
+{
+    PNET_BUFFER_LIST    currentNbl;
+    PNET_BUFFER_LIST    nextNbl = NULL;
+    ULONG               sendCompleteFlags = 0;
+
+    for (
+        currentNbl = NetBufferLists;
+        currentNbl != NULL;
+        currentNbl = nextNbl
+        )
+    {
+        ULONG       frameType;
+        ULONG       netBufferCount;
+        ULONG       byteCount;
+
+        nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+
+        // Set NBL completion status.
+        NET_BUFFER_LIST_STATUS(currentNbl) = SendCompletionStatus;
+
+        // Fetch first NBs frame type. All linked NBs will have same type.
+        frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(currentNbl));
+
+        // Fetch statistics for all NBs linked to the NB.
+        netBufferCount = tapGetNetBufferCountsFromNetBufferList(
+                            currentNbl,
+                            &byteCount
+                            );
+
+        // Update statistics by frame type
+        if(SendCompletionStatus == NDIS_STATUS_SUCCESS)
+        {
+            switch(frameType)
+            {
+            case NDIS_PACKET_TYPE_DIRECTED:
+                Adapter->FramesTxDirected += netBufferCount;
+                Adapter->BytesTxDirected += byteCount;
+                break;
+
+            case NDIS_PACKET_TYPE_BROADCAST:
+                Adapter->FramesTxBroadcast += netBufferCount;
+                Adapter->BytesTxBroadcast += byteCount;
+                break;
+
+            case NDIS_PACKET_TYPE_MULTICAST:
+                Adapter->FramesTxMulticast += netBufferCount;
+                Adapter->BytesTxMulticast += byteCount;
+                break;
+
+            default:
+                ASSERT(FALSE);
+                break;
+            }
+        }
+        else
+        {
+            // Transmit error.
+            Adapter->TransmitFailuresOther += netBufferCount;
+        }
+
+        currentNbl = nextNbl;
+    }
+
+    if(DispatchLevel)
+    {
+        sendCompleteFlags |= NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL;
+    }
+
+    // Complete the NBLs
+    NdisMSendNetBufferListsComplete(
+        Adapter->MiniportAdapterHandle,
+        NetBufferLists,
+        sendCompleteFlags
+        );
+}
+
+BOOLEAN
+tapNetBufferListNetBufferLengthsValid(
+    __in PTAP_ADAPTER_CONTEXT   Adapter,
+    __in  PNET_BUFFER_LIST      NetBufferLists
+    )
+/*++
+
+Routine Description:
+
+    Scan all NBLs and their linked NBs for valid lengths.
+
+    Fairly absurd to find and packets with bogus lengths, but wise
+    to check anyway. If ANY packet has a bogus length, then abort the
+    entire send.
+
+    The only time that one might see this check fail might be during
+    HCK driver testing. The HKC test might send oversize packets to
+    determine if the miniport can gracefully deal with them.
+
+    This check is fairly fast. Unlike NDIS 5 packets, fetching NDIS 6
+    packets lengths do not require any computation.
+
+Arguments:
+
+    Adapter                 Pointer to our adapter context
+    NetBufferLists          Head of a list of NBLs to examine
+
+Return Value:
+
+    Returns TRUE if all NBs have reasonable lengths.
+    Otherwise, returns FALSE.
+
+--*/
+{
+    PNET_BUFFER_LIST        currentNbl;
+
+    currentNbl = NetBufferLists;
+
+    while (currentNbl)
+    {
+        PNET_BUFFER_LIST    nextNbl;
+        PNET_BUFFER         currentNb;
+
+        // Locate next NBL
+        nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+
+        // Locate first NB (aka "packet")
+        currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl);
+
+        //
+        // Process all NBs linked to this NBL
+        //
+        while(currentNb)
+        {
+            PNET_BUFFER nextNb;
+            ULONG       packetLength;
+
+            // Locate next NB
+            nextNb = NET_BUFFER_NEXT_NB(currentNb);
+
+            packetLength = NET_BUFFER_DATA_LENGTH(currentNb);
+
+            // Minimum packet size is size of Ethernet plus IPv4 headers.
+            ASSERT(packetLength >= (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE));
+
+            if(packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE))
+            {
+                return FALSE;
+            }
+
+            // Maximum size should be Ethernet header size plus MTU plus modest pad for
+            // VLAN tag.
+            ASSERT( packetLength <= (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize));
+
+            if(packetLength > (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize))
+            {
+                return FALSE;
+            }
+
+            // Move to next NB
+            currentNb = nextNb;
+        }
+
+        // Move to next NBL
+        currentNbl = nextNbl;
+    }
+
+    return TRUE;
+}
+
+VOID
+AdapterSendNetBufferLists(
+    __in  NDIS_HANDLE             MiniportAdapterContext,
+    __in  PNET_BUFFER_LIST        NetBufferLists,
+    __in  NDIS_PORT_NUMBER        PortNumber,
+    __in  ULONG                   SendFlags
+    )
+/*++
+
+Routine Description:
+
+    Send Packet Array handler. Called by NDIS whenever a protocol
+    bound to our miniport sends one or more packets.
+
+    The input packet descriptor pointers have been ordered according
+    to the order in which the packets should be sent over the network
+    by the protocol driver that set up the packet array. The NDIS
+    library preserves the protocol-determined ordering when it submits
+    each packet array to MiniportSendPackets
+
+    As a deserialized driver, we are responsible for holding incoming send
+    packets in our internal queue until they can be transmitted over the
+    network and for preserving the protocol-determined ordering of packet
+    descriptors incoming to its MiniportSendPackets function.
+    A deserialized miniport driver must complete each incoming send packet
+    with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable.
+
+    Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+    MiniportAdapterContext      Pointer to our adapter
+    NetBufferLists              Head of a list of NBLs to send
+    PortNumber                  A miniport adapter port.  Default is 0.
+    SendFlags                   Additional flags for the send operation
+
+Return Value:
+
+    None.  Write status directly into each NBL with the NET_BUFFER_LIST_STATUS
+    macro.
+
+--*/
+{
+    NDIS_STATUS             status;
+    PTAP_ADAPTER_CONTEXT    adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+    BOOLEAN                 DispatchLevel = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL);
+    PNET_BUFFER_LIST        currentNbl;
+    BOOLEAN                 validNbLengths;
+
+    UNREFERENCED_PARAMETER(NetBufferLists);
+    UNREFERENCED_PARAMETER(PortNumber);
+    UNREFERENCED_PARAMETER(SendFlags);
+
+    ASSERT(PortNumber == 0); // Only the default port is supported
+
+    //
+    // Can't process sends if TAP device is not open.
+    // ----------------------------------------------
+    // Just perform a "lying send" and return packets as if they
+    // were successfully sent.
+    //
+    if(adapter->TapFileObject == NULL)
+    {
+        //
+        // Complete all NBLs and return if adapter not ready.
+        //
+        tapSendNetBufferListsComplete(
+            adapter,
+            NetBufferLists,
+            NDIS_STATUS_SUCCESS,
+            DispatchLevel
+            );
+
+        return;
+    }
+
+    //
+    // Check Adapter send/receive ready state.
+    //
+    status = tapAdapterSendAndReceiveReady(adapter);
+
+    if(status != NDIS_STATUS_SUCCESS)
+    {
+        //
+        // Complete all NBLs and return if adapter not ready.
+        //
+        tapSendNetBufferListsComplete(
+            adapter,
+            NetBufferLists,
+            status,
+            DispatchLevel
+            );
+
+        return;
+    }
+
+    //
+    // Scan all NBLs and linked packets for valid lengths.
+    // ---------------------------------------------------
+    // If _ANY_ NB length is invalid, then fail the entire send operation.
+    //
+    //    BUGBUG!!! Perhaps this should be less agressive. Fail only individual
+    //    NBLs...
+    //    
+    // If length check is valid, then TAP_PACKETS can be safely allocated
+    // and processed for all NBs being sent.
+    //
+    validNbLengths = tapNetBufferListNetBufferLengthsValid(
+                        adapter,
+                        NetBufferLists
+                        );
+
+    if(!validNbLengths)
+    {
+        //
+        // Complete all NBLs and return if and NB length is invalid.
+        //
+        tapSendNetBufferListsComplete(
+            adapter,
+            NetBufferLists,
+            NDIS_STATUS_INVALID_LENGTH,
+            DispatchLevel
+            );
+
+        return;
+    }
+
+    //
+    // Process each NBL individually
+    //
+    currentNbl = NetBufferLists;
+
+    while (currentNbl)
+    {
+        PNET_BUFFER_LIST    nextNbl;
+        PNET_BUFFER         currentNb;
+
+        // Locate next NBL
+        nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+
+        // Locate first NB (aka "packet")
+        currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl);
+
+        // Transmit all NBs linked to this NBL
+        while(currentNb)
+        {
+            PNET_BUFFER nextNb;
+
+            // Locate next NB
+            nextNb = NET_BUFFER_NEXT_NB(currentNb);
+
+            // Transmit the NB
+            tapAdapterTransmit(adapter,currentNb,DispatchLevel);
+
+            // Move to next NB
+            currentNb = nextNb;
+        }
+
+        // Move to next NBL
+        currentNbl = nextNbl;
+    }
+
+    // Complete all NBLs
+    tapSendNetBufferListsComplete(
+        adapter,
+        NetBufferLists,
+        NDIS_STATUS_SUCCESS,
+        DispatchLevel
+        );
+
+    // Attempt to complete pending read IRPs from pending TAP 
+    // send packet queue.
+    tapProcessSendPacketQueue(adapter);
+}
+
+VOID
+AdapterCancelSend(
+    __in  NDIS_HANDLE             MiniportAdapterContext,
+    __in  PVOID                   CancelId
+    )
+{
+    PTAP_ADAPTER_CONTEXT   adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+    //
+    // This miniport completes its sends quickly, so it isn't strictly
+    // neccessary to implement MiniportCancelSend.
+    //
+    // If we did implement it, we'd have to walk the Adapter->SendWaitList
+    // and look for any NB that points to a NBL where the CancelId matches
+    // NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(Nbl).  For any NB that so matches,
+    // we'd remove the NB from the SendWaitList and set the NBL's status to
+    // NDIS_STATUS_SEND_ABORTED, then complete the NBL.
+    //
+}
+
+// IRP_MJ_READ callback.
+NTSTATUS
+TapDeviceRead(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp
+    )
+{
+    NTSTATUS                ntStatus = STATUS_SUCCESS;// Assume success
+    PIO_STACK_LOCATION      irpSp;// Pointer to current stack location
+    PTAP_ADAPTER_CONTEXT    adapter = NULL;
+
+    PAGED_CODE();
+
+    irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+    //
+    // Fetch adapter context for this device.
+    // --------------------------------------
+    // Adapter pointer was stashed in FsContext when handle was opened.
+    //
+    adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+    ASSERT(adapter);
+
+    //
+    // Sanity checks on state variables
+    //
+    if (!tapAdapterReadAndWriteReady(adapter))
+    {
+        //DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n",
+        //    MINIPORT_INSTANCE_ID (adapter)));
+        //NOTE_ERROR();
+
+        Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+        return ntStatus;
+    }
+
+    // Save IRP-accessible copy of buffer length
+    Irp->IoStatus.Information = irpSp->Parameters.Read.Length;
+
+    if (Irp->MdlAddress == NULL)
+    {
+        DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n",
+            MINIPORT_INSTANCE_ID (adapter)));
+
+        NOTE_ERROR();
+        Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+        return ntStatus;
+    }
+
+    if ((Irp->AssociatedIrp.SystemBuffer
+            = MmGetSystemAddressForMdlSafe(
+                Irp->MdlAddress,
+                NormalPagePriority
+                ) ) == NULL
+        )
+    {
+        DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n",
+            MINIPORT_INSTANCE_ID (adapter)));
+
+        NOTE_ERROR();
+        Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+        Irp->IoStatus.Information = 0;
+        IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+        return ntStatus;
+    }
+
+    // BUGBUG!!! Use RemoveLock???
+
+    //
+    // Queue the IRP and return STATUS_PENDING.
+    // ----------------------------------------
+    // Note: IoCsqInsertIrp marks the IRP pending.
+    //
+
+    // BUGBUG!!! NDIS 5 implementation has IRP_QUEUE_SIZE of 16 and 
+    // does not queue IRP if this capacity is exceeded.
+    //
+    // Is this needed???
+    //
+    IoCsqInsertIrp(&adapter->PendingReadIrpQueue.CsqQueue, Irp, NULL);
+
+    // Attempt to complete pending read IRPs from pending TAP 
+    // send packet queue.
+    tapProcessSendPacketQueue(adapter);
+
+    ntStatus = STATUS_PENDING;
+
+    return ntStatus;
+}
+

+ 90 - 0
windows/TapDriver6/types.h

@@ -0,0 +1,90 @@
+/*
+ *  TAP-Windows -- A kernel driver to provide virtual tap
+ *                 device functionality on Windows.
+ *
+ *  This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ *  This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ *  and is released under the GPL version 2 (see below).
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef TAP_TYPES_DEFINED
+#define TAP_TYPES_DEFINED
+
+//typedef
+//struct _Queue
+//{
+//    ULONG base;
+//    ULONG size;
+//    ULONG capacity;
+//    ULONG max_size;
+//    PVOID data[];
+//} Queue;
+
+//typedef struct _TAP_PACKET;
+
+//typedef struct _TapExtension
+//{
+//  // TAP device object and packet queues
+//  Queue *m_PacketQueue, *m_IrpQueue;
+//  PDEVICE_OBJECT m_TapDevice;
+//  NDIS_HANDLE m_TapDeviceHandle;
+//  ULONG TapFileIsOpen;
+//
+//  // Used to lock packet queues
+//  NDIS_SPIN_LOCK m_QueueLock;
+//  BOOLEAN m_AllocatedSpinlocks;
+//
+//  // Used to bracket open/close
+//  // state changes.
+//  MUTEX m_OpenCloseMutex;
+//
+//  // True if device has been permanently halted
+//  BOOLEAN m_Halt;
+//
+//  // TAP device name
+//  unsigned char *m_TapName;
+//  UNICODE_STRING m_UnicodeLinkName;
+//  BOOLEAN m_CreatedUnicodeLinkName;
+//
+//  // Used for device status ioctl only
+//  const char *m_LastErrorFilename;
+//  int m_LastErrorLineNumber;
+//  LONG TapFileOpenCount;
+//
+//  // Flags
+//  BOOLEAN TapDeviceCreated;
+//  BOOLEAN m_CalledTapDeviceFreeResources;
+//
+//  // DPC queue for deferred packet injection
+//  BOOLEAN m_InjectDpcInitialized;
+//  KDPC m_InjectDpc;
+//  NDIS_SPIN_LOCK m_InjectLock;
+//  Queue *m_InjectQueue;
+//}
+//TapExtension, *TapExtensionPointer;
+
+typedef struct _InjectPacket
+   {
+#   define INJECT_PACKET_SIZE(data_size) (sizeof (InjectPacket) + (data_size))
+#   define INJECT_PACKET_FREE(ib)  NdisFreeMemory ((ib), INJECT_PACKET_SIZE ((ib)->m_Size), 0)
+    ULONG m_Size;
+    UCHAR m_Data []; // m_Data must be the last struct member
+   }
+InjectPacket, *InjectPacketPointer;
+
+#endif

+ 145 - 0
windows/ZeroTierOne.sln

@@ -5,6 +5,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver", "TapDriver\TapD
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroTierOne", "ZeroTierOne\ZeroTierOne.vcxproj", "{B00A4957-5977-4AC1-9EF4-571DC27EADA2}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver6", "TapDriver6\TapDriver6.vcxproj", "{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		CD_ROM|Any CPU = CD_ROM|Any CPU
@@ -295,6 +297,149 @@ Global
 		{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.ActiveCfg = Release|Win32
 		{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.Build.0 = Release|Win32
 		{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.Deploy.0 = Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Any CPU.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.ActiveCfg = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.Build.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.Deploy.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Any CPU.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.Build.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.Deploy.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.Build.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.Deploy.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.ActiveCfg = Win7 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.Build.0 = Win7 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.Deploy.0 = Win7 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.Build.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.Deploy.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Any CPU.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.ActiveCfg = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.Build.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.Deploy.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Any CPU.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.ActiveCfg = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.Build.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.Deploy.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Any CPU.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.ActiveCfg = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.Build.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.Deploy.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Any CPU.ActiveCfg = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.ActiveCfg = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.Build.0 = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.Deploy.0 = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.ActiveCfg = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.Build.0 = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.Deploy.0 = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.ActiveCfg = Vista Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.Build.0 = Vista Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.Deploy.0 = Vista Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.ActiveCfg = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.Build.0 = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.Deploy.0 = Vista Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Any CPU.ActiveCfg = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.ActiveCfg = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.Build.0 = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.Deploy.0 = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.ActiveCfg = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.Build.0 = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.Deploy.0 = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.ActiveCfg = Vista Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.Build.0 = Vista Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.Deploy.0 = Vista Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.ActiveCfg = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.Build.0 = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.Deploy.0 = Vista Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Any CPU.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.Build.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.Deploy.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.Build.0 = Win7 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.Deploy.0 = Win7 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.ActiveCfg = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.Build.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.Deploy.0 = Win7 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Any CPU.ActiveCfg = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.ActiveCfg = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.Build.0 = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.Deploy.0 = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.ActiveCfg = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.Build.0 = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.Deploy.0 = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.ActiveCfg = Win7 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.Build.0 = Win7 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.Deploy.0 = Win7 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.ActiveCfg = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.Build.0 = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.Deploy.0 = Win7 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Any CPU.ActiveCfg = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.ActiveCfg = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.Build.0 = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.Deploy.0 = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.Build.0 = Win8 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.ActiveCfg = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.Build.0 = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.Deploy.0 = Win8 Debug|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Any CPU.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.ActiveCfg = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.Build.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.Deploy.0 = Win8 Release|x64
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.ActiveCfg = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Build.0 = Win8 Release|Win32
+		{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Deploy.0 = Win8 Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE