summaryrefslogtreecommitdiff
path: root/windows
diff options
context:
space:
mode:
Diffstat (limited to 'windows')
-rw-r--r--windows/TapDriver6/TapDriver6.vcxproj249
-rw-r--r--windows/TapDriver6/TapDriver6.vcxproj.filters108
-rw-r--r--windows/TapDriver6/adapter.c1716
-rw-r--r--windows/TapDriver6/adapter.h348
-rw-r--r--windows/TapDriver6/config.h20
-rw-r--r--windows/TapDriver6/constants.h195
-rw-r--r--windows/TapDriver6/device.c1169
-rw-r--r--windows/TapDriver6/device.h50
-rw-r--r--windows/TapDriver6/dhcp.c710
-rw-r--r--windows/TapDriver6/dhcp.h165
-rw-r--r--windows/TapDriver6/endian.h35
-rw-r--r--windows/TapDriver6/error.c398
-rw-r--r--windows/TapDriver6/error.h114
-rw-r--r--windows/TapDriver6/hexdump.h63
-rw-r--r--windows/TapDriver6/lock.h75
-rw-r--r--windows/TapDriver6/macinfo.c164
-rw-r--r--windows/TapDriver6/macinfo.h53
-rw-r--r--windows/TapDriver6/mem.c401
-rw-r--r--windows/TapDriver6/mem.h113
-rw-r--r--windows/TapDriver6/oidrequest.c1028
-rw-r--r--windows/TapDriver6/proto.h224
-rw-r--r--windows/TapDriver6/prototypes.h87
-rw-r--r--windows/TapDriver6/resource.apsbin0 -> 77588 bytes
-rw-r--r--windows/TapDriver6/resource.rc62
-rw-r--r--windows/TapDriver6/rxpath.c667
-rw-r--r--windows/TapDriver6/tap-windows.h74
-rw-r--r--windows/TapDriver6/tap.h90
-rw-r--r--windows/TapDriver6/tapdrvr.c232
-rw-r--r--windows/TapDriver6/txpath.c1168
-rw-r--r--windows/TapDriver6/types.h90
-rw-r--r--windows/ZeroTierOne.sln145
31 files changed, 10013 insertions, 0 deletions
diff --git a/windows/TapDriver6/TapDriver6.vcxproj b/windows/TapDriver6/TapDriver6.vcxproj
new file mode 100644
index 00000000..280354ec
--- /dev/null
+++ b/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> \ No newline at end of file
diff --git a/windows/TapDriver6/TapDriver6.vcxproj.filters b/windows/TapDriver6/TapDriver6.vcxproj.filters
new file mode 100644
index 00000000..9839a59c
--- /dev/null
+++ b/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> \ No newline at end of file
diff --git a/windows/TapDriver6/adapter.c b/windows/TapDriver6/adapter.c
new file mode 100644
index 00000000..7ce4b310
--- /dev/null
+++ b/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);
+ }
+}
+
+
diff --git a/windows/TapDriver6/adapter.h b/windows/TapDriver6/adapter.h
new file mode 100644
index 00000000..4f267ec0
--- /dev/null
+++ b/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_ \ No newline at end of file
diff --git a/windows/TapDriver6/config.h b/windows/TapDriver6/config.h
new file mode 100644
index 00000000..37e26a92
--- /dev/null
+++ b/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"
diff --git a/windows/TapDriver6/constants.h b/windows/TapDriver6/constants.h
new file mode 100644
index 00000000..31b2d545
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/device.c b/windows/TapDriver6/device.c
new file mode 100644
index 00000000..2b7ba9b1
--- /dev/null
+++ b/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"));
+}
+
diff --git a/windows/TapDriver6/device.h b/windows/TapDriver6/device.h
new file mode 100644
index 00000000..93dae0d9
--- /dev/null
+++ b/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_ \ No newline at end of file
diff --git a/windows/TapDriver6/dhcp.c b/windows/TapDriver6/dhcp.c
new file mode 100644
index 00000000..30b22f4f
--- /dev/null
+++ b/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 */
diff --git a/windows/TapDriver6/dhcp.h b/windows/TapDriver6/dhcp.h
new file mode 100644
index 00000000..b594a5e9
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/endian.h b/windows/TapDriver6/endian.h
new file mode 100644
index 00000000..b7d34499
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/error.c b/windows/TapDriver6/error.c
new file mode 100644
index 00000000..1fad1d3a
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/error.h b/windows/TapDriver6/error.h
new file mode 100644
index 00000000..2ba39cc1
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/hexdump.h b/windows/TapDriver6/hexdump.h
new file mode 100644
index 00000000..d6275c18
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/lock.h b/windows/TapDriver6/lock.h
new file mode 100644
index 00000000..c80b164c
--- /dev/null
+++ b/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; \
+ } \
+ } \
+}
diff --git a/windows/TapDriver6/macinfo.c b/windows/TapDriver6/macinfo.c
new file mode 100644
index 00000000..dfd0a075
--- /dev/null
+++ b/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;
+}
diff --git a/windows/TapDriver6/macinfo.h b/windows/TapDriver6/macinfo.h
new file mode 100644
index 00000000..dd88b6f8
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/mem.c b/windows/TapDriver6/mem.c
new file mode 100644
index 00000000..ae2e3d40
--- /dev/null
+++ b/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));
+}
diff --git a/windows/TapDriver6/mem.h b/windows/TapDriver6/mem.h
new file mode 100644
index 00000000..a8359e19
--- /dev/null
+++ b/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
+ );
diff --git a/windows/TapDriver6/oidrequest.c b/windows/TapDriver6/oidrequest.c
new file mode 100644
index 00000000..a6882f89
--- /dev/null
+++ b/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.
+ //
+}
+
diff --git a/windows/TapDriver6/proto.h b/windows/TapDriver6/proto.h
new file mode 100644
index 00000000..cc23de6d
--- /dev/null
+++ b/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()
diff --git a/windows/TapDriver6/prototypes.h b/windows/TapDriver6/prototypes.h
new file mode 100644
index 00000000..ad70261d
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/resource.aps b/windows/TapDriver6/resource.aps
new file mode 100644
index 00000000..1552712d
--- /dev/null
+++ b/windows/TapDriver6/resource.aps
Binary files differ
diff --git a/windows/TapDriver6/resource.rc b/windows/TapDriver6/resource.rc
new file mode 100644
index 00000000..fbe27758
--- /dev/null
+++ b/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"
diff --git a/windows/TapDriver6/rxpath.c b/windows/TapDriver6/rxpath.c
new file mode 100644
index 00000000..7415b5e4
--- /dev/null
+++ b/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;
+}
+
diff --git a/windows/TapDriver6/tap-windows.h b/windows/TapDriver6/tap-windows.h
new file mode 100644
index 00000000..d546a5b1
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/tap.h b/windows/TapDriver6/tap.h
new file mode 100644
index 00000000..61a97850
--- /dev/null
+++ b/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
diff --git a/windows/TapDriver6/tapdrvr.c b/windows/TapDriver6/tapdrvr.c
new file mode 100644
index 00000000..6c537f1d
--- /dev/null
+++ b/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"));
+}
+
diff --git a/windows/TapDriver6/txpath.c b/windows/TapDriver6/txpath.c
new file mode 100644
index 00000000..6e084dfc
--- /dev/null
+++ b/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;
+}
+
diff --git a/windows/TapDriver6/types.h b/windows/TapDriver6/types.h
new file mode 100644
index 00000000..acea175c
--- /dev/null
+++ b/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
diff --git a/windows/ZeroTierOne.sln b/windows/ZeroTierOne.sln
index 09a0874b..3aebacb5 100644
--- a/windows/ZeroTierOne.sln
+++ b/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