diff --git a/third_party/jsign/.gitignore b/third_party/jsign/.gitignore new file mode 100644 index 00000000000..d392f0e82c4 --- /dev/null +++ b/third_party/jsign/.gitignore @@ -0,0 +1 @@ +*.jar diff --git a/third_party/jsign/LICENSE.txt b/third_party/jsign/LICENSE.txt new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/third_party/jsign/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/jsign/METADATA b/third_party/jsign/METADATA new file mode 100644 index 00000000000..d58f87d3812 --- /dev/null +++ b/third_party/jsign/METADATA @@ -0,0 +1,17 @@ +name: "Jsign" +description: + "Java implementation of Microsoft Authenticode for signing Windows " + "executable files, installers and scripts." + +third_party { + url { + type: HOMEPAGE + value: "https://ebourg.github.io/jsign/" + } + url { + type: GIT + value: "https://github.com/ebourg/jsign" + } + version: "4.2" + last_upgrade_date { year: 2022 month: 10 day: 6 } +} diff --git a/third_party/jsign/index.mjs b/third_party/jsign/index.mjs new file mode 100644 index 00000000000..d5cf3e10b21 --- /dev/null +++ b/third_party/jsign/index.mjs @@ -0,0 +1,71 @@ +// Copyright 2023 The Outline Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import {spawn} from 'node:child_process'; +import {resolve} from 'node:path'; + +import {downloadHttpsFile} from '../../src/build/download_file.mjs'; +import {getFileChecksum} from '../../src/build/get_file_checksum.mjs'; +import {getRootDir} from '../../src/build/get_root_dir.mjs'; + +/** + * Run jsign.jar to sign `fileToSign` with a list of cli arguments stored in `options`. + * @param {string} fileToSign The path string of a file to be signed. + * @param {string[]} options A list of cli arguments to be passed to jsign. see https://ebourg.github.io/jsign/ + * @returns {Promise} A promise containing the exit code of jsign. + */ +export async function jsign(fileToSign, options) { + if (!fileToSign) { + throw new Error('fileToSign is required by jsign'); + } + if (!options) { + throw new Error('options are required by jsign'); + } + + const jsignJarPath = await ensureJsignJar(); + const jsignProc = spawn('java', ['-jar', jsignJarPath, ...options, fileToSign], { + stdio: 'inherit', + }); + return await new Promise((resolve, reject) => { + jsignProc.on('error', reject); + jsignProc.on('exit', resolve); + }); +} + + +const JSIGN_FILE_NAME = 'jsign-4.2.jar'; +const JSIGN_DOWNLOAD_URL = 'https://github.com/ebourg/jsign/releases/download/4.2/jsign-4.2.jar'; +const JSIGN_SHA256_CHECKSUM = '290377fc4f593256200b3ea4061b7409e8276255f449d4c6de7833faf0850cc1'; + +/** + * Ensure jsign.jar exists and return the absolute path to it. + */ +async function ensureJsignJar() { + const jsignPath = resolve(getRootDir(), 'third_party', 'jsign', JSIGN_FILE_NAME); + if ((await getFileChecksum(jsignPath, 'sha256')) === JSIGN_SHA256_CHECKSUM) { + return jsignPath; + } + + console.debug(`downloading jsign from "${JSIGN_DOWNLOAD_URL}" to "${jsignPath}"`); + await downloadHttpsFile(JSIGN_DOWNLOAD_URL, jsignPath); + + const actualChecksum = await getFileChecksum(jsignPath, 'sha256'); + if (actualChecksum !== JSIGN_SHA256_CHECKSUM) { + throw new Error(`failed to verify "${jsignPath}". ` + + `Expected checksum ${JSIGN_SHA256_CHECKSUM}, but found ${actualChecksum}`); + } + + console.debug(`successfully downloaded "${jsignPath}"`); + return jsignPath; +} diff --git a/third_party/newtonsoft/LICENSE b/third_party/newtonsoft/LICENSE new file mode 100755 index 00000000000..ed11c37a1a2 --- /dev/null +++ b/third_party/newtonsoft/LICENSE @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2007 James Newton-King + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/third_party/newtonsoft/METADATA b/third_party/newtonsoft/METADATA new file mode 100755 index 00000000000..f43a7d6df0b --- /dev/null +++ b/third_party/newtonsoft/METADATA @@ -0,0 +1,16 @@ +name: "Newtonsoft.Json" +description: + "Json.NET is a high-performance JSON framework for .NET." + +third_party { + url { + type: HOMEPAGE + value: "https://www.newtonsoft.com/json" + } + url { + type: GIT + value: "https://github.com/JamesNK/Newtonsoft.Json" + } + version: "11.0.0" + last_upgrade_date { year: 2018 month: 6 day: 26 } +} diff --git a/third_party/newtonsoft/Newtonsoft.Json.dll b/third_party/newtonsoft/Newtonsoft.Json.dll new file mode 100755 index 00000000000..80699020cce Binary files /dev/null and b/third_party/newtonsoft/Newtonsoft.Json.dll differ diff --git a/third_party/sentry-android/LICENSE b/third_party/sentry-android/LICENSE new file mode 100644 index 00000000000..2e0d30a2e0f --- /dev/null +++ b/third_party/sentry-android/LICENSE @@ -0,0 +1,15 @@ +BSD 3-clause "New" or "Revised" License + +Copyright (c) 2016 Functional Software, Inc. +Copyright (c) 2012 Ken Cochrane and individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. 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. + + 3. Neither the name of the copyright holder 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 HOLDER 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. diff --git a/third_party/sentry-android/METADATA b/third_party/sentry-android/METADATA new file mode 100644 index 00000000000..e1c718627dd --- /dev/null +++ b/third_party/sentry-android/METADATA @@ -0,0 +1,15 @@ +name: "sentry-android" +description: "Crash and error reporting framework. Sentry SDK for Android." + +third_party { + url { + type: HOMEPAGE + value: "https://sentry.io" + } + url { + type: GIT + value: "https://github.com/getsentry/sentry-android/" + } + version: "2.0.2" + last_upgrade_date { year: 2020 month: 03 day: 04 } +} diff --git a/third_party/tap-windows6/.appveyor.yml b/third_party/tap-windows6/.appveyor.yml new file mode 100644 index 00000000000..09f2094db74 --- /dev/null +++ b/third_party/tap-windows6/.appveyor.yml @@ -0,0 +1,5 @@ +version: 1.0.{build} +build_script: +- cmd: python buildtap.py -b +artifacts: +- path: '*' diff --git a/third_party/tap-windows6/.gitattributes b/third_party/tap-windows6/.gitattributes new file mode 100644 index 00000000000..14d9eb5127e --- /dev/null +++ b/third_party/tap-windows6/.gitattributes @@ -0,0 +1 @@ +*.yml text=auto diff --git a/third_party/tap-windows6/.gitignore b/third_party/tap-windows6/.gitignore new file mode 100644 index 00000000000..c84d7450407 --- /dev/null +++ b/third_party/tap-windows6/.gitignore @@ -0,0 +1,10 @@ +dist/** +*.pyc +*.tar.gz +src/config.h +src/SOURCES +src/build*.log +src/obj* +src/i386 +src/amd64 +tap-windows-*.exe diff --git a/third_party/tap-windows6/CONTRIBUTING.rst b/third_party/tap-windows6/CONTRIBUTING.rst new file mode 100644 index 00000000000..6ee590833dd --- /dev/null +++ b/third_party/tap-windows6/CONTRIBUTING.rst @@ -0,0 +1,26 @@ +Contributing to tap-windows6 +============================ + +To contribute to tap-windows6 please send your patches to openvpn-devel mailing +list: + +- https://lists.sourceforge.net/lists/listinfo/openvpn-devel + +The subject line should look like this: + + [PATCH: tap-windows6] summary of the patch + +To avoid merging issues patches should be created with git-format-patch or sent +using git-send-email. The easiest way to add the subject line prefix is to use +this option: + + --subject-prefix='PATCH: tap-windows6' + +Patches that do not modify the actual driver code can be sent as GitHub pull +requests. Try to split large patches into small, atomic pieces to make reviews +and merging easier. + +If you want quick feedback on a patch, you can visit the #openvpn-devel channel +on Freenode. Note that you need to be logged in to join the channel: + +- http://freenode.net/faq.shtml#nicksetup diff --git a/third_party/tap-windows6/COPYING b/third_party/tap-windows6/COPYING new file mode 100644 index 00000000000..a2dbdb8f59e --- /dev/null +++ b/third_party/tap-windows6/COPYING @@ -0,0 +1,24 @@ +tap-windows6 license +-------------------- + +The source and object code of the tap-windows6 project +is Copyright (C) 2002-2014 OpenVPN Technologies, Inc. The +NSIS installer is Copyright (C) 2014 OpenVPN Technologies, +Inc. and (C) 2012 Alon Bar-Lev. Both are released under the +GPL version 2. See COPYRIGHT.GPL for the full GPL license. +The licensors also make the following statement borrowed +from the SPICE project: + +With respect to binaries built using the Microsoft(R) +Windows Driver Kit (WDK), GPLv2 does not extend to any code +contained in or derived from the WDK ("WDK Code"). As to +WDK Code, by using or distributing such binaries you agree +to be bound by the Microsoft Software License Terms for the +WDK. All WDK Code is considered by the GPLv2 licensors to +qualify for the special exception stated in section 3 of +GPLv2 (commonly known as the system library exception). + +The tap-windows.h file has been released under the MIT +license (see COPYRIGHT.MIT) as well as under GPLv2 (see +COPYRIGHT.GPL). This has been done to allow the use of the +header file in non-GPLv2 compatible projects. diff --git a/third_party/tap-windows6/COPYRIGHT.GPL b/third_party/tap-windows6/COPYRIGHT.GPL new file mode 100644 index 00000000000..d159169d105 --- /dev/null +++ b/third_party/tap-windows6/COPYRIGHT.GPL @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + + , 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 Lesser General +Public License instead of this License. diff --git a/third_party/tap-windows6/COPYRIGHT.MIT b/third_party/tap-windows6/COPYRIGHT.MIT new file mode 100644 index 00000000000..bfbb9008951 --- /dev/null +++ b/third_party/tap-windows6/COPYRIGHT.MIT @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright © 2014 OpenVPN Technologies, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/third_party/tap-windows6/LICENSE b/third_party/tap-windows6/LICENSE new file mode 100644 index 00000000000..a2dbdb8f59e --- /dev/null +++ b/third_party/tap-windows6/LICENSE @@ -0,0 +1,24 @@ +tap-windows6 license +-------------------- + +The source and object code of the tap-windows6 project +is Copyright (C) 2002-2014 OpenVPN Technologies, Inc. The +NSIS installer is Copyright (C) 2014 OpenVPN Technologies, +Inc. and (C) 2012 Alon Bar-Lev. Both are released under the +GPL version 2. See COPYRIGHT.GPL for the full GPL license. +The licensors also make the following statement borrowed +from the SPICE project: + +With respect to binaries built using the Microsoft(R) +Windows Driver Kit (WDK), GPLv2 does not extend to any code +contained in or derived from the WDK ("WDK Code"). As to +WDK Code, by using or distributing such binaries you agree +to be bound by the Microsoft Software License Terms for the +WDK. All WDK Code is considered by the GPLv2 licensors to +qualify for the special exception stated in section 3 of +GPLv2 (commonly known as the system library exception). + +The tap-windows.h file has been released under the MIT +license (see COPYRIGHT.MIT) as well as under GPLv2 (see +COPYRIGHT.GPL). This has been done to allow the use of the +header file in non-GPLv2 compatible projects. diff --git a/third_party/tap-windows6/LICENSE.gplv2 b/third_party/tap-windows6/LICENSE.gplv2 new file mode 100644 index 00000000000..d159169d105 --- /dev/null +++ b/third_party/tap-windows6/LICENSE.gplv2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + + , 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 Lesser General +Public License instead of this License. diff --git a/third_party/tap-windows6/METADATA b/third_party/tap-windows6/METADATA new file mode 100644 index 00000000000..5bf286f682d --- /dev/null +++ b/third_party/tap-windows6/METADATA @@ -0,0 +1,18 @@ +name: "tap-windows6" +description: + "Provides a TAP driver on Windows. In conjunction with tun2socks this " + "allows Shadowsocks to act as a VPN for the whole system. From the OpenVPN " + "project." + +third_party { + url { + type: HOMEPAGE + value: "https://openvpn.net/index.php/download/community-downloads.html" + } + url { + type: GIT + value: "https://github.com/OpenVPN/tap-windows6" + } + version: "9.21.2" + last_upgrade_date { year: 2018 month: 5 day: 7 } +} \ No newline at end of file diff --git a/third_party/tap-windows6/MSCV-VSClass3.cer b/third_party/tap-windows6/MSCV-VSClass3.cer new file mode 100644 index 00000000000..831757d5a5e Binary files /dev/null and b/third_party/tap-windows6/MSCV-VSClass3.cer differ diff --git a/third_party/tap-windows6/README.rst b/third_party/tap-windows6/README.rst new file mode 100644 index 00000000000..c7039a9df42 --- /dev/null +++ b/third_party/tap-windows6/README.rst @@ -0,0 +1,142 @@ +TAP-Windows driver (NDIS 6) +=========================== + +This is an NDIS 6 implementation of the TAP-Windows driver, used by OpenVPN and +other apps. NDIS 6 drivers can run on Windows Vista or higher. + +Build +----- + +To build, the following prerequisites are required: + +- Python 2.7 +- Microsoft Windows 7 WDK (Windows Driver Kit) +- Windows code signing certificate +- Git (not strictly required, but useful for running commands using bundled bash shell) +- MakeNSIS (optional) +- Patched source code directory of **devcon** sample from WDK (optional) +- Prebuilt tapinstall.exe binaries (optional) + +Make sure you add Python's install directory (usually c:\\python27) to the PATH +environment variable. + +These instructions have been tested on Windows 7 using Git Bash, as well as on +Windows 2012 Server using Git Bash and Windows Powershell. + +View build script options:: + + $ python buildtap.py + Usage: buildtap.py [options] + + Options: + -h, --help show this help message and exit + -s SRC, --src=SRC TAP-Windows top-level directory, default= + --ti=TAPINSTALL tapinstall (i.e. devcon) directory (optional) + -d, --debug enable debug build + -c, --clean do an nmake clean before build + -b, --build build TAP-Windows and possibly tapinstall (add -c to + clean before build) + --sign sign the driver files (disabled by default) + -p, --package generate an NSIS installer from the compiled files + --cert=CERT Common name of code signing certificate, default=openvpn + --crosscert=CERT The cross-certificate file to use, default=MSCV- + VSClass3.cer + --timestamp=URL Timestamp URL to use, default=http://timestamp.verisign.c + om/scripts/timstamp.dll + -a, --oas Build for OpenVPN Access Server clients + +Edit **version.m4** and **paths.py** as necessary then build:: + + $ python buildtap.py -b + +On successful completion, all build products will be placed in the "dist" +directory as well as tap6.tar.gz. The NSIS installer package will be placed to +the build root directory. + +Note that due to the strict driver signing requirements in Windows 10 you need +an EV certificate to sign the driver files. These EV certificates may be +stored inside a hardware device, which makes fully automated signing process +difficult, dangerous or impossible. Eventually the signing process will become +even more involved, with drivers having to be submitted to the Windows +Hardware Developer Center Dashboard portal. Therefore, by default, this +buildsystem no longer signs any files. You can revert to the old behavior +by using the --sign parameter. + +Building tapinstall (optional) +------------------------------ + +The build system supports building tapinstall.exe (a.k.a. devcon.exe). However +the devcon source code in WinDDK does not build without modifications which +cannot be made public due to licensing restrictions. For these reasons the +default behavior is to reuse pre-built executables. To make sure the buildsystem +finds the executables create the following directory structure under +tap-windows6 directory: +:: + tapinstall + └── 7600 + ├── objfre_wlh_amd64 + │   └── amd64 + │   └── tapinstall.exe + └── objfre_wlh_x86 + └── i386 + └── tapinstall.exe + +This structure is equal to what building tapinstall would create. Replace 7600 +with the major number of your WinDDK version. Finally call buildtap.py with +"--ti=tapinstall". + +Please note that the NSIS packaging (-p) step will fail if you don't have +tapinstall.exe available. Also don't use the "-c" flag or the above directories +will get wiped before MakeNSIS is able to find them. + +Install/Update/Remove +--------------------- + +The driver can be installed using a command-line tool, tapinstall.exe, which is +bundled with OpenVPN and tap-windows installers. Note that in some versions of +OpenVPN tapinstall.exe is called devcon.exe. To install, update or remove the +tap-windows NDIS 6 driver follow these steps: + +- place tapinstall.exe/devcon.exe to your PATH +- open an Administrator shell +- cd to **dist** +- cd to **amd64** or **i386** depending on your system's processor architecture. + +Install:: + + $ tapinstall install OemVista.inf TAP0901 + +Update:: + + $ tapinstall update OemVista.inf TAP0901 + +Remove:: + + $ tapinstall remove TAP0901 + +Notes on proxies +---------------- + +It is possible to build tap-windows6 without connectivity to the Internet but +any attempt to timestamp the driver will fail. For this reason configure your +outbound proxy server before starting the build. Note that the command prompt +also needs to be restarted to make use of new proxy settings. + +Notes on Authenticode signatures +-------------------------------- + +Recent Windows versions such as Windows 10 are fairly picky about the +Authenticode signatures of kernel-mode drivers. In addition making older Windows +versions such as Vista play along with signatures that Windows 10 accepts can be +rather challenging. A good starting point on this topic is the +`building tap-windows6 `_ +page on the OpenVPN community wiki. As that page points out, having two +completely separate Authenticode signatures may be the only reasonable option. +Fortunately there is a tool, `Sign-Tap6 `_, +which can be used to append secondary signatures to the tap-windows6 driver or +to handle the entire signing process if necessary. + +License +------- + +See the file `COPYING `_. diff --git a/third_party/tap-windows6/bin/amd64/OemVista.inf b/third_party/tap-windows6/bin/amd64/OemVista.inf new file mode 100644 index 00000000000..d92e2558b35 --- /dev/null +++ b/third_party/tap-windows6/bin/amd64/OemVista.inf @@ -0,0 +1,191 @@ +; **************************************************************************** +; * Copyright (C) 2002-2014 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\oemvista.inf +; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm + +; INSTALL/REMOVE DRIVER +; tapinstall install OemVista.inf tapoas +; tapinstall update OemVista.inf tapoas +; tapinstall remove tapoas + +;********************************************************* +; 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 = tap0901.cat + ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} + Provider = %Provider% + Class = Net + +; This version number should match the version +; number given in SOURCES. + DriverVer=04/21/2016,9.00.00.21 + +[Strings] + DeviceDescription = "TAP-Windows Adapter V9" + Provider = "TAP-Windows Provider V9" + +;---------------------------------------------------------------- +; Manufacturer + Product Section (Done) +;---------------------------------------------------------------- +[Manufacturer] + %Provider% = tap0901, NTamd64 + +[tap0901.NTamd64] + %DeviceDescription% = tap0901.ndi, root\tap0901 ; Root enumerated + %DeviceDescription% = tap0901.ndi, tap0901 ; Legacy + +;--------------------------------------------------------------- +; 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 ------------ + +[tap0901.ndi] + CopyFiles = tap0901.driver, tap0901.files + AddReg = tap0901.reg + AddReg = tap0901.params.reg + Characteristics = + *IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD + *MediaType = 0x0 ; NdisMedium802_3 + *PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[tap0901.ndi.Services] + AddService = tap0901, 2, tap0901.service + +[tap0901.reg] + HKR, Ndi, Service, 0, "tap0901" + HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" + HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + HKR, , Manufacturer, 0, "%Provider%" + HKR, , ProductName, 0, "%DeviceDescription%" + +[tap0901.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 --------------- + +[tap0901.service] + DisplayName = %DeviceDescription% + ServiceType = 1 + StartType = 3 + ErrorControl = 1 + LoadOrderGroup = NDIS + ServiceBinary = %12%\tap0901.sys + +;----------------------------------------------------------------- +; File Installation +;----------------------------------------------------------------- + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +; SourceDisksNames +; diskid = description[, [tagfile] [, , subdir]] +; 1 = "Intel Driver Disk 1",e100bex.sys,, + +[SourceDisksNames] + 1 = %DeviceDescription%, tap0901.sys + +; SourceDisksFiles +; filename_on_source = diskID[, [subdir][, size]] +; e100bex.sys = 1,, ; on distribution disk 1 + +[SourceDisksFiles] +tap0901.sys = 1 + +[DestinationDirs] + tap0901.files = 11 + tap0901.driver = 12 + +[tap0901.files] +; TapPanel.cpl,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK +; cipsrvr.exe,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +[tap0901.driver] + tap0901.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +;--------------------------------------------------------------- +; End +;--------------------------------------------------------------- diff --git a/third_party/tap-windows6/bin/amd64/tap0901.cat b/third_party/tap-windows6/bin/amd64/tap0901.cat new file mode 100644 index 00000000000..70ddd2c266e Binary files /dev/null and b/third_party/tap-windows6/bin/amd64/tap0901.cat differ diff --git a/third_party/tap-windows6/bin/amd64/tap0901.sys b/third_party/tap-windows6/bin/amd64/tap0901.sys new file mode 100755 index 00000000000..c6628201cdd Binary files /dev/null and b/third_party/tap-windows6/bin/amd64/tap0901.sys differ diff --git a/third_party/tap-windows6/bin/amd64/tapinstall.exe b/third_party/tap-windows6/bin/amd64/tapinstall.exe new file mode 100755 index 00000000000..3321052abe2 Binary files /dev/null and b/third_party/tap-windows6/bin/amd64/tapinstall.exe differ diff --git a/third_party/tap-windows6/bin/i386/OemVista.inf b/third_party/tap-windows6/bin/i386/OemVista.inf new file mode 100644 index 00000000000..6cd67913114 --- /dev/null +++ b/third_party/tap-windows6/bin/i386/OemVista.inf @@ -0,0 +1,191 @@ +; **************************************************************************** +; * Copyright (C) 2002-2014 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\oemvista.inf +; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm + +; INSTALL/REMOVE DRIVER +; tapinstall install OemVista.inf tapoas +; tapinstall update OemVista.inf tapoas +; tapinstall remove tapoas + +;********************************************************* +; 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 = tap0901.cat + ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} + Provider = %Provider% + Class = Net + +; This version number should match the version +; number given in SOURCES. + DriverVer=04/21/2016,9.00.00.21 + +[Strings] + DeviceDescription = "TAP-Windows Adapter V9" + Provider = "TAP-Windows Provider V9" + +;---------------------------------------------------------------- +; Manufacturer + Product Section (Done) +;---------------------------------------------------------------- +[Manufacturer] + %Provider% = tap0901 + +[tap0901] + %DeviceDescription% = tap0901.ndi, root\tap0901 ; Root enumerated + %DeviceDescription% = tap0901.ndi, tap0901 ; Legacy + +;--------------------------------------------------------------- +; 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 ------------ + +[tap0901.ndi] + CopyFiles = tap0901.driver, tap0901.files + AddReg = tap0901.reg + AddReg = tap0901.params.reg + Characteristics = + *IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD + *MediaType = 0x0 ; NdisMedium802_3 + *PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[tap0901.ndi.Services] + AddService = tap0901, 2, tap0901.service + +[tap0901.reg] + HKR, Ndi, Service, 0, "tap0901" + HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" + HKR, Ndi\Interfaces, LowerRange, 0, "ethernet" + HKR, , Manufacturer, 0, "%Provider%" + HKR, , ProductName, 0, "%DeviceDescription%" + +[tap0901.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 --------------- + +[tap0901.service] + DisplayName = %DeviceDescription% + ServiceType = 1 + StartType = 3 + ErrorControl = 1 + LoadOrderGroup = NDIS + ServiceBinary = %12%\tap0901.sys + +;----------------------------------------------------------------- +; File Installation +;----------------------------------------------------------------- + +;----------------- Copy Flags ------------ +; COPYFLG_NOSKIP = 0x02 +; COPYFLG_NOVERSIONCHECK = 0x04 +;----------------- Copy Flags ------------ + +; SourceDisksNames +; diskid = description[, [tagfile] [, , subdir]] +; 1 = "Intel Driver Disk 1",e100bex.sys,, + +[SourceDisksNames] + 1 = %DeviceDescription%, tap0901.sys + +; SourceDisksFiles +; filename_on_source = diskID[, [subdir][, size]] +; e100bex.sys = 1,, ; on distribution disk 1 + +[SourceDisksFiles] +tap0901.sys = 1 + +[DestinationDirs] + tap0901.files = 11 + tap0901.driver = 12 + +[tap0901.files] +; TapPanel.cpl,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK +; cipsrvr.exe,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +[tap0901.driver] + tap0901.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK + +;--------------------------------------------------------------- +; End +;--------------------------------------------------------------- diff --git a/third_party/tap-windows6/bin/i386/tap0901.cat b/third_party/tap-windows6/bin/i386/tap0901.cat new file mode 100644 index 00000000000..d8453103dab Binary files /dev/null and b/third_party/tap-windows6/bin/i386/tap0901.cat differ diff --git a/third_party/tap-windows6/bin/i386/tap0901.sys b/third_party/tap-windows6/bin/i386/tap0901.sys new file mode 100755 index 00000000000..fcba857d8fa Binary files /dev/null and b/third_party/tap-windows6/bin/i386/tap0901.sys differ diff --git a/third_party/tap-windows6/bin/i386/tapinstall.exe b/third_party/tap-windows6/bin/i386/tapinstall.exe new file mode 100755 index 00000000000..67e662a56fd Binary files /dev/null and b/third_party/tap-windows6/bin/i386/tapinstall.exe differ diff --git a/third_party/tap-windows6/bin/include/tap-windows.h b/third_party/tap-windows6/bin/include/tap-windows.h new file mode 100644 index 00000000000..d546a5b1cb9 --- /dev/null +++ b/third_party/tap-windows6/bin/include/tap-windows.h @@ -0,0 +1,74 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_WIN_H +#define __TAP_WIN_H + +/* + * ============= + * TAP IOCTLs + * ============= + */ + +#define TAP_WIN_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +/* Present in 8.1 */ + +#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED) + +/* Added in 8.2 */ + +/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */ +#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED) + +/* + * ================= + * Registry keys + * ================= + */ + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +/* + * ====================== + * Filesystem prefixes + * ====================== + */ + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAP_WIN_SUFFIX ".tap" + +#endif // __TAP_WIN_H diff --git a/third_party/tap-windows6/buildtap.py b/third_party/tap-windows6/buildtap.py new file mode 100644 index 00000000000..377138a40e8 --- /dev/null +++ b/third_party/tap-windows6/buildtap.py @@ -0,0 +1,513 @@ +# build TAP-Windows NDIS 6.0 driver + +import sys, os, re, shutil, tarfile + +import paths + +class BuildTAPWindows(object): + # regex for doing search replace on @MACRO@ style macros + macro_amper = re.compile(r"@(\w+)@") + + def __init__(self, opt): + self.opt = opt # command line options + if not opt.src: + raise ValueError("source directory undefined") + self.top = os.path.realpath(opt.src) # top-level dir + self.src = os.path.join(self.top, 'src') # src/openvpn dir + if opt.tapinstall: + self.top_tapinstall = os.path.realpath(opt.tapinstall) # tapinstall dir + else: + self.top_tapinstall = None + if opt.package: + raise ValueError("parameter -p must be used with --ti") + + # path to DDK + self.ddk_path = paths.DDK + + # path to makensis + self.makensis = os.path.join(paths.NSIS, 'makensis.exe') + + # Driver Kit build system strings + # This driver builds for a specific set of architectures. + # The driver kit build system has a set of architecture-specific paths. + # The installation script has a set of architecture-specific paths. + # The driver kit build system has a set of architecture-specific parameters. + # architecture -> build system parameter map + self.architecture_platform_map = {"i386": "x86", "amd64": "x64"} + # architecture -> build system folder name fragment map + self.architecture_platform_folder_map = {"i386": "x86", "amd64": "amd64"} + # supported arch names, also installation script folder names + self.architectures_supported = self.architecture_platform_map.keys() + + # driver signing options + self.codesign = opt.codesign + self.sign_cn = opt.cert + self.sign_cert = opt.certfile + self.cert_pw = opt.certpw + self.crosscert = os.path.join(self.top, opt.crosscert) + + self.inf2cat_cmd = os.path.join(self.ddk_path, 'bin', 'selfsign', 'Inf2Cat') + self.signtool_cmd = os.path.join(self.ddk_path, 'bin', 'x86', 'SignTool') + + self.timestamp_server = opt.timestamp + + # split a path into a list of components + @staticmethod + def path_split(path): + folders = [] + while True: + path, folder = os.path.split(path) + if folder: + folders.append(folder) + else: + if path: + folders.append(path) + break + folders.reverse() + return folders + + # run a command + def system(self, cmd): + print "RUN:", cmd + os.system(cmd) + + # make a directory + def mkdir(self, dir): + try: + os.mkdir(dir) + except: + pass + else: + print "MKDIR", dir + + # make a directory including parents + def makedirs(self, dir): + try: + os.makedirs(dir) + except: + pass + else: + print "MAKEDIRS", dir + + # copy a file + def cp(self, src, dest): + print "COPY %s %s" % (src, dest) + shutil.copy2(src, dest) + + # make a tarball + @staticmethod + def make_tarball(output_filename, source_dir, arcname=None): + if arcname is None: + arcname = os.path.basename(source_dir) + tar = tarfile.open(output_filename, "w:gz") + tar.add(source_dir, arcname=arcname) + tar.close() + print "***** Generated tarball:", output_filename + + # remove a file + def rm(self, file): + print "RM", file + os.remove(file) + + # remove whole directory tree, like rm -rf + def rmtree(self, dir): + print "RMTREE", dir + shutil.rmtree(dir, ignore_errors=True) + + # return path of dist directory + def dist_path(self): + return os.path.join(self.top, 'dist') + + # return path of dist include directory + def dist_include_path(self): + return os.path.join(self.dist_path(), 'include') + + # make a distribution directory (if absent) and return its path + def mkdir_dist(self, arch): + dir = self.drvdir(self.dist_path(), arch) + self.makedirs(dir) + return dir + + # run an MSVC command + def build_vc(self, cmd): + self.system('cmd /c "vcvarsall.bat x86 && %s"' % (cmd,)) + + # parse version.m4 file + def parse_version_m4(self): + kv = {} + r = re.compile(r'^define\(\[?(\w+)\]?,\s*\[(.*)\]\)') + with open(os.path.join(self.top, 'version.m4')) as f: + for line in f: + line = line.rstrip() + m = re.match(r, line) + if m: + g = m.groups() + kv[g[0]] = g[1] + return kv + + # our tap-windows version.m4 settings + def gen_version_m4(self, arch): + kv = self.parse_version_m4() + if self.opt.oas: # for OpenVPN Connect (i.e. OpenVPN Access Server) + kv['PRODUCT_NAME'] = "OpenVPNAS" + kv['PRODUCT_TAP_WIN_DEVICE_DESCRIPTION'] = "TAP Adapter OAS NDIS 6.0" + kv['PRODUCT_TAP_WIN_PROVIDER'] = "TAP-Win32 Provider OAS" + kv['PRODUCT_TAP_WIN_COMPONENT_ID'] = "tapoas" + + return kv + + # DDK major version number (as a string) + def ddk_major(self): + ddk_ver = os.path.basename(self.ddk_path) + ddk_ver_major = re.match(r'^(\d+)\.', ddk_ver).groups()[0] + return ddk_ver_major + + # return tapinstall source directory + def tapinstall_src(self): + if self.top_tapinstall: + d = os.path.join(self.top_tapinstall, self.ddk_major()) + if os.path.exists(d): + return d + else: + return self.top_tapinstall + + # preprocess a file, doing macro substitution on @MACRO@ + def preprocess(self, kv, in_path, out_path=None): + def repfn(m): + var, = m.groups() + return kv.get(var, '') + if out_path is None: + out_path = in_path + with open(in_path+'.in') as f: + modtxt = re.sub(self.macro_amper, repfn, f.read()) + with open(out_path, "w") as f: + f.write(modtxt) + + # set up configuration files for building tap driver + def config_tap(self, arch): + kv = self.gen_version_m4(arch) + drvdir = self.drvdir(self.src, arch) + self.mkdir(drvdir) + self.preprocess(kv, os.path.join(self.src, "OemVista.inf"), os.path.join(drvdir, "OemVista.inf")) + self.preprocess(kv, os.path.join(self.src, "SOURCES")) + self.preprocess(kv, os.path.join(self.src, "config.h")) + + # set up configuration files for building tapinstall + def config_tapinstall(self, arch): + kv = {} + tisrc = self.tapinstall_src() + self.preprocess(kv, os.path.join(tisrc, "sources")) + + # build a "build" file using DDK + def build_ddk(self, dir, arch, debug): + setenv_bat = os.path.join(self.ddk_path, 'bin', 'setenv.bat') + target = 'chk' if debug else 'fre' + target += ' ' + self.architecture_platform_map[arch] + + target += ' wlh' # vista + + self.system('cmd /c "%s %s %s no_oacr && cd %s && build -cef"' % ( + setenv_bat, + self.ddk_path, + target, + dir + )) + + # copy tap driver files to dist + def copy_tap_to_dist(self, arch): + dist = self.mkdir_dist(arch) + drvdir = self.drvdir(self.src, arch) + for dirpath, dirnames, filenames in os.walk(drvdir): + for f in filenames: + path = os.path.join(dirpath, f) + if f.endswith('.inf') or f.endswith('.cat') or f.endswith('.sys'): + destfn = os.path.join(dist, f) + self.cp(path, destfn) + + # copy tap-windows.h to dist/include + def copy_include(self): + incdir = os.path.join(self.dist_path(), 'include') + self.makedirs(incdir) + self.cp(os.path.join(self.src, 'tap-windows.h'), incdir) + + # copy tapinstall to dist + def copy_tapinstall_to_dist(self, arch): + dist = self.mkdir_dist(arch) + t = os.path.basename(dist) + tisrc = self.tapinstall_src() + for dirpath, dirnames, filenames in os.walk(tisrc): + if os.path.basename(dirpath) == t: + for f in filenames: + path = os.path.join(dirpath, f) + if f == 'tapinstall.exe': + destfn = os.path.join(dist, f) + self.cp(path, destfn) + + # copy dist-src to dist; dist-src contains prebuilt files + # for some old platforms (such as win2k) + def copy_dist_src_to_dist(self): + dist_path = self.path_split(self.dist_path()) + dist_src = os.path.join(self.top, "dist-src") + baselen = len(self.path_split(dist_src)) + for dirpath, dirnames, filenames in os.walk(dist_src): + dirpath_split = self.path_split(dirpath) + depth = len(dirpath_split) - baselen + dircomp = () + if depth > 0: + dircomp = dirpath_split[-depth:] + for exclude_dir in ('.svn', '.git'): + if exclude_dir in dirnames: + dirnames.remove(exclude_dir) + for f in filenames: + path = os.path.join(dirpath, f) + destdir = os.path.join(*(dist_path + dircomp)) + destfn = os.path.join(destdir, f) + self.makedirs(destdir) + self.cp(path, destfn) + + # build, sign, and verify tap driver + def build_tap(self): + for arch in self.architectures_supported: + print "***** BUILD TAP arch=%s" % (arch,) + self.config_tap(arch=arch) + self.build_ddk(dir=self.src, arch=arch, debug=opt.debug) + if self.codesign: + self.sign_verify(arch=arch) + self.copy_tap_to_dist(arch=arch) + + # build tapinstall + def build_tapinstall(self): + for arch in self.architectures_supported: + print "***** BUILD TAPINSTALL arch=%s" % (arch,) + tisrc = self.tapinstall_src() + # Only build if we have a chance of succeeding + sources_in = os.path.join(tisrc, "sources.in") + if os.path.isfile(sources_in): + self.config_tapinstall(arch=arch) + self.build_ddk(tisrc, arch=arch, debug=opt.debug) + if self.codesign: + self.sign_verify_ti(arch=arch) + self.copy_tapinstall_to_dist(arch) + + # build tap driver and tapinstall + def build(self): + self.build_tap() + self.copy_include() + if self.top_tapinstall: + self.build_tapinstall() + self.copy_dist_src_to_dist() + + print "***** Generated files" + self.dump_dist() + + tapbase = "tapoas6" if self.opt.oas else "tap6" + self.make_tarball(os.path.join(self.top, tapbase+".tar.gz"), + self.dist_path(), + tapbase) + + # package the produced files into an NSIS installer + def package(self): + + # Generate license.txt and converting LF -> CRLF as we go. Apparently + # this type of conversion will stop working in Python 3.x. + dst = open(os.path.join(self.dist_path(), 'license.txt'), mode='wb') + + for f in (os.path.join(self.top, 'COPYING'), os.path.join(self.top, 'COPYRIGHT.GPL')): + src=open(f, mode='rb') + dst.write(src.read()+'\r\n') + src.close() + + dst.close() + + # Copy tap-windows.h to dist include directory + self.mkdir(self.dist_include_path()) + self.cp(os.path.join(self.src, 'tap-windows.h'), self.dist_include_path()) + + # Get variables from version.m4 + kv = self.gen_version_m4("amd64") + + installer_type = "" + if self.opt.oas: + installer_type = "-oas" + installer_file=os.path.join(self.top, 'tap-windows'+installer_type+'-'+kv['PRODUCT_VERSION']+'-I'+kv['PRODUCT_TAP_WIN_BUILD']+'.exe') + + installer_cmd = "\"\"%s\" -DDEVCON32=%s -DDEVCON64=%s -DDEVCON_BASENAME=%s -DPRODUCT_TAP_WIN_COMPONENT_ID=%s -DPRODUCT_NAME=%s -DPRODUCT_PUBLISHER=\"%s\" -DPRODUCT_VERSION=%s -DPRODUCT_TAP_WIN_BUILD=%s -DOUTPUT=%s -DIMAGE=%s %s\"" % \ + (self.makensis, + self.tifile(arch="i386"), + self.tifile(arch="amd64"), + 'tapinstall.exe', + kv['PRODUCT_TAP_WIN_COMPONENT_ID'], + kv['PRODUCT_NAME'], + kv['PRODUCT_PUBLISHER'], + kv['PRODUCT_VERSION'], + kv['PRODUCT_TAP_WIN_BUILD'], + installer_file, + self.dist_path(), + os.path.join(self.top, 'installer', 'tap-windows6.nsi') + ) + + self.system(installer_cmd) + self.sign(installer_file) + + # like find . | sort + def enum_tree(self, dir): + data = [] + for dirpath, dirnames, filenames in os.walk(dir): + data.append(dirpath) + for f in filenames: + data.append(os.path.join(dirpath, f)) + data.sort() + return data + + # show files in dist + def dump_dist(self): + for f in self.enum_tree(self.dist_path()): + print f + + # remove generated files from given directory tree + def clean_tree(self, top): + for dirpath, dirnames, filenames in os.walk(top): + for d in list(dirnames): + if d in ('.svn', '.git'): + dirnames.remove(d) + else: + path = os.path.join(dirpath, d) + deldir = False + if d in ('amd64', 'i386', 'dist'): + deldir = True + if d.endswith('_amd64') or d.endswith('_x86'): + deldir = True + if deldir: + self.rmtree(path) + dirnames.remove(d) + for f in filenames: + path = os.path.join(dirpath, f) + if f in ('SOURCES', 'sources', 'config.h'): + self.rm(path) + if f.endswith('.log') or f.endswith('.wrn') or f.endswith('.cod'): + self.rm(path) + + # remove generated files for both tap-windows and tapinstall + def clean(self): + self.clean_tree(self.top) + if self.top_tapinstall: + self.clean_tree(self.top_tapinstall) + + # BEGIN Driver signing + + def drvdir(self, dir, arch): + return os.path.join(dir, arch) + + def drvfile(self, arch, ext): + dd = self.drvdir(self.src, arch) + for dirpath, dirnames, filenames in os.walk(dd): + catlist = [ f for f in filenames if f.endswith(ext) ] + assert(len(catlist)==1) + return os.path.join(dd, catlist[0]) + + def tifile(self, arch): + return os.path.join(self.tapinstall_src(), 'objfre_wlh_' + self.architecture_platform_folder_map[arch], arch, 'tapinstall.exe') + + def inf2cat(self, arch): + if arch == "amd64": + oslist = "Vista_X64,Server2008_X64,Server2008R2_X64,7_X64" + elif arch == "i386": + oslist = "Vista_X86,Server2008_X86,7_X86" + else: + print "ERROR: inf2cat OS list not known for architecture %s!!" % (arch) + self.system("%s /driver:%s /os:%s" % (self.inf2cat_cmd, self.drvdir(self.src, arch), oslist)) + + def sign(self, file): + certspec = "" + if self.sign_cert: + certspec += "/f '%s' " % self.sign_cert + if self.cert_pw: + certspec += "/p '%s' " % self.cert_pw + else: + certspec += "/s my /n %s " % self.sign_cn + + self.system("%s sign /v /ac %s %s /t %s %s" % ( + self.signtool_cmd, + self.crosscert, + certspec, + self.timestamp_server, + file, + )) + + def sign_driver(self, arch): + self.sign(self.drvfile(arch, '.cat')) + + def verify(self, arch): + self.system("%s verify /kp /v /c %s %s" % ( + self.signtool_cmd, + self.drvfile(arch, '.cat'), + self.drvfile(arch, '.sys'), + )) + + def sign_verify(self, arch): + self.inf2cat(arch) + self.sign_driver(arch) + self.verify(arch) + + def sign_verify_ti(self, arch): + self.sign(self.tifile(arch)) + self.system("%s verify /pa %s" % (self.signtool_cmd, self.tifile(arch))) + + # END Driver signing + +if __name__ == '__main__': + # parse options + import optparse, codecs + codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None) # windows UTF-8 hack + op = optparse.OptionParser() + + # defaults + src = os.path.dirname(os.path.realpath(__file__)) + cert = "openvpn" + crosscert = "MSCV-VSClass3.cer" # cross certs available here: http://msdn.microsoft.com/en-us/library/windows/hardware/dn170454(v=vs.85).aspx + timestamp = "http://timestamp.verisign.com/scripts/timstamp.dll" + + op.add_option("-s", "--src", dest="src", metavar="SRC", + + default=src, + help="TAP-Windows top-level directory, default=%s" % (src,)) + op.add_option("--ti", dest="tapinstall", metavar="TAPINSTALL", + help="tapinstall (i.e. devcon) directory (optional)") + op.add_option("-d", "--debug", action="store_true", dest="debug", + help="enable debug build") + op.add_option("-c", "--clean", action="store_true", dest="clean", + help="do an nmake clean before build") + op.add_option("-b", "--build", action="store_true", dest="build", + help="build TAP-Windows and possibly tapinstall (add -c to clean before build)") + op.add_option("--sign", action="store_true", dest="codesign", + default=False, help="sign the driver files") + op.add_option("-p", "--package", action="store_true", dest="package", + help="generate an NSIS installer from the compiled files") + op.add_option("--cert", dest="cert", metavar="CERT", + default=cert, + help="Common name of code signing certificate, default=%s" % (cert,)) + op.add_option("--certfile", dest="certfile", metavar="CERTFILE", + help="Path to the code signing certificate") + op.add_option("--certpw", dest="certpw", metavar="CERTPW", + help="Password for the code signing certificate/key (optional)") + op.add_option("--crosscert", dest="crosscert", metavar="CERT", + default=crosscert, + help="The cross-certificate file to use, default=%s" % (crosscert,)) + op.add_option("--timestamp", dest="timestamp", metavar="URL", + default=timestamp, + help="Timestamp URL to use, default=%s" % (timestamp,)) + op.add_option("-a", "--oas", action="store_true", dest="oas", + help="Build for OpenVPN Access Server clients") + (opt, args) = op.parse_args() + + if len(sys.argv) <= 1: + op.print_help() + sys.exit(1) + + btw = BuildTAPWindows(opt) + if opt.clean: + btw.clean() + if opt.build: + btw.build() + if opt.package: + btw.package() diff --git a/third_party/tap-windows6/installer/ShellLink.dll b/third_party/tap-windows6/installer/ShellLink.dll new file mode 100644 index 00000000000..f57ded34dab Binary files /dev/null and b/third_party/tap-windows6/installer/ShellLink.dll differ diff --git a/third_party/tap-windows6/installer/icon.ico b/third_party/tap-windows6/installer/icon.ico new file mode 100755 index 00000000000..03ea0b1dccf Binary files /dev/null and b/third_party/tap-windows6/installer/icon.ico differ diff --git a/third_party/tap-windows6/installer/install-whirl.bmp b/third_party/tap-windows6/installer/install-whirl.bmp new file mode 100755 index 00000000000..03f33fce967 Binary files /dev/null and b/third_party/tap-windows6/installer/install-whirl.bmp differ diff --git a/third_party/tap-windows6/installer/tap-windows6.nsi b/third_party/tap-windows6/installer/tap-windows6.nsi new file mode 100755 index 00000000000..2d0356673be --- /dev/null +++ b/third_party/tap-windows6/installer/tap-windows6.nsi @@ -0,0 +1,340 @@ +; **************************************************************************** +; * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. * +; * Copyright (C) 2012 Alon Bar-Lev * +; * 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 /SOLID lzma + +!addplugindir . +!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}-I${PRODUCT_TAP_WIN_BUILD}" + +!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 ${PRODUCT_NAME} will only run on Windows Vista 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\OemVista.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\OemVista.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\OemVista.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" "" + ; set runas admin flag on the addtap link + ShellLink::SetRunAsAdministrator "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Add a new TAP virtual ethernet adapter.lnk" + Pop $0 + ${If} $0 != 0 + DetailPrint "Setting RunAsAdmin flag on addtap failed: status = $0" + ${Endif} + CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Delete ALL TAP virtual ethernet adapters.lnk" "$INSTDIR\bin\deltapall.bat" "" + ; set runas admin flag on the deltapall link + ShellLink::SetRunAsAdministrator "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Delete ALL TAP virtual ethernet adapters.lnk" + Pop $0 + ${If} $0 != 0 + DetailPrint "Setting RunAsAdmin flag on deltapall failed: status = $0" + ${Endif} +SectionEnd + +Section /o "TAP SDK" SecTAPSDK + SetOverwrite on + SetOutPath "$INSTDIR\include" + File "${IMAGE}\include\tap-windows.h" +SectionEnd + +Function .onInit + ${GetParameters} $R0 + ClearErrors + +${IfNot} ${AtLeastWinVista} + MessageBox MB_OK "This package requires at least Windows Vista" + SetErrorLevel 1 + Quit +${EndIf} + + !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 + + ; 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\OemVista.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}" + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "NoModify" 1 + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "NoRepair" 1 + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "Publisher" "${PRODUCT_PUBLISHER}" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "HelpLink" "https://openvpn.net/index.php/open-source.html" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "URLInfoAbout" "https://openvpn.net" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "EstimatedSize" "$0" + +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\OemVista.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/third_party/tap-windows6/paths.py b/third_party/tap-windows6/paths.py new file mode 100644 index 00000000000..85984469b75 --- /dev/null +++ b/third_party/tap-windows6/paths.py @@ -0,0 +1,3 @@ +# Windows 7 DDK +DDK = "C:\\winddk\\7600.16385.1" +NSIS = "C:\\Program Files (x86)\\NSIS" diff --git a/third_party/tap-windows6/src/MAKEFILE b/third_party/tap-windows6/src/MAKEFILE new file mode 100644 index 00000000000..d5bedee2a8e --- /dev/null +++ b/third_party/tap-windows6/src/MAKEFILE @@ -0,0 +1,8 @@ +# +# 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 driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def + diff --git a/third_party/tap-windows6/src/OemVista.inf.in b/third_party/tap-windows6/src/OemVista.inf.in new file mode 100644 index 00000000000..a549bf6b4f2 --- /dev/null +++ b/third_party/tap-windows6/src/OemVista.inf.in @@ -0,0 +1,195 @@ +; **************************************************************************** +; * Copyright (C) 2002-2014 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\oemvista.inf +; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm + +; INSTALL/REMOVE DRIVER +; tapinstall install OemVista.inf tapoas +; tapinstall update OemVista.inf tapoas +; tapinstall remove tapoas + +;********************************************************* +; 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@, NTx86, NTamd64 + +[@PRODUCT_TAP_WIN_COMPONENT_ID@.NTx86] + %DeviceDescription% = @PRODUCT_TAP_WIN_COMPONENT_ID@.ndi, root\@PRODUCT_TAP_WIN_COMPONENT_ID@ ; Root enumerated + %DeviceDescription% = @PRODUCT_TAP_WIN_COMPONENT_ID@.ndi, @PRODUCT_TAP_WIN_COMPONENT_ID@ ; Legacy + +[@PRODUCT_TAP_WIN_COMPONENT_ID@.NTamd64] + %DeviceDescription% = @PRODUCT_TAP_WIN_COMPONENT_ID@.ndi, root\@PRODUCT_TAP_WIN_COMPONENT_ID@ ; Root enumerated + %DeviceDescription% = @PRODUCT_TAP_WIN_COMPONENT_ID@.ndi, @PRODUCT_TAP_WIN_COMPONENT_ID@ ; Legacy + +;--------------------------------------------------------------- +; 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@ + *IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD + *MediaType = 0x0 ; NdisMedium802_3 + *PhysicalMediaType = 14 ; NdisPhysicalMedium802_3 + +[@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] [, , 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/third_party/tap-windows6/src/SOURCES.in b/third_party/tap-windows6/src/SOURCES.in new file mode 100644 index 00000000000..f39ad40167a --- /dev/null +++ b/third_party/tap-windows6/src/SOURCES.in @@ -0,0 +1,60 @@ +# Build TAP-Windows NDIS 6.0 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 \ + $(DDK_LIB_PATH)\wdmsec.lib + +INCLUDES=$(DDK_INCLUDE_PATH) .. + +# System and NDIS wrapper definitions. +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER=1 +C_DEFINES=$(C_DEFINES) -DNDIS61_MINIPORT=1 + +# The TAP version numbers here must be >= +# PRODUCT_TAP_WIN32_MIN_x values defined in version.m4 +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 + +# Generate a linker map file just in case we need one for debugging +LINKER_FLAGS=$(LINKER_FLAGS) /INCREMENTAL:NO /MAP /MAPINFO:EXPORTS + + +# MSC_WARNING_LEVEL=/W4 /WX + +# disabled warning 4201 -- nonstandard extension used : nameless struct/union +# disabled warning 4214 -- nonstandard extension used : bit field types other than int +# disabled warning 4127 -- conditional expression is constant +MSC_WARNING_LEVEL=$(MSC_WARNING_LEVEL) /wd4201 /wd4214 /wd4127 + +SOURCES=\ + tapdrvr.c \ + adapter.c \ + device.c \ + rxpath.c \ + txpath.c \ + oidrequest.c \ + mem.c \ + macinfo.c \ + error.c \ + dhcp.c \ + resource.rc diff --git a/third_party/tap-windows6/src/adapter.c b/third_party/tap-windows6/src/adapter.c new file mode 100644 index 00000000000..6f24246b6d1 --- /dev/null +++ b/third_party/tap-windows6/src/adapter.c @@ -0,0 +1,1485 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +NDIS_OID TAPSupportedOids[] = { + OID_GEN_HARDWARE_STATUS, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_DRIVER_VERSION, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_STATISTICS, +#ifdef IMPLEMENT_OPTIONAL_OIDS + OID_GEN_TRANSMIT_QUEUE_LENGTH, // Optional +#endif // IMPLEMENT_OPTIONAL_OIDS + OID_GEN_LINK_PARAMETERS, + OID_GEN_INTERRUPT_MODERATION, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, +#ifdef IMPLEMENT_OPTIONAL_OIDS + OID_802_3_XMIT_DEFERRED, // Optional + OID_802_3_XMIT_MAX_COLLISIONS, // Optional + OID_802_3_RCV_OVERRUN, // Optional + OID_802_3_XMIT_UNDERRUN, // Optional + OID_802_3_XMIT_HEARTBEAT_FAILURE, // Optional + OID_802_3_XMIT_TIMES_CRS_LOST, // Optional + OID_802_3_XMIT_LATE_COLLISIONS, // Optional + OID_PNP_CAPABILITIES, // Optional +#endif // IMPLEMENT_OPTIONAL_OIDS +}; + +//====================================================================== +// TAP NDIS 6 Miniport Callbacks +//====================================================================== + +// Returns with reference count initialized to one. +PTAP_ADAPTER_CONTEXT +tapAdapterContextAllocate(__in NDIS_HANDLE MiniportAdapterHandle) { + PTAP_ADAPTER_CONTEXT adapter = NULL; + + adapter = (PTAP_ADAPTER_CONTEXT)NdisAllocateMemoryWithTagPriority( + GlobalData.NdisDriverHandle, sizeof(TAP_ADAPTER_CONTEXT), TAP_ADAPTER_TAG, + NormalPoolPriority); + + if (adapter) { + NET_BUFFER_LIST_POOL_PARAMETERS nblPoolParameters = {0}; + + NdisZeroMemory(adapter, sizeof(TAP_ADAPTER_CONTEXT)); + + adapter->MiniportAdapterHandle = MiniportAdapterHandle; + + // Initialize cancel-safe IRP queue + tapIrpCsqInitialize(&adapter->PendingReadIrpQueue); + + // Initialize TAP send packet queue. + tapPacketQueueInitialize(&adapter->SendPacketQueue); + + // Allocate the adapter lock. + NdisAllocateSpinLock(&adapter->AdapterLock); + + // NBL pool for making TAP receive indications. + NdisZeroMemory(&nblPoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS)); + + // Initialize event used to determine when all receive NBLs have been returned. + NdisInitializeEvent(&adapter->ReceiveNblInFlightCountZeroEvent); + + nblPoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + nblPoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; + nblPoolParameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1; + nblPoolParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT; + nblPoolParameters.ContextSize = 0; + // nblPoolParameters.ContextSize = sizeof(RX_NETBUFLIST_RSVD); + nblPoolParameters.fAllocateNetBuffer = TRUE; + nblPoolParameters.PoolTag = TAP_RX_NBL_TAG; + +#pragma warning(suppress : 28197) + adapter->ReceiveNblPool = + NdisAllocateNetBufferListPool(adapter->MiniportAdapterHandle, &nblPoolParameters); + + if (adapter->ReceiveNblPool == NULL) { + DEBUGP(("[TAP] Couldn't allocate adapter receive NBL pool\n")); + NdisFreeMemory(adapter, 0, 0); + } + + // Add initial reference. Normally removed in AdapterHalt. + adapter->RefCount = 1; + + // Safe for multiple removes. + NdisInitializeListHead(&adapter->AdapterListLink); + + // + // The miniport adapter is initially powered up + // + adapter->CurrentPowerState = NdisDeviceStateD0; + } + + return adapter; +} + +VOID tapReadPermanentAddress(__in PTAP_ADAPTER_CONTEXT Adapter, + __in NDIS_HANDLE ConfigurationHandle, __out MACADDR PermanentAddress) { + NDIS_STATUS status; + NDIS_CONFIGURATION_PARAMETER *configParameter; + NDIS_STRING macKey = NDIS_STRING_CONST("MAC"); + ANSI_STRING macString; + BOOLEAN macFromRegistry = FALSE; + + // Read MAC parameter from registry. + NdisReadConfiguration(&status, &configParameter, ConfigurationHandle, &macKey, + NdisParameterString); + + if (status == NDIS_STATUS_SUCCESS) { + if ((configParameter->ParameterType == NdisParameterString) && + (configParameter->ParameterData.StringData.Length >= 12)) { + if (RtlUnicodeStringToAnsiString(&macString, &configParameter->ParameterData.StringData, + TRUE) == STATUS_SUCCESS) { + macFromRegistry = ParseMAC(PermanentAddress, macString.Buffer); + RtlFreeAnsiString(&macString); + } + } + } + + if (!macFromRegistry) { + // + // There is no (valid) address stashed in the registry parameter. + // + // Make up a dummy mac address based on the ANSI representation of the + // NetCfgInstanceId GUID. + // + GenerateRandomMac(PermanentAddress, MINIPORT_INSTANCE_ID(Adapter)); + } +} + +NDIS_STATUS +tapReadConfiguration(__in PTAP_ADAPTER_CONTEXT Adapter) { + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + NDIS_CONFIGURATION_OBJECT configObject; + NDIS_HANDLE configHandle; + + DEBUGP(("[TAP] --> tapReadConfiguration\n")); + + // + // Setup defaults in case configuration cannot be opened. + // + Adapter->MtuSize = ETHERNET_MTU; + Adapter->MediaStateAlwaysConnected = FALSE; + Adapter->LogicalMediaState = FALSE; + Adapter->AllowNonAdmin = FALSE; + // + // Open the registry for this adapter to read advanced + // configuration parameters stored by the INF file. + // + NdisZeroMemory(&configObject, sizeof(configObject)); + + { C_ASSERT(sizeof(configObject) >= NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1); } + configObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT; + configObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1; + configObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1; + + configObject.NdisHandle = Adapter->MiniportAdapterHandle; + configObject.Flags = 0; + + status = NdisOpenConfigurationEx(&configObject, &configHandle); + + // Read on the opened configuration handle. + if (status == NDIS_STATUS_SUCCESS) { + NDIS_CONFIGURATION_PARAMETER *configParameter; + NDIS_STRING mkey = NDIS_STRING_CONST("NetCfgInstanceId"); + + // + // Read NetCfgInstanceId from the registry. + // ------------------------------------ + // NetCfgInstanceId is required to create device and associated + // symbolic link for the adapter device. + // + // NetCfgInstanceId is a GUID string provided by NDIS that identifies + // the adapter instance. An example is: + // + // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0} + // + // Other names are derived from NetCfgInstanceId. For example, MiniportName: + // + // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0} + // + NdisReadConfiguration(&status, &configParameter, configHandle, &mkey, NdisParameterString); + + if (status == NDIS_STATUS_SUCCESS) { + if (configParameter->ParameterType == NdisParameterString && + configParameter->ParameterData.StringData.Length <= + sizeof(Adapter->NetCfgInstanceIdBuffer) - sizeof(WCHAR)) { + DEBUGP(("[TAP] NdisReadConfiguration (NetCfgInstanceId=%wZ)\n", + &configParameter->ParameterData.StringData)); + + // Save NetCfgInstanceId as UNICODE_STRING. + Adapter->NetCfgInstanceId.Length = Adapter->NetCfgInstanceId.MaximumLength = + configParameter->ParameterData.StringData.Length; + + Adapter->NetCfgInstanceId.Buffer = Adapter->NetCfgInstanceIdBuffer; + + NdisMoveMemory(Adapter->NetCfgInstanceId.Buffer, + configParameter->ParameterData.StringData.Buffer, + Adapter->NetCfgInstanceId.Length); + + // Save NetCfgInstanceId as ANSI_STRING as well. + if (RtlUnicodeStringToAnsiString(&Adapter->NetCfgInstanceIdAnsi, + &configParameter->ParameterData.StringData, + TRUE) != STATUS_SUCCESS) { + DEBUGP(("[TAP] NetCfgInstanceId ANSI name conversion failed\n")); + status = NDIS_STATUS_RESOURCES; + } + } else { + DEBUGP(("[TAP] NetCfgInstanceId has invalid type\n")); + status = NDIS_STATUS_INVALID_DATA; + } + } else { + DEBUGP(("[TAP] NetCfgInstanceId failed\n")); + status = NDIS_STATUS_INVALID_DATA; + } + + if (status == NDIS_STATUS_SUCCESS) { + NDIS_STATUS localStatus; // Use default if these fail. + NDIS_CONFIGURATION_PARAMETER *configParameter; + NDIS_STRING mtuKey = NDIS_STRING_CONST("MTU"); + NDIS_STRING mediaStatusKey = NDIS_STRING_CONST("MediaStatus"); +#if ENABLE_NONADMIN + NDIS_STRING allowNonAdminKey = NDIS_STRING_CONST("AllowNonAdmin"); +#endif + + // Read MTU from the registry. + NdisReadConfiguration(&localStatus, &configParameter, configHandle, &mtuKey, + NdisParameterInteger); + + if (localStatus == NDIS_STATUS_SUCCESS) { + if (configParameter->ParameterType == NdisParameterInteger) { + int mtu = configParameter->ParameterData.IntegerData; + + if (mtu == 0) { + mtu = ETHERNET_MTU; + } + + // Sanity check + if (mtu < MINIMUM_MTU) { + mtu = MINIMUM_MTU; + } else if (mtu > MAXIMUM_MTU) { + mtu = MAXIMUM_MTU; + } + + Adapter->MtuSize = mtu; + } + } + + DEBUGP(("[%s] Using MTU %d\n", MINIPORT_INSTANCE_ID(Adapter), Adapter->MtuSize)); + + // Read MediaStatus setting from registry. + NdisReadConfiguration(&localStatus, &configParameter, configHandle, &mediaStatusKey, + NdisParameterInteger); + + if (localStatus == NDIS_STATUS_SUCCESS) { + if (configParameter->ParameterType == NdisParameterInteger) { + if (configParameter->ParameterData.IntegerData == 0) { + // Connect state is appplication controlled. + DEBUGP(("[%s] Initial MediaConnectState: Application Controlled\n", + MINIPORT_INSTANCE_ID(Adapter))); + + Adapter->MediaStateAlwaysConnected = FALSE; + Adapter->LogicalMediaState = FALSE; + } else { + // Connect state is always connected. + DEBUGP(("[%s] Initial MediaConnectState: Always Connected\n", + MINIPORT_INSTANCE_ID(Adapter))); + + Adapter->MediaStateAlwaysConnected = TRUE; + Adapter->LogicalMediaState = TRUE; + } + } + } + + // Read MAC PermanentAddress setting from registry. + tapReadPermanentAddress(Adapter, configHandle, Adapter->PermanentAddress); + + DEBUGP(("[%s] Using MAC PermanentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", + MINIPORT_INSTANCE_ID(Adapter), Adapter->PermanentAddress[0], + Adapter->PermanentAddress[1], Adapter->PermanentAddress[2], + Adapter->PermanentAddress[3], Adapter->PermanentAddress[4], + Adapter->PermanentAddress[5])); + + // Now seed the current MAC address with the permanent address. + ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress); + + DEBUGP(("[%s] Using MAC CurrentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", + MINIPORT_INSTANCE_ID(Adapter), Adapter->CurrentAddress[0], Adapter->CurrentAddress[1], + Adapter->CurrentAddress[2], Adapter->CurrentAddress[3], Adapter->CurrentAddress[4], + Adapter->CurrentAddress[5])); + + // Read optional AllowNonAdmin setting from registry. +#if ENABLE_NONADMIN + NdisReadConfiguration(&localStatus, &configParameter, configHandle, &allowNonAdminKey, + NdisParameterInteger); + + if (localStatus == NDIS_STATUS_SUCCESS) { + if (configParameter->ParameterType == NdisParameterInteger) { + Adapter->AllowNonAdmin = TRUE; + } + } +#endif + } + + // Close the configuration handle. + NdisCloseConfiguration(configHandle); + } else { + DEBUGP(("[TAP] Couldn't open adapter registry\n")); + } + + DEBUGP(("[TAP] <-- tapReadConfiguration; status = %8.8X\n", status)); + + return status; +} + +VOID tapAdapterContextAddToGlobalList(__in PTAP_ADAPTER_CONTEXT Adapter) { + LOCK_STATE lockState; + PLIST_ENTRY listEntry = &Adapter->AdapterListLink; + + // Acquire global adapter list lock. + NdisAcquireReadWriteLock(&GlobalData.Lock, + TRUE, // Acquire for write + &lockState); + + // Adapter context should NOT be in any list. + ASSERT((listEntry->Flink == listEntry) && (listEntry->Blink == listEntry)); + + // Add reference to persist until after removal. + tapAdapterContextReference(Adapter); + + // Add the adapter context to the global list. + InsertTailList(&GlobalData.AdapterList, &Adapter->AdapterListLink); + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock, &lockState); +} + +VOID tapAdapterContextRemoveFromGlobalList(__in PTAP_ADAPTER_CONTEXT Adapter) { + LOCK_STATE lockState; + + // Acquire global adapter list lock. + NdisAcquireReadWriteLock(&GlobalData.Lock, + TRUE, // Acquire for write + &lockState); + + // Remove the adapter context from the global list. + RemoveEntryList(&Adapter->AdapterListLink); + + // Safe for multiple removes. + NdisInitializeListHead(&Adapter->AdapterListLink); + + // Remove reference added in tapAdapterContextAddToGlobalList. + tapAdapterContextDereference(Adapter); + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock, &lockState); +} + +// Returns with added reference on adapter context. +PTAP_ADAPTER_CONTEXT +tapAdapterContextFromDeviceObject(__in PDEVICE_OBJECT DeviceObject) { + LOCK_STATE lockState; + + // Acquire global adapter list lock. + NdisAcquireReadWriteLock(&GlobalData.Lock, + FALSE, // Acquire for read + &lockState); + + if (!IsListEmpty(&GlobalData.AdapterList)) { + PLIST_ENTRY entry = GlobalData.AdapterList.Flink; + PTAP_ADAPTER_CONTEXT adapter; + + while (entry != &GlobalData.AdapterList) { + adapter = CONTAINING_RECORD(entry, TAP_ADAPTER_CONTEXT, AdapterListLink); + + // Match on DeviceObject + if (adapter->DeviceObject == DeviceObject) { + // Add reference to adapter context. + tapAdapterContextReference(adapter); + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock, &lockState); + + return adapter; + } + + // Move to next entry + entry = entry->Flink; + } + } + + // Release global adapter list lock. + NdisReleaseReadWriteLock(&GlobalData.Lock, &lockState); + + return (PTAP_ADAPTER_CONTEXT)NULL; +} + +NDIS_STATUS +AdapterSetOptions(__in NDIS_HANDLE NdisDriverHandle, __in NDIS_HANDLE DriverContext) +/*++ +Routine Description: + + The MiniportSetOptions function registers optional handlers. For each + optional handler that should be registered, this function makes a call + to NdisSetOptionalHandlers. + + MiniportSetOptions runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + DriverContext The context handle + +Return Value: + + NDIS_STATUS_xxx code + +--*/ +{ + NDIS_STATUS status; + + DEBUGP(("[TAP] --> AdapterSetOptions\n")); + + // + // Set any optional handlers by filling out the appropriate struct and + // calling NdisSetOptionalHandlers here. + // + + status = NDIS_STATUS_SUCCESS; + + DEBUGP(("[TAP] <-- AdapterSetOptions; status = %8.8X\n", status)); + + return status; +} + +NDIS_STATUS +AdapterCreate(__in NDIS_HANDLE MiniportAdapterHandle, __in NDIS_HANDLE MiniportDriverContext, + __in PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters) { + PTAP_ADAPTER_CONTEXT adapter = NULL; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(MiniportDriverContext); + UNREFERENCED_PARAMETER(MiniportInitParameters); + + DEBUGP(("[TAP] --> AdapterCreate\n")); + + do { + NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES regAttributes = {0}; + NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES genAttributes = {0}; + NDIS_PNP_CAPABILITIES pnpCapabilities = {0}; + + // + // Allocate adapter context structure and initialize all the + // memory resources for sending and receiving packets. + // + // Returns with reference count initialized to one. + // + adapter = tapAdapterContextAllocate(MiniportAdapterHandle); + + if (adapter == NULL) { + DEBUGP(("[TAP] Couldn't allocate adapter memory\n")); + status = NDIS_STATUS_RESOURCES; + break; + } + + // Enter the Initializing state. + DEBUGP(("[TAP] Miniport State: Initializing\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportInitializingState; + tapAdapterReleaseLock(adapter, FALSE); + + // + // First read adapter configuration from registry. + // ----------------------------------------------- + // Subsequent device registration will fail if NetCfgInstanceId + // has not been successfully read. + // + status = tapReadConfiguration(adapter); + + // + // Set the registration attributes. + // + { + C_ASSERT(sizeof(regAttributes) >= + NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1); + } + regAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES; + regAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + regAttributes.Header.Revision = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1; + + regAttributes.MiniportAdapterContext = adapter; + regAttributes.AttributeFlags = TAP_ADAPTER_ATTRIBUTES_FLAGS; + + regAttributes.CheckForHangTimeInSeconds = TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS; + regAttributes.InterfaceType = TAP_INTERFACE_TYPE; + + // NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(TAP_ADAPTER_CONTEXT); + status = NdisMSetMiniportAttributes(MiniportAdapterHandle, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)®Attributes); + + if (status != NDIS_STATUS_SUCCESS) { + DEBUGP(("[TAP] NdisSetOptionalHandlers failed; Status 0x%08x\n", status)); + break; + } + + // + // Next, set the general attributes. + // + { + C_ASSERT(sizeof(genAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1); + } + genAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES; + genAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + genAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; + + // + // Specify the medium type that the NIC can support but not + // necessarily the medium type that the NIC currently uses. + // + genAttributes.MediaType = TAP_MEDIUM_TYPE; + + // + // Specifiy medium type that the NIC currently uses. + // + genAttributes.PhysicalMediumType = TAP_PHYSICAL_MEDIUM; + + // + // Specifiy the maximum network frame size, in bytes, that the NIC + // supports excluding the header. + // + genAttributes.MtuSize = TAP_FRAME_MAX_DATA_SIZE; + genAttributes.MaxXmitLinkSpeed = TAP_XMIT_SPEED; + genAttributes.XmitLinkSpeed = TAP_XMIT_SPEED; + genAttributes.MaxRcvLinkSpeed = TAP_RECV_SPEED; + genAttributes.RcvLinkSpeed = TAP_RECV_SPEED; + + if (adapter->MediaStateAlwaysConnected) { + DEBUGP(("[%s] Initial MediaConnectState: Connected\n", MINIPORT_INSTANCE_ID(adapter))); + + genAttributes.MediaConnectState = MediaConnectStateConnected; + } else { + DEBUGP(("[%s] Initial MediaConnectState: Disconnected\n", MINIPORT_INSTANCE_ID(adapter))); + + genAttributes.MediaConnectState = MediaConnectStateDisconnected; + } + + genAttributes.MediaDuplexState = MediaDuplexStateFull; + + // + // The maximum number of bytes the NIC can provide as lookahead data. + // If that value is different from the size of the lookahead buffer + // supported by bound protocols, NDIS will call MiniportOidRequest to + // set the size of the lookahead buffer provided by the miniport driver + // to the minimum of the miniport driver and protocol(s) values. If the + // driver always indicates up full packets with + // NdisMIndicateReceiveNetBufferLists, it should set this value to the + // maximum total frame size, which excludes the header. + // + // Upper-layer drivers examine lookahead data to determine whether a + // packet that is associated with the lookahead data is intended for + // one or more of their clients. If the underlying driver supports + // multipacket receive indications, bound protocols are given full net + // packets on every indication. Consequently, this value is identical + // to that returned for OID_GEN_RECEIVE_BLOCK_SIZE. + // + genAttributes.LookaheadSize = TAP_MAX_LOOKAHEAD; + genAttributes.MacOptions = TAP_MAC_OPTIONS; + genAttributes.SupportedPacketFilters = TAP_SUPPORTED_FILTERS; + + // + // The maximum number of multicast addresses the NIC driver can manage. + // This list is global for all protocols bound to (or above) the NIC. + // Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from + // the NIC driver when attempting to set the multicast address list, + // even if the number of elements in the given list is less than the + // number originally returned for this query. + // + genAttributes.MaxMulticastListSize = TAP_MAX_MCAST_LIST; + genAttributes.MacAddressLength = MACADDR_SIZE; + + // + // Return the MAC address of the NIC burnt in the hardware. + // + ETH_COPY_NETWORK_ADDRESS(genAttributes.PermanentMacAddress, adapter->PermanentAddress); + + // + // Return the MAC address the NIC is currently programmed to use. Note + // that this address could be different from the permananent address as + // the user can override using registry. Read NdisReadNetworkAddress + // doc for more info. + // + ETH_COPY_NETWORK_ADDRESS(genAttributes.CurrentMacAddress, adapter->CurrentAddress); + + genAttributes.RecvScaleCapabilities = NULL; + genAttributes.AccessType = TAP_ACCESS_TYPE; + genAttributes.DirectionType = TAP_DIRECTION_TYPE; + genAttributes.ConnectionType = TAP_CONNECTION_TYPE; + genAttributes.IfType = TAP_IFTYPE; + genAttributes.IfConnectorPresent = TAP_HAS_PHYSICAL_CONNECTOR; + genAttributes.SupportedStatistics = TAP_SUPPORTED_STATISTICS; + genAttributes.SupportedPauseFunctions = + NdisPauseFunctionsUnsupported; // IEEE 802.3 pause frames + genAttributes.DataBackFillSize = 0; + genAttributes.ContextBackFillSize = 0; + + // + // The SupportedOidList is an array of OIDs for objects that the + // underlying driver or its NIC supports. Objects include general, + // media-specific, and implementation-specific objects. NDIS forwards a + // subset of the returned list to protocols that make this query. That + // is, NDIS filters any supported statistics OIDs out of the list + // because protocols never make statistics queries. + // + genAttributes.SupportedOidList = TAPSupportedOids; + genAttributes.SupportedOidListLength = sizeof(TAPSupportedOids); + genAttributes.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED; + + // + // Set power management capabilities + // + NdisZeroMemory(&pnpCapabilities, sizeof(pnpCapabilities)); + pnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; + pnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; + genAttributes.PowerManagementCapabilities = &pnpCapabilities; + + status = NdisMSetMiniportAttributes(MiniportAdapterHandle, + (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&genAttributes); + + if (status != NDIS_STATUS_SUCCESS) { + DEBUGP(("[TAP] NdisMSetMiniportAttributes failed; Status 0x%08x\n", status)); + break; + } + + // + // Create the Win32 device I/O interface. + // + status = CreateTapDevice(adapter); + + if (status == NDIS_STATUS_SUCCESS) { + // Add this adapter to the global adapter list. + tapAdapterContextAddToGlobalList(adapter); + } else { + DEBUGP(("[TAP] CreateTapDevice failed; Status 0x%08x\n", status)); + break; + } + } while (FALSE); + + if (status == NDIS_STATUS_SUCCESS) { + // Enter the Paused state if initialization is complete. + DEBUGP(("[TAP] Miniport State: Paused\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportPausedState; + tapAdapterReleaseLock(adapter, FALSE); + } else { + if (adapter != NULL) { + DEBUGP(("[TAP] Miniport State: Halted\n")); + + // + // Remove reference when adapter context was allocated + // --------------------------------------------------- + // This should result in freeing adapter context memory + // and assiciated resources. + // + tapAdapterContextDereference(adapter); + adapter = NULL; + } + } + + DEBUGP(("[TAP] <-- AdapterCreate; status = %8.8X\n", status)); + + return status; +} + +VOID AdapterHalt(__in NDIS_HANDLE MiniportAdapterContext, __in NDIS_HALT_ACTION HaltAction) +/*++ + +Routine Description: + + Halt handler is called when NDIS receives IRP_MN_STOP_DEVICE, + IRP_MN_SUPRISE_REMOVE or IRP_MN_REMOVE_DEVICE requests from the PNP + manager. Here, the driver should free all the resources acquired in + MiniportInitialize and stop access to the hardware. NDIS will not submit + any further request once this handler is invoked. + + 1) Free and unmap all I/O resources. + 2) Disable interrupt and deregister interrupt handler. + 3) Deregister shutdown handler regsitered by + NdisMRegisterAdapterShutdownHandler . + 4) Cancel all queued up timer callbacks. + 5) Finally wait indefinitely for all the outstanding receive + packets indicated to the protocol to return. + + MiniportHalt runs at IRQL = PASSIVE_LEVEL. + + +Arguments: + + MiniportAdapterContext Pointer to the Adapter + HaltAction The reason for halting the adapter + +Return Value: + + None. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + + UNREFERENCED_PARAMETER(HaltAction); + + DEBUGP(("[TAP] --> AdapterHalt\n")); + + // Enter the Halted state. + DEBUGP(("[TAP] Miniport State: Halted\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportHaltedState; + tapAdapterReleaseLock(adapter, FALSE); + + // Remove this adapter from the global adapter list. + tapAdapterContextRemoveFromGlobalList(adapter); + + // BUGBUG!!! Call AdapterShutdownEx to do some of the work of stopping. + + // TODO!!! More... + + // + // Destroy the TAP Win32 device. + // + DestroyTapDevice(adapter); + + // + // Remove initial reference added in AdapterCreate. + // ------------------------------------------------ + // This should result in freeing adapter context memory + // and resources allocated in AdapterCreate. + // + tapAdapterContextDereference(adapter); + adapter = NULL; + + DEBUGP(("[TAP] <-- AdapterHalt\n")); +} + +VOID tapWaitForReceiveNblInFlightCountZeroEvent(__in PTAP_ADAPTER_CONTEXT Adapter) { + LONG nblCount; + + // + // Wait until higher-level protocol has returned all NBLs + // to the driver. + // + + // Add one NBL "bias" to insure allow event to be reset safely. + nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0); + NdisResetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent); + + // + // Now remove the bias and wait for the ReceiveNblInFlightCountZeroEvent + // if the count returned is not zero. + // + nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount >= 0); + + if (nblCount) { + LARGE_INTEGER startTime, currentTime; + + NdisGetSystemUpTimeEx(&startTime); + + for (;;) { + BOOLEAN waitResult = + NdisWaitEvent(&Adapter->ReceiveNblInFlightCountZeroEvent, TAP_WAIT_POLL_LOOP_TIMEOUT); + + NdisGetSystemUpTimeEx(¤tTime); + + if (waitResult) { + break; + } + + DEBUGP(("[%s] Waiting for %d in-flight receive NBLs to be returned.\n", + MINIPORT_INSTANCE_ID(Adapter), Adapter->ReceiveNblInFlightCount)); + } + + DEBUGP(("[%s] Waited %d ms for all in-flight NBLs to be returned.\n", + MINIPORT_INSTANCE_ID(Adapter), (currentTime.LowPart - startTime.LowPart))); + } +} + +NDIS_STATUS +AdapterPause(__in NDIS_HANDLE MiniportAdapterContext, + __in PNDIS_MINIPORT_PAUSE_PARAMETERS PauseParameters) +/*++ + +Routine Description: + + When a miniport receives a pause request, it enters into a Pausing state. + The miniport should not indicate up any more network data. Any pending + send requests must be completed, and new requests must be rejected with + NDIS_STATUS_PAUSED. + + Once all sends have been completed and all recieve NBLs have returned to + the miniport, the miniport enters the Paused state. + + While paused, the miniport can still service interrupts from the hardware + (to, for example, continue to indicate NDIS_STATUS_MEDIA_CONNECT + notifications). + + The miniport must continue to be able to handle status indications and OID + requests. MiniportPause is different from MiniportHalt because, in + general, the MiniportPause operation won't release any resources. + MiniportPause must not attempt to acquire any resources where allocation + can fail, since MiniportPause itself must not fail. + + + MiniportPause runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + MiniportAdapterContext Pointer to the Adapter + MiniportPauseParameters Additional information about the pause operation + +Return Value: + + If the miniport is able to immediately enter the Paused state, it should + return NDIS_STATUS_SUCCESS. + + If the miniport must wait for send completions or pending receive NBLs, it + should return NDIS_STATUS_PENDING now, and call NDISMPauseComplete when the + miniport has entered the Paused state. + + No other return value is permitted. The pause operation must not fail. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(PauseParameters); + + DEBUGP(("[TAP] --> AdapterPause\n")); + + // Enter the Pausing state. + DEBUGP(("[TAP] Miniport State: Pausing\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportPausingState; + tapAdapterReleaseLock(adapter, FALSE); + + // + // Stop the flow of network data through the receive path + // ------------------------------------------------------ + // In the Pausing and Paused state tapAdapterSendAndReceiveReady + // will prevent new calls to NdisMIndicateReceiveNetBufferLists + // to indicate additional receive NBLs to the host. + // + // However, there may be some in-flight NBLs owned by the driver + // that have been indicated to the host but have not yet been + // returned. + // + // Wait here for all in-flight receive indications to be returned. + // + tapWaitForReceiveNblInFlightCountZeroEvent(adapter); + + // + // Stop the flow of network data through the send path + // --------------------------------------------------- + // The initial implementation of the NDIS 6 send path follows the + // NDIS 5 pattern. Under this approach every send packet is copied + // into a driver-owned TAP_PACKET structure and the NBL owned by + // higher-level protocol is immediatly completed. + // + // With this deep-copy approach the driver never claims ownership + // of any send NBL. + // + // A future implementation may queue send NBLs and thereby eliminate + // the need for the unnecessary allocation and deep copy of each packet. + // + // So, nothing to do here for the send path for now... + + status = NDIS_STATUS_SUCCESS; + + // Enter the Paused state. + DEBUGP(("[TAP] Miniport State: Paused\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportPausedState; + tapAdapterReleaseLock(adapter, FALSE); + + DEBUGP(("[TAP] <-- AdapterPause; status = %8.8X\n", status)); + + return status; +} + +NDIS_STATUS +AdapterRestart(__in NDIS_HANDLE MiniportAdapterContext, + __in PNDIS_MINIPORT_RESTART_PARAMETERS RestartParameters) +/*++ + +Routine Description: + + When a miniport receives a restart request, it enters into a Restarting + state. The miniport may begin indicating received data (e.g., using + NdisMIndicateReceiveNetBufferLists), handling status indications, and + processing OID requests in the Restarting state. However, no sends will be + requested while the miniport is in the Restarting state. + + Once the miniport is ready to send data, it has entered the Running state. + The miniport informs NDIS that it is in the Running state by returning + NDIS_STATUS_SUCCESS from this MiniportRestart function; or if this function + has already returned NDIS_STATUS_PENDING, by calling NdisMRestartComplete. + + + MiniportRestart runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + MiniportAdapterContext Pointer to the Adapter + RestartParameters Additional information about the restart operation + +Return Value: + + If the miniport is able to immediately enter the Running state, it should + return NDIS_STATUS_SUCCESS. + + If the miniport is still in the Restarting state, it should return + NDIS_STATUS_PENDING now, and call NdisMRestartComplete when the miniport + has entered the Running state. + + Other NDIS_STATUS codes indicate errors. If an error is encountered, the + miniport must return to the Paused state (i.e., stop indicating receives). + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(RestartParameters); + + DEBUGP(("[TAP] --> AdapterRestart\n")); + + // Enter the Restarting state. + DEBUGP(("[TAP] Miniport State: Restarting\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportRestartingState; + tapAdapterReleaseLock(adapter, FALSE); + + status = NDIS_STATUS_SUCCESS; + + if (status == NDIS_STATUS_SUCCESS) { + // Enter the Running state. + DEBUGP(("[TAP] Miniport State: Running\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportRunning; + tapAdapterReleaseLock(adapter, FALSE); + } else { + // Enter the Paused state if restart failed. + DEBUGP(("[TAP] Miniport State: Paused\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportPausedState; + tapAdapterReleaseLock(adapter, FALSE); + } + + DEBUGP(("[TAP] <-- AdapterRestart; status = %8.8X\n", status)); + + return status; +} + +BOOLEAN +tapAdapterReadAndWriteReady(__in PTAP_ADAPTER_CONTEXT Adapter) +/*++ + +Routine Description: + + This routine determines whether the adapter device interface can + accept read and write operations. + +Arguments: + + Adapter Pointer to our adapter context + +Return Value: + + Returns TRUE if the adapter state allows it to queue IRPs passed to + the device read and write callbacks. +--*/ +{ + if (!Adapter->TapDeviceCreated) { + // TAP device not created or is being destroyed. + return FALSE; + } + + if (Adapter->TapFileObject == NULL) { + // TAP application file object not open. + return FALSE; + } + + if (!Adapter->TapFileIsOpen) { + // TAP application file object may be closing. + return FALSE; + } + + if (!Adapter->LogicalMediaState) { + // Don't handle read/write if media not connected. + return FALSE; + } + + if (Adapter->CurrentPowerState != NdisDeviceStateD0) { + // Don't handle read/write if device is not fully powered. + return FALSE; + } + + return TRUE; +} + +NDIS_STATUS +tapAdapterSendAndReceiveReady(__in PTAP_ADAPTER_CONTEXT Adapter) +/*++ + +Routine Description: + + This routine determines whether the adapter NDIS send and receive + paths are ready. + + This routine examines various adapter state variables and returns + a value that indicates whether the adapter NDIS interfaces can + accept send packets or indicate receive packets. + + In normal operation the adapter may temporarily enter and then exit + a not-ready condition. In particular, the adapter becomes not-ready + when in the Pausing/Paused states, but may become ready again when + Restarted. + + Runs at IRQL <= DISPATCH_LEVEL + +Arguments: + + Adapter Pointer to our adapter context + +Return Value: + + Returns NDIS_STATUS_SUCCESS if the adapter state allows it to + accept send packets and indicate receive packets. + + Otherwise it returns a NDIS_STATUS value other than NDIS_STATUS_SUCCESS. + These status values can be used directly as the completion status for + packets that must be completed immediatly in the send path. +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + // + // Check various state variables to insure adapter is ready. + // + tapAdapterAcquireLock(Adapter, FALSE); + + if (!Adapter->LogicalMediaState) { + status = NDIS_STATUS_MEDIA_DISCONNECTED; + } else if (Adapter->CurrentPowerState != NdisDeviceStateD0) { + status = NDIS_STATUS_LOW_POWER_STATE; + } else if (Adapter->ResetInProgress) { + status = NDIS_STATUS_RESET_IN_PROGRESS; + } else { + switch (Adapter->Locked.AdapterState) { + case MiniportPausingState: + case MiniportPausedState: + status = NDIS_STATUS_PAUSED; + break; + + case MiniportHaltedState: + status = NDIS_STATUS_INVALID_STATE; + break; + + default: + status = NDIS_STATUS_SUCCESS; + break; + } + } + + tapAdapterReleaseLock(Adapter, FALSE); + + return status; +} + +BOOLEAN +AdapterCheckForHangEx(__in NDIS_HANDLE MiniportAdapterContext) +/*++ + +Routine Description: + + The MiniportCheckForHangEx handler is called to report the state of the + NIC, or to monitor the responsiveness of an underlying device driver. + This is an optional function. If this handler is not specified, NDIS + judges the driver unresponsive when the driver holds + MiniportQueryInformation or MiniportSetInformation requests for a + time-out interval (deafult 4 sec), and then calls the driver's + MiniportReset function. A NIC driver's MiniportInitialize function can + extend NDIS's time-out interval by calling NdisMSetAttributesEx to + avoid unnecessary resets. + + MiniportCheckForHangEx runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + + MiniportAdapterContext Pointer to our adapter + +Return Value: + + TRUE NDIS calls the driver's MiniportReset function. + FALSE Everything is fine + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + + // DEBUGP (("[TAP] --> AdapterCheckForHangEx\n")); + + // DEBUGP (("[TAP] <-- AdapterCheckForHangEx; status = FALSE\n")); + + return FALSE; // Everything is fine +} + +NDIS_STATUS +AdapterReset(__in NDIS_HANDLE MiniportAdapterContext, __out PBOOLEAN AddressingReset) +/*++ + +Routine Description: + + MiniportResetEx is a required to issue a hardware reset to the NIC + and/or to reset the driver's software state. + + 1) The miniport driver can optionally complete any pending + OID requests. NDIS will submit no further OID requests + to the miniport driver for the NIC being reset until + the reset operation has finished. After the reset, + NDIS will resubmit to the miniport driver any OID requests + that were pending but not completed by the miniport driver + before the reset. + + 2) A deserialized miniport driver must complete any pending send + operations. NDIS will not requeue pending send packets for + a deserialized driver since NDIS does not maintain the send + queue for such a driver. + + 3) If MiniportReset returns NDIS_STATUS_PENDING, the driver must + complete the original request subsequently with a call to + NdisMResetComplete. + + MiniportReset runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + +AddressingReset - If multicast or functional addressing information + or the lookahead size, is changed by a reset, + MiniportReset must set the variable at AddressingReset + to TRUE before it returns control. This causes NDIS to + call the MiniportSetInformation function to restore + the information. + +MiniportAdapterContext - Pointer to our adapter + +Return Value: + + NDIS_STATUS + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + NDIS_STATUS status; + + UNREFERENCED_PARAMETER(MiniportAdapterContext); + UNREFERENCED_PARAMETER(AddressingReset); + + DEBUGP(("[TAP] --> AdapterReset\n")); + + // Indicate that adapter reset is in progress. + adapter->ResetInProgress = TRUE; + + // See note above... + *AddressingReset = FALSE; + + // BUGBUG!!! TODO!!! Lots of work here... + + // Indicate that adapter reset has completed. + adapter->ResetInProgress = FALSE; + + status = NDIS_STATUS_SUCCESS; + + DEBUGP(("[TAP] <-- AdapterReset; status = %8.8X\n", status)); + + return status; +} + +VOID AdapterDevicePnpEventNotify(__in NDIS_HANDLE MiniportAdapterContext, + __in PNET_DEVICE_PNP_EVENT NetDevicePnPEvent) { + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + + DEBUGP(("[TAP] --> AdapterDevicePnpEventNotify\n")); + + /* + switch (NetDevicePnPEvent->DevicePnPEvent) + { + case NdisDevicePnPEventSurpriseRemoved: + // + // Called when NDIS receives IRP_MN_SUPRISE_REMOVAL. + // NDIS calls MiniportHalt function after this call returns. + // + MP_SET_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED); + DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventSurpriseRemoved\n", + Adapter); break; + + case NdisDevicePnPEventPowerProfileChanged: + // + // After initializing a miniport driver and after miniport driver + // receives an OID_PNP_SET_POWER notification that specifies + // a device power state of NdisDeviceStateD0 (the powered-on state), + // NDIS calls the miniport's MiniportPnPEventNotify function with + // PnPEvent set to NdisDevicePnPEventPowerProfileChanged. + // + DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: + NdisDevicePnPEventPowerProfileChanged\n", Adapter); + + if (NetDevicePnPEvent->InformationBufferLength == sizeof(ULONG)) + { + ULONG NdisPowerProfile = *((PULONG)NetDevicePnPEvent->InformationBuffer); + + if (NdisPowerProfile == NdisPowerProfileBattery) + { + DEBUGP(MP_INFO, "[%p] The host system is running on battery power\n", + Adapter); + } + if (NdisPowerProfile == NdisPowerProfileAcOnLine) + { + DEBUGP(MP_INFO, "[%p] The host system is running on AC power\n", Adapter); + } + } + break; + + default: + DEBUGP(MP_ERROR, "[%p] MPDevicePnpEventNotify: unknown PnP event 0x%x\n", Adapter, + NetDevicePnPEvent->DevicePnPEvent); + } + */ + DEBUGP(("[TAP] <-- AdapterDevicePnpEventNotify\n")); +} + +VOID AdapterShutdownEx(__in NDIS_HANDLE MiniportAdapterContext, + __in NDIS_SHUTDOWN_ACTION ShutdownAction) +/*++ + +Routine Description: + + The MiniportShutdownEx handler restores hardware to its initial state when + the system is shut down, whether by the user or because an unrecoverable + system error occurred. This is to ensure that the NIC is in a known + state and ready to be reinitialized when the machine is rebooted after + a system shutdown occurs for any reason, including a crash dump. + + Here just disable the interrupt and stop the DMA engine. Do not free + memory resources or wait for any packet transfers to complete. Do not call + into NDIS at this time. + + This can be called at aribitrary IRQL, including in the context of a + bugcheck. + +Arguments: + + MiniportAdapterContext Pointer to our adapter + ShutdownAction The reason why NDIS called the shutdown function + +Return Value: + + None. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + + UNREFERENCED_PARAMETER(ShutdownAction); + UNREFERENCED_PARAMETER(MiniportAdapterContext); + + DEBUGP(("[TAP] --> AdapterShutdownEx\n")); + + // Enter the Shutdown state. + DEBUGP(("[TAP] Miniport State: Shutdown\n")); + + tapAdapterAcquireLock(adapter, FALSE); + adapter->Locked.AdapterState = MiniportShutdownState; + tapAdapterReleaseLock(adapter, FALSE); + + // + // BUGBUG!!! FlushIrpQueues??? + // + + DEBUGP(("[TAP] <-- AdapterShutdownEx\n")); +} + +// Free adapter context memory and associated resources. +VOID tapAdapterContextFree(__in PTAP_ADAPTER_CONTEXT Adapter) { + PLIST_ENTRY listEntry = &Adapter->AdapterListLink; + + DEBUGP(("[TAP] --> tapAdapterContextFree\n")); + + // Adapter context should already be removed. + ASSERT((listEntry->Flink == listEntry) && (listEntry->Blink == listEntry)); + + // Insure that adapter context has been removed from global adapter list. + RemoveEntryList(&Adapter->AdapterListLink); + + // Free the adapter lock. + NdisFreeSpinLock(&Adapter->AdapterLock); + + // Free the ANSI NetCfgInstanceId buffer. + if (Adapter->NetCfgInstanceIdAnsi.Buffer != NULL) { + RtlFreeAnsiString(&Adapter->NetCfgInstanceIdAnsi); + } + + Adapter->NetCfgInstanceIdAnsi.Buffer = NULL; + + // Free the receive NBL pool. + if (Adapter->ReceiveNblPool != NULL) { + NdisFreeNetBufferListPool(Adapter->ReceiveNblPool); + } + + Adapter->ReceiveNblPool = NULL; + + NdisFreeMemory(Adapter, 0, 0); + + DEBUGP(("[TAP] <-- tapAdapterContextFree\n")); +} +ULONG +tapGetNetBufferFrameType(__in PNET_BUFFER NetBuffer) +/*++ + +Routine Description: + + Reads the network frame's destination address to determine the type + (broadcast, multicast, etc) + + Runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + + NetBuffer The NB to examine + +Return Value: + + NDIS_PACKET_TYPE_BROADCAST + NDIS_PACKET_TYPE_MULTICAST + NDIS_PACKET_TYPE_DIRECTED + +--*/ +{ + PETH_HEADER ethernetHeader; + + ethernetHeader = (PETH_HEADER)NdisGetDataBuffer(NetBuffer, sizeof(ETH_HEADER), NULL, 1, 0); + + ASSERT(ethernetHeader); + + if (ETH_IS_BROADCAST(ethernetHeader->dest)) { + return NDIS_PACKET_TYPE_BROADCAST; + } else if (ETH_IS_MULTICAST(ethernetHeader->dest)) { + return NDIS_PACKET_TYPE_MULTICAST; + } else { + return NDIS_PACKET_TYPE_DIRECTED; + } +} + +ULONG +tapGetNetBufferCountsFromNetBufferList(__in PNET_BUFFER_LIST NetBufferList, + __inout_opt PULONG TotalByteCount // Of all linked NBs + ) +/*++ + +Routine Description: + + Returns the number of net buffers linked to the net buffer list. + + Optionally retuens the total byte count of all net buffers linked + to the net buffer list + + Runs at IRQL <= DISPATCH_LEVEL. + +Arguments: + + NetBufferList The NBL to examine + +Return Value: + + The number of net buffers linked to the net buffer list. + +--*/ +{ + ULONG netBufferCount = 0; + PNET_BUFFER currentNb; + + if (TotalByteCount) { + *TotalByteCount = 0; + } + + currentNb = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + + while (currentNb) { + ++netBufferCount; + + if (TotalByteCount) { + *TotalByteCount += NET_BUFFER_DATA_LENGTH(currentNb); + } + + // Move to next NB + currentNb = NET_BUFFER_NEXT_NB(currentNb); + } + + return netBufferCount; +} + +VOID tapAdapterAcquireLock(__in PTAP_ADAPTER_CONTEXT Adapter, __in BOOLEAN DispatchLevel) { + ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql())); + + if (DispatchLevel) { + NdisDprAcquireSpinLock(&Adapter->AdapterLock); + } else { + NdisAcquireSpinLock(&Adapter->AdapterLock); + } +} + +VOID tapAdapterReleaseLock(__in PTAP_ADAPTER_CONTEXT Adapter, __in BOOLEAN DispatchLevel) { + ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql())); + + if (DispatchLevel) { + NdisDprReleaseSpinLock(&Adapter->AdapterLock); + } else { + NdisReleaseSpinLock(&Adapter->AdapterLock); + } +} diff --git a/third_party/tap-windows6/src/adapter.h b/third_party/tap-windows6/src/adapter.h new file mode 100644 index 00000000000..5d1f6efa6f0 --- /dev/null +++ b/third_party/tap-windows6/src/adapter.h @@ -0,0 +1,314 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_ADAPTER_CONTEXT_H_ +#define __TAP_ADAPTER_CONTEXT_H_ + +// Memory allocation tags. +#define TAP_ADAPTER_TAG ((ULONG)'ApaT') // "TapA +#define TAP_RX_NBL_TAG ((ULONG)'RpaT') // "TapR +#define TAP_RX_INJECT_BUFFER_TAG ((ULONG)'IpaT') // "TapI + +#define TAP_MAX_NDIS_NAME_LENGTH 64 // 38 character GUID string plus extra.. + +// TAP receive indication NBL flag definitions. +#define TAP_RX_NBL_FLAGS NBL_FLAGS_MINIPORT_RESERVED +#define TAP_RX_NBL_FLAGS_CLEAR_ALL(_NBL) ((_NBL)->Flags &= ~TAP_RX_NBL_FLAGS) +#define TAP_RX_NBL_FLAG_SET(_NBL, _F) ((_NBL)->Flags |= ((_F)&TAP_RX_NBL_FLAGS)) +#define TAP_RX_NBL_FLAG_CLEAR(_NBL, _F) ((_NBL)->Flags &= ~((_F)&TAP_RX_NBL_FLAGS)) +#define TAP_RX_NBL_FLAG_TEST(_NBL, _F) (((_NBL)->Flags & ((_F)&TAP_RX_NBL_FLAGS)) != 0) + +#define TAP_RX_NBL_FLAGS_IS_P2P 0x00001000 +#define TAP_RX_NBL_FLAGS_IS_INJECTED 0x00002000 + +// MSDN Ref: http://msdn.microsoft.com/en-us/library/windows/hardware/ff560490(v=vs.85).aspx +typedef enum _TAP_MINIPORT_ADAPTER_STATE { + // The Halted state is the initial state of all adapters. When an + // adapter is in the Halted state, NDIS can call the driver's + // MiniportInitializeEx function to initialize the adapter. + MiniportHaltedState, + + // In the Shutdown state, a system shutdown and restart must occur + // before the system can use the adapter again. + MiniportShutdownState, + + // In the Initializing state, a miniport driver completes any + // operations that are required to initialize an adapter. + MiniportInitializingState, + + // Entering the Paused state... + MiniportPausingState, + + // In the Paused state, the adapter does not indicate received + // network data or accept send requests. + MiniportPausedState, + + // In the Running state, a miniport driver performs send and + // receive processing for an adapter. + MiniportRunning, + + // In the Restarting state, a miniport driver completes any + // operations that are required to restart send and receive + // operations for an adapter. + MiniportRestartingState +} TAP_MINIPORT_ADAPTER_STATE, + *PTAP_MINIPORT_ADAPTER_STATE; + +// +// Each adapter managed by this driver has a TapAdapter struct. +// ------------------------------------------------------------ +// Since there is a one-to-one relationship between adapter instances +// and device instances this structure is the device extension as well. +// +typedef struct _TAP_ADAPTER_CONTEXT { + LIST_ENTRY AdapterListLink; + + volatile LONG RefCount; + + NDIS_HANDLE MiniportAdapterHandle; + + NDIS_SPIN_LOCK AdapterLock; // Lock for protection of state and outstanding sends and recvs + + // + // All fields that are protected by the AdapterLock are included + // in the Locked structure to remind us to take the Lock + // before accessing them :) + // + struct { + TAP_MINIPORT_ADAPTER_STATE AdapterState; + } Locked; + + BOOLEAN ResetInProgress; + + // + // NetCfgInstanceId as UNICODE_STRING + // ---------------------------------- + // This a GUID string provided by NDIS that identifies the adapter instance. + // An example is: + // + // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0} + // + // Other names are derived from NetCfgInstanceId. For example, MiniportName: + // + // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0} + // + NDIS_STRING NetCfgInstanceId; + WCHAR NetCfgInstanceIdBuffer[TAP_MAX_NDIS_NAME_LENGTH]; + +#define MINIPORT_INSTANCE_ID(a) ((a)->NetCfgInstanceIdAnsi.Buffer) + ANSI_STRING NetCfgInstanceIdAnsi; // Used occasionally + + ULONG MtuSize; // 1500 byte (typical) + + // TRUE if adapter should always be "connected" even when device node + // is not open by a userspace process. + // + // FALSE if connection state is application controlled. + BOOLEAN MediaStateAlwaysConnected; + + // TRUE if device is "connected". + BOOLEAN LogicalMediaState; + + NDIS_DEVICE_POWER_STATE CurrentPowerState; + + BOOLEAN AllowNonAdmin; + + MACADDR PermanentAddress; // From registry, if available + MACADDR CurrentAddress; + + // Device registration parameters from NdisRegisterDeviceEx. + NDIS_STRING DeviceName; + WCHAR DeviceNameBuffer[TAP_MAX_NDIS_NAME_LENGTH]; + + NDIS_STRING LinkName; + WCHAR LinkNameBuffer[TAP_MAX_NDIS_NAME_LENGTH]; + + NDIS_HANDLE DeviceHandle; + PDEVICE_OBJECT DeviceObject; + BOOLEAN TapDeviceCreated; // WAS: m_TapIsRunning + + PFILE_OBJECT TapFileObject; // Exclusive access + BOOLEAN TapFileIsOpen; // WAS: m_TapOpens + LONG TapFileOpenCount; // WAS: m_NumTapOpens + + // Cancel-Safe read IRP queue. + TAP_IRP_CSQ PendingReadIrpQueue; + + // Queue containing TAP packets representing host send NBs. These are + // waiting to be read by user-mode application. + TAP_PACKET_QUEUE SendPacketQueue; + + // NBL pool for making TAP receive indications. + NDIS_HANDLE ReceiveNblPool; + + volatile LONG ReceiveNblInFlightCount; +#define TAP_WAIT_POLL_LOOP_TIMEOUT 3000 // 3 seconds + NDIS_EVENT ReceiveNblInFlightCountZeroEvent; + + // Info for point-to-point mode + BOOLEAN m_tun; + IPADDR m_localIP; + IPADDR m_remoteNetwork; + IPADDR m_remoteNetmask; + ETH_HEADER m_TapToUser; + ETH_HEADER m_UserToTap; + ETH_HEADER m_UserToTap_IPv6; // same as UserToTap but proto=ipv6 + + // Info for DHCP server masquerade + BOOLEAN m_dhcp_enabled; + IPADDR m_dhcp_addr; + ULONG m_dhcp_netmask; + IPADDR m_dhcp_server_ip; + BOOLEAN m_dhcp_server_arp; + MACADDR m_dhcp_server_mac; + ULONG m_dhcp_lease_time; + UCHAR m_dhcp_user_supplied_options_buffer[DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE]; + ULONG m_dhcp_user_supplied_options_buffer_len; + BOOLEAN m_dhcp_received_discover; + ULONG m_dhcp_bad_requests; + + // Multicast list. Fixed size. + ULONG ulMCListSize; + UCHAR MCList[TAP_MAX_MCAST_LIST][MACADDR_SIZE]; + + ULONG PacketFilter; + ULONG ulLookahead; + + // + // Statistics + // ------------------------------------------------------------------------- + // + + // Packet counts + ULONG64 FramesRxDirected; + ULONG64 FramesRxMulticast; + ULONG64 FramesRxBroadcast; + ULONG64 FramesTxDirected; + ULONG64 FramesTxMulticast; + ULONG64 FramesTxBroadcast; + + // Byte counts + ULONG64 BytesRxDirected; + ULONG64 BytesRxMulticast; + ULONG64 BytesRxBroadcast; + ULONG64 BytesTxDirected; + ULONG64 BytesTxMulticast; + ULONG64 BytesTxBroadcast; + + // Count of transmit errors + ULONG TxAbortExcessCollisions; + ULONG TxLateCollisions; + ULONG TxDmaUnderrun; + ULONG TxLostCRS; + ULONG TxOKButDeferred; + ULONG OneRetry; + ULONG MoreThanOneRetry; + ULONG TotalRetries; + ULONG TransmitFailuresOther; + + // Count of receive errors + ULONG RxCrcErrors; + ULONG RxAlignmentErrors; + ULONG RxResourceErrors; + ULONG RxDmaOverrunErrors; + ULONG RxCdtFrames; + ULONG RxRuntErrors; + +#if PACKET_TRUNCATION_CHECK + LONG m_RxTrunc, m_TxTrunc; +#endif + + BOOLEAN m_InterfaceIsRunning; + LONG m_Rx, m_RxErr; + NDIS_MEDIUM m_Medium; + + // Help to tear down the adapter by keeping + // some state information on allocated + // resources. + BOOLEAN m_CalledAdapterFreeResources; + BOOLEAN m_RegisteredAdapterShutdownHandler; + +} TAP_ADAPTER_CONTEXT, *PTAP_ADAPTER_CONTEXT; + +FORCEINLINE +LONG tapAdapterContextReference(__in PTAP_ADAPTER_CONTEXT Adapter) { + LONG refCount = NdisInterlockedIncrement(&Adapter->RefCount); + + ASSERT(refCount > 1); // Cannot dereference a zombie. + + return refCount; +} + +VOID tapAdapterContextFree(__in PTAP_ADAPTER_CONTEXT Adapter); + +FORCEINLINE +LONG tapAdapterContextDereference(IN PTAP_ADAPTER_CONTEXT Adapter) { + LONG refCount = NdisInterlockedDecrement(&Adapter->RefCount); + ASSERT(refCount >= 0); + if (!refCount) { + tapAdapterContextFree(Adapter); + } + + return refCount; +} + +VOID tapAdapterAcquireLock(__in PTAP_ADAPTER_CONTEXT Adapter, __in BOOLEAN DispatchLevel); + +VOID tapAdapterReleaseLock(__in PTAP_ADAPTER_CONTEXT Adapter, __in BOOLEAN DispatchLevel); + +// Returns with added reference on adapter context. +PTAP_ADAPTER_CONTEXT +tapAdapterContextFromDeviceObject(__in PDEVICE_OBJECT DeviceObject); + +BOOLEAN +tapAdapterReadAndWriteReady(__in PTAP_ADAPTER_CONTEXT Adapter); + +NDIS_STATUS +tapAdapterSendAndReceiveReady(__in PTAP_ADAPTER_CONTEXT Adapter); + +ULONG +tapGetNetBufferFrameType(__in PNET_BUFFER NetBuffer); + +ULONG +tapGetNetBufferCountsFromNetBufferList(__in PNET_BUFFER_LIST NetBufferList, + __inout_opt PULONG TotalByteCount // Of all linked NBs +); + +// Prototypes for standard NDIS miniport entry points +MINIPORT_SET_OPTIONS AdapterSetOptions; +MINIPORT_INITIALIZE AdapterCreate; +MINIPORT_HALT AdapterHalt; +MINIPORT_UNLOAD TapDriverUnload; +MINIPORT_PAUSE AdapterPause; +MINIPORT_RESTART AdapterRestart; +MINIPORT_OID_REQUEST AdapterOidRequest; +MINIPORT_SEND_NET_BUFFER_LISTS AdapterSendNetBufferLists; +MINIPORT_RETURN_NET_BUFFER_LISTS AdapterReturnNetBufferLists; +MINIPORT_CANCEL_SEND AdapterCancelSend; +MINIPORT_CHECK_FOR_HANG AdapterCheckForHangEx; +MINIPORT_RESET AdapterReset; +MINIPORT_DEVICE_PNP_EVENT_NOTIFY AdapterDevicePnpEventNotify; +MINIPORT_SHUTDOWN AdapterShutdownEx; +MINIPORT_CANCEL_OID_REQUEST AdapterCancelOidRequest; + +#endif // __TAP_ADAPTER_CONTEXT_H_ \ No newline at end of file diff --git a/third_party/tap-windows6/src/config.h.in b/third_party/tap-windows6/src/config.h.in new file mode 100644 index 00000000000..322afa8dca2 --- /dev/null +++ b/third_party/tap-windows6/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/third_party/tap-windows6/src/constants.h b/third_party/tap-windows6/src/constants.h new file mode 100644 index 00000000000..34df6b96179 --- /dev/null +++ b/third_party/tap-windows6/src/constants.h @@ -0,0 +1,175 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//==================================================================== +// Product and Version public settings +//==================================================================== + +#define PRODUCT_STRING PRODUCT_TAP_DEVICE_DESCRIPTION + +// +// The major and minor versions should be defined in a central location such +// as a makefile that is preprocessed to insert the current values. +// + +#define TAP_DRIVER_VENDOR_VERSION ((TAP_DRIVER_MAJOR_VERSION << 16) | TAP_DRIVER_MINOR_VERSION) + +// +// Define the NDIS miniport interface version that this driver targets. +// +#if defined(NDIS60_MINIPORT) +#define TAP_NDIS_MAJOR_VERSION 6 +#define TAP_NDIS_MINOR_VERSION 0 +#elif defined(NDIS61_MINIPORT) +#define TAP_NDIS_MAJOR_VERSION 6 +#define TAP_NDIS_MINOR_VERSION 1 +#elif defined(NDIS620_MINIPORT) +#define TAP_NDIS_MAJOR_VERSION 6 +#define TAP_NDIS_MINOR_VERSION 20 +#elif defined(NDIS630_MINIPORT) +#define TAP_NDIS_MAJOR_VERSION 6 +#define TAP_NDIS_MINOR_VERSION 30 +#else +#define TAP_NDIS_MAJOR_VERSION 5 +#define TAP_NDIS_MINOR_VERSION 0 +#endif + +//=========================================================== +// Driver constants +//=========================================================== + +#define ETHERNET_HEADER_SIZE (sizeof(ETH_HEADER)) +#define ETHERNET_MTU 1500 +#define ETHERNET_PACKET_SIZE (ETHERNET_MTU + ETHERNET_HEADER_SIZE) +#define DEFAULT_PACKET_LOOKAHEAD (ETHERNET_PACKET_SIZE) +#define VLAN_TAG_SIZE 4 + +//=========================================================== +// Medium properties +//=========================================================== + +#define TAP_FRAME_HEADER_SIZE ETHERNET_HEADER_SIZE +#define TAP_FRAME_MAX_DATA_SIZE ETHERNET_MTU +#define TAP_MAX_FRAME_SIZE (TAP_FRAME_HEADER_SIZE + TAP_FRAME_MAX_DATA_SIZE) +#define TAP_MIN_FRAME_SIZE 60 + +#define TAP_MEDIUM_TYPE NdisMedium802_3 + +//=========================================================== +// Physical adapter properties +//=========================================================== + +// The bus that connects the adapter to the PC. +// (Example: PCI adapters should use NdisInterfacePci). +#define TAP_INTERFACE_TYPE NdisInterfaceInternal + +#define TAP_VENDOR_DESC PRODUCT_TAP_WIN_DEVICE_DESCRIPTION + +// Highest byte is the NIC byte plus three vendor bytes. This is normally +// obtained from the NIC. +#define TAP_VENDOR_ID 0x00FFFFFF + +// If you have physical hardware on 802.3, use NdisPhysicalMedium802_3. +#define TAP_PHYSICAL_MEDIUM NdisPhysicalMediumUnspecified + +// Claim to be 1Gbps duplex +#define MEGABITS_PER_SECOND 1000000ULL +#define TAP_XMIT_SPEED (1000ULL * MEGABITS_PER_SECOND) +#define TAP_RECV_SPEED (1000ULL * MEGABITS_PER_SECOND) + +// Max number of multicast addresses supported in hardware +#define TAP_MAX_MCAST_LIST 32 + +#define TAP_MAX_LOOKAHEAD TAP_FRAME_MAX_DATA_SIZE +#define TAP_BUFFER_SIZE TAP_MAX_FRAME_SIZE + +// Set this value to TRUE if there is a physical adapter. +#define TAP_HAS_PHYSICAL_CONNECTOR FALSE +#define TAP_ACCESS_TYPE NET_IF_ACCESS_BROADCAST +#define TAP_DIRECTION_TYPE NET_IF_DIRECTION_SENDRECEIVE +#define TAP_CONNECTION_TYPE NET_IF_CONNECTION_DEDICATED + +// This value must match the *IfType in the driver .inf file +#define TAP_IFTYPE IF_TYPE_ETHERNET_CSMACD + +// +// This is a virtual device, so it can tolerate surprise removal and +// suspend. Ensure the correct flags are set for your hardware. +// +#define TAP_ADAPTER_ATTRIBUTES_FLAGS \ + (NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK | NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM) + +#define TAP_SUPPORTED_FILTERS \ + (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST | NDIS_PACKET_TYPE_BROADCAST | \ + NDIS_PACKET_TYPE_ALL_LOCAL | NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_MULTICAST) + +#define TAP_MAX_MCAST_LIST 32 // Max length of multicast address list + +// +// Specify a bitmask that defines optional properties of the NIC. +// This miniport indicates receive with NdisMIndicateReceiveNetBufferLists +// function. Such a driver should set this NDIS_MAC_OPTION_TRANSFERS_NOT_PEND +// flag. +// +// NDIS_MAC_OPTION_NO_LOOPBACK tells NDIS that NIC has no internal +// loopback support so NDIS will manage loopbacks on behalf of +// this driver. +// +// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA tells the protocol that +// our receive buffer is not on a device-specific card. If +// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA is not set, multi-buffer +// indications are copied to a single flat buffer. +// + +#define TAP_MAC_OPTIONS \ + (NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \ + NDIS_MAC_OPTION_NO_LOOPBACK) + +#define TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS 4 + +// NDIS 6.x miniports must support all counters in OID_GEN_STATISTICS. +#define TAP_SUPPORTED_STATISTICS \ + (NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | \ + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | \ + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | \ + NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | \ + NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT) + +#define MINIMUM_MTU 576 // USE TCP Minimum MTU +#define MAXIMUM_MTU 65536 // IP maximum MTU + +#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size +#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace +#define INJECT_QUEUE_SIZE 16 // DHCP/ARP -> tap injection queue + +#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions diff --git a/third_party/tap-windows6/src/device.c b/third_party/tap-windows6/src/device.c new file mode 100644 index 00000000000..99c9eab8dd3 --- /dev/null +++ b/third_party/tap-windows6/src/device.c @@ -0,0 +1,983 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include // for SDDLs +#include "tap.h" + +//====================================================================== +// TAP Win32 Device I/O Callbacks +//====================================================================== + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, TapDeviceCreate) +#pragma alloc_text(PAGE, TapDeviceControl) +#pragma alloc_text(PAGE, TapDeviceCleanup) +#pragma alloc_text(PAGE, TapDeviceClose) +#endif // ALLOC_PRAGMA + +//=================================================================== +// Go back to default TAP mode from Point-To-Point mode. +// Also reset (i.e. disable) DHCP Masq mode. +//=================================================================== +VOID tapResetAdapterState(__in PTAP_ADAPTER_CONTEXT Adapter) { + // Point-To-Point + Adapter->m_tun = FALSE; + Adapter->m_localIP = 0; + Adapter->m_remoteNetwork = 0; + Adapter->m_remoteNetmask = 0; + NdisZeroMemory(&Adapter->m_TapToUser, sizeof(Adapter->m_TapToUser)); + NdisZeroMemory(&Adapter->m_UserToTap, sizeof(Adapter->m_UserToTap)); + NdisZeroMemory(&Adapter->m_UserToTap_IPv6, sizeof(Adapter->m_UserToTap_IPv6)); + + // DHCP Masq + Adapter->m_dhcp_enabled = FALSE; + Adapter->m_dhcp_server_arp = FALSE; + Adapter->m_dhcp_user_supplied_options_buffer_len = 0; + Adapter->m_dhcp_addr = 0; + Adapter->m_dhcp_netmask = 0; + Adapter->m_dhcp_server_ip = 0; + Adapter->m_dhcp_lease_time = 0; + Adapter->m_dhcp_received_discover = FALSE; + Adapter->m_dhcp_bad_requests = 0; + NdisZeroMemory(Adapter->m_dhcp_server_mac, MACADDR_SIZE); +} + +// IRP_MJ_CREATE +NTSTATUS +TapDeviceCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) +/*++ + +Routine Description: + + This routine is called by the I/O system when the device is opened. + + No action is performed other than completing the request successfully. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ +{ + NDIS_STATUS status; + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + PFILE_OBJECT originalFileObject; + + PAGED_CODE(); + + DEBUGP(("[TAP] --> TapDeviceCreate\n")); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Invalidate file context + // + irpSp->FileObject->FsContext = NULL; + irpSp->FileObject->FsContext2 = NULL; + + // + // Find adapter context for this device. + // ------------------------------------- + // Returns with added reference on adapter context. + // + adapter = tapAdapterContextFromDeviceObject(DeviceObject); + + // Insure that adapter exists. + ASSERT(adapter); + + if (adapter == NULL) { + DEBUGP(("[TAP] release [%d.%d] open request; adapter not found\n", TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION)); + + Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_DEVICE_DOES_NOT_EXIST; + } + + DEBUGP(("[%s] [TAP] release [%d.%d] open request (TapFileIsOpen=%d)\n", + MINIPORT_INSTANCE_ID(adapter), TAP_DRIVER_MAJOR_VERSION, TAP_DRIVER_MINOR_VERSION, + adapter->TapFileIsOpen)); + + // Enforce exclusive access + originalFileObject = + InterlockedCompareExchangePointer(&adapter->TapFileObject, irpSp->FileObject, NULL); + + if (originalFileObject == NULL) { + irpSp->FileObject->FsContext = adapter; // Quick reference + + status = STATUS_SUCCESS; + } else { + status = STATUS_UNSUCCESSFUL; + } + + // Release the lock. + // tapAdapterReleaseLock(adapter,FALSE); + + if (status == STATUS_SUCCESS) { + // Reset adapter state on successful open. + tapResetAdapterState(adapter); + + adapter->TapFileIsOpen = 1; // Legacy... + + // NOTE!!! Reference added by tapAdapterContextFromDeviceObject + // will be removed when file is closed. + } else { + DEBUGP(("[%s] TAP is presently unavailable (TapFileIsOpen=%d)\n", MINIPORT_INSTANCE_ID(adapter), + adapter->TapFileIsOpen)); + + NOTE_ERROR(); + + // Remove reference added by tapAdapterContextFromDeviceObject. + tapAdapterContextDereference(adapter); + } + + // Complete the IRP. + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + DEBUGP(("[TAP] <-- TapDeviceCreate; status = %8.8X\n", status)); + + return status; +} + +//=================================================== +// Tell Windows whether the TAP device should be +// considered "connected" or "disconnected". +// +// Allows application control of media connect state. +//=================================================== +VOID tapSetMediaConnectStatus(__in PTAP_ADAPTER_CONTEXT Adapter, __in BOOLEAN LogicalMediaState) { + NDIS_STATUS_INDICATION statusIndication; + NDIS_LINK_STATE linkState; + + NdisZeroMemory(&statusIndication, sizeof(NDIS_STATUS_INDICATION)); + NdisZeroMemory(&linkState, sizeof(NDIS_LINK_STATE)); + + // + // Fill in object headers + // + statusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION; + statusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1; + statusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION); + + linkState.Header.Revision = NDIS_LINK_STATE_REVISION_1; + linkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + linkState.Header.Size = sizeof(NDIS_LINK_STATE); + + // + // Link state buffer + // + if (Adapter->LogicalMediaState == TRUE) { + linkState.MediaConnectState = MediaConnectStateConnected; + } + + linkState.MediaDuplexState = MediaDuplexStateFull; + linkState.RcvLinkSpeed = TAP_RECV_SPEED; + linkState.XmitLinkSpeed = TAP_XMIT_SPEED; + + // + // Fill in the status buffer + // + statusIndication.StatusCode = NDIS_STATUS_LINK_STATE; + statusIndication.SourceHandle = Adapter->MiniportAdapterHandle; + statusIndication.DestinationHandle = NULL; + statusIndication.RequestId = 0; + + statusIndication.StatusBuffer = &linkState; + statusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE); + + // Fill in new media connect state. + if ((Adapter->LogicalMediaState != LogicalMediaState) && !Adapter->MediaStateAlwaysConnected) { + Adapter->LogicalMediaState = LogicalMediaState; + + if (LogicalMediaState == TRUE) { + linkState.MediaConnectState = MediaConnectStateConnected; + + DEBUGP(("[TAP] Set MediaConnectState: Connected.\n")); + } else { + linkState.MediaConnectState = MediaConnectStateDisconnected; + + DEBUGP(("[TAP] Set MediaConnectState: Disconnected.\n")); + } + } + + // Make the status indication. + if (Adapter->Locked.AdapterState != MiniportHaltedState) { + NdisMIndicateStatusEx(Adapter->MiniportAdapterHandle, &statusIndication); + } +} + +//====================================================== +// If DHCP mode is used together with tun +// mode, consider the fact that the P2P remote subnet +// might enclose the DHCP masq server address. +//====================================================== +VOID CheckIfDhcpAndTunMode(__in PTAP_ADAPTER_CONTEXT Adapter) { + if (Adapter->m_tun && Adapter->m_dhcp_enabled) { + if ((Adapter->m_dhcp_server_ip & Adapter->m_remoteNetmask) == Adapter->m_remoteNetwork) { + ETH_COPY_NETWORK_ADDRESS(Adapter->m_dhcp_server_mac, Adapter->m_TapToUser.dest); + Adapter->m_dhcp_server_arp = FALSE; + } + } +} + +// IRP_MJ_DEVICE_CONTROL callback. +NTSTATUS +TapDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) + +/*++ + +Routine Description: + + This routine is called by the I/O system to perform a device I/O + control function. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + NTSTATUS ntStatus = STATUS_SUCCESS; // Assume success + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + ULONG inBufLength; // Input buffer length + ULONG outBufLength; // Output buffer length + PCHAR inBuf, outBuf; // pointer to Input and output buffer + PMDL mdl = NULL; + PCHAR buffer = NULL; + + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT)(irpSp->FileObject)->FsContext; + + ASSERT(adapter); + + inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; + outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; + + if (!inBufLength || !outBufLength) { + ntStatus = STATUS_INVALID_PARAMETER; + goto End; + } + + // + // Determine which I/O control code was specified. + // + switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { + case TAP_WIN_IOCTL_GET_MAC: { + if (outBufLength >= MACADDR_SIZE) { + ETH_COPY_NETWORK_ADDRESS(Irp->AssociatedIrp.SystemBuffer, adapter->CurrentAddress); + + Irp->IoStatus.Information = MACADDR_SIZE; + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } break; + + case TAP_WIN_IOCTL_GET_VERSION: { + const ULONG size = sizeof(ULONG) * 3; + + if (outBufLength >= size) { + ((PULONG)(Irp->AssociatedIrp.SystemBuffer))[0] = TAP_DRIVER_MAJOR_VERSION; + + ((PULONG)(Irp->AssociatedIrp.SystemBuffer))[1] = TAP_DRIVER_MINOR_VERSION; + + ((PULONG)(Irp->AssociatedIrp.SystemBuffer))[2] +#if DBG + = 1; +#else + = 0; +#endif + Irp->IoStatus.Information = size; + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } break; + + case TAP_WIN_IOCTL_GET_MTU: { + const ULONG size = sizeof(ULONG) * 1; + + if (outBufLength >= size) { + ((PULONG)(Irp->AssociatedIrp.SystemBuffer))[0] = adapter->MtuSize; + + Irp->IoStatus.Information = size; + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } break; + + case TAP_WIN_IOCTL_CONFIG_TUN: { + if (inBufLength >= sizeof(IPADDR) * 3) { + MACADDR dest; + + adapter->m_tun = FALSE; + + GenerateRelatedMAC(dest, adapter->CurrentAddress, 1); + + adapter->m_localIP = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[0]; + adapter->m_remoteNetwork = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[1]; + adapter->m_remoteNetmask = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[2]; + + // Sanity check on network/netmask + if ((adapter->m_remoteNetwork & adapter->m_remoteNetmask) != adapter->m_remoteNetwork) { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + break; + } + + ETH_COPY_NETWORK_ADDRESS(adapter->m_TapToUser.src, adapter->CurrentAddress); + ETH_COPY_NETWORK_ADDRESS(adapter->m_TapToUser.dest, dest); + ETH_COPY_NETWORK_ADDRESS(adapter->m_UserToTap.src, dest); + ETH_COPY_NETWORK_ADDRESS(adapter->m_UserToTap.dest, adapter->CurrentAddress); + + adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons(NDIS_ETH_TYPE_IPV4); + adapter->m_UserToTap_IPv6 = adapter->m_UserToTap; + adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6); + + adapter->m_tun = TRUE; + + CheckIfDhcpAndTunMode(adapter); + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP(("[TAP] Set TUN mode.\n")); + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } break; + + case TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT: { + if (inBufLength >= sizeof(IPADDR) * 2) { + MACADDR dest; + + adapter->m_tun = FALSE; + + GenerateRelatedMAC(dest, adapter->CurrentAddress, 1); + + adapter->m_localIP = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[0]; + adapter->m_remoteNetwork = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[1]; + adapter->m_remoteNetmask = ~0; + + ETH_COPY_NETWORK_ADDRESS(adapter->m_TapToUser.src, adapter->CurrentAddress); + ETH_COPY_NETWORK_ADDRESS(adapter->m_TapToUser.dest, dest); + ETH_COPY_NETWORK_ADDRESS(adapter->m_UserToTap.src, dest); + ETH_COPY_NETWORK_ADDRESS(adapter->m_UserToTap.dest, adapter->CurrentAddress); + + adapter->m_TapToUser.proto = adapter->m_UserToTap.proto = htons(NDIS_ETH_TYPE_IPV4); + adapter->m_UserToTap_IPv6 = adapter->m_UserToTap; + adapter->m_UserToTap_IPv6.proto = htons(NDIS_ETH_TYPE_IPV6); + + adapter->m_tun = TRUE; + + CheckIfDhcpAndTunMode(adapter); + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP(("[TAP] Set P2P mode.\n")); + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } break; + + case TAP_WIN_IOCTL_CONFIG_DHCP_MASQ: { + if (inBufLength >= sizeof(IPADDR) * 4) { + adapter->m_dhcp_enabled = FALSE; + adapter->m_dhcp_server_arp = FALSE; + adapter->m_dhcp_user_supplied_options_buffer_len = 0; + + // Adapter IP addr / netmask + adapter->m_dhcp_addr = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[0]; + adapter->m_dhcp_netmask = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[1]; + + // IP addr of DHCP masq server + adapter->m_dhcp_server_ip = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[2]; + + // Lease time in seconds + adapter->m_dhcp_lease_time = ((IPADDR*)(Irp->AssociatedIrp.SystemBuffer))[3]; + + GenerateRelatedMAC(adapter->m_dhcp_server_mac, adapter->CurrentAddress, 2); + + adapter->m_dhcp_enabled = TRUE; + adapter->m_dhcp_server_arp = TRUE; + + CheckIfDhcpAndTunMode(adapter); + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP(("[TAP] Configured DHCP MASQ.\n")); + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } break; + + case TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT: { + if (inBufLength <= DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE && adapter->m_dhcp_enabled) { + adapter->m_dhcp_user_supplied_options_buffer_len = 0; + + NdisMoveMemory(adapter->m_dhcp_user_supplied_options_buffer, + Irp->AssociatedIrp.SystemBuffer, inBufLength); + + adapter->m_dhcp_user_supplied_options_buffer_len = inBufLength; + + Irp->IoStatus.Information = 1; // Simple boolean value + + DEBUGP(("[TAP] Set DHCP OPT.\n")); + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } break; + + case TAP_WIN_IOCTL_GET_INFO: { + char state[16]; + + // Fetch adapter (miniport) state. + if (tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) + state[0] = 'A'; + else + state[0] = 'a'; + + if (tapAdapterReadAndWriteReady(adapter)) + state[1] = 'T'; + else + state[1] = 't'; + + state[2] = '0' + adapter->CurrentPowerState; + + if (adapter->MediaStateAlwaysConnected) + state[3] = 'C'; + else + state[3] = 'c'; + + state[4] = '\0'; + + // BUGBUG!!! What follows, and is not yet implemented, is a real mess. + // BUGBUG!!! Tied closely to the NDIS 5 implementation. Need to map + // as much as possible to the NDIS 6 implementation. + Irp->IoStatus.Status = ntStatus = RtlStringCchPrintfExA( + ((LPTSTR)(Irp->AssociatedIrp.SystemBuffer)), outBufLength, NULL, NULL, + STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS, +#if PACKET_TRUNCATION_CHECK + "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] " + "InjQ=[%d,%d,%d]", +#else + "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] " + "InjQ=[%d,%d,%d]", +#endif + state, g_LastErrorFilename, g_LastErrorLineNumber, (int)adapter->TapFileOpenCount, + (int)(adapter->FramesTxDirected + adapter->FramesTxMulticast + + adapter->FramesTxBroadcast), + (int)adapter->TransmitFailuresOther, +#if PACKET_TRUNCATION_CHECK + (int)adapter->m_TxTrunc, +#endif + (int)adapter->m_Rx, (int)adapter->m_RxErr, +#if PACKET_TRUNCATION_CHECK + (int)adapter->m_RxTrunc, +#endif + (int)adapter->PendingReadIrpQueue.Count, (int)adapter->PendingReadIrpQueue.MaxCount, + (int)IRP_QUEUE_SIZE, // Ignored in NDIS 6 driver... + + (int)adapter->SendPacketQueue.Count, (int)adapter->SendPacketQueue.MaxCount, + (int)PACKET_QUEUE_SIZE, + + (int)0, // adapter->InjectPacketQueue.Count - Unused + (int)0, // adapter->InjectPacketQueue.MaxCount - Unused + (int)INJECT_QUEUE_SIZE); + + Irp->IoStatus.Information = outBufLength; + + // BUGBUG!!! Fail because this is not completely implemented. + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + } break; + +#if DBG + case TAP_WIN_IOCTL_GET_LOG_LINE: { + if (GetDebugLine((LPTSTR)Irp->AssociatedIrp.SystemBuffer, outBufLength)) { + Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS; + } else { + Irp->IoStatus.Status = ntStatus = STATUS_UNSUCCESSFUL; + } + + Irp->IoStatus.Information = outBufLength; + + break; + } +#endif + + case TAP_WIN_IOCTL_SET_MEDIA_STATUS: { + if (inBufLength >= sizeof(ULONG)) { + ULONG parm = ((PULONG)(Irp->AssociatedIrp.SystemBuffer))[0]; + tapSetMediaConnectStatus(adapter, (BOOLEAN)parm); + Irp->IoStatus.Information = 1; + } else { + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + } + } break; + + default: + + // + // The specified I/O control code is unrecognized by this driver. + // + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + break; + } + +End: + + // + // Finish the I/O operation by simply completing the packet and returning + // the same status as in the packet itself. + // + Irp->IoStatus.Status = ntStatus; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ntStatus; +} + +// Flush the pending read IRP queue. +VOID tapFlushIrpQueues(__in PTAP_ADAPTER_CONTEXT Adapter) { + DEBUGP(("[TAP] tapFlushIrpQueues: Flushing %d pending read IRPs\n", + Adapter->PendingReadIrpQueue.Count)); + + tapIrpCsqFlush(&Adapter->PendingReadIrpQueue); +} + +// IRP_MJ_CLEANUP +NTSTATUS +TapDeviceCleanup(PDEVICE_OBJECT DeviceObject, PIRP Irp) +/*++ + +Routine Description: + + Receipt of this request indicates that the last handle for a file + object that is associated with the target device object has been closed + (but, due to outstanding I/O requests, might not have been released). + + A driver that holds pending IRPs internally must implement a routine for + IRP_MJ_CLEANUP. When the routine is called, the driver should cancel all + the pending IRPs that belong to the file object identified by the IRP_MJ_CLEANUP + call. + + In other words, it should cancel all the IRPs that have the same file-object + pointer as the one supplied in the current I/O stack location of the IRP for the + IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should + not be canceled. Also, if an outstanding IRP is completed immediately, the + driver does not have to cancel it. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + to be cleaned up. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed. + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + + PAGED_CODE(); + + DEBUGP(("[TAP] --> TapDeviceCleanup\n")); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT)(irpSp->FileObject)->FsContext; + + // Insure that adapter exists. + ASSERT(adapter); + + if (adapter == NULL) { + DEBUGP(("[TAP] release [%d.%d] cleanup request; adapter not found\n", TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION)); + } + + if (adapter != NULL) { + adapter->TapFileIsOpen = 0; // Legacy... + + // Disconnect from media. + tapSetMediaConnectStatus(adapter, FALSE); + + // Reset adapter state when cleaning up; + tapResetAdapterState(adapter); + + // BUGBUG!!! Use RemoveLock??? + + // + // Flush pending send TAP packet queue. + // + tapFlushSendPacketQueue(adapter); + + ASSERT(adapter->SendPacketQueue.Count == 0); + + // + // Flush the pending IRP queues + // + tapFlushIrpQueues(adapter); + + ASSERT(adapter->PendingReadIrpQueue.Count == 0); + } + + // Complete the IRP. + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + DEBUGP(("[TAP] <-- TapDeviceCleanup; status = %8.8X\n", status)); + + return status; +} + +// IRP_MJ_CLOSE +NTSTATUS +TapDeviceClose(PDEVICE_OBJECT DeviceObject, PIRP Irp) +/*++ + +Routine Description: + + Receipt of this request indicates that the last handle of the file + object that is associated with the target device object has been closed + and released. + + All outstanding I/O requests have been completed or canceled. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + to be closed. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed. + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + + PAGED_CODE(); + + DEBUGP(("[TAP] --> TapDeviceClose\n")); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT)(irpSp->FileObject)->FsContext; + + // Insure that adapter exists. + ASSERT(adapter); + + if (adapter == NULL) { + DEBUGP(("[TAP] release [%d.%d] close request; adapter not found\n", TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION)); + } + + if (adapter != NULL) { + if (adapter->TapFileObject == NULL) { + // Should never happen!!! + ASSERT(FALSE); + } else { + ASSERT(irpSp->FileObject->FsContext == adapter); + + ASSERT(adapter->TapFileObject == irpSp->FileObject); + } + + adapter->TapFileObject = NULL; + irpSp->FileObject = NULL; + + // Remove reference added by when handle was opened. + tapAdapterContextDereference(adapter); + } + + // Complete the IRP. + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + DEBUGP(("[TAP] <-- TapDeviceClose; status = %8.8X\n", status)); + + return status; +} + +NTSTATUS +tapConcatenateNdisStrings(__inout PNDIS_STRING DestinationString, + __in_opt PNDIS_STRING SourceString1, __in_opt PNDIS_STRING SourceString2, + __in_opt PNDIS_STRING SourceString3) { + NTSTATUS status; + + ASSERT(SourceString1 && SourceString2 && SourceString3); + + status = RtlAppendUnicodeStringToString(DestinationString, SourceString1); + + if (status == STATUS_SUCCESS) { + status = RtlAppendUnicodeStringToString(DestinationString, SourceString2); + + if (status == STATUS_SUCCESS) { + status = RtlAppendUnicodeStringToString(DestinationString, SourceString3); + } + } + + return status; +} + +NTSTATUS +tapMakeDeviceNames(__in PTAP_ADAPTER_CONTEXT Adapter) { + NDIS_STATUS status; + NDIS_STRING deviceNamePrefix = NDIS_STRING_CONST("\\Device\\"); + NDIS_STRING tapNameSuffix = NDIS_STRING_CONST(".tap"); + + // Generate DeviceName from NetCfgInstanceId. + Adapter->DeviceName.Buffer = Adapter->DeviceNameBuffer; + Adapter->DeviceName.MaximumLength = sizeof(Adapter->DeviceNameBuffer); + + status = tapConcatenateNdisStrings(&Adapter->DeviceName, &deviceNamePrefix, + &Adapter->NetCfgInstanceId, &tapNameSuffix); + + if (status == STATUS_SUCCESS) { + NDIS_STRING linkNamePrefix = NDIS_STRING_CONST("\\DosDevices\\Global\\"); + + Adapter->LinkName.Buffer = Adapter->LinkNameBuffer; + Adapter->LinkName.MaximumLength = sizeof(Adapter->LinkNameBuffer); + + status = tapConcatenateNdisStrings(&Adapter->LinkName, &linkNamePrefix, + &Adapter->NetCfgInstanceId, &tapNameSuffix); + } + + return status; +} + +NDIS_STATUS +CreateTapDevice(__in PTAP_ADAPTER_CONTEXT Adapter) { + NDIS_STATUS status; + NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttribute; + PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION + 1]; + + DEBUGP(("[TAP] version [%d.%d] creating tap device: %wZ\n", TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, &Adapter->NetCfgInstanceId)); + + // Generate DeviceName and LinkName from NetCfgInstanceId. + status = tapMakeDeviceNames(Adapter); + + if (NT_SUCCESS(status)) { + DEBUGP(("[TAP] DeviceName: %wZ\n", &Adapter->DeviceName)); + DEBUGP(("[TAP] LinkName: %wZ\n", &Adapter->LinkName)); + + // Initialize dispatch table. + NdisZeroMemory(dispatchTable, (IRP_MJ_MAXIMUM_FUNCTION + 1) * sizeof(PDRIVER_DISPATCH)); + + dispatchTable[IRP_MJ_CREATE] = TapDeviceCreate; + dispatchTable[IRP_MJ_CLEANUP] = TapDeviceCleanup; + dispatchTable[IRP_MJ_CLOSE] = TapDeviceClose; + dispatchTable[IRP_MJ_READ] = TapDeviceRead; + dispatchTable[IRP_MJ_WRITE] = TapDeviceWrite; + dispatchTable[IRP_MJ_DEVICE_CONTROL] = TapDeviceControl; + + // + // Create a device object and register dispatch handlers + // + NdisZeroMemory(&deviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES)); + + deviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES; + deviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1; + deviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES); + + deviceAttribute.DeviceName = &Adapter->DeviceName; + deviceAttribute.SymbolicName = &Adapter->LinkName; + deviceAttribute.MajorFunctions = &dispatchTable[0]; + // deviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION); + +#if ENABLE_NONADMIN + if (Adapter->AllowNonAdmin) { + // + // SDDL_DEVOBJ_SYS_ALL_WORLD_RWX_RES_RWX allows the kernel and system complete + // control over the device. By default the admin can access the entire device, + // but cannot change the ACL (the admin must take control of the device first) + // + // Everyone else, including "restricted" or "untrusted" code can read or write + // to the device. Traversal beneath the device is also granted (removing it + // would only effect storage devices, except if the "bypass-traversal" + // privilege was revoked). + // + deviceAttribute.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX; + } +#endif + + status = NdisRegisterDeviceEx(Adapter->MiniportAdapterHandle, &deviceAttribute, + &Adapter->DeviceObject, &Adapter->DeviceHandle); + } + + ASSERT(NT_SUCCESS(status)); + + if (NT_SUCCESS(status)) { + // Set TAP device flags. + (Adapter->DeviceObject)->Flags &= ~DO_BUFFERED_IO; + (Adapter->DeviceObject)->Flags |= DO_DIRECT_IO; + ; + + //======================== + // Finalize initialization + //======================== + + Adapter->TapDeviceCreated = TRUE; + + DEBUGP(("[%wZ] successfully created TAP device [%wZ]\n", &Adapter->NetCfgInstanceId, + &Adapter->DeviceName)); + } + + DEBUGP(("[TAP] <-- CreateTapDevice; status = %8.8X\n", status)); + + return status; +} + +// +// DestroyTapDevice is called from AdapterHalt and NDIS miniport +// is in Halted state. Prior to entering the Halted state the +// miniport would have passed through the Pausing and Paused +// states. These miniport states have responsibility for waiting +// until NDIS network operations have completed. +// +VOID DestroyTapDevice(__in PTAP_ADAPTER_CONTEXT Adapter) { + DEBUGP(("[TAP] --> DestroyTapDevice; Adapter: %wZ\n", &Adapter->NetCfgInstanceId)); + + // + // Let clients know we are shutting down + // + Adapter->TapDeviceCreated = FALSE; + + // + // Flush pending send TAP packet queue. + // + tapFlushSendPacketQueue(Adapter); + + ASSERT(Adapter->SendPacketQueue.Count == 0); + + // + // Flush IRP queues. Wait for pending I/O. Etc. + // -------------------------------------------- + // Exhaust IRP and packet queues. Any pending IRPs will + // be cancelled, causing user-space to get this error + // on overlapped reads: + // + // ERROR_OPERATION_ABORTED, code=995 + // + // "The I/O operation has been aborted because of either a + // thread exit or an application request." + // + // It's important that user-space close the device handle + // when this code is returned, so that when we finally + // do a NdisMDeregisterDeviceEx, the device reference count + // is 0. Otherwise the driver will not unload even if the + // the last adapter has been halted. + // + // The act of flushing the queues at this point should result in the user-mode + // application closing the adapter's device handle. Closing the handle will + // result in the TapDeviceCleanup call being made, followed by the a call to + // the TapDeviceClose callback. + // + tapFlushIrpQueues(Adapter); + + ASSERT(Adapter->PendingReadIrpQueue.Count == 0); + + // + // Deregister the Win32 device. + // ---------------------------- + // When a driver calls NdisDeregisterDeviceEx, the I/O manager deletes the + // target device object if there are no outstanding references to it. However, + // if any outstanding references remain, the I/O manager marks the device + // object as "delete pending" and deletes the device object when the references + // are finally released. + // + if (Adapter->DeviceHandle) { + DEBUGP(("[TAP] Calling NdisDeregisterDeviceEx\n")); + NdisDeregisterDeviceEx(Adapter->DeviceHandle); + } + + Adapter->DeviceHandle = NULL; + + DEBUGP(("[TAP] <-- DestroyTapDevice\n")); +} diff --git a/third_party/tap-windows6/src/device.h b/third_party/tap-windows6/src/device.h new file mode 100644 index 00000000000..44118126572 --- /dev/null +++ b/third_party/tap-windows6/src/device.h @@ -0,0 +1,44 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __TAP_DEVICE_H_ +#define __TAP_DEVICE_H_ + +//====================================================================== +// TAP Prototypes for standard Win32 device I/O entry points +//====================================================================== + +__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH TapDeviceCreate; + +__drv_dispatchType(IRP_MJ_READ) DRIVER_DISPATCH TapDeviceRead; + +__drv_dispatchType(IRP_MJ_WRITE) DRIVER_DISPATCH TapDeviceWrite; + +__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH TapDeviceControl; + +__drv_dispatchType(IRP_MJ_CLEANUP) DRIVER_DISPATCH TapDeviceCleanup; + +__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH TapDeviceClose; + +#endif // __TAP_DEVICE_H_ \ No newline at end of file diff --git a/third_party/tap-windows6/src/dhcp.c b/third_party/tap-windows6/src/dhcp.c new file mode 100644 index 00000000000..9f0bb962e49 --- /dev/null +++ b/third_party/tap-windows6/src/dhcp.c @@ -0,0 +1,532 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tap.h" + +//========================= +// Code to set DHCP options +//========================= + +VOID SetDHCPOpt(__in DHCPMsg *m, __in void *data, __in unsigned int len) { + if (!m->overflow) { + if (m->optlen + len <= DHCP_OPTIONS_BUFFER_SIZE) { + if (len) { + NdisMoveMemory(m->msg.options + m->optlen, data, len); + m->optlen += len; + } + } else { + m->overflow = TRUE; + } + } +} + +VOID SetDHCPOpt0(__in DHCPMsg *msg, __in int type) { + DHCPOPT0 opt; + opt.type = (UCHAR)type; + SetDHCPOpt(msg, &opt, sizeof(opt)); +} + +VOID SetDHCPOpt8(__in DHCPMsg *msg, __in int type, __in ULONG data) { + DHCPOPT8 opt; + opt.type = (UCHAR)type; + opt.len = sizeof(opt.data); + opt.data = (UCHAR)data; + SetDHCPOpt(msg, &opt, sizeof(opt)); +} + +VOID SetDHCPOpt32(__in DHCPMsg *msg, __in int type, __in ULONG data) { + DHCPOPT32 opt; + opt.type = (UCHAR)type; + opt.len = sizeof(opt.data); + opt.data = data; + SetDHCPOpt(msg, &opt, sizeof(opt)); +} + +//============== +// Checksum code +//============== + +USHORT +ip_checksum(__in const UCHAR *buf, __in const int len_ip_header) { + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words in the packet + // and add them up + for (i = 0; i < len_ip_header - 1; i += 2) { + word16 = ((buf[i] << 8) & 0xFF00) + (buf[i + 1] & 0xFF); + sum += (ULONG)word16; + } + + // take only 16 bits out of the 32 bit sum and add up the carries + while (sum >> 16) { + sum = (sum & 0xFFFF) + (sum >> 16); + } + + // one's complement the result + return ((USHORT)~sum); +} + +USHORT +udp_checksum(__in const UCHAR *buf, __in const int len_udp, __in const UCHAR *src_addr, + __in const UCHAR *dest_addr) { + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words and + // calculate the sum of all 16 bit words + for (i = 0; i < len_udp; i += 2) { + word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i + 1] & 0xFF) : 0); + sum += word16; + } + + // add the UDP pseudo header which contains the IP source and destination addresses + for (i = 0; i < 4; i += 2) { + word16 = ((src_addr[i] << 8) & 0xFF00) + (src_addr[i + 1] & 0xFF); + sum += word16; + } + + for (i = 0; i < 4; i += 2) { + word16 = ((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i + 1] & 0xFF); + sum += word16; + } + + // the protocol number and the length of the UDP packet + sum += (USHORT)IPPROTO_UDP + (USHORT)len_udp; + + // keep only the last 16 bits of the 32 bit calculated sum and add the carries + while (sum >> 16) { + sum = (sum & 0xFFFF) + (sum >> 16); + } + + // Take the one's complement of sum + return ((USHORT)~sum); +} + +//================================ +// Set IP and UDP packet checksums +//================================ + +VOID SetChecksumDHCPMsg(__in DHCPMsg *m) { + // Set IP checksum + m->msg.pre.ip.check = htons(ip_checksum((UCHAR *)&m->msg.pre.ip, sizeof(IPHDR))); + + // Set UDP Checksum + m->msg.pre.udp.check = + htons(udp_checksum((UCHAR *)&m->msg.pre.udp, sizeof(UDPHDR) + sizeof(DHCP) + m->optlen, + (UCHAR *)&m->msg.pre.ip.saddr, (UCHAR *)&m->msg.pre.ip.daddr)); +} + +//=================== +// DHCP message tests +//=================== + +int GetDHCPMessageType(__in const DHCP *dhcp, __in const int optlen) { + const UCHAR *p = (UCHAR *)(dhcp + 1); + int i; + + for (i = 0; i < optlen; ++i) { + const UCHAR type = p[i]; + const int room = optlen - i - 1; + + if (type == DHCP_END) // didn't find what we were looking for + return -1; + else if (type == DHCP_PAD) // no-operation + ; + else if (type == DHCP_MSG_TYPE) // what we are looking for + { + if (room >= 2) { + if (p[i + 1] == 1) // message length should be 1 + return p[i + 2]; // return message type + } + return -1; + } else // some other message + { + if (room >= 1) { + const int len = p[i + 1]; // get message length + i += (len + 1); // advance to next message + } + } + } + return -1; +} + +BOOLEAN +DHCPMessageOurs(__in const PTAP_ADAPTER_CONTEXT Adapter, __in const ETH_HEADER *eth, + __in const IPHDR *ip, __in const UDPHDR *udp, __in const DHCP *dhcp) { + // Must be UDPv4 protocol + if (!(eth->proto == htons(NDIS_ETH_TYPE_IPV4) && ip->protocol == IPPROTO_UDP)) { + return FALSE; + } + + // Source MAC must be our adapter + if (!MAC_EQUAL(eth->src, Adapter->CurrentAddress)) { + return FALSE; + } + + // Dest MAC must be either broadcast or our virtual DHCP server + if (!(ETH_IS_BROADCAST(eth->dest) || MAC_EQUAL(eth->dest, Adapter->m_dhcp_server_mac))) { + return FALSE; + } + + // Port numbers must be correct + if (!(udp->dest == htons(BOOTPS_PORT) && udp->source == htons(BOOTPC_PORT))) { + return FALSE; + } + + // Hardware address must be MAC addr sized + if (!(dhcp->hlen == sizeof(MACADDR))) { + return FALSE; + } + + // Hardware address must match our adapter + if (!MAC_EQUAL(eth->src, dhcp->chaddr)) { + return FALSE; + } + + return TRUE; +} + +//===================================================== +// Build all of DHCP packet except for DHCP options. +// Assume that *p has been zeroed before we are called. +//===================================================== + +VOID BuildDHCPPre(__in const PTAP_ADAPTER_CONTEXT Adapter, __inout DHCPPre *p, + __in const ETH_HEADER *eth, __in const IPHDR *ip, __in const UDPHDR *udp, + __in const DHCP *dhcp, __in const int optlen, __in const int type) { + // Should we broadcast or direct to a specific MAC / IP address? + const BOOLEAN broadcast = (type == DHCPNAK || ETH_IS_BROADCAST(eth->dest)); + + // + // Build ethernet header + // + ETH_COPY_NETWORK_ADDRESS(p->eth.src, Adapter->m_dhcp_server_mac); + + if (broadcast) { + memset(p->eth.dest, 0xFF, ETH_LENGTH_OF_ADDRESS); + } else { + ETH_COPY_NETWORK_ADDRESS(p->eth.dest, eth->src); + } + + p->eth.proto = htons(NDIS_ETH_TYPE_IPV4); + + // + // Build IP header + // + p->ip.version_len = (4 << 4) | (sizeof(IPHDR) >> 2); + p->ip.tos = 0; + p->ip.tot_len = htons(sizeof(IPHDR) + sizeof(UDPHDR) + sizeof(DHCP) + optlen); + p->ip.id = 0; + p->ip.frag_off = 0; + p->ip.ttl = 16; + p->ip.protocol = IPPROTO_UDP; + p->ip.check = 0; + p->ip.saddr = Adapter->m_dhcp_server_ip; + + if (broadcast) { + p->ip.daddr = ~0; + } else { + p->ip.daddr = Adapter->m_dhcp_addr; + } + + // + // Build UDP header + // + p->udp.source = htons(BOOTPS_PORT); + p->udp.dest = htons(BOOTPC_PORT); + p->udp.len = htons(sizeof(UDPHDR) + sizeof(DHCP) + optlen); + p->udp.check = 0; + + // Build DHCP response + + p->dhcp.op = BOOTREPLY; + p->dhcp.htype = 1; + p->dhcp.hlen = sizeof(MACADDR); + p->dhcp.hops = 0; + p->dhcp.xid = dhcp->xid; + p->dhcp.secs = 0; + p->dhcp.flags = 0; + p->dhcp.ciaddr = 0; + + if (type == DHCPNAK) { + p->dhcp.yiaddr = 0; + } else { + p->dhcp.yiaddr = Adapter->m_dhcp_addr; + } + + p->dhcp.siaddr = Adapter->m_dhcp_server_ip; + p->dhcp.giaddr = 0; + ETH_COPY_NETWORK_ADDRESS(p->dhcp.chaddr, eth->src); + p->dhcp.magic = htonl(0x63825363); +} + +//============================= +// Build specific DHCP messages +//============================= + +VOID SendDHCPMsg(__in PTAP_ADAPTER_CONTEXT Adapter, __in const int type, __in const ETH_HEADER *eth, + __in const IPHDR *ip, __in const UDPHDR *udp, __in const DHCP *dhcp) { + DHCPMsg *pkt; + + if (!(type == DHCPOFFER || type == DHCPACK || type == DHCPNAK)) { + DEBUGP(("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type)); + return; + } + + pkt = (DHCPMsg *)MemAlloc(sizeof(DHCPMsg), TRUE); + + if (pkt) { + //----------------------- + // Build DHCP options + //----------------------- + + // Message Type + SetDHCPOpt8(pkt, DHCP_MSG_TYPE, type); + + // Server ID + SetDHCPOpt32(pkt, DHCP_SERVER_ID, Adapter->m_dhcp_server_ip); + + if (type == DHCPOFFER || type == DHCPACK) { + // Lease Time + SetDHCPOpt32(pkt, DHCP_LEASE_TIME, htonl(Adapter->m_dhcp_lease_time)); + + // Netmask + SetDHCPOpt32(pkt, DHCP_NETMASK, Adapter->m_dhcp_netmask); + + // Other user-defined options + SetDHCPOpt(pkt, Adapter->m_dhcp_user_supplied_options_buffer, + Adapter->m_dhcp_user_supplied_options_buffer_len); + } + + // End + SetDHCPOpt0(pkt, DHCP_END); + + if (!DHCPMSG_OVERFLOW(pkt)) { + // The initial part of the DHCP message (not including options) gets built here + BuildDHCPPre(Adapter, &pkt->msg.pre, eth, ip, udp, dhcp, DHCPMSG_LEN_OPT(pkt), type); + + SetChecksumDHCPMsg(pkt); + + DUMP_PACKET("DHCPMsg", DHCPMSG_BUF(pkt), DHCPMSG_LEN_FULL(pkt)); + + // Return DHCP response to kernel + IndicateReceivePacket(Adapter, DHCPMSG_BUF(pkt), DHCPMSG_LEN_FULL(pkt)); + } else { + DEBUGP(("[TAP] SendDHCPMsg: DHCP buffer overflow\n")); + } + + MemFree(pkt, sizeof(DHCPMsg)); + } +} + +//=================================================================== +// Handle a BOOTPS packet produced by the local system to +// resolve the address/netmask of this adapter. +// If we are in TAP_WIN_IOCTL_CONFIG_DHCP_MASQ mode, reply +// to the message. Return TRUE if we processed the passed +// message, so that downstream stages can ignore it. +//=================================================================== + +BOOLEAN +ProcessDHCP(__in PTAP_ADAPTER_CONTEXT Adapter, __in const ETH_HEADER *eth, __in const IPHDR *ip, + __in const UDPHDR *udp, __in const DHCP *dhcp, __in int optlen) { + int msg_type; + + // Sanity check IP header + if (!(ntohs(ip->tot_len) == sizeof(IPHDR) + sizeof(UDPHDR) + sizeof(DHCP) + optlen && + (ntohs(ip->frag_off) & IP_OFFMASK) == 0)) { + return TRUE; + } + + // Does this message belong to us? + if (!DHCPMessageOurs(Adapter, eth, ip, udp, dhcp)) { + return FALSE; + } + + msg_type = GetDHCPMessageType(dhcp, optlen); + + // Drop non-BOOTREQUEST messages + if (dhcp->op != BOOTREQUEST) { + return TRUE; + } + + // Drop any messages except DHCPDISCOVER or DHCPREQUEST + if (!(msg_type == DHCPDISCOVER || msg_type == DHCPREQUEST)) { + return TRUE; + } + + // Should we reply with DHCPOFFER, DHCPACK, or DHCPNAK? + if (msg_type == DHCPREQUEST && ((dhcp->ciaddr && dhcp->ciaddr != Adapter->m_dhcp_addr) || + !Adapter->m_dhcp_received_discover || + Adapter->m_dhcp_bad_requests >= BAD_DHCPREQUEST_NAK_THRESHOLD)) { + SendDHCPMsg(Adapter, DHCPNAK, eth, ip, udp, dhcp); + } else { + SendDHCPMsg(Adapter, (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK), eth, ip, udp, dhcp); + } + + // Remember if we received a DHCPDISCOVER + if (msg_type == DHCPDISCOVER) { + Adapter->m_dhcp_received_discover = TRUE; + } + + // Is this a bad DHCPREQUEST? + if (msg_type == DHCPREQUEST && dhcp->ciaddr && dhcp->ciaddr != Adapter->m_dhcp_addr) { + ++Adapter->m_dhcp_bad_requests; + } + + return TRUE; +} + +#if DBG + +const char *message_op_text(int op) { + switch (op) { + case BOOTREQUEST: + return "BOOTREQUEST"; + + case BOOTREPLY: + return "BOOTREPLY"; + + default: + return "???"; + } +} + +const char *message_type_text(int type) { + switch (type) { + case DHCPDISCOVER: + return "DHCPDISCOVER"; + + case DHCPOFFER: + return "DHCPOFFER"; + + case DHCPREQUEST: + return "DHCPREQUEST"; + + case DHCPDECLINE: + return "DHCPDECLINE"; + + case DHCPACK: + return "DHCPACK"; + + case DHCPNAK: + return "DHCPNAK"; + + case DHCPRELEASE: + return "DHCPRELEASE"; + + case DHCPINFORM: + return "DHCPINFORM"; + + default: + return "???"; + } +} + +const char *port_name(int port) { + switch (port) { + case BOOTPS_PORT: + return "BOOTPS"; + + case BOOTPC_PORT: + return "BOOTPC"; + + default: + return "unknown"; + } +} + +VOID DumpDHCP(const ETH_HEADER *eth, const IPHDR *ip, const UDPHDR *udp, const DHCP *dhcp, + const int optlen) { + DEBUGP((" %s", message_op_text(dhcp->op))); + DEBUGP((" %s ", message_type_text(GetDHCPMessageType(dhcp, optlen)))); + PrIP(ip->saddr); + DEBUGP((":%s[", port_name(ntohs(udp->source)))); + PrMac(eth->src); + DEBUGP(("] -> ")); + PrIP(ip->daddr); + DEBUGP((":%s[", port_name(ntohs(udp->dest)))); + PrMac(eth->dest); + DEBUGP(("]")); + if (dhcp->ciaddr) { + DEBUGP((" ci=")); + PrIP(dhcp->ciaddr); + } + if (dhcp->yiaddr) { + DEBUGP((" yi=")); + PrIP(dhcp->yiaddr); + } + if (dhcp->siaddr) { + DEBUGP((" si=")); + PrIP(dhcp->siaddr); + } + if (dhcp->hlen == sizeof(MACADDR)) { + DEBUGP((" ch=")); + PrMac(dhcp->chaddr); + } + + DEBUGP((" xid=0x%08x", ntohl(dhcp->xid))); + + if (ntohl(dhcp->magic) != 0x63825363) DEBUGP((" ma=0x%08x", ntohl(dhcp->magic))); + if (dhcp->htype != 1) DEBUGP((" htype=%d", dhcp->htype)); + if (dhcp->hops) DEBUGP((" hops=%d", dhcp->hops)); + if (ntohs(dhcp->secs)) DEBUGP((" secs=%d", ntohs(dhcp->secs))); + if (ntohs(dhcp->flags)) DEBUGP((" flags=0x%04x", ntohs(dhcp->flags))); + + // extra stuff + + if (ip->version_len != 0x45) DEBUGP((" vl=0x%02x", ip->version_len)); + if (ntohs(ip->tot_len) != sizeof(IPHDR) + sizeof(UDPHDR) + sizeof(DHCP) + optlen) + DEBUGP((" tl=%d", ntohs(ip->tot_len))); + if (ntohs(udp->len) != sizeof(UDPHDR) + sizeof(DHCP) + optlen) + DEBUGP((" ul=%d", ntohs(udp->len))); + + if (ip->tos) DEBUGP((" tos=0x%02x", ip->tos)); + if (ntohs(ip->id)) DEBUGP((" id=0x%04x", ntohs(ip->id))); + if (ntohs(ip->frag_off)) DEBUGP((" frag_off=0x%04x", ntohs(ip->frag_off))); + + DEBUGP((" ttl=%d", ip->ttl)); + DEBUGP((" ic=0x%04x [0x%04x]", ntohs(ip->check), ip_checksum((UCHAR *)ip, sizeof(IPHDR)))); + DEBUGP((" uc=0x%04x [0x%04x/%d]", ntohs(udp->check), + udp_checksum((UCHAR *)udp, sizeof(UDPHDR) + sizeof(DHCP) + optlen, (UCHAR *)&ip->saddr, + (UCHAR *)&ip->daddr), + optlen)); + + // Options + { + const UCHAR *opt = (UCHAR *)(dhcp + 1); + int i; + + DEBUGP((" OPT")); + for (i = 0; i < optlen; ++i) { + const UCHAR data = opt[i]; + DEBUGP((".%d", data)); + } + } +} + +#endif /* DBG */ diff --git a/third_party/tap-windows6/src/dhcp.h b/third_party/tap-windows6/src/dhcp.h new file mode 100644 index 00000000000..054b5d93266 --- /dev/null +++ b/third_party/tap-windows6/src/dhcp.h @@ -0,0 +1,161 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#pragma once + +#pragma pack(1) + +//=================================================== +// How many bad DHCPREQUESTs do we receive before we +// return a NAK? +// +// A bad DHCPREQUEST is defined to be one where the +// requestor doesn't know its IP address. +//=================================================== + +#define BAD_DHCPREQUEST_NAK_THRESHOLD 3 + +//============================================== +// Maximum number of DHCP options bytes supplied +//============================================== + +#define DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE 256 +#define DHCP_OPTIONS_BUFFER_SIZE 256 + +//=================================== +// UDP port numbers of DHCP messages. +//=================================== + +#define BOOTPS_PORT 67 +#define BOOTPC_PORT 68 + +//=========================== +// The DHCP message structure +//=========================== + +typedef struct { +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + UCHAR op; /* message op */ + + UCHAR htype; /* hardware address type (e.g. '1' = 10Mb Ethernet) */ + UCHAR hlen; /* hardware address length (e.g. '6' for 10Mb Ethernet) */ + UCHAR hops; /* client sets to 0, may be used by relay agents */ + ULONG xid; /* transaction ID, chosen by client */ + USHORT secs; /* seconds since request process began, set by client */ + USHORT flags; + ULONG ciaddr; /* client IP address, client sets if known */ + ULONG yiaddr; /* 'your' IP address -- server's response to client */ + ULONG siaddr; /* server IP address */ + ULONG giaddr; /* relay agent IP address */ + UCHAR chaddr[16]; /* client hardware address */ + UCHAR sname[64]; /* optional server host name */ + UCHAR file[128]; /* boot file name */ + ULONG magic; /* must be 0x63825363 (network order) */ +} DHCP; + +typedef struct { + ETH_HEADER eth; + IPHDR ip; + UDPHDR udp; + DHCP dhcp; +} DHCPPre; + +typedef struct { + DHCPPre pre; + UCHAR options[DHCP_OPTIONS_BUFFER_SIZE]; +} DHCPFull; + +typedef struct { + unsigned int optlen; + BOOLEAN overflow; + DHCPFull msg; +} DHCPMsg; + +//=================== +// Macros for DHCPMSG +//=================== + +#define DHCPMSG_LEN_BASE(p) (sizeof(DHCPPre)) +#define DHCPMSG_LEN_OPT(p) ((p)->optlen) +#define DHCPMSG_LEN_FULL(p) (DHCPMSG_LEN_BASE(p) + DHCPMSG_LEN_OPT(p)) +#define DHCPMSG_BUF(p) ((UCHAR *)&(p)->msg) +#define DHCPMSG_OVERFLOW(p) ((p)->overflow) + +//======================================== +// structs to hold individual DHCP options +//======================================== + +typedef struct { + UCHAR type; +} DHCPOPT0; + +typedef struct { + UCHAR type; + UCHAR len; + UCHAR data; +} DHCPOPT8; + +typedef struct { + UCHAR type; + UCHAR len; + ULONG data; +} DHCPOPT32; + +#pragma pack() + +//================== +// DHCP Option types +//================== + +#define DHCP_MSG_TYPE 53 /* message type (u8) */ +#define DHCP_PARM_REQ 55 /* parameter request list: c1 (u8), ... */ +#define DHCP_CLIENT_ID 61 /* client ID: type (u8), i1 (u8), ... */ +#define DHCP_IP 50 /* requested IP addr (u32) */ +#define DHCP_NETMASK 1 /* subnet mask (u32) */ +#define DHCP_LEASE_TIME 51 /* lease time sec (u32) */ +#define DHCP_RENEW_TIME 58 /* renewal time sec (u32) */ +#define DHCP_REBIND_TIME 59 /* rebind time sec (u32) */ +#define DHCP_SERVER_ID 54 /* server ID: IP addr (u32) */ +#define DHCP_PAD 0 +#define DHCP_END 255 + +//==================== +// DHCP Messages types +//==================== + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +#if DBG + +VOID DumpDHCP(const ETH_HEADER *eth, const IPHDR *ip, const UDPHDR *udp, const DHCP *dhcp, + const int optlen); + +#endif diff --git a/third_party/tap-windows6/src/endian.h b/third_party/tap-windows6/src/endian.h new file mode 100644 index 00000000000..b7d34499903 --- /dev/null +++ b/third_party/tap-windows6/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-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef TAP_LITTLE_ENDIAN +#define ntohs(x) RtlUshortByteSwap(x) +#define htons(x) RtlUshortByteSwap(x) +#define ntohl(x) RtlUlongByteSwap(x) +#define htonl(x) RtlUlongByteSwap(x) +#else +#define ntohs(x) ((USHORT)(x)) +#define htons(x) ((USHORT)(x)) +#define ntohl(x) ((ULONG)(x)) +#define htonl(x) ((ULONG)(x)) +#endif diff --git a/third_party/tap-windows6/src/error.c b/third_party/tap-windows6/src/error.c new file mode 100644 index 00000000000..b3aaf5af549 --- /dev/null +++ b/third_party/tap-windows6/src/error.c @@ -0,0 +1,310 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tap.h" + +//----------------- +// DEBUGGING OUTPUT +//----------------- + +const char *g_LastErrorFilename; +int g_LastErrorLineNumber; + +#if DBG + +DebugOutput g_Debug; + +BOOLEAN +NewlineExists(const char *str, int len) { + while (len-- > 0) { + const char c = *str++; + if (c == '\n') + return TRUE; + else if (c == '\0') + break; + } + return FALSE; +} + +VOID MyDebugInit(unsigned int bufsiz) { + NdisZeroMemory(&g_Debug, sizeof(g_Debug)); + g_Debug.text = (char *)MemAlloc(bufsiz, FALSE); + + if (g_Debug.text) { + g_Debug.capacity = bufsiz; + } +} + +VOID MyDebugFree() { + if (g_Debug.text) { + MemFree(g_Debug.text, g_Debug.capacity); + } + + NdisZeroMemory(&g_Debug, sizeof(g_Debug)); +} + +VOID MyDebugPrint(const unsigned char *format, ...) { + if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT) { + BOOLEAN owned; + ACQUIRE_MUTEX_ADAPTIVE(&g_Debug.lock, owned); + if (owned) { + const int remaining = (int)g_Debug.capacity - (int)g_Debug.out; + + if (remaining > 0) { + va_list args; + NTSTATUS status; + char *end; + +#ifdef DBG_PRINT + va_start(args, format); + vDbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, format, args); + va_end(args); +#endif + va_start(args, format); + status = RtlStringCchVPrintfExA(g_Debug.text + g_Debug.out, remaining, &end, NULL, + STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS, format, args); + va_end(args); + va_start(args, format); + vDbgPrintEx(DPFLTR_IHVDRIVER_ID, 1, format, args); + va_end(args); + if (status == STATUS_SUCCESS) + g_Debug.out = (unsigned int)(end - g_Debug.text); + else + g_Debug.error = TRUE; + } else + g_Debug.error = TRUE; + + RELEASE_MUTEX(&g_Debug.lock); + } else + g_Debug.error = TRUE; + } +} + +BOOLEAN +GetDebugLine(__in char *buf, __in const int len) { + static const char *truncated = "[OUTPUT TRUNCATED]\n"; + BOOLEAN ret = FALSE; + + NdisZeroMemory(buf, len); + + if (g_Debug.text && g_Debug.capacity > 0) { + BOOLEAN owned; + ACQUIRE_MUTEX_ADAPTIVE(&g_Debug.lock, owned); + if (owned) { + int i = 0; + + if (g_Debug.error || + NewlineExists(g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in)) { + while (i < (len - 1) && g_Debug.in < g_Debug.out) { + const char c = g_Debug.text[g_Debug.in++]; + if (c == '\n') break; + buf[i++] = c; + } + if (i < len) buf[i] = '\0'; + } + + if (!i) { + if (g_Debug.in == g_Debug.out) { + g_Debug.in = g_Debug.out = 0; + if (g_Debug.error) { + const unsigned int tlen = strlen(truncated); + if (tlen < g_Debug.capacity) { + NdisMoveMemory(g_Debug.text, truncated, tlen + 1); + g_Debug.out = tlen; + } + g_Debug.error = FALSE; + } + } + } else + ret = TRUE; + + RELEASE_MUTEX(&g_Debug.lock); + } + } + return ret; +} + +VOID PrMac(const MACADDR mac) { + DEBUGP(("%x:%x:%x:%x:%x:%x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); +} + +VOID PrIP(IPADDR ip_addr) { + const unsigned char *ip = (const unsigned char *)&ip_addr; + + DEBUGP(("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])); +} + +const char *PrIPProto(int proto) { + switch (proto) { + case IPPROTO_UDP: + return "UDP"; + + case IPPROTO_TCP: + return "TCP"; + + case IPPROTO_ICMP: + return "ICMP"; + + case IPPROTO_IGMP: + return "IGMP"; + + default: + return "???"; + } +} + +VOID DumpARP(const char *prefix, const ARP_PACKET *arp) { + DEBUGP(("%s ARP src=", prefix)); + PrMac(arp->m_MAC_Source); + DEBUGP((" dest=")); + PrMac(arp->m_MAC_Destination); + DEBUGP((" OP=0x%04x", (int)ntohs(arp->m_ARP_Operation))); + DEBUGP((" M=0x%04x(%d)", (int)ntohs(arp->m_MAC_AddressType), (int)arp->m_MAC_AddressSize)); + DEBUGP((" P=0x%04x(%d)", (int)ntohs(arp->m_PROTO_AddressType), (int)arp->m_PROTO_AddressSize)); + + DEBUGP((" MacSrc=")); + PrMac(arp->m_ARP_MAC_Source); + DEBUGP((" MacDest=")); + PrMac(arp->m_ARP_MAC_Destination); + + DEBUGP((" IPSrc=")); + PrIP(arp->m_ARP_IP_Source); + DEBUGP((" IPDest=")); + PrIP(arp->m_ARP_IP_Destination); + + DEBUGP(("\n")); +} + +struct ethpayload { + ETH_HEADER eth; + UCHAR payload[DEFAULT_PACKET_LOOKAHEAD]; +}; + +#ifdef ALLOW_PACKET_DUMP + +VOID DumpPacket2(__in const char *prefix, __in const ETH_HEADER *eth, + __in const unsigned char *data, __in unsigned int len) { + struct ethpayload *ep = (struct ethpayload *)MemAlloc(sizeof(struct ethpayload), TRUE); + if (ep) { + if (len > DEFAULT_PACKET_LOOKAHEAD) len = DEFAULT_PACKET_LOOKAHEAD; + ep->eth = *eth; + NdisMoveMemory(ep->payload, data, len); + DumpPacket(prefix, (unsigned char *)ep, sizeof(ETH_HEADER) + len); + MemFree(ep, sizeof(struct ethpayload)); + } +} + +VOID DumpPacket(__in const char *prefix, __in const unsigned char *data, __in unsigned int len) { + const ETH_HEADER *eth = (const ETH_HEADER *)data; + const IPHDR *ip = (const IPHDR *)(data + sizeof(ETH_HEADER)); + + if (len < sizeof(ETH_HEADER)) { + DEBUGP(("%s TRUNCATED PACKET LEN=%d\n", prefix, len)); + return; + } + + // ARP Packet? + if (len >= sizeof(ARP_PACKET) && eth->proto == htons(ETH_P_ARP)) { + DumpARP(prefix, (const ARP_PACKET *)data); + return; + } + + // IPv4 packet? + if (len >= (sizeof(IPHDR) + sizeof(ETH_HEADER)) && eth->proto == htons(ETH_P_IP) && + IPH_GET_VER(ip->version_len) == 4) { + const int hlen = IPH_GET_LEN(ip->version_len); + const int blen = len - sizeof(ETH_HEADER); + BOOLEAN did = FALSE; + + DEBUGP(("%s IPv4 %s[%d]", prefix, PrIPProto(ip->protocol), len)); + + if (!(ntohs(ip->tot_len) == blen && hlen <= blen)) { + DEBUGP((" XXX")); + return; + } + + // TCP packet? + if (ip->protocol == IPPROTO_TCP && blen - hlen >= (sizeof(TCPHDR))) { + const TCPHDR *tcp = (TCPHDR *)(data + sizeof(ETH_HEADER) + hlen); + DEBUGP((" ")); + PrIP(ip->saddr); + DEBUGP((":%d", ntohs(tcp->source))); + DEBUGP((" -> ")); + PrIP(ip->daddr); + DEBUGP((":%d", ntohs(tcp->dest))); + did = TRUE; + } + + // UDP packet? + else if ((ntohs(ip->frag_off) & IP_OFFMASK) == 0 && ip->protocol == IPPROTO_UDP && + blen - hlen >= (sizeof(UDPHDR))) { + const UDPHDR *udp = (UDPHDR *)(data + sizeof(ETH_HEADER) + hlen); + + // DHCP packet? + if ((udp->dest == htons(BOOTPC_PORT) || udp->dest == htons(BOOTPS_PORT)) && + blen - hlen >= (sizeof(UDPHDR) + sizeof(DHCP))) { + const DHCP *dhcp = (DHCP *)(data + hlen + sizeof(ETH_HEADER) + sizeof(UDPHDR)); + + int optlen = len - sizeof(ETH_HEADER) - hlen - sizeof(UDPHDR) - sizeof(DHCP); + + if (optlen < 0) optlen = 0; + + DumpDHCP(eth, ip, udp, dhcp, optlen); + did = TRUE; + } + + if (!did) { + DEBUGP((" ")); + PrIP(ip->saddr); + DEBUGP((":%d", ntohs(udp->source))); + DEBUGP((" -> ")); + PrIP(ip->daddr); + DEBUGP((":%d", ntohs(udp->dest))); + did = TRUE; + } + } + + if (!did) { + DEBUGP((" ipproto=%d ", ip->protocol)); + PrIP(ip->saddr); + DEBUGP((" -> ")); + PrIP(ip->daddr); + } + + DEBUGP(("\n")); + return; + } + + { + DEBUGP(("%s ??? src=", prefix)); + PrMac(eth->src); + DEBUGP((" dest=")); + PrMac(eth->dest); + DEBUGP((" proto=0x%04x len=%d\n", (int)ntohs(eth->proto), len)); + } +} + +#endif // ALLOW_PACKET_DUMP + +#endif diff --git a/third_party/tap-windows6/src/error.h b/third_party/tap-windows6/src/error.h new file mode 100644 index 00000000000..6a03330fd04 --- /dev/null +++ b/third_party/tap-windows6/src/error.h @@ -0,0 +1,104 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//----------------- +// DEBUGGING OUTPUT +//----------------- + +extern const char *g_LastErrorFilename; +extern int g_LastErrorLineNumber; + +// Debug info output +#define ALSO_DBGPRINT 1 +#define DEBUGP_AT_DISPATCH 1 + +// Uncomment line below to allow packet dumps +//#define ALLOW_PACKET_DUMP 1 + +#define NOTE_ERROR() \ + { \ + g_LastErrorFilename = __FILE__; \ + g_LastErrorLineNumber = __LINE__; \ + } + +#if DBG + +typedef struct { + unsigned int in; + unsigned int out; + unsigned int capacity; + char *text; + BOOLEAN error; + MUTEX lock; +} DebugOutput; + +VOID MyDebugPrint(const unsigned char *format, ...); + +VOID PrMac(const MACADDR mac); + +VOID PrIP(IPADDR ip_addr); + +#ifdef ALLOW_PACKET_DUMP + +VOID DumpPacket(__in const char *prefix, __in const unsigned char *data, __in unsigned int len); + +DumpPacket2(__in const char *prefix, __in const ETH_HEADER *eth, __in const unsigned char *data, + __in unsigned int len); + +#else +#define DUMP_PACKET(prefix, data, len) +#define DUMP_PACKET2(prefix, eth, data, len) +#endif + +#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql() < DISPATCH_LEVEL) + +#if ALSO_DBGPRINT +#define DEBUGP(fmt) \ + { \ + MyDebugPrint fmt; \ + if (CAN_WE_PRINT) DbgPrint fmt; \ + } +#else +#define DEBUGP(fmt) \ + { MyDebugPrint fmt; } +#endif + +#ifdef ALLOW_PACKET_DUMP + +#define DUMP_PACKET(prefix, data, len) DumpPacket(prefix, data, len) + +#define DUMP_PACKET2(prefix, eth, data, len) DumpPacket2(prefix, eth, data, len) + +#endif + +BOOLEAN +GetDebugLine(__in char *buf, __in const int len); + +#else + +#define DEBUGP(fmt) +#define DUMP_PACKET(prefix, data, len) +#define DUMP_PACKET2(prefix, eth, data, len) + +#endif diff --git a/third_party/tap-windows6/src/hexdump.h b/third_party/tap-windows6/src/hexdump.h new file mode 100644 index 00000000000..fbffe4fe793 --- /dev/null +++ b/third_party/tap-windows6/src/hexdump.h @@ -0,0 +1,64 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HEXDUMP_DEFINED +#define HEXDUMP_DEFINED + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Debug Routines +//===================================================================================== + +#ifndef NDIS_MINIPORT_DRIVER +#include +#include +#include +#include +#include + +#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/third_party/tap-windows6/src/lock.h b/third_party/tap-windows6/src/lock.h new file mode 100644 index 00000000000..6f5c605543f --- /dev/null +++ b/third_party/tap-windows6/src/lock.h @@ -0,0 +1,67 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +typedef struct { + volatile long count; +} MUTEX; + +#define MUTEX_SLEEP_TIME 10000 // microseconds + +#define INIT_MUTEX(m) \ + { (m)->count = 0; } + +#define ACQUIRE_MUTEX_BLOCKING(m) \ + { \ + while (NdisInterlockedIncrement(&((m)->count)) != 1) { \ + NdisInterlockedDecrement(&((m)->count)); \ + NdisMSleep(MUTEX_SLEEP_TIME); \ + } \ + } + +#define RELEASE_MUTEX(m) \ + { NdisInterlockedDecrement(&((m)->count)); } + +#define ACQUIRE_MUTEX_NONBLOCKING(m, result) \ + { \ + if (NdisInterlockedIncrement(&((m)->count)) != 1) { \ + NdisInterlockedDecrement(&((m)->count)); \ + result = FALSE; \ + } else { \ + result = TRUE; \ + } \ + } + +#define ACQUIRE_MUTEX_ADAPTIVE(m, result) \ + { \ + result = TRUE; \ + while (NdisInterlockedIncrement(&((m)->count)) != 1) { \ + NdisInterlockedDecrement(&((m)->count)); \ + if (KeGetCurrentIrql() < DISPATCH_LEVEL) \ + NdisMSleep(MUTEX_SLEEP_TIME); \ + else { \ + result = FALSE; \ + break; \ + } \ + } \ + } diff --git a/third_party/tap-windows6/src/macinfo.c b/third_party/tap-windows6/src/macinfo.c new file mode 100644 index 00000000000..88155dd9d75 --- /dev/null +++ b/third_party/tap-windows6/src/macinfo.c @@ -0,0 +1,132 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "tap.h" + +int HexStringToDecimalInt(const int p_Character) { + int l_Value = 0; + + if (p_Character >= 'A' && p_Character <= 'F') + l_Value = (p_Character - 'A') + 10; + else if (p_Character >= 'a' && p_Character <= 'f') + l_Value = (p_Character - 'a') + 10; + else if (p_Character >= '0' && p_Character <= '9') + l_Value = p_Character - '0'; + + return l_Value; +} + +BOOLEAN +ParseMAC(MACADDR dest, const char *src) { + int c; + int mac_index = 0; + BOOLEAN high_digit = FALSE; + int delim_action = 1; + + ASSERT(src); + ASSERT(dest); + + CLEAR_MAC(dest); + + while (c = *src++) { + if (IsMacDelimiter(c)) { + mac_index += delim_action; + high_digit = FALSE; + delim_action = 1; + } else if (IsHexDigit(c)) { + const int digit = HexStringToDecimalInt(c); + if (mac_index < sizeof(MACADDR)) { + if (!high_digit) { + dest[mac_index] = (char)(digit); + high_digit = TRUE; + delim_action = 1; + } else { + dest[mac_index] = (char)(dest[mac_index] * 16 + digit); + ++mac_index; + high_digit = FALSE; + delim_action = 0; + } + } else + return FALSE; + } else + return FALSE; + } + + return (mac_index + delim_action) >= sizeof(MACADDR); +} + +/* + * Generate a MAC using the GUID in the adapter name. + * + * The mac is constructed as 00:FF:xx:xx:xx:xx where + * the Xs are taken from the first 32 bits of the GUID in the + * adapter name. This is similar to the Linux 2.4 tap MAC + * generator, except linux uses 32 random bits for the Xs. + * + * In general, this solution is reasonable for most + * applications except for very large bridged TAP networks, + * where the probability of address collisions becomes more + * than infintesimal. + * + * Using the well-known "birthday paradox", on a 1000 node + * network the probability of collision would be + * 0.000116292153. On a 10,000 node network, the probability + * of collision would be 0.01157288998621678766. + */ + +VOID GenerateRandomMac(__in MACADDR mac, __in const unsigned char *adapter_name) { + unsigned const char *cp = adapter_name; + unsigned char c; + unsigned int i = 2; + unsigned int byte = 0; + int brace = 0; + int state = 0; + + CLEAR_MAC(mac); + + mac[0] = 0x00; + mac[1] = 0xFF; + + while (c = *cp++) { + if (i >= sizeof(MACADDR)) break; + if (c == '{') brace = 1; + if (IsHexDigit(c) && brace) { + const unsigned int digit = HexStringToDecimalInt(c); + if (state) { + byte <<= 4; + byte |= digit; + mac[i++] = (unsigned char)byte; + state = 0; + } else { + byte = digit; + state = 1; + } + } + } +} + +VOID GenerateRelatedMAC(__in MACADDR dest, __in const MACADDR src, __in const int delta) { + ETH_COPY_NETWORK_ADDRESS(dest, src); + dest[2] += (UCHAR)delta; +} diff --git a/third_party/tap-windows6/src/macinfo.h b/third_party/tap-windows6/src/macinfo.h new file mode 100644 index 00000000000..22e8bf8bfb0 --- /dev/null +++ b/third_party/tap-windows6/src/macinfo.h @@ -0,0 +1,44 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MacInfoDefined +#define MacInfoDefined + +//=================================================================================== +// Macros +//=================================================================================== +#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.') +#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) + +#define CLEAR_MAC(dest) NdisZeroMemory((dest), sizeof(MACADDR)) +#define MAC_EQUAL(a, b) (memcmp((a), (b), sizeof(MACADDR)) == 0) + +BOOLEAN +ParseMAC(MACADDR dest, const char *src); + +VOID GenerateRandomMac(__in MACADDR mac, __in const unsigned char *adapter_name); + +VOID GenerateRelatedMAC(__in MACADDR dest, __in const MACADDR src, __in const int delta); + +#endif diff --git a/third_party/tap-windows6/src/mem.c b/third_party/tap-windows6/src/mem.c new file mode 100644 index 00000000000..42129f7aec5 --- /dev/null +++ b/third_party/tap-windows6/src/mem.c @@ -0,0 +1,285 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//------------------ +// Memory Management +//------------------ + +#include "tap.h" + +PVOID +MemAlloc(__in ULONG p_Size, __in BOOLEAN zero) { + PVOID l_Return = NULL; + + if (p_Size) { + __try { + if (NdisAllocateMemoryWithTag(&l_Return, p_Size, 'APAT') == NDIS_STATUS_SUCCESS) { + if (zero) { + NdisZeroMemory(l_Return, p_Size); + } + } else { + l_Return = NULL; + } + } __except (EXCEPTION_EXECUTE_HANDLER) { + l_Return = NULL; + } + } + + return l_Return; +} + +VOID MemFree(__in PVOID p_Addr, __in ULONG p_Size) { + if (p_Addr && p_Size) { + __try { +#if DBG + NdisZeroMemory(p_Addr, p_Size); +#endif + NdisFreeMemory(p_Addr, p_Size, 0); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } + } +} + +//====================================================================== +// TAP Packet Queue Support +//====================================================================== + +VOID tapPacketQueueInsertTail(__in PTAP_PACKET_QUEUE TapPacketQueue, __in PTAP_PACKET TapPacket) { + KIRQL irql; + + KeAcquireSpinLock(&TapPacketQueue->QueueLock, &irql); + + InsertTailList(&TapPacketQueue->Queue, &TapPacket->QueueLink); + + // BUGBUG!!! Enforce PACKET_QUEUE_SIZE queue count limit??? + // For NDIS 6 there is no per-packet status, so this will need to + // be handled on per-NBL basis in AdapterSendNetBufferLists... + + // Update counts + ++TapPacketQueue->Count; + + if (TapPacketQueue->Count > TapPacketQueue->MaxCount) { + TapPacketQueue->MaxCount = TapPacketQueue->Count; + + DEBUGP(("[TAP] tapPacketQueueInsertTail: New MAX queued packet count = %d\n", + TapPacketQueue->MaxCount)); + } + + KeReleaseSpinLock(&TapPacketQueue->QueueLock, irql); +} + +// Call with QueueLock held +PTAP_PACKET +tapPacketRemoveHeadLocked(__in PTAP_PACKET_QUEUE TapPacketQueue) { + PTAP_PACKET tapPacket = NULL; + PLIST_ENTRY listEntry; + + listEntry = RemoveHeadList(&TapPacketQueue->Queue); + + if (listEntry != &TapPacketQueue->Queue) { + tapPacket = CONTAINING_RECORD(listEntry, TAP_PACKET, QueueLink); + + // Update counts + --TapPacketQueue->Count; + } + + return tapPacket; +} + +VOID tapPacketQueueInitialize(__in PTAP_PACKET_QUEUE TapPacketQueue) { + KeInitializeSpinLock(&TapPacketQueue->QueueLock); + + NdisInitializeListHead(&TapPacketQueue->Queue); +} + +//====================================================================== +// TAP Cancel-Safe Queue Support +//====================================================================== + +VOID tapIrpCsqInsert(__in struct _IO_CSQ *Csq, __in PIRP Irp) { + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ)Csq; + + InsertTailList(&tapIrpCsq->Queue, &Irp->Tail.Overlay.ListEntry); + + // Update counts + ++tapIrpCsq->Count; + + if (tapIrpCsq->Count > tapIrpCsq->MaxCount) { + tapIrpCsq->MaxCount = tapIrpCsq->Count; + + DEBUGP(("[TAP] tapIrpCsqInsert: New MAX queued IRP count = %d\n", tapIrpCsq->MaxCount)); + } +} + +VOID tapIrpCsqRemoveIrp(__in PIO_CSQ Csq, __in PIRP Irp) { + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ)Csq; + + // Update counts + --tapIrpCsq->Count; + + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + +PIRP tapIrpCsqPeekNextIrp(__in PIO_CSQ Csq, __in PIRP Irp, __in PVOID PeekContext) { + PTAP_IRP_CSQ tapIrpCsq; + PIRP nextIrp = NULL; + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + PIO_STACK_LOCATION irpStack; + + tapIrpCsq = (PTAP_IRP_CSQ)Csq; + + listHead = &tapIrpCsq->Queue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if (Irp == NULL) { + nextEntry = listHead->Flink; + } else { + nextEntry = Irp->Tail.Overlay.ListEntry.Flink; + } + + while (nextEntry != listHead) { + nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); + + irpStack = IoGetCurrentIrpStackLocation(nextIrp); + + // + // If context is present, continue until you find a matching one. + // Else you break out as you got next one. + // + if (PeekContext) { + if (irpStack->FileObject == (PFILE_OBJECT)PeekContext) { + break; + } + } else { + break; + } + + nextIrp = NULL; + nextEntry = nextEntry->Flink; + } + + return nextIrp; +} + +// +// tapIrpCsqAcquireQueueLock modifies the execution level of the current processor. +// +// KeAcquireSpinLock raises the execution level to Dispatch Level and stores +// the current execution level in the Irql parameter to be restored at a later +// time. KeAcqurieSpinLock also requires us to be running at no higher than +// Dispatch level when it is called. +// +// The annotations reflect these changes and requirments. +// + +__drv_raisesIRQL(DISPATCH_LEVEL) __drv_maxIRQL(DISPATCH_LEVEL) VOID + tapIrpCsqAcquireQueueLock(__in PIO_CSQ Csq, __out PKIRQL Irql) { + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ)Csq; + + // + // Suppressing because the address below csq is valid since it's + // part of TAP_ADAPTER_CONTEXT structure. + // +#pragma prefast(suppress \ + : __WARNING_BUFFER_UNDERFLOW, \ + "Underflow using expression 'adapter->PendingReadCsqQueueLock'") + KeAcquireSpinLock(&tapIrpCsq->QueueLock, Irql); +} + +// +// tapIrpCsqReleaseQueueLock modifies the execution level of the current processor. +// +// KeReleaseSpinLock assumes we already hold the spin lock and are therefore +// running at Dispatch level. It will use the Irql parameter saved in a +// previous call to KeAcquireSpinLock to return the thread back to it's original +// execution level. +// +// The annotations reflect these changes and requirments. +// + +__drv_requiresIRQL(DISPATCH_LEVEL) VOID + tapIrpCsqReleaseQueueLock(__in PIO_CSQ Csq, __in KIRQL Irql) { + PTAP_IRP_CSQ tapIrpCsq; + + tapIrpCsq = (PTAP_IRP_CSQ)Csq; + + // + // Suppressing because the address below csq is valid since it's + // part of TAP_ADAPTER_CONTEXT structure. + // +#pragma prefast(suppress \ + : __WARNING_BUFFER_UNDERFLOW, \ + "Underflow using expression 'adapter->PendingReadCsqQueueLock'") + KeReleaseSpinLock(&tapIrpCsq->QueueLock, Irql); +} + +VOID tapIrpCsqCompleteCanceledIrp(__in PIO_CSQ pCsq, __in PIRP Irp) { + UNREFERENCED_PARAMETER(pCsq); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + +VOID tapIrpCsqInitialize(__in PTAP_IRP_CSQ TapIrpCsq) { + KeInitializeSpinLock(&TapIrpCsq->QueueLock); + + NdisInitializeListHead(&TapIrpCsq->Queue); + + IoCsqInitialize(&TapIrpCsq->CsqQueue, tapIrpCsqInsert, tapIrpCsqRemoveIrp, tapIrpCsqPeekNextIrp, + tapIrpCsqAcquireQueueLock, tapIrpCsqReleaseQueueLock, + tapIrpCsqCompleteCanceledIrp); +} + +VOID tapIrpCsqFlush(__in PTAP_IRP_CSQ TapIrpCsq) { + PIRP pendingIrp; + + // + // Flush the pending read IRP queue. + // + pendingIrp = IoCsqRemoveNextIrp(&TapIrpCsq->CsqQueue, NULL); + + while (pendingIrp) { + // Cancel the IRP + pendingIrp->IoStatus.Information = 0; + pendingIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); + + pendingIrp = IoCsqRemoveNextIrp(&TapIrpCsq->CsqQueue, NULL); + } + + ASSERT(IsListEmpty(&TapIrpCsq->Queue)); +} diff --git a/third_party/tap-windows6/src/mem.h b/third_party/tap-windows6/src/mem.h new file mode 100644 index 00000000000..e9b7c510efd --- /dev/null +++ b/third_party/tap-windows6/src/mem.h @@ -0,0 +1,81 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//------------------ +// Memory Management +//------------------ + +PVOID +MemAlloc(__in ULONG p_Size, __in BOOLEAN zero); + +VOID MemFree(__in PVOID p_Addr, __in ULONG p_Size); + +//====================================================================== +// TAP Packet Queue +//====================================================================== + +typedef struct _TAP_PACKET { + LIST_ENTRY QueueLink; + +#define TAP_PACKET_SIZE(data_size) (sizeof(TAP_PACKET) + (data_size)) +#define TP_TUN 0x80000000 +#define TP_SIZE_MASK (~TP_TUN) + ULONG m_SizeFlags; + + // m_Data must be the last struct member + UCHAR m_Data[]; +} TAP_PACKET, *PTAP_PACKET; + +#define TAP_PACKET_TAG '6PAT' // "TAP6" + +typedef struct _TAP_PACKET_QUEUE { + KSPIN_LOCK QueueLock; + LIST_ENTRY Queue; + ULONG Count; // Count of currently queued items + ULONG MaxCount; +} TAP_PACKET_QUEUE, *PTAP_PACKET_QUEUE; + +VOID tapPacketQueueInsertTail(__in PTAP_PACKET_QUEUE TapPacketQueue, __in PTAP_PACKET TapPacket); + +// Call with QueueLock held +PTAP_PACKET +tapPacketRemoveHeadLocked(__in PTAP_PACKET_QUEUE TapPacketQueue); + +VOID tapPacketQueueInitialize(__in PTAP_PACKET_QUEUE TapPacketQueue); + +//---------------------- +// Cancel-Safe IRP Queue +//---------------------- + +typedef struct _TAP_IRP_CSQ { + IO_CSQ CsqQueue; + KSPIN_LOCK QueueLock; + LIST_ENTRY Queue; + ULONG Count; // Count of currently queued items + ULONG MaxCount; +} TAP_IRP_CSQ, *PTAP_IRP_CSQ; + +VOID tapIrpCsqInitialize(__in PTAP_IRP_CSQ TapIrpCsq); + +VOID tapIrpCsqFlush(__in PTAP_IRP_CSQ TapIrpCsq); diff --git a/third_party/tap-windows6/src/oidrequest.c b/third_party/tap-windows6/src/oidrequest.c new file mode 100644 index 00000000000..a75d69672ed --- /dev/null +++ b/third_party/tap-windows6/src/oidrequest.c @@ -0,0 +1,916 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +#ifndef DBG + +#define DBG_PRINT_OID_NAME + +#else + +VOID DBG_PRINT_OID_NAME(__in NDIS_OID Oid) { + PCHAR oidName = NULL; + + switch (Oid) { + +#undef MAKECASE +#define MAKECASE(oidx) \ + case oidx: \ + oidName = #oidx "\n"; \ + break; + + /* Operational OIDs */ + MAKECASE(OID_GEN_SUPPORTED_LIST) + MAKECASE(OID_GEN_HARDWARE_STATUS) + MAKECASE(OID_GEN_MEDIA_SUPPORTED) + MAKECASE(OID_GEN_MEDIA_IN_USE) + MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD) + MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE) + MAKECASE(OID_GEN_LINK_SPEED) + MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE) + MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE) + MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE) + MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE) + MAKECASE(OID_GEN_VENDOR_ID) + MAKECASE(OID_GEN_VENDOR_DESCRIPTION) + MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION) + MAKECASE(OID_GEN_CURRENT_PACKET_FILTER) + MAKECASE(OID_GEN_CURRENT_LOOKAHEAD) + MAKECASE(OID_GEN_DRIVER_VERSION) + MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE) + MAKECASE(OID_GEN_PROTOCOL_OPTIONS) + MAKECASE(OID_GEN_MAC_OPTIONS) + MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS) + MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS) + MAKECASE(OID_GEN_SUPPORTED_GUIDS) + MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES) + MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET) + MAKECASE(OID_GEN_MEDIA_CAPABILITIES) + MAKECASE(OID_GEN_PHYSICAL_MEDIUM) + MAKECASE(OID_GEN_MACHINE_NAME) + MAKECASE(OID_GEN_VLAN_ID) + MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER) + + /* Operational OIDs for NDIS 6.0 */ + MAKECASE(OID_GEN_MAX_LINK_SPEED) + MAKECASE(OID_GEN_LINK_STATE) + MAKECASE(OID_GEN_LINK_PARAMETERS) + MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES) + MAKECASE(OID_GEN_ENUMERATE_PORTS) + MAKECASE(OID_GEN_PORT_STATE) + MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS) + MAKECASE(OID_GEN_INTERRUPT_MODERATION) + MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX) + + /* Statistical OIDs */ + MAKECASE(OID_GEN_XMIT_OK) + MAKECASE(OID_GEN_RCV_OK) + MAKECASE(OID_GEN_XMIT_ERROR) + MAKECASE(OID_GEN_RCV_ERROR) + MAKECASE(OID_GEN_RCV_NO_BUFFER) + MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT) + MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT) + MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT) + MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT) + MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT) + MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT) + MAKECASE(OID_GEN_DIRECTED_BYTES_RCV) + MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV) + MAKECASE(OID_GEN_MULTICAST_BYTES_RCV) + MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV) + MAKECASE(OID_GEN_BROADCAST_BYTES_RCV) + MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV) + MAKECASE(OID_GEN_RCV_CRC_ERROR) + MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH) + + /* Statistical OIDs for NDIS 6.0 */ + MAKECASE(OID_GEN_STATISTICS) + MAKECASE(OID_GEN_BYTES_RCV) + MAKECASE(OID_GEN_BYTES_XMIT) + MAKECASE(OID_GEN_RCV_DISCARDS) + MAKECASE(OID_GEN_XMIT_DISCARDS) + + /* Misc OIDs */ + MAKECASE(OID_GEN_GET_TIME_CAPS) + MAKECASE(OID_GEN_GET_NETCARD_TIME) + MAKECASE(OID_GEN_NETCARD_LOAD) + MAKECASE(OID_GEN_DEVICE_PROFILE) + MAKECASE(OID_GEN_INIT_TIME_MS) + MAKECASE(OID_GEN_RESET_COUNTS) + MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS) + + /* PnP power management operational OIDs */ + MAKECASE(OID_PNP_CAPABILITIES) + MAKECASE(OID_PNP_SET_POWER) + MAKECASE(OID_PNP_QUERY_POWER) + MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_ENABLE_WAKE_UP) + MAKECASE(OID_PNP_WAKE_UP_PATTERN_LIST) + + /* PnP power management statistical OIDs */ + MAKECASE(OID_PNP_WAKE_UP_ERROR) + MAKECASE(OID_PNP_WAKE_UP_OK) + + /* Ethernet operational OIDs */ + MAKECASE(OID_802_3_PERMANENT_ADDRESS) + MAKECASE(OID_802_3_CURRENT_ADDRESS) + MAKECASE(OID_802_3_MULTICAST_LIST) + MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE) + MAKECASE(OID_802_3_MAC_OPTIONS) + + /* Ethernet operational OIDs for NDIS 6.0 */ + MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS) + MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS) + + /* Ethernet statistical OIDs */ + MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT) + MAKECASE(OID_802_3_XMIT_ONE_COLLISION) + MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS) + MAKECASE(OID_802_3_XMIT_DEFERRED) + MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS) + MAKECASE(OID_802_3_RCV_OVERRUN) + MAKECASE(OID_802_3_XMIT_UNDERRUN) + MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE) + MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST) + MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS) + + /* TCP/IP OIDs */ + MAKECASE(OID_TCP_TASK_OFFLOAD) + MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA) + MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA) + MAKECASE(OID_TCP_SAN_SUPPORT) + MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA) + MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA) + MAKECASE(OID_TCP4_OFFLOAD_STATS) + MAKECASE(OID_TCP6_OFFLOAD_STATS) + MAKECASE(OID_IP4_OFFLOAD_STATS) + MAKECASE(OID_IP6_OFFLOAD_STATS) + + /* TCP offload OIDs for NDIS 6 */ + MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG) + MAKECASE(OID_TCP_OFFLOAD_PARAMETERS) + MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) + MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG) + MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES) + MAKECASE(OID_OFFLOAD_ENCAPSULATION) + +#if (NDIS_SUPPORT_NDIS620) + /* VMQ OIDs for NDIS 6.20 */ + MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE) + MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER) + MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE) + MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE) + MAKECASE(OID_RECEIVE_FILTER_SET_FILTER) +#endif + +#if (NDIS_SUPPORT_NDIS630) + /* NDIS QoS OIDs for NDIS 6.30 */ + MAKECASE(OID_QOS_PARAMETERS) +#endif + } + + if (oidName) { + DEBUGP(("OID: %s", oidName)); + } else { + DEBUGP(("<** Unknown OID 0x%08x **>\n", Oid)); + } +} + +#endif // DBG + +//====================================================================== +// TAP NDIS 6 OID Request Callbacks +//====================================================================== + +NDIS_STATUS +tapSetMulticastList(__in PTAP_ADAPTER_CONTEXT Adapter, __in PNDIS_OID_REQUEST OidRequest) { + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + // + // Initialize. + // + OidRequest->DATA.SET_INFORMATION.BytesNeeded = MACADDR_SIZE; + OidRequest->DATA.SET_INFORMATION.BytesRead = + OidRequest->DATA.SET_INFORMATION.InformationBufferLength; + + do { + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength % MACADDR_SIZE) { + status = NDIS_STATUS_INVALID_LENGTH; + break; + } + + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength > + (TAP_MAX_MCAST_LIST * MACADDR_SIZE)) { + status = NDIS_STATUS_MULTICAST_FULL; + OidRequest->DATA.SET_INFORMATION.BytesNeeded = TAP_MAX_MCAST_LIST * MACADDR_SIZE; + break; + } + + // BUGBUG!!! Is lock needed??? If so, use NDIS_RW_LOCK. Also apply to packet filter. + + NdisZeroMemory(Adapter->MCList, TAP_MAX_MCAST_LIST * MACADDR_SIZE); + + NdisMoveMemory(Adapter->MCList, OidRequest->DATA.SET_INFORMATION.InformationBuffer, + OidRequest->DATA.SET_INFORMATION.InformationBufferLength); + + Adapter->ulMCListSize = OidRequest->DATA.SET_INFORMATION.InformationBufferLength / MACADDR_SIZE; + + } while (FALSE); + return status; +} + +NDIS_STATUS +tapSetPacketFilter(__in PTAP_ADAPTER_CONTEXT Adapter, __in ULONG PacketFilter) { + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + // any bits not supported? + if (PacketFilter & ~(TAP_SUPPORTED_FILTERS)) { + DEBUGP(("[TAP] Unsupported packet filter: 0x%08x\n", PacketFilter)); + status = NDIS_STATUS_NOT_SUPPORTED; + } else { + // Any actual filtering changes? + if (PacketFilter != Adapter->PacketFilter) { + // + // Change the filtering modes on hardware + // + + // Save the new packet filter value + Adapter->PacketFilter = PacketFilter; + } + } + + return status; +} + +NDIS_STATUS +AdapterSetPowerD0(__in PTAP_ADAPTER_CONTEXT Adapter) +/*++ +Routine Description: + + NIC power has been restored to the working power state (D0). + Prepare the NIC for normal operation: + - Restore hardware context (packet filters, multicast addresses, MAC address, etc.) + - Enable interrupts and the NIC's DMA engine. + +Arguments: + + Adapter - Pointer to adapter block + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DEBUGP(("[TAP] PowerState: Fully powered\n")); + + // Start data path... + + return status; +} + +NDIS_STATUS +AdapterSetPowerLow(__in PTAP_ADAPTER_CONTEXT Adapter, __in NDIS_DEVICE_POWER_STATE PowerState) +/*++ +Routine Description: + + The NIC is about to be transitioned to a low power state. + Prepare the NIC for the sleeping state: + - Disable interrupts and the NIC's DMA engine, cancel timers. + - Save any hardware context that the NIC cannot preserve in + a sleeping state (packet filters, multicast addresses, + the current MAC address, etc.) + A miniport driver cannot access the NIC hardware after + the NIC has been set to the D3 state by the bus driver. + + Miniport drivers NDIS v6.30 and above + Do NOT wait for NDIS to return the ownership of all + NBLs from outstanding receive indications + Retain ownership of all the receive descriptors and + packet buffers previously owned by the hardware. + +Arguments: + + Adapter - Pointer to adapter block + PowerState - New power state + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DEBUGP(("[TAP] PowerState: Low-power\n")); + + // + // Miniport drivers NDIS v6.20 and below are + // paused prior the low power transition + // + + // Check for paused state... + // Verify data path stopped... + + return status; +} + +NDIS_STATUS +tapSetInformation(__in PTAP_ADAPTER_CONTEXT Adapter, __in PNDIS_OID_REQUEST OidRequest) +/*++ + +Routine Description: + + Helper function to perform a set OID request + +Arguments: + + Adapter - + NdisSetRequest - The OID to set + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DBG_PRINT_OID_NAME(OidRequest->DATA.SET_INFORMATION.Oid); + + switch (OidRequest->DATA.SET_INFORMATION.Oid) { + case OID_802_3_MULTICAST_LIST: + // + // Set the multicast address list on the NIC for packet reception. + // The NIC driver can set a limit on the number of multicast + // addresses bound protocol drivers can enable simultaneously. + // NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver + // exceeds this limit or if it specifies an invalid multicast + // address. + // + status = tapSetMulticastList(Adapter, OidRequest); + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + // + // A protocol driver can set a suggested value for the number + // of bytes to be used in its binding; however, the underlying + // NIC driver is never required to limit its indications to + // the value set. + // + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG)) { + OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG); + status = NDIS_STATUS_INVALID_LENGTH; + break; + } + + Adapter->ulLookahead = *(PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer; + + OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG); + status = NDIS_STATUS_SUCCESS; + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + // + // Program the hardware to indicate the packets + // of certain filter types. + // + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG)) { + OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG); + status = NDIS_STATUS_INVALID_LENGTH; + break; + } + + OidRequest->DATA.SET_INFORMATION.BytesRead = + OidRequest->DATA.SET_INFORMATION.InformationBufferLength; + + status = tapSetPacketFilter(Adapter, + *((PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer)); + + break; + + case OID_PNP_SET_POWER: { + // Sanity check. + if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength < + sizeof(NDIS_DEVICE_POWER_STATE)) { + status = NDIS_STATUS_INVALID_LENGTH; + } else { + NDIS_DEVICE_POWER_STATE PowerState; + + PowerState = + *(PNDIS_DEVICE_POWER_STATE UNALIGNED)OidRequest->DATA.SET_INFORMATION.InformationBuffer; + OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE); + + if (PowerState < NdisDeviceStateD0 || PowerState > NdisDeviceStateD3) { + status = NDIS_STATUS_INVALID_DATA; + } else { + Adapter->CurrentPowerState = PowerState; + + if (PowerState == NdisDeviceStateD0) { + status = AdapterSetPowerD0(Adapter); + } else { + status = AdapterSetPowerLow(Adapter, PowerState); + } + } + } + } break; + +#if (NDIS_SUPPORT_NDIS61) + case OID_PNP_ADD_WAKE_UP_PATTERN: + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + case OID_PNP_ENABLE_WAKE_UP: +#endif + ASSERT(!"NIC does not support wake on LAN OIDs"); + default: + // + // The entry point may by used by other requests + // + status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + return status; +} + +NDIS_STATUS +tapQueryInformation(__in PTAP_ADAPTER_CONTEXT Adapter, __in PNDIS_OID_REQUEST OidRequest) +/*++ + +Routine Description: + + Helper function to perform a query OID request + +Arguments: + + Adapter - + OidRequest - The OID request that is being queried + +Return Value: + + NDIS_STATUS + +--*/ +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + NDIS_MEDIUM Medium = TAP_MEDIUM_TYPE; + NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; + UCHAR VendorDesc[] = TAP_VENDOR_DESC; + ULONG ulInfo; + USHORT usInfo; + ULONG64 ulInfo64; + + // Default to returning the ULONG value + PVOID pInfo = NULL; + ULONG ulInfoLen = sizeof(ulInfo); + + // ATTENTION!!! Ignore OIDs to noisy to print... + if ((OidRequest->DATA.QUERY_INFORMATION.Oid != OID_GEN_STATISTICS) && + (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP4_OFFLOAD_STATS) && + (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP6_OFFLOAD_STATS)) { + DBG_PRINT_OID_NAME(OidRequest->DATA.QUERY_INFORMATION.Oid); + } + + // Dispatch based on object identifier (OID). + switch (OidRequest->DATA.QUERY_INFORMATION.Oid) { + case OID_GEN_HARDWARE_STATUS: + // + // Specify the current hardware status of the underlying NIC as + // one of the following NDIS_HARDWARE_STATUS-type values. + // + pInfo = (PVOID)&HardwareStatus; + ulInfoLen = sizeof(NDIS_HARDWARE_STATUS); + break; + + case OID_802_3_PERMANENT_ADDRESS: + // + // Return the MAC address of the NIC burnt in the hardware. + // + pInfo = Adapter->PermanentAddress; + ulInfoLen = MACADDR_SIZE; + break; + + case OID_802_3_CURRENT_ADDRESS: + // + // Return the MAC address the NIC is currently programmed to + // use. Note that this address could be different from the + // permananent address as the user can override using + // registry. Read NdisReadNetworkAddress doc for more info. + // + pInfo = Adapter->CurrentAddress; + ulInfoLen = MACADDR_SIZE; + break; + + case OID_GEN_MEDIA_SUPPORTED: + // + // Return an array of media that are supported by the miniport. + // This miniport only supports one medium (Ethernet), so the OID + // returns identical results to OID_GEN_MEDIA_IN_USE. + // + + __fallthrough; + + case OID_GEN_MEDIA_IN_USE: + // + // Return an array of media that are currently in use by the + // miniport. This array should be a subset of the array returned + // by OID_GEN_MEDIA_SUPPORTED. + // + pInfo = &Medium; + ulInfoLen = sizeof(Medium); + break; + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + // + // Specify the maximum total packet length, in bytes, the NIC + // supports including the header. A protocol driver might use + // this returned length as a gauge to determine the maximum + // size packet that a NIC driver could forward to the + // protocol driver. The miniport driver must never indicate + // up to the bound protocol driver packets received over the + // network that are longer than the packet size specified by + // OID_GEN_MAXIMUM_TOTAL_SIZE. + // + + __fallthrough; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + // + // The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum + // number of bytes that a single net packet occupies in the + // transmit buffer space of the NIC. In our case, the transmit + // block size is identical to its maximum packet size. + __fallthrough; + + case OID_GEN_RECEIVE_BLOCK_SIZE: + // + // The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of + // storage, in bytes, that a single packet occupies in the receive + // buffer space of the NIC. + // + ulInfo = (ULONG)TAP_MAX_FRAME_SIZE; + pInfo = &ulInfo; + break; + + case OID_GEN_INTERRUPT_MODERATION: { + PNDIS_INTERRUPT_MODERATION_PARAMETERS moderationParams = + (PNDIS_INTERRUPT_MODERATION_PARAMETERS) + OidRequest->DATA.QUERY_INFORMATION.InformationBuffer; + + moderationParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + moderationParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + moderationParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + moderationParams->Flags = 0; + moderationParams->InterruptModeration = NdisInterruptModerationNotSupported; + ulInfoLen = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1; + } break; + + case OID_PNP_QUERY_POWER: + // Simply succeed this. + break; + + case OID_GEN_VENDOR_ID: + // + // Specify a three-byte IEEE-registered vendor code, followed + // by a single byte that the vendor assigns to identify a + // particular NIC. The IEEE code uniquely identifies the vendor + // and is the same as the three bytes appearing at the beginning + // of the NIC hardware address. Vendors without an IEEE-registered + // code should use the value 0xFFFFFF. + // + + ulInfo = TAP_VENDOR_ID; + pInfo = &ulInfo; + break; + + case OID_GEN_VENDOR_DESCRIPTION: + // + // Specify a zero-terminated string describing the NIC vendor. + // + pInfo = VendorDesc; + ulInfoLen = sizeof(VendorDesc); + break; + + case OID_GEN_VENDOR_DRIVER_VERSION: + // + // Specify the vendor-assigned version number of the NIC driver. + // The low-order half of the return value specifies the minor + // version; the high-order half specifies the major version. + // + + ulInfo = TAP_DRIVER_VENDOR_VERSION; + pInfo = &ulInfo; + break; + + case OID_GEN_DRIVER_VERSION: + // + // Specify the NDIS version in use by the NIC driver. The high + // byte is the major version number; the low byte is the minor + // version number. + // + usInfo = (USHORT)(TAP_NDIS_MAJOR_VERSION << 8) + TAP_NDIS_MINOR_VERSION; + pInfo = (PVOID)&usInfo; + ulInfoLen = sizeof(USHORT); + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + // + // The maximum number of multicast addresses the NIC driver + // can manage. This list is global for all protocols bound + // to (or above) the NIC. Consequently, a protocol can receive + // NDIS_STATUS_MULTICAST_FULL from the NIC driver when + // attempting to set the multicast address list, even if + // the number of elements in the given list is less than + // the number originally returned for this query. + // + + ulInfo = TAP_MAX_MCAST_LIST; + pInfo = &ulInfo; + break; + + case OID_GEN_XMIT_ERROR: + ulInfo = + (ULONG)(Adapter->TxAbortExcessCollisions + Adapter->TxDmaUnderrun + Adapter->TxLostCRS + + Adapter->TxLateCollisions + Adapter->TransmitFailuresOther); + pInfo = &ulInfo; + break; + + case OID_GEN_RCV_ERROR: + ulInfo = (ULONG)(Adapter->RxCrcErrors + Adapter->RxAlignmentErrors + + Adapter->RxDmaOverrunErrors + Adapter->RxRuntErrors); + pInfo = &ulInfo; + break; + + case OID_GEN_RCV_DISCARDS: + ulInfo = (ULONG)Adapter->RxResourceErrors; + pInfo = &ulInfo; + break; + + case OID_GEN_RCV_NO_BUFFER: + ulInfo = (ULONG)Adapter->RxResourceErrors; + pInfo = &ulInfo; + break; + + case OID_GEN_XMIT_OK: + ulInfo64 = + Adapter->FramesTxBroadcast + Adapter->FramesTxMulticast + Adapter->FramesTxDirected; + pInfo = &ulInfo64; + if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) || + OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0) { + ulInfoLen = sizeof(ULONG64); + } else { + ulInfoLen = sizeof(ULONG); + } + + // We should always report that only 8 bytes are required to keep ndistest happy + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); + break; + + case OID_GEN_RCV_OK: + ulInfo64 = + Adapter->FramesRxBroadcast + Adapter->FramesRxMulticast + Adapter->FramesRxDirected; + + pInfo = &ulInfo64; + + if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) || + OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0) { + ulInfoLen = sizeof(ULONG64); + } else { + ulInfoLen = sizeof(ULONG); + } + + // We should always report that only 8 bytes are required to keep ndistest happy + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64); + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + + ulInfo = Adapter->RxAlignmentErrors; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_ONE_COLLISION: + + ulInfo = Adapter->OneRetry; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_MORE_COLLISIONS: + + ulInfo = Adapter->MoreThanOneRetry; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_DEFERRED: + + ulInfo = Adapter->TxOKButDeferred; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_MAX_COLLISIONS: + + ulInfo = Adapter->TxAbortExcessCollisions; + pInfo = &ulInfo; + break; + + case OID_802_3_RCV_OVERRUN: + + ulInfo = Adapter->RxDmaOverrunErrors; + pInfo = &ulInfo; + break; + + case OID_802_3_XMIT_UNDERRUN: + + ulInfo = Adapter->TxDmaUnderrun; + pInfo = &ulInfo; + break; + + case OID_GEN_STATISTICS: + + if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < + sizeof(NDIS_STATISTICS_INFO)) { + status = NDIS_STATUS_INVALID_LENGTH; + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(NDIS_STATISTICS_INFO); + break; + } else { + PNDIS_STATISTICS_INFO Statistics = + (PNDIS_STATISTICS_INFO)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer; + + { C_ASSERT(sizeof(NDIS_STATISTICS_INFO) >= NDIS_SIZEOF_STATISTICS_INFO_REVISION_1); } + Statistics->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; + Statistics->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; + Statistics->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1; + + Statistics->SupportedStatistics = TAP_SUPPORTED_STATISTICS; + + /* Bytes in */ + Statistics->ifHCInOctets = + Adapter->BytesRxDirected + Adapter->BytesRxMulticast + Adapter->BytesRxBroadcast; + + Statistics->ifHCInUcastOctets = Adapter->BytesRxDirected; + + Statistics->ifHCInMulticastOctets = Adapter->BytesRxMulticast; + + Statistics->ifHCInBroadcastOctets = Adapter->BytesRxBroadcast; + + /* Packets in */ + Statistics->ifHCInUcastPkts = Adapter->FramesRxDirected; + + Statistics->ifHCInMulticastPkts = Adapter->FramesRxMulticast; + + Statistics->ifHCInBroadcastPkts = Adapter->FramesRxBroadcast; + + /* Errors in */ + Statistics->ifInErrors = Adapter->RxCrcErrors + Adapter->RxAlignmentErrors + + Adapter->RxDmaOverrunErrors + Adapter->RxRuntErrors; + + Statistics->ifInDiscards = Adapter->RxResourceErrors; + + /* Bytes out */ + Statistics->ifHCOutOctets = + Adapter->BytesTxDirected + Adapter->BytesTxMulticast + Adapter->BytesTxBroadcast; + + Statistics->ifHCOutUcastOctets = Adapter->BytesTxDirected; + + Statistics->ifHCOutMulticastOctets = Adapter->BytesTxMulticast; + + Statistics->ifHCOutBroadcastOctets = Adapter->BytesTxBroadcast; + + /* Packets out */ + Statistics->ifHCOutUcastPkts = Adapter->FramesTxDirected; + + Statistics->ifHCOutMulticastPkts = Adapter->FramesTxMulticast; + + Statistics->ifHCOutBroadcastPkts = Adapter->FramesTxBroadcast; + + /* Errors out */ + Statistics->ifOutErrors = Adapter->TxAbortExcessCollisions + Adapter->TxDmaUnderrun + + Adapter->TxLostCRS + Adapter->TxLateCollisions + + Adapter->TransmitFailuresOther; + + Statistics->ifOutDiscards = 0ULL; + + ulInfoLen = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1; + } + + break; + + // TODO: Inplement these query information requests. + case OID_GEN_RECEIVE_BUFFER_SPACE: + case OID_GEN_MAXIMUM_SEND_PACKETS: + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_802_3_XMIT_LATE_COLLISIONS: + + default: + // + // The entry point may by used by other requests + // + status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if (status == NDIS_STATUS_SUCCESS) { + ASSERT(ulInfoLen > 0); + + if (ulInfoLen <= OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength) { + if (pInfo) { + // Copy result into InformationBuffer + NdisMoveMemory(OidRequest->DATA.QUERY_INFORMATION.InformationBuffer, pInfo, ulInfoLen); + } + + OidRequest->DATA.QUERY_INFORMATION.BytesWritten = ulInfoLen; + } else { + // too short + OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = ulInfoLen; + status = NDIS_STATUS_BUFFER_TOO_SHORT; + } + } + + return status; +} + +NDIS_STATUS +AdapterOidRequest(__in NDIS_HANDLE MiniportAdapterContext, __in PNDIS_OID_REQUEST OidRequest) +/*++ + +Routine Description: + + Entry point called by NDIS to get or set the value of a specified OID. + +Arguments: + + MiniportAdapterContext - Our adapter handle + NdisRequest - The OID request to handle + +Return Value: + + Return code from the NdisRequest below. + +--*/ +{ + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + NDIS_STATUS status; + + // Dispatch based on request type. + switch (OidRequest->RequestType) { + case NdisRequestSetInformation: + status = tapSetInformation(adapter, OidRequest); + break; + + case NdisRequestQueryInformation: + case NdisRequestQueryStatistics: + status = tapQueryInformation(adapter, OidRequest); + break; + + case NdisRequestMethod: // TAP doesn't need to respond to this request type. + default: + // + // The entry point may by used by other requests + // + status = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + return status; +} + +VOID AdapterCancelOidRequest(__in NDIS_HANDLE MiniportAdapterContext, __in PVOID RequestId) { + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + + UNREFERENCED_PARAMETER(RequestId); + + // + // This miniport sample does not pend any OID requests, so we don't have + // to worry about cancelling them. + // +} diff --git a/third_party/tap-windows6/src/proto.h b/third_party/tap-windows6/src/proto.h new file mode 100644 index 00000000000..2e692c171ea --- /dev/null +++ b/third_party/tap-windows6/src/proto.h @@ -0,0 +1,220 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//============================================================ +// MAC address, Ethernet header, and ARP +//============================================================ + +#pragma pack(1) + +#define IP_HEADER_SIZE 20 +#define IPV6_HEADER_SIZE 40 + +#define MACADDR_SIZE 6 +typedef unsigned char MACADDR[MACADDR_SIZE]; + +typedef unsigned long IPADDR; +typedef unsigned char IPV6ADDR[16]; + +//----------------- +// Ethernet address +//----------------- + +typedef struct { + MACADDR addr; +} ETH_ADDR; + +typedef struct { + ETH_ADDR list[TAP_MAX_MCAST_LIST]; +} MC_LIST; + +// BUGBUG!!! Consider using ststem defines in netiodef.h!!! + +//---------------- +// Ethernet header +//---------------- +typedef struct { + MACADDR dest; /* destination eth addr */ + MACADDR src; /* source ether addr */ + USHORT proto; /* packet type ID field */ +} ETH_HEADER, *PETH_HEADER; + +//---------------- +// ARP packet +//---------------- + +typedef struct { + MACADDR m_MAC_Destination; // Reverse these two + MACADDR m_MAC_Source; // to answer ARP requests + USHORT m_Proto; // 0x0806 + +#define MAC_ADDR_TYPE 0x0001 + USHORT m_MAC_AddressType; // 0x0001 + + USHORT m_PROTO_AddressType; // 0x0800 + UCHAR m_MAC_AddressSize; // 0x06 + UCHAR m_PROTO_AddressSize; // 0x04 + +#define ARP_REQUEST 0x0001 +#define ARP_REPLY 0x0002 + USHORT m_ARP_Operation; // 0x0001 for ARP request, 0x0002 for ARP reply + + MACADDR m_ARP_MAC_Source; + IPADDR m_ARP_IP_Source; + MACADDR m_ARP_MAC_Destination; + IPADDR m_ARP_IP_Destination; +} ARP_PACKET, *PARP_PACKET; + +//---------- +// IP Header +//---------- + +typedef struct { +#define IPH_GET_VER(v) (((v) >> 4) & 0x0F) +#define IPH_GET_LEN(v) (((v)&0x0F) << 2) + UCHAR version_len; + + UCHAR tos; + USHORT tot_len; + USHORT id; + +#define IP_OFFMASK 0x1fff + USHORT frag_off; + + UCHAR ttl; + +#define IPPROTO_UDP 17 /* UDP protocol */ +#define IPPROTO_TCP 6 /* TCP protocol */ +#define IPPROTO_ICMP 1 /* ICMP protocol */ +#define IPPROTO_IGMP 2 /* IGMP protocol */ + UCHAR protocol; + + USHORT check; + ULONG saddr; + ULONG daddr; + /* The options start here. */ +} IPHDR; + +//----------- +// UDP header +//----------- + +typedef struct { + USHORT source; + USHORT dest; + USHORT len; + USHORT check; +} UDPHDR; + +//-------------------------- +// TCP header, per RFC 793. +//-------------------------- + +typedef struct { + USHORT source; /* source port */ + USHORT dest; /* destination port */ + ULONG seq; /* sequence number */ + ULONG ack_seq; /* acknowledgement number */ + +#define TCPH_GET_DOFF(d) (((d)&0xF0) >> 2) + UCHAR doff_res; + +#define TCPH_FIN_MASK (1 << 0) +#define TCPH_SYN_MASK (1 << 1) +#define TCPH_RST_MASK (1 << 2) +#define TCPH_PSH_MASK (1 << 3) +#define TCPH_ACK_MASK (1 << 4) +#define TCPH_URG_MASK (1 << 5) +#define TCPH_ECE_MASK (1 << 6) +#define TCPH_CWR_MASK (1 << 7) + UCHAR flags; + + USHORT window; + USHORT check; + USHORT urg_ptr; +} TCPHDR; + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 + +//------------ +// IPv6 Header +//------------ + +typedef struct { + UCHAR version_prio; + UCHAR flow_lbl[3]; + USHORT payload_len; +#define IPPROTO_ICMPV6 0x3a /* ICMP protocol v6 */ + UCHAR nexthdr; + UCHAR hop_limit; + IPV6ADDR saddr; + IPV6ADDR daddr; +} IPV6HDR; + +//-------------------------------------------- +// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861) +//-------------------------------------------- + +// Neighbor Solictiation - RFC 4861, 4.3 +// (this is just the ICMPv6 part of the packet) +typedef struct { + UCHAR type; +#define ICMPV6_TYPE_NS 135 // neighbour solicitation + UCHAR code; +#define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA + USHORT checksum; + ULONG reserved; + IPV6ADDR target_addr; +} ICMPV6_NS; + +// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1 +// (this is just the ICMPv6 payload) +typedef struct { + UCHAR type; +#define ICMPV6_TYPE_NA 136 // neighbour advertisement + UCHAR code; +#define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA + USHORT checksum; + UCHAR rso_bits; // Router(0), Solicited(2), Ovrrd(4) + UCHAR reserved[3]; + IPV6ADDR target_addr; + // always include "Target Link-layer Address" option (RFC 4861 4.6.1) + UCHAR opt_type; +#define ICMPV6_OPTION_TLLA 2 + UCHAR opt_length; +#define ICMPV6_LENGTH_TLLA 1 // multiplied by 8 -> 1 = 8 bytes + MACADDR target_macaddr; +} ICMPV6_NA; + +// this is the complete packet with Ethernet and IPv6 headers +typedef struct { + ETH_HEADER eth; + IPV6HDR ipv6; + ICMPV6_NA icmpv6; +} ICMPV6_NA_PKT; + +#pragma pack() diff --git a/third_party/tap-windows6/src/prototypes.h b/third_party/tap-windows6/src/prototypes.h new file mode 100644 index 00000000000..29a315e0f85 --- /dev/null +++ b/third_party/tap-windows6/src/prototypes.h @@ -0,0 +1,64 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TAP_PROTOTYPES_DEFINED +#define TAP_PROTOTYPES_DEFINED + +DRIVER_INITIALIZE DriverEntry; + +// VOID AdapterFreeResources +// ( +// TapAdapterPointer p_Adapter +// ); +// + +// +// NTSTATUS TapDeviceHook +// ( +// IN PDEVICE_OBJECT p_DeviceObject, +// IN PIRP p_IRP +// ); +// + +NDIS_STATUS +CreateTapDevice(__in PTAP_ADAPTER_CONTEXT Adapter); + +VOID DestroyTapDevice(__in PTAP_ADAPTER_CONTEXT Adapter); + +// Flush the pending send TAP packet queue. +VOID tapFlushSendPacketQueue(__in PTAP_ADAPTER_CONTEXT Adapter); + +VOID IndicateReceivePacket(__in PTAP_ADAPTER_CONTEXT Adapter, __in PUCHAR packetData, + __in const unsigned int packetLength); + +BOOLEAN +ProcessDHCP(__in PTAP_ADAPTER_CONTEXT Adapter, __in const ETH_HEADER *eth, __in const IPHDR *ip, + __in const UDPHDR *udp, __in const DHCP *dhcp, __in int optlen); + +BOOLEAN +ProcessARP(__in PTAP_ADAPTER_CONTEXT Adapter, __in const PARP_PACKET src, + __in const IPADDR adapter_ip, __in const IPADDR ip_network, __in const IPADDR ip_netmask, + __in const MACADDR mac); + +#endif diff --git a/third_party/tap-windows6/src/resource.rc b/third_party/tap-windows6/src/resource.rc new file mode 100644 index 00000000000..3c40d030e36 --- /dev/null +++ b/third_party/tap-windows6/src/resource.rc @@ -0,0 +1,62 @@ +#include +#include + +#include "config.h" + +#undef VER_PRODUCTVERSION +#undef VER_PRODUCTVERSION_STR +#undef VER_COMPANYNAME_STR +#undef VER_PRODUCTNAME_STR + +/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR + * and VER_INTERNALNAME_STR must be defined before including COMMON.VER + * The strings don't need a '\0', since common.ver has them. + */ + +#define VER_FILETYPE VFT_DRV +/* possible values: VFT_UNKNOWN + VFT_APP + VFT_DLL + VFT_DRV + VFT_FONT + VFT_VXD + VFT_STATIC_LIB +*/ +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +/* possible values VFT2_UNKNOWN + VFT2_DRV_PRINTER + VFT2_DRV_KEYBOARD + VFT2_DRV_LANGUAGE + VFT2_DRV_DISPLAY + VFT2_DRV_MOUSE + VFT2_DRV_NETWORK + VFT2_DRV_SYSTEM + VFT2_DRV_INSTALLABLE + VFT2_DRV_SOUND + VFT2_DRV_COMM +*/ + +#define VER_COMPANYNAME_STR "The OpenVPN Project" +#define VER_FILEDESCRIPTION_STR "TAP-Windows Virtual Network Driver (NDIS 6.0)" +#define VER_ORIGINALFILENAME_STR PRODUCT_TAP_WIN_COMPONENT_ID ".sys" +#define VER_LEGALCOPYRIGHT_YEARS "2003-2018" +#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/third_party/tap-windows6/src/rxpath.c b/third_party/tap-windows6/src/rxpath.c new file mode 100644 index 00000000000..3e76f584755 --- /dev/null +++ b/third_party/tap-windows6/src/rxpath.c @@ -0,0 +1,552 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +//====================================================================== +// TAP Receive Path Support +//====================================================================== + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, TapDeviceWrite) +#endif // ALLOC_PRAGMA + +//=============================================================== +// Used in cases where internally generated packets such as +// ARP or DHCP replies must be returned to the kernel, to be +// seen as an incoming packet "arriving" on the interface. +//=============================================================== + +VOID IndicateReceivePacket(__in PTAP_ADAPTER_CONTEXT Adapter, __in PUCHAR packetData, + __in const unsigned int packetLength) { + PUCHAR injectBuffer; + + // + // Handle miniport Pause + // --------------------- + // NDIS 6 miniports implement a temporary "Pause" state normally followed + // by the Restart. While in the Pause state it is forbidden for the miniport + // to indicate receive NBLs. + // + // That is: The device interface may be "up", but the NDIS miniport send/receive + // interface may be temporarily "down". + // + // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path + // the code below will simply ignore inject packets passed to the driver while + // the miniport is in the Paused state. + // + // The correct implementation is to go ahead and build the NBLs corresponding + // to the inject packet - but queue them. When Restart is entered the + // queued NBLs would be dequeued and indicated to the host. + // + if (tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS) { + DEBUGP(("[%s] Lying send in IndicateReceivePacket while adapter paused\n", + MINIPORT_INSTANCE_ID(Adapter))); + + return; + } + + // Allocate flat buffer for packet data. + injectBuffer = (PUCHAR)NdisAllocateMemoryWithTagPriority( + Adapter->MiniportAdapterHandle, packetLength, TAP_RX_INJECT_BUFFER_TAG, NormalPoolPriority); + + if (injectBuffer) { + PMDL mdl; + + // Copy packet data to flat buffer. + NdisMoveMemory(injectBuffer, packetData, packetLength); + + // Allocate MDL for flat buffer. + mdl = NdisAllocateMdl(Adapter->MiniportAdapterHandle, injectBuffer, packetLength); + + if (mdl) { + PNET_BUFFER_LIST netBufferList; + + mdl->Next = NULL; // No next MDL + + // Allocate the NBL and NB. Link MDL chain to NB. + netBufferList = NdisAllocateNetBufferAndNetBufferList(Adapter->ReceiveNblPool, + 0, // ContextSize + 0, // ContextBackFill + mdl, // MDL chain + 0, packetLength); + + if (netBufferList != NULL) { + ULONG receiveFlags = 0; + LONG nblCount; + + NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL + + if (KeGetCurrentIrql() == DISPATCH_LEVEL) { + receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL; + } + + // Set flag indicating that this is an injected packet + TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); + TAP_RX_NBL_FLAG_SET(netBufferList, TAP_RX_NBL_FLAGS_IS_INJECTED); + + netBufferList->MiniportReserved[0] = NULL; + netBufferList->MiniportReserved[1] = NULL; + + // Increment in-flight receive NBL count. + nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0); + + netBufferList->SourceHandle = Adapter->MiniportAdapterHandle; + + // + // Indicate the packet + // ------------------- + // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length + // contains the complete packet including Ethernet header and payload. + // + NdisMIndicateReceiveNetBufferLists(Adapter->MiniportAdapterHandle, netBufferList, + NDIS_DEFAULT_PORT_NUMBER, + 1, // NumberOfNetBufferLists + receiveFlags); + + return; + } else { + DEBUGP(("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n", + MINIPORT_INSTANCE_ID(Adapter))); + NOTE_ERROR(); + + NdisFreeMdl(mdl); + NdisFreeMemory(injectBuffer, 0, 0); + } + } else { + DEBUGP(("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n", + MINIPORT_INSTANCE_ID(Adapter))); + NOTE_ERROR(); + + NdisFreeMemory(injectBuffer, 0, 0); + } + } else { + DEBUGP(("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n", + MINIPORT_INSTANCE_ID(Adapter))); + NOTE_ERROR(); + } +} + +VOID tapCompleteIrpAndFreeReceiveNetBufferList(__in PTAP_ADAPTER_CONTEXT Adapter, + __in PNET_BUFFER_LIST + NetBufferList, // Only one NB here... + __in NTSTATUS IoCompletionStatus) { + PIRP irp; + ULONG frameType, netBufferCount, byteCount; + LONG nblCount; + + // Fetch NB frame type. + frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList)); + + // Fetch statistics for all NBs linked to the NB. + netBufferCount = tapGetNetBufferCountsFromNetBufferList(NetBufferList, &byteCount); + + // Update statistics by frame type + if (IoCompletionStatus == STATUS_SUCCESS) { + switch (frameType) { + case NDIS_PACKET_TYPE_DIRECTED: + Adapter->FramesRxDirected += netBufferCount; + Adapter->BytesRxDirected += byteCount; + break; + + case NDIS_PACKET_TYPE_BROADCAST: + Adapter->FramesRxBroadcast += netBufferCount; + Adapter->BytesRxBroadcast += byteCount; + break; + + case NDIS_PACKET_TYPE_MULTICAST: + Adapter->FramesRxMulticast += netBufferCount; + Adapter->BytesRxMulticast += byteCount; + break; + + default: + ASSERT(FALSE); + break; + } + } + + // + // Handle P2P Packet + // ----------------- + // Free MDL allocated for P2P Ethernet header. + // + if (TAP_RX_NBL_FLAG_TEST(NetBufferList, TAP_RX_NBL_FLAGS_IS_P2P)) { + PNET_BUFFER netBuffer; + PMDL mdl; + + netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + mdl = NET_BUFFER_FIRST_MDL(netBuffer); + mdl->Next = NULL; + + NdisFreeMdl(mdl); + } + + // + // Handle Injected Packet + // ----------------------- + // Free MDL and data buffer allocated for injected packet. + // + if (TAP_RX_NBL_FLAG_TEST(NetBufferList, TAP_RX_NBL_FLAGS_IS_INJECTED)) { + PNET_BUFFER netBuffer; + PMDL mdl; + PUCHAR injectBuffer; + + netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList); + mdl = NET_BUFFER_FIRST_MDL(netBuffer); + + injectBuffer = (PUCHAR)MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority); + + if (injectBuffer) { + NdisFreeMemory(injectBuffer, 0, 0); + } + + NdisFreeMdl(mdl); + } + + // + // Complete the IRP + // + irp = (PIRP)NetBufferList->MiniportReserved[0]; + + if (irp) { + irp->IoStatus.Status = IoCompletionStatus; + IoCompleteRequest(irp, IO_NO_INCREMENT); + } + + // Decrement in-flight receive NBL count. + nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount); + ASSERT(nblCount >= 0); + if (0 == nblCount) { + NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent); + } + + // Free the NBL + NdisFreeNetBufferList(NetBufferList); +} + +VOID AdapterReturnNetBufferLists(__in NDIS_HANDLE MiniportAdapterContext, + __in PNET_BUFFER_LIST NetBufferLists, __in ULONG ReturnFlags) { + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + PNET_BUFFER_LIST currentNbl, nextNbl; + + UNREFERENCED_PARAMETER(ReturnFlags); + + // + // Process each NBL individually + // + currentNbl = NetBufferLists; + while (currentNbl) { + PNET_BUFFER_LIST nextNbl; + + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + NET_BUFFER_LIST_NEXT_NBL(currentNbl) = NULL; + + // Complete write IRP and free NBL and associated resources. + tapCompleteIrpAndFreeReceiveNetBufferList(adapter, currentNbl, STATUS_SUCCESS); + + // Move to next NBL + currentNbl = nextNbl; + } +} + +// IRP_MJ_WRITE callback. +NTSTATUS +TapDeviceWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp) { + NTSTATUS ntStatus = STATUS_SUCCESS; // Assume success + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + ULONG dataLength; + + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT)(irpSp->FileObject)->FsContext; + + ASSERT(adapter); + + // + // Sanity checks on state variables + // + if (!tapAdapterReadAndWriteReady(adapter)) { + // DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n", + // MINIPORT_INSTANCE_ID (adapter))); + // NOTE_ERROR(); + + Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // Save IRP-accessible copy of buffer length + Irp->IoStatus.Information = irpSp->Parameters.Write.Length; + + if (Irp->MdlAddress == NULL) { + DEBUGP(("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID(adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // + // Try to get a virtual address for the MDL. + // + NdisQueryMdl(Irp->MdlAddress, &Irp->AssociatedIrp.SystemBuffer, &dataLength, NormalPagePriority); + + if (Irp->AssociatedIrp.SystemBuffer == NULL) { + DEBUGP(("[%s] Could not map address in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID(adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + ASSERT(dataLength == irpSp->Parameters.Write.Length); + + Irp->IoStatus.Information = irpSp->Parameters.Write.Length; + + // + // Handle miniport Pause + // --------------------- + // NDIS 6 miniports implement a temporary "Pause" state normally followed + // by the Restart. While in the Pause state it is forbidden for the miniport + // to indicate receive NBLs. + // + // That is: The device interface may be "up", but the NDIS miniport send/receive + // interface may be temporarily "down". + // + // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path + // the code below will perform a "lying send" for write IRPs passed to the + // driver while the miniport is in the Paused state. + // + // The correct implementation is to go ahead and build the NBLs corresponding + // to the user-mode write - but queue them. When Restart is entered the + // queued NBLs would be dequeued and indicated to the host. + // + if (tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS) { + if (!adapter->m_tun && ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)) { + PNET_BUFFER_LIST netBufferList; + + DUMP_PACKET("IRP_MJ_WRITE ETH", (unsigned char *)Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify((unsigned char *)Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length, FALSE, "RX", &adapter->m_RxTrunc); +#endif + (Irp->MdlAddress)->Next = NULL; // No next MDL + + // Allocate the NBL and NB. Link MDL chain to NB. + netBufferList = NdisAllocateNetBufferAndNetBufferList(adapter->ReceiveNblPool, + 0, // ContextSize + 0, // ContextBackFill + Irp->MdlAddress, // MDL chain + 0, dataLength); + + if (netBufferList != NULL) { + LONG nblCount; + + NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL + + // Stash IRP pointer in NBL MiniportReserved[0] field. + netBufferList->MiniportReserved[0] = Irp; + netBufferList->MiniportReserved[1] = NULL; + + // This IRP is pended. + IoMarkIrpPending(Irp); + + // This IRP cannot be cancelled while in-flight. + IoSetCancelRoutine(Irp, NULL); + + TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); + + // Increment in-flight receive NBL count. + nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0); + + // + // Indicate the packet + // ------------------- + // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length + // contains the complete packet including Ethernet header and payload. + // + NdisMIndicateReceiveNetBufferLists(adapter->MiniportAdapterHandle, netBufferList, + NDIS_DEFAULT_PORT_NUMBER, + 1, // NumberOfNetBufferLists + 0 // ReceiveFlags + ); + + ntStatus = STATUS_PENDING; + } else { + DEBUGP(("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", + MINIPORT_INSTANCE_ID(adapter))); + NOTE_ERROR(); + + // Fail the IRP + Irp->IoStatus.Information = 0; + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE)) { + PETH_HEADER p_UserToTap = &adapter->m_UserToTap; + PMDL mdl; // Head of MDL chain. + + // For IPv6, need to use Ethernet header with IPv6 proto + if (IPH_GET_VER(((IPHDR *)Irp->AssociatedIrp.SystemBuffer)->version_len) == 6) { + p_UserToTap = &adapter->m_UserToTap_IPv6; + } + + DUMP_PACKET2("IRP_MJ_WRITE P2P", p_UserToTap, + (unsigned char *)Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify((unsigned char *)Irp->AssociatedIrp.SystemBuffer, + irpSp->Parameters.Write.Length, TRUE, "RX", &adapter->m_RxTrunc); +#endif + + // + // Allocate MDL for Ethernet header + // -------------------------------- + // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length + // contains the only the Ethernet payload. Prepend the user-mode provided + // payload with the Ethernet header pointed to by p_UserToTap. + // + mdl = NdisAllocateMdl(adapter->MiniportAdapterHandle, p_UserToTap, sizeof(ETH_HEADER)); + + if (mdl != NULL) { + PNET_BUFFER_LIST netBufferList; + + // Chain user's Ethernet payload behind Ethernet header. + mdl->Next = Irp->MdlAddress; + (Irp->MdlAddress)->Next = NULL; // No next MDL + + // Allocate the NBL and NB. Link MDL chain to NB. + netBufferList = NdisAllocateNetBufferAndNetBufferList(adapter->ReceiveNblPool, + 0, // ContextSize + 0, // ContextBackFill + mdl, // MDL chain + 0, sizeof(ETH_HEADER) + dataLength); + + if (netBufferList != NULL) { + LONG nblCount; + + NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL + + // This IRP is pended. + IoMarkIrpPending(Irp); + + // This IRP cannot be cancelled while in-flight. + IoSetCancelRoutine(Irp, NULL); + + // Stash IRP pointer in NBL MiniportReserved[0] field. + netBufferList->MiniportReserved[0] = Irp; + netBufferList->MiniportReserved[1] = NULL; + + // Set flag indicating that this is P2P packet + TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList); + TAP_RX_NBL_FLAG_SET(netBufferList, TAP_RX_NBL_FLAGS_IS_P2P); + + // Increment in-flight receive NBL count. + nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount); + ASSERT(nblCount > 0); + + // + // Indicate the packet + // + NdisMIndicateReceiveNetBufferLists(adapter->MiniportAdapterHandle, netBufferList, + NDIS_DEFAULT_PORT_NUMBER, + 1, // NumberOfNetBufferLists + 0 // ReceiveFlags + ); + + ntStatus = STATUS_PENDING; + } else { + mdl->Next = NULL; + NdisFreeMdl(mdl); + + DEBUGP(("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n", + MINIPORT_INSTANCE_ID(adapter))); + NOTE_ERROR(); + + // Fail the IRP + Irp->IoStatus.Information = 0; + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } else { + DEBUGP(("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n", MINIPORT_INSTANCE_ID(adapter))); + NOTE_ERROR(); + + // Fail the IRP + Irp->IoStatus.Information = 0; + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } else { + DEBUGP(("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n", MINIPORT_INSTANCE_ID(adapter), + irpSp->Parameters.Write.Length)); + NOTE_ERROR(); + + Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE; + Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL; + } + } else { + DEBUGP( + ("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n", MINIPORT_INSTANCE_ID(adapter))); + + ntStatus = STATUS_SUCCESS; + } + + if (ntStatus != STATUS_PENDING) { + Irp->IoStatus.Status = ntStatus; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return ntStatus; +} diff --git a/third_party/tap-windows6/src/tap-windows.h b/third_party/tap-windows6/src/tap-windows.h new file mode 100644 index 00000000000..66daf73fd63 --- /dev/null +++ b/third_party/tap-windows6/src/tap-windows.h @@ -0,0 +1,77 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). This particular file + * (tap-windows.h) is also licensed using the MIT license (see COPYRIGHT.MIT). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_WIN_H +#define __TAP_WIN_H + +/* + * ============= + * TAP IOCTLs + * ============= + */ + +#define TAP_WIN_CONTROL_CODE(request, method) \ + CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +/* Present in 8.1 */ + +#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE(1, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE(2, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE(3, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE(4, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE(5, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE(6, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE(7, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE(8, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE(9, METHOD_BUFFERED) + +/* Added in 8.2 */ + +/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */ +#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE(10, METHOD_BUFFERED) + +/* + * ================= + * Registry keys + * ================= + */ + +#define ADAPTER_KEY \ + "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY \ + "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +/* + * ====================== + * Filesystem prefixes + * ====================== + */ + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAP_WIN_SUFFIX ".tap" + +#endif // __TAP_WIN_H diff --git a/third_party/tap-windows6/src/tap.h b/third_party/tap-windows6/src/tap.h new file mode 100644 index 00000000000..c72e8b17fea --- /dev/null +++ b/third_party/tap-windows6/src/tap.h @@ -0,0 +1,80 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_H +#define __TAP_H + +#include +#include +#include +#include + +#include "adapter.h" +#include "config.h" +#include "constants.h" +#include "device.h" +#include "dhcp.h" +#include "endian.h" +#include "error.h" +#include "lock.h" +#include "macinfo.h" +#include "mem.h" +#include "proto.h" +#include "prototypes.h" +#include "tap-windows.h" +#include "types.h" + +//======================================================== +// Check for truncated IPv4 packets, log errors if found. +//======================================================== +#define PACKET_TRUNCATION_CHECK 0 + +//======================================================== +// EXPERIMENTAL -- Configure TAP device object to be +// accessible from non-administrative accounts, based +// on an advanced properties setting. +// +// Duplicates the functionality of OpenVPN's +// --allow-nonadmin directive. +//======================================================== +#define ENABLE_NONADMIN 1 + +// +// The driver has exactly one instance of the TAP_GLOBAL structure. NDIS keeps +// an opaque handle to this data, (it doesn't attempt to read or interpret this +// data), and it passes the handle back to the miniport in MiniportSetOptions +// and MiniportInitializeEx. +// +typedef struct _TAP_GLOBAL { + LIST_ENTRY AdapterList; + + NDIS_RW_LOCK Lock; + + NDIS_HANDLE NdisDriverHandle; // From NdisMRegisterMiniportDriver + +} TAP_GLOBAL, *PTAP_GLOBAL; + +// Global data +extern TAP_GLOBAL GlobalData; + +#endif // __TAP_H diff --git a/third_party/tap-windows6/src/tapdrvr.c b/third_party/tap-windows6/src/tapdrvr.c new file mode 100644 index 00000000000..9cb8874ba92 --- /dev/null +++ b/third_party/tap-windows6/src/tapdrvr.c @@ -0,0 +1,209 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//====================================================== +// This driver is designed to work on Windows Vista or higher +// versions of Windows. +// +// It is SMP-safe and handles power management. +// +// By default we operate as a "tap" virtual ethernet +// 802.3 interface, but we can emulate a "tun" +// interface (point-to-point IPv4) through the +// TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT or +// TAP_WIN_IOCTL_CONFIG_TUN ioctl. +//====================================================== + +// +// Include files. +// + +#include + +#include "tap.h" + +// Global data +TAP_GLOBAL GlobalData; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, TapDriverUnload) +#endif // ALLOC_PRAGMA + +NTSTATUS +DriverEntry(__in PDRIVER_OBJECT DriverObject, __in PUNICODE_STRING RegistryPath) +/*++ +Routine Description: + + In the context of its DriverEntry function, a miniport driver associates + itself with NDIS, specifies the NDIS version that it is using, and + registers its entry points. + + +Arguments: + PVOID DriverObject - pointer to the driver object. + PVOID RegistryPath - pointer to the driver registry path. + + Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(RegistryPath); + + DEBUGP(("[TAP] --> DriverEntry; version [%d.%d] %s %s\n", TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, __DATE__, __TIME__)); + + DEBUGP(("[TAP] Registry Path: '%wZ'\n", RegistryPath)); + + // + // Initialize any driver-global variables here. + // + NdisZeroMemory(&GlobalData, sizeof(GlobalData)); + + // + // The ApaterList in the GlobalData structure is used to track multiple + // adapters controlled by this miniport. + // + NdisInitializeListHead(&GlobalData.AdapterList); + + // + // This lock protects the AdapterList. + // + NdisInitializeReadWriteLock(&GlobalData.Lock); + + do { + NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniportCharacteristics; + + NdisZeroMemory(&miniportCharacteristics, sizeof(miniportCharacteristics)); + + { + C_ASSERT(sizeof(miniportCharacteristics) >= + NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2); + } + miniportCharacteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS; + miniportCharacteristics.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; + miniportCharacteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2; + + miniportCharacteristics.MajorNdisVersion = TAP_NDIS_MAJOR_VERSION; + miniportCharacteristics.MinorNdisVersion = TAP_NDIS_MINOR_VERSION; + + miniportCharacteristics.MajorDriverVersion = TAP_DRIVER_MAJOR_VERSION; + miniportCharacteristics.MinorDriverVersion = TAP_DRIVER_MINOR_VERSION; + + miniportCharacteristics.Flags = 0; + + // miniportCharacteristics.SetOptionsHandler = MPSetOptions; // Optional + miniportCharacteristics.InitializeHandlerEx = AdapterCreate; + miniportCharacteristics.HaltHandlerEx = AdapterHalt; + miniportCharacteristics.UnloadHandler = TapDriverUnload; + miniportCharacteristics.PauseHandler = AdapterPause; + miniportCharacteristics.RestartHandler = AdapterRestart; + miniportCharacteristics.OidRequestHandler = AdapterOidRequest; + miniportCharacteristics.SendNetBufferListsHandler = AdapterSendNetBufferLists; + miniportCharacteristics.ReturnNetBufferListsHandler = AdapterReturnNetBufferLists; + miniportCharacteristics.CancelSendHandler = AdapterCancelSend; + miniportCharacteristics.CheckForHangHandlerEx = AdapterCheckForHangEx; + miniportCharacteristics.ResetHandlerEx = AdapterReset; + miniportCharacteristics.DevicePnPEventNotifyHandler = AdapterDevicePnpEventNotify; + miniportCharacteristics.ShutdownHandlerEx = AdapterShutdownEx; + miniportCharacteristics.CancelOidRequestHandler = AdapterCancelOidRequest; + + // + // Associate the miniport driver with NDIS by calling the + // NdisMRegisterMiniportDriver. This function returns an NdisDriverHandle. + // The miniport driver must retain this handle but it should never attempt + // to access or interpret this handle. + // + // By calling NdisMRegisterMiniportDriver, the driver indicates that it + // is ready for NDIS to call the driver's MiniportSetOptions and + // MiniportInitializeEx handlers. + // + DEBUGP(("[TAP] Calling NdisMRegisterMiniportDriver...\n")); + // NDIS_DECLARE_MINIPORT_DRIVER_CONTEXT(TAP_GLOBAL); + status = NdisMRegisterMiniportDriver(DriverObject, RegistryPath, &GlobalData, + &miniportCharacteristics, &GlobalData.NdisDriverHandle); + + if (NDIS_STATUS_SUCCESS == status) { + DEBUGP(("[TAP] Registered miniport successfully\n")); + } else { + DEBUGP(("[TAP] NdisMRegisterMiniportDriver failed: %8.8X\n", status)); + TapDriverUnload(DriverObject); + status = NDIS_STATUS_FAILURE; + break; + } + } while (FALSE); + + DEBUGP(("[TAP] <-- DriverEntry; status = %8.8X\n", status)); + + return status; +} + +VOID TapDriverUnload(__in PDRIVER_OBJECT DriverObject) +/*++ + +Routine Description: + + The unload handler is called during driver unload to free up resources + acquired in DriverEntry. This handler is registered in DriverEntry through + NdisMRegisterMiniportDriver. Note that an unload handler differs from + a MiniportHalt function in that this unload handler releases resources that + are global to the driver, while the halt handler releases resource for a + particular adapter. + + Runs at IRQL = PASSIVE_LEVEL. + +Arguments: + + DriverObject Not used + +Return Value: + + None. + +--*/ +{ + PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; + UNICODE_STRING uniWin32NameString; + + DEBUGP(("[TAP] --> TapDriverUnload; version [%d.%d] %s %s unloaded\n", TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, __DATE__, __TIME__)); + + PAGED_CODE(); + + // + // Clean up all globals that were allocated in DriverEntry + // + + ASSERT(IsListEmpty(&GlobalData.AdapterList)); + + if (GlobalData.NdisDriverHandle != NULL) { + NdisMDeregisterMiniportDriver(GlobalData.NdisDriverHandle); + } + + DEBUGP(("[TAP] <-- TapDriverUnload\n")); +} diff --git a/third_party/tap-windows6/src/txpath.c b/third_party/tap-windows6/src/txpath.c new file mode 100644 index 00000000000..c314e95e1a1 --- /dev/null +++ b/third_party/tap-windows6/src/txpath.c @@ -0,0 +1,960 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// +// Include files. +// + +#include "tap.h" + +//====================================================================== +// TAP Send Path Support +//====================================================================== + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, TapDeviceRead) +#endif // ALLOC_PRAGMA + +// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum +// see RFC 4443, 2.3, and RFC 2460, 8.1 +USHORT +icmpv6_checksum(__in const UCHAR *buf, __in const int len_icmpv6, __in const UCHAR *saddr6, + __in const UCHAR *daddr6) { + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words and + // calculate the sum of all 16 bit words + for (i = 0; i < len_icmpv6; i += 2) { + word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i + 1] & 0xFF) : 0); + sum += word16; + } + + // add the IPv6 pseudo header which contains the IP source and destination addresses + for (i = 0; i < 16; i += 2) { + word16 = ((saddr6[i] << 8) & 0xFF00) + (saddr6[i + 1] & 0xFF); + sum += word16; + } + + for (i = 0; i < 16; i += 2) { + word16 = ((daddr6[i] << 8) & 0xFF00) + (daddr6[i + 1] & 0xFF); + sum += word16; + } + + // the next-header number and the length of the ICMPv6 packet + sum += (USHORT)IPPROTO_ICMPV6 + (USHORT)len_icmpv6; + + // keep only the last 16 bits of the 32 bit calculated sum and add the carries + while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16); + + // Take the one's complement of sum + return ((USHORT)~sum); +} + +// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that +// the tap driver needs to answer?" +// see RFC 4861 4.3 for the different cases +static IPV6ADDR IPV6_NS_TARGET_MCAST = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08}; +static IPV6ADDR IPV6_NS_TARGET_UNICAST = {0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08}; + +BOOLEAN +HandleIPv6NeighborDiscovery(__in PTAP_ADAPTER_CONTEXT Adapter, __in UCHAR *m_Data, + __in ULONG packetLength) { + 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 + } + + // Make sure that packet is large enough to be ICMPv6 + if (packetLength < (ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE + sizeof(ICMPV6_NS))) { + return FALSE; // packet too short + } + + // ICMPv6 type+code must be 135/0 for NS + if (icmpv6_ns->type != ICMPV6_TYPE_NS || icmpv6_ns->code != ICMPV6_CODE_0) { + return FALSE; // wrong ICMPv6 type + } + + // ICMPv6 target address must be fe80::8 (magic) + if (memcmp(icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST, sizeof(IPV6ADDR)) != 0) { + return FALSE; // not for us + } + + // packet identified, build magic response packet + + na = (ICMPV6_NA_PKT *)MemAlloc(sizeof(ICMPV6_NA_PKT), TRUE); + if (!na) return FALSE; + + //------------------------------------------------ + // Initialize Neighbour Advertisement reply packet + //------------------------------------------------ + + // ethernet header + na->eth.proto = htons(NDIS_ETH_TYPE_IPV6); + ETH_COPY_NETWORK_ADDRESS(na->eth.dest, Adapter->PermanentAddress); + ETH_COPY_NETWORK_ADDRESS(na->eth.src, Adapter->m_TapToUser.dest); + + // IPv6 header + na->ipv6.version_prio = ipv6->version_prio; + NdisMoveMemory(na->ipv6.flow_lbl, ipv6->flow_lbl, sizeof(na->ipv6.flow_lbl)); + icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR); + na->ipv6.payload_len = htons(icmpv6_len); + na->ipv6.nexthdr = IPPROTO_ICMPV6; + na->ipv6.hop_limit = 255; + NdisMoveMemory(na->ipv6.saddr, IPV6_NS_TARGET_UNICAST, sizeof(IPV6ADDR)); + NdisMoveMemory(na->ipv6.daddr, ipv6->saddr, sizeof(IPV6ADDR)); + + // ICMPv6 + na->icmpv6.type = ICMPV6_TYPE_NA; + na->icmpv6.code = ICMPV6_CODE_0; + na->icmpv6.checksum = 0; + na->icmpv6.rso_bits = 0x60; // Solicited + Override + NdisZeroMemory(na->icmpv6.reserved, sizeof(na->icmpv6.reserved)); + NdisMoveMemory(na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST, sizeof(IPV6ADDR)); + + // ICMPv6 option "Target Link Layer Address" + na->icmpv6.opt_type = ICMPV6_OPTION_TLLA; + na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA; + ETH_COPY_NETWORK_ADDRESS(na->icmpv6.target_macaddr, Adapter->m_TapToUser.dest); + + // calculate and set checksum + icmpv6_csum = icmpv6_checksum((UCHAR *)&(na->icmpv6), icmpv6_len, na->ipv6.saddr, na->ipv6.daddr); + + na->icmpv6.checksum = htons(icmpv6_csum); + + DUMP_PACKET("HandleIPv6NeighborDiscovery", (unsigned char *)na, sizeof(ICMPV6_NA_PKT)); + + IndicateReceivePacket(Adapter, (UCHAR *)na, sizeof(ICMPV6_NA_PKT)); + + MemFree(na, sizeof(ICMPV6_NA_PKT)); + + return TRUE; // all fine +} + +//=================================================== +// Generate an ARP reply message for specific kinds +// ARP queries. +//=================================================== +BOOLEAN +ProcessARP(__in PTAP_ADAPTER_CONTEXT Adapter, __in const PARP_PACKET src, + __in const IPADDR adapter_ip, __in const IPADDR ip_network, __in const IPADDR ip_netmask, + __in const MACADDR mac) { + //----------------------------------------------- + // Is this the kind of packet we are looking for? + //----------------------------------------------- + if (src->m_Proto == htons(NDIS_ETH_TYPE_ARP) && + MAC_EQUAL(src->m_MAC_Source, Adapter->PermanentAddress) && + MAC_EQUAL(src->m_ARP_MAC_Source, Adapter->PermanentAddress) && + ETH_IS_BROADCAST(src->m_MAC_Destination) && src->m_ARP_Operation == htons(ARP_REQUEST) && + src->m_MAC_AddressType == htons(MAC_ADDR_TYPE) && src->m_MAC_AddressSize == sizeof(MACADDR) && + src->m_PROTO_AddressType == htons(NDIS_ETH_TYPE_IPV4) && + src->m_PROTO_AddressSize == sizeof(IPADDR) && src->m_ARP_IP_Source == adapter_ip && + (src->m_ARP_IP_Destination & ip_netmask) == ip_network && + src->m_ARP_IP_Destination != adapter_ip) { + ARP_PACKET *arp = (ARP_PACKET *)MemAlloc(sizeof(ARP_PACKET), TRUE); + if (arp) { + //---------------------------------------------- + // Initialize ARP reply fields + //---------------------------------------------- + arp->m_Proto = htons(NDIS_ETH_TYPE_ARP); + arp->m_MAC_AddressType = htons(MAC_ADDR_TYPE); + arp->m_PROTO_AddressType = htons(NDIS_ETH_TYPE_IPV4); + arp->m_MAC_AddressSize = sizeof(MACADDR); + arp->m_PROTO_AddressSize = sizeof(IPADDR); + arp->m_ARP_Operation = htons(ARP_REPLY); + + //---------------------------------------------- + // ARP addresses + //---------------------------------------------- + ETH_COPY_NETWORK_ADDRESS(arp->m_MAC_Source, mac); + ETH_COPY_NETWORK_ADDRESS(arp->m_MAC_Destination, Adapter->PermanentAddress); + ETH_COPY_NETWORK_ADDRESS(arp->m_ARP_MAC_Source, mac); + ETH_COPY_NETWORK_ADDRESS(arp->m_ARP_MAC_Destination, Adapter->PermanentAddress); + arp->m_ARP_IP_Source = src->m_ARP_IP_Destination; + arp->m_ARP_IP_Destination = adapter_ip; + + DUMP_PACKET("ProcessARP", (unsigned char *)arp, sizeof(ARP_PACKET)); + + IndicateReceivePacket(Adapter, (UCHAR *)arp, sizeof(ARP_PACKET)); + + MemFree(arp, sizeof(ARP_PACKET)); + } + + return TRUE; + } else + return FALSE; +} + +//============================================================= +// CompleteIRP is normally called with an adapter -> userspace +// network packet and an IRP (Pending I/O request) from userspace. +// +// The IRP will normally represent a queued overlapped read +// operation from userspace that is in a wait state. +// +// Use the ethernet packet to satisfy the IRP. +//============================================================= + +VOID tapCompletePendingReadIrp(__in PIRP Irp, __in PTAP_PACKET TapPacket) { + int offset; + int len; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + ASSERT(Irp); + ASSERT(TapPacket); + + //------------------------------------------- + // While TapPacket always contains a + // full ethernet packet, including the + // ethernet header, in point-to-point mode, + // we only want to return the IPv4 + // component. + //------------------------------------------- + + if (TapPacket->m_SizeFlags & TP_TUN) { + offset = ETHERNET_HEADER_SIZE; + len = (int)(TapPacket->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE; + } else { + offset = 0; + len = (TapPacket->m_SizeFlags & TP_SIZE_MASK); + } + + if (len < 0 || (int)Irp->IoStatus.Information < len) { + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = status = STATUS_BUFFER_OVERFLOW; + NOTE_ERROR(); + } else { + Irp->IoStatus.Information = len; + Irp->IoStatus.Status = status = STATUS_SUCCESS; + + // Copy packet data + NdisMoveMemory(Irp->AssociatedIrp.SystemBuffer, TapPacket->m_Data + offset, len); + } + + // Free the TAP packet + NdisFreeMemory(TapPacket, 0, 0); + + // Complete the IRP + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); +} + +VOID tapProcessSendPacketQueue(__in PTAP_ADAPTER_CONTEXT Adapter) { + KIRQL irql; + + // Process the send packet queue + KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock, &irql); + + while (Adapter->SendPacketQueue.Count > 0) { + PIRP irp; + PTAP_PACKET tapPacket; + + // Fetch a read IRP + irp = IoCsqRemoveNextIrp(&Adapter->PendingReadIrpQueue.CsqQueue, NULL); + + if (irp == NULL) { + // No IRP to satisfy + break; + } + + // Fetch a queued TAP send packet + tapPacket = tapPacketRemoveHeadLocked(&Adapter->SendPacketQueue); + + ASSERT(tapPacket); + + // BUGBUG!!! Investigate whether release/reacquire can cause + // out-of-order IRP completion. Also, whether user-mode can + // tolerate out-of-order packets. + + // Release packet queue lock while completing the IRP + // KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql); + + // Complete the read IRP from queued TAP send packet. + tapCompletePendingReadIrp(irp, tapPacket); + + // Reqcquire packet queue lock after completing the IRP + // KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql); + } + + KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock, irql); +} + +// Flush the pending send TAP packet queue. +VOID tapFlushSendPacketQueue(__in PTAP_ADAPTER_CONTEXT Adapter) { + KIRQL irql; + + // Process the send packet queue + KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock, &irql); + + DEBUGP( + ("[TAP] tapFlushSendPacketQueue: Flushing %d TAP packets\n", Adapter->SendPacketQueue.Count)); + + while (Adapter->SendPacketQueue.Count > 0) { + PTAP_PACKET tapPacket; + + // Fetch a queued TAP send packet + tapPacket = tapPacketRemoveHeadLocked(&Adapter->SendPacketQueue); + + ASSERT(tapPacket); + + // Free the TAP packet + NdisFreeMemory(tapPacket, 0, 0); + } + + KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock, irql); +} + +VOID tapAdapterTransmit(__in PTAP_ADAPTER_CONTEXT Adapter, __in PNET_BUFFER NetBuffer, + __in BOOLEAN DispatchLevel) +/*++ + +Routine Description: + + This routine is called to transmit an individual net buffer using a + style similar to the previous NDIS 5 AdapterTransmit function. + + In this implementation adapter state and NB length checks have already + been done before this function has been called. + + The net buffer will be completed by the calling routine after this + routine exits. So, under this design it is necessary to make a deep + copy of frame data in the net buffer. + + This routine creates a flat buffer copy of NB frame data. This is an + unnecessary performance bottleneck. However, the bottleneck is probably + not significant or measurable except for adapters running at 1Gbps or + greater speeds. Since this adapter is currently running at 100Mbps this + defect can be ignored. + + Runs at IRQL <= DISPATCH_LEVEL + +Arguments: + + Adapter Pointer to our adapter context + NetBuffer Pointer to the net buffer to transmit + DispatchLevel TRUE if called at IRQL == DISPATCH_LEVEL + +Return Value: + + None. + + In the Microsoft NDIS 6 architecture there is no per-packet status. + +--*/ +{ + NDIS_STATUS status; + ULONG packetLength; + PTAP_PACKET tapPacket; + PVOID packetData; + + packetLength = NET_BUFFER_DATA_LENGTH(NetBuffer); + + // Allocate TAP packet memory + tapPacket = (PTAP_PACKET)NdisAllocateMemoryWithTagPriority(Adapter->MiniportAdapterHandle, + TAP_PACKET_SIZE(packetLength), + TAP_PACKET_TAG, NormalPoolPriority); + + if (tapPacket == NULL) { + DEBUGP(("[TAP] tapAdapterTransmit: TAP packet allocation failed\n")); + return; + } + + tapPacket->m_SizeFlags = (packetLength & TP_SIZE_MASK); + + // + // Reassemble packet contents + // -------------------------- + // NdisGetDataBuffer does most of the work. There are two cases: + // + // 1.) If the NB data was not contiguous it will copy the entire + // NB's data to m_data and return pointer to m_data. + // 2.) If the NB data was contiguous it returns a pointer to the + // first byte of the contiguous data instead of a pointer to m_Data. + // In this case the data will not have been copied to m_Data. Copy + // to m_Data will need to be done in an extra step. + // + // Case 1.) is the most likely in normal operation. + // + packetData = NdisGetDataBuffer(NetBuffer, packetLength, tapPacket->m_Data, 1, 0); + + if (packetData == NULL) { + DEBUGP(("[TAP] tapAdapterTransmit: Could not get packet data\n")); + + NdisFreeMemory(tapPacket, 0, 0); + + return; + } + + if (packetData != tapPacket->m_Data) { + // Packet data was contiguous and not yet copied to m_Data. + NdisMoveMemory(tapPacket->m_Data, packetData, packetLength); + } + + DUMP_PACKET("AdapterTransmit", tapPacket->m_Data, packetLength); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify(tapPacket->m_Data, packetLength, FALSE, "TX", &Adapter->m_TxTrunc); +#endif + + //===================================================== + // Are we running in DHCP server masquerade mode? + // + // If so, catch both DHCP requests and ARP queries + // to resolve the address of our virtual DHCP server. + //===================================================== + if (Adapter->m_dhcp_enabled) { + const ETH_HEADER *eth = (ETH_HEADER *)tapPacket->m_Data; + const IPHDR *ip = (IPHDR *)(tapPacket->m_Data + sizeof(ETH_HEADER)); + const UDPHDR *udp = (UDPHDR *)(tapPacket->m_Data + sizeof(ETH_HEADER) + sizeof(IPHDR)); + + // ARP packet? + if (packetLength == sizeof(ARP_PACKET) && eth->proto == htons(NDIS_ETH_TYPE_ARP) && + Adapter->m_dhcp_server_arp) { + if (ProcessARP(Adapter, (PARP_PACKET)tapPacket->m_Data, Adapter->m_dhcp_addr, + Adapter->m_dhcp_server_ip, ~0, Adapter->m_dhcp_server_mac)) { + goto no_queue; + } + } + + // DHCP packet? + else if (packetLength >= sizeof(ETH_HEADER) + sizeof(IPHDR) + sizeof(UDPHDR) + sizeof(DHCP) && + eth->proto == htons(NDIS_ETH_TYPE_IPV4) && + ip->version_len == 0x45 // IPv4, 20 byte header + && ip->protocol == IPPROTO_UDP && udp->dest == htons(BOOTPS_PORT)) { + const DHCP *dhcp = + (DHCP *)(tapPacket->m_Data + sizeof(ETH_HEADER) + sizeof(IPHDR) + sizeof(UDPHDR)); + + const int optlen = + packetLength - sizeof(ETH_HEADER) - sizeof(IPHDR) - sizeof(UDPHDR) - sizeof(DHCP); + + if (optlen > 0) // we must have at least one DHCP option + { + if (ProcessDHCP(Adapter, eth, ip, udp, dhcp, optlen)) { + goto no_queue; + } + } else { + goto no_queue; + } + } + } + + //=============================================== + // In Point-To-Point mode, check to see whether + // packet is ARP (handled) or IPv4 (sent to app). + // IPv6 packets are inspected for neighbour discovery + // (to be handled locally), and the rest is forwarded + // all other protocols are dropped + //=============================================== + if (Adapter->m_tun) { + ETH_HEADER *e; + + e = (ETH_HEADER *)tapPacket->m_Data; + + switch (ntohs(e->proto)) { + case NDIS_ETH_TYPE_ARP: + + // Make sure that packet is the right size for ARP. + if (packetLength != sizeof(ARP_PACKET)) { + goto no_queue; + } + + ProcessARP(Adapter, (PARP_PACKET)tapPacket->m_Data, Adapter->m_localIP, + Adapter->m_remoteNetwork, Adapter->m_remoteNetmask, Adapter->m_TapToUser.dest); + + default: + goto no_queue; + + case NDIS_ETH_TYPE_IPV4: + + // Make sure that packet is large enough to be IPv4. + if (packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)) { + goto no_queue; + } + + // Only accept directed packets, not broadcasts. + if (memcmp(e, &Adapter->m_TapToUser, ETHERNET_HEADER_SIZE)) { + goto no_queue; + } + + // Packet looks like IPv4, queue it. :-) + tapPacket->m_SizeFlags |= TP_TUN; + break; + + case NDIS_ETH_TYPE_IPV6: + // Make sure that packet is large enough to be IPv6. + if (packetLength < (ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE)) { + goto no_queue; + } + + // Broadcasts and multicasts are handled specially + // (to be implemented) + + // Neighbor discovery packets to fe80::8 are special + // OpenVPN sets this next-hop to signal "handled by tapdrv" + if (HandleIPv6NeighborDiscovery(Adapter, tapPacket->m_Data, packetLength)) { + goto no_queue; + } + + // Packet looks like IPv6, queue it. :-) + tapPacket->m_SizeFlags |= TP_TUN; + } + } + + //=============================================== + // Push packet onto queue to wait for read from + // userspace. + //=============================================== + if (tapAdapterReadAndWriteReady(Adapter)) { + tapPacketQueueInsertTail(&Adapter->SendPacketQueue, tapPacket); + } else { + // + // Tragedy. All this work and the packet is of no use... + // + NdisFreeMemory(tapPacket, 0, 0); + } + + // Return after queuing or freeing TAP packet. + return; + + // Free TAP packet without queuing. +no_queue: + if (tapPacket != NULL) { + NdisFreeMemory(tapPacket, 0, 0); + } + + return; +} + +VOID tapSendNetBufferListsComplete(__in PTAP_ADAPTER_CONTEXT Adapter, + __in PNET_BUFFER_LIST NetBufferLists, + __in NDIS_STATUS SendCompletionStatus, + __in BOOLEAN DispatchLevel) { + PNET_BUFFER_LIST currentNbl; + PNET_BUFFER_LIST nextNbl = NULL; + ULONG sendCompleteFlags = 0; + + for (currentNbl = NetBufferLists; currentNbl != NULL; currentNbl = nextNbl) { + ULONG frameType; + ULONG netBufferCount; + ULONG byteCount; + + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + + // Set NBL completion status. + NET_BUFFER_LIST_STATUS(currentNbl) = SendCompletionStatus; + + // Fetch first NBs frame type. All linked NBs will have same type. + frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(currentNbl)); + + // Fetch statistics for all NBs linked to the NB. + netBufferCount = tapGetNetBufferCountsFromNetBufferList(currentNbl, &byteCount); + + // Update statistics by frame type + if (SendCompletionStatus == NDIS_STATUS_SUCCESS) { + switch (frameType) { + case NDIS_PACKET_TYPE_DIRECTED: + Adapter->FramesTxDirected += netBufferCount; + Adapter->BytesTxDirected += byteCount; + break; + + case NDIS_PACKET_TYPE_BROADCAST: + Adapter->FramesTxBroadcast += netBufferCount; + Adapter->BytesTxBroadcast += byteCount; + break; + + case NDIS_PACKET_TYPE_MULTICAST: + Adapter->FramesTxMulticast += netBufferCount; + Adapter->BytesTxMulticast += byteCount; + break; + + default: + ASSERT(FALSE); + break; + } + } else { + // Transmit error. + Adapter->TransmitFailuresOther += netBufferCount; + } + + currentNbl = nextNbl; + } + + if (DispatchLevel) { + sendCompleteFlags |= NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL; + } + + // Complete the NBLs + NdisMSendNetBufferListsComplete(Adapter->MiniportAdapterHandle, NetBufferLists, + sendCompleteFlags); +} + +BOOLEAN +tapNetBufferListNetBufferLengthsValid(__in PTAP_ADAPTER_CONTEXT Adapter, + __in PNET_BUFFER_LIST NetBufferLists) +/*++ + +Routine Description: + + Scan all NBLs and their linked NBs for valid lengths. + + Fairly absurd to find and packets with bogus lengths, but wise + to check anyway. If ANY packet has a bogus length, then abort the + entire send. + + The only time that one might see this check fail might be during + HCK driver testing. The HKC test might send oversize packets to + determine if the miniport can gracefully deal with them. + + This check is fairly fast. Unlike NDIS 5 packets, fetching NDIS 6 + packets lengths do not require any computation. + +Arguments: + + Adapter Pointer to our adapter context + NetBufferLists Head of a list of NBLs to examine + +Return Value: + + Returns TRUE if all NBs have reasonable lengths. + Otherwise, returns FALSE. + +--*/ +{ + PNET_BUFFER_LIST currentNbl; + + currentNbl = NetBufferLists; + + while (currentNbl) { + PNET_BUFFER_LIST nextNbl; + PNET_BUFFER currentNb; + + // Locate next NBL + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + + // Locate first NB (aka "packet") + currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl); + + // + // Process all NBs linked to this NBL + // + while (currentNb) { + PNET_BUFFER nextNb; + ULONG packetLength; + + // Locate next NB + nextNb = NET_BUFFER_NEXT_NB(currentNb); + + packetLength = NET_BUFFER_DATA_LENGTH(currentNb); + + // Minimum packet size is size of Ethernet plus IPv4 headers. + ASSERT(packetLength >= (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)); + + if (packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE)) { + return FALSE; + } + + // Maximum size should be Ethernet header size plus MTU plus modest pad for + // VLAN tag. + ASSERT(packetLength <= (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize)); + + if (packetLength > (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize)) { + return FALSE; + } + + // Move to next NB + currentNb = nextNb; + } + + // Move to next NBL + currentNbl = nextNbl; + } + + return TRUE; +} + +VOID AdapterSendNetBufferLists(__in NDIS_HANDLE MiniportAdapterContext, + __in PNET_BUFFER_LIST NetBufferLists, + __in NDIS_PORT_NUMBER PortNumber, __in ULONG SendFlags) +/*++ + +Routine Description: + + Send Packet Array handler. Called by NDIS whenever a protocol + bound to our miniport sends one or more packets. + + The input packet descriptor pointers have been ordered according + to the order in which the packets should be sent over the network + by the protocol driver that set up the packet array. The NDIS + library preserves the protocol-determined ordering when it submits + each packet array to MiniportSendPackets + + As a deserialized driver, we are responsible for holding incoming send + packets in our internal queue until they can be transmitted over the + network and for preserving the protocol-determined ordering of packet + descriptors incoming to its MiniportSendPackets function. + A deserialized miniport driver must complete each incoming send packet + with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable. + + Runs at IRQL <= DISPATCH_LEVEL + +Arguments: + + MiniportAdapterContext Pointer to our adapter + NetBufferLists Head of a list of NBLs to send + PortNumber A miniport adapter port. Default is 0. + SendFlags Additional flags for the send operation + +Return Value: + + None. Write status directly into each NBL with the NET_BUFFER_LIST_STATUS + macro. + +--*/ +{ + NDIS_STATUS status; + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + BOOLEAN DispatchLevel = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL); + PNET_BUFFER_LIST currentNbl; + BOOLEAN validNbLengths; + + UNREFERENCED_PARAMETER(NetBufferLists); + UNREFERENCED_PARAMETER(PortNumber); + UNREFERENCED_PARAMETER(SendFlags); + + ASSERT(PortNumber == 0); // Only the default port is supported + + // + // Can't process sends if TAP device is not open. + // ---------------------------------------------- + // Just perform a "lying send" and return packets as if they + // were successfully sent. + // + if (adapter->TapFileObject == NULL) { + // + // Complete all NBLs and return if adapter not ready. + // + tapSendNetBufferListsComplete(adapter, NetBufferLists, NDIS_STATUS_SUCCESS, DispatchLevel); + + return; + } + + // + // Check Adapter send/receive ready state. + // + status = tapAdapterSendAndReceiveReady(adapter); + + if (status != NDIS_STATUS_SUCCESS) { + // + // Complete all NBLs and return if adapter not ready. + // + tapSendNetBufferListsComplete(adapter, NetBufferLists, status, DispatchLevel); + + return; + } + + // + // Scan all NBLs and linked packets for valid lengths. + // --------------------------------------------------- + // If _ANY_ NB length is invalid, then fail the entire send operation. + // + // BUGBUG!!! Perhaps this should be less agressive. Fail only individual + // NBLs... + // + // If length check is valid, then TAP_PACKETS can be safely allocated + // and processed for all NBs being sent. + // + validNbLengths = tapNetBufferListNetBufferLengthsValid(adapter, NetBufferLists); + + if (!validNbLengths) { + // + // Complete all NBLs and return if and NB length is invalid. + // + tapSendNetBufferListsComplete(adapter, NetBufferLists, NDIS_STATUS_INVALID_LENGTH, + DispatchLevel); + + return; + } + + // + // Process each NBL individually + // + currentNbl = NetBufferLists; + + while (currentNbl) { + PNET_BUFFER_LIST nextNbl; + PNET_BUFFER currentNb; + + // Locate next NBL + nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl); + + // Locate first NB (aka "packet") + currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl); + + // Transmit all NBs linked to this NBL + while (currentNb) { + PNET_BUFFER nextNb; + + // Locate next NB + nextNb = NET_BUFFER_NEXT_NB(currentNb); + + // Transmit the NB + tapAdapterTransmit(adapter, currentNb, DispatchLevel); + + // Move to next NB + currentNb = nextNb; + } + + // Move to next NBL + currentNbl = nextNbl; + } + + // Complete all NBLs + tapSendNetBufferListsComplete(adapter, NetBufferLists, NDIS_STATUS_SUCCESS, DispatchLevel); + + // Attempt to complete pending read IRPs from pending TAP + // send packet queue. + tapProcessSendPacketQueue(adapter); +} + +VOID AdapterCancelSend(__in NDIS_HANDLE MiniportAdapterContext, __in PVOID CancelId) { + PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT)MiniportAdapterContext; + + // + // This miniport completes its sends quickly, so it isn't strictly + // neccessary to implement MiniportCancelSend. + // + // If we did implement it, we'd have to walk the Adapter->SendWaitList + // and look for any NB that points to a NBL where the CancelId matches + // NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(Nbl). For any NB that so matches, + // we'd remove the NB from the SendWaitList and set the NBL's status to + // NDIS_STATUS_SEND_ABORTED, then complete the NBL. + // +} + +// IRP_MJ_READ callback. +NTSTATUS +TapDeviceRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) { + NTSTATUS ntStatus = STATUS_SUCCESS; // Assume success + PIO_STACK_LOCATION irpSp; // Pointer to current stack location + PTAP_ADAPTER_CONTEXT adapter = NULL; + + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Fetch adapter context for this device. + // -------------------------------------- + // Adapter pointer was stashed in FsContext when handle was opened. + // + adapter = (PTAP_ADAPTER_CONTEXT)(irpSp->FileObject)->FsContext; + + ASSERT(adapter); + + // + // Sanity checks on state variables + // + if (!tapAdapterReadAndWriteReady(adapter)) { + // DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n", + // MINIPORT_INSTANCE_ID (adapter))); + // NOTE_ERROR(); + + Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // Save IRP-accessible copy of buffer length + Irp->IoStatus.Information = irpSp->Parameters.Read.Length; + + if (Irp->MdlAddress == NULL) { + DEBUGP(("[%s] MdlAddress is NULL for IRP_MJ_READ\n", MINIPORT_INSTANCE_ID(adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + if ((Irp->AssociatedIrp.SystemBuffer = + MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)) == NULL) { + DEBUGP(("[%s] Could not map address in IRP_MJ_READ\n", MINIPORT_INSTANCE_ID(adapter))); + + NOTE_ERROR(); + Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return ntStatus; + } + + // BUGBUG!!! Use RemoveLock??? + + // + // Queue the IRP and return STATUS_PENDING. + // ---------------------------------------- + // Note: IoCsqInsertIrp marks the IRP pending. + // + + // BUGBUG!!! NDIS 5 implementation has IRP_QUEUE_SIZE of 16 and + // does not queue IRP if this capacity is exceeded. + // + // Is this needed??? + // + IoCsqInsertIrp(&adapter->PendingReadIrpQueue.CsqQueue, Irp, NULL); + + // Attempt to complete pending read IRPs from pending TAP + // send packet queue. + tapProcessSendPacketQueue(adapter); + + ntStatus = STATUS_PENDING; + + return ntStatus; +} diff --git a/third_party/tap-windows6/src/types.h b/third_party/tap-windows6/src/types.h new file mode 100644 index 00000000000..e3c3e806ff8 --- /dev/null +++ b/third_party/tap-windows6/src/types.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-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TAP_TYPES_DEFINED +#define TAP_TYPES_DEFINED + +// typedef +// struct _Queue +//{ +// ULONG base; +// ULONG size; +// ULONG capacity; +// ULONG max_size; +// PVOID data[]; +//} Queue; + +// typedef struct _TAP_PACKET; + +// typedef struct _TapExtension +//{ +// // TAP device object and packet queues +// Queue *m_PacketQueue, *m_IrpQueue; +// PDEVICE_OBJECT m_TapDevice; +// NDIS_HANDLE m_TapDeviceHandle; +// ULONG TapFileIsOpen; +// +// // Used to lock packet queues +// NDIS_SPIN_LOCK m_QueueLock; +// BOOLEAN m_AllocatedSpinlocks; +// +// // Used to bracket open/close +// // state changes. +// MUTEX m_OpenCloseMutex; +// +// // True if device has been permanently halted +// BOOLEAN m_Halt; +// +// // TAP device name +// unsigned char *m_TapName; +// UNICODE_STRING m_UnicodeLinkName; +// BOOLEAN m_CreatedUnicodeLinkName; +// +// // Used for device status ioctl only +// const char *m_LastErrorFilename; +// int m_LastErrorLineNumber; +// LONG TapFileOpenCount; +// +// // Flags +// BOOLEAN TapDeviceCreated; +// BOOLEAN m_CalledTapDeviceFreeResources; +// +// // DPC queue for deferred packet injection +// BOOLEAN m_InjectDpcInitialized; +// KDPC m_InjectDpc; +// NDIS_SPIN_LOCK m_InjectLock; +// Queue *m_InjectQueue; +//} +// TapExtension, *TapExtensionPointer; + +typedef struct _InjectPacket { +#define INJECT_PACKET_SIZE(data_size) (sizeof(InjectPacket) + (data_size)) +#define INJECT_PACKET_FREE(ib) NdisFreeMemory((ib), INJECT_PACKET_SIZE((ib)->m_Size), 0) + ULONG m_Size; + UCHAR m_Data[]; // m_Data must be the last struct member +} InjectPacket, *InjectPacketPointer; + +#endif diff --git a/third_party/tap-windows6/version.m4 b/third_party/tap-windows6/version.m4 new file mode 100644 index 00000000000..1d7f92ef769 --- /dev/null +++ b/third_party/tap-windows6/version.m4 @@ -0,0 +1,14 @@ +dnl define the TAP version +define([PRODUCT_NAME], [TAP-Windows]) +define([PRODUCT_PUBLISHER], [OpenVPN Technologies, Inc.]) +define([PRODUCT_VERSION], [9.22.1]) +define([PRODUCT_VERSION_RESOURCE], [9,0,0,22]) +define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901]) +define([PRODUCT_TAP_WIN_MAJOR], [9]) +define([PRODUCT_TAP_WIN_MINOR], [22]) +define([PRODUCT_TAP_WIN_REVISION], [1]) +define([PRODUCT_TAP_WIN_BUILD], [601]) +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], [04/15/2018])