summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-08-15 15:52:52 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-08-15 15:52:52 -0400
commitd7bd3e37cbf63b3862f3e001c94c5f23e965a7b5 (patch)
tree8b148fe3c676892373cbab22146a86a815677d67
parentb23748aa5a10a61b1dd5f5598c7577c8c2142aaf (diff)
downloadinfinitytier-d7bd3e37cbf63b3862f3e001c94c5f23e965a7b5.tar.gz
infinitytier-d7bd3e37cbf63b3862f3e001c94c5f23e965a7b5.zip
Add a fork of tap-windows from OpenVPN, will be customized.
-rw-r--r--windows-tap/COPYING40
-rw-r--r--windows-tap/COPYRIGHT.GPL339
-rw-r--r--windows-tap/_build.bat49
-rw-r--r--windows-tap/build.bat55
-rw-r--r--windows-tap/build/MSCV-VSClass3.cer32
-rw-r--r--windows-tap/build/msvc-generate.js118
-rw-r--r--windows-tap/build/unix2dos.js54
-rw-r--r--windows-tap/build/vars.amd64.m42
-rw-r--r--windows-tap/build/vars.i386.m42
-rw-r--r--windows-tap/build/zip.js74
-rw-r--r--windows-tap/config-env.bat.in15
-rw-r--r--windows-tap/configure.bat94
-rw-r--r--windows-tap/installer/build.bat95
-rwxr-xr-xwindows-tap/installer/icon.icobin0 -> 22486 bytes
-rwxr-xr-xwindows-tap/installer/install-whirl.bmpbin0 -> 25820 bytes
-rwxr-xr-xwindows-tap/installer/tap-windows.nsi317
-rwxr-xr-xwindows-tap/src/MAKEFILE6
-rwxr-xr-xwindows-tap/src/OemWin2k.inf.in187
-rwxr-xr-xwindows-tap/src/SOURCES.in65
-rw-r--r--windows-tap/src/config.h.in9
-rwxr-xr-xwindows-tap/src/constants.h52
-rwxr-xr-xwindows-tap/src/dhcp.c599
-rwxr-xr-xwindows-tap/src/dhcp.h164
-rwxr-xr-xwindows-tap/src/endian.h35
-rwxr-xr-xwindows-tap/src/error.c385
-rwxr-xr-xwindows-tap/src/error.h88
-rwxr-xr-xwindows-tap/src/hexdump.c69
-rwxr-xr-xwindows-tap/src/hexdump.h63
-rwxr-xr-xwindows-tap/src/instance.c241
-rwxr-xr-xwindows-tap/src/lock.h75
-rwxr-xr-xwindows-tap/src/macinfo.c154
-rwxr-xr-xwindows-tap/src/macinfo.h38
-rwxr-xr-xwindows-tap/src/mem.c186
-rwxr-xr-xwindows-tap/src/proto.h224
-rwxr-xr-xwindows-tap/src/prototypes.h260
-rwxr-xr-xwindows-tap/src/resource.rc62
-rwxr-xr-xwindows-tap/src/tap-windows.h74
-rwxr-xr-xwindows-tap/src/tapdrvr.c3147
-rwxr-xr-xwindows-tap/src/types.h178
-rw-r--r--windows-tap/version.m411
40 files changed, 7658 insertions, 0 deletions
diff --git a/windows-tap/COPYING b/windows-tap/COPYING
new file mode 100644
index 00000000..5686795f
--- /dev/null
+++ b/windows-tap/COPYING
@@ -0,0 +1,40 @@
+TAP-Win32/TAP-Win64 Driver license:
+-----------------------------------
+
+ This device driver was inspired by the CIPE-Win32 driver by
+ Damion K. Wilson.
+
+ The source and object code of the TAP-Win32/TAP-Win64 driver
+ is Copyright (C) 2002-2010 OpenVPN Technologies, Inc., and is released under
+ the GPL version 2.
+
+NSIS License:
+-------------
+
+ Copyright (C) 2002-2003 Joost Verburg
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute
+ it freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented;
+ you must not claim that you wrote the original software.
+ If you use this software in a product, an acknowledgment in the
+ product documentation would be appreciated but is not required.
+ 2. Altered versions must be plainly marked as such,
+ and must not be misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any distribution.
+
+GNU Public License (GPL)
+------------------------
+
+ TAP-Win32 distributions are licensed under the GPL version 2 (see
+ COPYRIGHT.GPL).
+
+ In the Windows binary distribution of OpenVPN, the
+ GPL is reproduced below.
+
diff --git a/windows-tap/COPYRIGHT.GPL b/windows-tap/COPYRIGHT.GPL
new file mode 100644
index 00000000..ff8a7f00
--- /dev/null
+++ b/windows-tap/COPYRIGHT.GPL
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/windows-tap/_build.bat b/windows-tap/_build.bat
new file mode 100644
index 00000000..718feb23
--- /dev/null
+++ b/windows-tap/_build.bat
@@ -0,0 +1,49 @@
+@echo off
+rem TAP-Windows -- A kernel driver to provide virtual tap
+rem device functionality on Windows.
+rem
+rem Copyright (C) 2012 Alon Bar-Lev <alon.barlev@gmail.com>
+rem
+rem This program is free software; you can redistribute it and/or modify
+rem it under the terms of the GNU General Public License as published by
+rem the Free Software Foundation; either version 2 of the License, or
+rem (at your option) any later version.
+rem
+rem This program is distributed in the hope that it will be useful,
+rem but WITHOUT ANY WARRANTY; without even the implied warranty of
+rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+rem GNU General Public License for more details.
+rem
+rem You should have received a copy of the GNU General Public License
+rem along with this program (see the file COPYING included with this
+rem distribution); if not, write to the Free Software Foundation, Inc.,
+rem 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+setlocal enableextensions enabledelayedexpansion
+
+set root=%cd%
+set myos=%1
+set myprofile=%2
+set mymode=fre
+
+echo Building %myos%-%myprofile%-%mymode%
+
+call "%DDK%\bin\setenv" %DDK% %mymode% %myprofile% %myos% no_oacr
+if errorlevel 1 goto error
+
+cd /d %root%
+cd src
+nmake
+if errorlevel 1 goto error
+
+set rc=0
+goto end
+
+:error
+echo FAIL %myos%-%myprofile%-%mymode%
+set rc=1
+goto end
+
+:end
+
+endlocal
diff --git a/windows-tap/build.bat b/windows-tap/build.bat
new file mode 100644
index 00000000..925975a1
--- /dev/null
+++ b/windows-tap/build.bat
@@ -0,0 +1,55 @@
+@echo off
+rem TAP-Windows -- A kernel driver to provide virtual tap
+rem device functionality on Windows.
+rem
+rem Copyright (C) 2012 Alon Bar-Lev <alon.barlev@gmail.com>
+rem
+rem This program is free software; you can redistribute it and/or modify
+rem it under the terms of the GNU General Public License as published by
+rem the Free Software Foundation; either version 2 of the License, or
+rem (at your option) any later version.
+rem
+rem This program is distributed in the hope that it will be useful,
+rem but WITHOUT ANY WARRANTY; without even the implied warranty of
+rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+rem GNU General Public License for more details.
+rem
+rem You should have received a copy of the GNU General Public License
+rem along with this program (see the file COPYING included with this
+rem distribution); if not, write to the Free Software Foundation, Inc.,
+rem 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+cd /d %0\..
+
+if not exist config-env.bat (
+ echo please run configure
+ exit /b 1
+)
+
+setlocal
+
+call config-env.bat
+
+for /d %%d in (src\obj*) do rmdir /q /s %%d > nul 2>&1
+for %%f in (src\amd64\*.sys src\i386\*.sys) do del /s %%f > nul 2>&1
+
+cmd /c _build WXP x86
+if errorlevel 1 goto error
+cmd /c _build WIN7 x64
+if errorlevel 1 goto error
+
+call installer\build
+
+set rc=0
+goto end
+
+:error
+echo FAIL
+set rc=1
+goto end
+
+:end
+
+endlocal
+
+exit /b %rc%
diff --git a/windows-tap/build/MSCV-VSClass3.cer b/windows-tap/build/MSCV-VSClass3.cer
new file mode 100644
index 00000000..af1b6162
--- /dev/null
+++ b/windows-tap/build/MSCV-VSClass3.cer
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFmjCCA4KgAwIBAgIKYRmT5AAAAAAAHDANBgkqhkiG9w0BAQUFADB/MQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
+MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQDEyBNaWNyb3Nv
+ZnQgQ29kZSBWZXJpZmljYXRpb24gUm9vdDAeFw0xMTAyMjIxOTI1MTdaFw0yMTAy
+MjIxOTM1MTdaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIElu
+Yy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShj
+KSAyMDA2IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkx
+RTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgLSBHNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAK8kCAgpejWeYAyq50s7Ttx8vDxFHLsr4P4pAvlXCKNkhRUn9fGtyDGJ
+XSLoKqqmQrOP+LlVt7G3S7P+j34HV+zvQ9tmYhVhz2ANpNje+ODDYgg9VBPrScpZ
+VIUm5SuPG5/r9aGRwjNJ2ENjalJL0o/ocFFN0Ylpe8dw9rPcEnTbe11LVtOWvxV3
+obD0oiXyrxySZxjl9AYE75C55ADk3Tq1Gf8CuvQ87uCL6zeL7PTXrPL28D2v3XWR
+MxkdHEDLdCQZIZPZFP6sKlLHj9UESeSNY0eIPGmDy/5HvSt+T8WVrg6d1NFDwGdz
+4xQIfuU/n3O4MwrPXT80h5aK7lPoJRUCAwEAAaOByzCByDARBgNVHSAECjAIMAYG
+BFUdIAAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAYYwHQYDVR0OBBYEFH/T
+ZafC3ey78DAJ80M5+gKvMzEzMB8GA1UdIwQYMBaAFGL7CiFbf0NuEdoJVFBr9dKW
+cfGeMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9w
+a2kvY3JsL3Byb2R1Y3RzL01pY3Jvc29mdENvZGVWZXJpZlJvb3QuY3JsMA0GCSqG
+SIb3DQEBBQUAA4ICAQCBKoIWjDRnK+UD6zR7jKKjUIr0VYbxHoyOrn3uAxnOcpUY
+SK1iEf0g/T9HBgFa4uBvjBUsTjxqUGwLNqPPeg2cQrxc+BnVYONp5uIjQWeMaIN2
+K4+Toyq1f75Z+6nJsiaPyqLzghuYPpGVJ5eGYe5bXQdrzYao4mWAqOIV4rK+IwVq
+ugzzR5NNrKSMB3k5wGESOgUNiaPsn1eJhPvsynxHZhSR2LYPGV3muEqsvEfIcUOW
+5jIgpdx3hv0844tx23ubA/y3HTJk6xZSoEOj+i6tWZJOfMfyM0JIOFE6fDjHGyQi
+KEAeGkYfF9sY9/AnNWy4Y9nNuWRdK6Ve78YptPLH+CHMBLpX/QG2q8Zn+efTmX/0
+9SL6cvX9/zocQjqh+YAYpe6NHNRmnkUB/qru//sXjzD38c0pxZ3stdVJAD2FuMu7
+kzonaknAMK5myfcjKDJ2+aSDVshIzlqWqqDMDMR/tI6Xr23jVCfDn4bA1uRzCJcF
+29BUYl4DSMLVn3+nZozQnbBP1NOYX0t6yX+yKVLQEoDHD1S2HmfNxqBsEQOE00h1
+5yr+sDtuCjqma3aZBaPxd2hhMxRHBvxTf1K9khRcSiRqZ4yvjZCq0PZ5IRuTJnzD
+zh69iDiSrkXGGWpJULMF+K5ZN4pqJQOUsVmBUOi6g4C3IzX0drlnHVkYrSCNlA==
+-----END CERTIFICATE-----
diff --git a/windows-tap/build/msvc-generate.js b/windows-tap/build/msvc-generate.js
new file mode 100644
index 00000000..d9564cfd
--- /dev/null
+++ b/windows-tap/build/msvc-generate.js
@@ -0,0 +1,118 @@
+/*
+ * msvc-generate.js - string transformation
+ *
+ * Copyright (C) 2008-2012 Alon Bar-Lev <alon.barlev@gmail.com>
+ *
+ * BSD License
+ * ============
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * o Neither the name of the Alon Bar-Lev nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+var ForReading = 1;
+var fso = new ActiveXObject("Scripting.FileSystemObject");
+var input = "nul";
+var output = "nul";
+var files = new Array();
+var env = new Array();
+
+function initialize() {
+ for (var i=0;i<WScript.Arguments.length;i++) {
+ var arg = WScript.Arguments(i);
+ if (arg.match(/^--input=(.*)$/)) {
+ input=RegExp.$1;
+ }
+ else if (arg.match(/^--output=(.*)$/)) {
+ output=RegExp.$1;
+ }
+ else if (arg.match(/^--config=(.*)$/)) {
+ files.push(RegExp.$1);
+ }
+ else if (arg.match(/^--var=([^=]*)=(.*)$/)) {
+ env[RegExp.$1] = RegExp.$2;
+ }
+ }
+}
+
+function process_config(vars, file) {
+ try {
+ var fin = fso.OpenTextFile(file, ForReading);
+
+ while (!fin.AtEndOfStream) {
+ var content = fin.ReadLine();
+ if (content.match(/^[ \t]*define\(\[(.*)\],[ \t]*\[(.*)\]\)[ \t]*/)) {
+ vars[RegExp.$1] = RegExp.$2;
+ }
+ }
+ }
+ catch(e) {
+ throw new Error(1, "Cannot process '" + file + "'.");
+ }
+}
+
+function process_file(vars, input, output) {
+ var fin = fso.OpenTextFile(input, ForReading);
+ var fout = fso.CreateTextFile(output);
+ var content = fin.ReadAll();
+
+ for (var i in vars) {
+ content = content.replace(new RegExp("@"+i+"@", "g"), vars[i]);
+ }
+
+ fout.Write(content);
+}
+
+function build_vars() {
+ var vars = new Array();
+ for (var f in files) {
+ process_config(vars, files[f]);
+ }
+ for (var e in env) {
+ vars[e] = env[e];
+ }
+ return vars;
+}
+
+function main() {
+ try {
+ initialize();
+
+ var vars = build_vars();
+
+ process_file(
+ vars,
+ input,
+ output
+ );
+
+ WScript.Quit(0);
+ }
+ catch(e) {
+ WScript.Echo("ERROR: when procssing " + output + ": " + e.description);
+ WScript.Quit(1);
+ }
+}
+
+main();
diff --git a/windows-tap/build/unix2dos.js b/windows-tap/build/unix2dos.js
new file mode 100644
index 00000000..51ee7c99
--- /dev/null
+++ b/windows-tap/build/unix2dos.js
@@ -0,0 +1,54 @@
+/*
+ * unix2dos.js - a simple unix2dos implementation in jscript.
+ *
+ * Copyright (C) 2008-2012 Alon Bar-Lev <alon.barlev@gmail.com>
+ *
+ * BSD License
+ * ============
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * o Neither the name of the Alon Bar-Lev nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+var ForReading = 1;
+
+try {
+ var fso = new ActiveXObject("Scripting.FileSystemObject");
+ for (var i=0;i<WScript.Arguments.length;i++) {
+ var file = WScript.Arguments(i);
+ var tmp = file+".tmp";
+ var fin = fso.OpenTextFile(file, ForReading);
+ var fout = fso.CreateTextFile(tmp);
+ fout.Write(fin.ReadAll().replace(/\n/g, "\r\n"));
+ fin.Close();
+ fout.Close();
+ fso.DeleteFile(file);
+ fso.MoveFile(tmp, file);
+ }
+ WScript.Quit(0);
+}
+catch(e) {
+ WScript.Echo("ERROR: " + e.description);
+ WScript.Quit(1);
+}
diff --git a/windows-tap/build/vars.amd64.m4 b/windows-tap/build/vars.amd64.m4
new file mode 100644
index 00000000..26132501
--- /dev/null
+++ b/windows-tap/build/vars.amd64.m4
@@ -0,0 +1,2 @@
+define([INF_PROVIDER_SUFFIX], [, NTamd64])
+define([INF_SECTION_SUFFIX], [.NTamd64])
diff --git a/windows-tap/build/vars.i386.m4 b/windows-tap/build/vars.i386.m4
new file mode 100644
index 00000000..9bd4d316
--- /dev/null
+++ b/windows-tap/build/vars.i386.m4
@@ -0,0 +1,2 @@
+define([INF_PROVIDER_SUFFIX], [])
+define([INF_SECTION_SUFFIX], [])
diff --git a/windows-tap/build/zip.js b/windows-tap/build/zip.js
new file mode 100644
index 00000000..6550d8a7
--- /dev/null
+++ b/windows-tap/build/zip.js
@@ -0,0 +1,74 @@
+/*
+ * zip.js - a simple zip implementation in jscript.
+ *
+ * Copyright (C) 2008-2012 Alon Bar-Lev <alon.barlev@gmail.com>
+ *
+ * BSD License
+ * ============
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * o Neither the name of the Alon Bar-Lev nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+var ForReading = 0;
+var ForWriting = 1;
+var fso = new ActiveXObject("Scripting.FileSystemObject");
+
+function zip(source, destination) {
+ try {
+ var f = OpenTextFile(destination, ForReading);
+ f.Close();
+ }
+ catch(e) {
+ var f = fso.CreateTextFile(destination, ForWriting);
+ var zipheader = "PK" + String.fromCharCode(5) + String.fromCharCode(6);
+ for (var i=0;i<18;i++) {
+ zipheader += String.fromCharCode(0);
+ }
+ f.Write(zipheader);
+ f.Close();
+ }
+
+ var shell = new ActiveXObject("Shell.Application");
+ var source = shell.NameSpace(fso.GetAbsolutePathName(source));
+ var destination = shell.NameSpace(fso.GetAbsolutePathName(destination));
+
+ destination.CopyHere(source.Items(), 4);
+ while(source.Items().Count != destination.Items().Count) {
+ WScript.Sleep(1000);
+ }
+}
+
+var index = 0;
+var source = WScript.Arguments(index++);
+var destination = WScript.Arguments(index++);
+try {
+ zip(source, destination);
+ WScript.Quit(0);
+}
+catch(e) {
+ WScript.Echo("ERROR: Cannot zip '" + destination + "'.");
+ WScript.Quit(1);
+}
+
diff --git a/windows-tap/config-env.bat.in b/windows-tap/config-env.bat.in
new file mode 100644
index 00000000..49f60668
--- /dev/null
+++ b/windows-tap/config-env.bat.in
@@ -0,0 +1,15 @@
+set DDK=@DDK@
+set DEVCON32=@DEVCON32@
+set DEVCON64=@DEVCON64@
+set DEVCON_BASENAME=@DEVCON_BASENAME@
+set SIGNTOOL=@SIGNTOOL@
+set MAKENSIS=@MAKENSIS@
+set CODESIGN_PKCS12=@CODESIGN_PKCS12@
+set CODESIGN_PASS=@CODESIGN_PASS@
+set CODESIGN_CROSS=@CODESIGN_CROSS@
+set CODESIGN_TIMESTAMP=@CODESIGN_TIMESTAMP@
+set CODESIGN_ISTEST=@CODESIGN_ISTEST@
+set PRODUCT_TAP_WIN_COMPONENT_ID=@PRODUCT_TAP_WIN_COMPONENT_ID@
+set PRODUCT_NAME=@PRODUCT_NAME@
+set PRODUCT_VERSION=@PRODUCT_VERSION@
+set OUTDIR=@OUTDIR@
diff --git a/windows-tap/configure.bat b/windows-tap/configure.bat
new file mode 100644
index 00000000..a5da0cc0
--- /dev/null
+++ b/windows-tap/configure.bat
@@ -0,0 +1,94 @@
+@echo off
+rem TAP-Windows -- A kernel driver to provide virtual tap
+rem device functionality on Windows.
+rem
+rem Copyright (C) 2012 Alon Bar-Lev <alon.barlev@gmail.com>
+rem
+rem This program is free software; you can redistribute it and/or modify
+rem it under the terms of the GNU General Public License as published by
+rem the Free Software Foundation; either version 2 of the License, or
+rem (at your option) any later version.
+rem
+rem This program is distributed in the hope that it will be useful,
+rem but WITHOUT ANY WARRANTY; without even the implied warranty of
+rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+rem GNU General Public License for more details.
+rem
+rem You should have received a copy of the GNU General Public License
+rem along with this program (see the file COPYING included with this
+rem distribution); if not, write to the Free Software Foundation, Inc.,
+rem 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+cd /d %0\..
+
+if "%1"=="--help" (
+ echo %0
+ echo Environment:
+ echo DDK DDK home
+ echo SIGNTOOL signtool, default from DDK
+ echo DEVCON32 devcon, default from DDK
+ echo DEVCON64 devcon, default from DDK
+ echo MAKENSIS nullsoft installer
+ echo CODESIGN_PKCS12 Code sign PKCS#12 optional
+ echo CODESIGN_PASS Code sign password
+ echo CODESIGN_CROSS Cross certificate to be used
+ echo CODESIGN_TIMESTAMP Timestamp URL
+ echo CODESIGN_ISTEST If yes, use test certificate
+ echo OUTDIR Output directory
+ exit /b 1
+)
+
+setlocal
+
+if "%DDK%"=="" for /d %%f in (c:\WINDDK\*) do set DDK=%%f
+
+if "%DDK%"=="" (
+ echo cannot find ddk
+ goto error
+)
+
+if "%SIGNTOOL%"=="" set SIGNTOOL=%DDK%\bin\x86\signtool.exe
+if "%DEVCON32%"=="" set DEVCON32=%DDK%\tools\devcon\i386\devcon.exe
+if "%DEVCON64%"=="" set DEVCON64=%DDK%\tools\devcon\amd64\devcon.exe
+for /f %%f in ("%DEVCON32%") do set DEVCON_BASENAME=%%~nf%%~xf
+
+if "%MAKENSIS%"=="" for /d %%f in ("%ProgramFiles%\NSIS" "%ProgramFiles(x86)%\NSIS") do if exist "%%f" set MAKENSIS=%%~f
+
+if "%MAKENSIS%"=="" (
+ echo cannot find nsis
+ goto error
+)
+
+if "%CODESIGN_CROSS%"=="" set CODESIGN_CROSS=%cd%\build\MSCV-VSClass3.cer
+if "%CODESIGN_TIMESTAMP%"=="" set CODESIGN_TIMESTAMP=http://timestamp.verisign.com/scripts/timestamp.dll
+
+if "%OUTDIR%"=="" set OUTDIR=%cd%
+
+set msvcg_args=cscript //nologo build/msvc-generate.js --config=version.m4
+if exist config-local.m4 set msvcg_args=%msvcg_args% --config=config-local.m4
+set msvcg_args=%msvcg_args% --var=DDK="%DDK%" --var=MAKENSIS="%MAKENSIS%" --var=SIGNTOOL="%SIGNTOOL%" --var=DEVCON32="%DEVCON32%" --var=DEVCON64="%DEVCON64%" --var=DEVCON_BASENAME="%DEVCON_BASENAME%" --var=EXTRA_C_DEFINES="%EXTRA_C_DEFINES%" --var=CODESIGN_PKCS12="%CODESIGN_PKCS12%" --var=CODESIGN_PASS="%CODESIGN_PASS%" --var=CODESIGN_CROSS="%CODESIGN_CROSS%" --var=CODESIGN_TIMESTAMP="%CODESIGN_TIMESTAMP%" --var=CODESIGN_ISTEST="%CODESIGN_ISTEST%" --var=OUTDIR="%OUTDIR%"
+
+for %%f in (config-env.bat src\SOURCES src\config.h) do (
+ %msvcg_args% --input=%%f.in --output=%%f
+ if errorlevel 1 goto error
+)
+
+for %%a in (i386 amd64) do (
+ mkdir src\%%a > nul 2>&1
+ %msvcg_args% --config=build\vars.%%a.m4 --input=src\OemWin2k.inf.in --output=src\%%a\OemWin2k.inf
+ if errorlevel 1 goto error
+)
+
+set rc=0
+goto end
+
+:error
+echo FAILED
+set rc=1
+goto end
+
+:end
+
+endlocal
+
+exit /b %rc%
diff --git a/windows-tap/installer/build.bat b/windows-tap/installer/build.bat
new file mode 100644
index 00000000..3d7a2109
--- /dev/null
+++ b/windows-tap/installer/build.bat
@@ -0,0 +1,95 @@
+@echo off
+rem TAP-Windows -- A kernel driver to provide virtual tap
+rem device functionality on Windows.
+rem
+rem Copyright (C) 2012 Alon Bar-Lev <alon.barlev@gmail.com>
+rem
+rem This program is free software; you can redistribute it and/or modify
+rem it under the terms of the GNU General Public License as published by
+rem the Free Software Foundation; either version 2 of the License, or
+rem (at your option) any later version.
+rem
+rem This program is distributed in the hope that it will be useful,
+rem but WITHOUT ANY WARRANTY; without even the implied warranty of
+rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+rem GNU General Public License for more details.
+rem
+rem You should have received a copy of the GNU General Public License
+rem along with this program (see the file COPYING included with this
+rem distribution); if not, write to the Free Software Foundation, Inc.,
+rem 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+setlocal
+
+set wd=%cd%
+cd %0\..
+
+if "%MAKENSIS%"=="" call ..\config-env.bat
+
+if "%OUTDIR%"=="" set OUTDIR=.
+set OUTPUT=%OUTDIR%\tap-windows-%PRODUCT_VERSION%
+set TAP_ROOT=tmp\image\tap-windows-%PRODUCT_VERSION%
+
+set SIGNTOOL_CMD="%SIGNTOOL%" sign /v /p "%CODESIGN_PASS%" /f "%CODESIGN_PKCS12%"
+set SIGNTOOL_CMD_DRIVERS=%SIGNTOOL_CMD%
+if "%CODESIGN_ISTEST%" NEQ "yes" (
+ set SIGNTOOL_CMD=%SIGNTOOL_CMD% /t "%CODESIGN_TIMESTAMP%"
+ set SIGNTOOL_CMD_DRIVERS=%SIGNTOOL_CMD% /ac "%CODESIGN_CROSS%"
+)
+
+del "%OUTPUT%.*" > nul 2>&1
+rmdir /q /s tmp > nul 2>&1
+
+mkdir %TAP_ROOT%\include
+copy ..\src\tap-windows.h %TAP_ROOT%\include
+if errorlevel 1 goto error
+mkdir %TAP_ROOT%\i386
+copy ..\src\i386\* %TAP_ROOT%\i386
+if errorlevel 1 goto error
+mkdir %TAP_ROOT%\amd64
+copy ..\src\amd64\* %TAP_ROOT%\amd64
+if errorlevel 1 goto error
+
+type ..\COPYING > %TAP_ROOT%\license.txt
+type ..\COPYRIGHT.GPL >> %TAP_ROOT%\license.txt
+cscript //nologo ..\build\unix2dos.js %TAP_ROOT%\license.txt
+if errorlevel 1 goto error
+
+"%DDK%\bin\selfsign\inf2cat" /driver:%TAP_ROOT%\i386 /os:XP_X86,Vista_X86,7_X86,Server2003_X86,Server2008_X86
+"%DDK%\bin\selfsign\inf2cat" /driver:%TAP_ROOT%\amd64 /os:XP_X64,Vista_X64,7_X64,Server2003_X64,Server2008_X64,Server2008R2_X64
+
+if not "%CODESIGN_PKCS12%"=="" (
+ for %%a in (i386 amd64) do (
+ %SIGNTOOL_CMD_DRIVERS% "%TAP_ROOT%\%%a\%PRODUCT_TAP_WIN_COMPONENT_ID%.sys"
+ if errorlevel 1 goto error
+ %SIGNTOOL_CMD_DRIVERS% "%TAP_ROOT%\%%a\%PRODUCT_TAP_WIN_COMPONENT_ID%.cat"
+ if errorlevel 1 goto error
+ )
+)
+
+cscript //nologo ..\build\zip.js tmp\image "%OUTPUT%.zip"
+if errorlevel 1 goto error
+
+"%MAKENSIS%\makensis" -DDEVCON32="%DEVCON32%" -DDEVCON64="%DEVCON64%" -DDEVCON_BASENAME="%DEVCON_BASENAME%" -DPRODUCT_TAP_WIN_COMPONENT_ID="%PRODUCT_TAP_WIN_COMPONENT_ID%" -DPRODUCT_NAME="%PRODUCT_NAME%" -DPRODUCT_VERSION="%PRODUCT_VERSION%" -DOUTPUT="%OUTPUT%.exe" -DIMAGE="%TAP_ROOT%" tap-windows.nsi
+if errorlevel 1 goto error
+
+if not "%CODESIGN_PKCS12%"=="" (
+ %SIGNTOOL_CMD% "%OUTPUT%.exe"
+ if errorlevel 1 goto error
+)
+
+set rc=0
+goto end
+
+:error
+echo FATAL
+set rc=1
+goto end
+
+:end
+
+cd %wd%
+
+endlocal
+
+exit /b %rc%
diff --git a/windows-tap/installer/icon.ico b/windows-tap/installer/icon.ico
new file mode 100755
index 00000000..03ea0b1d
--- /dev/null
+++ b/windows-tap/installer/icon.ico
Binary files differ
diff --git a/windows-tap/installer/install-whirl.bmp b/windows-tap/installer/install-whirl.bmp
new file mode 100755
index 00000000..03f33fce
--- /dev/null
+++ b/windows-tap/installer/install-whirl.bmp
Binary files differ
diff --git a/windows-tap/installer/tap-windows.nsi b/windows-tap/installer/tap-windows.nsi
new file mode 100755
index 00000000..dd662a22
--- /dev/null
+++ b/windows-tap/installer/tap-windows.nsi
@@ -0,0 +1,317 @@
+; ****************************************************************************
+; * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. *
+; * Copyright (C) 2012 Alon Bar-Lev <alon.barlev@gmail.com> *
+; * 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. *
+; ****************************************************************************
+
+; TAP-Windows install script for Windows, using NSIS
+
+SetCompressor lzma
+
+!include "MUI.nsh"
+!include "StrFunc.nsh"
+!include "x64.nsh"
+!define MULTIUSER_EXECUTIONLEVEL Admin
+!include "MultiUser.nsh"
+!include FileFunc.nsh
+!insertmacro GetParameters
+!insertmacro GetOptions
+
+${StrLoc}
+
+;--------------------------------
+;Configuration
+
+;General
+
+OutFile "${OUTPUT}"
+
+ShowInstDetails show
+ShowUninstDetails show
+
+;Remember install folder
+InstallDirRegKey HKLM "SOFTWARE\${PRODUCT_NAME}" ""
+
+;--------------------------------
+;Modern UI Configuration
+
+Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
+
+!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of ${PRODUCT_NAME}, a kernel driver to provide virtual tap device functionality on Windows originally written by James Yonan.\r\n\r\nNote that the Windows version of ${PRODUCT_NAME} will only run on Windows XP or later.\r\n\r\n\r\n"
+
+!define MUI_COMPONENTSPAGE_TEXT_TOP "Select the components to install/upgrade. Stop any ${PRODUCT_NAME} processes or the ${PRODUCT_NAME} service if it is running. All DLLs are installed locally."
+
+!define MUI_COMPONENTSPAGE_SMALLDESC
+!define MUI_FINISHPAGE_NOAUTOCLOSE
+!define MUI_ABORTWARNING
+!define MUI_ICON "icon.ico"
+!define MUI_UNICON "icon.ico"
+!define MUI_HEADERIMAGE
+!define MUI_HEADERIMAGE_BITMAP "install-whirl.bmp"
+!define MUI_UNFINISHPAGE_NOAUTOCLOSE
+
+!insertmacro MUI_PAGE_WELCOME
+!insertmacro MUI_PAGE_LICENSE "${IMAGE}\license.txt"
+!insertmacro MUI_PAGE_COMPONENTS
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
+!insertmacro MUI_PAGE_FINISH
+
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+!insertmacro MUI_UNPAGE_FINISH
+
+;--------------------------------
+;Languages
+
+!insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+;Language Strings
+
+LangString DESC_SecTAP ${LANG_ENGLISH} "Install/Upgrade the TAP virtual device driver. Will not interfere with CIPE."
+LangString DESC_SecTAPUtilities ${LANG_ENGLISH} "Install the TAP Utilities."
+LangString DESC_SecTAPSDK ${LANG_ENGLISH} "Install the TAP SDK."
+
+;--------------------------------
+;Reserve Files
+
+;Things that need to be extracted on first (keep these lines before any File command!)
+;Only useful for BZIP2 compression
+
+ReserveFile "install-whirl.bmp"
+
+;--------------------------------
+;Macros
+
+!macro SelectByParameter SECT PARAMETER DEFAULT
+ ${GetOptions} $R0 "/${PARAMETER}=" $0
+ ${If} ${DEFAULT} == 0
+ ${If} $0 == 1
+ !insertmacro SelectSection ${SECT}
+ ${EndIf}
+ ${Else}
+ ${If} $0 != 0
+ !insertmacro SelectSection ${SECT}
+ ${EndIf}
+ ${EndIf}
+!macroend
+
+;--------------------------------
+;Installer Sections
+
+Section /o "TAP Virtual Ethernet Adapter" SecTAP
+
+ SetOverwrite on
+
+ ${If} ${RunningX64}
+ DetailPrint "We are running on a 64-bit system."
+
+ SetOutPath "$INSTDIR\bin"
+ File "${DEVCON64}"
+
+ SetOutPath "$INSTDIR\driver"
+ File "${IMAGE}\amd64\OemWin2k.inf"
+ File "${IMAGE}\amd64\${PRODUCT_TAP_WIN_COMPONENT_ID}.cat"
+ File "${IMAGE}\amd64\${PRODUCT_TAP_WIN_COMPONENT_ID}.sys"
+ ${Else}
+ DetailPrint "We are running on a 32-bit system."
+
+ SetOutPath "$INSTDIR\bin"
+ File "${DEVCON32}"
+
+ SetOutPath "$INSTDIR\driver"
+ File "${IMAGE}\i386\OemWin2k.inf"
+ File "${IMAGE}\i386\${PRODUCT_TAP_WIN_COMPONENT_ID}.cat"
+ File "${IMAGE}\i386\${PRODUCT_TAP_WIN_COMPONENT_ID}.sys"
+ ${EndIf}
+SectionEnd
+
+Section /o "TAP Utilities" SecTAPUtilities
+ SetOverwrite on
+
+ # Delete previous start menu
+ RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
+
+ FileOpen $R0 "$INSTDIR\bin\addtap.bat" w
+ FileWrite $R0 "rem Add a new TAP virtual ethernet adapter$\r$\n"
+ FileWrite $R0 '"$INSTDIR\bin\${DEVCON_BASENAME}" install "$INSTDIR\driver\OemWin2k.inf" ${PRODUCT_TAP_WIN_COMPONENT_ID}$\r$\n'
+ FileWrite $R0 "pause$\r$\n"
+ FileClose $R0
+
+ FileOpen $R0 "$INSTDIR\bin\deltapall.bat" w
+ FileWrite $R0 "echo WARNING: this script will delete ALL TAP virtual adapters (use the device manager to delete adapters one at a time)$\r$\n"
+ FileWrite $R0 "pause$\r$\n"
+ FileWrite $R0 '"$INSTDIR\bin\${DEVCON_BASENAME}" remove ${PRODUCT_TAP_WIN_COMPONENT_ID}$\r$\n'
+ FileWrite $R0 "pause$\r$\n"
+ FileClose $R0
+
+ ; Create shortcuts
+ CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}\Utilities"
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Add a new TAP virtual ethernet adapter.lnk" "$INSTDIR\bin\addtap.bat" ""
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Delete ALL TAP virtual ethernet adapters.lnk" "$INSTDIR\bin\deltapall.bat" ""
+SectionEnd
+
+Section /o "TAP SDK" SecTAPSDK
+ SetOverwrite on
+ SetOutPath "$INSTDIR\include"
+ File "${IMAGE}\include\tap-windows.h"
+SectionEnd
+
+Function .onInit
+ ${GetParameters} $R0
+ ClearErrors
+
+ !insertmacro SelectByParameter ${SecTAP} SELECT_TAP 1
+ !insertmacro SelectByParameter ${SecTAPUtilities} SELECT_UTILITIES 0
+ !insertmacro SelectByParameter ${SecTAPSDK} SELECT_SDK 0
+
+ !insertmacro MULTIUSER_INIT
+ SetShellVarContext all
+
+ ${If} ${RunningX64}
+ SetRegView 64
+ StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCT_NAME}"
+ ${Else}
+ StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCT_NAME}"
+ ${EndIf}
+FunctionEnd
+
+;--------------------------------
+;Dependencies
+
+Function .onSelChange
+ ${If} ${SectionIsSelected} ${SecTAPUtilities}
+ !insertmacro SelectSection ${SecTAP}
+ ${EndIf}
+FunctionEnd
+
+;--------------------
+;Post-install section
+
+Section -post
+
+ SetOverwrite on
+
+ ; Store README, license, icon
+ SetOverwrite on
+ SetOutPath $INSTDIR
+ File "${IMAGE}\license.txt"
+ File "icon.ico"
+
+ ${If} ${SectionIsSelected} ${SecTAP}
+ ;
+ ; install/upgrade TAP driver if selected, using devcon
+ ;
+ ; TAP install/update was selected.
+ ; Should we install or update?
+ ; If tapinstall error occurred, $R5 will
+ ; be nonzero.
+ IntOp $R5 0 & 0
+ nsExec::ExecToStack '"$INSTDIR\bin\${DEVCON_BASENAME}" hwids ${PRODUCT_TAP_WIN_COMPONENT_ID}'
+ Pop $R0 # return value/error/timeout
+ IntOp $R5 $R5 | $R0
+ DetailPrint "${DEVCON_BASENAME} hwids returned: $R0"
+
+ ; If tapinstall output string contains "${PRODUCT_TAP_WIN_COMPONENT_ID}" we assume
+ ; that TAP device has been previously installed,
+ ; therefore we will update, not install.
+ Push "${PRODUCT_TAP_WIN_COMPONENT_ID}"
+ Push ">"
+ Call StrLoc
+ Pop $R0
+
+ ${If} $R5 == 0
+ ${If} $R0 == ""
+ StrCpy $R1 "install"
+ ${Else}
+ StrCpy $R1 "update"
+ ${EndIf}
+ DetailPrint "TAP $R1 (${PRODUCT_TAP_WIN_COMPONENT_ID}) (May require confirmation)"
+ nsExec::ExecToLog '"$INSTDIR\bin\${DEVCON_BASENAME}" $R1 "$INSTDIR\driver\OemWin2k.inf" ${PRODUCT_TAP_WIN_COMPONENT_ID}'
+ Pop $R0 # return value/error/timeout
+ ${If} $R0 == ""
+ IntOp $R0 0 & 0
+ SetRebootFlag true
+ DetailPrint "REBOOT flag set"
+ ${EndIf}
+ IntOp $R5 $R5 | $R0
+ DetailPrint "${DEVCON_BASENAME} returned: $R0"
+ ${EndIf}
+
+ DetailPrint "${DEVCON_BASENAME} cumulative status: $R5"
+ ${If} $R5 != 0
+ MessageBox MB_OK "An error occurred installing the TAP device driver."
+ ${EndIf}
+
+ ; Store install folder in registry
+ WriteRegStr HKLM SOFTWARE\${PRODUCT_NAME} "" $INSTDIR
+ ${EndIf}
+
+ ; Create uninstaller
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+ ; Show up in Add/Remove programs
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayName" "${PRODUCT_NAME} ${PRODUCT_VERSION}"
+ WriteRegExpandStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayIcon" "$INSTDIR\icon.ico"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayVersion" "${PRODUCT_VERSION}"
+
+ ; Advise a reboot
+ ;Messagebox MB_OK "IMPORTANT: Rebooting the system is advised in order to finalize TAP driver installation/upgrade (this is an informational message only, pressing OK will not reboot)."
+
+SectionEnd
+
+;--------------------------------
+;Descriptions
+
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+!insertmacro MUI_DESCRIPTION_TEXT ${SecTAP} $(DESC_SecTAP)
+!insertmacro MUI_DESCRIPTION_TEXT ${SecTAPUtilities} $(DESC_SecTAPUtilities)
+!insertmacro MUI_DESCRIPTION_TEXT ${SecTAPSDK} $(DESC_SecTAPSDK)
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+;--------------------------------
+;Uninstaller Section
+
+Function un.onInit
+ ClearErrors
+ !insertmacro MULTIUSER_UNINIT
+ SetShellVarContext all
+ ${If} ${RunningX64}
+ SetRegView 64
+ ${EndIf}
+FunctionEnd
+
+Section "Uninstall"
+ DetailPrint "TAP REMOVE"
+ nsExec::ExecToLog '"$INSTDIR\bin\${DEVCON_BASENAME}" remove ${PRODUCT_TAP_WIN_COMPONENT_ID}'
+ Pop $R0 # return value/error/timeout
+ DetailPrint "${DEVCON_BASENAME} remove returned: $R0"
+
+ Delete "$INSTDIR\bin\${DEVCON_BASENAME}"
+ Delete "$INSTDIR\bin\addtap.bat"
+ Delete "$INSTDIR\bin\deltapall.bat"
+
+ Delete "$INSTDIR\driver\OemWin2k.inf"
+ Delete "$INSTDIR\driver\${PRODUCT_TAP_WIN_COMPONENT_ID}.cat"
+ Delete "$INSTDIR\driver\${PRODUCT_TAP_WIN_COMPONENT_ID}.sys"
+
+ Delete "$INSTDIR\include\tap-windows.h"
+
+ Delete "$INSTDIR\icon.ico"
+ Delete "$INSTDIR\license.txt"
+ Delete "$INSTDIR\Uninstall.exe"
+
+ RMDir "$INSTDIR\bin"
+ RMDir "$INSTDIR\driver"
+ RMDir "$INSTDIR\include"
+ RMDir "$INSTDIR"
+ RMDir /r "$SMPROGRAMS\${PRODUCT_NAME}"
+
+ DeleteRegKey HKLM "SOFTWARE\${PRODUCT_NAME}"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+
+SectionEnd
diff --git a/windows-tap/src/MAKEFILE b/windows-tap/src/MAKEFILE
new file mode 100755
index 00000000..6ee4f43f
--- /dev/null
+++ b/windows-tap/src/MAKEFILE
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/windows-tap/src/OemWin2k.inf.in b/windows-tap/src/OemWin2k.inf.in
new file mode 100755
index 00000000..ef73600e
--- /dev/null
+++ b/windows-tap/src/OemWin2k.inf.in
@@ -0,0 +1,187 @@
+; ****************************************************************************
+; * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. *
+; * 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. *
+; ****************************************************************************
+
+; SYNTAX CHECKER
+; cd \WINDDK\3790\tools\chkinf
+; chkinf c:\src\openvpn\tap-win32\i386\oemwin2k.inf
+; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm
+
+; INSTALL/REMOVE DRIVER
+; tapinstall install OemWin2k.inf TAP0901
+; tapinstall update OemWin2k.inf TAP0901
+; tapinstall remove TAP0901
+
+;*********************************************************
+; Note to Developers:
+;
+; If you are bundling the TAP-Windows driver with your app,
+; you should try to rename it in such a way that it will
+; not collide with other instances of TAP-Windows defined
+; by other apps. Multiple versions of the TAP-Windows
+; driver, each installed by different apps, can coexist
+; on the same machine if you follow these guidelines.
+; NOTE: these instructions assume you are editing the
+; generated OemWin2k.inf file, not the source
+; OemWin2k.inf.in file which is preprocessed by winconfig
+; and uses macro definitions from settings.in.
+;
+; (1) Rename all tapXXXX instances in this file to
+; something different (use at least 5 characters
+; for this name!)
+; (2) Change the "!define TAP" definition in openvpn.nsi
+; to match what you changed tapXXXX to.
+; (3) Change TARGETNAME in SOURCES to match what you
+; changed tapXXXX to.
+; (4) Change TAP_COMPONENT_ID in common.h to match what
+; you changed tapXXXX to.
+; (5) Change SZDEPENDENCIES in service.h to match what
+; you changed tapXXXX to.
+; (6) Change DeviceDescription and Provider strings.
+; (7) Change PRODUCT_TAP_WIN_DEVICE_DESCRIPTION in constants.h to what you
+; set DeviceDescription to.
+;
+;*********************************************************
+
+[Version]
+ Signature = "$Windows NT$"
+ CatalogFile = @PRODUCT_TAP_WIN_COMPONENT_ID@.cat
+ ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+ Provider = %Provider%
+ Class = Net
+
+; This version number should match the version
+; number given in SOURCES.
+ DriverVer=@PRODUCT_TAP_WIN_RELDATE@,@PRODUCT_TAP_WIN_MAJOR@.00.00.@PRODUCT_TAP_WIN_MINOR@
+
+[Strings]
+ DeviceDescription = "@PRODUCT_TAP_WIN_DEVICE_DESCRIPTION@"
+ Provider = "@PRODUCT_TAP_WIN_PROVIDER@"
+
+;----------------------------------------------------------------
+; Manufacturer + Product Section (Done)
+;----------------------------------------------------------------
+[Manufacturer]
+ %Provider% = @PRODUCT_TAP_WIN_COMPONENT_ID@@INF_PROVIDER_SUFFIX@
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@@INF_SECTION_SUFFIX@]
+ %DeviceDescription% = @PRODUCT_TAP_WIN_COMPONENT_ID@.ndi, @PRODUCT_TAP_WIN_COMPONENT_ID@
+
+;---------------------------------------------------------------
+; Driver Section (Done)
+;---------------------------------------------------------------
+
+;----------------- Characteristics ------------
+; NCF_PHYSICAL = 0x04
+; NCF_VIRTUAL = 0x01
+; NCF_SOFTWARE_ENUMERATED = 0x02
+; NCF_HIDDEN = 0x08
+; NCF_NO_SERVICE = 0x10
+; NCF_HAS_UI = 0x80
+;----------------- Characteristics ------------
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@.ndi]
+ CopyFiles = @PRODUCT_TAP_WIN_COMPONENT_ID@.driver, @PRODUCT_TAP_WIN_COMPONENT_ID@.files
+ AddReg = @PRODUCT_TAP_WIN_COMPONENT_ID@.reg
+ AddReg = @PRODUCT_TAP_WIN_COMPONENT_ID@.params.reg
+ Characteristics = @PRODUCT_TAP_WIN_CHARACTERISTICS@
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@.ndi.Services]
+ AddService = @PRODUCT_TAP_WIN_COMPONENT_ID@, 2, @PRODUCT_TAP_WIN_COMPONENT_ID@.service
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@.reg]
+ HKR, Ndi, Service, 0, "@PRODUCT_TAP_WIN_COMPONENT_ID@"
+ HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
+ HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+ HKR, , Manufacturer, 0, "%Provider%"
+ HKR, , ProductName, 0, "%DeviceDescription%"
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@.params.reg]
+ HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
+ HKR, Ndi\params\MTU, Type, 0, "int"
+ HKR, Ndi\params\MTU, Default, 0, "1500"
+ HKR, Ndi\params\MTU, Optional, 0, "0"
+ HKR, Ndi\params\MTU, Min, 0, "100"
+ HKR, Ndi\params\MTU, Max, 0, "1500"
+ HKR, Ndi\params\MTU, Step, 0, "1"
+ HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
+ HKR, Ndi\params\MediaStatus, Type, 0, "enum"
+ HKR, Ndi\params\MediaStatus, Default, 0, "0"
+ HKR, Ndi\params\MediaStatus, Optional, 0, "0"
+ HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
+ HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
+ HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
+ HKR, Ndi\params\MAC, Type, 0, "edit"
+ HKR, Ndi\params\MAC, Optional, 0, "1"
+ HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access"
+ HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum"
+ HKR, Ndi\params\AllowNonAdmin, Default, 0, "1"
+ HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0"
+ HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed"
+ HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed"
+
+;----------------------------------------------------------------
+; Service Section
+;----------------------------------------------------------------
+
+;---------- Service Type -------------
+; SERVICE_KERNEL_DRIVER = 0x01
+; SERVICE_WIN32_OWN_PROCESS = 0x10
+;---------- Service Type -------------
+
+;---------- Start Mode ---------------
+; SERVICE_BOOT_START = 0x0
+; SERVICE_SYSTEM_START = 0x1
+; SERVICE_AUTO_START = 0x2
+; SERVICE_DEMAND_START = 0x3
+; SERVICE_DISABLED = 0x4
+;---------- Start Mode ---------------
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@.service]
+ DisplayName = %DeviceDescription%
+ ServiceType = 1
+ StartType = 3
+ ErrorControl = 1
+ LoadOrderGroup = NDIS
+ ServiceBinary = %12%\@PRODUCT_TAP_WIN_COMPONENT_ID@.sys
+
+;-----------------------------------------------------------------
+; File Installation
+;-----------------------------------------------------------------
+
+;----------------- Copy Flags ------------
+; COPYFLG_NOSKIP = 0x02
+; COPYFLG_NOVERSIONCHECK = 0x04
+;----------------- Copy Flags ------------
+
+; SourceDisksNames
+; diskid = description[, [tagfile] [, <unused>, subdir]]
+; 1 = "Intel Driver Disk 1",e100bex.sys,,
+
+[SourceDisksNames]
+ 1 = %DeviceDescription%, @PRODUCT_TAP_WIN_COMPONENT_ID@.sys
+
+; SourceDisksFiles
+; filename_on_source = diskID[, [subdir][, size]]
+; e100bex.sys = 1,, ; on distribution disk 1
+
+[SourceDisksFiles]
+@PRODUCT_TAP_WIN_COMPONENT_ID@.sys = 1
+
+[DestinationDirs]
+ @PRODUCT_TAP_WIN_COMPONENT_ID@.files = 11
+ @PRODUCT_TAP_WIN_COMPONENT_ID@.driver = 12
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@.files]
+; TapPanel.cpl,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+; cipsrvr.exe,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+
+[@PRODUCT_TAP_WIN_COMPONENT_ID@.driver]
+ @PRODUCT_TAP_WIN_COMPONENT_ID@.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+
+;---------------------------------------------------------------
+; End
+;---------------------------------------------------------------
diff --git a/windows-tap/src/SOURCES.in b/windows-tap/src/SOURCES.in
new file mode 100755
index 00000000..3e1ee81d
--- /dev/null
+++ b/windows-tap/src/SOURCES.in
@@ -0,0 +1,65 @@
+# Build TAP-Windows driver.
+# Build Command: build -cef
+
+MAJORCOMP=ntos
+MINORCOMP=ndis
+
+TARGETNAME=@PRODUCT_TAP_WIN_COMPONENT_ID@
+TARGETTYPE=DRIVER
+TARGETPATH=.
+TARGETLIBS=$(DDK_LIB_PATH)\ndis.lib $(DDK_LIB_PATH)\ntstrsafe.lib
+INCLUDES=$(DDK_INCLUDE_PATH) ..
+
+# The TAP version numbers here must be >=
+# PRODUCT_TAP_WIN32_MIN_x values defined in version.m4
+C_DEFINES=
+C_DEFINES=$(C_DEFINES) @EXTRA_C_DEFINES@
+C_DEFINES=$(C_DEFINES) -DTAP_DRIVER_MAJOR_VERSION=@PRODUCT_TAP_WIN_MAJOR@
+C_DEFINES=$(C_DEFINES) -DTAP_DRIVER_MINOR_VERSION=@PRODUCT_TAP_WIN_MINOR@
+
+# Produce the same symbolic information for both free & checked builds.
+# This will allow us to perform full source-level debugging on both
+# builds without affecting the free build's performance.
+!IF "$(DDKBUILDENV)" != "chk"
+NTDEBUGTYPE=both
+USE_PDB=1
+!ELSE
+NTDEBUGTYPE=both
+USE_PDB=1
+!ENDIF
+
+# Set compiler optimizations:
+# /Ox - Full optimization enabled
+# /Os - favor speed over size when optimizing
+# /Od - Disable all optimizations
+# /Oi - Enable optimization for intrinsic functions
+# /Fc - Generate mixed assembler/source code files
+#
+# For both checked and free builds, make sure that any intrinsic
+# functions are compiled correctly. To do this, ensure that /Oi
+# is selected for both free and checked builds. There is a bug in
+# VC++ 6.0 (at least through SP4) where, if you specify any
+# intrinsic functions in your code with "#pragma intrinsic" but
+# you don't have the /Oi optimization enabled, neither a call
+# to the function, nor the intrinsic inline version of the function
+# will end up in your object code. This bug only applies to free
+# builds, but just to be safe we'll make sure that the flag is
+# enabled for all builds.
+
+!IF "$(DDKBUILDENV)" != "chk"
+MSC_OPTIMIZATION=/Ox /Oi /Fc
+!ELSE
+MSC_OPTIMIZATION=/Od /Oi /Fc
+!ENDIF
+
+# Generate a linker map file just in case we need one for debugging
+LINKER_FLAGS=$(LINKER_FLAGS) /INCREMENTAL:NO /MAP /MAPINFO:EXPORTS
+
+# Generate a browser information file for use in IDE development
+#BROWSER_INFO=1
+#BROWSERFILE=$(TARGETNAME).BSC -n
+
+# Abort compilation on warnings by adding /WX
+MSC_WARNING_LEVEL=/W3
+
+SOURCES=tapdrvr.c resource.rc
diff --git a/windows-tap/src/config.h.in b/windows-tap/src/config.h.in
new file mode 100644
index 00000000..322afa8d
--- /dev/null
+++ b/windows-tap/src/config.h.in
@@ -0,0 +1,9 @@
+#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@"
diff --git a/windows-tap/src/constants.h b/windows-tap/src/constants.h
new file mode 100755
index 00000000..2451f128
--- /dev/null
+++ b/windows-tap/src/constants.h
@@ -0,0 +1,52 @@
+/*
+ * 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-2010 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
+
+#define TAP_NDIS_MAJOR_VERSION 5
+#define TAP_NDIS_MINOR_VERSION 0
+
+//===========================================================
+// 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 NIC_MAX_MCAST_LIST 32 // Max length of multicast address list
+
+#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-tap/src/dhcp.c b/windows-tap/src/dhcp.c
new file mode 100755
index 00000000..a3f74057
--- /dev/null
+++ b/windows-tap/src/dhcp.c
@@ -0,0 +1,599 @@
+/*
+ * 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-2010 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
+ */
+
+//=========================
+// Code to set DHCP options
+//=========================
+
+VOID
+SetDHCPOpt (DHCPMsg *m, void *data, 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 (DHCPMsg *msg, int type)
+{
+ DHCPOPT0 opt;
+ opt.type = (UCHAR) type;
+ SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+VOID
+SetDHCPOpt8 (DHCPMsg *msg, int type, ULONG data)
+{
+ DHCPOPT8 opt;
+ opt.type = (UCHAR) type;
+ opt.len = sizeof (opt.data);
+ opt.data = (UCHAR) data;
+ SetDHCPOpt (msg, &opt, sizeof (opt));
+}
+
+VOID
+SetDHCPOpt32 (DHCPMsg *msg, int type, 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 (const UCHAR *buf, 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 (const UCHAR *buf,
+ const int len_udp,
+ const UCHAR *src_addr,
+ 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 (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 (const DHCP *dhcp, 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 (const TapAdapterPointer p_Adapter,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp)
+{
+ // Must be UDPv4 protocol
+ if (!(eth->proto == htons (ETH_P_IP) && ip->protocol == IPPROTO_UDP))
+ return FALSE;
+
+ // Source MAC must be our adapter
+ if (!MAC_EQUAL (eth->src, p_Adapter->m_MAC))
+ return FALSE;
+
+ // Dest MAC must be either broadcast or our virtual DHCP server
+ if (!(MAC_EQUAL (eth->dest, p_Adapter->m_MAC_Broadcast)
+ || MAC_EQUAL (eth->dest, p_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 (const TapAdapterPointer a,
+ DHCPPre *p,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp,
+ const int optlen,
+ const int type)
+{
+ // Should we broadcast or direct to a specific MAC / IP address?
+ const BOOLEAN broadcast = (type == DHCPNAK
+ || MAC_EQUAL (eth->dest, a->m_MAC_Broadcast));
+ // Build ethernet header
+
+ COPY_MAC (p->eth.src, a->m_dhcp_server_mac);
+
+ if (broadcast)
+ COPY_MAC (p->eth.dest, a->m_MAC_Broadcast);
+ else
+ COPY_MAC (p->eth.dest, eth->src);
+
+ p->eth.proto = htons (ETH_P_IP);
+
+ // 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 = a->m_dhcp_server_ip;
+
+ if (broadcast)
+ p->ip.daddr = ~0;
+ else
+ p->ip.daddr = a->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 = a->m_dhcp_addr;
+
+ p->dhcp.siaddr = a->m_dhcp_server_ip;
+ p->dhcp.giaddr = 0;
+ COPY_MAC (p->dhcp.chaddr, eth->src);
+ p->dhcp.magic = htonl (0x63825363);
+}
+//=============================
+// Build specific DHCP messages
+//=============================
+
+VOID
+SendDHCPMsg (const TapAdapterPointer a,
+ const int type,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ 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, a->m_dhcp_server_ip);
+
+ if (type == DHCPOFFER || type == DHCPACK)
+ {
+ // Lease Time
+ SetDHCPOpt32 (pkt, DHCP_LEASE_TIME, htonl (a->m_dhcp_lease_time));
+
+ // Netmask
+ SetDHCPOpt32 (pkt, DHCP_NETMASK, a->m_dhcp_netmask);
+
+ // Other user-defined options
+ SetDHCPOpt (pkt,
+ a->m_dhcp_user_supplied_options_buffer,
+ a->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 (a,
+ &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
+ InjectPacketDeferred (a,
+ 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 (TapAdapterPointer p_Adapter,
+ const ETH_HEADER *eth,
+ const IPHDR *ip,
+ const UDPHDR *udp,
+ const DHCP *dhcp,
+ 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 (p_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 != p_Adapter->m_dhcp_addr)
+ || !p_Adapter->m_dhcp_received_discover
+ || p_Adapter->m_dhcp_bad_requests >= BAD_DHCPREQUEST_NAK_THRESHOLD))
+ SendDHCPMsg (p_Adapter,
+ DHCPNAK,
+ eth, ip, udp, dhcp);
+ else
+ SendDHCPMsg (p_Adapter,
+ (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK),
+ eth, ip, udp, dhcp);
+
+ // Remember if we received a DHCPDISCOVER
+ if (msg_type == DHCPDISCOVER)
+ p_Adapter->m_dhcp_received_discover = TRUE;
+
+ // Is this a bad DHCPREQUEST?
+ if (msg_type == DHCPREQUEST && dhcp->ciaddr && dhcp->ciaddr != p_Adapter->m_dhcp_addr)
+ ++p_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-tap/src/dhcp.h b/windows-tap/src/dhcp.h
new file mode 100755
index 00000000..94765a7b
--- /dev/null
+++ b/windows-tap/src/dhcp.h
@@ -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-2010 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 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-tap/src/endian.h b/windows-tap/src/endian.h
new file mode 100755
index 00000000..0f7025d5
--- /dev/null
+++ b/windows-tap/src/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-2010 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-tap/src/error.c b/windows-tap/src/error.c
new file mode 100755
index 00000000..69e9ec63
--- /dev/null
+++ b/windows-tap/src/error.c
@@ -0,0 +1,385 @@
+/*
+ * 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-2010 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
+//-----------------
+
+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 (char *buf, 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
+MyAssert (const unsigned char *file, int line)
+{
+ DEBUGP (("MYASSERT failed %s/%d\n", file, line));
+ KeBugCheckEx (0x0F00BABA,
+ (ULONG_PTR) line,
+ (ULONG_PTR) 0,
+ (ULONG_PTR) 0,
+ (ULONG_PTR) 0);
+}
+
+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];
+};
+
+VOID
+DumpPacket2 (const char *prefix,
+ const ETH_HEADER *eth,
+ const unsigned char *data,
+ 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 (const char *prefix,
+ const unsigned char *data,
+ 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
diff --git a/windows-tap/src/error.h b/windows-tap/src/error.h
new file mode 100755
index 00000000..47f436c5
--- /dev/null
+++ b/windows-tap/src/error.h
@@ -0,0 +1,88 @@
+/*
+ * 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-2010 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
+//-----------------
+
+#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 MyAssert (const unsigned char *file, int line);
+
+VOID DumpPacket (const char *prefix,
+ const unsigned char *data,
+ unsigned int len);
+
+VOID DumpPacket2 (const char *prefix,
+ const ETH_HEADER *eth,
+ const unsigned char *data,
+ unsigned int len);
+
+#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
+
+#define MYASSERT(exp) \
+{ \
+ if (!(exp)) \
+ { \
+ MyAssert(__FILE__, __LINE__); \
+ } \
+}
+
+#define DUMP_PACKET(prefix, data, len) \
+ DumpPacket (prefix, data, len)
+
+#define DUMP_PACKET2(prefix, eth, data, len) \
+ DumpPacket2 (prefix, eth, data, len)
+
+#else
+
+#define DEBUGP(fmt)
+#define MYASSERT(exp)
+#define DUMP_PACKET(prefix, data, len)
+#define DUMP_PACKET2(prefix, eth, data, len)
+
+#endif
diff --git a/windows-tap/src/hexdump.c b/windows-tap/src/hexdump.c
new file mode 100755
index 00000000..8589f4b2
--- /dev/null
+++ b/windows-tap/src/hexdump.c
@@ -0,0 +1,69 @@
+/*
+ * 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-2010 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 __cplusplus
+extern "C" {
+#endif
+
+#include "hexdump.h"
+
+#ifndef NDIS_MINIPORT_DRIVER
+
+VOID (*DbgMessage)(char *p_Format, ...) = DisplayDebugString;
+
+VOID DisplayDebugString (char *p_Format, ...)
+ {
+ static char l_Buffer [4096];
+
+ va_list l_ArgumentList;
+ va_start (l_ArgumentList, p_Format);
+ vsprintf (l_Buffer, p_Format, l_ArgumentList);
+ va_end (l_ArgumentList);
+
+ OutputDebugStringA (l_Buffer);
+ }
+
+#endif
+
+VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size)
+ {
+ unsigned long l_Index, l_Idx;
+ unsigned char l_Row [17];
+
+ for (l_Index = l_Row [16] = 0; l_Index < p_Size || l_Index % 16; ++l_Index)
+ {
+ if (l_Index % 16 == 0)
+ DEBUGP (("%05x ", l_Index));
+ DEBUGP (("%02x ", l_Row [l_Index % 16] = (l_Index < p_Size ? p_Buffer [l_Index] : 0)));
+ l_Row [l_Index % 16] = IfPrint (l_Row [l_Index % 16]);
+ if ((l_Index + 1) % 16 == 0)
+ DEBUGP ((" %s\n", l_Row));
+ }
+
+ DEBUGP (("\n"));
+ }
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/windows-tap/src/hexdump.h b/windows-tap/src/hexdump.h
new file mode 100755
index 00000000..d0b152d1
--- /dev/null
+++ b/windows-tap/src/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-2010 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-tap/src/instance.c b/windows-tap/src/instance.c
new file mode 100755
index 00000000..33ef878f
--- /dev/null
+++ b/windows-tap/src/instance.c
@@ -0,0 +1,241 @@
+/*
+ * 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-2010 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
+ */
+
+#define INSTANCE_KEY(a) ((PVOID)((a)->m_Extension.m_TapDevice))
+
+#define N_INSTANCE_BUCKETS 256
+
+typedef struct _INSTANCE {
+ struct _INSTANCE *next;
+ TapAdapterPointer m_Adapter;
+} INSTANCE;
+
+typedef struct {
+ INSTANCE *list;
+ MUTEX lock;
+} INSTANCE_BUCKET;
+
+typedef struct {
+ INSTANCE_BUCKET buckets[N_INSTANCE_BUCKETS];
+} INSTANCE_HASH;
+
+INSTANCE_HASH *g_InstanceHash = NULL;
+
+// must return a hash >= 0 and < N_INSTANCE_BUCKETS
+int
+InstanceHashValue (PVOID addr)
+{
+ UCHAR *p = (UCHAR *) &addr;
+
+ if (sizeof (addr) == 4)
+ return p[0] ^ p[1] ^ p[2] ^ p[3];
+ else if (sizeof (addr) == 8)
+ return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4] ^ p[5] ^ p[6] ^ p[7];
+ else
+ {
+ MYASSERT (0);
+ }
+}
+
+BOOLEAN
+InitInstanceList (VOID)
+{
+ MYASSERT (g_InstanceHash == NULL);
+ g_InstanceHash = MemAlloc (sizeof (INSTANCE_HASH), TRUE);
+ if (g_InstanceHash)
+ {
+ int i;
+ for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
+ INIT_MUTEX (&g_InstanceHash->buckets[i].lock);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+int
+NInstances (VOID)
+{
+ int i, n = 0;
+
+ if (g_InstanceHash)
+ {
+ for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
+ {
+ BOOLEAN got_lock;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current;
+ for (current = ib->list; current != NULL; current = current->next)
+ ++n;
+ RELEASE_MUTEX (&ib->lock);
+ }
+ else
+ return -1;
+ }
+ }
+
+ return n;
+}
+
+int
+InstanceMaxBucketSize (VOID)
+{
+ int i, n = 0;
+
+ if (g_InstanceHash)
+ {
+ for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
+ {
+ BOOLEAN got_lock;
+ int bucket_size = 0;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current;
+ for (current = ib->list; current != NULL; current = current->next)
+ ++bucket_size;
+ if (bucket_size > n)
+ n = bucket_size;
+ RELEASE_MUTEX (&ib->lock);
+ }
+ else
+ return -1;
+ }
+ }
+
+ return n;
+}
+
+VOID
+FreeInstanceList (VOID)
+{
+ if (g_InstanceHash)
+ {
+ MYASSERT (NInstances() == 0);
+ MemFree (g_InstanceHash, sizeof (INSTANCE_HASH));
+ g_InstanceHash = NULL;
+ }
+}
+
+BOOLEAN
+AddAdapterToInstanceList (TapAdapterPointer p_Adapter)
+{
+ BOOLEAN got_lock;
+ BOOLEAN ret = FALSE;
+ const int hash = InstanceHashValue(INSTANCE_KEY(p_Adapter));
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[hash];
+
+ DEBUGP (("[TAP] AddAdapterToInstanceList hash=%d\n", hash));
+
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *i = MemAlloc (sizeof (INSTANCE), FALSE);
+ if (i)
+ {
+ MYASSERT (p_Adapter);
+ i->m_Adapter = p_Adapter;
+ i->next = ib->list;
+ ib->list = i;
+ ret = TRUE;
+ }
+ RELEASE_MUTEX (&ib->lock);
+ }
+
+ return ret;
+}
+
+BOOLEAN
+RemoveAdapterFromInstanceList (TapAdapterPointer p_Adapter)
+{
+ BOOLEAN got_lock;
+ BOOLEAN ret = FALSE;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue(INSTANCE_KEY(p_Adapter))];
+
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current, *prev=NULL;
+ for (current = ib->list; current != NULL; current = current->next)
+ {
+ if (current->m_Adapter == p_Adapter) // found match
+ {
+ if (prev)
+ prev->next = current->next;
+ else
+ ib->list = current->next;
+ MemFree (current->m_Adapter, sizeof (TapAdapter));
+ MemFree (current, sizeof (INSTANCE));
+ ret = TRUE;
+ break;
+ }
+ prev = current;
+ }
+ RELEASE_MUTEX (&ib->lock);
+ }
+
+ return ret;
+}
+
+TapAdapterPointer
+LookupAdapterInInstanceList (PDEVICE_OBJECT p_DeviceObject)
+{
+ BOOLEAN got_lock;
+ TapAdapterPointer ret = NULL;
+ INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue((PVOID)p_DeviceObject)];
+
+ ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
+
+ if (got_lock)
+ {
+ INSTANCE *current, *prev=NULL;
+ for (current = ib->list; current != NULL; current = current->next)
+ {
+ if (p_DeviceObject == INSTANCE_KEY (current->m_Adapter)) // found match
+ {
+ // move it to head of list
+ if (prev)
+ {
+ prev->next = current->next;
+ current->next = ib->list;
+ ib->list = current;
+ }
+ ret = ib->list->m_Adapter;
+ break;
+ }
+ prev = current;
+ }
+ RELEASE_MUTEX (&ib->lock);
+ }
+
+ return ret;
+}
diff --git a/windows-tap/src/lock.h b/windows-tap/src/lock.h
new file mode 100755
index 00000000..e2a2029e
--- /dev/null
+++ b/windows-tap/src/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-2010 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-tap/src/macinfo.c b/windows-tap/src/macinfo.c
new file mode 100755
index 00000000..fca53079
--- /dev/null
+++ b/windows-tap/src/macinfo.c
@@ -0,0 +1,154 @@
+/*
+ * 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-2010 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 "macinfo.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;
+
+ MYASSERT (src);
+ MYASSERT (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 (MACADDR mac, 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 (MACADDR dest, const MACADDR src, const int delta)
+{
+ COPY_MAC (dest, src);
+ dest[2] += (UCHAR) delta;
+}
diff --git a/windows-tap/src/macinfo.h b/windows-tap/src/macinfo.h
new file mode 100755
index 00000000..ba843e8c
--- /dev/null
+++ b/windows-tap/src/macinfo.h
@@ -0,0 +1,38 @@
+/*
+ * 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-2010 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 COPY_MAC(dest, src) NdisMoveMemory ((dest), (src), sizeof (MACADDR))
+#define CLEAR_MAC(dest) NdisZeroMemory ((dest), sizeof (MACADDR))
+#define MAC_EQUAL(a,b) (memcmp ((a), (b), sizeof (MACADDR)) == 0)
+
+#endif
diff --git a/windows-tap/src/mem.c b/windows-tap/src/mem.c
new file mode 100755
index 00000000..c56304cc
--- /dev/null
+++ b/windows-tap/src/mem.c
@@ -0,0 +1,186 @@
+/*
+ * 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-2010 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 (ULONG p_Size, 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 (PVOID p_Addr, 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)
+ {
+ }
+ }
+}
+
+/*
+ * Circular queue management routines.
+ */
+
+#define QUEUE_BYTE_ALLOCATION(size) \
+ (sizeof (Queue) + (size * sizeof (PVOID)))
+
+#define QUEUE_ADD_INDEX(var, inc) \
+{ \
+ var += inc; \
+ if (var >= q->capacity) \
+ var -= q->capacity; \
+ MYASSERT (var < q->capacity); \
+}
+
+#define QUEUE_SANITY_CHECK() \
+ MYASSERT (q != NULL && q->base < q->capacity && q->size <= q->capacity)
+
+#define QueueCount(q) (q->size)
+
+#define UPDATE_MAX_SIZE() \
+{ \
+ if (q->size > q->max_size) \
+ q->max_size = q->size; \
+}
+
+Queue *
+QueueInit (ULONG capacity)
+{
+ Queue *q;
+
+ MYASSERT (capacity > 0);
+ q = (Queue *) MemAlloc (QUEUE_BYTE_ALLOCATION (capacity), TRUE);
+ if (!q)
+ return NULL;
+
+ q->base = q->size = 0;
+ q->capacity = capacity;
+ q->max_size = 0;
+ return q;
+}
+
+VOID
+QueueFree (Queue *q)
+{
+ if (q)
+ {
+ QUEUE_SANITY_CHECK ();
+ MemFree (q, QUEUE_BYTE_ALLOCATION (q->capacity));
+ }
+}
+
+PVOID
+QueuePush (Queue *q, PVOID item)
+{
+ ULONG dest;
+ QUEUE_SANITY_CHECK ();
+ if (q->size == q->capacity)
+ return NULL;
+ dest = q->base;
+ QUEUE_ADD_INDEX (dest, q->size);
+ q->data[dest] = item;
+ ++q->size;
+ UPDATE_MAX_SIZE();
+ return item;
+}
+
+PVOID
+QueuePop (Queue *q)
+{
+ ULONG oldbase;
+ QUEUE_SANITY_CHECK ();
+ if (!q->size)
+ return NULL;
+ oldbase = q->base;
+ QUEUE_ADD_INDEX (q->base, 1);
+ --q->size;
+ UPDATE_MAX_SIZE();
+ return q->data[oldbase];
+}
+
+PVOID
+QueueExtract (Queue *q, PVOID item)
+{
+ ULONG src, dest, count, n;
+ QUEUE_SANITY_CHECK ();
+ n = 0;
+ src = dest = q->base;
+ count = q->size;
+ while (count--)
+ {
+ if (item == q->data[src])
+ {
+ ++n;
+ --q->size;
+ }
+ else
+ {
+ q->data[dest] = q->data[src];
+ QUEUE_ADD_INDEX (dest, 1);
+ }
+ QUEUE_ADD_INDEX (src, 1);
+ }
+ if (n)
+ return item;
+ else
+ return NULL;
+}
+
+#undef QUEUE_BYTE_ALLOCATION
+#undef QUEUE_ADD_INDEX
+#undef QUEUE_SANITY_CHECK
+#undef UPDATE_MAX_SIZE
diff --git a/windows-tap/src/proto.h b/windows-tap/src/proto.h
new file mode 100755
index 00000000..71916a96
--- /dev/null
+++ b/windows-tap/src/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-2010 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
+
+typedef unsigned char MACADDR [6];
+typedef unsigned long IPADDR;
+typedef unsigned char IPV6ADDR [16];
+
+//-----------------
+// Ethernet address
+//-----------------
+
+typedef struct {
+ MACADDR addr;
+} ETH_ADDR;
+
+typedef struct {
+ ETH_ADDR list[NIC_MAX_MCAST_LIST];
+} MC_LIST;
+
+//----------------
+// Ethernet header
+//----------------
+
+typedef struct
+{
+ MACADDR dest; /* destination eth addr */
+ MACADDR src; /* source ether addr */
+
+# define ETH_P_IP 0x0800 /* IPv4 protocol */
+# define ETH_P_IPV6 0x86DD /* IPv6 protocol */
+# define ETH_P_ARP 0x0806 /* ARP protocol */
+ 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-tap/src/prototypes.h b/windows-tap/src/prototypes.h
new file mode 100755
index 00000000..50cc4610
--- /dev/null
+++ b/windows-tap/src/prototypes.h
@@ -0,0 +1,260 @@
+/*
+ * 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-2010 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
+
+NTSTATUS DriverEntry
+ (
+ IN PDRIVER_OBJECT p_DriverObject,
+ IN PUNICODE_STRING p_RegistryPath
+ );
+
+VOID TapDriverUnload
+ (
+ IN PDRIVER_OBJECT p_DriverObject
+ );
+
+NDIS_STATUS AdapterCreate
+ (
+ OUT PNDIS_STATUS p_ErrorStatus,
+ OUT PUINT p_MediaIndex,
+ IN PNDIS_MEDIUM p_Media,
+ IN UINT p_MediaCount,
+ IN NDIS_HANDLE p_AdapterHandle,
+ IN NDIS_HANDLE p_ConfigurationHandle
+ );
+
+VOID AdapterHalt
+ (
+ IN NDIS_HANDLE p_AdapterContext
+ );
+
+VOID AdapterFreeResources
+ (
+ TapAdapterPointer p_Adapter
+ );
+
+NDIS_STATUS AdapterReset
+ (
+ OUT PBOOLEAN p_AddressingReset,
+ IN NDIS_HANDLE p_AdapterContext
+ );
+
+NDIS_STATUS AdapterQuery
+ (
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesWritten,
+ OUT PULONG p_BytesNeeded
+ );
+
+NDIS_STATUS AdapterModify
+ (
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesRead,
+ OUT PULONG p_BytesNeeded
+ );
+
+NDIS_STATUS AdapterTransmit
+ (
+ IN NDIS_HANDLE p_AdapterContext,
+ IN PNDIS_PACKET p_Packet,
+ IN UINT p_Flags
+ );
+
+NDIS_STATUS AdapterReceive
+ (
+ OUT PNDIS_PACKET p_Packet,
+ OUT PUINT p_Transferred,
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_HANDLE p_ReceiveContext,
+ IN UINT p_Offset,
+ IN UINT p_ToTransfer
+ );
+
+NTSTATUS TapDeviceHook
+ (
+ IN PDEVICE_OBJECT p_DeviceObject,
+ IN PIRP p_IRP
+ );
+
+NDIS_STATUS CreateTapDevice
+ (
+ TapExtensionPointer p_Extension,
+ const char *p_Name
+ );
+
+VOID DestroyTapDevice
+ (
+ TapExtensionPointer p_Extension
+ );
+
+VOID TapDeviceFreeResources
+ (
+ TapExtensionPointer p_Extension
+ );
+
+NTSTATUS CompleteIRP
+ (
+ IN PIRP p_IRP,
+ IN TapPacketPointer p_PacketBuffer,
+ IN CCHAR PriorityBoost
+ );
+
+VOID CancelIRPCallback
+ (
+ IN PDEVICE_OBJECT p_DeviceObject,
+ IN PIRP p_IRP
+ );
+
+VOID CancelIRP
+ (
+ TapExtensionPointer p_Extension,
+ IN PIRP p_IRP,
+ BOOLEAN callback
+ );
+
+VOID FlushQueues
+ (
+ TapExtensionPointer p_Extension
+ );
+
+VOID ResetTapAdapterState
+ (
+ TapAdapterPointer p_Adapter
+ );
+
+BOOLEAN ProcessARP
+ (
+ TapAdapterPointer p_Adapter,
+ const PARP_PACKET src,
+ const IPADDR adapter_ip,
+ const IPADDR ip_network,
+ const IPADDR ip_netmask,
+ const MACADDR mac
+ );
+
+VOID SetMediaStatus
+ (
+ TapAdapterPointer p_Adapter,
+ BOOLEAN state
+ );
+
+VOID InjectPacketDeferred
+ (
+ TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len
+ );
+
+VOID InjectPacketNow
+ (
+ TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len
+ );
+
+// for KDEFERRED_ROUTINE and Static Driver Verifier
+//#include <wdm.h>
+//KDEFERRED_ROUTINE InjectPacketDpc;
+
+VOID InjectPacketDpc
+ (
+ KDPC *Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2
+ );
+
+VOID CheckIfDhcpAndTunMode
+ (
+ TapAdapterPointer p_Adapter
+ );
+
+VOID HookDispatchFunctions();
+
+#if ENABLE_NONADMIN
+
+#if defined(DDKVER_MAJOR) && DDKVER_MAJOR < 5600
+/*
+ * Better solution for use on Vista DDK, but possibly not compatible with
+ * earlier DDKs:
+ *
+ * Eliminate the definition of SECURITY_DESCRIPTOR (and even ZwSetSecurityObject),
+ * and at the top of tapdrv.c change:
+ *
+ * #include <ndis.h>
+ * #include <ntstrsafe.h>
+ * #include <ntddk.h>
+ *
+ * To
+ *
+ * #include <ntifs.h>
+ * #include <ndis.h>
+ * #include <ntstrsafe.h>
+ */
+typedef struct _SECURITY_DESCRIPTOR {
+ unsigned char opaque[64];
+} SECURITY_DESCRIPTOR;
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwSetSecurityObject (
+ IN HANDLE Handle,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+#endif
+
+VOID AllowNonAdmin (TapExtensionPointer p_Extension);
+
+#endif
+
+struct WIN2K_NDIS_MINIPORT_BLOCK
+{
+ unsigned char opaque[16];
+ UNICODE_STRING MiniportName; // how mini-port refers to us
+};
+
+#if PACKET_TRUNCATION_CHECK
+
+VOID IPv4PacketSizeVerify
+ (
+ const UCHAR *data,
+ ULONG length,
+ BOOLEAN tun,
+ const char *prefix,
+ LONG *counter
+ );
+
+#endif
+
+#endif
diff --git a/windows-tap/src/resource.rc b/windows-tap/src/resource.rc
new file mode 100755
index 00000000..b669c349
--- /dev/null
+++ b/windows-tap/src/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"
+#define VER_ORIGINALFILENAME_STR PRODUCT_TAP_WIN_COMPONENT_ID ".sys"
+#define VER_LEGALCOPYRIGHT_YEARS "2003-2010"
+#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-tap/src/tap-windows.h b/windows-tap/src/tap-windows.h
new file mode 100755
index 00000000..5c5bf5dd
--- /dev/null
+++ b/windows-tap/src/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-2010 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
diff --git a/windows-tap/src/tapdrvr.c b/windows-tap/src/tapdrvr.c
new file mode 100755
index 00000000..43eca58c
--- /dev/null
+++ b/windows-tap/src/tapdrvr.c
@@ -0,0 +1,3147 @@
+/*
+ * 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-2010 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 Win 2000 or higher
+// versions of Windows.
+//
+// It is SMP-safe and handles NDIS 5 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 "tap-windows.h"
+#include "config.h"
+
+#define NDIS_MINIPORT_DRIVER
+#define BINARY_COMPATIBLE 0
+#define NDIS50_MINIPORT 1
+#define NDIS_WDM 0
+#define NDIS50 1
+#define NTSTRSAFE_LIB
+
+// Debug info output
+#define ALSO_DBGPRINT 1
+#define DEBUGP_AT_DISPATCH 0
+
+//========================================================
+// 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
+
+#if defined(DDKVER_MAJOR) && DDKVER_MAJOR < 5600
+#include <ndis.h>
+#include <ntstrsafe.h>
+#include <ntddk.h>
+#else
+#include <ntifs.h>
+#include <ndis.h>
+#include <ntstrsafe.h>
+#endif
+
+#include "lock.h"
+#include "constants.h"
+#include "proto.h"
+#include "error.h"
+#include "endian.h"
+#include "dhcp.h"
+#include "types.h"
+#include "prototypes.h"
+
+#include "mem.c"
+#include "macinfo.c"
+#include "error.c"
+#include "dhcp.c"
+#include "instance.c"
+
+#define IS_UP(ta) \
+ ((ta)->m_InterfaceIsRunning && (ta)->m_Extension.m_TapIsRunning)
+
+#define INCREMENT_STAT(s) ++(s)
+
+#define NAME_BUFFER_SIZE 80
+
+//========================================================
+// Globals
+//========================================================
+
+NDIS_HANDLE g_NdisWrapperHandle;
+
+const UINT g_SupportedOIDList[] = {
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ OID_GEN_SUPPORTED_LIST
+};
+
+//============================================================
+// Driver Entry
+//============================================================
+#pragma NDIS_INIT_FUNCTION (DriverEntry)
+
+DRIVER_INITIALIZE DriverEntry;
+NTSTATUS
+DriverEntry (IN PDRIVER_OBJECT p_DriverObject,
+ IN PUNICODE_STRING p_RegistryPath)
+{
+ NDIS_STATUS l_Status = NDIS_STATUS_FAILURE;
+ NDIS_MINIPORT_CHARACTERISTICS *l_Properties = NULL;
+
+ //========================================================
+ // Notify NDIS that a new miniport driver is initializing.
+ //========================================================
+
+ NdisMInitializeWrapper (&g_NdisWrapperHandle,
+ p_DriverObject,
+ p_RegistryPath, NULL);
+
+ //======================
+ // Global initialization
+ //======================
+
+#if DBG
+ MyDebugInit (10000); // Allocate debugging text space
+#endif
+
+ if (!InitInstanceList ())
+ {
+ DEBUGP (("[TAP] Allocation failed for adapter instance list\n"));
+ goto cleanup;
+ }
+
+ //=======================================
+ // Set and register miniport entry points
+ //=======================================
+
+ l_Properties = MemAlloc (sizeof (NDIS_MINIPORT_CHARACTERISTICS), TRUE);
+
+ if (l_Properties == NULL)
+ {
+ DEBUGP (("[TAP] Allocation failed for miniport entry points\n"));
+ goto cleanup;
+ }
+
+ l_Properties->MajorNdisVersion = TAP_NDIS_MAJOR_VERSION;
+ l_Properties->MinorNdisVersion = TAP_NDIS_MINOR_VERSION;
+ l_Properties->InitializeHandler = AdapterCreate;
+ l_Properties->HaltHandler = AdapterHalt;
+ l_Properties->ResetHandler = AdapterReset; /* DISPATCH_LEVEL */
+ l_Properties->TransferDataHandler = AdapterReceive; /* DISPATCH_LEVEL */
+ l_Properties->SendHandler = AdapterTransmit; /* DISPATCH_LEVEL */
+ l_Properties->QueryInformationHandler = AdapterQuery; /* DISPATCH_LEVEL */
+ l_Properties->SetInformationHandler = AdapterModify; /* DISPATCH_LEVEL */
+
+ switch (l_Status =
+ NdisMRegisterMiniport (g_NdisWrapperHandle, l_Properties,
+ sizeof (NDIS_MINIPORT_CHARACTERISTICS)))
+ {
+ case NDIS_STATUS_SUCCESS:
+ {
+ DEBUGP (("[TAP] version [%d.%d] %s %s registered miniport successfully\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__));
+ DEBUGP (("Registry Path: '%.*S'\n", p_RegistryPath->Length/2, p_RegistryPath->Buffer));
+ break;
+ }
+
+ case NDIS_STATUS_BAD_CHARACTERISTICS:
+ {
+ DEBUGP (("[TAP] Miniport characteristics were badly defined\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+
+ case NDIS_STATUS_BAD_VERSION:
+ {
+ DEBUGP
+ (("[TAP] NDIS Version is wrong for the given characteristics\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+
+ case NDIS_STATUS_RESOURCES:
+ {
+ DEBUGP (("[TAP] Insufficient resources\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+
+ default:
+ case NDIS_STATUS_FAILURE:
+ {
+ DEBUGP (("[TAP] Unknown fatal registration error\n"));
+ NdisTerminateWrapper (g_NdisWrapperHandle, NULL);
+ break;
+ }
+ }
+
+ cleanup:
+ if (l_Properties)
+ MemFree (l_Properties, sizeof (NDIS_MINIPORT_CHARACTERISTICS));
+
+ if (l_Status == NDIS_STATUS_SUCCESS)
+ NdisMRegisterUnloadHandler (g_NdisWrapperHandle, TapDriverUnload);
+ else
+ TapDriverUnload (p_DriverObject);
+
+ return l_Status;
+}
+
+//============================================================
+// Driver Unload
+//============================================================
+DRIVER_UNLOAD TapDriverUnload;
+VOID
+TapDriverUnload (IN PDRIVER_OBJECT p_DriverObject)
+{
+ DEBUGP (("[TAP] version [%d.%d] %s %s unloaded, instances=%d, imbs=%d\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__,
+ NInstances(),
+ InstanceMaxBucketSize()));
+
+ FreeInstanceList ();
+
+ //==============================
+ // Free debugging text space
+ //==============================
+#if DBG
+ MyDebugFree ();
+#endif
+}
+
+//==========================================================
+// Adapter Initialization
+//==========================================================
+NDIS_STATUS AdapterCreate
+(OUT PNDIS_STATUS p_ErrorStatus,
+ OUT PUINT p_MediaIndex,
+ IN PNDIS_MEDIUM p_Media,
+ IN UINT p_MediaCount,
+ IN NDIS_HANDLE p_AdapterHandle,
+ IN NDIS_HANDLE p_ConfigurationHandle)
+{
+ TapAdapterPointer l_Adapter = NULL;
+
+ NDIS_MEDIUM l_PreferredMedium = NdisMedium802_3; // Ethernet
+ BOOLEAN l_MacFromRegistry = FALSE;
+ UINT l_Index;
+ NDIS_STATUS status;
+
+#if ENABLE_NONADMIN
+ BOOLEAN enable_non_admin = FALSE;
+#endif
+
+ DEBUGP (("[TAP] AdapterCreate called\n"));
+
+ //====================================
+ // Make sure adapter type is supported
+ //====================================
+
+ for (l_Index = 0;
+ l_Index < p_MediaCount && p_Media[l_Index] != l_PreferredMedium;
+ ++l_Index);
+
+ if (l_Index == p_MediaCount)
+ {
+ DEBUGP (("[TAP] Unsupported adapter type [wanted: %d]\n",
+ l_PreferredMedium));
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+ }
+
+ *p_MediaIndex = l_Index;
+
+ //=========================================
+ // Allocate memory for TapAdapter structure
+ //=========================================
+
+ l_Adapter = MemAlloc (sizeof (TapAdapter), TRUE);
+
+ if (l_Adapter == NULL)
+ {
+ DEBUGP (("[TAP] Couldn't allocate adapter memory\n"));
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ //==========================================
+ // Inform the NDIS library about significant
+ // features of our virtual NIC.
+ //==========================================
+
+ NdisMSetAttributesEx
+ (p_AdapterHandle,
+ (NDIS_HANDLE) l_Adapter,
+ 16,
+ NDIS_ATTRIBUTE_DESERIALIZE
+ | NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT
+ | NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT
+ | NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+ NdisInterfaceInternal);
+
+ //=====================================
+ // Initialize simple Adapter parameters
+ //=====================================
+
+ l_Adapter->m_Lookahead = DEFAULT_PACKET_LOOKAHEAD;
+ l_Adapter->m_Medium = l_PreferredMedium;
+ l_Adapter->m_DeviceState = '?';
+ l_Adapter->m_MiniportAdapterHandle = p_AdapterHandle;
+
+ //==================================
+ // Allocate spinlock for controlling
+ // access to multicast address list.
+ //==================================
+ NdisAllocateSpinLock (&l_Adapter->m_MCLock);
+ l_Adapter->m_MCLockAllocated = TRUE;
+
+ //====================================================
+ // Register a shutdown handler which will be called
+ // on system restart/shutdown to halt our virtual NIC.
+ //====================================================
+
+ NdisMRegisterAdapterShutdownHandler (p_AdapterHandle, l_Adapter,
+ AdapterHalt);
+ l_Adapter->m_RegisteredAdapterShutdownHandler = TRUE;
+
+ //============================================
+ // Get parameters from registry which were set
+ // in the adapter advanced properties dialog.
+ //============================================
+ {
+ NDIS_STATUS status;
+ NDIS_HANDLE configHandle;
+ NDIS_CONFIGURATION_PARAMETER *parm;
+
+ // set defaults in case our registry query fails
+ l_Adapter->m_MTU = ETHERNET_MTU;
+ l_Adapter->m_MediaStateAlwaysConnected = FALSE;
+ l_Adapter->m_MediaState = FALSE;
+
+ NdisOpenConfiguration (&status, &configHandle, p_ConfigurationHandle);
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] Couldn't open adapter registry\n"));
+ AdapterFreeResources (l_Adapter);
+ return status;
+ }
+
+ //====================================
+ // Allocate and construct adapter name
+ //====================================
+ {
+
+ NDIS_STRING mkey = NDIS_STRING_CONST("MiniportName");
+ NDIS_STRING vkey = NDIS_STRING_CONST("NdisVersion");
+ NDIS_STATUS vstatus;
+ NDIS_CONFIGURATION_PARAMETER *vparm;
+
+ NdisReadConfiguration (&vstatus, &vparm, configHandle, &vkey, NdisParameterInteger);
+ if (vstatus == NDIS_STATUS_SUCCESS)
+ DEBUGP (("[TAP] NdisReadConfiguration NdisVersion=%X\n", vparm->ParameterData.IntegerData));
+
+ NdisReadConfiguration (&status, &parm, configHandle, &mkey, NdisParameterString);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterString)
+ {
+ DEBUGP (("[TAP] NdisReadConfiguration (MiniportName=%.*S)\n",
+ parm->ParameterData.StringData.Length/2,
+ parm->ParameterData.StringData.Buffer));
+
+ if (RtlUnicodeStringToAnsiString (
+ &l_Adapter->m_NameAnsi,
+ &parm->ParameterData.StringData,
+ TRUE) != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] MiniportName failed\n"));
+ status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ }
+ else
+ {
+ /* "MiniportName" is available only XP and above. Not on Windows 2000. */
+ if (vstatus == NDIS_STATUS_SUCCESS && vparm->ParameterData.IntegerData == 0x50000)
+ {
+ /* Fallback for Windows 2000 with NDIS version 5.00.00
+ Don't use this on Vista, 'NDIS_MINIPORT_BLOCK' was changed! */
+ if (RtlUnicodeStringToAnsiString (&l_Adapter->m_NameAnsi,
+ &((struct WIN2K_NDIS_MINIPORT_BLOCK *) p_AdapterHandle)->MiniportName,
+ TRUE) != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] MiniportName (W2K) failed\n"));
+ status = NDIS_STATUS_RESOURCES;
+ }
+ else
+ {
+ DEBUGP (("[TAP] MiniportName (W2K) succeeded: %s\n", l_Adapter->m_NameAnsi.Buffer));
+ status = NDIS_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+
+ /* Can't continue without name (see macro 'NAME') */
+ if (status != NDIS_STATUS_SUCCESS || !l_Adapter->m_NameAnsi.Buffer)
+ {
+ NdisCloseConfiguration (configHandle);
+ AdapterFreeResources (l_Adapter);
+ DEBUGP (("[TAP] failed to get miniport name\n"));
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ /* Read MTU setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("MTU");
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterInteger)
+ {
+ int mtu = parm->ParameterData.IntegerData;
+ if (mtu < MINIMUM_MTU)
+ mtu = MINIMUM_MTU;
+ if (mtu > MAXIMUM_MTU)
+ mtu = MAXIMUM_MTU;
+ l_Adapter->m_MTU = mtu;
+ }
+ }
+ }
+
+ /* Read Media Status setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("MediaStatus");
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterInteger)
+ {
+ if (parm->ParameterData.IntegerData)
+ {
+ l_Adapter->m_MediaStateAlwaysConnected = TRUE;
+ l_Adapter->m_MediaState = TRUE;
+ }
+ }
+ }
+ }
+
+#if ENABLE_NONADMIN
+ /* Read AllowNonAdmin setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("AllowNonAdmin");
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterInteger);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterInteger)
+ {
+ if (parm->ParameterData.IntegerData)
+ {
+ enable_non_admin = TRUE;
+ }
+ }
+ }
+ }
+#endif
+
+ /* Read optional MAC setting from registry */
+ {
+ NDIS_STRING key = NDIS_STRING_CONST("MAC");
+ ANSI_STRING mac_string;
+ NdisReadConfiguration (&status, &parm, configHandle,
+ &key, NdisParameterString);
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (parm->ParameterType == NdisParameterString)
+ {
+ if (RtlUnicodeStringToAnsiString (&mac_string, &parm->ParameterData.StringData, TRUE) == STATUS_SUCCESS)
+ {
+ l_MacFromRegistry = ParseMAC (l_Adapter->m_MAC, mac_string.Buffer);
+ RtlFreeAnsiString (&mac_string);
+ }
+ }
+ }
+ }
+
+ NdisCloseConfiguration (configHandle);
+
+ DEBUGP (("[%s] MTU=%d\n", NAME (l_Adapter), l_Adapter->m_MTU));
+ }
+
+ //==================================
+ // Store and update MAC address info
+ //==================================
+
+ if (!l_MacFromRegistry)
+ GenerateRandomMac (l_Adapter->m_MAC, NAME (l_Adapter));
+
+ DEBUGP (("[%s] Using MAC %x:%x:%x:%x:%x:%x\n",
+ NAME (l_Adapter),
+ l_Adapter->m_MAC[0], l_Adapter->m_MAC[1], l_Adapter->m_MAC[2],
+ l_Adapter->m_MAC[3], l_Adapter->m_MAC[4], l_Adapter->m_MAC[5]));
+
+ //==================
+ // Set broadcast MAC
+ //==================
+ {
+ int i;
+ for (i = 0; i < sizeof (MACADDR); ++i)
+ l_Adapter->m_MAC_Broadcast[i] = 0xFF;
+ }
+
+ //====================================
+ // Initialize TAP device
+ //====================================
+ {
+ NDIS_STATUS tap_status;
+ tap_status = CreateTapDevice (&l_Adapter->m_Extension, NAME (l_Adapter));
+ if (tap_status != NDIS_STATUS_SUCCESS)
+ {
+ AdapterFreeResources (l_Adapter);
+ DEBUGP (("[TAP] CreateTapDevice failed\n"));
+ return tap_status;
+ }
+ }
+
+ if (!AddAdapterToInstanceList (l_Adapter))
+ {
+ NOTE_ERROR ();
+ TapDeviceFreeResources (&l_Adapter->m_Extension);
+ AdapterFreeResources (l_Adapter);
+ DEBUGP (("[TAP] AddAdapterToInstanceList failed\n"));
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ l_Adapter->m_InterfaceIsRunning = TRUE;
+
+#if ENABLE_NONADMIN
+ if (enable_non_admin)
+ AllowNonAdmin (&l_Adapter->m_Extension);
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+VOID
+AdapterHalt (IN NDIS_HANDLE p_AdapterContext)
+{
+ BOOLEAN status;
+
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+
+ NOTE_ERROR ();
+
+ l_Adapter->m_InterfaceIsRunning = FALSE;
+
+ DEBUGP (("[%s] is being halted\n", NAME (l_Adapter)));
+
+ DestroyTapDevice (&l_Adapter->m_Extension);
+
+ // Free resources
+ DEBUGP (("[%s] Freeing Resources\n", NAME (l_Adapter)));
+ AdapterFreeResources (l_Adapter);
+
+ status = RemoveAdapterFromInstanceList (l_Adapter);
+ DEBUGP (("[TAP] RemoveAdapterFromInstanceList returned %d\n", (int) status));
+
+ DEBUGP (("[TAP] version [%d.%d] %s %s AdapterHalt returning\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__));
+}
+
+VOID
+AdapterFreeResources (TapAdapterPointer p_Adapter)
+{
+ MYASSERT (!p_Adapter->m_CalledAdapterFreeResources);
+ p_Adapter->m_CalledAdapterFreeResources = TRUE;
+
+ if (p_Adapter->m_NameAnsi.Buffer)
+ RtlFreeAnsiString (&p_Adapter->m_NameAnsi);
+
+ if (p_Adapter->m_RegisteredAdapterShutdownHandler)
+ NdisMDeregisterAdapterShutdownHandler (p_Adapter->m_MiniportAdapterHandle);
+
+ if (p_Adapter->m_MCLockAllocated)
+ NdisFreeSpinLock (&p_Adapter->m_MCLock);
+}
+
+VOID
+DestroyTapDevice (TapExtensionPointer p_Extension)
+{
+ DEBUGP (("[%s] Destroying tap device\n", p_Extension->m_TapName));
+
+ //======================================
+ // Let clients know we are shutting down
+ //======================================
+ p_Extension->m_TapIsRunning = FALSE;
+ p_Extension->m_TapOpens = 0;
+ p_Extension->m_Halt = TRUE;
+
+ //=====================================
+ // If we are concurrently executing in
+ // TapDeviceHook or AdapterTransmit,
+ // give those calls time to finish.
+ // Note that we must be running at IRQL
+ // < DISPATCH_LEVEL in order to call
+ // NdisMSleep.
+ //=====================================
+ NdisMSleep (500000);
+
+ //===========================================================
+ // Exhaust IRP and packet queues. Any pending IRPs will
+ // be cancelled, causing user-space to get this error
+ // on overlapped reads:
+ // The I/O operation has been aborted because of either a
+ // thread exit or an application request. (code=995)
+ // It's important that user-space close the device handle
+ // when this code is returned, so that when we finally
+ // do a NdisMDeregisterDevice, the device reference count
+ // is 0. Otherwise the driver will not unload even if the
+ // the last adapter has been halted.
+ //===========================================================
+ FlushQueues (p_Extension);
+ NdisMSleep (500000); // give user space time to respond to IRP cancel
+
+ TapDeviceFreeResources (p_Extension);
+}
+
+VOID
+TapDeviceFreeResources (TapExtensionPointer p_Extension)
+{
+ MYASSERT (p_Extension);
+ MYASSERT (!p_Extension->m_CalledTapDeviceFreeResources);
+ p_Extension->m_CalledTapDeviceFreeResources = TRUE;
+
+ if (p_Extension->m_PacketQueue)
+ QueueFree (p_Extension->m_PacketQueue);
+ if (p_Extension->m_IrpQueue)
+ QueueFree (p_Extension->m_IrpQueue);
+ if (p_Extension->m_InjectQueue)
+ QueueFree (p_Extension->m_InjectQueue);
+
+ if (p_Extension->m_CreatedUnicodeLinkName)
+ RtlFreeUnicodeString (&p_Extension->m_UnicodeLinkName);
+
+ //==========================================================
+ // According to DDK docs, the device is not actually deleted
+ // until its reference count falls to zero. That means we
+ // still need to gracefully fail TapDeviceHook requests
+ // after this point, otherwise ugly things would happen if
+ // the device was disabled (e.g. in the network connections
+ // control panel) while a userspace app still held an open
+ // file handle to it.
+ //==========================================================
+
+ if (p_Extension->m_TapDevice)
+ {
+ BOOLEAN status;
+ status = (NdisMDeregisterDevice (p_Extension->m_TapDeviceHandle)
+ == NDIS_STATUS_SUCCESS);
+ DEBUGP (("[TAP] Deregistering TAP device, status=%d\n", (int)status));
+ }
+
+ if (p_Extension->m_TapName)
+ MemFree (p_Extension->m_TapName, NAME_BUFFER_SIZE);
+
+ if (p_Extension->m_InjectDpcInitialized)
+ KeRemoveQueueDpc (&p_Extension->m_InjectDpc);
+
+ if (p_Extension->m_AllocatedSpinlocks)
+ {
+ NdisFreeSpinLock (&p_Extension->m_QueueLock);
+ NdisFreeSpinLock (&p_Extension->m_InjectLock);
+ }
+}
+
+//========================================================================
+// Tap Device Initialization
+//========================================================================
+
+NDIS_STATUS
+CreateTapDevice (TapExtensionPointer p_Extension, const char *p_Name)
+{
+# define SIZEOF_DISPATCH (sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1))
+ PDRIVER_DISPATCH *l_Dispatch = NULL;
+ ANSI_STRING l_TapString, l_LinkString;
+ UNICODE_STRING l_TapUnicode;
+ BOOLEAN l_FreeTapUnicode = FALSE;
+ NTSTATUS l_Status, l_Return = NDIS_STATUS_SUCCESS;
+ const char *l_UsableName;
+
+ DEBUGP (("[TAP] version [%d.%d] creating tap device: %s\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ p_Name));
+
+ NdisZeroMemory (p_Extension, sizeof (TapExtension));
+
+ INIT_MUTEX (&p_Extension->m_OpenCloseMutex);
+
+ l_LinkString.Buffer = NULL;
+ l_TapString.Buffer = NULL;
+
+ l_TapString.MaximumLength = l_LinkString.MaximumLength = NAME_BUFFER_SIZE;
+
+ //=======================================
+ // Set TAP device entry points
+ //=======================================
+
+ if ((l_Dispatch = MemAlloc (SIZEOF_DISPATCH, TRUE)) == NULL)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP dispatch table\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ l_Dispatch[IRP_MJ_DEVICE_CONTROL] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_READ] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_WRITE] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_CREATE] = TapDeviceHook;
+ l_Dispatch[IRP_MJ_CLOSE] = TapDeviceHook;
+
+ //==================================
+ // Find the beginning of the GUID
+ //==================================
+ l_UsableName = p_Name;
+ while (*l_UsableName != '{')
+ {
+ if (*l_UsableName == '\0')
+ {
+ DEBUGP (("[%s] couldn't find leading '{' in name\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ ++l_UsableName;
+ }
+
+ //==================================
+ // Allocate pool for TAP device name
+ //==================================
+
+ if ((p_Extension->m_TapName = l_TapString.Buffer =
+ MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP name buffer\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ //================================================
+ // Allocate pool for TAP symbolic link name buffer
+ //================================================
+
+ if ((l_LinkString.Buffer =
+ MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP symbolic link name buffer\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ //=======================================================
+ // Set TAP device name
+ //=======================================================
+
+ l_Status = RtlStringCchPrintfExA
+ (l_TapString.Buffer,
+ l_TapString.MaximumLength,
+ NULL,
+ NULL,
+ STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
+ "%s%s%s",
+ SYSDEVICEDIR,
+ l_UsableName,
+ TAP_WIN_SUFFIX);
+
+ if (l_Status != STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't format TAP device name\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ l_TapString.Length = (USHORT) strlen (l_TapString.Buffer);
+
+ DEBUGP (("TAP DEV NAME: '%s'\n", l_TapString.Buffer));
+
+ //=======================================================
+ // Set TAP link name
+ //=======================================================
+
+ l_Status = RtlStringCchPrintfExA
+ (l_LinkString.Buffer,
+ l_LinkString.MaximumLength,
+ NULL,
+ NULL,
+ STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS,
+ "%s%s%s",
+ USERDEVICEDIR,
+ l_UsableName,
+ TAP_WIN_SUFFIX);
+
+ if (l_Status != STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't format TAP device symbolic link\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ l_LinkString.Length = (USHORT) strlen (l_LinkString.Buffer);
+
+ DEBUGP (("TAP LINK NAME: '%s'\n", l_LinkString.Buffer));
+
+ //==================================================
+ // Convert strings to unicode
+ //==================================================
+ if (RtlAnsiStringToUnicodeString (&l_TapUnicode, &l_TapString, TRUE) !=
+ STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP unicode name buffer\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ l_FreeTapUnicode = TRUE;
+
+ if (RtlAnsiStringToUnicodeString
+ (&p_Extension->m_UnicodeLinkName, &l_LinkString, TRUE)
+ != STATUS_SUCCESS)
+ {
+ DEBUGP
+ (("[%s] Couldn't allocate unicode string for symbolic link name\n",
+ p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+ p_Extension->m_CreatedUnicodeLinkName = TRUE;
+
+ //==================================================
+ // Create new TAP device with symbolic
+ // link and associate with adapter.
+ //==================================================
+
+ l_Status = NdisMRegisterDevice
+ (g_NdisWrapperHandle,
+ &l_TapUnicode,
+ &p_Extension->m_UnicodeLinkName,
+ l_Dispatch,
+ &p_Extension->m_TapDevice,
+ &p_Extension->m_TapDeviceHandle
+ );
+
+ if (l_Status != STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] couldn't be created\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ /* Set TAP device flags */
+ p_Extension->m_TapDevice->Flags |= DO_DIRECT_IO;
+
+ //========================================================
+ // Initialize Packet and IRP queues.
+ //
+ // The packet queue is used to buffer data which has been
+ // "transmitted" by the virtual NIC, before user space
+ // has had a chance to read it.
+ //
+ // The IRP queue is used to buffer pending I/O requests
+ // from userspace, i.e. read requests on the TAP device
+ // waiting for the system to "transmit" something through
+ // the virtual NIC.
+ //
+ // Basically, packets in the packet queue are used
+ // to satisfy IRP requests in the IRP queue.
+ //
+ // QueueLock is used to lock the packet queue used
+ // for the TAP-Windows NIC -> User Space packet flow direction.
+ //
+ // All accesses to packet or IRP queues should be
+ // bracketed by the QueueLock spinlock,
+ // in order to be SMP-safe.
+ //========================================================
+
+ NdisAllocateSpinLock (&p_Extension->m_QueueLock);
+ NdisAllocateSpinLock (&p_Extension->m_InjectLock);
+ p_Extension->m_AllocatedSpinlocks = TRUE;
+
+ p_Extension->m_PacketQueue = QueueInit (PACKET_QUEUE_SIZE);
+ p_Extension->m_IrpQueue = QueueInit (IRP_QUEUE_SIZE);
+ p_Extension->m_InjectQueue = QueueInit (INJECT_QUEUE_SIZE);
+ if (!p_Extension->m_PacketQueue
+ || !p_Extension->m_IrpQueue
+ || !p_Extension->m_InjectQueue)
+ {
+ DEBUGP (("[%s] couldn't alloc TAP queues\n", p_Name));
+ l_Return = NDIS_STATUS_RESOURCES;
+ goto cleanup;
+ }
+
+ //=================================================================
+ // Initialize deferred procedure call for DHCP/ARP packet injection
+ //=================================================================
+
+ KeInitializeDpc (&p_Extension->m_InjectDpc, InjectPacketDpc, NULL);
+ p_Extension->m_InjectDpcInitialized = TRUE;
+
+ //========================
+ // Finalize initialization
+ //========================
+
+ p_Extension->m_TapIsRunning = TRUE;
+
+ DEBUGP (("[%s] successfully created TAP device [%s]\n", p_Name,
+ p_Extension->m_TapName));
+
+ cleanup:
+ if (l_FreeTapUnicode)
+ RtlFreeUnicodeString (&l_TapUnicode);
+ if (l_LinkString.Buffer)
+ MemFree (l_LinkString.Buffer, NAME_BUFFER_SIZE);
+ if (l_Dispatch)
+ MemFree (l_Dispatch, SIZEOF_DISPATCH);
+
+ if (l_Return != NDIS_STATUS_SUCCESS)
+ TapDeviceFreeResources (p_Extension);
+
+ return l_Return;
+}
+#undef SIZEOF_DISPATCH
+
+//========================================================
+// Adapter Control
+//========================================================
+NDIS_STATUS
+AdapterReset (OUT PBOOLEAN p_AddressingReset, IN NDIS_HANDLE p_AdapterContext)
+{
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ DEBUGP (("[%s] is resetting\n", NAME (l_Adapter)));
+ return NDIS_STATUS_SUCCESS;
+}
+
+NDIS_STATUS AdapterReceive
+ (OUT PNDIS_PACKET p_Packet,
+ OUT PUINT p_Transferred,
+ IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_HANDLE p_ReceiveContext,
+ IN UINT p_Offset,
+ IN UINT p_ToTransfer)
+{
+ return NDIS_STATUS_SUCCESS;
+}
+
+//==============================================================
+// Adapter Option Query/Modification
+//==============================================================
+NDIS_STATUS AdapterQuery
+(IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesWritten, OUT PULONG p_BytesNeeded)
+{
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ TapAdapterQuery l_Query, *l_QueryPtr = &l_Query;
+ NDIS_STATUS l_Status = NDIS_STATUS_SUCCESS;
+ UINT l_QueryLength = 4;
+ BOOLEAN lock_succeeded;
+
+ NdisZeroMemory (&l_Query, sizeof (l_Query));
+
+ switch (p_OID)
+ {
+ //===================================================================
+ // Vendor & Driver version Info
+ //===================================================================
+ case OID_GEN_VENDOR_DESCRIPTION:
+ l_QueryPtr = (TapAdapterQueryPointer) PRODUCT_TAP_WIN_DEVICE_DESCRIPTION;
+ l_QueryLength = strlen (PRODUCT_TAP_WIN_DEVICE_DESCRIPTION) + 1;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ l_Query.m_Long = 0xffffff;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ l_Query.m_Short =
+ (((USHORT) TAP_NDIS_MAJOR_VERSION) << 8 | (USHORT)
+ TAP_NDIS_MINOR_VERSION);
+ l_QueryLength = sizeof (unsigned short);
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ l_Query.m_Long =
+ (((USHORT) PRODUCT_TAP_WIN_MAJOR) << 8 | (USHORT)
+ PRODUCT_TAP_WIN_MINOR);
+ break;
+
+ //=================================================================
+ // Statistics
+ //=================================================================
+ case OID_GEN_RCV_NO_BUFFER:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+ l_Query.m_Long = 0;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ l_Query.m_Long = l_Adapter->m_Tx;
+ break;
+
+ case OID_GEN_RCV_OK:
+ l_Query.m_Long = l_Adapter->m_Rx;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ l_Query.m_Long = l_Adapter->m_TxErr;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ l_Query.m_Long = l_Adapter->m_RxErr;
+ break;
+
+ //===================================================================
+ // Device & Protocol Options
+ //===================================================================
+ case OID_GEN_SUPPORTED_LIST:
+ l_QueryPtr = (TapAdapterQueryPointer) g_SupportedOIDList;
+ l_QueryLength = sizeof (g_SupportedOIDList);
+ break;
+
+ case OID_GEN_MAC_OPTIONS:
+ // This MUST be here !!!
+ l_Query.m_Long = (NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+ | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA
+ | NDIS_MAC_OPTION_NO_LOOPBACK
+ | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND);
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ l_Query.m_Long =
+ (NDIS_PACKET_TYPE_ALL_LOCAL |
+ NDIS_PACKET_TYPE_BROADCAST |
+ NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL);
+
+ break;
+
+ case OID_GEN_PROTOCOL_OPTIONS:
+ l_Query.m_Long = 0;
+ break;
+
+ //==================================================================
+ // Device Info
+ //==================================================================
+ case OID_GEN_MEDIA_CONNECT_STATUS:
+ l_Query.m_Long = l_Adapter->m_MediaState
+ ? NdisMediaStateConnected : NdisMediaStateDisconnected;
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+ l_Query.m_HardwareStatus = NdisHardwareStatusReady;
+ l_QueryLength = sizeof (NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ case OID_GEN_MEDIA_IN_USE:
+ l_Query.m_Medium = l_Adapter->m_Medium;
+ l_QueryLength = sizeof (NDIS_MEDIUM);
+ break;
+
+ case OID_GEN_PHYSICAL_MEDIUM:
+ l_Query.m_PhysicalMedium = NdisPhysicalMediumUnspecified;
+ l_QueryLength = sizeof (NDIS_PHYSICAL_MEDIUM);
+ break;
+
+ case OID_GEN_LINK_SPEED:
+ l_Query.m_Long = 100000; // rate / 100 bps
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ COPY_MAC (l_Query.m_MacAddress, l_Adapter->m_MAC);
+ l_QueryLength = sizeof (MACADDR);
+ break;
+
+ //==================================================================
+ // Limits
+ //==================================================================
+
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ l_Query.m_Long = 1;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ l_Query.m_Long = NIC_MAX_MCAST_LIST;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ l_Query.m_Long = l_Adapter->m_Lookahead;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ l_Query.m_Long = DEFAULT_PACKET_LOOKAHEAD;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ l_Query.m_Long = l_Adapter->m_MTU;
+ break;
+
+ case OID_PNP_CAPABILITIES:
+ do
+ {
+ PNDIS_PNP_CAPABILITIES pPNPCapabilities;
+ PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct;
+
+ if (p_BufferLength >= sizeof (NDIS_PNP_CAPABILITIES))
+ {
+ pPNPCapabilities = (PNDIS_PNP_CAPABILITIES) (p_Buffer);
+
+ //
+ // Setting up the buffer to be returned
+ // to the Protocol above the Passthru miniport
+ //
+ pPMstruct = &pPNPCapabilities->WakeUpCapabilities;
+ pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+ }
+ l_QueryLength = sizeof (NDIS_PNP_CAPABILITIES);
+ }
+ while (FALSE);
+ break;
+ case OID_PNP_QUERY_POWER:
+ break;
+
+ // Required OIDs that we don't support
+
+ case OID_GEN_SUPPORTED_GUIDS:
+ case OID_GEN_MEDIA_CAPABILITIES:
+ case OID_TCP_TASK_OFFLOAD:
+ case OID_FFP_SUPPORT:
+ l_Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ // Optional stats OIDs
+
+ case OID_GEN_DIRECTED_BYTES_XMIT:
+ case OID_GEN_DIRECTED_FRAMES_XMIT:
+ case OID_GEN_MULTICAST_BYTES_XMIT:
+ case OID_GEN_MULTICAST_FRAMES_XMIT:
+ case OID_GEN_BROADCAST_BYTES_XMIT:
+ case OID_GEN_BROADCAST_FRAMES_XMIT:
+ case OID_GEN_DIRECTED_BYTES_RCV:
+ case OID_GEN_DIRECTED_FRAMES_RCV:
+ case OID_GEN_MULTICAST_BYTES_RCV:
+ case OID_GEN_MULTICAST_FRAMES_RCV:
+ case OID_GEN_BROADCAST_BYTES_RCV:
+ case OID_GEN_BROADCAST_FRAMES_RCV:
+ l_Status = NDIS_STATUS_INVALID_OID;
+ break;
+
+ //===================================================================
+ // Not Handled
+ //===================================================================
+ default:
+ DEBUGP (("[%s] Unhandled OID %lx\n", NAME (l_Adapter), p_OID));
+ l_Status = NDIS_STATUS_INVALID_OID;
+ break;
+ }
+
+ if (l_Status != NDIS_STATUS_SUCCESS)
+ ;
+ else if (l_QueryLength > p_BufferLength)
+ {
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ *p_BytesNeeded = l_QueryLength;
+ }
+ else
+ NdisMoveMemory (p_Buffer, (PVOID) l_QueryPtr,
+ (*p_BytesWritten = l_QueryLength));
+
+ return l_Status;
+}
+
+NDIS_STATUS AdapterModify
+(IN NDIS_HANDLE p_AdapterContext,
+ IN NDIS_OID p_OID,
+ IN PVOID p_Buffer,
+ IN ULONG p_BufferLength,
+ OUT PULONG p_BytesRead,
+ OUT PULONG p_BytesNeeded)
+{
+ TapAdapterQueryPointer l_Query = (TapAdapterQueryPointer) p_Buffer;
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ NDIS_STATUS l_Status = NDIS_STATUS_INVALID_OID;
+ ULONG l_Long;
+
+ switch (p_OID)
+ {
+ //==================================================================
+ // Device Info
+ //==================================================================
+ case OID_802_3_MULTICAST_LIST:
+ DEBUGP (("[%s] Setting [OID_802_3_MULTICAST_LIST]\n",
+ NAME (l_Adapter)));
+
+ *p_BytesNeeded = sizeof (ETH_ADDR);
+ *p_BytesRead = p_BufferLength;
+
+ if (p_BufferLength % sizeof (ETH_ADDR))
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ else if (p_BufferLength > sizeof (MC_LIST))
+ {
+ l_Status = NDIS_STATUS_MULTICAST_FULL;
+ *p_BytesNeeded = sizeof (MC_LIST);
+ }
+ else
+ {
+ NdisAcquireSpinLock (&l_Adapter->m_MCLock);
+
+ NdisZeroMemory(&l_Adapter->m_MCList, sizeof (MC_LIST));
+
+ NdisMoveMemory(&l_Adapter->m_MCList,
+ p_Buffer,
+ p_BufferLength);
+
+ l_Adapter->m_MCListSize = p_BufferLength / sizeof (ETH_ADDR);
+
+ NdisReleaseSpinLock (&l_Adapter->m_MCLock);
+
+ l_Status = NDIS_STATUS_SUCCESS;
+ }
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ *p_BytesNeeded = 4;
+
+ if (p_BufferLength >= sizeof (ULONG))
+ {
+ DEBUGP
+ (("[%s] Setting [OID_GEN_CURRENT_PACKET_FILTER] to [0x%02lx]\n",
+ NAME (l_Adapter), l_Query->m_Long));
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = sizeof (ULONG);
+ }
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (p_BufferLength < sizeof (ULONG))
+ {
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ *p_BytesNeeded = 4;
+ }
+ else if (l_Query->m_Long > DEFAULT_PACKET_LOOKAHEAD
+ || l_Query->m_Long <= 0)
+ {
+ l_Status = NDIS_STATUS_INVALID_DATA;
+ }
+ else
+ {
+ DEBUGP (("[%s] Setting [OID_GEN_CURRENT_LOOKAHEAD] to [%d]\n",
+ NAME (l_Adapter), l_Query->m_Long));
+ l_Adapter->m_Lookahead = l_Query->m_Long;
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = sizeof (ULONG);
+ }
+ break;
+
+ case OID_GEN_NETWORK_LAYER_ADDRESSES:
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+
+ case OID_GEN_TRANSPORT_HEADER_OFFSET:
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+
+ case OID_PNP_SET_POWER:
+ do
+ {
+ NDIS_DEVICE_POWER_STATE NewDeviceState;
+
+ NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE) p_Buffer);
+
+ switch (NewDeviceState)
+ {
+ case NdisDeviceStateD0:
+ l_Adapter->m_DeviceState = '0';
+ break;
+ case NdisDeviceStateD1:
+ l_Adapter->m_DeviceState = '1';
+ break;
+ case NdisDeviceStateD2:
+ l_Adapter->m_DeviceState = '2';
+ break;
+ case NdisDeviceStateD3:
+ l_Adapter->m_DeviceState = '3';
+ break;
+ default:
+ l_Adapter->m_DeviceState = '?';
+ break;
+ }
+
+ l_Status = NDIS_STATUS_FAILURE;
+
+ //
+ // Check for invalid length
+ //
+ if (p_BufferLength < sizeof (NDIS_DEVICE_POWER_STATE))
+ {
+ l_Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ if (NewDeviceState > NdisDeviceStateD0)
+ {
+ l_Adapter->m_InterfaceIsRunning = FALSE;
+ DEBUGP (("[%s] Power management device state OFF\n",
+ NAME (l_Adapter)));
+ }
+ else
+ {
+ l_Adapter->m_InterfaceIsRunning = TRUE;
+ DEBUGP (("[%s] Power management device state ON\n",
+ NAME (l_Adapter)));
+ }
+
+ l_Status = NDIS_STATUS_SUCCESS;
+ }
+ while (FALSE);
+
+ if (l_Status == NDIS_STATUS_SUCCESS)
+ {
+ *p_BytesRead = sizeof (NDIS_DEVICE_POWER_STATE);
+ *p_BytesNeeded = 0;
+ }
+ else
+ {
+ *p_BytesRead = 0;
+ *p_BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+ }
+ break;
+
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ l_Status = NDIS_STATUS_SUCCESS;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+
+ default:
+ DEBUGP (("[%s] Can't set value for OID %lx\n", NAME (l_Adapter),
+ p_OID));
+ l_Status = NDIS_STATUS_INVALID_OID;
+ *p_BytesRead = *p_BytesNeeded = 0;
+ break;
+ }
+
+ return l_Status;
+}
+
+// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum
+// see RFC 4443, 2.3, and RFC 2460, 8.1
+USHORT
+icmpv6_checksum (const UCHAR *buf,
+ const int len_icmpv6,
+ const UCHAR *saddr6,
+ 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( TapAdapterPointer p_Adapter, 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(ETH_P_IPV6);
+ COPY_MAC(na->eth.dest, p_Adapter->m_MAC);
+ COPY_MAC(na->eth.src, p_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;
+ COPY_MAC( na->icmpv6.target_macaddr, p_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));
+
+ InjectPacketDeferred (p_Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT));
+
+ MemFree (na, sizeof (ICMPV6_NA_PKT));
+
+ return TRUE; // all fine
+}
+
+//====================================================================
+// Adapter Transmission
+//====================================================================
+NDIS_STATUS
+AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
+ IN PNDIS_PACKET p_Packet,
+ IN UINT p_Flags)
+{
+ TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext;
+ ULONG l_Index = 0, l_PacketLength = 0;
+ UINT l_BufferLength = 0;
+ PIRP l_IRP;
+ TapPacketPointer l_PacketBuffer;
+ PNDIS_BUFFER l_NDIS_Buffer;
+ PUCHAR l_Buffer;
+ PVOID result;
+
+ NdisQueryPacket (p_Packet, NULL, NULL, &l_NDIS_Buffer, &l_PacketLength);
+
+ //====================================================
+ // Here we abandon the transmission attempt if any of
+ // the parameters is wrong or memory allocation fails
+ // but we do not indicate failure. The packet is
+ // silently dropped.
+ //====================================================
+
+ if (l_PacketLength < ETHERNET_HEADER_SIZE || l_PacketLength > 65535)
+ goto exit_fail;
+ else if (!l_Adapter->m_Extension.m_TapOpens || !l_Adapter->m_MediaState)
+ goto exit_success; // Nothing is bound to the TAP device
+
+ if (NdisAllocateMemoryWithTag (&l_PacketBuffer,
+ TAP_PACKET_SIZE (l_PacketLength),
+ '5PAT') != NDIS_STATUS_SUCCESS)
+ goto exit_no_resources;
+
+ if (l_PacketBuffer == NULL)
+ goto exit_no_resources;
+
+ l_PacketBuffer->m_SizeFlags = (l_PacketLength & TP_SIZE_MASK);
+
+ //===========================
+ // Reassemble packet contents
+ //===========================
+
+ __try
+ {
+ l_Index = 0;
+ while (l_NDIS_Buffer && l_Index < l_PacketLength)
+ {
+ ULONG newlen;
+ NdisQueryBuffer (l_NDIS_Buffer, (PVOID *) & l_Buffer,
+ &l_BufferLength);
+ newlen = l_Index + l_BufferLength;
+ if (newlen > l_PacketLength)
+ {
+ NOTE_ERROR ();
+ goto no_queue; /* overflow */
+ }
+ NdisMoveMemory (l_PacketBuffer->m_Data + l_Index, l_Buffer,
+ l_BufferLength);
+ l_Index = newlen;
+ NdisGetNextBuffer (l_NDIS_Buffer, &l_NDIS_Buffer);
+ }
+ if (l_Index != l_PacketLength)
+ {
+ NOTE_ERROR ();
+ goto no_queue; /* underflow */
+ }
+
+ DUMP_PACKET ("AdapterTransmit", l_PacketBuffer->m_Data, l_PacketLength);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify (l_PacketBuffer->m_Data, l_PacketLength, FALSE, "TX", &l_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 (l_Adapter->m_dhcp_enabled)
+ {
+ const ETH_HEADER *eth = (ETH_HEADER *) l_PacketBuffer->m_Data;
+ const IPHDR *ip = (IPHDR *) (l_PacketBuffer->m_Data + sizeof (ETH_HEADER));
+ const UDPHDR *udp = (UDPHDR *) (l_PacketBuffer->m_Data + sizeof (ETH_HEADER) + sizeof (IPHDR));
+
+ // ARP packet?
+ if (l_PacketLength == sizeof (ARP_PACKET)
+ && eth->proto == htons (ETH_P_ARP)
+ && l_Adapter->m_dhcp_server_arp)
+ {
+ if (ProcessARP (l_Adapter,
+ (PARP_PACKET) l_PacketBuffer->m_Data,
+ l_Adapter->m_dhcp_addr,
+ l_Adapter->m_dhcp_server_ip,
+ ~0,
+ l_Adapter->m_dhcp_server_mac))
+ goto no_queue;
+ }
+
+ // DHCP packet?
+ else if (l_PacketLength >= sizeof (ETH_HEADER) + sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP)
+ && eth->proto == htons (ETH_P_IP)
+ && ip->version_len == 0x45 // IPv4, 20 byte header
+ && ip->protocol == IPPROTO_UDP
+ && udp->dest == htons (BOOTPS_PORT))
+ {
+ const DHCP *dhcp = (DHCP *) (l_PacketBuffer->m_Data
+ + sizeof (ETH_HEADER)
+ + sizeof (IPHDR)
+ + sizeof (UDPHDR));
+
+ const int optlen = l_PacketLength
+ - sizeof (ETH_HEADER)
+ - sizeof (IPHDR)
+ - sizeof (UDPHDR)
+ - sizeof (DHCP);
+
+ if (optlen > 0) // we must have at least one DHCP option
+ {
+ if (ProcessDHCP (l_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 (l_Adapter->m_tun)
+ {
+ ETH_HEADER *e;
+
+ if (l_PacketLength < ETHERNET_HEADER_SIZE)
+ goto no_queue;
+
+ e = (ETH_HEADER *) l_PacketBuffer->m_Data;
+
+ switch (ntohs (e->proto))
+ {
+ case ETH_P_ARP:
+
+ // Make sure that packet is the
+ // right size for ARP.
+ if (l_PacketLength != sizeof (ARP_PACKET))
+ goto no_queue;
+
+ ProcessARP (l_Adapter,
+ (PARP_PACKET) l_PacketBuffer->m_Data,
+ l_Adapter->m_localIP,
+ l_Adapter->m_remoteNetwork,
+ l_Adapter->m_remoteNetmask,
+ l_Adapter->m_TapToUser.dest);
+
+ default:
+ goto no_queue;
+
+ case ETH_P_IP:
+
+ // Make sure that packet is large
+ // enough to be IPv4.
+ if (l_PacketLength
+ < ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)
+ goto no_queue;
+
+ // Only accept directed packets,
+ // not broadcasts.
+ if (memcmp (e, &l_Adapter->m_TapToUser, ETHERNET_HEADER_SIZE))
+ goto no_queue;
+
+ // Packet looks like IPv4, queue it.
+ l_PacketBuffer->m_SizeFlags |= TP_TUN;
+ break;
+
+ case ETH_P_IPV6:
+ // make sure that packet is large
+ // enough to be IPv6
+ if (l_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( l_Adapter,
+ l_PacketBuffer->m_Data ))
+ {
+ goto no_queue;
+ }
+
+ // Packet looks like IPv6, queue it :-)
+ l_PacketBuffer->m_SizeFlags |= TP_TUN;
+ }
+ }
+
+ //===============================================
+ // Push packet onto queue to wait for read from
+ // userspace.
+ //===============================================
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ result = NULL;
+ if (IS_UP (l_Adapter))
+ result = QueuePush (l_Adapter->m_Extension.m_PacketQueue, l_PacketBuffer);
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if ((TapPacketPointer) result != l_PacketBuffer)
+ {
+ // adapter receive overrun
+ INCREMENT_STAT (l_Adapter->m_TxErr);
+ goto no_queue;
+ }
+ else
+ {
+ INCREMENT_STAT (l_Adapter->m_Tx);
+ }
+
+ //============================================================
+ // Cycle through IRPs and packets, try to satisfy each pending
+ // IRP with a queued packet.
+ //============================================================
+ while (TRUE)
+ {
+ l_IRP = NULL;
+ l_PacketBuffer = NULL;
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (IS_UP (l_Adapter)
+ && QueueCount (l_Adapter->m_Extension.m_PacketQueue)
+ && QueueCount (l_Adapter->m_Extension.m_IrpQueue))
+ {
+ l_IRP = (PIRP) QueuePop (l_Adapter->m_Extension.m_IrpQueue);
+ l_PacketBuffer = (TapPacketPointer)
+ QueuePop (l_Adapter->m_Extension.m_PacketQueue);
+ }
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ MYASSERT ((l_IRP != NULL) + (l_PacketBuffer != NULL) != 1);
+
+ if (l_IRP && l_PacketBuffer)
+ {
+ CompleteIRP (l_IRP,
+ l_PacketBuffer,
+ IO_NETWORK_INCREMENT);
+ }
+ else
+ break;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+
+ return NDIS_STATUS_SUCCESS;
+
+ no_queue:
+ NdisFreeMemory (l_PacketBuffer,
+ TAP_PACKET_SIZE (l_PacketLength),
+ 0);
+
+ exit_success:
+ return NDIS_STATUS_SUCCESS;
+
+ exit_fail:
+ return NDIS_STATUS_FAILURE;
+
+ exit_no_resources:
+ return NDIS_STATUS_RESOURCES;
+}
+
+//======================================================================
+// Hooks for catching TAP device IRP's.
+//======================================================================
+
+DRIVER_DISPATCH TapDeviceHook;
+NTSTATUS
+TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
+{
+ TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject);
+ PIO_STACK_LOCATION l_IrpSp;
+ NTSTATUS l_Status = STATUS_SUCCESS;
+ BOOLEAN accessible;
+
+ l_IrpSp = IoGetCurrentIrpStackLocation (p_IRP);
+
+ p_IRP->IoStatus.Status = STATUS_SUCCESS;
+ p_IRP->IoStatus.Information = 0;
+
+ if (!l_Adapter || l_Adapter->m_Extension.m_Halt)
+ {
+ DEBUGP (("TapDeviceHook called when TAP device is halted, MajorFunction=%d\n",
+ (int)l_IrpSp->MajorFunction));
+
+ if (l_IrpSp->MajorFunction == IRP_MJ_CLOSE)
+ {
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ p_IRP->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ return STATUS_NO_SUCH_DEVICE;
+ }
+ }
+
+ switch (l_IrpSp->MajorFunction)
+ {
+ //===========================================================
+ // Ioctl call handlers
+ //===========================================================
+ case IRP_MJ_DEVICE_CONTROL:
+ {
+ switch (l_IrpSp->Parameters.DeviceIoControl.IoControlCode)
+ {
+ case TAP_WIN_IOCTL_GET_MAC:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
+ >= sizeof (MACADDR))
+ {
+ COPY_MAC (p_IRP->AssociatedIrp.SystemBuffer,
+ l_Adapter->m_MAC);
+ p_IRP->IoStatus.Information = sizeof (MACADDR);
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+ case TAP_WIN_IOCTL_GET_VERSION:
+ {
+ const ULONG size = sizeof (ULONG) * 3;
+ if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
+ >= size)
+ {
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0]
+ = TAP_DRIVER_MAJOR_VERSION;
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[1]
+ = TAP_DRIVER_MINOR_VERSION;
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[2]
+#if DBG
+ = 1;
+#else
+ = 0;
+#endif
+ p_IRP->IoStatus.Information = size;
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+ }
+ case TAP_WIN_IOCTL_GET_MTU:
+ {
+ const ULONG size = sizeof (ULONG) * 1;
+ if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength
+ >= size)
+ {
+ ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0]
+ = l_Adapter->m_MTU;
+ p_IRP->IoStatus.Information = size;
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+ }
+ case TAP_WIN_IOCTL_GET_INFO:
+ {
+ char state[16];
+ if (l_Adapter->m_InterfaceIsRunning)
+ state[0] = 'A';
+ else
+ state[0] = 'a';
+ if (l_Adapter->m_Extension.m_TapIsRunning)
+ state[1] = 'T';
+ else
+ state[1] = 't';
+ state[2] = l_Adapter->m_DeviceState;
+ if (l_Adapter->m_MediaStateAlwaysConnected)
+ state[3] = 'C';
+ else
+ state[3] = 'c';
+ state[4] = '\0';
+
+ p_IRP->IoStatus.Status = l_Status = RtlStringCchPrintfExA (
+ ((LPTSTR) (p_IRP->AssociatedIrp.SystemBuffer)),
+ l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ 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)l_Adapter->m_Extension.m_NumTapOpens,
+ (int)l_Adapter->m_Tx,
+ (int)l_Adapter->m_TxErr,
+#if PACKET_TRUNCATION_CHECK
+ (int)l_Adapter->m_TxTrunc,
+#endif
+ (int)l_Adapter->m_Rx,
+ (int)l_Adapter->m_RxErr,
+#if PACKET_TRUNCATION_CHECK
+ (int)l_Adapter->m_RxTrunc,
+#endif
+ (int)l_Adapter->m_Extension.m_IrpQueue->size,
+ (int)l_Adapter->m_Extension.m_IrpQueue->max_size,
+ (int)IRP_QUEUE_SIZE,
+ (int)l_Adapter->m_Extension.m_PacketQueue->size,
+ (int)l_Adapter->m_Extension.m_PacketQueue->max_size,
+ (int)PACKET_QUEUE_SIZE,
+ (int)l_Adapter->m_Extension.m_InjectQueue->size,
+ (int)l_Adapter->m_Extension.m_InjectQueue->max_size,
+ (int)INJECT_QUEUE_SIZE
+ );
+
+ p_IRP->IoStatus.Information
+ = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ break;
+ }
+
+#if DBG
+ case TAP_WIN_IOCTL_GET_LOG_LINE:
+ {
+ if (GetDebugLine ((LPTSTR)p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength))
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ else
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+
+ p_IRP->IoStatus.Information
+ = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ break;
+ }
+#endif
+
+ case TAP_WIN_IOCTL_CONFIG_TUN:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (IPADDR) * 3))
+ {
+ MACADDR dest;
+
+ l_Adapter->m_tun = FALSE;
+
+ GenerateRelatedMAC (dest, l_Adapter->m_MAC, 1);
+
+ l_Adapter->m_localIP = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ l_Adapter->m_remoteNetwork = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+ l_Adapter->m_remoteNetmask = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[2];
+
+ // sanity check on network/netmask
+ if ((l_Adapter->m_remoteNetwork & l_Adapter->m_remoteNetmask) != l_Adapter->m_remoteNetwork)
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ COPY_MAC (l_Adapter->m_TapToUser.src, l_Adapter->m_MAC);
+ COPY_MAC (l_Adapter->m_TapToUser.dest, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.src, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
+
+ l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+ l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
+ l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
+
+ l_Adapter->m_tun = TRUE;
+
+ CheckIfDhcpAndTunMode (l_Adapter);
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ case TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: // Obsoleted by TAP_WIN_IOCTL_CONFIG_TUN
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (IPADDR) * 2))
+ {
+ MACADDR dest;
+
+ l_Adapter->m_tun = FALSE;
+
+ GenerateRelatedMAC (dest, l_Adapter->m_MAC, 1);
+
+ l_Adapter->m_localIP = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ l_Adapter->m_remoteNetwork = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+ l_Adapter->m_remoteNetmask = ~0;
+
+ COPY_MAC (l_Adapter->m_TapToUser.src, l_Adapter->m_MAC);
+ COPY_MAC (l_Adapter->m_TapToUser.dest, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.src, dest);
+ COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
+
+ l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+ l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
+ l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
+
+ l_Adapter->m_tun = TRUE;
+
+ CheckIfDhcpAndTunMode (l_Adapter);
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ case TAP_WIN_IOCTL_SET_MEDIA_STATUS:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (ULONG) * 1))
+ {
+ ULONG parm = ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ SetMediaStatus (l_Adapter, (BOOLEAN) parm);
+ p_IRP->IoStatus.Information = 1;
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+ break;
+ }
+
+ case TAP_WIN_IOCTL_CONFIG_DHCP_MASQ:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
+ (sizeof (IPADDR) * 4))
+ {
+ l_Adapter->m_dhcp_enabled = FALSE;
+ l_Adapter->m_dhcp_server_arp = FALSE;
+ l_Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+
+ // Adapter IP addr / netmask
+ l_Adapter->m_dhcp_addr =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0];
+ l_Adapter->m_dhcp_netmask =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1];
+
+ // IP addr of DHCP masq server
+ l_Adapter->m_dhcp_server_ip =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[2];
+
+ // Lease time in seconds
+ l_Adapter->m_dhcp_lease_time =
+ ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[3];
+
+ GenerateRelatedMAC (l_Adapter->m_dhcp_server_mac, l_Adapter->m_MAC, 2);
+
+ l_Adapter->m_dhcp_enabled = TRUE;
+ l_Adapter->m_dhcp_server_arp = TRUE;
+
+ CheckIfDhcpAndTunMode (l_Adapter);
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ case TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT:
+ {
+ if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength <=
+ DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE
+ && l_Adapter->m_dhcp_enabled)
+ {
+ l_Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+
+ NdisMoveMemory (l_Adapter->m_dhcp_user_supplied_options_buffer,
+ p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.DeviceIoControl.InputBufferLength);
+
+ l_Adapter->m_dhcp_user_supplied_options_buffer_len =
+ l_IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+ p_IRP->IoStatus.Information = 1; // Simple boolean value
+ }
+ else
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ }
+
+ break;
+ }
+
+ default:
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //===========================================================
+ // User mode thread issued a read request on the tap device
+ // If there are packets waiting to be read, then the request
+ // will be satisfied here. If not, then the request will be
+ // queued and satisfied by any packet that is not used to
+ // satisfy requests ahead of it.
+ //===========================================================
+ case IRP_MJ_READ:
+ {
+ TapPacketPointer l_PacketBuffer;
+ BOOLEAN pending = FALSE;
+
+ // Save IRP-accessible copy of buffer length
+ p_IRP->IoStatus.Information = l_IrpSp->Parameters.Read.Length;
+
+ if (p_IRP->MdlAddress == NULL)
+ {
+ DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+ else if ((p_IRP->AssociatedIrp.SystemBuffer =
+ MmGetSystemAddressForMdlSafe
+ (p_IRP->MdlAddress, NormalPagePriority)) == NULL)
+ {
+ DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+ else if (!l_Adapter->m_InterfaceIsRunning)
+ {
+ DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //==================================
+ // Can we provide immediate service?
+ //==================================
+
+ l_PacketBuffer = NULL;
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (IS_UP (l_Adapter)
+ && QueueCount (l_Adapter->m_Extension.m_PacketQueue)
+ && QueueCount (l_Adapter->m_Extension.m_IrpQueue) == 0)
+ {
+ l_PacketBuffer = (TapPacketPointer)
+ QueuePop (l_Adapter->m_Extension.m_PacketQueue);
+ }
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (l_PacketBuffer)
+ {
+ l_Status = CompleteIRP (p_IRP,
+ l_PacketBuffer,
+ IO_NO_INCREMENT);
+ break;
+ }
+
+ //=============================
+ // Attempt to pend read request
+ //=============================
+
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (IS_UP (l_Adapter)
+ && QueuePush (l_Adapter->m_Extension.m_IrpQueue, p_IRP) == (PIRP) p_IRP)
+ {
+ IoSetCancelRoutine (p_IRP, CancelIRPCallback);
+ l_Status = STATUS_PENDING;
+ IoMarkIrpPending (p_IRP);
+ pending = TRUE;
+ }
+
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock);
+
+ if (pending)
+ break;
+
+ // Can't queue anymore IRP's
+ DEBUGP (("[%s] TAP [%s] read IRP overrun\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapName));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //==============================================================
+ // User mode issued a WriteFile request on the TAP file handle.
+ // The request will always get satisfied here. The call may
+ // fail if there are too many pending packets (queue full).
+ //==============================================================
+ case IRP_MJ_WRITE:
+ {
+ if (p_IRP->MdlAddress == NULL)
+ {
+ DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else if ((p_IRP->AssociatedIrp.SystemBuffer =
+ MmGetSystemAddressForMdlSafe
+ (p_IRP->MdlAddress, NormalPagePriority)) == NULL)
+ {
+ DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else if (!l_Adapter->m_InterfaceIsRunning)
+ {
+ DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else if (!l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
+ {
+ __try
+ {
+ p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
+
+ DUMP_PACKET ("IRP_MJ_WRITE ETH",
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify ((unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length,
+ FALSE,
+ "RX",
+ &l_Adapter->m_RxTrunc);
+#endif
+
+ NdisMEthIndicateReceive
+ (l_Adapter->m_MiniportAdapterHandle,
+ (NDIS_HANDLE) l_Adapter,
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ ETHERNET_HEADER_SIZE,
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer + ETHERNET_HEADER_SIZE,
+ l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE,
+ l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE);
+
+ NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle);
+
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ }
+ else if (l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
+ {
+ __try
+ {
+ ETH_HEADER * p_UserToTap = &l_Adapter->m_UserToTap;
+
+ // for IPv6, need to use ethernet header with IPv6 proto
+ if ( IPH_GET_VER( ((IPHDR*) p_IRP->AssociatedIrp.SystemBuffer)->version_len) == 6 )
+ {
+ p_UserToTap = &l_Adapter->m_UserToTap_IPv6;
+ }
+
+ p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
+
+ DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
+ p_UserToTap,
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify ((unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length,
+ TRUE,
+ "RX",
+ &l_Adapter->m_RxTrunc);
+#endif
+
+ NdisMEthIndicateReceive
+ (l_Adapter->m_MiniportAdapterHandle,
+ (NDIS_HANDLE) l_Adapter,
+ (unsigned char *) p_UserToTap,
+ sizeof (ETH_HEADER),
+ (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
+ l_IrpSp->Parameters.Write.Length,
+ l_IrpSp->Parameters.Write.Length);
+
+ NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle);
+
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE (P2P)\n",
+ NAME (l_Adapter)));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
+ NAME (l_Adapter),
+ l_IrpSp->Parameters.Write.Length));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE;
+ p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (l_Status == STATUS_SUCCESS)
+ INCREMENT_STAT (l_Adapter->m_Rx);
+ else
+ INCREMENT_STAT (l_Adapter->m_RxErr);
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //--------------------------------------------------------------
+ // User mode thread has called CreateFile() on the tap device
+ //--------------------------------------------------------------
+ case IRP_MJ_CREATE:
+ {
+ BOOLEAN succeeded = FALSE;
+ BOOLEAN mutex_succeeded;
+
+ DEBUGP
+ (("[%s] [TAP] release [%d.%d] open request (m_TapOpens=%d)\n",
+ NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION, l_Adapter->m_Extension.m_TapOpens));
+
+ ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded);
+ if (mutex_succeeded)
+ {
+ if (l_Adapter->m_Extension.m_TapIsRunning && !l_Adapter->m_Extension.m_TapOpens)
+ {
+ ResetTapAdapterState (l_Adapter);
+ l_Adapter->m_Extension.m_TapOpens = 1;
+ succeeded = TRUE;
+ }
+
+ if (succeeded)
+ {
+ INCREMENT_STAT (l_Adapter->m_Extension.m_NumTapOpens);
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+ p_IRP->IoStatus.Information = 0;
+ }
+ else
+ {
+ DEBUGP (("[%s] TAP is presently unavailable (m_TapOpens=%d)\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex);
+ }
+ else
+ {
+ DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //-----------------------------------------------------------
+ // User mode thread called CloseHandle() on the tap device
+ //-----------------------------------------------------------
+ case IRP_MJ_CLOSE:
+ {
+ BOOLEAN mutex_succeeded;
+
+ DEBUGP (("[%s] [TAP] release [%d.%d] close/cleanup request\n",
+ NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION));
+
+ ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded);
+ if (mutex_succeeded)
+ {
+ l_Adapter->m_Extension.m_TapOpens = 0;
+ ResetTapAdapterState (l_Adapter);
+ FlushQueues (&l_Adapter->m_Extension);
+ SetMediaStatus (l_Adapter, FALSE);
+ RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex);
+ }
+ else
+ {
+ DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n",
+ NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens));
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+
+ //------------------
+ // Strange Request
+ //------------------
+ default:
+ {
+ //NOTE_ERROR ();
+ p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+ break;
+ }
+ }
+
+ return l_Status;
+}
+
+//=============================================================
+// 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.
+//=============================================================
+
+NTSTATUS
+CompleteIRP (IN PIRP p_IRP,
+ IN TapPacketPointer p_PacketBuffer,
+ IN CCHAR PriorityBoost)
+{
+ NTSTATUS l_Status = STATUS_UNSUCCESSFUL;
+
+ int offset;
+ int len;
+
+ MYASSERT (p_IRP);
+ MYASSERT (p_PacketBuffer);
+
+ IoSetCancelRoutine (p_IRP, NULL); // Disable cancel routine
+
+ //-------------------------------------------
+ // While p_PacketBuffer always contains a
+ // full ethernet packet, including the
+ // ethernet header, in point-to-point mode,
+ // we only want to return the IPv4
+ // component.
+ //-------------------------------------------
+
+ if (p_PacketBuffer->m_SizeFlags & TP_TUN)
+ {
+ offset = ETHERNET_HEADER_SIZE;
+ len = (int) (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE;
+ }
+ else
+ {
+ offset = 0;
+ len = (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK);
+ }
+
+ if (len < 0 || (int) p_IRP->IoStatus.Information < len)
+ {
+ p_IRP->IoStatus.Information = 0;
+ p_IRP->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ NOTE_ERROR ();
+ }
+ else
+ {
+ p_IRP->IoStatus.Information = len;
+ p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS;
+
+ __try
+ {
+ NdisMoveMemory (p_IRP->AssociatedIrp.SystemBuffer,
+ p_PacketBuffer->m_Data + offset,
+ len);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ NOTE_ERROR ();
+ p_IRP->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ p_IRP->IoStatus.Information = 0;
+ }
+ }
+
+ __try
+ {
+ NdisFreeMemory (p_PacketBuffer,
+ TAP_PACKET_SIZE (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK),
+ 0);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+
+ if (l_Status == STATUS_SUCCESS)
+ {
+ IoCompleteRequest (p_IRP, PriorityBoost);
+ }
+ else
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+
+ return l_Status;
+}
+
+//==============================================
+// IRPs get cancelled for a number of reasons.
+//
+// The TAP device could be closed by userspace
+// when there are still pending read operations.
+//
+// The user could disable the TAP adapter in the
+// network connections control panel, while the
+// device is still open by a process.
+//==============================================
+VOID
+CancelIRPCallback (IN PDEVICE_OBJECT p_DeviceObject,
+ IN PIRP p_IRP)
+{
+ TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject);
+ CancelIRP (l_Adapter ? &l_Adapter->m_Extension : NULL, p_IRP, TRUE);
+}
+
+VOID
+CancelIRP (TapExtensionPointer p_Extension,
+ IN PIRP p_IRP,
+ BOOLEAN callback)
+{
+ BOOLEAN exists = FALSE;
+
+ MYASSERT (p_IRP);
+
+ if (p_Extension)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_QueueLock);
+ exists = (QueueExtract (p_Extension->m_IrpQueue, p_IRP) == p_IRP);
+ NdisReleaseSpinLock (&p_Extension->m_QueueLock);
+ }
+ else
+ exists = TRUE;
+
+ if (exists)
+ {
+ IoSetCancelRoutine (p_IRP, NULL);
+ p_IRP->IoStatus.Status = STATUS_CANCELLED;
+ p_IRP->IoStatus.Information = 0;
+ }
+
+ if (callback)
+ IoReleaseCancelSpinLock (p_IRP->CancelIrql);
+
+ if (exists)
+ IoCompleteRequest (p_IRP, IO_NO_INCREMENT);
+}
+
+//===========================================
+// Exhaust packet, IRP, and injection queues.
+//===========================================
+VOID
+FlushQueues (TapExtensionPointer p_Extension)
+{
+ PIRP l_IRP;
+ TapPacketPointer l_PacketBuffer;
+ InjectPacketPointer l_InjectBuffer;
+ int n_IRP=0, n_Packet=0, n_Inject=0;
+
+ MYASSERT (p_Extension);
+ MYASSERT (p_Extension->m_TapDevice);
+
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_QueueLock);
+ l_IRP = QueuePop (p_Extension->m_IrpQueue);
+ NdisReleaseSpinLock (&p_Extension->m_QueueLock);
+ if (l_IRP)
+ {
+ ++n_IRP;
+ CancelIRP (NULL, l_IRP, FALSE);
+ }
+ else
+ break;
+ }
+
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_QueueLock);
+ l_PacketBuffer = QueuePop (p_Extension->m_PacketQueue);
+ NdisReleaseSpinLock (&p_Extension->m_QueueLock);
+ if (l_PacketBuffer)
+ {
+ ++n_Packet;
+ MemFree (l_PacketBuffer, TAP_PACKET_SIZE (l_PacketBuffer->m_SizeFlags & TP_SIZE_MASK));
+ }
+ else
+ break;
+ }
+
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&p_Extension->m_InjectLock);
+ l_InjectBuffer = QueuePop (p_Extension->m_InjectQueue);
+ NdisReleaseSpinLock (&p_Extension->m_InjectLock);
+ if (l_InjectBuffer)
+ {
+ ++n_Inject;
+ INJECT_PACKET_FREE(l_InjectBuffer);
+ }
+ else
+ break;
+ }
+
+ DEBUGP ((
+ "[%s] [TAP] FlushQueues n_IRP=[%d,%d,%d] n_Packet=[%d,%d,%d] n_Inject=[%d,%d,%d]\n",
+ p_Extension->m_TapName,
+ n_IRP,
+ p_Extension->m_IrpQueue->max_size,
+ IRP_QUEUE_SIZE,
+ n_Packet,
+ p_Extension->m_PacketQueue->max_size,
+ PACKET_QUEUE_SIZE,
+ n_Inject,
+ p_Extension->m_InjectQueue->max_size,
+ INJECT_QUEUE_SIZE
+ ));
+}
+
+//===================================================
+// Tell Windows whether the TAP device should be
+// considered "connected" or "disconnected".
+//===================================================
+VOID
+SetMediaStatus (TapAdapterPointer p_Adapter, BOOLEAN state)
+{
+ if (p_Adapter->m_MediaState != state && !p_Adapter->m_MediaStateAlwaysConnected)
+ {
+ if (state)
+ NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle,
+ NDIS_STATUS_MEDIA_CONNECT, NULL, 0);
+ else
+ NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle,
+ NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0);
+
+ NdisMIndicateStatusComplete (p_Adapter->m_MiniportAdapterHandle);
+ p_Adapter->m_MediaState = state;
+ }
+}
+
+
+//======================================================
+// 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 (TapAdapterPointer p_Adapter)
+{
+ if (p_Adapter->m_tun && p_Adapter->m_dhcp_enabled)
+ {
+ if ((p_Adapter->m_dhcp_server_ip & p_Adapter->m_remoteNetmask) == p_Adapter->m_remoteNetwork)
+ {
+ COPY_MAC (p_Adapter->m_dhcp_server_mac, p_Adapter->m_TapToUser.dest);
+ p_Adapter->m_dhcp_server_arp = FALSE;
+ }
+ }
+}
+
+//===================================================
+// Generate an ARP reply message for specific kinds
+// ARP queries.
+//===================================================
+BOOLEAN
+ProcessARP (TapAdapterPointer p_Adapter,
+ const PARP_PACKET src,
+ const IPADDR adapter_ip,
+ const IPADDR ip_network,
+ const IPADDR ip_netmask,
+ const MACADDR mac)
+{
+ //-----------------------------------------------
+ // Is this the kind of packet we are looking for?
+ //-----------------------------------------------
+ if (src->m_Proto == htons (ETH_P_ARP)
+ && MAC_EQUAL (src->m_MAC_Source, p_Adapter->m_MAC)
+ && MAC_EQUAL (src->m_ARP_MAC_Source, p_Adapter->m_MAC)
+ && MAC_EQUAL (src->m_MAC_Destination, p_Adapter->m_MAC_Broadcast)
+ && 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 (ETH_P_IP)
+ && 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 (ETH_P_ARP);
+ arp->m_MAC_AddressType = htons (MAC_ADDR_TYPE);
+ arp->m_PROTO_AddressType = htons (ETH_P_IP);
+ arp->m_MAC_AddressSize = sizeof (MACADDR);
+ arp->m_PROTO_AddressSize = sizeof (IPADDR);
+ arp->m_ARP_Operation = htons (ARP_REPLY);
+
+ //----------------------------------------------
+ // ARP addresses
+ //----------------------------------------------
+ COPY_MAC (arp->m_MAC_Source, mac);
+ COPY_MAC (arp->m_MAC_Destination, p_Adapter->m_MAC);
+ COPY_MAC (arp->m_ARP_MAC_Source, mac);
+ COPY_MAC (arp->m_ARP_MAC_Destination, p_Adapter->m_MAC);
+ 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));
+
+ InjectPacketDeferred (p_Adapter, (UCHAR *) arp, sizeof (ARP_PACKET));
+
+ MemFree (arp, sizeof (ARP_PACKET));
+ }
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+//===============================================================
+// 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.
+//===============================================================
+
+// Defer packet injection till IRQL < DISPATCH_LEVEL
+VOID
+InjectPacketDeferred (TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len)
+{
+ InjectPacketPointer l_InjectBuffer;
+ PVOID result;
+
+ if (NdisAllocateMemoryWithTag (&l_InjectBuffer,
+ INJECT_PACKET_SIZE (len),
+ 'IPAT') == NDIS_STATUS_SUCCESS)
+ {
+ l_InjectBuffer->m_Size = len;
+ NdisMoveMemory (l_InjectBuffer->m_Data, packet, len);
+ NdisAcquireSpinLock (&p_Adapter->m_Extension.m_InjectLock);
+ result = QueuePush (p_Adapter->m_Extension.m_InjectQueue, l_InjectBuffer);
+ NdisReleaseSpinLock (&p_Adapter->m_Extension.m_InjectLock);
+ if (result)
+ KeInsertQueueDpc (&p_Adapter->m_Extension.m_InjectDpc, p_Adapter, NULL);
+ else
+ INJECT_PACKET_FREE(l_InjectBuffer);
+ }
+}
+
+// Handle the injection of previously deferred packets
+VOID
+InjectPacketDpc(KDPC *Dpc,
+ PVOID DeferredContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2)
+{
+ InjectPacketPointer l_InjectBuffer;
+ TapAdapterPointer l_Adapter = (TapAdapterPointer)SystemArgument1;
+ while (TRUE)
+ {
+ NdisAcquireSpinLock (&l_Adapter->m_Extension.m_InjectLock);
+ l_InjectBuffer = QueuePop (l_Adapter->m_Extension.m_InjectQueue);
+ NdisReleaseSpinLock (&l_Adapter->m_Extension.m_InjectLock);
+ if (l_InjectBuffer)
+ {
+ InjectPacketNow(l_Adapter, l_InjectBuffer->m_Data, l_InjectBuffer->m_Size);
+ INJECT_PACKET_FREE(l_InjectBuffer);
+ }
+ else
+ break;
+ }
+}
+
+// Do packet injection now
+VOID
+InjectPacketNow (TapAdapterPointer p_Adapter,
+ UCHAR *packet,
+ const unsigned int len)
+{
+ MYASSERT (len >= ETHERNET_HEADER_SIZE);
+
+ __try
+ {
+ //------------------------------------------------------------
+ // NdisMEthIndicateReceive and NdisMEthIndicateReceiveComplete
+ // could potentially be called reentrantly both here and in
+ // TapDeviceHook/IRP_MJ_WRITE.
+ //
+ // The DDK docs imply that this is okay.
+ //
+ // Note that reentrant behavior could only occur if the
+ // non-deferred version of InjectPacket is used.
+ //------------------------------------------------------------
+ NdisMEthIndicateReceive
+ (p_Adapter->m_MiniportAdapterHandle,
+ (NDIS_HANDLE) p_Adapter,
+ packet,
+ ETHERNET_HEADER_SIZE,
+ packet + ETHERNET_HEADER_SIZE,
+ len - ETHERNET_HEADER_SIZE,
+ len - ETHERNET_HEADER_SIZE);
+
+ NdisMEthIndicateReceiveComplete (p_Adapter->m_MiniportAdapterHandle);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ DEBUGP (("[%s] NdisMEthIndicateReceive failed in InjectPacketNow\n",
+ NAME (p_Adapter)));
+ NOTE_ERROR ();
+ }
+}
+
+//===================================================================
+// Go back to default TAP mode from Point-To-Point mode.
+// Also reset (i.e. disable) DHCP Masq mode.
+//===================================================================
+VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
+{
+ // Point-To-Point
+ p_Adapter->m_tun = FALSE;
+ p_Adapter->m_localIP = 0;
+ p_Adapter->m_remoteNetwork = 0;
+ p_Adapter->m_remoteNetmask = 0;
+ NdisZeroMemory (&p_Adapter->m_TapToUser, sizeof (p_Adapter->m_TapToUser));
+ NdisZeroMemory (&p_Adapter->m_UserToTap, sizeof (p_Adapter->m_UserToTap));
+ NdisZeroMemory (&p_Adapter->m_UserToTap_IPv6, sizeof (p_Adapter->m_UserToTap_IPv6));
+
+ // DHCP Masq
+ p_Adapter->m_dhcp_enabled = FALSE;
+ p_Adapter->m_dhcp_server_arp = FALSE;
+ p_Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+ p_Adapter->m_dhcp_addr = 0;
+ p_Adapter->m_dhcp_netmask = 0;
+ p_Adapter->m_dhcp_server_ip = 0;
+ p_Adapter->m_dhcp_lease_time = 0;
+ p_Adapter->m_dhcp_received_discover = FALSE;
+ p_Adapter->m_dhcp_bad_requests = 0;
+ NdisZeroMemory (p_Adapter->m_dhcp_server_mac, sizeof (MACADDR));
+}
+
+#if ENABLE_NONADMIN
+
+//===================================================================
+// Set TAP device handle to be accessible without admin privileges.
+//===================================================================
+VOID AllowNonAdmin (TapExtensionPointer p_Extension)
+{
+ NTSTATUS stat;
+ SECURITY_DESCRIPTOR sd;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK isb;
+ HANDLE hand = NULL;
+
+ NdisZeroMemory (&sd, sizeof (sd));
+ NdisZeroMemory (&oa, sizeof (oa));
+ NdisZeroMemory (&isb, sizeof (isb));
+
+ if (!p_Extension->m_CreatedUnicodeLinkName)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: UnicodeLinkName is uninitialized\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: RtlCreateSecurityDescriptor failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ InitializeObjectAttributes (
+ &oa,
+ &p_Extension->m_UnicodeLinkName,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+
+ stat = ZwOpenFile (
+ &hand,
+ WRITE_DAC,
+ &oa,
+ &isb,
+ 0,
+ 0
+ );
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwOpenFile failed, status=0x%08x\n", (unsigned int)stat));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = ZwSetSecurityObject (hand, DACL_SECURITY_INFORMATION, &sd);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwSetSecurityObject failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ stat = ZwClose (hand);
+ if (stat != STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] AllowNonAdmin: ZwClose failed\n"));
+ NOTE_ERROR ();
+ return;
+ }
+
+ DEBUGP (("[TAP] AllowNonAdmin: SUCCEEDED\n"));
+}
+
+#endif
+
+#if PACKET_TRUNCATION_CHECK
+
+VOID
+IPv4PacketSizeVerify (const UCHAR *data, ULONG length, BOOLEAN tun, const char *prefix, LONG *counter)
+{
+ const IPHDR *ip;
+ int len = length;
+
+ if (tun)
+ {
+ ip = (IPHDR *) data;
+ }
+ else
+ {
+ if (length >= sizeof (ETH_HEADER))
+ {
+ const ETH_HEADER *eth = (ETH_HEADER *) data;
+
+ if (eth->proto != htons (ETH_P_IP))
+ return;
+
+ ip = (IPHDR *) (data + sizeof (ETH_HEADER));
+ len -= sizeof (ETH_HEADER);
+ }
+ else
+ return;
+ }
+
+ if (len >= sizeof (IPHDR))
+ {
+ const int totlen = ntohs (ip->tot_len);
+
+ DEBUGP (("[TAP] IPv4PacketSizeVerify %s len=%d totlen=%d\n", prefix, len, totlen));
+
+ if (len != totlen)
+ ++(*counter);
+ }
+}
+
+#endif
+
+//======================================================================
+// End of Source
+//======================================================================
diff --git a/windows-tap/src/types.h b/windows-tap/src/types.h
new file mode 100755
index 00000000..6ca841d4
--- /dev/null
+++ b/windows-tap/src/types.h
@@ -0,0 +1,178 @@
+/*
+ * 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-2010 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 _TapAdapter;
+typedef struct _TapPacket;
+
+typedef union _TapAdapterQuery
+{
+ NDIS_HARDWARE_STATUS m_HardwareStatus;
+ NDIS_MEDIUM m_Medium;
+ NDIS_PHYSICAL_MEDIUM m_PhysicalMedium;
+ UCHAR m_MacAddress [6];
+ UCHAR m_Buffer [256];
+ ULONG m_Long;
+ USHORT m_Short;
+ UCHAR m_Byte;
+}
+TapAdapterQuery, *TapAdapterQueryPointer;
+
+typedef struct _TapExtension
+{
+ // TAP device object and packet queues
+ Queue *m_PacketQueue, *m_IrpQueue;
+ PDEVICE_OBJECT m_TapDevice;
+ NDIS_HANDLE m_TapDeviceHandle;
+ ULONG m_TapOpens;
+
+ // 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 m_NumTapOpens;
+
+ // Flags
+ BOOLEAN m_TapIsRunning;
+ 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 _TapPacket
+ {
+# define TAP_PACKET_SIZE(data_size) (sizeof (TapPacket) + (data_size))
+# define TP_TUN 0x80000000
+# define TP_SIZE_MASK (~TP_TUN)
+ ULONG m_SizeFlags;
+ UCHAR m_Data []; // m_Data must be the last struct member
+ }
+TapPacket, *TapPacketPointer;
+
+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;
+
+typedef struct _TapAdapter
+{
+# define NAME(a) ((a)->m_NameAnsi.Buffer)
+ ANSI_STRING m_NameAnsi;
+ MACADDR m_MAC;
+ BOOLEAN m_InterfaceIsRunning;
+ NDIS_HANDLE m_MiniportAdapterHandle;
+ LONG m_Rx, m_Tx, m_RxErr, m_TxErr;
+#if PACKET_TRUNCATION_CHECK
+ LONG m_RxTrunc, m_TxTrunc;
+#endif
+ NDIS_MEDIUM m_Medium;
+ ULONG m_Lookahead;
+ ULONG m_MTU;
+
+ // TRUE if adapter should always be
+ // "connected" even when device node
+ // is not open by a userspace process.
+ BOOLEAN m_MediaStateAlwaysConnected;
+
+ // TRUE if device is "connected"
+ BOOLEAN m_MediaState;
+
+ // Adapter power state
+ char m_DeviceState;
+
+ // 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
+ MACADDR m_MAC_Broadcast;
+
+ // Used 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;
+
+ // Help to tear down the adapter by keeping
+ // some state information on allocated
+ // resources.
+ BOOLEAN m_CalledAdapterFreeResources;
+ BOOLEAN m_RegisteredAdapterShutdownHandler;
+
+ // Multicast list info
+ NDIS_SPIN_LOCK m_MCLock;
+ BOOLEAN m_MCLockAllocated;
+ ULONG m_MCListSize;
+ MC_LIST m_MCList;
+
+ // Information on the TAP device
+ TapExtension m_Extension;
+} TapAdapter, *TapAdapterPointer;
+
+#endif
diff --git a/windows-tap/version.m4 b/windows-tap/version.m4
new file mode 100644
index 00000000..242b8e0d
--- /dev/null
+++ b/windows-tap/version.m4
@@ -0,0 +1,11 @@
+dnl define the TAP version
+define([PRODUCT_NAME], [TAP-Windows])
+define([PRODUCT_VERSION], [9.9.2])
+define([PRODUCT_VERSION_RESOURCE], [9,0,0,9])
+define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901])
+define([PRODUCT_TAP_WIN_MAJOR], [9])
+define([PRODUCT_TAP_WIN_MINOR], [9])
+define([PRODUCT_TAP_WIN_PROVIDER], [TAP-Windows Provider V9])
+define([PRODUCT_TAP_WIN_CHARACTERISTICS], [0x81])
+define([PRODUCT_TAP_WIN_DEVICE_DESCRIPTION], [TAP-Windows Adapter V9])
+define([PRODUCT_TAP_WIN_RELDATE], [07/02/2012])