summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrant Limberg <glimberg@gmail.com>2015-04-25 18:59:52 -0700
committerGrant Limberg <glimberg@gmail.com>2015-04-25 18:59:52 -0700
commitec45aeb42aa644b71654b0467c4aebc80e896420 (patch)
treee7d544030dfc9e279007a8455a12206e895446eb
parenta86a0ab2b13ae19d99f4667666a25b337e0b93f1 (diff)
parent7af1f3a79ab8928a3b49bac458ee87368c46edc5 (diff)
downloadinfinitytier-ec45aeb42aa644b71654b0467c4aebc80e896420.tar.gz
infinitytier-ec45aeb42aa644b71654b0467c4aebc80e896420.zip
Merge branch 'adamierymenko-dev' into android-jni
-rw-r--r--attic/Node.cpp949
-rw-r--r--attic/Node.hpp245
-rw-r--r--attic/WindowsEthernetTapFactory.cpp162
-rw-r--r--attic/WindowsEthernetTapFactory.hpp90
-rw-r--r--attic/main.cpp887
-rw-r--r--ext/bin/tap-windows-ndis5/x64/WdfCoinstaller01011.dll (renamed from ext/bin/tap-windows/x64/WdfCoinstaller01011.dll)bin1795952 -> 1795952 bytes
-rw-r--r--ext/bin/tap-windows-ndis5/x64/zttap200.cat (renamed from ext/bin/tap-windows/x64/zttap200.cat)bin10549 -> 10549 bytes
-rw-r--r--ext/bin/tap-windows-ndis5/x64/zttap200.inf (renamed from ext/bin/tap-windows/x64/zttap200.inf)0
-rw-r--r--ext/bin/tap-windows-ndis5/x64/zttap200.sys (renamed from ext/bin/tap-windows/x64/zttap200.sys)bin31896 -> 31896 bytes
-rw-r--r--ext/bin/tap-windows-ndis5/x86/WdfCoinstaller01011.dll (renamed from ext/bin/tap-windows/x86/WdfCoinstaller01011.dll)bin1629040 -> 1629040 bytes
-rw-r--r--ext/bin/tap-windows-ndis5/x86/zttap200.cat (renamed from ext/bin/tap-windows/x86/zttap200.cat)bin10496 -> 10496 bytes
-rw-r--r--ext/bin/tap-windows-ndis5/x86/zttap200.inf (renamed from ext/bin/tap-windows/x86/zttap200.inf)0
-rw-r--r--ext/bin/tap-windows-ndis5/x86/zttap200.sys (renamed from ext/bin/tap-windows/x86/zttap200.sys)bin28824 -> 28824 bytes
-rw-r--r--ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dllbin0 -> 1795952 bytes
-rw-r--r--ext/bin/tap-windows-ndis6/x64/zttap300.catbin0 -> 9941 bytes
-rw-r--r--ext/bin/tap-windows-ndis6/x64/zttap300.inf143
-rw-r--r--ext/bin/tap-windows-ndis6/x64/zttap300.sysbin0 -> 30488 bytes
-rw-r--r--ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dllbin0 -> 1629040 bytes
-rw-r--r--ext/bin/tap-windows-ndis6/x86/zttap300.catbin0 -> 9941 bytes
-rw-r--r--ext/bin/tap-windows-ndis6/x86/zttap300.inf139
-rw-r--r--ext/bin/tap-windows-ndis6/x86/zttap300.sysbin0 -> 27928 bytes
-rw-r--r--osdep/WindowsEthernetTap.cpp25
-rw-r--r--windows/TapDriver6/TapDriver6.vcxproj371
-rw-r--r--windows/TapDriver6/TapDriver6.vcxproj.filters110
-rw-r--r--windows/TapDriver6/adapter.c1716
-rw-r--r--windows/TapDriver6/adapter.h352
-rw-r--r--windows/TapDriver6/config.h9
-rw-r--r--windows/TapDriver6/constants.h196
-rw-r--r--windows/TapDriver6/device.c1209
-rw-r--r--windows/TapDriver6/device.h50
-rw-r--r--windows/TapDriver6/endian.h35
-rw-r--r--windows/TapDriver6/error.c398
-rw-r--r--windows/TapDriver6/error.h114
-rw-r--r--windows/TapDriver6/hexdump.h63
-rw-r--r--windows/TapDriver6/lock.h75
-rw-r--r--windows/TapDriver6/macinfo.c164
-rw-r--r--windows/TapDriver6/macinfo.h53
-rw-r--r--windows/TapDriver6/mem.c401
-rw-r--r--windows/TapDriver6/mem.h113
-rw-r--r--windows/TapDriver6/oidrequest.c1028
-rw-r--r--windows/TapDriver6/proto.h224
-rw-r--r--windows/TapDriver6/prototypes.h91
-rw-r--r--windows/TapDriver6/resource.h1573
-rw-r--r--windows/TapDriver6/resource.rc88
-rw-r--r--windows/TapDriver6/rxpath.c669
-rw-r--r--windows/TapDriver6/tap-windows.h81
-rw-r--r--windows/TapDriver6/tap.h88
-rw-r--r--windows/TapDriver6/tapdrvr.c232
-rw-r--r--windows/TapDriver6/txpath.c1175
-rw-r--r--windows/TapDriver6/types.h90
-rw-r--r--windows/TapDriver6/zttap300.inf143
-rw-r--r--windows/ZeroTierOne.sln145
52 files changed, 11356 insertions, 2340 deletions
diff --git a/attic/Node.cpp b/attic/Node.cpp
deleted file mode 100644
index 71c2d3fa..00000000
--- a/attic/Node.cpp
+++ /dev/null
@@ -1,949 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include <map>
-#include <set>
-#include <utility>
-#include <algorithm>
-#include <list>
-#include <vector>
-#include <string>
-
-#include "Constants.hpp"
-
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#include <Windows.h>
-#include <ShlObj.h>
-#else
-#include <fcntl.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/file.h>
-#endif
-
-#include "../version.h"
-
-#include "Node.hpp"
-#include "RuntimeEnvironment.hpp"
-#include "Logger.hpp"
-#include "Utils.hpp"
-#include "Defaults.hpp"
-#include "Identity.hpp"
-#include "Topology.hpp"
-#include "SocketManager.hpp"
-#include "Packet.hpp"
-#include "Switch.hpp"
-#include "EthernetTap.hpp"
-#include "CMWC4096.hpp"
-#include "NodeConfig.hpp"
-#include "Network.hpp"
-#include "MulticastGroup.hpp"
-#include "Multicaster.hpp"
-#include "Mutex.hpp"
-#include "SoftwareUpdater.hpp"
-#include "Buffer.hpp"
-#include "AntiRecursion.hpp"
-#include "HttpClient.hpp"
-#include "NetworkConfigMaster.hpp"
-
-namespace ZeroTier {
-
-struct _NodeImpl
-{
- RuntimeEnvironment renv;
-
- std::string reasonForTerminationStr;
- volatile Node::ReasonForTermination reasonForTermination;
-
- volatile bool started;
- volatile bool running;
- volatile bool resynchronize;
-
- volatile bool disableRootTopologyUpdates;
- std::string overrideRootTopology;
-
- // This function performs final node tear-down
- inline Node::ReasonForTermination terminate()
- {
- RuntimeEnvironment *RR = &renv;
- LOG("terminating: %s",reasonForTerminationStr.c_str());
-
- running = false;
-
- delete renv.updater; renv.updater = (SoftwareUpdater *)0;
- delete renv.nc; renv.nc = (NodeConfig *)0; // shut down all networks, close taps, etc.
- delete renv.topology; renv.topology = (Topology *)0; // now we no longer need routing info
- delete renv.mc; renv.mc = (Multicaster *)0;
- delete renv.antiRec; renv.antiRec = (AntiRecursion *)0;
- delete renv.sw; renv.sw = (Switch *)0; // order matters less from here down
- delete renv.http; renv.http = (HttpClient *)0;
- delete renv.prng; renv.prng = (CMWC4096 *)0;
- delete renv.log; renv.log = (Logger *)0; // but stop logging last of all
-
- return reasonForTermination;
- }
-
- inline Node::ReasonForTermination terminateBecause(Node::ReasonForTermination r,const char *rstr)
- {
- reasonForTerminationStr = rstr;
- reasonForTermination = r;
- return terminate();
- }
-};
-
-Node::Node(
- const char *hp,
- EthernetTapFactory *tf,
- SocketManager *sm,
- NetworkConfigMaster *nm,
- bool resetIdentity,
- const char *overrideRootTopology) throw() :
- _impl(new _NodeImpl)
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
-
- if ((hp)&&(hp[0]))
- impl->renv.homePath = hp;
- else impl->renv.homePath = ZT_DEFAULTS.defaultHomePath;
-
- impl->renv.tapFactory = tf;
- impl->renv.sm = sm;
- impl->renv.netconfMaster = nm;
-
- if (resetIdentity) {
- // Forget identity and peer database, peer keys, etc.
- Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
- Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
- Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "peers.persist").c_str());
-
- // Truncate network config information in networks.d but leave the files since we
- // still want to remember any networks we have joined. This will force those networks
- // to be reconfigured with our newly regenerated identity after startup.
- std::string networksDotD(impl->renv.homePath + ZT_PATH_SEPARATOR_S + "networks.d");
- std::map< std::string,bool > nwfiles(Utils::listDirectory(networksDotD.c_str()));
- for(std::map<std::string,bool>::iterator nwf(nwfiles.begin());nwf!=nwfiles.end();++nwf) {
- FILE *trun = fopen((networksDotD + ZT_PATH_SEPARATOR_S + nwf->first).c_str(),"w");
- if (trun)
- fclose(trun);
- }
- }
-
- impl->reasonForTermination = Node::NODE_RUNNING;
- impl->started = false;
- impl->running = false;
- impl->resynchronize = false;
-
- if (overrideRootTopology) {
- impl->disableRootTopologyUpdates = true;
- impl->overrideRootTopology = overrideRootTopology;
- } else {
- impl->disableRootTopologyUpdates = false;
- }
-}
-
-Node::~Node()
-{
- delete (_NodeImpl *)_impl;
-}
-
-static void _CBztTraffic(const SharedPtr<Socket> &fromSock,void *arg,const InetAddress &from,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &data)
-{
- ((const RuntimeEnvironment *)arg)->sw->onRemotePacket(fromSock,from,data);
-}
-
-static void _cbHandleGetRootTopology(void *arg,int code,const std::string &url,const std::string &body)
-{
- RuntimeEnvironment *RR = (RuntimeEnvironment *)arg;
-
- if ((code != 200)||(body.length() == 0)) {
- TRACE("failed to retrieve %s",url.c_str());
- return;
- }
-
- try {
- Dictionary rt(body);
- if (!Topology::authenticateRootTopology(rt)) {
- LOG("discarded invalid root topology update from %s (signature check failed)",url.c_str());
- return;
- }
-
- {
- std::string rootTopologyPath(RR->homePath + ZT_PATH_SEPARATOR_S + "root-topology");
- std::string rootTopology;
- if (Utils::readFile(rootTopologyPath.c_str(),rootTopology)) {
- Dictionary alreadyHave(rootTopology);
- if (alreadyHave == rt) {
- TRACE("retrieved root topology from %s but no change (same as on disk)",url.c_str());
- return;
- } else if (alreadyHave.signatureTimestamp() > rt.signatureTimestamp()) {
- TRACE("retrieved root topology from %s but no change (ours is newer)",url.c_str());
- return;
- }
- }
- Utils::writeFile(rootTopologyPath.c_str(),body);
- }
-
- RR->topology->setSupernodes(Dictionary(rt.get("supernodes")));
- } catch ( ... ) {
- LOG("discarded invalid root topology update from %s (format invalid)",url.c_str());
- return;
- }
-}
-
-Node::ReasonForTermination Node::run()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
-
- impl->started = true;
- impl->running = true;
-
- try {
-#ifdef ZT_LOG_STDOUT
- RR->log = new Logger((const char *)0,(const char *)0,0);
-#else
- RR->log = new Logger((RR->homePath + ZT_PATH_SEPARATOR_S + "node.log").c_str(),(const char *)0,131072);
-#endif
-
- LOG("starting version %s",versionString());
-
- // Create non-crypto PRNG right away in case other code in init wants to use it
- RR->prng = new CMWC4096();
-
- // Read identity public and secret, generating if not present
- {
- bool gotId = false;
- std::string identitySecretPath(RR->homePath + ZT_PATH_SEPARATOR_S + "identity.secret");
- std::string identityPublicPath(RR->homePath + ZT_PATH_SEPARATOR_S + "identity.public");
- std::string idser;
- if (Utils::readFile(identitySecretPath.c_str(),idser))
- gotId = RR->identity.fromString(idser);
- if ((gotId)&&(!RR->identity.locallyValidate()))
- gotId = false;
- if (gotId) {
- // Make sure identity.public matches identity.secret
- idser = std::string();
- Utils::readFile(identityPublicPath.c_str(),idser);
- std::string pubid(RR->identity.toString(false));
- if (idser != pubid) {
- if (!Utils::writeFile(identityPublicPath.c_str(),pubid))
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.public (home path not writable?)");
- }
- } else {
- LOG("no identity found or identity invalid, generating one... this might take a few seconds...");
- RR->identity.generate();
- LOG("generated new identity: %s",RR->identity.address().toString().c_str());
- idser = RR->identity.toString(true);
- if (!Utils::writeFile(identitySecretPath.c_str(),idser))
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.secret (home path not writable?)");
- idser = RR->identity.toString(false);
- if (!Utils::writeFile(identityPublicPath.c_str(),idser))
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.public (home path not writable?)");
- }
- Utils::lockDownFile(identitySecretPath.c_str(),false);
- }
-
- // Make sure networks.d exists (used by NodeConfig to remember networks)
- {
- std::string networksDotD(RR->homePath + ZT_PATH_SEPARATOR_S + "networks.d");
-#ifdef __WINDOWS__
- CreateDirectoryA(networksDotD.c_str(),NULL);
-#else
- mkdir(networksDotD.c_str(),0700);
-#endif
- }
- // Make sure iddb.d exists (used by Topology to remember identities)
- {
- std::string iddbDotD(RR->homePath + ZT_PATH_SEPARATOR_S + "iddb.d");
-#ifdef __WINDOWS__
- CreateDirectoryA(iddbDotD.c_str(),NULL);
-#else
- mkdir(iddbDotD.c_str(),0700);
-#endif
- }
-
- RR->http = new HttpClient();
- RR->sw = new Switch(RR);
- RR->mc = new Multicaster(RR);
- RR->antiRec = new AntiRecursion();
- RR->topology = new Topology(RR);
- try {
- RR->nc = new NodeConfig(RR);
- } catch (std::exception &exc) {
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unable to initialize IPC socket: is ZeroTier One already running?");
- }
- RR->node = this;
-
-#ifdef ZT_AUTO_UPDATE
- if (ZT_DEFAULTS.updateLatestNfoURL.length()) {
- RR->updater = new SoftwareUpdater(RR);
- RR->updater->cleanOldUpdates(); // clean out updates.d on startup
- } else {
- LOG("WARNING: unable to enable software updates: latest .nfo URL from ZT_DEFAULTS is empty (does this platform actually support software updates?)");
- }
-#endif
-
- // Initialize root topology from defaults or root-toplogy file in home path on disk
- if (impl->overrideRootTopology.length() == 0) {
- std::string rootTopologyPath(RR->homePath + ZT_PATH_SEPARATOR_S + "root-topology");
- std::string rootTopology;
- if (!Utils::readFile(rootTopologyPath.c_str(),rootTopology))
- rootTopology = ZT_DEFAULTS.defaultRootTopology;
- try {
- Dictionary rt(rootTopology);
-
- if (Topology::authenticateRootTopology(rt)) {
- // Set supernodes if root topology signature is valid
- RR->topology->setSupernodes(Dictionary(rt.get("supernodes",""))); // set supernodes from root-topology
-
- // If root-topology contains noupdate=1, disable further updates and only use what was on disk
- impl->disableRootTopologyUpdates = (Utils::strToInt(rt.get("noupdate","0").c_str()) > 0);
- } else {
- // Revert to built-in defaults if root topology fails signature check
- LOG("%s failed signature check, using built-in defaults instead",rootTopologyPath.c_str());
- Utils::rm(rootTopologyPath.c_str());
- RR->topology->setSupernodes(Dictionary(Dictionary(ZT_DEFAULTS.defaultRootTopology).get("supernodes","")));
- impl->disableRootTopologyUpdates = false;
- }
- } catch ( ... ) {
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format");
- }
- } else {
- try {
- Dictionary rt(impl->overrideRootTopology);
- RR->topology->setSupernodes(Dictionary(rt.get("supernodes","")));
- impl->disableRootTopologyUpdates = true;
- } catch ( ... ) {
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format");
- }
- }
-
- // Delete peers.persist if it exists -- legacy file, just takes up space
- Utils::rm(std::string(RR->homePath + ZT_PATH_SEPARATOR_S + "peers.persist").c_str());
- } catch (std::bad_alloc &exc) {
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"memory allocation failure");
- } catch (std::runtime_error &exc) {
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,exc.what());
- } catch ( ... ) {
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unknown exception during initialization");
- }
-
- // Core I/O loop
- try {
- /* Shut down if this file exists but fails to open. This is used on Mac to
- * shut down automatically on .app deletion by symlinking this to the
- * Info.plist file inside the ZeroTier One application. This causes the
- * service to die when the user throws away the app, allowing uninstallation
- * in the natural Mac way. */
- std::string shutdownIfUnreadablePath(RR->homePath + ZT_PATH_SEPARATOR_S + "shutdownIfUnreadable");
-
- uint64_t lastNetworkAutoconfCheck = Utils::now() - 5000ULL; // check autoconf again after 5s for startup
- uint64_t lastPingCheck = 0;
- uint64_t lastClean = Utils::now(); // don't need to do this immediately
- uint64_t lastMulticastCheck = 0;
- uint64_t lastSupernodePingCheck = 0;
- uint64_t lastBeacon = 0;
- uint64_t lastRootTopologyFetch = 0;
- uint64_t lastShutdownIfUnreadableCheck = 0;
- long lastDelayDelta = 0;
-
- RR->timeOfLastResynchronize = Utils::now();
-
- // We are up and running
- RR->initialized = true;
-
- while (impl->reasonForTermination == NODE_RUNNING) {
- uint64_t now = Utils::now();
- bool resynchronize = false;
-
- /* This is how the service automatically shuts down when the OSX .app is
- * thrown in the trash. It's not used on any other platform for now but
- * could do similar things. It's disabled on Windows since it doesn't really
- * work there. */
-#ifdef __UNIX_LIKE__
- if ((now - lastShutdownIfUnreadableCheck) > 10000) {
- lastShutdownIfUnreadableCheck = now;
- if (Utils::fileExists(shutdownIfUnreadablePath.c_str(),false)) {
- int tmpfd = ::open(shutdownIfUnreadablePath.c_str(),O_RDONLY,0);
- if (tmpfd < 0) {
- return impl->terminateBecause(Node::NODE_NORMAL_TERMINATION,"shutdownIfUnreadable exists but is not readable");
- } else ::close(tmpfd);
- }
- }
-#endif
-
- // If it looks like the computer slept and woke, resynchronize.
- if (lastDelayDelta >= ZT_SLEEP_WAKE_DETECTION_THRESHOLD) {
- resynchronize = true;
- LOG("probable suspend/resume detected, pausing a moment for things to settle...");
- Thread::sleep(ZT_SLEEP_WAKE_SETTLE_TIME);
- }
-
- // Supernodes do not resynchronize unless explicitly ordered via SIGHUP.
- if ((resynchronize)&&(RR->topology->amSupernode()))
- resynchronize = false;
-
- // Check for SIGHUP / force resync.
- if (impl->resynchronize) {
- impl->resynchronize = false;
- resynchronize = true;
- LOG("resynchronize forced by user, syncing with network");
- }
-
- if (resynchronize) {
- RR->tcpTunnelingEnabled = false; // turn off TCP tunneling master switch at first, will be reenabled on persistent UDP failure
- RR->timeOfLastResynchronize = now;
- }
-
- /* Supernodes are pinged separately and more aggressively. The
- * ZT_STARTUP_AGGRO parameter sets a limit on how rapidly they are
- * tried, while PingSupernodesThatNeedPing contains the logic for
- * determining if they need PING. */
- if ((now - lastSupernodePingCheck) >= ZT_STARTUP_AGGRO) {
- lastSupernodePingCheck = now;
-
- uint64_t lastReceiveFromAnySupernode = 0; // function object result paramter
- RR->topology->eachSupernodePeer(Topology::FindMostRecentDirectReceiveTimestamp(lastReceiveFromAnySupernode));
-
- // Turn on TCP tunneling master switch if we haven't heard anything since before
- // the last resynchronize and we've been trying long enough.
- uint64_t tlr = RR->timeOfLastResynchronize;
- if ((lastReceiveFromAnySupernode < tlr)&&((now - tlr) >= ZT_TCP_TUNNEL_FAILOVER_TIMEOUT)) {
- TRACE("network still unreachable after %u ms, TCP TUNNELING ENABLED",(unsigned int)ZT_TCP_TUNNEL_FAILOVER_TIMEOUT);
- RR->tcpTunnelingEnabled = true;
- }
-
- RR->topology->eachSupernodePeer(Topology::PingSupernodesThatNeedPing(RR,now));
- }
-
- if (resynchronize) {
- RR->sm->closeTcpSockets();
- } else {
- /* Periodically check for changes in our local multicast subscriptions
- * and broadcast those changes to directly connected peers. */
- if ((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD) {
- lastMulticastCheck = now;
- try {
- std::vector< SharedPtr<Network> > networks(RR->nc->networks());
- for(std::vector< SharedPtr<Network> >::const_iterator nw(networks.begin());nw!=networks.end();++nw)
- (*nw)->rescanMulticastGroups();
- } catch (std::exception &exc) {
- LOG("unexpected exception announcing multicast groups: %s",exc.what());
- } catch ( ... ) {
- LOG("unexpected exception announcing multicast groups: (unknown)");
- }
- }
-
- /* Periodically ping all our non-stale direct peers unless we're a supernode.
- * Supernodes only ping each other (which is done above). */
- if ((!RR->topology->amSupernode())&&((now - lastPingCheck) >= ZT_PING_CHECK_DELAY)) {
- lastPingCheck = now;
- try {
- RR->topology->eachPeer(Topology::PingPeersThatNeedPing(RR,now));
- } catch (std::exception &exc) {
- LOG("unexpected exception running ping check cycle: %s",exc.what());
- } catch ( ... ) {
- LOG("unexpected exception running ping check cycle: (unkonwn)");
- }
- }
- }
-
- // Update network configurations when needed.
- try {
- if ((resynchronize)||((now - lastNetworkAutoconfCheck) >= ZT_NETWORK_AUTOCONF_CHECK_DELAY)) {
- lastNetworkAutoconfCheck = now;
- std::vector< SharedPtr<Network> > nets(RR->nc->networks());
- for(std::vector< SharedPtr<Network> >::iterator n(nets.begin());n!=nets.end();++n) {
- if ((now - (*n)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)
- (*n)->requestConfiguration();
- }
- }
- } catch ( ... ) {
- LOG("unexpected exception updating network configurations (non-fatal, will retry)");
- }
-
- // Do periodic tasks in submodules.
- if ((now - lastClean) >= ZT_DB_CLEAN_PERIOD) {
- lastClean = now;
- try {
- RR->topology->clean(now);
- } catch ( ... ) {
- LOG("unexpected exception in Topology::clean() (non-fatal)");
- }
- try {
- RR->mc->clean(now);
- } catch ( ... ) {
- LOG("unexpected exception in Multicaster::clean() (non-fatal)");
- }
- try {
- RR->nc->clean();
- } catch ( ... ) {
- LOG("unexpected exception in NodeConfig::clean() (non-fatal)");
- }
- try {
- if (RR->updater)
- RR->updater->checkIfMaxIntervalExceeded(now);
- } catch ( ... ) {
- LOG("unexpected exception in SoftwareUpdater::checkIfMaxIntervalExceeded() (non-fatal)");
- }
- }
-
- // Send beacons to physical local LANs
- try {
- if ((resynchronize)||((now - lastBeacon) >= ZT_BEACON_INTERVAL)) {
- lastBeacon = now;
- char bcn[ZT_PROTO_BEACON_LENGTH];
- void *bcnptr = bcn;
- *((uint32_t *)(bcnptr)) = RR->prng->next32();
- bcnptr = bcn + 4;
- *((uint32_t *)(bcnptr)) = RR->prng->next32();
- RR->identity.address().copyTo(bcn + ZT_PROTO_BEACON_IDX_ADDRESS,ZT_ADDRESS_LENGTH);
- TRACE("sending LAN beacon to %s",ZT_DEFAULTS.v4Broadcast.toString().c_str());
- RR->antiRec->logOutgoingZT(bcn,ZT_PROTO_BEACON_LENGTH);
- RR->sm->send(ZT_DEFAULTS.v4Broadcast,false,false,bcn,ZT_PROTO_BEACON_LENGTH);
- }
- } catch ( ... ) {
- LOG("unexpected exception sending LAN beacon (non-fatal)");
- }
-
- // Check for updates to root topology (supernodes) periodically
- try {
- if ((now - lastRootTopologyFetch) >= ZT_UPDATE_ROOT_TOPOLOGY_CHECK_INTERVAL) {
- lastRootTopologyFetch = now;
- if (!impl->disableRootTopologyUpdates) {
- TRACE("fetching root topology from %s",ZT_DEFAULTS.rootTopologyUpdateURL.c_str());
- RR->http->GET(ZT_DEFAULTS.rootTopologyUpdateURL,HttpClient::NO_HEADERS,60,&_cbHandleGetRootTopology,RR);
- }
- }
- } catch ( ... ) {
- LOG("unexpected exception attempting to check for root topology updates (non-fatal)");
- }
-
- // Sleep for loop interval or until something interesting happens.
- try {
- unsigned long delay = std::min((unsigned long)ZT_MAX_SERVICE_LOOP_INTERVAL,RR->sw->doTimerTasks());
- uint64_t start = Utils::now();
- RR->sm->poll(delay,&_CBztTraffic,RR);
- lastDelayDelta = (long)(Utils::now() - start) - (long)delay; // used to detect sleep/wake
- } catch (std::exception &exc) {
- LOG("unexpected exception running Switch doTimerTasks: %s",exc.what());
- } catch ( ... ) {
- LOG("unexpected exception running Switch doTimerTasks: (unknown)");
- }
- }
- } catch ( ... ) {
- LOG("FATAL: unexpected exception in core loop: unknown exception");
- return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unexpected exception during outer main I/O loop");
- }
-
- return impl->terminate();
-}
-
-const char *Node::terminationMessage() const
- throw()
-{
- if ((!((_NodeImpl *)_impl)->started)||(((_NodeImpl *)_impl)->running))
- return (const char *)0;
- return ((_NodeImpl *)_impl)->reasonForTerminationStr.c_str();
-}
-
-void Node::terminate(ReasonForTermination reason,const char *reasonText)
- throw()
-{
- ((_NodeImpl *)_impl)->reasonForTermination = reason;
- ((_NodeImpl *)_impl)->reasonForTerminationStr = ((reasonText) ? reasonText : "");
- ((_NodeImpl *)_impl)->renv.sm->whack();
-}
-
-void Node::resync()
- throw()
-{
- ((_NodeImpl *)_impl)->resynchronize = true;
- ((_NodeImpl *)_impl)->renv.sm->whack();
-}
-
-bool Node::online()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
- if ((!RR)||(!RR->initialized))
- return false;
- uint64_t now = Utils::now();
- uint64_t since = RR->timeOfLastResynchronize;
- std::vector< SharedPtr<Peer> > snp(RR->topology->supernodePeers());
- for(std::vector< SharedPtr<Peer> >::const_iterator sn(snp.begin());sn!=snp.end();++sn) {
- uint64_t lastRec = (*sn)->lastDirectReceive();
- if ((lastRec)&&(lastRec > since)&&((now - lastRec) < ZT_PEER_PATH_ACTIVITY_TIMEOUT))
- return true;
- }
- return false;
-}
-
-bool Node::started()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- return impl->started;
-}
-
-bool Node::running()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- return impl->running;
-}
-
-bool Node::initialized()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
- return ((RR)&&(RR->initialized));
-}
-
-uint64_t Node::address()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
- if ((!RR)||(!RR->initialized))
- return 0;
- return RR->identity.address().toInt();
-}
-
-void Node::join(uint64_t nwid)
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
- if ((RR)&&(RR->initialized))
- RR->nc->join(nwid);
-}
-
-void Node::leave(uint64_t nwid)
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
- if ((RR)&&(RR->initialized))
- RR->nc->leave(nwid);
-}
-
-struct GatherPeerStatistics
-{
- uint64_t now;
- ZT1_Node_Status *status;
- inline void operator()(Topology &t,const SharedPtr<Peer> &p)
- {
- ++status->knownPeers;
- if (p->hasActiveDirectPath(now))
- ++status->directlyConnectedPeers;
- if (p->alive(now))
- ++status->alivePeers;
- }
-};
-void Node::status(ZT1_Node_Status *status)
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
-
- memset(status,0,sizeof(ZT1_Node_Status));
-
- if ((!RR)||(!RR->initialized))
- return;
-
- Utils::scopy(status->publicIdentity,sizeof(status->publicIdentity),RR->identity.toString(false).c_str());
- RR->identity.address().toString(status->address,sizeof(status->address));
- status->rawAddress = RR->identity.address().toInt();
-
- status->knownPeers = 0;
- status->supernodes = RR->topology->numSupernodes();
- status->directlyConnectedPeers = 0;
- status->alivePeers = 0;
- GatherPeerStatistics gps;
- gps.now = Utils::now();
- gps.status = status;
- RR->topology->eachPeer<GatherPeerStatistics &>(gps);
-
- if (status->alivePeers > 0) {
- double dlsr = (double)status->directlyConnectedPeers / (double)status->alivePeers;
- if (dlsr > 1.0) dlsr = 1.0;
- if (dlsr < 0.0) dlsr = 0.0;
- status->directLinkSuccessRate = (float)dlsr;
- } else status->directLinkSuccessRate = 1.0f; // no connections to no active peers == 100% success at nothing
-
- status->online = online();
- status->running = impl->running;
- status->initialized = true;
-}
-
-struct CollectPeersAndPaths
-{
- std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > > data;
- inline void operator()(Topology &t,const SharedPtr<Peer> &p) { this->data.push_back(std::pair< SharedPtr<Peer>,std::vector<Path> >(p,p->paths())); }
-};
-struct SortPeersAndPathsInAscendingAddressOrder
-{
- inline bool operator()(const std::pair< SharedPtr<Peer>,std::vector<Path> > &a,const std::pair< SharedPtr<Peer>,std::vector<Path> > &b) const { return (a.first->address() < b.first->address()); }
-};
-ZT1_Node_PeerList *Node::listPeers()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
-
- if ((!RR)||(!RR->initialized))
- return (ZT1_Node_PeerList *)0;
-
- CollectPeersAndPaths pp;
- RR->topology->eachPeer<CollectPeersAndPaths &>(pp);
- std::sort(pp.data.begin(),pp.data.end(),SortPeersAndPathsInAscendingAddressOrder());
-
- unsigned int returnBufSize = sizeof(ZT1_Node_PeerList);
- for(std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > >::iterator p(pp.data.begin());p!=pp.data.end();++p)
- returnBufSize += sizeof(ZT1_Node_Peer) + (sizeof(ZT1_Node_PhysicalPath) * (unsigned int)p->second.size());
-
- char *buf = (char *)::malloc(returnBufSize);
- if (!buf)
- return (ZT1_Node_PeerList *)0;
- memset(buf,0,returnBufSize);
-
- ZT1_Node_PeerList *pl = (ZT1_Node_PeerList *)buf;
- buf += sizeof(ZT1_Node_PeerList);
-
- pl->peers = (ZT1_Node_Peer *)buf;
- buf += (sizeof(ZT1_Node_Peer) * pp.data.size());
- pl->numPeers = 0;
-
- uint64_t now = Utils::now();
- for(std::vector< std::pair< SharedPtr<Peer>,std::vector<Path> > >::iterator p(pp.data.begin());p!=pp.data.end();++p) {
- ZT1_Node_Peer *prec = &(pl->peers[pl->numPeers++]);
- if (p->first->remoteVersionKnown())
- Utils::snprintf(prec->remoteVersion,sizeof(prec->remoteVersion),"%u.%u.%u",p->first->remoteVersionMajor(),p->first->remoteVersionMinor(),p->first->remoteVersionRevision());
- p->first->address().toString(prec->address,sizeof(prec->address));
- prec->rawAddress = p->first->address().toInt();
- prec->latency = p->first->latency();
- prec->role = RR->topology->isSupernode(p->first->address()) ? ZT1_Node_Peer_SUPERNODE : ZT1_Node_Peer_NODE;
-
- prec->paths = (ZT1_Node_PhysicalPath *)buf;
- buf += sizeof(ZT1_Node_PhysicalPath) * p->second.size();
-
- prec->numPaths = 0;
- for(std::vector<Path>::iterator pi(p->second.begin());pi!=p->second.end();++pi) {
- ZT1_Node_PhysicalPath *path = &(prec->paths[prec->numPaths++]);
- path->type = (ZT1_Node_PhysicalPathType)pi->type();
- if (pi->address().isV6()) {
- path->address.type = ZT1_Node_PhysicalAddress_TYPE_IPV6;
- memcpy(path->address.bits,pi->address().rawIpData(),16);
- // TODO: zoneIndex not supported yet, but should be once echo-location works w/V6
- } else {
- path->address.type = ZT1_Node_PhysicalAddress_TYPE_IPV4;
- memcpy(path->address.bits,pi->address().rawIpData(),4);
- }
- path->address.port = pi->address().port();
- Utils::scopy(path->address.ascii,sizeof(path->address.ascii),pi->address().toIpString().c_str());
- path->lastSend = (pi->lastSend() > 0) ? ((long)(now - pi->lastSend())) : (long)-1;
- path->lastReceive = (pi->lastReceived() > 0) ? ((long)(now - pi->lastReceived())) : (long)-1;
- path->lastPing = (pi->lastPing() > 0) ? ((long)(now - pi->lastPing())) : (long)-1;
- path->active = pi->active(now);
- path->fixed = pi->fixed();
- }
- }
-
- return pl;
-}
-
-// Fills out everything but ips[] and numIps, which must be done more manually
-static void _fillNetworkQueryResultBuffer(const SharedPtr<Network> &network,const SharedPtr<NetworkConfig> &nconf,ZT1_Node_Network *nbuf)
-{
- nbuf->nwid = network->id();
- Utils::snprintf(nbuf->nwidHex,sizeof(nbuf->nwidHex),"%.16llx",(unsigned long long)network->id());
- if (nconf) {
- Utils::scopy(nbuf->name,sizeof(nbuf->name),nconf->name().c_str());
- Utils::scopy(nbuf->description,sizeof(nbuf->description),nconf->description().c_str());
- }
- Utils::scopy(nbuf->device,sizeof(nbuf->device),network->tapDeviceName().c_str());
- Utils::scopy(nbuf->statusStr,sizeof(nbuf->statusStr),Network::statusString(network->status()));
- network->mac().toString(nbuf->macStr,sizeof(nbuf->macStr));
- network->mac().copyTo(nbuf->mac,sizeof(nbuf->mac));
- uint64_t lcu = network->lastConfigUpdate();
- if (lcu > 0)
- nbuf->configAge = (long)(Utils::now() - lcu);
- else nbuf->configAge = -1;
- nbuf->status = (ZT1_Node_NetworkStatus)network->status();
- nbuf->enabled = network->enabled();
- nbuf->isPrivate = (nconf) ? nconf->isPrivate() : true;
-}
-
-ZT1_Node_Network *Node::getNetworkStatus(uint64_t nwid)
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
-
- if ((!RR)||(!RR->initialized))
- return (ZT1_Node_Network *)0;
-
- SharedPtr<Network> network(RR->nc->network(nwid));
- if (!network)
- return (ZT1_Node_Network *)0;
- SharedPtr<NetworkConfig> nconf(network->config2());
- std::set<InetAddress> ips(network->ips());
-
- char *buf = (char *)::malloc(sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * ips.size()));
- if (!buf)
- return (ZT1_Node_Network *)0;
- memset(buf,0,sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * ips.size()));
-
- ZT1_Node_Network *nbuf = (ZT1_Node_Network *)buf;
- buf += sizeof(ZT1_Node_Network);
-
- _fillNetworkQueryResultBuffer(network,nconf,nbuf);
-
- nbuf->ips = (ZT1_Node_PhysicalAddress *)buf;
- nbuf->numIps = 0;
- for(std::set<InetAddress>::iterator ip(ips.begin());ip!=ips.end();++ip) {
- ZT1_Node_PhysicalAddress *ipb = &(nbuf->ips[nbuf->numIps++]);
- if (ip->isV6()) {
- ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV6;
- memcpy(ipb->bits,ip->rawIpData(),16);
- } else {
- ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV4;
- memcpy(ipb->bits,ip->rawIpData(),4);
- }
- ipb->port = ip->port();
- Utils::scopy(ipb->ascii,sizeof(ipb->ascii),ip->toIpString().c_str());
- }
-
- return nbuf;
-}
-
-ZT1_Node_NetworkList *Node::listNetworks()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
-
- if ((!RR)||(!RR->initialized))
- return (ZT1_Node_NetworkList *)0;
-
- std::vector< SharedPtr<Network> > networks(RR->nc->networks());
- std::vector< SharedPtr<NetworkConfig> > nconfs(networks.size());
- std::vector< std::set<InetAddress> > ipsv(networks.size());
-
- unsigned long returnBufSize = sizeof(ZT1_Node_NetworkList);
- for(unsigned long i=0;i<networks.size();++i) {
- nconfs[i] = networks[i]->config2(); // note: can return NULL
- ipsv[i] = networks[i]->ips();
- returnBufSize += sizeof(ZT1_Node_Network) + (sizeof(ZT1_Node_PhysicalAddress) * (unsigned int)ipsv[i].size());
- }
-
- char *buf = (char *)::malloc(returnBufSize);
- if (!buf)
- return (ZT1_Node_NetworkList *)0;
- memset(buf,0,returnBufSize);
-
- ZT1_Node_NetworkList *nl = (ZT1_Node_NetworkList *)buf;
- buf += sizeof(ZT1_Node_NetworkList);
-
- nl->networks = (ZT1_Node_Network *)buf;
- buf += sizeof(ZT1_Node_Network) * networks.size();
-
- for(unsigned long i=0;i<networks.size();++i) {
- ZT1_Node_Network *nbuf = &(nl->networks[nl->numNetworks++]);
-
- _fillNetworkQueryResultBuffer(networks[i],nconfs[i],nbuf);
-
- nbuf->ips = (ZT1_Node_PhysicalAddress *)buf;
- buf += sizeof(ZT1_Node_PhysicalAddress) * ipsv[i].size();
-
- nbuf->numIps = 0;
- for(std::set<InetAddress>::iterator ip(ipsv[i].begin());ip!=ipsv[i].end();++ip) {
- ZT1_Node_PhysicalAddress *ipb = &(nbuf->ips[nbuf->numIps++]);
- if (ip->isV6()) {
- ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV6;
- memcpy(ipb->bits,ip->rawIpData(),16);
- } else {
- ipb->type = ZT1_Node_PhysicalAddress_TYPE_IPV4;
- memcpy(ipb->bits,ip->rawIpData(),4);
- }
- ipb->port = ip->port();
- Utils::scopy(ipb->ascii,sizeof(ipb->ascii),ip->toIpString().c_str());
- }
- }
-
- return nl;
-}
-
-void Node::freeQueryResult(void *qr)
- throw()
-{
- if (qr)
- ::free(qr);
-}
-
-bool Node::updateCheck()
- throw()
-{
- _NodeImpl *impl = (_NodeImpl *)_impl;
- RuntimeEnvironment *RR = (RuntimeEnvironment *)&(impl->renv);
- if (RR->updater) {
- RR->updater->checkNow();
- return true;
- }
- return false;
-}
-
-class _VersionStringMaker
-{
-public:
- char vs[32];
- _VersionStringMaker()
- {
- Utils::snprintf(vs,sizeof(vs),"%d.%d.%d",(int)ZEROTIER_ONE_VERSION_MAJOR,(int)ZEROTIER_ONE_VERSION_MINOR,(int)ZEROTIER_ONE_VERSION_REVISION);
- }
- ~_VersionStringMaker() {}
-};
-static const _VersionStringMaker __versionString;
-
-const char *Node::versionString() throw() { return __versionString.vs; }
-
-unsigned int Node::versionMajor() throw() { return ZEROTIER_ONE_VERSION_MAJOR; }
-unsigned int Node::versionMinor() throw() { return ZEROTIER_ONE_VERSION_MINOR; }
-unsigned int Node::versionRevision() throw() { return ZEROTIER_ONE_VERSION_REVISION; }
-
-} // namespace ZeroTier
diff --git a/attic/Node.hpp b/attic/Node.hpp
deleted file mode 100644
index c75b884f..00000000
--- a/attic/Node.hpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_NODE_HPP
-#define ZT_NODE_HPP
-
-#include <stdint.h>
-
-#include "../include/ZeroTierOne.h"
-
-namespace ZeroTier {
-
-class EthernetTapFactory;
-class RoutingTable;
-class SocketManager;
-class NetworkConfigMaster;
-
-/**
- * A ZeroTier One node
- */
-class Node
-{
-public:
- /**
- * Returned by node main if/when it terminates
- */
- enum ReasonForTermination
- {
- /**
- * Node is currently in run()
- */
- NODE_RUNNING = 0,
-
- /**
- * Node is shutting down for normal reasons, including a signal
- */
- NODE_NORMAL_TERMINATION = 1,
-
- /**
- * An upgrade is available. Its path is in reasonForTermination().
- */
- NODE_RESTART_FOR_UPGRADE = 2,
-
- /**
- * A serious unrecoverable error has occurred.
- */
- NODE_UNRECOVERABLE_ERROR = 3,
-
- /**
- * An address collision occurred (typically this should cause re-invocation with resetIdentity set to true)
- */
- NODE_ADDRESS_COLLISION = 4
- };
-
- /**
- * Create a new node
- *
- * The node is not executed until run() is called. The supplied tap factory
- * and routing table must not be freed until the node is no longer
- * executing. Node does not delete these objects; the caller still owns
- * them.
- *
- * @param hp Home directory path or NULL for system-wide default for this platform
- * @param tf Ethernet tap factory for platform network stack
- * @param sm Socket manager for physical network I/O
- * @param nm Network configuration master or NULL for none
- * @param resetIdentity If true, delete identity before starting and regenerate
- * @param overrideRootTopology Override root topology with this dictionary (in string serialized format) and do not update (default: NULL for none)
- */
- Node(
- const char *hp,
- EthernetTapFactory *tf,
- SocketManager *sm,
- NetworkConfigMaster *nm,
- bool resetIdentity,
- const char *overrideRootTopology = (const char *)0) throw();
-
- ~Node();
-
- /**
- * Execute node in current thread, return on shutdown
- *
- * @return Reason for termination
- */
- ReasonForTermination run()
- throw();
-
- /**
- * Obtain a human-readable reason for node termination
- *
- * @return Reason for node termination or NULL if run() has not returned
- */
- const char *terminationMessage() const
- throw();
-
- /**
- * Terminate this node, causing run() to return
- *
- * @param reason Reason for termination
- * @param reasonText Text to be returned by terminationMessage()
- */
- void terminate(ReasonForTermination reason,const char *reasonText)
- throw();
-
- /**
- * Forget p2p links now and resynchronize with peers
- *
- * This can be used if the containing application knows its network environment has
- * changed. ZeroTier itself tries to detect such changes, but is not always successful.
- */
- void resync()
- throw();
-
- /**
- * @return True if we appear to be online in some viable capacity
- */
- bool online()
- throw();
-
- /**
- * @return True if run() has been called
- */
- bool started()
- throw();
-
- /**
- * @return True if run() has not yet returned
- */
- bool running()
- throw();
-
- /**
- * @return True if initialization phase of startup is complete
- */
- bool initialized()
- throw();
-
- /**
- * @return This node's address (in least significant 40 bits of 64-bit int) or 0 if not yet initialized
- */
- uint64_t address()
- throw();
-
- /**
- * Join a network
- *
- * Use getNetworkStatus() to check the network's status after joining. If you
- * are already a member of the network, this does nothing.
- *
- * @param nwid 64-bit network ID
- */
- void join(uint64_t nwid)
- throw();
-
- /**
- * Leave a network (if a member)
- *
- * @param nwid 64-bit network ID
- */
- void leave(uint64_t nwid)
- throw();
-
- /**
- * Get the status of this node
- *
- * @param status Buffer to fill with status information
- */
- void status(ZT1_Node_Status *status)
- throw();
-
- /**
- * @return List of known peers or NULL on failure
- */
- ZT1_Node_PeerList *listPeers()
- throw();
-
- /**
- * @param nwid 64-bit network ID
- * @return Network status or NULL if we are not a member of this network
- */
- ZT1_Node_Network *getNetworkStatus(uint64_t nwid)
- throw();
-
- /**
- * @return List of networks we've joined or NULL on failure
- */
- ZT1_Node_NetworkList *listNetworks()
- throw();
-
- /**
- * Free a query result buffer
- *
- * Use this to free the return values of listNetworks(), listPeers(), etc.
- *
- * @param qr Query result buffer
- */
- void freeQueryResult(void *qr)
- throw();
-
- /**
- * Check for software updates (if enabled) (updates will eventually get factored out of node/)
- */
- bool updateCheck()
- throw();
-
- static const char *versionString() throw();
- static unsigned int versionMajor() throw();
- static unsigned int versionMinor() throw();
- static unsigned int versionRevision() throw();
-
-private:
- // Nodes are not copyable
- Node(const Node&);
- const Node& operator=(const Node&);
-
- void *const _impl; // private implementation
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/attic/WindowsEthernetTapFactory.cpp b/attic/WindowsEthernetTapFactory.cpp
deleted file mode 100644
index 996460a1..00000000
--- a/attic/WindowsEthernetTapFactory.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include "WindowsEthernetTapFactory.hpp"
-#include "WindowsEthernetTap.hpp"
-
-namespace ZeroTier {
-
-WindowsEthernetTapFactory::Env::Env()
-{
-#ifdef _WIN64
- is64Bit = TRUE;
- devcon = "\\devcon_x64.exe";
- tapDriver = "\\tap-windows\\x64\\zttap200.inf";
-#else
- is64Bit = FALSE;
- IsWow64Process(GetCurrentProcess(),&is64Bit);
- devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe");
- tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf");
-#endif
-}
-const WindowsEthernetTapFactory::Env WindowsEthernetTapFactory::WINENV;
-
-WindowsEthernetTapFactory::WindowsEthernetTapFactory(const char *pathToHelpers) :
- _pathToHelpers(pathToHelpers)
-{
-}
-
-WindowsEthernetTapFactory::~WindowsEthernetTapFactory()
-{
- Mutex::Lock _l(_devices_m);
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
- delete *d;
-}
-
-EthernetTap *WindowsEthernetTapFactory::open(
- const MAC &mac,
- unsigned int mtu,
- unsigned int metric,
- uint64_t nwid,
- const char *desiredDevice,
- const char *friendlyName,
- void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
- void *arg)
-{
- Mutex::Lock _l(_devices_m);
- EthernetTap *t = new WindowsEthernetTap(_pathToHelpers.c_str(),mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
- _devices.push_back(t);
- return t;
-}
-
-void WindowsEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
-{
- if (!tap)
- return;
-
- std::string instanceId(((WindowsEthernetTap *)tap)->instanceId());
- Mutex::Lock _l(_devices_m);
-
- for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
- if (*d == tap) {
- _devices.erase(d);
- break;
- }
- }
-
- delete tap;
-
- if (destroyPersistentDevices)
- _deletePersistentTapDevice(_pathToHelpers.c_str(),instanceId.c_str());
-}
-
-void WindowsEthernetTapFactory::destroyAllPersistentTapDevices(const char *pathToHelpers)
-{
- char subkeyName[4096];
- char subkeyClass[4096];
- char data[4096];
-
- std::set<std::string> instanceIdPathsToRemove;
- {
- HKEY nwAdapters;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS)
- return;
-
- for(DWORD subkeyIndex=0;;++subkeyIndex) {
- DWORD type;
- DWORD dataLen;
- DWORD subkeyNameLen = sizeof(subkeyName);
- DWORD subkeyClassLen = sizeof(subkeyClass);
- FILETIME lastWriteTime;
- if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) {
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) {
- data[dataLen] = '\0';
- if (!strnicmp(data,"zttap",5)) {
- std::string instanceIdPath;
- type = 0;
- dataLen = sizeof(data);
- if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
- instanceIdPath.assign(data,dataLen);
- if (instanceIdPath.length() != 0)
- instanceIdPathsToRemove.insert(instanceIdPath);
- }
- }
- } else break; // end of list or failure
- }
-
- RegCloseKey(nwAdapters);
- }
-
- for(std::set<std::string>::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp)
- _deletePersistentTapDevice(pathToHelpers,iidp->c_str());
-}
-
-void WindowsEthernetTapFactory::_deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId)
-{
- HANDLE devconLog = CreateFileA((std::string(pathToHelpers) + "\\devcon.log").c_str(),GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
- STARTUPINFOA startupInfo;
- startupInfo.cb = sizeof(startupInfo);
- if (devconLog != INVALID_HANDLE_VALUE) {
- SetFilePointer(devconLog,0,0,FILE_END);
- startupInfo.hStdOutput = devconLog;
- startupInfo.hStdError = devconLog;
- }
- PROCESS_INFORMATION processInfo;
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (CreateProcessA(NULL,(LPSTR)(std::string("\"") + pathToHelpers + WINENV.devcon + "\" remove @" + instanceId).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
- }
- if (devconLog != INVALID_HANDLE_VALUE)
- CloseHandle(devconLog);
-}
-
-} // namespace ZeroTier
diff --git a/attic/WindowsEthernetTapFactory.hpp b/attic/WindowsEthernetTapFactory.hpp
deleted file mode 100644
index 47e146e3..00000000
--- a/attic/WindowsEthernetTapFactory.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_WINDOWSETHERNETTAPFACTORY_HPP
-#define ZT_WINDOWSETHERNETTAPFACTORY_HPP
-
-#include <vector>
-#include <string>
-
-#include "../node/EthernetTapFactory.hpp"
-#include "../node/Mutex.hpp"
-
-namespace ZeroTier {
-
-class WindowsEthernetTapFactory : public EthernetTapFactory
-{
-public:
- class Env
- {
- public:
- Env();
- BOOL is64Bit; // true if WIN64 or WoW64 (32-bit binary on 64-bit architecture)
- const char *devcon; // name of devcon binary in pathToHelpers to use
- const char *tapDriver; // relative path to driver under pathToHelpers to use
- };
-
- /**
- * Constants related to Windows environment, computed on program start
- */
- static const Env WINENV;
-
- /**
- * @param pathToHelpers Path to devcon32.exe, devcon64.exe, and other required helper binaries (ZeroTier running directory)
- */
- WindowsEthernetTapFactory(const char *pathToHelpers);
- virtual ~WindowsEthernetTapFactory();
-
- virtual EthernetTap *open(
- const MAC &mac,
- unsigned int mtu,
- unsigned int metric,
- uint64_t nwid,
- const char *desiredDevice,
- const char *friendlyName,
- void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
- void *arg);
- virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
-
- /**
- * Uninstalls all persistent tap devices in the system belonging to ZeroTier
- *
- * This is for uninstallation. Do not call this while tap devices are active.
- */
- static void destroyAllPersistentTapDevices(const char *pathToHelpers);
-
-private:
- static void _deletePersistentTapDevice(const char *pathToHelpers,const char *instanceId);
-
- std::string _pathToHelpers;
- std::vector<EthernetTap *> _devices;
- Mutex _devices_m;
-};
-
-} // namespace ZeroTier
-
-#endif
diff --git a/attic/main.cpp b/attic/main.cpp
deleted file mode 100644
index 60a03b7b..00000000
--- a/attic/main.cpp
+++ /dev/null
@@ -1,887 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015 ZeroTier, Inc.
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-// Uncomment on Windows to assume -C and run in console instead of service
-// Useful for Visual Studio debugging (launch VS as Administrator to run)
-//#define ZT_WIN_RUN_IN_CONSOLE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-
-#include <string>
-#include <stdexcept>
-
-#include "node/Constants.hpp"
-
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#include <Windows.h>
-#include <tchar.h>
-#include <wchar.h>
-#include <lmcons.h>
-#include <newdev.h>
-#include <atlbase.h>
-#include "windows/ZeroTierOne/ServiceInstaller.h"
-#include "windows/ZeroTierOne/ServiceBase.h"
-#include "windows/ZeroTierOne/ZeroTierOneService.h"
-#else
-#include <unistd.h>
-#include <pwd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <signal.h>
-#endif
-
-#include "node/Constants.hpp"
-
-#include "node/Defaults.hpp"
-#include "node/Utils.hpp"
-#include "node/Node.hpp"
-#include "node/C25519.hpp"
-#include "node/Identity.hpp"
-#include "node/Thread.hpp"
-#include "node/CertificateOfMembership.hpp"
-#include "node/EthernetTapFactory.hpp"
-#include "node/SocketManager.hpp"
-
-#include "control/NodeControlClient.hpp"
-#include "control/NodeControlService.hpp"
-
-#include "osdep/NativeSocketManager.hpp"
-
-#ifdef ZT_ENABLE_NETCONF_MASTER
-#include "netconf/SqliteNetworkConfigMaster.hpp"
-#endif // ZT_ENABLE_NETCONF_MASTER
-
-#ifdef __WINDOWS__
-#include "osdep/WindowsEthernetTapFactory.hpp"
-#define ZTCreatePlatformEthernetTapFactory (new WindowsEthernetTapFactory(homeDir))
-#endif // __WINDOWS__
-
-#ifdef __LINUX__
-#include "osdep/LinuxEthernetTapFactory.hpp"
-#define ZTCreatePlatformEthernetTapFactory (new LinuxEthernetTapFactory())
-#endif // __LINUX__
-
-#ifdef __APPLE__
-#include "osdep/OSXEthernetTapFactory.hpp"
-#define ZTCreatePlatformEthernetTapFactory (new OSXEthernetTapFactory(homeDir,"tap.kext"))
-#endif // __APPLE__
-
-#ifndef ZTCreatePlatformEthernetTapFactory
-#ifdef __BSD__
-#include "osdep/BSDEthernetTapFactory.hpp"
-#define ZTCreatePlatformEthernetTapFactory (new BSDEthernetTapFactory())
-#else
-#error Sorry, this platform has no osdep/ implementation yet. Fork me on GitHub and add one?
-#endif // __BSD__
-#endif // ZTCreatePlatformEthernetTapFactory
-
-using namespace ZeroTier;
-
-static Node *node = (Node *)0;
-
-namespace ZeroTierCLI { // ---------------------------------------------------
-
-static void printHelp(FILE *out,const char *cn)
-{
- fprintf(out,"Usage: %s <command> (use 'help' for help)"ZT_EOL_S,cn);
-}
-
-static void _CBresultHandler(void *arg,const char *line)
-{
- if (line) {
- if ((line[0] == '.')&&(line[1] == (char)0)) {
- fflush(stdout);
- ::exit(0); // terminate CLI on end of message
- } else {
- fprintf(stdout,"%s"ZT_EOL_S,line);
- }
- }
-}
-
-#ifdef __WINDOWS__
-static int main(const char *homeDir,int argc,_TCHAR* argv[])
-#else
-static int main(const char *homeDir,int argc,char **argv)
-#endif
-{
- if (argc < 2) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- std::string query;
- for(int i=1;i<argc;++i) {
- if (argv[i][0] == '-') {
- switch(argv[i][1]) {
- case 'q': // ignore -q since it's used to invoke this
- break;
- case 'h':
- default:
- printHelp(stdout,argv[0]);
- return 1;
- }
- } else if ((!homeDir)||(strcmp(homeDir,argv[i]))) {
- if (query.length())
- query.push_back(' ');
- query.append(argv[i]);
- }
- }
- if (!query.length()) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- if (!homeDir)
- homeDir = ZT_DEFAULTS.defaultHomePath.c_str();
-
- try {
- std::string buf;
- if (!Utils::readFile((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),buf)) {
- fprintf(stderr,"%s: fatal error: unable to read node address from identity.public in home path"ZT_EOL_S,argv[0]);
- return 1;
- }
- Identity id;
- if (!id.fromString(buf)) {
- fprintf(stderr,"%s: fatal error: unable to read node address from identity.public in home path"ZT_EOL_S,argv[0]);
- return 1;
- }
-
- std::string authToken(NodeControlClient::getAuthToken((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),false));
- if (!authToken.length())
- authToken = NodeControlClient::getAuthToken(NodeControlClient::authTokenDefaultUserPath(),false);
- if (!authToken.length()) {
- fprintf(stderr,"%s: fatal error: unable to read authentication token from home path or user home"ZT_EOL_S,argv[0]);
- return 1;
- }
-
- NodeControlClient client((std::string(ZT_IPC_ENDPOINT_BASE) + id.address().toString()).c_str(),authToken.c_str(),&_CBresultHandler,(void *)0);
- const char *err = client.error();
- if (err) {
- fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],err);
- return 1;
- }
- client.send(query.c_str());
- for(;;) { Thread::sleep(60000); } // exit() is called at end of message from handler
- } catch (std::exception &exc) {
- fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],exc.what());
- return 1;
- } catch ( ... ) {
- fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (unknown exception)"ZT_EOL_S,argv[0]);
- return 1;
- }
-
- return 0;
-}
-
-} // namespace ZeroTierCLI ---------------------------------------------------
-
-namespace ZeroTierIdTool { // ------------------------------------------------
-
-static void printHelp(FILE *out,const char *pn)
-{
- fprintf(out,"Usage: %s <command> [<args>]"ZT_EOL_S""ZT_EOL_S"Commands:"ZT_EOL_S,pn);
- fprintf(out," generate [<identity.secret>] [<identity.public>]"ZT_EOL_S);
- fprintf(out," validate <identity.secret/public>"ZT_EOL_S);
- fprintf(out," getpublic <identity.secret>"ZT_EOL_S);
- fprintf(out," sign <identity.secret> <file>"ZT_EOL_S);
- fprintf(out," verify <identity.secret/public> <file> <signature>"ZT_EOL_S);
- fprintf(out," mkcom <identity.secret> [<id,value,maxDelta> ...] (hexadecimal integers)"ZT_EOL_S);
-}
-
-static Identity getIdFromArg(char *arg)
-{
- Identity id;
- if ((strlen(arg) > 32)&&(arg[10] == ':')) { // identity is a literal on the command line
- if (id.fromString(arg))
- return id;
- } else { // identity is to be read from a file
- std::string idser;
- if (Utils::readFile(arg,idser)) {
- if (id.fromString(idser))
- return id;
- }
- }
- return Identity();
-}
-
-#ifdef __WINDOWS__
-static int main(int argc,_TCHAR* argv[])
-#else
-static int main(int argc,char **argv)
-#endif
-{
- if (argc < 2) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- if (!strcmp(argv[1],"generate")) {
- Identity id;
- id.generate();
- std::string idser = id.toString(true);
- if (argc >= 3) {
- if (!Utils::writeFile(argv[2],idser)) {
- fprintf(stderr,"Error writing to %s"ZT_EOL_S,argv[2]);
- return 1;
- } else printf("%s written"ZT_EOL_S,argv[2]);
- if (argc >= 4) {
- idser = id.toString(false);
- if (!Utils::writeFile(argv[3],idser)) {
- fprintf(stderr,"Error writing to %s"ZT_EOL_S,argv[3]);
- return 1;
- } else printf("%s written"ZT_EOL_S,argv[3]);
- }
- } else printf("%s",idser.c_str());
- } else if (!strcmp(argv[1],"validate")) {
- if (argc < 3) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- Identity id = getIdFromArg(argv[2]);
- if (!id) {
- fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
- return 1;
- }
-
- if (!id.locallyValidate()) {
- fprintf(stderr,"%s FAILED validation."ZT_EOL_S,argv[2]);
- return 1;
- } else printf("%s is a valid identity"ZT_EOL_S,argv[2]);
- } else if (!strcmp(argv[1],"getpublic")) {
- if (argc < 3) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- Identity id = getIdFromArg(argv[2]);
- if (!id) {
- fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
- return 1;
- }
-
- printf("%s",id.toString(false).c_str());
- } else if (!strcmp(argv[1],"sign")) {
- if (argc < 4) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- Identity id = getIdFromArg(argv[2]);
- if (!id) {
- fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
- return 1;
- }
-
- if (!id.hasPrivate()) {
- fprintf(stderr,"%s does not contain a private key (must use private to sign)"ZT_EOL_S,argv[2]);
- return 1;
- }
-
- std::string inf;
- if (!Utils::readFile(argv[3],inf)) {
- fprintf(stderr,"%s is not readable"ZT_EOL_S,argv[3]);
- return 1;
- }
- C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length());
- printf("%s",Utils::hex(signature.data,(unsigned int)signature.size()).c_str());
- } else if (!strcmp(argv[1],"verify")) {
- if (argc < 4) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- Identity id = getIdFromArg(argv[2]);
- if (!id) {
- fprintf(stderr,"Identity argument invalid or file unreadable: %s"ZT_EOL_S,argv[2]);
- return 1;
- }
-
- std::string inf;
- if (!Utils::readFile(argv[3],inf)) {
- fprintf(stderr,"%s is not readable"ZT_EOL_S,argv[3]);
- return 1;
- }
-
- std::string signature(Utils::unhex(argv[4]));
- if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) {
- printf("%s signature valid"ZT_EOL_S,argv[3]);
- } else {
- fprintf(stderr,"%s signature check FAILED"ZT_EOL_S,argv[3]);
- return 1;
- }
- } else if (!strcmp(argv[1],"mkcom")) {
- if (argc < 3) {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- Identity id = getIdFromArg(argv[2]);
- if ((!id)||(!id.hasPrivate())) {
- fprintf(stderr,"Identity argument invalid, does not include private key, or file unreadable: %s"ZT_EOL_S,argv[2]);
- return 1;
- }
-
- CertificateOfMembership com;
- for(int a=3;a<argc;++a) {
- std::vector<std::string> params(Utils::split(argv[a],",","",""));
- if (params.size() == 3) {
- uint64_t qId = Utils::hexStrToU64(params[0].c_str());
- uint64_t qValue = Utils::hexStrToU64(params[1].c_str());
- uint64_t qMaxDelta = Utils::hexStrToU64(params[2].c_str());
- com.setQualifier(qId,qValue,qMaxDelta);
- }
- }
- if (!com.sign(id)) {
- fprintf(stderr,"Signature of certificate of membership failed."ZT_EOL_S);
- return 1;
- }
-
- printf("%s",com.toString().c_str());
- } else {
- printHelp(stdout,argv[0]);
- return 1;
- }
-
- return 0;
-}
-
-} // namespace ZeroTierIdTool ------------------------------------------------
-
-#ifdef __UNIX_LIKE__
-static void sighandlerHup(int sig)
-{
- Node *n = node;
- if (n)
- n->resync();
-}
-static void sighandlerQuit(int sig)
-{
- Node *n = node;
- if (n)
- n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal");
- else exit(0);
-}
-#endif
-
-#ifdef __WINDOWS__
-// Console signal handler routine to allow CTRL+C to work, mostly for testing
-static BOOL WINAPI _winConsoleCtrlHandler(DWORD dwCtrlType)
-{
- switch(dwCtrlType) {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- case CTRL_CLOSE_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- Node *n = node;
- if (n)
- n->terminate(Node::NODE_NORMAL_TERMINATION,"terminated by signal");
- return TRUE;
- }
- return FALSE;
-}
-
-// Pokes a hole in the Windows firewall (advfirewall) for the running program
-static void _winPokeAHole()
-{
- char myPath[MAX_PATH];
- DWORD ps = GetModuleFileNameA(NULL,myPath,sizeof(myPath));
- if ((ps > 0)&&(ps < (DWORD)sizeof(myPath))) {
- STARTUPINFOA startupInfo;
- PROCESS_INFORMATION processInfo;
-
- startupInfo.cb = sizeof(startupInfo);
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall delete rule name=\"ZeroTier One\" program=\"") + myPath + "\"").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
- }
-
- startupInfo.cb = sizeof(startupInfo);
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=in action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
- }
-
- startupInfo.cb = sizeof(startupInfo);
- memset(&startupInfo,0,sizeof(STARTUPINFOA));
- memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\netsh.exe advfirewall firewall add rule name=\"ZeroTier One\" dir=out action=allow program=\"") + myPath + "\" enable=yes").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
- WaitForSingleObject(processInfo.hProcess,INFINITE);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
- }
- }
-}
-
-// Returns true if this is running as the local administrator
-static BOOL IsCurrentUserLocalAdministrator(void)
-{
- BOOL fReturn = FALSE;
- DWORD dwStatus;
- DWORD dwAccessMask;
- DWORD dwAccessDesired;
- DWORD dwACLSize;
- DWORD dwStructureSize = sizeof(PRIVILEGE_SET);
- PACL pACL = NULL;
- PSID psidAdmin = NULL;
-
- HANDLE hToken = NULL;
- HANDLE hImpersonationToken = NULL;
-
- PRIVILEGE_SET ps;
- GENERIC_MAPPING GenericMapping;
-
- PSECURITY_DESCRIPTOR psdAdmin = NULL;
- SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY;
-
- const DWORD ACCESS_READ = 1;
- const DWORD ACCESS_WRITE = 2;
-
- __try
- {
- if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY,TRUE,&hToken))
- {
- if (GetLastError() != ERROR_NO_TOKEN)
- __leave;
- if (!OpenProcessToken(GetCurrentProcess(),TOKEN_DUPLICATE|TOKEN_QUERY, &hToken))
- __leave;
- }
- if (!DuplicateToken (hToken, SecurityImpersonation,&hImpersonationToken))
- __leave;
- if (!AllocateAndInitializeSid(&SystemSidAuthority, 2,
- SECURITY_BUILTIN_DOMAIN_RID,
- DOMAIN_ALIAS_RID_ADMINS,
- 0, 0, 0, 0, 0, 0, &psidAdmin))
- __leave;
- psdAdmin = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
- if (psdAdmin == NULL)
- __leave;
- if (!InitializeSecurityDescriptor(psdAdmin,SECURITY_DESCRIPTOR_REVISION))
- __leave;
- dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD);
- pACL = (PACL)LocalAlloc(LPTR, dwACLSize);
- if (pACL == NULL)
- __leave;
- if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2))
- __leave;
- dwAccessMask= ACCESS_READ | ACCESS_WRITE;
- if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin))
- __leave;
- if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE))
- __leave;
-
- SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE);
- SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE);
-
- if (!IsValidSecurityDescriptor(psdAdmin))
- __leave;
- dwAccessDesired = ACCESS_READ;
-
- GenericMapping.GenericRead = ACCESS_READ;
- GenericMapping.GenericWrite = ACCESS_WRITE;
- GenericMapping.GenericExecute = 0;
- GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE;
-
- if (!AccessCheck(psdAdmin, hImpersonationToken, dwAccessDesired,
- &GenericMapping, &ps, &dwStructureSize, &dwStatus,
- &fReturn))
- {
- fReturn = FALSE;
- __leave;
- }
- }
- __finally
- {
- // Clean up.
- if (pACL) LocalFree(pACL);
- if (psdAdmin) LocalFree(psdAdmin);
- if (psidAdmin) FreeSid(psidAdmin);
- if (hImpersonationToken) CloseHandle (hImpersonationToken);
- if (hToken) CloseHandle (hToken);
- }
-
- return fReturn;
-}
-#endif // __WINDOWS__
-
-// ---------------------------------------------------------------------------
-
-static void printHelp(const char *cn,FILE *out)
-{
- fprintf(out,"ZeroTier One version %d.%d.%d"ZT_EOL_S"(c)2011-2014 ZeroTier Networks LLC"ZT_EOL_S,Node::versionMajor(),Node::versionMinor(),Node::versionRevision());
- fprintf(out,"Licensed under the GNU General Public License v3"ZT_EOL_S""ZT_EOL_S);
-#ifdef ZT_AUTO_UPDATE
- fprintf(out,"Auto-update enabled build, will update from URL:"ZT_EOL_S);
- fprintf(out," %s"ZT_EOL_S,ZT_DEFAULTS.updateLatestNfoURL.c_str());
- fprintf(out,"Update authentication signing authorities: "ZT_EOL_S);
- int no = 0;
- for(std::map< Address,Identity >::const_iterator sa(ZT_DEFAULTS.updateAuthorities.begin());sa!=ZT_DEFAULTS.updateAuthorities.end();++sa) {
- if (no == 0)
- fprintf(out," %s",sa->first.toString().c_str());
- else fprintf(out,", %s",sa->first.toString().c_str());
- if (++no == 6) {
- fprintf(out,ZT_EOL_S);
- no = 0;
- }
- }
- fprintf(out,ZT_EOL_S""ZT_EOL_S);
-#else
- fprintf(out,"Auto-updates not enabled on this build. You must update manually."ZT_EOL_S""ZT_EOL_S);
-#endif
- fprintf(out,"Usage: %s [-switches] [home directory] [-q <query>]"ZT_EOL_S""ZT_EOL_S,cn);
- fprintf(out,"Available switches:"ZT_EOL_S);
- fprintf(out," -h - Display this help"ZT_EOL_S);
- fprintf(out," -v - Show version"ZT_EOL_S);
- fprintf(out," -p<port> - Port for UDP (default: 9993)"ZT_EOL_S);
- fprintf(out," -t<port> - Port for TCP (default: disabled)"ZT_EOL_S);
- //fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S);
-#ifdef __UNIX_LIKE__
- fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)"ZT_EOL_S);
-#endif
- fprintf(out," -q - Send a query to a running service (zerotier-cli)"ZT_EOL_S);
- fprintf(out," -i - Generate and manage identities (zerotier-idtool)"ZT_EOL_S);
-#ifdef __WINDOWS__
- fprintf(out," -C - Run from command line instead of as service (Windows)"ZT_EOL_S);
- fprintf(out," -I - Install Windows service (Windows)"ZT_EOL_S);
- fprintf(out," -R - Uninstall Windows service (Windows)"ZT_EOL_S);
- fprintf(out," -D - Load tap driver into system driver store (Windows)"ZT_EOL_S);
-#endif
-}
-
-#ifdef __WINDOWS__
-int _tmain(int argc, _TCHAR* argv[])
-#else
-int main(int argc,char **argv)
-#endif
-{
-#ifdef __UNIX_LIKE__
- signal(SIGHUP,&sighandlerHup);
- signal(SIGPIPE,SIG_IGN);
- signal(SIGUSR1,SIG_IGN);
- signal(SIGUSR2,SIG_IGN);
- signal(SIGALRM,SIG_IGN);
- signal(SIGINT,&sighandlerQuit);
- signal(SIGTERM,&sighandlerQuit);
- signal(SIGQUIT,&sighandlerQuit);
-
- /* Ensure that there are no inherited file descriptors open from a previous
- * incarnation. This is a hack to ensure that GitHub issue #61 or variants
- * of it do not return, and should not do anything otherwise bad. */
- {
- int mfd = STDIN_FILENO;
- if (STDOUT_FILENO > mfd) mfd = STDOUT_FILENO;
- if (STDERR_FILENO > mfd) mfd = STDERR_FILENO;
- for(int f=mfd+1;f<1024;++f)
- ::close(f);
- }
-#endif
-
-#ifdef __WINDOWS__
- WSADATA wsaData;
- WSAStartup(MAKEWORD(2,2),&wsaData);
-#endif
-
- if ((strstr(argv[0],"zerotier-cli"))||(strstr(argv[0],"ZEROTIER-CLI")))
- return ZeroTierCLI::main((const char *)0,argc,argv);
- if ((strstr(argv[0],"zerotier-idtool"))||(strstr(argv[0],"ZEROTIER-IDTOOL")))
- return ZeroTierIdTool::main(argc,argv);
-
- const char *homeDir = (const char *)0;
- unsigned int udpPort = ZT_DEFAULT_UDP_PORT;
- unsigned int tcpPort = 0;
-
- std::string overrideRootTopology;
-#ifdef __UNIX_LIKE__
- bool runAsDaemon = false;
-#endif
-#ifdef __WINDOWS__
-#ifdef ZT_WIN_RUN_IN_CONSOLE
- bool winRunFromCommandLine = true;
-#else
- bool winRunFromCommandLine = false;
-#endif
-#endif // __WINDOWS__
-
- for(int i=1;i<argc;++i) {
- if (argv[i][0] == '-') {
- switch(argv[i][1]) {
- case 'p':
- udpPort = Utils::strToUInt(argv[i] + 2);
- if (udpPort > 65535) {
- printHelp(argv[0],stdout);
- return 1;
- }
- break;
- case 't':
- tcpPort = Utils::strToUInt(argv[i] + 2);
- if (tcpPort > 65535) {
- printHelp(argv[0],stdout);
- return 1;
- }
- break;
-#ifdef __UNIX_LIKE__
- case 'd':
- runAsDaemon = true;
- break;
-#endif
- case 'T':
- if (argv[i][2]) {
- if (!Utils::readFile(argv[i] + 2,overrideRootTopology)) {
- fprintf(stderr,"%s: cannot read root topology from %s"ZT_EOL_S,argv[0],argv[i] + 2);
- return 1;
- }
- } else {
- printHelp(argv[0],stdout);
- return 1;
- }
- break;
- case 'v':
- printf("%s"ZT_EOL_S,Node::versionString());
- return 0;
- case 'q':
- if (argv[i][2]) {
- printHelp(argv[0],stdout);
- return 0;
- } else return ZeroTierCLI::main(homeDir,argc,argv);
- case 'i':
- if (argv[i][2]) {
- printHelp(argv[0],stdout);
- return 0;
- } else return ZeroTierIdTool::main(argc,argv);
-#ifdef __WINDOWS__
- case 'C':
- winRunFromCommandLine = true;
- break;
- case 'I': { // install self as service
- if (IsCurrentUserLocalAdministrator() != TRUE) {
- fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
- return 1;
- }
- std::string ret(InstallService(ZT_SERVICE_NAME,ZT_SERVICE_DISPLAY_NAME,ZT_SERVICE_START_TYPE,ZT_SERVICE_DEPENDENCIES,ZT_SERVICE_ACCOUNT,ZT_SERVICE_PASSWORD));
- if (ret.length()) {
- fprintf(stderr,"%s: unable to install service: %s"ZT_EOL_S,argv[0],ret.c_str());
- return 3;
- }
- return 0;
- } break;
- case 'R': { // uninstall self as service
- if (IsCurrentUserLocalAdministrator() != TRUE) {
- fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
- return 1;
- }
- std::string ret(UninstallService(ZT_SERVICE_NAME));
- if (ret.length()) {
- fprintf(stderr,"%s: unable to uninstall service: %s"ZT_EOL_S,argv[0],ret.c_str());
- return 3;
- }
- return 0;
- } break;
- case 'D': { // install Windows driver (since PNPUTIL.EXE seems to be weirdly unreliable)
- std::string pathToInf;
-#ifdef _WIN64
- pathToInf = ZT_DEFAULTS.defaultHomePath + "\\tap-windows\\x64\\zttap200.inf";
-#else
- pathToInf = ZT_DEFAULTS.defaultHomePath + "\\tap-windows\\x86\\zttap200.inf";
-#endif
- printf("Installing ZeroTier One virtual Ethernet port driver."ZT_EOL_S""ZT_EOL_S"NOTE: If you don't see a confirmation window to allow driver installation,"ZT_EOL_S"check to make sure it didn't appear under the installer."ZT_EOL_S);
- BOOL needReboot = FALSE;
- if (DiInstallDriverA(NULL,pathToInf.c_str(),DIIRFLAG_FORCE_INF,&needReboot)) {
- printf("%s: driver successfully installed from %s"ZT_EOL_S,argv[0],pathToInf.c_str());
- return 0;
- } else {
- printf("%s: failed installing %s: %d"ZT_EOL_S,argv[0],pathToInf.c_str(),(int)GetLastError());
- return 3;
- }
- } break;
-#endif // __WINDOWS__
- case 'h':
- case '?':
- default:
- printHelp(argv[0],stdout);
- return 0;
- }
- } else {
- if (homeDir) {
- printHelp(argv[0],stdout);
- return 0;
- } else homeDir = argv[i];
- }
- }
- if ((!homeDir)||(strlen(homeDir) == 0))
- homeDir = ZT_DEFAULTS.defaultHomePath.c_str();
-
-#ifdef __UNIX_LIKE__
- if (getuid() != 0) {
- fprintf(stderr,"%s: must be run as root (uid 0)\n",argv[0]);
- return 1;
- }
-
- if (runAsDaemon) {
- long p = (long)fork();
- if (p < 0) {
- fprintf(stderr,"%s: could not fork"ZT_EOL_S,argv[0]);
- return 1;
- } else if (p > 0)
- return 0; // forked
- // else p == 0, so we are daemonized
- }
-
- mkdir(homeDir,0755); // will fail if it already exists, but that's fine
-
- {
- // Write .pid file to home folder
- char pidpath[4096];
- Utils::snprintf(pidpath,sizeof(pidpath),"%s/zerotier-one.pid",homeDir);
- FILE *pf = fopen(pidpath,"w");
- if (pf) {
- fprintf(pf,"%ld",(long)getpid());
- fclose(pf);
- }
- }
-#endif // __UNIX_LIKE__
-
-#ifdef __WINDOWS__
- if (winRunFromCommandLine) {
- // Running in "interactive" mode (mostly for debugging)
- if (IsCurrentUserLocalAdministrator() != TRUE) {
- fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
- return 1;
- }
- _winPokeAHole();
- SetConsoleCtrlHandler(&_winConsoleCtrlHandler,TRUE);
- // continues on to ordinary command line execution code below...
- } else {
- // Running from service manager
- _winPokeAHole();
- ZeroTierOneService zt1Service;
- if (CServiceBase::Run(zt1Service) == TRUE) {
- return 0;
- } else {
- fprintf(stderr,"%s: unable to start service (try -h for help)"ZT_EOL_S,argv[0]);
- return 1;
- }
- }
-#endif // __WINDOWS__
-
- int exitCode = 0;
- bool needsReset = false;
- EthernetTapFactory *tapFactory = (EthernetTapFactory *)0;
- SocketManager *socketManager = (SocketManager *)0;
- NodeControlService *controlService = (NodeControlService *)0;
- NetworkConfigMaster *netconfMaster = (NetworkConfigMaster *)0;
-
- try {
- // Get or create authtoken.secret -- note that if this fails, authentication
- // will always fail since an empty auth token won't work. This should always
- // succeed unless something is wrong with the filesystem.
- std::string authToken(NodeControlClient::getAuthToken((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),true));
-
- tapFactory = ZTCreatePlatformEthernetTapFactory;
-
- try {
- socketManager = new NativeSocketManager(udpPort,tcpPort);
- } catch ( ... ) {
- fprintf(stderr,"%s: unable to bind to port: %u/UDP, %u/TCP (0 == disabled)"ZT_EOL_S,argv[0],udpPort,tcpPort);
- throw;
- }
-
- node = new Node(homeDir,tapFactory,socketManager,netconfMaster,needsReset,(overrideRootTopology.length() > 0) ? overrideRootTopology.c_str() : (const char *)0);
- controlService = new NodeControlService(node,authToken.c_str());
-
- switch(node->run()) {
-#ifdef __WINDOWS__
- case Node::NODE_RESTART_FOR_UPGRADE: {
- const char *upgPath = node->terminationMessage();
- if (upgPath) {
- if (!ZeroTierOneService::doStartUpgrade(std::string(upgPath))) {
- exitCode = 3;
- fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (doStartUpgrade failed)"ZT_EOL_S,argv[0],(upgPath) ? upgPath : "(unknown path)");
- }
- } else {
- exitCode = 3;
- fprintf(stderr,"%s: abnormal termination: unable to execute update at %s (no upgrade path provided)"ZT_EOL_S,argv[0],(upgPath) ? upgPath : "(unknown path)");
- }
- } break;
-#else // __UNIX_LIKE__
- case Node::NODE_RESTART_FOR_UPGRADE: {
- const char *upgPath = node->terminationMessage();
- // On Unix-type OSes we exec() right into the upgrade. This in turn will
- // end with us being re-launched either via the upgrade itself or something
- // like OSX's launchd.
- if (upgPath) {
- Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
- std::string updateLogPath(homeDir);
- updateLogPath.append("/autoupdate.log");
- Utils::rm(updateLogPath.c_str());
- Utils::redirectUnixOutputs(updateLogPath.c_str(),(const char *)0);
- ::execl(upgPath,upgPath,(char *)0);
- }
- exitCode = 3;
- fprintf(stderr,"%s: abnormal termination: unable to execute update at %s"ZT_EOL_S,argv[0],(upgPath) ? upgPath : "(unknown path)");
- } break;
-#endif // __WINDOWS__ / __UNIX_LIKE__
-
- case Node::NODE_UNRECOVERABLE_ERROR: {
- exitCode = 3;
- const char *termReason = node->terminationMessage();
- fprintf(stderr,"%s: abnormal termination: %s"ZT_EOL_S,argv[0],(termReason) ? termReason : "(unknown reason)");
- } break;
-
- default:
- break;
- }
- } catch ( std::exception &exc ) {
- fprintf(stderr,"%s: unexpected exception: %s"ZT_EOL_S,argv[0],exc.what());
- exitCode = 3;
- } catch ( ... ) {
- fprintf(stderr,"%s: unexpected exception: unknown exception"ZT_EOL_S,argv[0]);
- exitCode = 3;
- }
-
- delete controlService;
- delete node; node = (Node *)0;
- delete socketManager;
- delete tapFactory;
-
-#ifdef __UNIX_LIKE__
- Utils::rm((std::string(homeDir)+"/zerotier-one.pid").c_str());
-#endif
-
- return exitCode;
-}
diff --git a/ext/bin/tap-windows/x64/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis5/x64/WdfCoinstaller01011.dll
index d49d2913..d49d2913 100644
--- a/ext/bin/tap-windows/x64/WdfCoinstaller01011.dll
+++ b/ext/bin/tap-windows-ndis5/x64/WdfCoinstaller01011.dll
Binary files differ
diff --git a/ext/bin/tap-windows/x64/zttap200.cat b/ext/bin/tap-windows-ndis5/x64/zttap200.cat
index a3769e40..a3769e40 100644
--- a/ext/bin/tap-windows/x64/zttap200.cat
+++ b/ext/bin/tap-windows-ndis5/x64/zttap200.cat
Binary files differ
diff --git a/ext/bin/tap-windows/x64/zttap200.inf b/ext/bin/tap-windows-ndis5/x64/zttap200.inf
index dc1a7422..dc1a7422 100644
--- a/ext/bin/tap-windows/x64/zttap200.inf
+++ b/ext/bin/tap-windows-ndis5/x64/zttap200.inf
diff --git a/ext/bin/tap-windows/x64/zttap200.sys b/ext/bin/tap-windows-ndis5/x64/zttap200.sys
index 339351fb..339351fb 100644
--- a/ext/bin/tap-windows/x64/zttap200.sys
+++ b/ext/bin/tap-windows-ndis5/x64/zttap200.sys
Binary files differ
diff --git a/ext/bin/tap-windows/x86/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis5/x86/WdfCoinstaller01011.dll
index e943ea45..e943ea45 100644
--- a/ext/bin/tap-windows/x86/WdfCoinstaller01011.dll
+++ b/ext/bin/tap-windows-ndis5/x86/WdfCoinstaller01011.dll
Binary files differ
diff --git a/ext/bin/tap-windows/x86/zttap200.cat b/ext/bin/tap-windows-ndis5/x86/zttap200.cat
index d90ecbbe..d90ecbbe 100644
--- a/ext/bin/tap-windows/x86/zttap200.cat
+++ b/ext/bin/tap-windows-ndis5/x86/zttap200.cat
Binary files differ
diff --git a/ext/bin/tap-windows/x86/zttap200.inf b/ext/bin/tap-windows-ndis5/x86/zttap200.inf
index 99aac9f2..99aac9f2 100644
--- a/ext/bin/tap-windows/x86/zttap200.inf
+++ b/ext/bin/tap-windows-ndis5/x86/zttap200.inf
diff --git a/ext/bin/tap-windows/x86/zttap200.sys b/ext/bin/tap-windows-ndis5/x86/zttap200.sys
index b7b11fbe..b7b11fbe 100644
--- a/ext/bin/tap-windows/x86/zttap200.sys
+++ b/ext/bin/tap-windows-ndis5/x86/zttap200.sys
Binary files differ
diff --git a/ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll
new file mode 100644
index 00000000..d49d2913
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll
Binary files differ
diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.cat b/ext/bin/tap-windows-ndis6/x64/zttap300.cat
new file mode 100644
index 00000000..f1f878a3
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x64/zttap300.cat
Binary files differ
diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.inf b/ext/bin/tap-windows-ndis6/x64/zttap300.inf
new file mode 100644
index 00000000..9cc9ffc7
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x64/zttap300.inf
@@ -0,0 +1,143 @@
+;
+; ZeroTier One Virtual Network Port NDIS6 Driver
+;
+; Based on the OpenVPN tap-windows6 driver version 9.21.1 git
+; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3.
+; See: https://github.com/OpenVPN/tap-windows6
+;
+; Modified by ZeroTier, Inc. - https://www.zerotier.com/
+;
+; (1) Comment out 'tun' functionality and related features such as DHCP
+; emulation, since we don't use any of that. Just want straight 'tap'.
+; (2) Added custom IOCTL to enumerate L2 multicast memberships.
+; (3) Increase maximum number of multicast memberships to 128.
+; (4) Set default and max device MTU to 2800.
+; (5) Rename/rebrand driver as ZeroTier network port driver.
+;
+; Original copyright below. Modifications released under GPLv2 as well.
+;
+; ****************************************************************************
+; * 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. *
+; ****************************************************************************
+;
+
+[Version]
+Signature = "$Windows NT$"
+CatalogFile = zttap300.cat
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %Provider%
+Class = Net
+DriverVer=04/25/2015,6.2.9200.20557
+
+[Strings]
+DeviceDescription = "ZeroTier One Virtual Port"
+Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat.
+
+; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
+[Manufacturer]
+%Provider%=zttap300,NTamd64
+
+[zttap300]
+%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
+%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
+
+[zttap300.NTamd64]
+%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
+%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
+
+;----------------- Characteristics ------------
+; NCF_PHYSICAL = 0x04
+; NCF_VIRTUAL = 0x01
+; NCF_SOFTWARE_ENUMERATED = 0x02
+; NCF_HIDDEN = 0x08
+; NCF_NO_SERVICE = 0x10
+; NCF_HAS_UI = 0x80
+;----------------- Characteristics ------------
+[zttap300.ndi]
+CopyFiles = zttap300.driver, zttap300.files
+AddReg = zttap300.reg
+AddReg = zttap300.params.reg
+Characteristics = 0x81
+*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD
+*MediaType = 0x0 ; NdisMedium802_3
+*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3
+
+[zttap300.ndi.Services]
+AddService = zttap300, 2, zttap300.service
+
+[zttap300.reg]
+HKR, Ndi, Service, 0, "zttap300"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows.
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+HKR, , Manufacturer, 0, "%Provider%"
+HKR, , ProductName, 0, "%DeviceDescription%"
+
+[zttap300.params.reg]
+HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
+HKR, Ndi\params\MTU, Type, 0, "int"
+HKR, Ndi\params\MTU, Default, 0, "2800"
+HKR, Ndi\params\MTU, Optional, 0, "0"
+HKR, Ndi\params\MTU, Min, 0, "100"
+HKR, Ndi\params\MTU, Max, 0, "2800"
+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, "0"
+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 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 ---------------
+
+[zttap300.service]
+DisplayName = %DeviceDescription%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+LoadOrderGroup = NDIS
+ServiceBinary = %12%\zttap300.sys
+
+;----------------- Copy Flags ------------
+; COPYFLG_NOSKIP = 0x02
+; COPYFLG_NOVERSIONCHECK = 0x04
+;----------------- Copy Flags ------------
+
+[SourceDisksNames]
+1 = %DeviceDescription%, zttap300.sys
+
+[SourceDisksFiles]
+zttap300.sys = 1
+
+[DestinationDirs]
+zttap300.files = 11
+zttap300.driver = 12
+
+[zttap300.files]
+;
+
+[zttap300.driver]
+zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+
diff --git a/ext/bin/tap-windows-ndis6/x64/zttap300.sys b/ext/bin/tap-windows-ndis6/x64/zttap300.sys
new file mode 100644
index 00000000..060916f9
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x64/zttap300.sys
Binary files differ
diff --git a/ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll b/ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll
new file mode 100644
index 00000000..e943ea45
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll
Binary files differ
diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.cat b/ext/bin/tap-windows-ndis6/x86/zttap300.cat
new file mode 100644
index 00000000..d899961e
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x86/zttap300.cat
Binary files differ
diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.inf b/ext/bin/tap-windows-ndis6/x86/zttap300.inf
new file mode 100644
index 00000000..5f46dbfd
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x86/zttap300.inf
@@ -0,0 +1,139 @@
+;
+; ZeroTier One Virtual Network Port NDIS6 Driver
+;
+; Based on the OpenVPN tap-windows6 driver version 9.21.1 git
+; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3.
+; See: https://github.com/OpenVPN/tap-windows6
+;
+; Modified by ZeroTier, Inc. - https://www.zerotier.com/
+;
+; (1) Comment out 'tun' functionality and related features such as DHCP
+; emulation, since we don't use any of that. Just want straight 'tap'.
+; (2) Added custom IOCTL to enumerate L2 multicast memberships.
+; (3) Increase maximum number of multicast memberships to 128.
+; (4) Set default and max device MTU to 2800.
+; (5) Rename/rebrand driver as ZeroTier network port driver.
+;
+; Original copyright below. Modifications released under GPLv2 as well.
+;
+; ****************************************************************************
+; * 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. *
+; ****************************************************************************
+;
+
+[Version]
+Signature = "$Windows NT$"
+CatalogFile = zttap300.cat
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %Provider%
+Class = Net
+DriverVer=04/25/2015,6.2.9200.20557
+
+[Strings]
+DeviceDescription = "ZeroTier One Virtual Port"
+Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat.
+
+; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
+[Manufacturer]
+%Provider%=zttap300
+
+[zttap300]
+%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
+%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
+
+;----------------- Characteristics ------------
+; NCF_PHYSICAL = 0x04
+; NCF_VIRTUAL = 0x01
+; NCF_SOFTWARE_ENUMERATED = 0x02
+; NCF_HIDDEN = 0x08
+; NCF_NO_SERVICE = 0x10
+; NCF_HAS_UI = 0x80
+;----------------- Characteristics ------------
+[zttap300.ndi]
+CopyFiles = zttap300.driver, zttap300.files
+AddReg = zttap300.reg
+AddReg = zttap300.params.reg
+Characteristics = 0x81
+*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD
+*MediaType = 0x0 ; NdisMedium802_3
+*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3
+
+[zttap300.ndi.Services]
+AddService = zttap300, 2, zttap300.service
+
+[zttap300.reg]
+HKR, Ndi, Service, 0, "zttap300"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows.
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+HKR, , Manufacturer, 0, "%Provider%"
+HKR, , ProductName, 0, "%DeviceDescription%"
+
+[zttap300.params.reg]
+HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
+HKR, Ndi\params\MTU, Type, 0, "int"
+HKR, Ndi\params\MTU, Default, 0, "2800"
+HKR, Ndi\params\MTU, Optional, 0, "0"
+HKR, Ndi\params\MTU, Min, 0, "100"
+HKR, Ndi\params\MTU, Max, 0, "2800"
+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, "0"
+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 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 ---------------
+
+[zttap300.service]
+DisplayName = %DeviceDescription%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+LoadOrderGroup = NDIS
+ServiceBinary = %12%\zttap300.sys
+
+;----------------- Copy Flags ------------
+; COPYFLG_NOSKIP = 0x02
+; COPYFLG_NOVERSIONCHECK = 0x04
+;----------------- Copy Flags ------------
+
+[SourceDisksNames]
+1 = %DeviceDescription%, zttap300.sys
+
+[SourceDisksFiles]
+zttap300.sys = 1
+
+[DestinationDirs]
+zttap300.files = 11
+zttap300.driver = 12
+
+[zttap300.files]
+;
+
+[zttap300.driver]
+zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+
diff --git a/ext/bin/tap-windows-ndis6/x86/zttap300.sys b/ext/bin/tap-windows-ndis6/x86/zttap300.sys
new file mode 100644
index 00000000..29933e3e
--- /dev/null
+++ b/ext/bin/tap-windows-ndis6/x86/zttap300.sys
Binary files differ
diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp
index a0999b3d..220516ab 100644
--- a/osdep/WindowsEthernetTap.cpp
+++ b/osdep/WindowsEthernetTap.cpp
@@ -72,20 +72,21 @@ public:
#ifdef _WIN64
is64Bit = TRUE;
devcon = "\\devcon_x64.exe";
- tapDriver = "\\tap-windows\\x64\\zttap200.inf";
+ tapDriverNdis5 = "\\tap-windows\\x64\\zttap200.inf";
+ tapDriverNdis6 = "\\tap-windows\\x64\\zttap300.inf";
#else
is64Bit = FALSE;
IsWow64Process(GetCurrentProcess(),&is64Bit);
devcon = ((is64Bit == TRUE) ? "\\devcon_x64.exe" : "\\devcon_x86.exe");
- tapDriver = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf");
+ tapDriverNdis5 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap200.inf" : "\\tap-windows\\x86\\zttap200.inf");
+ tapDriverNdis6 = ((is64Bit == TRUE) ? "\\tap-windows\\x64\\zttap300.inf" : "\\tap-windows\\x86\\zttap300.inf");
#endif
}
-
BOOL is64Bit;
- std::string devcon;
- std::string tapDriver;
+ const char *devcon;
+ const char *tapDriverNdis5;
+ const char *tapDriverNdis6;
};
-
static const WindowsEthernetTapEnv WINENV;
} // anonymous namespace
@@ -123,6 +124,16 @@ WindowsEthernetTap::WindowsEthernetTap(
Mutex::Lock _l(_systemTapInitLock);
+ std::string tapDriverPath(_pathToHelpers + WINENV.tapDriverNdis6);
+ const char *tapDriverName = "zttap300";
+ if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) {
+ tapDriverPath = _pathToHelpers + WINENV.tapDriverNdis5;
+ tapDriverName = "zttap200";
+ if (::PathFileExistsA(tapDriverPath.c_str()) == FALSE) {
+ throw std::runtime_error("no tap driver available: cannot find zttap300.inf (NDIS6) or zttap200.inf (NDIS5) under home path");
+ }
+ }
+
HKEY nwAdapters;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS)
throw std::runtime_error("unable to open registry key for network adapter enumeration");
@@ -198,7 +209,7 @@ WindowsEthernetTap::WindowsEthernetTap(
PROCESS_INFORMATION processInfo;
memset(&startupInfo,0,sizeof(STARTUPINFOA));
memset(&processInfo,0,sizeof(PROCESS_INFORMATION));
- if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" install \"" + _pathToHelpers + WINENV.tapDriver + "\" zttap200").c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
+ if (!CreateProcessA(NULL,(LPSTR)(std::string("\"") + _pathToHelpers + WINENV.devcon + "\" install \"" + tapDriverPath + "\" " + tapDriverName).c_str(),NULL,NULL,FALSE,0,NULL,NULL,&startupInfo,&processInfo)) {
RegCloseKey(nwAdapters);
if (devconLog != INVALID_HANDLE_VALUE)
CloseHandle(devconLog);
diff --git a/windows/TapDriver6/TapDriver6.vcxproj b/windows/TapDriver6/TapDriver6.vcxproj
new file mode 100644
index 00000000..ffe9441c
--- /dev/null
+++ b/windows/TapDriver6/TapDriver6.vcxproj
@@ -0,0 +1,371 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Win8 Debug|Win32">
+ <Configuration>Win8 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Release|Win32">
+ <Configuration>Win8 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Debug|Win32">
+ <Configuration>Win7 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Release|Win32">
+ <Configuration>Win7 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Vista Debug|Win32">
+ <Configuration>Vista Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Vista Release|Win32">
+ <Configuration>Vista Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Debug|x64">
+ <Configuration>Win8 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win8 Release|x64">
+ <Configuration>Win8 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Debug|x64">
+ <Configuration>Win7 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Win7 Release|x64">
+ <Configuration>Win7 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Vista Debug|x64">
+ <Configuration>Vista Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Vista Release|x64">
+ <Configuration>Vista Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}</ProjectGuid>
+ <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ <Configuration>Win8 Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <RootNamespace>TapDriver6</RootNamespace>
+ <VCTargetsPath Condition="'$(VCTargetsPath11)' != '' and '$(VisualStudioVersion)' == '11.0'">$(VCTargetsPath11)</VCTargetsPath>
+ </PropertyGroup>
+ <PropertyGroup Label="PropertySheets">
+ <PlatformToolset>WindowsKernelModeDriver8.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'" Label="Configuration">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'" Label="Configuration">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'" Label="Configuration">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'" Label="Configuration">
+ <TargetVersion>Vista</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">
+ <TargetName>zttap300</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <WppEnabled>false</WppEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile. ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>false</WppKernelMode>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</WppMinimalRebuildFromTracking>
+ <WppMinimalRebuildFromTracking Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</WppMinimalRebuildFromTracking>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">Level1</WarningLevel>
+ <WarningLevel Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">Level1</WarningLevel>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">Default</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">Default</CompileAs>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">C:\WinDDK\7600.16385.1\lib\win7\amd64\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\amd64\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">C:\WinDDK\7600.16385.1\lib\win7\i386\ndis.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\ntstrsafe.lib;C:\WinDDK\7600.16385.1\lib\win7\i386\wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ <Inf>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveDate Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</SpecifyDriverVerDirectiveDate>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="adapter.c" />
+ <ClCompile Include="device.c" />
+ <ClCompile Include="error.c" />
+ <ClCompile Include="macinfo.c" />
+ <ClCompile Include="mem.c" />
+ <ClCompile Include="oidrequest.c" />
+ <ClCompile Include="rxpath.c" />
+ <ClCompile Include="tapdrvr.c" />
+ <ClCompile Include="txpath.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="adapter.h" />
+ <ClInclude Include="config.h" />
+ <ClInclude Include="constants.h" />
+ <ClInclude Include="device.h" />
+ <ClInclude Include="endian.h" />
+ <ClInclude Include="error.h" />
+ <ClInclude Include="hexdump.h" />
+ <ClInclude Include="lock.h" />
+ <ClInclude Include="macinfo.h" />
+ <ClInclude Include="mem.h" />
+ <ClInclude Include="proto.h" />
+ <ClInclude Include="prototypes.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="tap-windows.h" />
+ <ClInclude Include="tap.h" />
+ <ClInclude Include="types.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resource.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="zttap300.inf">
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Release|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|Win32'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Debug|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Debug|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Vista Release|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win7 Debug|x64'">3.00.00.0</TimeStamp>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win7 Release|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <SpecifyDriverVerDirectiveVersion Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">false</SpecifyDriverVerDirectiveVersion>
+ <TimeStamp Condition="'$(Configuration)|$(Platform)'=='Win8 Release|x64'">3.00.00.0</TimeStamp>
+ </Inf>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/windows/TapDriver6/TapDriver6.vcxproj.filters b/windows/TapDriver6/TapDriver6.vcxproj.filters
new file mode 100644
index 00000000..14cbbde0
--- /dev/null
+++ b/windows/TapDriver6/TapDriver6.vcxproj.filters
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Driver Files">
+ <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="adapter.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="device.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="error.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="macinfo.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mem.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="oidrequest.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rxpath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="tapdrvr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="txpath.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="adapter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="constants.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="device.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="endian.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="error.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="hexdump.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lock.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="macinfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mem.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="proto.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="prototypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="tap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="tap-windows.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="types.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resource.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="zttap300.inf">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/windows/TapDriver6/adapter.c b/windows/TapDriver6/adapter.c
new file mode 100644
index 00000000..7ce4b310
--- /dev/null
+++ b/windows/TapDriver6/adapter.c
@@ -0,0 +1,1716 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+NDIS_OID TAPSupportedOids[] =
+{
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_STATISTICS,
+#ifdef IMPLEMENT_OPTIONAL_OIDS
+ OID_GEN_TRANSMIT_QUEUE_LENGTH, // Optional
+#endif // IMPLEMENT_OPTIONAL_OIDS
+ OID_GEN_LINK_PARAMETERS,
+ OID_GEN_INTERRUPT_MODERATION,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_SEND_PACKETS,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef IMPLEMENT_OPTIONAL_OIDS
+ OID_802_3_XMIT_DEFERRED, // Optional
+ OID_802_3_XMIT_MAX_COLLISIONS, // Optional
+ OID_802_3_RCV_OVERRUN, // Optional
+ OID_802_3_XMIT_UNDERRUN, // Optional
+ OID_802_3_XMIT_HEARTBEAT_FAILURE, // Optional
+ OID_802_3_XMIT_TIMES_CRS_LOST, // Optional
+ OID_802_3_XMIT_LATE_COLLISIONS, // Optional
+ OID_PNP_CAPABILITIES, // Optional
+#endif // IMPLEMENT_OPTIONAL_OIDS
+};
+
+//======================================================================
+// TAP NDIS 6 Miniport Callbacks
+//======================================================================
+
+// Returns with reference count initialized to one.
+PTAP_ADAPTER_CONTEXT
+tapAdapterContextAllocate(
+ __in NDIS_HANDLE MiniportAdapterHandle
+)
+{
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+
+ adapter = (PTAP_ADAPTER_CONTEXT )NdisAllocateMemoryWithTagPriority(
+ GlobalData.NdisDriverHandle,
+ sizeof(TAP_ADAPTER_CONTEXT),
+ TAP_ADAPTER_TAG,
+ NormalPoolPriority
+ );
+
+ if(adapter)
+ {
+ NET_BUFFER_LIST_POOL_PARAMETERS nblPoolParameters = {0};
+
+ NdisZeroMemory(adapter,sizeof(TAP_ADAPTER_CONTEXT));
+
+ adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ // Initialize cancel-safe IRP queue
+ tapIrpCsqInitialize(&adapter->PendingReadIrpQueue);
+
+ // Initialize TAP send packet queue.
+ tapPacketQueueInitialize(&adapter->SendPacketQueue);
+
+ // Allocate the adapter lock.
+ NdisAllocateSpinLock(&adapter->AdapterLock);
+
+ // NBL pool for making TAP receive indications.
+ NdisZeroMemory(&nblPoolParameters, sizeof(NET_BUFFER_LIST_POOL_PARAMETERS));
+
+ // Initialize event used to determine when all receive NBLs have been returned.
+ NdisInitializeEvent(&adapter->ReceiveNblInFlightCountZeroEvent);
+
+ nblPoolParameters.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ nblPoolParameters.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ nblPoolParameters.Header.Size = NDIS_SIZEOF_NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ nblPoolParameters.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
+ nblPoolParameters.ContextSize = 0;
+ //nblPoolParameters.ContextSize = sizeof(RX_NETBUFLIST_RSVD);
+ nblPoolParameters.fAllocateNetBuffer = TRUE;
+ nblPoolParameters.PoolTag = TAP_RX_NBL_TAG;
+
+#pragma warning( suppress : 28197 )
+ adapter->ReceiveNblPool = NdisAllocateNetBufferListPool(
+ adapter->MiniportAdapterHandle,
+ &nblPoolParameters);
+
+ if (adapter->ReceiveNblPool == NULL)
+ {
+ DEBUGP (("[TAP] Couldn't allocate adapter receive NBL pool\n"));
+ NdisFreeMemory(adapter,0,0);
+ }
+
+ // Add initial reference. Normally removed in AdapterHalt.
+ adapter->RefCount = 1;
+
+ // Safe for multiple removes.
+ NdisInitializeListHead(&adapter->AdapterListLink);
+
+ //
+ // The miniport adapter is initially powered up
+ //
+ adapter->CurrentPowerState = NdisDeviceStateD0;
+ }
+
+ return adapter;
+}
+
+VOID
+tapReadPermanentAddress(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in NDIS_HANDLE ConfigurationHandle,
+ __out MACADDR PermanentAddress
+ )
+{
+ NDIS_STATUS status;
+ NDIS_CONFIGURATION_PARAMETER *configParameter;
+ NDIS_STRING macKey = NDIS_STRING_CONST("MAC");
+ ANSI_STRING macString;
+ BOOLEAN macFromRegistry = FALSE;
+
+ // Read MAC parameter from registry.
+ NdisReadConfiguration(
+ &status,
+ &configParameter,
+ ConfigurationHandle,
+ &macKey,
+ NdisParameterString
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if( (configParameter->ParameterType == NdisParameterString)
+ && (configParameter->ParameterData.StringData.Length >= 12)
+ )
+ {
+ if (RtlUnicodeStringToAnsiString(
+ &macString,
+ &configParameter->ParameterData.StringData,
+ TRUE) == STATUS_SUCCESS
+ )
+ {
+ macFromRegistry = ParseMAC (PermanentAddress, macString.Buffer);
+ RtlFreeAnsiString (&macString);
+ }
+ }
+ }
+
+ if(!macFromRegistry)
+ {
+ //
+ // There is no (valid) address stashed in the registry parameter.
+ //
+ // Make up a dummy mac address based on the ANSI representation of the
+ // NetCfgInstanceId GUID.
+ //
+ GenerateRandomMac(PermanentAddress, MINIPORT_INSTANCE_ID(Adapter));
+ }
+}
+
+NDIS_STATUS
+tapReadConfiguration(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ NDIS_CONFIGURATION_OBJECT configObject;
+ NDIS_HANDLE configHandle;
+
+ DEBUGP (("[TAP] --> tapReadConfiguration\n"));
+
+ //
+ // Setup defaults in case configuration cannot be opened.
+ //
+ Adapter->MtuSize = ETHERNET_MTU;
+ Adapter->MediaStateAlwaysConnected = FALSE;
+ Adapter->LogicalMediaState = FALSE;
+ Adapter->AllowNonAdmin = FALSE;
+ //
+ // Open the registry for this adapter to read advanced
+ // configuration parameters stored by the INF file.
+ //
+ NdisZeroMemory(&configObject, sizeof(configObject));
+
+ {C_ASSERT(sizeof(configObject) >= NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1);}
+ configObject.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
+ configObject.Header.Size = NDIS_SIZEOF_CONFIGURATION_OBJECT_REVISION_1;
+ configObject.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
+
+ configObject.NdisHandle = Adapter->MiniportAdapterHandle;
+ configObject.Flags = 0;
+
+ status = NdisOpenConfigurationEx(
+ &configObject,
+ &configHandle
+ );
+
+ // Read on the opened configuration handle.
+ if(status == NDIS_STATUS_SUCCESS)
+ {
+ NDIS_CONFIGURATION_PARAMETER *configParameter;
+ NDIS_STRING mkey = NDIS_STRING_CONST("NetCfgInstanceId");
+
+ //
+ // Read NetCfgInstanceId from the registry.
+ // ------------------------------------
+ // NetCfgInstanceId is required to create device and associated
+ // symbolic link for the adapter device.
+ //
+ // NetCfgInstanceId is a GUID string provided by NDIS that identifies
+ // the adapter instance. An example is:
+ //
+ // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0}
+ //
+ // Other names are derived from NetCfgInstanceId. For example, MiniportName:
+ //
+ // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0}
+ //
+ NdisReadConfiguration (
+ &status,
+ &configParameter,
+ configHandle,
+ &mkey,
+ NdisParameterString
+ );
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ if (configParameter->ParameterType == NdisParameterString)
+ {
+ DEBUGP (("[TAP] NdisReadConfiguration (NetCfgInstanceId=%wZ)\n",
+ &configParameter->ParameterData.StringData ));
+
+ // Save NetCfgInstanceId as UNICODE_STRING.
+ Adapter->NetCfgInstanceId.Length = Adapter->NetCfgInstanceId.MaximumLength
+ = configParameter->ParameterData.StringData.Length;
+
+ Adapter->NetCfgInstanceId.Buffer = Adapter->NetCfgInstanceIdBuffer;
+
+ NdisMoveMemory(
+ Adapter->NetCfgInstanceId.Buffer,
+ configParameter->ParameterData.StringData.Buffer,
+ Adapter->NetCfgInstanceId.Length
+ );
+
+ // Save NetCfgInstanceId as ANSI_STRING as well.
+ if (RtlUnicodeStringToAnsiString (
+ &Adapter->NetCfgInstanceIdAnsi,
+ &configParameter->ParameterData.StringData,
+ TRUE) != STATUS_SUCCESS
+ )
+ {
+ DEBUGP (("[TAP] NetCfgInstanceId ANSI name conversion failed\n"));
+ status = NDIS_STATUS_RESOURCES;
+ }
+ }
+ else
+ {
+ DEBUGP (("[TAP] NetCfgInstanceId has invalid type\n"));
+ status = NDIS_STATUS_INVALID_DATA;
+ }
+ }
+ else
+ {
+ DEBUGP (("[TAP] NetCfgInstanceId failed\n"));
+ status = NDIS_STATUS_INVALID_DATA;
+ }
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ NDIS_STATUS localStatus; // Use default if these fail.
+ NDIS_CONFIGURATION_PARAMETER *configParameter;
+ NDIS_STRING mtuKey = NDIS_STRING_CONST("MTU");
+ NDIS_STRING mediaStatusKey = NDIS_STRING_CONST("MediaStatus");
+#if ENABLE_NONADMIN
+ NDIS_STRING allowNonAdminKey = NDIS_STRING_CONST("AllowNonAdmin");
+#endif
+
+ // Read MTU from the registry.
+ NdisReadConfiguration (
+ &localStatus,
+ &configParameter,
+ configHandle,
+ &mtuKey,
+ NdisParameterInteger
+ );
+
+ if (localStatus == NDIS_STATUS_SUCCESS)
+ {
+ if (configParameter->ParameterType == NdisParameterInteger)
+ {
+ int mtu = configParameter->ParameterData.IntegerData;
+
+ if(mtu == 0)
+ {
+ mtu = ETHERNET_MTU;
+ }
+
+ // Sanity check
+ if (mtu < MINIMUM_MTU)
+ {
+ mtu = MINIMUM_MTU;
+ }
+ else if (mtu > MAXIMUM_MTU)
+ {
+ mtu = MAXIMUM_MTU;
+ }
+
+ Adapter->MtuSize = mtu;
+ }
+ }
+
+ DEBUGP (("[%s] Using MTU %d\n",
+ MINIPORT_INSTANCE_ID (Adapter),
+ Adapter->MtuSize
+ ));
+
+ // Read MediaStatus setting from registry.
+ NdisReadConfiguration (
+ &localStatus,
+ &configParameter,
+ configHandle,
+ &mediaStatusKey,
+ NdisParameterInteger
+ );
+
+ if (localStatus == NDIS_STATUS_SUCCESS)
+ {
+ if (configParameter->ParameterType == NdisParameterInteger)
+ {
+ if(configParameter->ParameterData.IntegerData == 0)
+ {
+ // Connect state is appplication controlled.
+ DEBUGP(("[%s] Initial MediaConnectState: Application Controlled\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+
+ Adapter->MediaStateAlwaysConnected = FALSE;
+ Adapter->LogicalMediaState = FALSE;
+ }
+ else
+ {
+ // Connect state is always connected.
+ DEBUGP(("[%s] Initial MediaConnectState: Always Connected\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+
+ Adapter->MediaStateAlwaysConnected = TRUE;
+ Adapter->LogicalMediaState = TRUE;
+ }
+ }
+ }
+
+ // Read MAC PermanentAddress setting from registry.
+ tapReadPermanentAddress(
+ Adapter,
+ configHandle,
+ Adapter->PermanentAddress
+ );
+
+ DEBUGP (("[%s] Using MAC PermanentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+ MINIPORT_INSTANCE_ID (Adapter),
+ Adapter->PermanentAddress[0],
+ Adapter->PermanentAddress[1],
+ Adapter->PermanentAddress[2],
+ Adapter->PermanentAddress[3],
+ Adapter->PermanentAddress[4],
+ Adapter->PermanentAddress[5])
+ );
+
+ // Now seed the current MAC address with the permanent address.
+ ETH_COPY_NETWORK_ADDRESS(Adapter->CurrentAddress, Adapter->PermanentAddress);
+
+ DEBUGP (("[%s] Using MAC CurrentAddress %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+ MINIPORT_INSTANCE_ID (Adapter),
+ Adapter->CurrentAddress[0],
+ Adapter->CurrentAddress[1],
+ Adapter->CurrentAddress[2],
+ Adapter->CurrentAddress[3],
+ Adapter->CurrentAddress[4],
+ Adapter->CurrentAddress[5])
+ );
+
+ // Read optional AllowNonAdmin setting from registry.
+#if ENABLE_NONADMIN
+ NdisReadConfiguration (
+ &localStatus,
+ &configParameter,
+ configHandle,
+ &allowNonAdminKey,
+ NdisParameterInteger
+ );
+
+ if (localStatus == NDIS_STATUS_SUCCESS)
+ {
+ if (configParameter->ParameterType == NdisParameterInteger)
+ {
+ Adapter->AllowNonAdmin = TRUE;
+ }
+ }
+#endif
+ }
+
+ // Close the configuration handle.
+ NdisCloseConfiguration(configHandle);
+ }
+ else
+ {
+ DEBUGP (("[TAP] Couldn't open adapter registry\n"));
+ }
+
+ DEBUGP (("[TAP] <-- tapReadConfiguration; status = %8.8X\n",status));
+
+ return status;
+}
+
+VOID
+tapAdapterContextAddToGlobalList(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ LOCK_STATE lockState;
+ PLIST_ENTRY listEntry = &Adapter->AdapterListLink;
+
+ // Acquire global adapter list lock.
+ NdisAcquireReadWriteLock(
+ &GlobalData.Lock,
+ TRUE, // Acquire for write
+ &lockState
+ );
+
+ // Adapter context should NOT be in any list.
+ ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) );
+
+ // Add reference to persist until after removal.
+ tapAdapterContextReference(Adapter);
+
+ // Add the adapter context to the global list.
+ InsertTailList(&GlobalData.AdapterList,&Adapter->AdapterListLink);
+
+ // Release global adapter list lock.
+ NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+}
+
+VOID
+tapAdapterContextRemoveFromGlobalList(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ LOCK_STATE lockState;
+
+ // Acquire global adapter list lock.
+ NdisAcquireReadWriteLock(
+ &GlobalData.Lock,
+ TRUE, // Acquire for write
+ &lockState
+ );
+
+ // Remove the adapter context from the global list.
+ RemoveEntryList(&Adapter->AdapterListLink);
+
+ // Safe for multiple removes.
+ NdisInitializeListHead(&Adapter->AdapterListLink);
+
+ // Remove reference added in tapAdapterContextAddToGlobalList.
+ tapAdapterContextDereference(Adapter);
+
+ // Release global adapter list lock.
+ NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+}
+
+// Returns with added reference on adapter context.
+PTAP_ADAPTER_CONTEXT
+tapAdapterContextFromDeviceObject(
+ __in PDEVICE_OBJECT DeviceObject
+ )
+{
+ LOCK_STATE lockState;
+
+ // Acquire global adapter list lock.
+ NdisAcquireReadWriteLock(
+ &GlobalData.Lock,
+ FALSE, // Acquire for read
+ &lockState
+ );
+
+ if (!IsListEmpty(&GlobalData.AdapterList))
+ {
+ PLIST_ENTRY entry = GlobalData.AdapterList.Flink;
+ PTAP_ADAPTER_CONTEXT adapter;
+
+ while (entry != &GlobalData.AdapterList)
+ {
+ adapter = CONTAINING_RECORD(entry, TAP_ADAPTER_CONTEXT, AdapterListLink);
+
+ // Match on DeviceObject
+ if(adapter->DeviceObject == DeviceObject )
+ {
+ // Add reference to adapter context.
+ tapAdapterContextReference(adapter);
+
+ // Release global adapter list lock.
+ NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+
+ return adapter;
+ }
+
+ // Move to next entry
+ entry = entry->Flink;
+ }
+ }
+
+ // Release global adapter list lock.
+ NdisReleaseReadWriteLock(&GlobalData.Lock,&lockState);
+
+ return (PTAP_ADAPTER_CONTEXT )NULL;
+}
+
+NDIS_STATUS
+AdapterSetOptions(
+ __in NDIS_HANDLE NdisDriverHandle,
+ __in NDIS_HANDLE DriverContext
+ )
+/*++
+Routine Description:
+
+ The MiniportSetOptions function registers optional handlers. For each
+ optional handler that should be registered, this function makes a call
+ to NdisSetOptionalHandlers.
+
+ MiniportSetOptions runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ DriverContext The context handle
+
+Return Value:
+
+ NDIS_STATUS_xxx code
+
+--*/
+{
+ NDIS_STATUS status;
+
+ DEBUGP (("[TAP] --> AdapterSetOptions\n"));
+
+ //
+ // Set any optional handlers by filling out the appropriate struct and
+ // calling NdisSetOptionalHandlers here.
+ //
+
+ status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP (("[TAP] <-- AdapterSetOptions; status = %8.8X\n",status));
+
+ return status;
+}
+
+NDIS_STATUS
+AdapterCreate(
+ __in NDIS_HANDLE MiniportAdapterHandle,
+ __in NDIS_HANDLE MiniportDriverContext,
+ __in PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters
+ )
+{
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+ NDIS_STATUS status;
+
+ UNREFERENCED_PARAMETER(MiniportDriverContext);
+ UNREFERENCED_PARAMETER(MiniportInitParameters);
+
+ DEBUGP (("[TAP] --> AdapterCreate\n"));
+
+ do
+ {
+ NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES regAttributes = {0};
+ NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES genAttributes = {0};
+ NDIS_PNP_CAPABILITIES pnpCapabilities = {0};
+
+ //
+ // Allocate adapter context structure and initialize all the
+ // memory resources for sending and receiving packets.
+ //
+ // Returns with reference count initialized to one.
+ //
+ adapter = tapAdapterContextAllocate(MiniportAdapterHandle);
+
+ if(adapter == NULL)
+ {
+ DEBUGP (("[TAP] Couldn't allocate adapter memory\n"));
+ status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ // Enter the Initializing state.
+ DEBUGP (("[TAP] Miniport State: Initializing\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportInitializingState;
+ tapAdapterReleaseLock(adapter,FALSE);
+
+ //
+ // First read adapter configuration from registry.
+ // -----------------------------------------------
+ // Subsequent device registration will fail if NetCfgInstanceId
+ // has not been successfully read.
+ //
+ status = tapReadConfiguration(adapter);
+
+ //
+ // Set the registration attributes.
+ //
+ {C_ASSERT(sizeof(regAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1);}
+ regAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
+ regAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+ regAttributes.Header.Revision = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+
+ regAttributes.MiniportAdapterContext = adapter;
+ regAttributes.AttributeFlags = TAP_ADAPTER_ATTRIBUTES_FLAGS;
+
+ regAttributes.CheckForHangTimeInSeconds = TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS;
+ regAttributes.InterfaceType = TAP_INTERFACE_TYPE;
+
+ //NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(TAP_ADAPTER_CONTEXT);
+ status = NdisMSetMiniportAttributes(
+ MiniportAdapterHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&regAttributes
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] NdisSetOptionalHandlers failed; Status 0x%08x\n",status));
+ break;
+ }
+
+ //
+ // Next, set the general attributes.
+ //
+ {C_ASSERT(sizeof(genAttributes) >= NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1);}
+ genAttributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
+ genAttributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+ genAttributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+
+ //
+ // Specify the medium type that the NIC can support but not
+ // necessarily the medium type that the NIC currently uses.
+ //
+ genAttributes.MediaType = TAP_MEDIUM_TYPE;
+
+ //
+ // Specifiy medium type that the NIC currently uses.
+ //
+ genAttributes.PhysicalMediumType = TAP_PHYSICAL_MEDIUM;
+
+ //
+ // Specifiy the maximum network frame size, in bytes, that the NIC
+ // supports excluding the header.
+ //
+ genAttributes.MtuSize = TAP_FRAME_MAX_DATA_SIZE;
+ genAttributes.MaxXmitLinkSpeed = TAP_XMIT_SPEED;
+ genAttributes.XmitLinkSpeed = TAP_XMIT_SPEED;
+ genAttributes.MaxRcvLinkSpeed = TAP_RECV_SPEED;
+ genAttributes.RcvLinkSpeed = TAP_RECV_SPEED;
+
+ if(adapter->MediaStateAlwaysConnected)
+ {
+ DEBUGP(("[%s] Initial MediaConnectState: Connected\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ genAttributes.MediaConnectState = MediaConnectStateConnected;
+ }
+ else
+ {
+ DEBUGP(("[%s] Initial MediaConnectState: Disconnected\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ genAttributes.MediaConnectState = MediaConnectStateDisconnected;
+ }
+
+ genAttributes.MediaDuplexState = MediaDuplexStateFull;
+
+ //
+ // The maximum number of bytes the NIC can provide as lookahead data.
+ // If that value is different from the size of the lookahead buffer
+ // supported by bound protocols, NDIS will call MiniportOidRequest to
+ // set the size of the lookahead buffer provided by the miniport driver
+ // to the minimum of the miniport driver and protocol(s) values. If the
+ // driver always indicates up full packets with
+ // NdisMIndicateReceiveNetBufferLists, it should set this value to the
+ // maximum total frame size, which excludes the header.
+ //
+ // Upper-layer drivers examine lookahead data to determine whether a
+ // packet that is associated with the lookahead data is intended for
+ // one or more of their clients. If the underlying driver supports
+ // multipacket receive indications, bound protocols are given full net
+ // packets on every indication. Consequently, this value is identical
+ // to that returned for OID_GEN_RECEIVE_BLOCK_SIZE.
+ //
+ genAttributes.LookaheadSize = TAP_MAX_LOOKAHEAD;
+ genAttributes.MacOptions = TAP_MAC_OPTIONS;
+ genAttributes.SupportedPacketFilters = TAP_SUPPORTED_FILTERS;
+
+ //
+ // The maximum number of multicast addresses the NIC driver can manage.
+ // This list is global for all protocols bound to (or above) the NIC.
+ // Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from
+ // the NIC driver when attempting to set the multicast address list,
+ // even if the number of elements in the given list is less than the
+ // number originally returned for this query.
+ //
+ genAttributes.MaxMulticastListSize = TAP_MAX_MCAST_LIST;
+ genAttributes.MacAddressLength = MACADDR_SIZE;
+
+ //
+ // Return the MAC address of the NIC burnt in the hardware.
+ //
+ ETH_COPY_NETWORK_ADDRESS(genAttributes.PermanentMacAddress, adapter->PermanentAddress);
+
+ //
+ // Return the MAC address the NIC is currently programmed to use. Note
+ // that this address could be different from the permananent address as
+ // the user can override using registry. Read NdisReadNetworkAddress
+ // doc for more info.
+ //
+ ETH_COPY_NETWORK_ADDRESS(genAttributes.CurrentMacAddress, adapter->CurrentAddress);
+
+ genAttributes.RecvScaleCapabilities = NULL;
+ genAttributes.AccessType = TAP_ACCESS_TYPE;
+ genAttributes.DirectionType = TAP_DIRECTION_TYPE;
+ genAttributes.ConnectionType = TAP_CONNECTION_TYPE;
+ genAttributes.IfType = TAP_IFTYPE;
+ genAttributes.IfConnectorPresent = TAP_HAS_PHYSICAL_CONNECTOR;
+ genAttributes.SupportedStatistics = TAP_SUPPORTED_STATISTICS;
+ genAttributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported; // IEEE 802.3 pause frames
+ genAttributes.DataBackFillSize = 0;
+ genAttributes.ContextBackFillSize = 0;
+
+ //
+ // The SupportedOidList is an array of OIDs for objects that the
+ // underlying driver or its NIC supports. Objects include general,
+ // media-specific, and implementation-specific objects. NDIS forwards a
+ // subset of the returned list to protocols that make this query. That
+ // is, NDIS filters any supported statistics OIDs out of the list
+ // because protocols never make statistics queries.
+ //
+ genAttributes.SupportedOidList = TAPSupportedOids;
+ genAttributes.SupportedOidListLength = sizeof(TAPSupportedOids);
+ genAttributes.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
+
+ //
+ // Set power management capabilities
+ //
+ NdisZeroMemory(&pnpCapabilities, sizeof(pnpCapabilities));
+ pnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
+ genAttributes.PowerManagementCapabilities = &pnpCapabilities;
+
+ status = NdisMSetMiniportAttributes(
+ MiniportAdapterHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&genAttributes
+ );
+
+ if (status != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP (("[TAP] NdisMSetMiniportAttributes failed; Status 0x%08x\n",status));
+ break;
+ }
+
+ //
+ // Create the Win32 device I/O interface.
+ //
+ status = CreateTapDevice(adapter);
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ // Add this adapter to the global adapter list.
+ tapAdapterContextAddToGlobalList(adapter);
+ }
+ else
+ {
+ DEBUGP (("[TAP] CreateTapDevice failed; Status 0x%08x\n",status));
+ break;
+ }
+ } while(FALSE);
+
+ if(status == NDIS_STATUS_SUCCESS)
+ {
+ // Enter the Paused state if initialization is complete.
+ DEBUGP (("[TAP] Miniport State: Paused\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportPausedState;
+ tapAdapterReleaseLock(adapter,FALSE);
+ }
+ else
+ {
+ if(adapter != NULL)
+ {
+ DEBUGP (("[TAP] Miniport State: Halted\n"));
+
+ //
+ // Remove reference when adapter context was allocated
+ // ---------------------------------------------------
+ // This should result in freeing adapter context memory
+ // and assiciated resources.
+ //
+ tapAdapterContextDereference(adapter);
+ adapter = NULL;
+ }
+ }
+
+ DEBUGP (("[TAP] <-- AdapterCreate; status = %8.8X\n",status));
+
+ return status;
+}
+
+VOID
+AdapterHalt(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in NDIS_HALT_ACTION HaltAction
+ )
+/*++
+
+Routine Description:
+
+ Halt handler is called when NDIS receives IRP_MN_STOP_DEVICE,
+ IRP_MN_SUPRISE_REMOVE or IRP_MN_REMOVE_DEVICE requests from the PNP
+ manager. Here, the driver should free all the resources acquired in
+ MiniportInitialize and stop access to the hardware. NDIS will not submit
+ any further request once this handler is invoked.
+
+ 1) Free and unmap all I/O resources.
+ 2) Disable interrupt and deregister interrupt handler.
+ 3) Deregister shutdown handler regsitered by
+ NdisMRegisterAdapterShutdownHandler .
+ 4) Cancel all queued up timer callbacks.
+ 5) Finally wait indefinitely for all the outstanding receive
+ packets indicated to the protocol to return.
+
+ MiniportHalt runs at IRQL = PASSIVE_LEVEL.
+
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the Adapter
+ HaltAction The reason for halting the adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+ UNREFERENCED_PARAMETER(HaltAction);
+
+ DEBUGP (("[TAP] --> AdapterHalt\n"));
+
+ // Enter the Halted state.
+ DEBUGP (("[TAP] Miniport State: Halted\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportHaltedState;
+ tapAdapterReleaseLock(adapter,FALSE);
+
+ // Remove this adapter from the global adapter list.
+ tapAdapterContextRemoveFromGlobalList(adapter);
+
+ // BUGBUG!!! Call AdapterShutdownEx to do some of the work of stopping.
+
+ // TODO!!! More...
+
+ //
+ // Destroy the TAP Win32 device.
+ //
+ DestroyTapDevice(adapter);
+
+ //
+ // Remove initial reference added in AdapterCreate.
+ // ------------------------------------------------
+ // This should result in freeing adapter context memory
+ // and resources allocated in AdapterCreate.
+ //
+ tapAdapterContextDereference(adapter);
+ adapter = NULL;
+
+ DEBUGP (("[TAP] <-- AdapterHalt\n"));
+}
+
+VOID
+tapWaitForReceiveNblInFlightCountZeroEvent(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ LONG nblCount;
+
+ //
+ // Wait until higher-level protocol has returned all NBLs
+ // to the driver.
+ //
+
+ // Add one NBL "bias" to insure allow event to be reset safely.
+ nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount > 0 );
+ NdisResetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent);
+
+ //
+ // Now remove the bias and wait for the ReceiveNblInFlightCountZeroEvent
+ // if the count returned is not zero.
+ //
+ nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount >= 0);
+
+ if(nblCount)
+ {
+ LARGE_INTEGER startTime, currentTime;
+
+ NdisGetSystemUpTimeEx(&startTime);
+
+ for (;;)
+ {
+ BOOLEAN waitResult = NdisWaitEvent(
+ &Adapter->ReceiveNblInFlightCountZeroEvent,
+ TAP_WAIT_POLL_LOOP_TIMEOUT
+ );
+
+ NdisGetSystemUpTimeEx(&currentTime);
+
+ if (waitResult)
+ {
+ break;
+ }
+
+ DEBUGP (("[%s] Waiting for %d in-flight receive NBLs to be returned.\n",
+ MINIPORT_INSTANCE_ID (Adapter),
+ Adapter->ReceiveNblInFlightCount
+ ));
+ }
+
+ DEBUGP (("[%s] Waited %d ms for all in-flight NBLs to be returned.\n",
+ MINIPORT_INSTANCE_ID (Adapter),
+ (currentTime.LowPart - startTime.LowPart)
+ ));
+ }
+}
+
+NDIS_STATUS
+AdapterPause(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PNDIS_MINIPORT_PAUSE_PARAMETERS PauseParameters
+ )
+/*++
+
+Routine Description:
+
+ When a miniport receives a pause request, it enters into a Pausing state.
+ The miniport should not indicate up any more network data. Any pending
+ send requests must be completed, and new requests must be rejected with
+ NDIS_STATUS_PAUSED.
+
+ Once all sends have been completed and all recieve NBLs have returned to
+ the miniport, the miniport enters the Paused state.
+
+ While paused, the miniport can still service interrupts from the hardware
+ (to, for example, continue to indicate NDIS_STATUS_MEDIA_CONNECT
+ notifications).
+
+ The miniport must continue to be able to handle status indications and OID
+ requests. MiniportPause is different from MiniportHalt because, in
+ general, the MiniportPause operation won't release any resources.
+ MiniportPause must not attempt to acquire any resources where allocation
+ can fail, since MiniportPause itself must not fail.
+
+
+ MiniportPause runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the Adapter
+ MiniportPauseParameters Additional information about the pause operation
+
+Return Value:
+
+ If the miniport is able to immediately enter the Paused state, it should
+ return NDIS_STATUS_SUCCESS.
+
+ If the miniport must wait for send completions or pending receive NBLs, it
+ should return NDIS_STATUS_PENDING now, and call NDISMPauseComplete when the
+ miniport has entered the Paused state.
+
+ No other return value is permitted. The pause operation must not fail.
+
+--*/
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+ NDIS_STATUS status;
+
+ UNREFERENCED_PARAMETER(PauseParameters);
+
+ DEBUGP (("[TAP] --> AdapterPause\n"));
+
+ // Enter the Pausing state.
+ DEBUGP (("[TAP] Miniport State: Pausing\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportPausingState;
+ tapAdapterReleaseLock(adapter,FALSE);
+
+ //
+ // Stop the flow of network data through the receive path
+ // ------------------------------------------------------
+ // In the Pausing and Paused state tapAdapterSendAndReceiveReady
+ // will prevent new calls to NdisMIndicateReceiveNetBufferLists
+ // to indicate additional receive NBLs to the host.
+ //
+ // However, there may be some in-flight NBLs owned by the driver
+ // that have been indicated to the host but have not yet been
+ // returned.
+ //
+ // Wait here for all in-flight receive indications to be returned.
+ //
+ tapWaitForReceiveNblInFlightCountZeroEvent(adapter);
+
+ //
+ // Stop the flow of network data through the send path
+ // ---------------------------------------------------
+ // The initial implementation of the NDIS 6 send path follows the
+ // NDIS 5 pattern. Under this approach every send packet is copied
+ // into a driver-owned TAP_PACKET structure and the NBL owned by
+ // higher-level protocol is immediatly completed.
+ //
+ // With this deep-copy approach the driver never claims ownership
+ // of any send NBL.
+ //
+ // A future implementation may queue send NBLs and thereby eliminate
+ // the need for the unnecessary allocation and deep copy of each packet.
+ //
+ // So, nothing to do here for the send path for now...
+
+ status = NDIS_STATUS_SUCCESS;
+
+ // Enter the Paused state.
+ DEBUGP (("[TAP] Miniport State: Paused\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportPausedState;
+ tapAdapterReleaseLock(adapter,FALSE);
+
+ DEBUGP (("[TAP] <-- AdapterPause; status = %8.8X\n",status));
+
+ return status;
+}
+
+NDIS_STATUS
+AdapterRestart(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PNDIS_MINIPORT_RESTART_PARAMETERS RestartParameters
+ )
+/*++
+
+Routine Description:
+
+ When a miniport receives a restart request, it enters into a Restarting
+ state. The miniport may begin indicating received data (e.g., using
+ NdisMIndicateReceiveNetBufferLists), handling status indications, and
+ processing OID requests in the Restarting state. However, no sends will be
+ requested while the miniport is in the Restarting state.
+
+ Once the miniport is ready to send data, it has entered the Running state.
+ The miniport informs NDIS that it is in the Running state by returning
+ NDIS_STATUS_SUCCESS from this MiniportRestart function; or if this function
+ has already returned NDIS_STATUS_PENDING, by calling NdisMRestartComplete.
+
+
+ MiniportRestart runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the Adapter
+ RestartParameters Additional information about the restart operation
+
+Return Value:
+
+ If the miniport is able to immediately enter the Running state, it should
+ return NDIS_STATUS_SUCCESS.
+
+ If the miniport is still in the Restarting state, it should return
+ NDIS_STATUS_PENDING now, and call NdisMRestartComplete when the miniport
+ has entered the Running state.
+
+ Other NDIS_STATUS codes indicate errors. If an error is encountered, the
+ miniport must return to the Paused state (i.e., stop indicating receives).
+
+--*/
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+ NDIS_STATUS status;
+
+ UNREFERENCED_PARAMETER(RestartParameters);
+
+ DEBUGP (("[TAP] --> AdapterRestart\n"));
+
+ // Enter the Restarting state.
+ DEBUGP (("[TAP] Miniport State: Restarting\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportRestartingState;
+ tapAdapterReleaseLock(adapter,FALSE);
+
+ status = NDIS_STATUS_SUCCESS;
+
+ if(status == NDIS_STATUS_SUCCESS)
+ {
+ // Enter the Running state.
+ DEBUGP (("[TAP] Miniport State: Running\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportRunning;
+ tapAdapterReleaseLock(adapter,FALSE);
+ }
+ else
+ {
+ // Enter the Paused state if restart failed.
+ DEBUGP (("[TAP] Miniport State: Paused\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportPausedState;
+ tapAdapterReleaseLock(adapter,FALSE);
+ }
+
+ DEBUGP (("[TAP] <-- AdapterRestart; status = %8.8X\n",status));
+
+ return status;
+}
+
+BOOLEAN
+tapAdapterReadAndWriteReady(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine determines whether the adapter device interface can
+ accept read and write operations.
+
+Arguments:
+
+ Adapter Pointer to our adapter context
+
+Return Value:
+
+ Returns TRUE if the adapter state allows it to queue IRPs passed to
+ the device read and write callbacks.
+--*/
+{
+ if(!Adapter->TapDeviceCreated)
+ {
+ // TAP device not created or is being destroyed.
+ return FALSE;
+ }
+
+ if(Adapter->TapFileObject == NULL)
+ {
+ // TAP application file object not open.
+ return FALSE;
+ }
+
+ if(!Adapter->TapFileIsOpen)
+ {
+ // TAP application file object may be closing.
+ return FALSE;
+ }
+
+ if(!Adapter->LogicalMediaState)
+ {
+ // Don't handle read/write if media not connected.
+ return FALSE;
+ }
+
+ if(Adapter->CurrentPowerState != NdisDeviceStateD0)
+ {
+ // Don't handle read/write if device is not fully powered.
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+NDIS_STATUS
+tapAdapterSendAndReceiveReady(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine determines whether the adapter NDIS send and receive
+ paths are ready.
+
+ This routine examines various adapter state variables and returns
+ a value that indicates whether the adapter NDIS interfaces can
+ accept send packets or indicate receive packets.
+
+ In normal operation the adapter may temporarily enter and then exit
+ a not-ready condition. In particular, the adapter becomes not-ready
+ when in the Pausing/Paused states, but may become ready again when
+ Restarted.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter Pointer to our adapter context
+
+Return Value:
+
+ Returns NDIS_STATUS_SUCCESS if the adapter state allows it to
+ accept send packets and indicate receive packets.
+
+ Otherwise it returns a NDIS_STATUS value other than NDIS_STATUS_SUCCESS.
+ These status values can be used directly as the completion status for
+ packets that must be completed immediatly in the send path.
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Check various state variables to insure adapter is ready.
+ //
+ tapAdapterAcquireLock(Adapter,FALSE);
+
+ if(!Adapter->LogicalMediaState)
+ {
+ status = NDIS_STATUS_MEDIA_DISCONNECTED;
+ }
+ else if(Adapter->CurrentPowerState != NdisDeviceStateD0)
+ {
+ status = NDIS_STATUS_LOW_POWER_STATE;
+ }
+ else if(Adapter->ResetInProgress)
+ {
+ status = NDIS_STATUS_RESET_IN_PROGRESS;
+ }
+ else
+ {
+ switch(Adapter->Locked.AdapterState)
+ {
+ case MiniportPausingState:
+ case MiniportPausedState:
+ status = NDIS_STATUS_PAUSED;
+ break;
+
+ case MiniportHaltedState:
+ status = NDIS_STATUS_INVALID_STATE;
+ break;
+
+ default:
+ status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ tapAdapterReleaseLock(Adapter,FALSE);
+
+ return status;
+}
+
+BOOLEAN
+AdapterCheckForHangEx(
+ __in NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ The MiniportCheckForHangEx handler is called to report the state of the
+ NIC, or to monitor the responsiveness of an underlying device driver.
+ This is an optional function. If this handler is not specified, NDIS
+ judges the driver unresponsive when the driver holds
+ MiniportQueryInformation or MiniportSetInformation requests for a
+ time-out interval (deafult 4 sec), and then calls the driver's
+ MiniportReset function. A NIC driver's MiniportInitialize function can
+ extend NDIS's time-out interval by calling NdisMSetAttributesEx to
+ avoid unnecessary resets.
+
+ MiniportCheckForHangEx runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+
+Return Value:
+
+ TRUE NDIS calls the driver's MiniportReset function.
+ FALSE Everything is fine
+
+--*/
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+ //DEBUGP (("[TAP] --> AdapterCheckForHangEx\n"));
+
+ //DEBUGP (("[TAP] <-- AdapterCheckForHangEx; status = FALSE\n"));
+
+ return FALSE; // Everything is fine
+}
+
+NDIS_STATUS
+AdapterReset(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __out PBOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+ MiniportResetEx is a required to issue a hardware reset to the NIC
+ and/or to reset the driver's software state.
+
+ 1) The miniport driver can optionally complete any pending
+ OID requests. NDIS will submit no further OID requests
+ to the miniport driver for the NIC being reset until
+ the reset operation has finished. After the reset,
+ NDIS will resubmit to the miniport driver any OID requests
+ that were pending but not completed by the miniport driver
+ before the reset.
+
+ 2) A deserialized miniport driver must complete any pending send
+ operations. NDIS will not requeue pending send packets for
+ a deserialized driver since NDIS does not maintain the send
+ queue for such a driver.
+
+ 3) If MiniportReset returns NDIS_STATUS_PENDING, the driver must
+ complete the original request subsequently with a call to
+ NdisMResetComplete.
+
+ MiniportReset runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+AddressingReset - If multicast or functional addressing information
+ or the lookahead size, is changed by a reset,
+ MiniportReset must set the variable at AddressingReset
+ to TRUE before it returns control. This causes NDIS to
+ call the MiniportSetInformation function to restore
+ the information.
+
+MiniportAdapterContext - Pointer to our adapter
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+ NDIS_STATUS status;
+
+ UNREFERENCED_PARAMETER(MiniportAdapterContext);
+ UNREFERENCED_PARAMETER(AddressingReset);
+
+ DEBUGP (("[TAP] --> AdapterReset\n"));
+
+ // Indicate that adapter reset is in progress.
+ adapter->ResetInProgress = TRUE;
+
+ // See note above...
+ *AddressingReset = FALSE;
+
+ // BUGBUG!!! TODO!!! Lots of work here...
+
+ // Indicate that adapter reset has completed.
+ adapter->ResetInProgress = FALSE;
+
+ status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP (("[TAP] <-- AdapterReset; status = %8.8X\n",status));
+
+ return status;
+}
+
+VOID
+AdapterDevicePnpEventNotify(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PNET_DEVICE_PNP_EVENT NetDevicePnPEvent
+ )
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+ DEBUGP (("[TAP] --> AdapterDevicePnpEventNotify\n"));
+
+/*
+ switch (NetDevicePnPEvent->DevicePnPEvent)
+ {
+ case NdisDevicePnPEventSurpriseRemoved:
+ //
+ // Called when NDIS receives IRP_MN_SUPRISE_REMOVAL.
+ // NDIS calls MiniportHalt function after this call returns.
+ //
+ MP_SET_FLAG(Adapter, fMP_ADAPTER_SURPRISE_REMOVED);
+ DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventSurpriseRemoved\n", Adapter);
+ break;
+
+ case NdisDevicePnPEventPowerProfileChanged:
+ //
+ // After initializing a miniport driver and after miniport driver
+ // receives an OID_PNP_SET_POWER notification that specifies
+ // a device power state of NdisDeviceStateD0 (the powered-on state),
+ // NDIS calls the miniport's MiniportPnPEventNotify function with
+ // PnPEvent set to NdisDevicePnPEventPowerProfileChanged.
+ //
+ DEBUGP(MP_INFO, "[%p] MPDevicePnpEventNotify: NdisDevicePnPEventPowerProfileChanged\n", Adapter);
+
+ if (NetDevicePnPEvent->InformationBufferLength == sizeof(ULONG))
+ {
+ ULONG NdisPowerProfile = *((PULONG)NetDevicePnPEvent->InformationBuffer);
+
+ if (NdisPowerProfile == NdisPowerProfileBattery)
+ {
+ DEBUGP(MP_INFO, "[%p] The host system is running on battery power\n", Adapter);
+ }
+ if (NdisPowerProfile == NdisPowerProfileAcOnLine)
+ {
+ DEBUGP(MP_INFO, "[%p] The host system is running on AC power\n", Adapter);
+ }
+ }
+ break;
+
+ default:
+ DEBUGP(MP_ERROR, "[%p] MPDevicePnpEventNotify: unknown PnP event 0x%x\n", Adapter, NetDevicePnPEvent->DevicePnPEvent);
+ }
+*/
+ DEBUGP (("[TAP] <-- AdapterDevicePnpEventNotify\n"));
+}
+
+VOID
+AdapterShutdownEx(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in NDIS_SHUTDOWN_ACTION ShutdownAction
+ )
+/*++
+
+Routine Description:
+
+ The MiniportShutdownEx handler restores hardware to its initial state when
+ the system is shut down, whether by the user or because an unrecoverable
+ system error occurred. This is to ensure that the NIC is in a known
+ state and ready to be reinitialized when the machine is rebooted after
+ a system shutdown occurs for any reason, including a crash dump.
+
+ Here just disable the interrupt and stop the DMA engine. Do not free
+ memory resources or wait for any packet transfers to complete. Do not call
+ into NDIS at this time.
+
+ This can be called at aribitrary IRQL, including in the context of a
+ bugcheck.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ ShutdownAction The reason why NDIS called the shutdown function
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+ UNREFERENCED_PARAMETER(ShutdownAction);
+ UNREFERENCED_PARAMETER(MiniportAdapterContext);
+
+ DEBUGP (("[TAP] --> AdapterShutdownEx\n"));
+
+ // Enter the Shutdown state.
+ DEBUGP (("[TAP] Miniport State: Shutdown\n"));
+
+ tapAdapterAcquireLock(adapter,FALSE);
+ adapter->Locked.AdapterState = MiniportShutdownState;
+ tapAdapterReleaseLock(adapter,FALSE);
+
+ //
+ // BUGBUG!!! FlushIrpQueues???
+ //
+
+ DEBUGP (("[TAP] <-- AdapterShutdownEx\n"));
+}
+
+
+// Free adapter context memory and associated resources.
+VOID
+tapAdapterContextFree(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ PLIST_ENTRY listEntry = &Adapter->AdapterListLink;
+
+ DEBUGP (("[TAP] --> tapAdapterContextFree\n"));
+
+ // Adapter context should already be removed.
+ ASSERT( (listEntry->Flink == listEntry) && (listEntry->Blink == listEntry ) );
+
+ // Insure that adapter context has been removed from global adapter list.
+ RemoveEntryList(&Adapter->AdapterListLink);
+
+ // Free the adapter lock.
+ NdisFreeSpinLock(&Adapter->AdapterLock);
+
+ // Free the ANSI NetCfgInstanceId buffer.
+ if(Adapter->NetCfgInstanceIdAnsi.Buffer != NULL)
+ {
+ RtlFreeAnsiString(&Adapter->NetCfgInstanceIdAnsi);
+ }
+
+ Adapter->NetCfgInstanceIdAnsi.Buffer = NULL;
+
+ // Free the receive NBL pool.
+ if(Adapter->ReceiveNblPool != NULL )
+ {
+ NdisFreeNetBufferListPool(Adapter->ReceiveNblPool);
+ }
+
+ Adapter->ReceiveNblPool = NULL;
+
+ NdisFreeMemory(Adapter,0,0);
+
+ DEBUGP (("[TAP] <-- tapAdapterContextFree\n"));
+}
+ULONG
+tapGetNetBufferFrameType(
+ __in PNET_BUFFER NetBuffer
+ )
+/*++
+
+Routine Description:
+
+ Reads the network frame's destination address to determine the type
+ (broadcast, multicast, etc)
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ NetBuffer The NB to examine
+
+Return Value:
+
+ NDIS_PACKET_TYPE_BROADCAST
+ NDIS_PACKET_TYPE_MULTICAST
+ NDIS_PACKET_TYPE_DIRECTED
+
+--*/
+{
+ PETH_HEADER ethernetHeader;
+
+ ethernetHeader = (PETH_HEADER )NdisGetDataBuffer(
+ NetBuffer,
+ sizeof(ETH_HEADER),
+ NULL,
+ 1,
+ 0
+ );
+
+ ASSERT(ethernetHeader);
+
+ if (ETH_IS_BROADCAST(ethernetHeader->dest))
+ {
+ return NDIS_PACKET_TYPE_BROADCAST;
+ }
+ else if(ETH_IS_MULTICAST(ethernetHeader->dest))
+ {
+ return NDIS_PACKET_TYPE_MULTICAST;
+ }
+ else
+ {
+ return NDIS_PACKET_TYPE_DIRECTED;
+ }
+
+}
+
+ULONG
+tapGetNetBufferCountsFromNetBufferList(
+ __in PNET_BUFFER_LIST NetBufferList,
+ __inout_opt PULONG TotalByteCount // Of all linked NBs
+ )
+/*++
+
+Routine Description:
+
+ Returns the number of net buffers linked to the net buffer list.
+
+ Optionally retuens the total byte count of all net buffers linked
+ to the net buffer list
+
+ Runs at IRQL <= DISPATCH_LEVEL.
+
+Arguments:
+
+ NetBufferList The NBL to examine
+
+Return Value:
+
+ The number of net buffers linked to the net buffer list.
+
+--*/
+{
+ ULONG netBufferCount = 0;
+ PNET_BUFFER currentNb;
+
+ if(TotalByteCount)
+ {
+ *TotalByteCount = 0;
+ }
+
+ currentNb = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+
+ while(currentNb)
+ {
+ ++netBufferCount;
+
+ if(TotalByteCount)
+ {
+ *TotalByteCount += NET_BUFFER_DATA_LENGTH(currentNb);
+ }
+
+ // Move to next NB
+ currentNb = NET_BUFFER_NEXT_NB(currentNb);
+ }
+
+ return netBufferCount;
+}
+
+VOID
+tapAdapterAcquireLock(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in BOOLEAN DispatchLevel
+ )
+{
+ ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql()));
+
+ if (DispatchLevel)
+ {
+ NdisDprAcquireSpinLock(&Adapter->AdapterLock);
+ }
+ else
+ {
+ NdisAcquireSpinLock(&Adapter->AdapterLock);
+ }
+}
+
+VOID
+tapAdapterReleaseLock(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in BOOLEAN DispatchLevel
+ )
+{
+ ASSERT(!DispatchLevel || (DISPATCH_LEVEL == KeGetCurrentIrql()));
+
+ if (DispatchLevel)
+ {
+ NdisDprReleaseSpinLock(&Adapter->AdapterLock);
+ }
+ else
+ {
+ NdisReleaseSpinLock(&Adapter->AdapterLock);
+ }
+}
+
+
diff --git a/windows/TapDriver6/adapter.h b/windows/TapDriver6/adapter.h
new file mode 100644
index 00000000..0ebaaea7
--- /dev/null
+++ b/windows/TapDriver6/adapter.h
@@ -0,0 +1,352 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __TAP_ADAPTER_CONTEXT_H_
+#define __TAP_ADAPTER_CONTEXT_H_
+
+#include "tap.h"
+
+// Memory allocation tags.
+#define TAP_ADAPTER_TAG ((ULONG)'ApaT') // "TapA
+#define TAP_RX_NBL_TAG ((ULONG)'RpaT') // "TapR
+#define TAP_RX_INJECT_BUFFER_TAG ((ULONG)'IpaT') // "TapI
+
+#define TAP_MAX_NDIS_NAME_LENGTH 64 // 38 character GUID string plus extra..
+
+// TAP receive indication NBL flag definitions.
+#define TAP_RX_NBL_FLAGS NBL_FLAGS_MINIPORT_RESERVED
+#define TAP_RX_NBL_FLAGS_CLEAR_ALL(_NBL) ((_NBL)->Flags &= ~TAP_RX_NBL_FLAGS)
+#define TAP_RX_NBL_FLAG_SET(_NBL, _F) ((_NBL)->Flags |= ((_F) & TAP_RX_NBL_FLAGS))
+#define TAP_RX_NBL_FLAG_CLEAR(_NBL, _F) ((_NBL)->Flags &= ~((_F) & TAP_RX_NBL_FLAGS))
+#define TAP_RX_NBL_FLAG_TEST(_NBL, _F) (((_NBL)->Flags & ((_F) & TAP_RX_NBL_FLAGS)) != 0)
+
+#define TAP_RX_NBL_FLAGS_IS_P2P 0x00001000
+#define TAP_RX_NBL_FLAGS_IS_INJECTED 0x00002000
+
+// MSDN Ref: http://msdn.microsoft.com/en-us/library/windows/hardware/ff560490(v=vs.85).aspx
+typedef
+enum _TAP_MINIPORT_ADAPTER_STATE
+{
+ // The Halted state is the initial state of all adapters. When an
+ // adapter is in the Halted state, NDIS can call the driver's
+ // MiniportInitializeEx function to initialize the adapter.
+ MiniportHaltedState,
+
+ // In the Shutdown state, a system shutdown and restart must occur
+ // before the system can use the adapter again.
+ MiniportShutdownState,
+
+ // In the Initializing state, a miniport driver completes any
+ //operations that are required to initialize an adapter.
+ MiniportInitializingState,
+
+ // Entering the Paused state...
+ MiniportPausingState,
+
+ // In the Paused state, the adapter does not indicate received
+ // network data or accept send requests.
+ MiniportPausedState,
+
+ // In the Running state, a miniport driver performs send and
+ // receive processing for an adapter.
+ MiniportRunning,
+
+ // In the Restarting state, a miniport driver completes any
+ // operations that are required to restart send and receive
+ // operations for an adapter.
+ MiniportRestartingState
+} TAP_MINIPORT_ADAPTER_STATE, *PTAP_MINIPORT_ADAPTER_STATE;
+
+//
+// Each adapter managed by this driver has a TapAdapter struct.
+// ------------------------------------------------------------
+// Since there is a one-to-one relationship between adapter instances
+// and device instances this structure is the device extension as well.
+//
+typedef struct _TAP_ADAPTER_CONTEXT
+{
+ LIST_ENTRY AdapterListLink;
+
+ volatile LONG RefCount;
+
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ NDIS_SPIN_LOCK AdapterLock; // Lock for protection of state and outstanding sends and recvs
+
+ //
+ // All fields that are protected by the AdapterLock are included
+ // in the Locked structure to remind us to take the Lock
+ // before accessing them :)
+ //
+ struct
+ {
+ TAP_MINIPORT_ADAPTER_STATE AdapterState;
+ } Locked;
+
+ BOOLEAN ResetInProgress;
+
+ //
+ // NetCfgInstanceId as UNICODE_STRING
+ // ----------------------------------
+ // This a GUID string provided by NDIS that identifies the adapter instance.
+ // An example is:
+ //
+ // NetCfgInstanceId={410EB49D-2381-4FE7-9B36-498E22619DF0}
+ //
+ // Other names are derived from NetCfgInstanceId. For example, MiniportName:
+ //
+ // MiniportName=\DEVICE\{410EB49D-2381-4FE7-9B36-498E22619DF0}
+ //
+ NDIS_STRING NetCfgInstanceId;
+ WCHAR NetCfgInstanceIdBuffer[TAP_MAX_NDIS_NAME_LENGTH];
+
+# define MINIPORT_INSTANCE_ID(a) ((a)->NetCfgInstanceIdAnsi.Buffer)
+ ANSI_STRING NetCfgInstanceIdAnsi; // Used occasionally
+
+ ULONG MtuSize; // 1500 byte (typical)
+
+ // TRUE if adapter should always be "connected" even when device node
+ // is not open by a userspace process.
+ //
+ // FALSE if connection state is application controlled.
+ BOOLEAN MediaStateAlwaysConnected;
+
+ // TRUE if device is "connected".
+ BOOLEAN LogicalMediaState;
+
+ NDIS_DEVICE_POWER_STATE CurrentPowerState;
+
+ BOOLEAN AllowNonAdmin;
+
+ MACADDR PermanentAddress; // From registry, if available
+ MACADDR CurrentAddress;
+
+ // Device registration parameters from NdisRegisterDeviceEx.
+ NDIS_STRING DeviceName;
+ WCHAR DeviceNameBuffer[TAP_MAX_NDIS_NAME_LENGTH];
+
+ NDIS_STRING LinkName;
+ WCHAR LinkNameBuffer[TAP_MAX_NDIS_NAME_LENGTH];
+
+ NDIS_HANDLE DeviceHandle;
+ PDEVICE_OBJECT DeviceObject;
+ BOOLEAN TapDeviceCreated; // WAS: m_TapIsRunning
+
+ PFILE_OBJECT TapFileObject; // Exclusive access
+ BOOLEAN TapFileIsOpen; // WAS: m_TapOpens
+ LONG TapFileOpenCount; // WAS: m_NumTapOpens
+
+ // Cancel-Safe read IRP queue.
+ TAP_IRP_CSQ PendingReadIrpQueue;
+
+ // Queue containing TAP packets representing host send NBs. These are
+ // waiting to be read by user-mode application.
+ TAP_PACKET_QUEUE SendPacketQueue;
+
+ // NBL pool for making TAP receive indications.
+ NDIS_HANDLE ReceiveNblPool;
+
+ volatile LONG ReceiveNblInFlightCount;
+#define TAP_WAIT_POLL_LOOP_TIMEOUT 3000 // 3 seconds
+ NDIS_EVENT ReceiveNblInFlightCountZeroEvent;
+
+ /*
+ // Info for point-to-point mode
+ BOOLEAN m_tun;
+ IPADDR m_localIP;
+ IPADDR m_remoteNetwork;
+ IPADDR m_remoteNetmask;
+ ETH_HEADER m_TapToUser;
+ ETH_HEADER m_UserToTap;
+ ETH_HEADER m_UserToTap_IPv6; // same as UserToTap but proto=ipv6
+ */
+
+ // Info for DHCP server masquerade
+ /*
+ BOOLEAN m_dhcp_enabled;
+ IPADDR m_dhcp_addr;
+ ULONG m_dhcp_netmask;
+ IPADDR m_dhcp_server_ip;
+ BOOLEAN m_dhcp_server_arp;
+ MACADDR m_dhcp_server_mac;
+ ULONG m_dhcp_lease_time;
+ UCHAR m_dhcp_user_supplied_options_buffer[DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE];
+ ULONG m_dhcp_user_supplied_options_buffer_len;
+ BOOLEAN m_dhcp_received_discover;
+ ULONG m_dhcp_bad_requests;
+ */
+
+ // Multicast list. Fixed size.
+ ULONG ulMCListSize;
+ UCHAR MCList[TAP_MAX_MCAST_LIST][MACADDR_SIZE];
+
+ ULONG PacketFilter;
+ ULONG ulLookahead;
+
+ //
+ // Statistics
+ // -------------------------------------------------------------------------
+ //
+
+ // Packet counts
+ ULONG64 FramesRxDirected;
+ ULONG64 FramesRxMulticast;
+ ULONG64 FramesRxBroadcast;
+ ULONG64 FramesTxDirected;
+ ULONG64 FramesTxMulticast;
+ ULONG64 FramesTxBroadcast;
+
+ // Byte counts
+ ULONG64 BytesRxDirected;
+ ULONG64 BytesRxMulticast;
+ ULONG64 BytesRxBroadcast;
+ ULONG64 BytesTxDirected;
+ ULONG64 BytesTxMulticast;
+ ULONG64 BytesTxBroadcast;
+
+ // Count of transmit errors
+ ULONG TxAbortExcessCollisions;
+ ULONG TxLateCollisions;
+ ULONG TxDmaUnderrun;
+ ULONG TxLostCRS;
+ ULONG TxOKButDeferred;
+ ULONG OneRetry;
+ ULONG MoreThanOneRetry;
+ ULONG TotalRetries;
+ ULONG TransmitFailuresOther;
+
+ // Count of receive errors
+ ULONG RxCrcErrors;
+ ULONG RxAlignmentErrors;
+ ULONG RxResourceErrors;
+ ULONG RxDmaOverrunErrors;
+ ULONG RxCdtFrames;
+ ULONG RxRuntErrors;
+
+#if PACKET_TRUNCATION_CHECK
+ LONG m_RxTrunc, m_TxTrunc;
+#endif
+
+ BOOLEAN m_InterfaceIsRunning;
+ LONG m_Rx, m_RxErr;
+ NDIS_MEDIUM m_Medium;
+
+ // Help to tear down the adapter by keeping
+ // some state information on allocated
+ // resources.
+ BOOLEAN m_CalledAdapterFreeResources;
+ BOOLEAN m_RegisteredAdapterShutdownHandler;
+
+} TAP_ADAPTER_CONTEXT, *PTAP_ADAPTER_CONTEXT;
+
+FORCEINLINE
+LONG
+tapAdapterContextReference(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ LONG refCount = NdisInterlockedIncrement(&Adapter->RefCount);
+
+ ASSERT(refCount>1); // Cannot dereference a zombie.
+
+ return refCount;
+}
+
+VOID
+tapAdapterContextFree(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ );
+
+FORCEINLINE
+LONG
+tapAdapterContextDereference(
+ IN PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ LONG refCount = NdisInterlockedDecrement(&Adapter->RefCount);
+ ASSERT(refCount >= 0);
+ if (!refCount)
+ {
+ tapAdapterContextFree(Adapter);
+ }
+
+ return refCount;
+}
+
+VOID
+tapAdapterAcquireLock(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in BOOLEAN DispatchLevel
+ );
+
+VOID
+tapAdapterReleaseLock(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in BOOLEAN DispatchLevel
+ );
+
+// Returns with added reference on adapter context.
+PTAP_ADAPTER_CONTEXT
+tapAdapterContextFromDeviceObject(
+ __in PDEVICE_OBJECT DeviceObject
+ );
+
+BOOLEAN
+tapAdapterReadAndWriteReady(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ );
+
+NDIS_STATUS
+tapAdapterSendAndReceiveReady(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ );
+
+ULONG
+tapGetNetBufferFrameType(
+ __in PNET_BUFFER NetBuffer
+ );
+
+ULONG
+tapGetNetBufferCountsFromNetBufferList(
+ __in PNET_BUFFER_LIST NetBufferList,
+ __inout_opt PULONG TotalByteCount // Of all linked NBs
+ );
+
+// Prototypes for standard NDIS miniport entry points
+MINIPORT_SET_OPTIONS AdapterSetOptions;
+MINIPORT_INITIALIZE AdapterCreate;
+MINIPORT_HALT AdapterHalt;
+MINIPORT_UNLOAD TapDriverUnload;
+MINIPORT_PAUSE AdapterPause;
+MINIPORT_RESTART AdapterRestart;
+MINIPORT_OID_REQUEST AdapterOidRequest;
+MINIPORT_SEND_NET_BUFFER_LISTS AdapterSendNetBufferLists;
+MINIPORT_RETURN_NET_BUFFER_LISTS AdapterReturnNetBufferLists;
+MINIPORT_CANCEL_SEND AdapterCancelSend;
+MINIPORT_CHECK_FOR_HANG AdapterCheckForHangEx;
+MINIPORT_RESET AdapterReset;
+MINIPORT_DEVICE_PNP_EVENT_NOTIFY AdapterDevicePnpEventNotify;
+MINIPORT_SHUTDOWN AdapterShutdownEx;
+MINIPORT_CANCEL_OID_REQUEST AdapterCancelOidRequest;
+
+#endif // __TAP_ADAPTER_CONTEXT_H_ \ No newline at end of file
diff --git a/windows/TapDriver6/config.h b/windows/TapDriver6/config.h
new file mode 100644
index 00000000..4d36c5a1
--- /dev/null
+++ b/windows/TapDriver6/config.h
@@ -0,0 +1,9 @@
+#define PRODUCT_NAME "ZeroTier One Virtual Port"
+#define PRODUCT_VERSION "3.0.0"
+#define PRODUCT_VERSION_RESOURCE 3,0,0,1
+#define PRODUCT_TAP_WIN_COMPONENT_ID "zttap300"
+#define PRODUCT_TAP_WIN_MAJOR 3
+#define PRODUCT_TAP_WIN_MINOR 0
+#define PRODUCT_TAP_WIN_PROVIDER "ZeroTier Networks"
+#define PRODUCT_TAP_WIN_DEVICE_DESCRIPTION PRODUCT_NAME
+#define PRODUCT_TAP_WIN_RELDATE "04/25/2015"
diff --git a/windows/TapDriver6/constants.h b/windows/TapDriver6/constants.h
new file mode 100644
index 00000000..91a876f2
--- /dev/null
+++ b/windows/TapDriver6/constants.h
@@ -0,0 +1,196 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//====================================================================
+// Product and Version public settings
+//====================================================================
+
+#define PRODUCT_STRING PRODUCT_TAP_DEVICE_DESCRIPTION
+
+
+//
+// Update the driver version number every time you release a new driver
+// The high word is the major version. The low word is the minor version.
+// Also make sure that VER_FILEVERSION specified in the .RC file also
+// matches with the driver version because NDISTESTER checks for that.
+//
+#ifndef TAP_DRIVER_MAJOR_VERSION
+
+#define TAP_DRIVER_MAJOR_VERSION 0x04
+#define TAP_DRIVER_MINOR_VERSION 0x02
+
+#endif
+
+#define TAP_DRIVER_VENDOR_VERSION ((TAP_DRIVER_MAJOR_VERSION << 16) | TAP_DRIVER_MINOR_VERSION)
+
+//
+// Define the NDIS miniport interface version that this driver targets.
+//
+#if defined(NDIS60_MINIPORT)
+# define TAP_NDIS_MAJOR_VERSION 6
+# define TAP_NDIS_MINOR_VERSION 0
+#elif defined(NDIS61_MINIPORT)
+# define TAP_NDIS_MAJOR_VERSION 6
+# define TAP_NDIS_MINOR_VERSION 1
+#elif defined(NDIS620_MINIPORT)
+# define TAP_NDIS_MAJOR_VERSION 6
+# define TAP_NDIS_MINOR_VERSION 20
+#elif defined(NDIS630_MINIPORT)
+# define TAP_NDIS_MAJOR_VERSION 6
+# define TAP_NDIS_MINOR_VERSION 30
+#else
+#define TAP_NDIS_MAJOR_VERSION 5
+#define TAP_NDIS_MINOR_VERSION 0
+#endif
+
+//===========================================================
+// Driver constants
+//===========================================================
+
+#define ETHERNET_HEADER_SIZE (sizeof (ETH_HEADER))
+//#define ETHERNET_MTU 1500
+#define ETHERNET_MTU 2800
+#define ETHERNET_PACKET_SIZE (ETHERNET_MTU + ETHERNET_HEADER_SIZE)
+#define DEFAULT_PACKET_LOOKAHEAD (ETHERNET_PACKET_SIZE)
+#define VLAN_TAG_SIZE 4
+
+//===========================================================
+// Medium properties
+//===========================================================
+
+#define TAP_FRAME_HEADER_SIZE ETHERNET_HEADER_SIZE
+#define TAP_FRAME_MAX_DATA_SIZE ETHERNET_MTU
+#define TAP_MAX_FRAME_SIZE (TAP_FRAME_HEADER_SIZE + TAP_FRAME_MAX_DATA_SIZE)
+#define TAP_MIN_FRAME_SIZE 60
+
+#define TAP_MEDIUM_TYPE NdisMedium802_3
+
+//===========================================================
+// Physical adapter properties
+//===========================================================
+
+// The bus that connects the adapter to the PC.
+// (Example: PCI adapters should use NdisInterfacePci).
+#define TAP_INTERFACE_TYPE NdisInterfaceInternal
+
+#define TAP_VENDOR_DESC PRODUCT_TAP_WIN_DEVICE_DESCRIPTION
+
+// Highest byte is the NIC byte plus three vendor bytes. This is normally
+// obtained from the NIC.
+#define TAP_VENDOR_ID 0x00FFFFFF
+
+// If you have physical hardware on 802.3, use NdisPhysicalMedium802_3.
+#define TAP_PHYSICAL_MEDIUM NdisPhysicalMediumUnspecified
+
+// Claim to be 100mbps duplex
+#define MEGABITS_PER_SECOND 1000000ULL
+#define TAP_XMIT_SPEED (100ULL*MEGABITS_PER_SECOND)
+#define TAP_RECV_SPEED (100ULL*MEGABITS_PER_SECOND)
+
+// Max number of multicast addresses supported in hardware
+#define TAP_MAX_MCAST_LIST 128
+
+#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 128 // Max length of multicast address list
+
+//
+// Specify a bitmask that defines optional properties of the NIC.
+// This miniport indicates receive with NdisMIndicateReceiveNetBufferLists
+// function. Such a driver should set this NDIS_MAC_OPTION_TRANSFERS_NOT_PEND
+// flag.
+//
+// NDIS_MAC_OPTION_NO_LOOPBACK tells NDIS that NIC has no internal
+// loopback support so NDIS will manage loopbacks on behalf of
+// this driver.
+//
+// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA tells the protocol that
+// our receive buffer is not on a device-specific card. If
+// NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA is not set, multi-buffer
+// indications are copied to a single flat buffer.
+//
+
+#define TAP_MAC_OPTIONS (\
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \
+ NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | \
+ NDIS_MAC_OPTION_NO_LOOPBACK)
+
+#define TAP_ADAPTER_CHECK_FOR_HANG_TIME_IN_SECONDS 4
+
+
+// NDIS 6.x miniports must support all counters in OID_GEN_STATISTICS.
+#define TAP_SUPPORTED_STATISTICS (\
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS | \
+ NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR | \
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR | \
+ NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS | \
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV | \
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT | \
+ NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT)
+
+
+#define MINIMUM_MTU 576 // USE TCP Minimum MTU
+#define MAXIMUM_MTU 65536 // IP maximum MTU
+
+#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size
+#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace
+#define INJECT_QUEUE_SIZE 16 // DHCP/ARP -> tap injection queue
+
+#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions
diff --git a/windows/TapDriver6/device.c b/windows/TapDriver6/device.c
new file mode 100644
index 00000000..7367143b
--- /dev/null
+++ b/windows/TapDriver6/device.c
@@ -0,0 +1,1209 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+#include <wdmsec.h> // for SDDLs
+
+//======================================================================
+// TAP Win32 Device I/O Callbacks
+//======================================================================
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, TapDeviceCreate)
+#pragma alloc_text( PAGE, TapDeviceControl)
+#pragma alloc_text( PAGE, TapDeviceCleanup)
+#pragma alloc_text( PAGE, TapDeviceClose)
+#endif // ALLOC_PRAGMA
+
+//===================================================================
+// Go back to default TAP mode from Point-To-Point mode.
+// Also reset (i.e. disable) DHCP Masq mode.
+//===================================================================
+VOID tapResetAdapterState(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ /*
+ // Point-To-Point
+ Adapter->m_tun = FALSE;
+ Adapter->m_localIP = 0;
+ Adapter->m_remoteNetwork = 0;
+ Adapter->m_remoteNetmask = 0;
+ NdisZeroMemory (&Adapter->m_TapToUser, sizeof (Adapter->m_TapToUser));
+ NdisZeroMemory (&Adapter->m_UserToTap, sizeof (Adapter->m_UserToTap));
+ NdisZeroMemory (&Adapter->m_UserToTap_IPv6, sizeof (Adapter->m_UserToTap_IPv6));
+ */
+
+ // DHCP Masq
+ /*
+ Adapter->m_dhcp_enabled = FALSE;
+ Adapter->m_dhcp_server_arp = FALSE;
+ Adapter->m_dhcp_user_supplied_options_buffer_len = 0;
+ Adapter->m_dhcp_addr = 0;
+ Adapter->m_dhcp_netmask = 0;
+ Adapter->m_dhcp_server_ip = 0;
+ Adapter->m_dhcp_lease_time = 0;
+ Adapter->m_dhcp_received_discover = FALSE;
+ Adapter->m_dhcp_bad_requests = 0;
+ NdisZeroMemory (Adapter->m_dhcp_server_mac, MACADDR_SIZE);
+ */
+}
+
+// IRP_MJ_CREATE
+NTSTATUS
+TapDeviceCreate(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system when the device is opened.
+
+ No action is performed other than completing the request successfully.
+
+Arguments:
+
+ DeviceObject - a pointer to the object that represents the device
+ that I/O is to be done on.
+
+ Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NT status code
+
+--*/
+{
+ NDIS_STATUS status;
+ PIO_STACK_LOCATION irpSp;// Pointer to current stack location
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+ PFILE_OBJECT originalFileObject;
+
+ PAGED_CODE();
+
+ DEBUGP (("[TAP] --> TapDeviceCreate\n"));
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ //
+ // Invalidate file context
+ //
+ irpSp->FileObject->FsContext = NULL;
+ irpSp->FileObject->FsContext2 = NULL;
+
+ //
+ // Find adapter context for this device.
+ // -------------------------------------
+ // Returns with added reference on adapter context.
+ //
+ adapter = tapAdapterContextFromDeviceObject(DeviceObject);
+
+ // Insure that adapter exists.
+ ASSERT(adapter);
+
+ if(adapter == NULL )
+ {
+ DEBUGP (("[TAP] release [%d.%d] open request; adapter not found\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION
+ ));
+
+ Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ DEBUGP(("[%s] [TAP] release [%d.%d] open request (TapFileIsOpen=%d)\n",
+ MINIPORT_INSTANCE_ID(adapter),
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ adapter->TapFileIsOpen
+ ));
+
+ // Enforce exclusive access
+ originalFileObject = InterlockedCompareExchangePointer(
+ &adapter->TapFileObject,
+ irpSp->FileObject,
+ NULL
+ );
+
+ if(originalFileObject == NULL)
+ {
+ irpSp->FileObject->FsContext = adapter; // Quick reference
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ // Release the lock.
+ //tapAdapterReleaseLock(adapter,FALSE);
+
+ if(status == STATUS_SUCCESS)
+ {
+ // Reset adapter state on successful open.
+ tapResetAdapterState(adapter);
+
+ adapter->TapFileIsOpen = 1; // Legacy...
+
+ // NOTE!!! Reference added by tapAdapterContextFromDeviceObject
+ // will be removed when file is closed.
+ }
+ else
+ {
+ DEBUGP (("[%s] TAP is presently unavailable (TapFileIsOpen=%d)\n",
+ MINIPORT_INSTANCE_ID(adapter), adapter->TapFileIsOpen
+ ));
+
+ NOTE_ERROR();
+
+ // Remove reference added by tapAdapterContextFromDeviceObject.
+ tapAdapterContextDereference(adapter);
+ }
+
+ // Complete the IRP.
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+ DEBUGP (("[TAP] <-- TapDeviceCreate; status = %8.8X\n",status));
+
+ return status;
+}
+
+//===================================================
+// Tell Windows whether the TAP device should be
+// considered "connected" or "disconnected".
+//
+// Allows application control of media connect state.
+//===================================================
+VOID
+tapSetMediaConnectStatus(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in BOOLEAN LogicalMediaState
+ )
+{
+ NDIS_STATUS_INDICATION statusIndication;
+ NDIS_LINK_STATE linkState;
+
+ NdisZeroMemory(&statusIndication, sizeof(NDIS_STATUS_INDICATION));
+ NdisZeroMemory(&linkState, sizeof(NDIS_LINK_STATE));
+
+ //
+ // Fill in object headers
+ //
+ statusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
+ statusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
+ statusIndication.Header.Size = sizeof(NDIS_STATUS_INDICATION);
+
+ linkState.Header.Revision = NDIS_LINK_STATE_REVISION_1;
+ linkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ linkState.Header.Size = sizeof(NDIS_LINK_STATE);
+
+ //
+ // Link state buffer
+ //
+ if(Adapter->LogicalMediaState == TRUE)
+ {
+ linkState.MediaConnectState = MediaConnectStateConnected;
+ }
+
+ linkState.MediaDuplexState = MediaDuplexStateFull;
+ linkState.RcvLinkSpeed = TAP_RECV_SPEED;
+ linkState.XmitLinkSpeed = TAP_XMIT_SPEED;
+
+ //
+ // Fill in the status buffer
+ //
+ statusIndication.StatusCode = NDIS_STATUS_LINK_STATE;
+ statusIndication.SourceHandle = Adapter->MiniportAdapterHandle;
+ statusIndication.DestinationHandle = NULL;
+ statusIndication.RequestId = 0;
+
+ statusIndication.StatusBuffer = &linkState;
+ statusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE);
+
+ // Fill in new media connect state.
+ if ( (Adapter->LogicalMediaState != LogicalMediaState) && !Adapter->MediaStateAlwaysConnected)
+ {
+ Adapter->LogicalMediaState = LogicalMediaState;
+
+ if (LogicalMediaState == TRUE)
+ {
+ linkState.MediaConnectState = MediaConnectStateConnected;
+
+ DEBUGP (("[TAP] Set MediaConnectState: Connected.\n"));
+ }
+ else
+ {
+ linkState.MediaConnectState = MediaConnectStateDisconnected;
+
+ DEBUGP (("[TAP] Set MediaConnectState: Disconnected.\n"));
+ }
+ }
+
+ // Make the status indication.
+ if(Adapter->Locked.AdapterState != MiniportHaltedState)
+ {
+ NdisMIndicateStatusEx(Adapter->MiniportAdapterHandle, &statusIndication);
+ }
+}
+
+/*
+//======================================================
+// If DHCP mode is used together with tun
+// mode, consider the fact that the P2P remote subnet
+// might enclose the DHCP masq server address.
+//======================================================
+VOID
+CheckIfDhcpAndTunMode (
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ if (Adapter->m_tun && Adapter->m_dhcp_enabled)
+ {
+ if ((Adapter->m_dhcp_server_ip & Adapter->m_remoteNetmask) == Adapter->m_remoteNetwork)
+ {
+ ETH_COPY_NETWORK_ADDRESS (Adapter->m_dhcp_server_mac, Adapter->m_TapToUser.dest);
+ Adapter->m_dhcp_server_arp = FALSE;
+ }
+ }
+}
+*/
+
+// IRP_MJ_DEVICE_CONTROL callback.
+NTSTATUS
+TapDeviceControl(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to perform a device I/O
+ control function.
+
+Arguments:
+
+ DeviceObject - a pointer to the object that represents the device
+ that I/O is to be done on.
+
+ Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NT status code
+
+--*/
+
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS; // Assume success
+ PIO_STACK_LOCATION irpSp; // Pointer to current stack location
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+ ULONG inBufLength; // Input buffer length
+ ULONG outBufLength; // Output buffer length
+ PCHAR inBuf, outBuf; // pointer to Input and output buffer
+ PMDL mdl = NULL;
+ PCHAR buffer = NULL;
+
+ PAGED_CODE();
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Fetch adapter context for this device.
+ // --------------------------------------
+ // Adapter pointer was stashed in FsContext when handle was opened.
+ //
+ adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+ ASSERT(adapter);
+
+ inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
+ outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (!inBufLength || !outBufLength)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ goto End;
+ }
+
+ //
+ // Determine which I/O control code was specified.
+ //
+ switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
+ {
+ case TAP_WIN_IOCTL_GET_MAC:
+ {
+ if (outBufLength >= MACADDR_SIZE )
+ {
+ ETH_COPY_NETWORK_ADDRESS(
+ Irp->AssociatedIrp.SystemBuffer,
+ adapter->CurrentAddress
+ );
+
+ Irp->IoStatus.Information = MACADDR_SIZE;
+ }
+ else
+ {
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ break;
+
+ case TAP_WIN_IOCTL_GET_VERSION:
+ {
+ const ULONG size = sizeof (ULONG) * 3;
+
+ if (outBufLength >= size)
+ {
+ ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]
+ = TAP_DRIVER_MAJOR_VERSION;
+
+ ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[1]
+ = TAP_DRIVER_MINOR_VERSION;
+
+ ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[2]
+#if DBG
+ = 1;
+#else
+ = 0;
+#endif
+ Irp->IoStatus.Information = size;
+ }
+ else
+ {
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ break;
+
+ case TAP_WIN_IOCTL_GET_MTU:
+ {
+ const ULONG size = sizeof (ULONG) * 1;
+
+ if (outBufLength >= size)
+ {
+ ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0]
+ = adapter->MtuSize;
+
+ Irp->IoStatus.Information = size;
+ }
+ else
+ {
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ break;
+
+ // Allow ZeroTier One to get multicast memberships at the L2 level in a
+ // protocol-neutral manner.
+ case TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS:
+ {
+ if (outBufLength < TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE) {
+ /* output buffer too small */
+ NOTE_ERROR ();
+ Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+ } else {
+ char *out = (char *)Irp->AssociatedIrp.SystemBuffer;
+ char *end = out + TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE;
+ unsigned long i,j;
+ for(i=0;i<adapter->ulMCListSize;++i) {
+ if (i >= TAP_MAX_MCAST_LIST)
+ break;
+ for(j=0;j<6;++j)
+ *(out++) = adapter->MCList[i][j];
+ if (out >= end)
+ break;
+ }
+ while (out < end)
+ *(out++) = (char)0;
+ Irp->IoStatus.Information = TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE;
+ Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
+ }
+ break;
+ }
+
+
+#if 0
+ 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;
+#endif
+
+#if 0
+ 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;
+#endif
+
+#if 0
+ 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;
+ }
+#endif
+
+#if DBG
+ case TAP_WIN_IOCTL_GET_LOG_LINE:
+ {
+ if (GetDebugLine( (LPTSTR)Irp->AssociatedIrp.SystemBuffer,outBufLength))
+ {
+ Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ Irp->IoStatus.Status = ntStatus = STATUS_UNSUCCESSFUL;
+ }
+
+ Irp->IoStatus.Information = outBufLength;
+
+ break;
+ }
+#endif
+
+ case TAP_WIN_IOCTL_SET_MEDIA_STATUS:
+ {
+ if(inBufLength >= sizeof(ULONG))
+ {
+ ULONG parm = ((PULONG) (Irp->AssociatedIrp.SystemBuffer))[0];
+ tapSetMediaConnectStatus (adapter, (BOOLEAN) parm);
+ Irp->IoStatus.Information = 1;
+ }
+ else
+ {
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ default:
+
+ //
+ // The specified I/O control code is unrecognized by this driver.
+ //
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+End:
+
+ //
+ // Finish the I/O operation by simply completing the packet and returning
+ // the same status as in the packet itself.
+ //
+ Irp->IoStatus.Status = ntStatus;
+
+ IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+ return ntStatus;
+}
+
+// Flush the pending read IRP queue.
+VOID
+tapFlushIrpQueues(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+
+ DEBUGP (("[TAP] tapFlushIrpQueues: Flushing %d pending read IRPs\n",
+ Adapter->PendingReadIrpQueue.Count));
+
+ tapIrpCsqFlush(&Adapter->PendingReadIrpQueue);
+}
+
+// IRP_MJ_CLEANUP
+NTSTATUS
+TapDeviceCleanup(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ Receipt of this request indicates that the last handle for a file
+ object that is associated with the target device object has been closed
+ (but, due to outstanding I/O requests, might not have been released).
+
+ A driver that holds pending IRPs internally must implement a routine for
+ IRP_MJ_CLEANUP. When the routine is called, the driver should cancel all
+ the pending IRPs that belong to the file object identified by the IRP_MJ_CLEANUP
+ call.
+
+ In other words, it should cancel all the IRPs that have the same file-object
+ pointer as the one supplied in the current I/O stack location of the IRP for the
+ IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should
+ not be canceled. Also, if an outstanding IRP is completed immediately, the
+ driver does not have to cancel it.
+
+Arguments:
+
+ DeviceObject - a pointer to the object that represents the device
+ to be cleaned up.
+
+ Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NT status code
+
+--*/
+
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed.
+ PIO_STACK_LOCATION irpSp; // Pointer to current stack location
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+
+ PAGED_CODE();
+
+ DEBUGP (("[TAP] --> TapDeviceCleanup\n"));
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ //
+ // Fetch adapter context for this device.
+ // --------------------------------------
+ // Adapter pointer was stashed in FsContext when handle was opened.
+ //
+ adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+ // Insure that adapter exists.
+ ASSERT(adapter);
+
+ if(adapter == NULL )
+ {
+ DEBUGP (("[TAP] release [%d.%d] cleanup request; adapter not found\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION
+ ));
+ }
+
+ if(adapter != NULL )
+ {
+ adapter->TapFileIsOpen = 0; // Legacy...
+
+ // Disconnect from media.
+ tapSetMediaConnectStatus(adapter,FALSE);
+
+ // Reset adapter state when cleaning up;
+ tapResetAdapterState(adapter);
+
+ // BUGBUG!!! Use RemoveLock???
+
+ //
+ // Flush pending send TAP packet queue.
+ //
+ tapFlushSendPacketQueue(adapter);
+
+ ASSERT(adapter->SendPacketQueue.Count == 0);
+
+ //
+ // Flush the pending IRP queues
+ //
+ tapFlushIrpQueues(adapter);
+
+ ASSERT(adapter->PendingReadIrpQueue.Count == 0);
+ }
+
+ // Complete the IRP.
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+ DEBUGP (("[TAP] <-- TapDeviceCleanup; status = %8.8X\n",status));
+
+ return status;
+}
+
+// IRP_MJ_CLOSE
+NTSTATUS
+TapDeviceClose(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ Receipt of this request indicates that the last handle of the file
+ object that is associated with the target device object has been closed
+ and released.
+
+ All outstanding I/O requests have been completed or canceled.
+
+Arguments:
+
+ DeviceObject - a pointer to the object that represents the device
+ to be closed.
+
+ Irp - a pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NT status code
+
+--*/
+
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS; // Always succeed.
+ PIO_STACK_LOCATION irpSp; // Pointer to current stack location
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+
+ PAGED_CODE();
+
+ DEBUGP (("[TAP] --> TapDeviceClose\n"));
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ //
+ // Fetch adapter context for this device.
+ // --------------------------------------
+ // Adapter pointer was stashed in FsContext when handle was opened.
+ //
+ adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+ // Insure that adapter exists.
+ ASSERT(adapter);
+
+ if(adapter == NULL )
+ {
+ DEBUGP (("[TAP] release [%d.%d] close request; adapter not found\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION
+ ));
+ }
+
+ if(adapter != NULL )
+ {
+ if(adapter->TapFileObject == NULL)
+ {
+ // Should never happen!!!
+ ASSERT(FALSE);
+ }
+ else
+ {
+ ASSERT(irpSp->FileObject->FsContext == adapter);
+
+ ASSERT(adapter->TapFileObject == irpSp->FileObject);
+ }
+
+ adapter->TapFileObject = NULL;
+ irpSp->FileObject = NULL;
+
+ // Remove reference added by when handle was opened.
+ tapAdapterContextDereference(adapter);
+ }
+
+ // Complete the IRP.
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+
+ IoCompleteRequest( Irp, IO_NO_INCREMENT );
+
+ DEBUGP (("[TAP] <-- TapDeviceClose; status = %8.8X\n",status));
+
+ return status;
+}
+
+NTSTATUS
+tapConcatenateNdisStrings(
+ __inout PNDIS_STRING DestinationString,
+ __in_opt PNDIS_STRING SourceString1,
+ __in_opt PNDIS_STRING SourceString2,
+ __in_opt PNDIS_STRING SourceString3
+ )
+{
+ NTSTATUS status;
+
+ ASSERT(SourceString1 && SourceString2 && SourceString3);
+
+ status = RtlAppendUnicodeStringToString(
+ DestinationString,
+ SourceString1
+ );
+
+ if(status == STATUS_SUCCESS)
+ {
+ status = RtlAppendUnicodeStringToString(
+ DestinationString,
+ SourceString2
+ );
+
+ if(status == STATUS_SUCCESS)
+ {
+ status = RtlAppendUnicodeStringToString(
+ DestinationString,
+ SourceString3
+ );
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+tapMakeDeviceNames(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ NDIS_STATUS status;
+ NDIS_STRING deviceNamePrefix = NDIS_STRING_CONST("\\Device\\");
+ NDIS_STRING tapNameSuffix = NDIS_STRING_CONST(".tap");
+
+ // Generate DeviceName from NetCfgInstanceId.
+ Adapter->DeviceName.Buffer = Adapter->DeviceNameBuffer;
+ Adapter->DeviceName.MaximumLength = sizeof(Adapter->DeviceNameBuffer);
+
+ status = tapConcatenateNdisStrings(
+ &Adapter->DeviceName,
+ &deviceNamePrefix,
+ &Adapter->NetCfgInstanceId,
+ &tapNameSuffix
+ );
+
+ if(status == STATUS_SUCCESS)
+ {
+ NDIS_STRING linkNamePrefix = NDIS_STRING_CONST("\\DosDevices\\Global\\");
+
+ Adapter->LinkName.Buffer = Adapter->LinkNameBuffer;
+ Adapter->LinkName.MaximumLength = sizeof(Adapter->LinkNameBuffer);
+
+ status = tapConcatenateNdisStrings(
+ &Adapter->LinkName,
+ &linkNamePrefix,
+ &Adapter->NetCfgInstanceId,
+ &tapNameSuffix
+ );
+ }
+
+ return status;
+}
+
+NDIS_STATUS
+CreateTapDevice(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ NDIS_STATUS status;
+ NDIS_DEVICE_OBJECT_ATTRIBUTES deviceAttribute;
+ PDRIVER_DISPATCH dispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
+
+ DEBUGP (("[TAP] version [%d.%d] creating tap device: %wZ\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ &Adapter->NetCfgInstanceId));
+
+ // Generate DeviceName and LinkName from NetCfgInstanceId.
+ status = tapMakeDeviceNames(Adapter);
+
+ if (NT_SUCCESS(status))
+ {
+ DEBUGP (("[TAP] DeviceName: %wZ\n",&Adapter->DeviceName));
+ DEBUGP (("[TAP] LinkName: %wZ\n",&Adapter->LinkName));
+
+ // Initialize dispatch table.
+ NdisZeroMemory(dispatchTable, (IRP_MJ_MAXIMUM_FUNCTION+1) * sizeof(PDRIVER_DISPATCH));
+
+ dispatchTable[IRP_MJ_CREATE] = TapDeviceCreate;
+ dispatchTable[IRP_MJ_CLEANUP] = TapDeviceCleanup;
+ dispatchTable[IRP_MJ_CLOSE] = TapDeviceClose;
+ dispatchTable[IRP_MJ_READ] = TapDeviceRead;
+ dispatchTable[IRP_MJ_WRITE] = TapDeviceWrite;
+ dispatchTable[IRP_MJ_DEVICE_CONTROL] = TapDeviceControl;
+
+ //
+ // Create a device object and register dispatch handlers
+ //
+ NdisZeroMemory(&deviceAttribute, sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES));
+
+ deviceAttribute.Header.Type = NDIS_OBJECT_TYPE_DEVICE_OBJECT_ATTRIBUTES;
+ deviceAttribute.Header.Revision = NDIS_DEVICE_OBJECT_ATTRIBUTES_REVISION_1;
+ deviceAttribute.Header.Size = sizeof(NDIS_DEVICE_OBJECT_ATTRIBUTES);
+
+ deviceAttribute.DeviceName = &Adapter->DeviceName;
+ deviceAttribute.SymbolicName = &Adapter->LinkName;
+ deviceAttribute.MajorFunctions = &dispatchTable[0];
+ //deviceAttribute.ExtensionSize = sizeof(FILTER_DEVICE_EXTENSION);
+
+#if ENABLE_NONADMIN
+ if(Adapter->AllowNonAdmin)
+ {
+ //
+ // SDDL_DEVOBJ_SYS_ALL_WORLD_RWX_RES_RWX allows the kernel and system complete
+ // control over the device. By default the admin can access the entire device,
+ // but cannot change the ACL (the admin must take control of the device first)
+ //
+ // Everyone else, including "restricted" or "untrusted" code can read or write
+ // to the device. Traversal beneath the device is also granted (removing it
+ // would only effect storage devices, except if the "bypass-traversal"
+ // privilege was revoked).
+ //
+ deviceAttribute.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX;
+ }
+#endif
+
+ status = NdisRegisterDeviceEx(
+ Adapter->MiniportAdapterHandle,
+ &deviceAttribute,
+ &Adapter->DeviceObject,
+ &Adapter->DeviceHandle
+ );
+ }
+
+ ASSERT(NT_SUCCESS(status));
+
+ if (NT_SUCCESS(status))
+ {
+ // Set TAP device flags.
+ (Adapter->DeviceObject)->Flags &= ~DO_BUFFERED_IO;
+ (Adapter->DeviceObject)->Flags |= DO_DIRECT_IO;;
+
+ //========================
+ // Finalize initialization
+ //========================
+
+ Adapter->TapDeviceCreated = TRUE;
+
+ DEBUGP (("[%wZ] successfully created TAP device [%wZ]\n",
+ &Adapter->NetCfgInstanceId,
+ &Adapter->DeviceName
+ ));
+ }
+
+ DEBUGP (("[TAP] <-- CreateTapDevice; status = %8.8X\n",status));
+
+ return status;
+}
+
+//
+// DestroyTapDevice is called from AdapterHalt and NDIS miniport
+// is in Halted state. Prior to entering the Halted state the
+// miniport would have passed through the Pausing and Paused
+// states. These miniport states have responsibility for waiting
+// until NDIS network operations have completed.
+//
+VOID
+DestroyTapDevice(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ DEBUGP (("[TAP] --> DestroyTapDevice; Adapter: %wZ\n",
+ &Adapter->NetCfgInstanceId));
+
+ //
+ // Let clients know we are shutting down
+ //
+ Adapter->TapDeviceCreated = FALSE;
+
+ //
+ // Flush pending send TAP packet queue.
+ //
+ tapFlushSendPacketQueue(Adapter);
+
+ ASSERT(Adapter->SendPacketQueue.Count == 0);
+
+ //
+ // Flush IRP queues. Wait for pending I/O. Etc.
+ // --------------------------------------------
+ // Exhaust IRP and packet queues. Any pending IRPs will
+ // be cancelled, causing user-space to get this error
+ // on overlapped reads:
+ //
+ // ERROR_OPERATION_ABORTED, code=995
+ //
+ // "The I/O operation has been aborted because of either a
+ // thread exit or an application request."
+ //
+ // It's important that user-space close the device handle
+ // when this code is returned, so that when we finally
+ // do a NdisMDeregisterDeviceEx, the device reference count
+ // is 0. Otherwise the driver will not unload even if the
+ // the last adapter has been halted.
+ //
+ // The act of flushing the queues at this point should result in the user-mode
+ // application closing the adapter's device handle. Closing the handle will
+ // result in the TapDeviceCleanup call being made, followed by the a call to
+ // the TapDeviceClose callback.
+ //
+ tapFlushIrpQueues(Adapter);
+
+ ASSERT(Adapter->PendingReadIrpQueue.Count == 0);
+
+ //
+ // Deregister the Win32 device.
+ // ----------------------------
+ // When a driver calls NdisDeregisterDeviceEx, the I/O manager deletes the
+ // target device object if there are no outstanding references to it. However,
+ // if any outstanding references remain, the I/O manager marks the device
+ // object as "delete pending" and deletes the device object when the references
+ // are finally released.
+ //
+ if(Adapter->DeviceHandle)
+ {
+ DEBUGP (("[TAP] Calling NdisDeregisterDeviceEx\n"));
+ NdisDeregisterDeviceEx(Adapter->DeviceHandle);
+ }
+
+ Adapter->DeviceHandle = NULL;
+
+ DEBUGP (("[TAP] <-- DestroyTapDevice\n"));
+}
+
diff --git a/windows/TapDriver6/device.h b/windows/TapDriver6/device.h
new file mode 100644
index 00000000..93dae0d9
--- /dev/null
+++ b/windows/TapDriver6/device.h
@@ -0,0 +1,50 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __TAP_DEVICE_H_
+#define __TAP_DEVICE_H_
+
+//======================================================================
+// TAP Prototypes for standard Win32 device I/O entry points
+//======================================================================
+
+__drv_dispatchType(IRP_MJ_CREATE)
+DRIVER_DISPATCH TapDeviceCreate;
+
+__drv_dispatchType(IRP_MJ_READ)
+DRIVER_DISPATCH TapDeviceRead;
+
+__drv_dispatchType(IRP_MJ_WRITE)
+DRIVER_DISPATCH TapDeviceWrite;
+
+__drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
+DRIVER_DISPATCH TapDeviceControl;
+
+__drv_dispatchType(IRP_MJ_CLEANUP)
+DRIVER_DISPATCH TapDeviceCleanup;
+
+__drv_dispatchType(IRP_MJ_CLOSE)
+DRIVER_DISPATCH TapDeviceClose;
+
+#endif // __TAP_DEVICE_H_ \ No newline at end of file
diff --git a/windows/TapDriver6/endian.h b/windows/TapDriver6/endian.h
new file mode 100644
index 00000000..b7d34499
--- /dev/null
+++ b/windows/TapDriver6/endian.h
@@ -0,0 +1,35 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef TAP_LITTLE_ENDIAN
+#define ntohs(x) RtlUshortByteSwap(x)
+#define htons(x) RtlUshortByteSwap(x)
+#define ntohl(x) RtlUlongByteSwap(x)
+#define htonl(x) RtlUlongByteSwap(x)
+#else
+#define ntohs(x) ((USHORT)(x))
+#define htons(x) ((USHORT)(x))
+#define ntohl(x) ((ULONG)(x))
+#define htonl(x) ((ULONG)(x))
+#endif
diff --git a/windows/TapDriver6/error.c b/windows/TapDriver6/error.c
new file mode 100644
index 00000000..1fad1d3a
--- /dev/null
+++ b/windows/TapDriver6/error.c
@@ -0,0 +1,398 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "tap.h"
+
+//-----------------
+// DEBUGGING OUTPUT
+//-----------------
+
+const char *g_LastErrorFilename;
+int g_LastErrorLineNumber;
+
+#if DBG
+
+DebugOutput g_Debug;
+
+BOOLEAN
+NewlineExists (const char *str, int len)
+{
+ while (len-- > 0)
+ {
+ const char c = *str++;
+ if (c == '\n')
+ return TRUE;
+ else if (c == '\0')
+ break;
+ }
+ return FALSE;
+}
+
+VOID
+MyDebugInit (unsigned int bufsiz)
+{
+ NdisZeroMemory (&g_Debug, sizeof (g_Debug));
+ g_Debug.text = (char *) MemAlloc (bufsiz, FALSE);
+
+ if (g_Debug.text)
+ {
+ g_Debug.capacity = bufsiz;
+ }
+}
+
+VOID
+MyDebugFree ()
+{
+ if (g_Debug.text)
+ {
+ MemFree (g_Debug.text, g_Debug.capacity);
+ }
+
+ NdisZeroMemory (&g_Debug, sizeof (g_Debug));
+}
+
+VOID
+MyDebugPrint (const unsigned char* format, ...)
+{
+ if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT)
+ {
+ BOOLEAN owned;
+ ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
+ if (owned)
+ {
+ const int remaining = (int)g_Debug.capacity - (int)g_Debug.out;
+
+ if (remaining > 0)
+ {
+ va_list args;
+ NTSTATUS status;
+ char *end;
+
+#ifdef DBG_PRINT
+ va_start (args, format);
+ vDbgPrintEx (DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, format, args);
+ va_end (args);
+#endif
+ va_start (args, format);
+ status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out,
+ remaining,
+ &end,
+ NULL,
+ STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS,
+ format,
+ args);
+ va_end (args);
+ va_start (args, format);
+ vDbgPrintEx(DPFLTR_IHVDRIVER_ID , 1, format, args);
+ va_end (args);
+ if (status == STATUS_SUCCESS)
+ g_Debug.out = (unsigned int) (end - g_Debug.text);
+ else
+ g_Debug.error = TRUE;
+ }
+ else
+ g_Debug.error = TRUE;
+
+ RELEASE_MUTEX (&g_Debug.lock);
+ }
+ else
+ g_Debug.error = TRUE;
+ }
+}
+
+BOOLEAN
+GetDebugLine (
+ __in char *buf,
+ __in const int len
+ )
+{
+ static const char *truncated = "[OUTPUT TRUNCATED]\n";
+ BOOLEAN ret = FALSE;
+
+ NdisZeroMemory (buf, len);
+
+ if (g_Debug.text && g_Debug.capacity > 0)
+ {
+ BOOLEAN owned;
+ ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned);
+ if (owned)
+ {
+ int i = 0;
+
+ if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in))
+ {
+ while (i < (len - 1) && g_Debug.in < g_Debug.out)
+ {
+ const char c = g_Debug.text[g_Debug.in++];
+ if (c == '\n')
+ break;
+ buf[i++] = c;
+ }
+ if (i < len)
+ buf[i] = '\0';
+ }
+
+ if (!i)
+ {
+ if (g_Debug.in == g_Debug.out)
+ {
+ g_Debug.in = g_Debug.out = 0;
+ if (g_Debug.error)
+ {
+ const unsigned int tlen = strlen (truncated);
+ if (tlen < g_Debug.capacity)
+ {
+ NdisMoveMemory (g_Debug.text, truncated, tlen+1);
+ g_Debug.out = tlen;
+ }
+ g_Debug.error = FALSE;
+ }
+ }
+ }
+ else
+ ret = TRUE;
+
+ RELEASE_MUTEX (&g_Debug.lock);
+ }
+ }
+ return ret;
+}
+
+VOID
+PrMac (const MACADDR mac)
+{
+ DEBUGP (("%x:%x:%x:%x:%x:%x",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]));
+}
+
+VOID
+PrIP (IPADDR ip_addr)
+{
+ const unsigned char *ip = (const unsigned char *) &ip_addr;
+
+ DEBUGP (("%d.%d.%d.%d",
+ ip[0], ip[1], ip[2], ip[3]));
+}
+
+const char *
+PrIPProto (int proto)
+{
+ switch (proto)
+ {
+ case IPPROTO_UDP:
+ return "UDP";
+
+ case IPPROTO_TCP:
+ return "TCP";
+
+ case IPPROTO_ICMP:
+ return "ICMP";
+
+ case IPPROTO_IGMP:
+ return "IGMP";
+
+ default:
+ return "???";
+ }
+}
+
+VOID
+DumpARP (const char *prefix, const ARP_PACKET *arp)
+{
+ DEBUGP (("%s ARP src=", prefix));
+ PrMac (arp->m_MAC_Source);
+ DEBUGP ((" dest="));
+ PrMac (arp->m_MAC_Destination);
+ DEBUGP ((" OP=0x%04x",
+ (int)ntohs(arp->m_ARP_Operation)));
+ DEBUGP ((" M=0x%04x(%d)",
+ (int)ntohs(arp->m_MAC_AddressType),
+ (int)arp->m_MAC_AddressSize));
+ DEBUGP ((" P=0x%04x(%d)",
+ (int)ntohs(arp->m_PROTO_AddressType),
+ (int)arp->m_PROTO_AddressSize));
+
+ DEBUGP ((" MacSrc="));
+ PrMac (arp->m_ARP_MAC_Source);
+ DEBUGP ((" MacDest="));
+ PrMac (arp->m_ARP_MAC_Destination);
+
+ DEBUGP ((" IPSrc="));
+ PrIP (arp->m_ARP_IP_Source);
+ DEBUGP ((" IPDest="));
+ PrIP (arp->m_ARP_IP_Destination);
+
+ DEBUGP (("\n"));
+}
+
+struct ethpayload
+{
+ ETH_HEADER eth;
+ UCHAR payload[DEFAULT_PACKET_LOOKAHEAD];
+};
+
+#ifdef ALLOW_PACKET_DUMP
+
+VOID
+DumpPacket2(
+ __in const char *prefix,
+ __in const ETH_HEADER *eth,
+ __in const unsigned char *data,
+ __in unsigned int len
+ )
+{
+ struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE);
+ if (ep)
+ {
+ if (len > DEFAULT_PACKET_LOOKAHEAD)
+ len = DEFAULT_PACKET_LOOKAHEAD;
+ ep->eth = *eth;
+ NdisMoveMemory (ep->payload, data, len);
+ DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len);
+ MemFree (ep, sizeof (struct ethpayload));
+ }
+}
+
+VOID
+DumpPacket(
+ __in const char *prefix,
+ __in const unsigned char *data,
+ __in unsigned int len
+ )
+{
+ const ETH_HEADER *eth = (const ETH_HEADER *) data;
+ const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER));
+
+ if (len < sizeof (ETH_HEADER))
+ {
+ DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len));
+ return;
+ }
+
+ // ARP Packet?
+ if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP))
+ {
+ DumpARP (prefix, (const ARP_PACKET *) data);
+ return;
+ }
+
+ // IPv4 packet?
+ if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER))
+ && eth->proto == htons (ETH_P_IP)
+ && IPH_GET_VER (ip->version_len) == 4)
+ {
+ const int hlen = IPH_GET_LEN (ip->version_len);
+ const int blen = len - sizeof (ETH_HEADER);
+ BOOLEAN did = FALSE;
+
+ DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len));
+
+ if (!(ntohs (ip->tot_len) == blen && hlen <= blen))
+ {
+ DEBUGP ((" XXX"));
+ return;
+ }
+
+ // TCP packet?
+ if (ip->protocol == IPPROTO_TCP
+ && blen - hlen >= (sizeof (TCPHDR)))
+ {
+ const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen);
+ DEBUGP ((" "));
+ PrIP (ip->saddr);
+ DEBUGP ((":%d", ntohs (tcp->source)));
+ DEBUGP ((" -> "));
+ PrIP (ip->daddr);
+ DEBUGP ((":%d", ntohs (tcp->dest)));
+ did = TRUE;
+ }
+
+ // UDP packet?
+ else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0
+ && ip->protocol == IPPROTO_UDP
+ && blen - hlen >= (sizeof (UDPHDR)))
+ {
+ const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen);
+
+ // DHCP packet?
+ if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT))
+ && blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP)))
+ {
+ const DHCP *dhcp = (DHCP *) (data
+ + hlen
+ + sizeof (ETH_HEADER)
+ + sizeof (UDPHDR));
+
+ int optlen = len
+ - sizeof (ETH_HEADER)
+ - hlen
+ - sizeof (UDPHDR)
+ - sizeof (DHCP);
+
+ if (optlen < 0)
+ optlen = 0;
+
+ DumpDHCP (eth, ip, udp, dhcp, optlen);
+ did = TRUE;
+ }
+
+ if (!did)
+ {
+ DEBUGP ((" "));
+ PrIP (ip->saddr);
+ DEBUGP ((":%d", ntohs (udp->source)));
+ DEBUGP ((" -> "));
+ PrIP (ip->daddr);
+ DEBUGP ((":%d", ntohs (udp->dest)));
+ did = TRUE;
+ }
+ }
+
+ if (!did)
+ {
+ DEBUGP ((" ipproto=%d ", ip->protocol));
+ PrIP (ip->saddr);
+ DEBUGP ((" -> "));
+ PrIP (ip->daddr);
+ }
+
+ DEBUGP (("\n"));
+ return;
+ }
+
+ {
+ DEBUGP (("%s ??? src=", prefix));
+ PrMac (eth->src);
+ DEBUGP ((" dest="));
+ PrMac (eth->dest);
+ DEBUGP ((" proto=0x%04x len=%d\n",
+ (int) ntohs(eth->proto),
+ len));
+ }
+}
+
+#endif // ALLOW_PACKET_DUMP
+
+#endif
diff --git a/windows/TapDriver6/error.h b/windows/TapDriver6/error.h
new file mode 100644
index 00000000..2ba39cc1
--- /dev/null
+++ b/windows/TapDriver6/error.h
@@ -0,0 +1,114 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//-----------------
+// DEBUGGING OUTPUT
+//-----------------
+
+extern const char *g_LastErrorFilename;
+extern int g_LastErrorLineNumber;
+
+// Debug info output
+#define ALSO_DBGPRINT 1
+#define DEBUGP_AT_DISPATCH 1
+
+// Uncomment line below to allow packet dumps
+//#define ALLOW_PACKET_DUMP 1
+
+#define NOTE_ERROR() \
+{ \
+ g_LastErrorFilename = __FILE__; \
+ g_LastErrorLineNumber = __LINE__; \
+}
+
+#if DBG
+
+typedef struct
+{
+ unsigned int in;
+ unsigned int out;
+ unsigned int capacity;
+ char *text;
+ BOOLEAN error;
+ MUTEX lock;
+} DebugOutput;
+
+VOID MyDebugPrint (const unsigned char* format, ...);
+
+VOID PrMac (const MACADDR mac);
+
+VOID PrIP (IPADDR ip_addr);
+
+#ifdef ALLOW_PACKET_DUMP
+
+VOID
+DumpPacket(
+ __in const char *prefix,
+ __in const unsigned char *data,
+ __in unsigned int len
+ );
+
+DumpPacket2(
+ __in const char *prefix,
+ __in const ETH_HEADER *eth,
+ __in const unsigned char *data,
+ __in unsigned int len
+ );
+
+#else
+#define DUMP_PACKET(prefix, data, len)
+#define DUMP_PACKET2(prefix, eth, data, len)
+#endif
+
+#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql () < DISPATCH_LEVEL)
+
+#if ALSO_DBGPRINT
+#define DEBUGP(fmt) { MyDebugPrint fmt; if (CAN_WE_PRINT) DbgPrint fmt; }
+#else
+#define DEBUGP(fmt) { MyDebugPrint fmt; }
+#endif
+
+#ifdef ALLOW_PACKET_DUMP
+
+#define DUMP_PACKET(prefix, data, len) \
+ DumpPacket (prefix, data, len)
+
+#define DUMP_PACKET2(prefix, eth, data, len) \
+ DumpPacket2 (prefix, eth, data, len)
+
+#endif
+
+BOOLEAN
+GetDebugLine (
+ __in char *buf,
+ __in const int len
+ );
+
+#else
+
+#define DEBUGP(fmt)
+#define DUMP_PACKET(prefix, data, len)
+#define DUMP_PACKET2(prefix, eth, data, len)
+
+#endif
diff --git a/windows/TapDriver6/hexdump.h b/windows/TapDriver6/hexdump.h
new file mode 100644
index 00000000..d6275c18
--- /dev/null
+++ b/windows/TapDriver6/hexdump.h
@@ -0,0 +1,63 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef HEXDUMP_DEFINED
+#define HEXDUMP_DEFINED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//=====================================================================================
+// Debug Routines
+//=====================================================================================
+
+#ifndef NDIS_MINIPORT_DRIVER
+# include <stdio.h>
+# include <ctype.h>
+# include <windows.h>
+# include <winnt.h>
+# include <memory.h>
+
+# ifndef DEBUGP
+# define DEBUGP(fmt) { DbgMessage fmt; }
+# endif
+
+ extern VOID (*DbgMessage)(char *p_Format, ...);
+
+ VOID DisplayDebugString (char *p_Format, ...);
+#endif
+
+//===================================================================================
+// Reporting / Debugging
+//===================================================================================
+#define IfPrint(c) (c >= 32 && c < 127 ? c : '.')
+
+VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/windows/TapDriver6/lock.h b/windows/TapDriver6/lock.h
new file mode 100644
index 00000000..c80b164c
--- /dev/null
+++ b/windows/TapDriver6/lock.h
@@ -0,0 +1,75 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+typedef struct
+{
+ volatile long count;
+} MUTEX;
+
+#define MUTEX_SLEEP_TIME 10000 // microseconds
+
+#define INIT_MUTEX(m) { (m)->count = 0; }
+
+#define ACQUIRE_MUTEX_BLOCKING(m) \
+{ \
+ while (NdisInterlockedIncrement (&((m)->count)) != 1) \
+ { \
+ NdisInterlockedDecrement(&((m)->count)); \
+ NdisMSleep(MUTEX_SLEEP_TIME); \
+ } \
+}
+
+#define RELEASE_MUTEX(m) \
+{ \
+ NdisInterlockedDecrement(&((m)->count)); \
+}
+
+#define ACQUIRE_MUTEX_NONBLOCKING(m, result) \
+{ \
+ if (NdisInterlockedIncrement (&((m)->count)) != 1) \
+ { \
+ NdisInterlockedDecrement(&((m)->count)); \
+ result = FALSE; \
+ } \
+ else \
+ { \
+ result = TRUE; \
+ } \
+}
+
+#define ACQUIRE_MUTEX_ADAPTIVE(m, result) \
+{ \
+ result = TRUE; \
+ while (NdisInterlockedIncrement (&((m)->count)) != 1) \
+ { \
+ NdisInterlockedDecrement(&((m)->count)); \
+ if (KeGetCurrentIrql () < DISPATCH_LEVEL) \
+ NdisMSleep(MUTEX_SLEEP_TIME); \
+ else \
+ { \
+ result = FALSE; \
+ break; \
+ } \
+ } \
+}
diff --git a/windows/TapDriver6/macinfo.c b/windows/TapDriver6/macinfo.c
new file mode 100644
index 00000000..dfd0a075
--- /dev/null
+++ b/windows/TapDriver6/macinfo.c
@@ -0,0 +1,164 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "tap.h"
+
+int
+HexStringToDecimalInt (const int p_Character)
+{
+ int l_Value = 0;
+
+ if (p_Character >= 'A' && p_Character <= 'F')
+ l_Value = (p_Character - 'A') + 10;
+ else if (p_Character >= 'a' && p_Character <= 'f')
+ l_Value = (p_Character - 'a') + 10;
+ else if (p_Character >= '0' && p_Character <= '9')
+ l_Value = p_Character - '0';
+
+ return l_Value;
+}
+
+BOOLEAN
+ParseMAC (MACADDR dest, const char *src)
+{
+ int c;
+ int mac_index = 0;
+ BOOLEAN high_digit = FALSE;
+ int delim_action = 1;
+
+ ASSERT (src);
+ ASSERT (dest);
+
+ CLEAR_MAC (dest);
+
+ while (c = *src++)
+ {
+ if (IsMacDelimiter (c))
+ {
+ mac_index += delim_action;
+ high_digit = FALSE;
+ delim_action = 1;
+ }
+ else if (IsHexDigit (c))
+ {
+ const int digit = HexStringToDecimalInt (c);
+ if (mac_index < sizeof (MACADDR))
+ {
+ if (!high_digit)
+ {
+ dest[mac_index] = (char)(digit);
+ high_digit = TRUE;
+ delim_action = 1;
+ }
+ else
+ {
+ dest[mac_index] = (char)(dest[mac_index] * 16 + digit);
+ ++mac_index;
+ high_digit = FALSE;
+ delim_action = 0;
+ }
+ }
+ else
+ return FALSE;
+ }
+ else
+ return FALSE;
+ }
+
+ return (mac_index + delim_action) >= sizeof (MACADDR);
+}
+
+/*
+ * Generate a MAC using the GUID in the adapter name.
+ *
+ * The mac is constructed as 00:FF:xx:xx:xx:xx where
+ * the Xs are taken from the first 32 bits of the GUID in the
+ * adapter name. This is similar to the Linux 2.4 tap MAC
+ * generator, except linux uses 32 random bits for the Xs.
+ *
+ * In general, this solution is reasonable for most
+ * applications except for very large bridged TAP networks,
+ * where the probability of address collisions becomes more
+ * than infintesimal.
+ *
+ * Using the well-known "birthday paradox", on a 1000 node
+ * network the probability of collision would be
+ * 0.000116292153. On a 10,000 node network, the probability
+ * of collision would be 0.01157288998621678766.
+ */
+
+VOID
+GenerateRandomMac(
+ __in MACADDR mac,
+ __in const unsigned char *adapter_name
+ )
+{
+ unsigned const char *cp = adapter_name;
+ unsigned char c;
+ unsigned int i = 2;
+ unsigned int byte = 0;
+ int brace = 0;
+ int state = 0;
+
+ CLEAR_MAC (mac);
+
+ mac[0] = 0x00;
+ mac[1] = 0xFF;
+
+ while (c = *cp++)
+ {
+ if (i >= sizeof (MACADDR))
+ break;
+ if (c == '{')
+ brace = 1;
+ if (IsHexDigit (c) && brace)
+ {
+ const unsigned int digit = HexStringToDecimalInt (c);
+ if (state)
+ {
+ byte <<= 4;
+ byte |= digit;
+ mac[i++] = (unsigned char) byte;
+ state = 0;
+ }
+ else
+ {
+ byte = digit;
+ state = 1;
+ }
+ }
+ }
+}
+
+VOID
+GenerateRelatedMAC(
+ __in MACADDR dest,
+ __in const MACADDR src,
+ __in const int delta
+ )
+{
+ ETH_COPY_NETWORK_ADDRESS (dest, src);
+ dest[2] += (UCHAR) delta;
+}
diff --git a/windows/TapDriver6/macinfo.h b/windows/TapDriver6/macinfo.h
new file mode 100644
index 00000000..dd88b6f8
--- /dev/null
+++ b/windows/TapDriver6/macinfo.h
@@ -0,0 +1,53 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MacInfoDefined
+#define MacInfoDefined
+
+//===================================================================================
+// Macros
+//===================================================================================
+#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.')
+#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))
+
+#define CLEAR_MAC(dest) NdisZeroMemory ((dest), sizeof (MACADDR))
+#define MAC_EQUAL(a,b) (memcmp ((a), (b), sizeof (MACADDR)) == 0)
+
+BOOLEAN
+ParseMAC (MACADDR dest, const char *src);
+
+VOID
+GenerateRandomMac(
+ __in MACADDR mac,
+ __in const unsigned char *adapter_name
+ );
+
+VOID
+GenerateRelatedMAC(
+ __in MACADDR dest,
+ __in const MACADDR src,
+ __in const int delta
+ );
+
+#endif
diff --git a/windows/TapDriver6/mem.c b/windows/TapDriver6/mem.c
new file mode 100644
index 00000000..ae2e3d40
--- /dev/null
+++ b/windows/TapDriver6/mem.c
@@ -0,0 +1,401 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//------------------
+// Memory Management
+//------------------
+
+#include "tap.h"
+
+PVOID
+MemAlloc(
+ __in ULONG p_Size,
+ __in BOOLEAN zero
+ )
+{
+ PVOID l_Return = NULL;
+
+ if (p_Size)
+ {
+ __try
+ {
+ if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT')
+ == NDIS_STATUS_SUCCESS)
+ {
+ if (zero)
+ {
+ NdisZeroMemory (l_Return, p_Size);
+ }
+ }
+ else
+ {
+ l_Return = NULL;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ l_Return = NULL;
+ }
+ }
+
+ return l_Return;
+}
+
+VOID
+MemFree(
+ __in PVOID p_Addr,
+ __in ULONG p_Size
+ )
+{
+ if (p_Addr && p_Size)
+ {
+ __try
+ {
+#if DBG
+ NdisZeroMemory (p_Addr, p_Size);
+#endif
+ NdisFreeMemory (p_Addr, p_Size, 0);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ }
+}
+
+//======================================================================
+// TAP Packet Queue Support
+//======================================================================
+
+VOID
+tapPacketQueueInsertTail(
+ __in PTAP_PACKET_QUEUE TapPacketQueue,
+ __in PTAP_PACKET TapPacket
+ )
+{
+ KIRQL irql;
+
+ KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql);
+
+ InsertTailList(&TapPacketQueue->Queue,&TapPacket->QueueLink);
+
+ // BUGBUG!!! Enforce PACKET_QUEUE_SIZE queue count limit???
+ // For NDIS 6 there is no per-packet status, so this will need to
+ // be handled on per-NBL basis in AdapterSendNetBufferLists...
+
+ // Update counts
+ ++TapPacketQueue->Count;
+
+ if(TapPacketQueue->Count > TapPacketQueue->MaxCount)
+ {
+ TapPacketQueue->MaxCount = TapPacketQueue->Count;
+
+ DEBUGP (("[TAP] tapPacketQueueInsertTail: New MAX queued packet count = %d\n",
+ TapPacketQueue->MaxCount));
+ }
+
+ KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql);
+}
+
+// Call with QueueLock held
+PTAP_PACKET
+tapPacketRemoveHeadLocked(
+ __in PTAP_PACKET_QUEUE TapPacketQueue
+ )
+{
+ PTAP_PACKET tapPacket = NULL;
+ PLIST_ENTRY listEntry;
+
+ listEntry = RemoveHeadList(&TapPacketQueue->Queue);
+
+ if(listEntry != &TapPacketQueue->Queue)
+ {
+ tapPacket = CONTAINING_RECORD(listEntry, TAP_PACKET, QueueLink);
+
+ // Update counts
+ --TapPacketQueue->Count;
+ }
+
+ return tapPacket;
+}
+
+PTAP_PACKET
+tapPacketRemoveHead(
+ __in PTAP_PACKET_QUEUE TapPacketQueue
+ )
+{
+ PTAP_PACKET tapPacket = NULL;
+ KIRQL irql;
+
+ KeAcquireSpinLock(&TapPacketQueue->QueueLock,&irql);
+
+ tapPacket = tapPacketRemoveHeadLocked(TapPacketQueue);
+
+ KeReleaseSpinLock(&TapPacketQueue->QueueLock,irql);
+
+ return tapPacket;
+}
+
+VOID
+tapPacketQueueInitialize(
+ __in PTAP_PACKET_QUEUE TapPacketQueue
+ )
+{
+ KeInitializeSpinLock(&TapPacketQueue->QueueLock);
+
+ NdisInitializeListHead(&TapPacketQueue->Queue);
+}
+
+//======================================================================
+// TAP Cancel-Safe Queue Support
+//======================================================================
+
+VOID
+tapIrpCsqInsert (
+ __in struct _IO_CSQ *Csq,
+ __in PIRP Irp
+ )
+{
+ PTAP_IRP_CSQ tapIrpCsq;
+
+ tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+ InsertTailList(
+ &tapIrpCsq->Queue,
+ &Irp->Tail.Overlay.ListEntry
+ );
+
+ // Update counts
+ ++tapIrpCsq->Count;
+
+ if(tapIrpCsq->Count > tapIrpCsq->MaxCount)
+ {
+ tapIrpCsq->MaxCount = tapIrpCsq->Count;
+
+ DEBUGP (("[TAP] tapIrpCsqInsert: New MAX queued IRP count = %d\n",
+ tapIrpCsq->MaxCount));
+ }
+}
+
+VOID
+tapIrpCsqRemoveIrp(
+ __in PIO_CSQ Csq,
+ __in PIRP Irp
+ )
+{
+ PTAP_IRP_CSQ tapIrpCsq;
+
+ tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+ // Update counts
+ --tapIrpCsq->Count;
+
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+}
+
+
+PIRP
+tapIrpCsqPeekNextIrp(
+ __in PIO_CSQ Csq,
+ __in PIRP Irp,
+ __in PVOID PeekContext
+ )
+{
+ PTAP_IRP_CSQ tapIrpCsq;
+ PIRP nextIrp = NULL;
+ PLIST_ENTRY nextEntry;
+ PLIST_ENTRY listHead;
+ PIO_STACK_LOCATION irpStack;
+
+ tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+ listHead = &tapIrpCsq->Queue;
+
+ //
+ // If the IRP is NULL, we will start peeking from the listhead, else
+ // we will start from that IRP onwards. This is done under the
+ // assumption that new IRPs are always inserted at the tail.
+ //
+
+ if (Irp == NULL)
+ {
+ nextEntry = listHead->Flink;
+ }
+ else
+ {
+ nextEntry = Irp->Tail.Overlay.ListEntry.Flink;
+ }
+
+ while(nextEntry != listHead)
+ {
+ nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry);
+
+ irpStack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ //
+ // If context is present, continue until you find a matching one.
+ // Else you break out as you got next one.
+ //
+ if (PeekContext)
+ {
+ if (irpStack->FileObject == (PFILE_OBJECT) PeekContext)
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ nextIrp = NULL;
+ nextEntry = nextEntry->Flink;
+ }
+
+ return nextIrp;
+}
+
+//
+// tapIrpCsqAcquireQueueLock modifies the execution level of the current processor.
+//
+// KeAcquireSpinLock raises the execution level to Dispatch Level and stores
+// the current execution level in the Irql parameter to be restored at a later
+// time. KeAcqurieSpinLock also requires us to be running at no higher than
+// Dispatch level when it is called.
+//
+// The annotations reflect these changes and requirments.
+//
+
+__drv_raisesIRQL(DISPATCH_LEVEL)
+__drv_maxIRQL(DISPATCH_LEVEL)
+VOID
+tapIrpCsqAcquireQueueLock(
+ __in PIO_CSQ Csq,
+ __out PKIRQL Irql
+ )
+{
+ PTAP_IRP_CSQ tapIrpCsq;
+
+ tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+ //
+ // Suppressing because the address below csq is valid since it's
+ // part of TAP_ADAPTER_CONTEXT structure.
+ //
+#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'")
+ KeAcquireSpinLock(&tapIrpCsq->QueueLock, Irql);
+}
+
+//
+// tapIrpCsqReleaseQueueLock modifies the execution level of the current processor.
+//
+// KeReleaseSpinLock assumes we already hold the spin lock and are therefore
+// running at Dispatch level. It will use the Irql parameter saved in a
+// previous call to KeAcquireSpinLock to return the thread back to it's original
+// execution level.
+//
+// The annotations reflect these changes and requirments.
+//
+
+__drv_requiresIRQL(DISPATCH_LEVEL)
+VOID
+tapIrpCsqReleaseQueueLock(
+ __in PIO_CSQ Csq,
+ __in KIRQL Irql
+ )
+{
+ PTAP_IRP_CSQ tapIrpCsq;
+
+ tapIrpCsq = (PTAP_IRP_CSQ )Csq;
+
+ //
+ // Suppressing because the address below csq is valid since it's
+ // part of TAP_ADAPTER_CONTEXT structure.
+ //
+#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'adapter->PendingReadCsqQueueLock'")
+ KeReleaseSpinLock(&tapIrpCsq->QueueLock, Irql);
+}
+
+VOID
+tapIrpCsqCompleteCanceledIrp(
+ __in PIO_CSQ pCsq,
+ __in PIRP Irp
+ )
+{
+ UNREFERENCED_PARAMETER(pCsq);
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+VOID
+tapIrpCsqInitialize(
+ __in PTAP_IRP_CSQ TapIrpCsq
+ )
+{
+ KeInitializeSpinLock(&TapIrpCsq->QueueLock);
+
+ NdisInitializeListHead(&TapIrpCsq->Queue);
+
+ IoCsqInitialize(
+ &TapIrpCsq->CsqQueue,
+ tapIrpCsqInsert,
+ tapIrpCsqRemoveIrp,
+ tapIrpCsqPeekNextIrp,
+ tapIrpCsqAcquireQueueLock,
+ tapIrpCsqReleaseQueueLock,
+ tapIrpCsqCompleteCanceledIrp
+ );
+}
+
+VOID
+tapIrpCsqFlush(
+ __in PTAP_IRP_CSQ TapIrpCsq
+ )
+{
+ PIRP pendingIrp;
+
+ //
+ // Flush the pending read IRP queue.
+ //
+ pendingIrp = IoCsqRemoveNextIrp(
+ &TapIrpCsq->CsqQueue,
+ NULL
+ );
+
+ while(pendingIrp)
+ {
+ // Cancel the IRP
+ pendingIrp->IoStatus.Information = 0;
+ pendingIrp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
+
+ pendingIrp = IoCsqRemoveNextIrp(
+ &TapIrpCsq->CsqQueue,
+ NULL
+ );
+ }
+
+ ASSERT(IsListEmpty(&TapIrpCsq->Queue));
+}
diff --git a/windows/TapDriver6/mem.h b/windows/TapDriver6/mem.h
new file mode 100644
index 00000000..a8359e19
--- /dev/null
+++ b/windows/TapDriver6/mem.h
@@ -0,0 +1,113 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//------------------
+// Memory Management
+//------------------
+
+PVOID
+MemAlloc(
+ __in ULONG p_Size,
+ __in BOOLEAN zero
+ );
+
+VOID
+MemFree(
+ __in PVOID p_Addr,
+ __in ULONG p_Size
+ );
+
+//======================================================================
+// TAP Packet Queue
+//======================================================================
+
+typedef
+struct _TAP_PACKET
+{
+ LIST_ENTRY QueueLink;
+
+# define TAP_PACKET_SIZE(data_size) (sizeof (TAP_PACKET) + (data_size))
+# define TP_TUN 0x80000000
+# define TP_SIZE_MASK (~TP_TUN)
+ ULONG m_SizeFlags;
+
+ // m_Data must be the last struct member
+ UCHAR m_Data [];
+} TAP_PACKET, *PTAP_PACKET;
+
+#define TAP_PACKET_TAG '6PAT' // "TAP6"
+
+typedef struct _TAP_PACKET_QUEUE
+{
+ KSPIN_LOCK QueueLock;
+ LIST_ENTRY Queue;
+ ULONG Count; // Count of currently queued items
+ ULONG MaxCount;
+} TAP_PACKET_QUEUE, *PTAP_PACKET_QUEUE;
+
+VOID
+tapPacketQueueInsertTail(
+ __in PTAP_PACKET_QUEUE TapPacketQueue,
+ __in PTAP_PACKET TapPacket
+ );
+
+
+// Call with QueueLock held
+PTAP_PACKET
+tapPacketRemoveHeadLocked(
+ __in PTAP_PACKET_QUEUE TapPacketQueue
+ );
+
+PTAP_PACKET
+tapPacketRemoveHead(
+ __in PTAP_PACKET_QUEUE TapPacketQueue
+ );
+
+VOID
+tapPacketQueueInitialize(
+ __in PTAP_PACKET_QUEUE TapPacketQueue
+ );
+
+//----------------------
+// Cancel-Safe IRP Queue
+//----------------------
+
+typedef struct _TAP_IRP_CSQ
+{
+ IO_CSQ CsqQueue;
+ KSPIN_LOCK QueueLock;
+ LIST_ENTRY Queue;
+ ULONG Count; // Count of currently queued items
+ ULONG MaxCount;
+} TAP_IRP_CSQ, *PTAP_IRP_CSQ;
+
+VOID
+tapIrpCsqInitialize(
+ __in PTAP_IRP_CSQ TapIrpCsq
+ );
+
+VOID
+tapIrpCsqFlush(
+ __in PTAP_IRP_CSQ TapIrpCsq
+ );
diff --git a/windows/TapDriver6/oidrequest.c b/windows/TapDriver6/oidrequest.c
new file mode 100644
index 00000000..a6882f89
--- /dev/null
+++ b/windows/TapDriver6/oidrequest.c
@@ -0,0 +1,1028 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+#ifndef DBG
+
+#define DBG_PRINT_OID_NAME
+
+#else
+
+VOID
+DBG_PRINT_OID_NAME(
+ __in NDIS_OID Oid
+ )
+{
+ PCHAR oidName = NULL;
+
+ switch (Oid){
+
+ #undef MAKECASE
+ #define MAKECASE(oidx) case oidx: oidName = #oidx "\n"; break;
+
+ /* Operational OIDs */
+ MAKECASE(OID_GEN_SUPPORTED_LIST)
+ MAKECASE(OID_GEN_HARDWARE_STATUS)
+ MAKECASE(OID_GEN_MEDIA_SUPPORTED)
+ MAKECASE(OID_GEN_MEDIA_IN_USE)
+ MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD)
+ MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE)
+ MAKECASE(OID_GEN_LINK_SPEED)
+ MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE)
+ MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE)
+ MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE)
+ MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE)
+ MAKECASE(OID_GEN_VENDOR_ID)
+ MAKECASE(OID_GEN_VENDOR_DESCRIPTION)
+ MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION)
+ MAKECASE(OID_GEN_CURRENT_PACKET_FILTER)
+ MAKECASE(OID_GEN_CURRENT_LOOKAHEAD)
+ MAKECASE(OID_GEN_DRIVER_VERSION)
+ MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE)
+ MAKECASE(OID_GEN_PROTOCOL_OPTIONS)
+ MAKECASE(OID_GEN_MAC_OPTIONS)
+ MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS)
+ MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS)
+ MAKECASE(OID_GEN_SUPPORTED_GUIDS)
+ MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES)
+ MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET)
+ MAKECASE(OID_GEN_MEDIA_CAPABILITIES)
+ MAKECASE(OID_GEN_PHYSICAL_MEDIUM)
+ MAKECASE(OID_GEN_MACHINE_NAME)
+ MAKECASE(OID_GEN_VLAN_ID)
+ MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER)
+
+ /* Operational OIDs for NDIS 6.0 */
+ MAKECASE(OID_GEN_MAX_LINK_SPEED)
+ MAKECASE(OID_GEN_LINK_STATE)
+ MAKECASE(OID_GEN_LINK_PARAMETERS)
+ MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES)
+ MAKECASE(OID_GEN_ENUMERATE_PORTS)
+ MAKECASE(OID_GEN_PORT_STATE)
+ MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS)
+ MAKECASE(OID_GEN_INTERRUPT_MODERATION)
+ MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX)
+
+ /* Statistical OIDs */
+ MAKECASE(OID_GEN_XMIT_OK)
+ MAKECASE(OID_GEN_RCV_OK)
+ MAKECASE(OID_GEN_XMIT_ERROR)
+ MAKECASE(OID_GEN_RCV_ERROR)
+ MAKECASE(OID_GEN_RCV_NO_BUFFER)
+ MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT)
+ MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT)
+ MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT)
+ MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT)
+ MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT)
+ MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT)
+ MAKECASE(OID_GEN_DIRECTED_BYTES_RCV)
+ MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV)
+ MAKECASE(OID_GEN_MULTICAST_BYTES_RCV)
+ MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV)
+ MAKECASE(OID_GEN_BROADCAST_BYTES_RCV)
+ MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV)
+ MAKECASE(OID_GEN_RCV_CRC_ERROR)
+ MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH)
+
+ /* Statistical OIDs for NDIS 6.0 */
+ MAKECASE(OID_GEN_STATISTICS)
+ MAKECASE(OID_GEN_BYTES_RCV)
+ MAKECASE(OID_GEN_BYTES_XMIT)
+ MAKECASE(OID_GEN_RCV_DISCARDS)
+ MAKECASE(OID_GEN_XMIT_DISCARDS)
+
+ /* Misc OIDs */
+ MAKECASE(OID_GEN_GET_TIME_CAPS)
+ MAKECASE(OID_GEN_GET_NETCARD_TIME)
+ MAKECASE(OID_GEN_NETCARD_LOAD)
+ MAKECASE(OID_GEN_DEVICE_PROFILE)
+ MAKECASE(OID_GEN_INIT_TIME_MS)
+ MAKECASE(OID_GEN_RESET_COUNTS)
+ MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS)
+
+ /* PnP power management operational OIDs */
+ MAKECASE(OID_PNP_CAPABILITIES)
+ MAKECASE(OID_PNP_SET_POWER)
+ MAKECASE(OID_PNP_QUERY_POWER)
+ MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN)
+ MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN)
+ MAKECASE(OID_PNP_ENABLE_WAKE_UP)
+ MAKECASE(OID_PNP_WAKE_UP_PATTERN_LIST)
+
+ /* PnP power management statistical OIDs */
+ MAKECASE(OID_PNP_WAKE_UP_ERROR)
+ MAKECASE(OID_PNP_WAKE_UP_OK)
+
+ /* Ethernet operational OIDs */
+ MAKECASE(OID_802_3_PERMANENT_ADDRESS)
+ MAKECASE(OID_802_3_CURRENT_ADDRESS)
+ MAKECASE(OID_802_3_MULTICAST_LIST)
+ MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE)
+ MAKECASE(OID_802_3_MAC_OPTIONS)
+
+ /* Ethernet operational OIDs for NDIS 6.0 */
+ MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS)
+ MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS)
+
+ /* Ethernet statistical OIDs */
+ MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT)
+ MAKECASE(OID_802_3_XMIT_ONE_COLLISION)
+ MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS)
+ MAKECASE(OID_802_3_XMIT_DEFERRED)
+ MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS)
+ MAKECASE(OID_802_3_RCV_OVERRUN)
+ MAKECASE(OID_802_3_XMIT_UNDERRUN)
+ MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE)
+ MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST)
+ MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS)
+
+ /* TCP/IP OIDs */
+ MAKECASE(OID_TCP_TASK_OFFLOAD)
+ MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA)
+ MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA)
+ MAKECASE(OID_TCP_SAN_SUPPORT)
+ MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA)
+ MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA)
+ MAKECASE(OID_TCP4_OFFLOAD_STATS)
+ MAKECASE(OID_TCP6_OFFLOAD_STATS)
+ MAKECASE(OID_IP4_OFFLOAD_STATS)
+ MAKECASE(OID_IP6_OFFLOAD_STATS)
+
+ /* TCP offload OIDs for NDIS 6 */
+ MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG)
+ MAKECASE(OID_TCP_OFFLOAD_PARAMETERS)
+ MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES)
+ MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG)
+ MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES)
+ MAKECASE(OID_OFFLOAD_ENCAPSULATION)
+
+#if (NDIS_SUPPORT_NDIS620)
+ /* VMQ OIDs for NDIS 6.20 */
+ MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE)
+ MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER)
+ MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE)
+ MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE)
+ MAKECASE(OID_RECEIVE_FILTER_SET_FILTER)
+#endif
+
+#if (NDIS_SUPPORT_NDIS630)
+ /* NDIS QoS OIDs for NDIS 6.30 */
+ MAKECASE(OID_QOS_PARAMETERS)
+#endif
+ }
+
+ if (oidName)
+ {
+ DEBUGP(("OID: %s", oidName));
+ }
+ else
+ {
+ DEBUGP(("<** Unknown OID 0x%08x **>\n", Oid));
+ }
+}
+
+#endif // DBG
+
+//======================================================================
+// TAP NDIS 6 OID Request Callbacks
+//======================================================================
+
+NDIS_STATUS
+tapSetMulticastList(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNDIS_OID_REQUEST OidRequest
+ )
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ //
+ // Initialize.
+ //
+ OidRequest->DATA.SET_INFORMATION.BytesNeeded = MACADDR_SIZE;
+ OidRequest->DATA.SET_INFORMATION.BytesRead
+ = OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+
+ do
+ {
+ if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength % MACADDR_SIZE)
+ {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength > (TAP_MAX_MCAST_LIST * MACADDR_SIZE))
+ {
+ status = NDIS_STATUS_MULTICAST_FULL;
+ OidRequest->DATA.SET_INFORMATION.BytesNeeded = TAP_MAX_MCAST_LIST * MACADDR_SIZE;
+ break;
+ }
+
+ // BUGBUG!!! Is lock needed??? If so, use NDIS_RW_LOCK. Also apply to packet filter.
+
+ NdisZeroMemory(Adapter->MCList,
+ TAP_MAX_MCAST_LIST * MACADDR_SIZE);
+
+ NdisMoveMemory(Adapter->MCList,
+ OidRequest->DATA.SET_INFORMATION.InformationBuffer,
+ OidRequest->DATA.SET_INFORMATION.InformationBufferLength);
+
+ Adapter->ulMCListSize = OidRequest->DATA.SET_INFORMATION.InformationBufferLength / MACADDR_SIZE;
+
+ } while(FALSE);
+ return status;
+}
+
+NDIS_STATUS
+tapSetPacketFilter(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in ULONG PacketFilter
+ )
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ // any bits not supported?
+ if (PacketFilter & ~(TAP_SUPPORTED_FILTERS))
+ {
+ DEBUGP (("[TAP] Unsupported packet filter: 0x%08x\n", PacketFilter));
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ // Any actual filtering changes?
+ if (PacketFilter != Adapter->PacketFilter)
+ {
+ //
+ // Change the filtering modes on hardware
+ //
+
+ // Save the new packet filter value
+ Adapter->PacketFilter = PacketFilter;
+ }
+ }
+
+ return status;
+}
+
+NDIS_STATUS
+AdapterSetPowerD0(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+/*++
+Routine Description:
+
+ NIC power has been restored to the working power state (D0).
+ Prepare the NIC for normal operation:
+ - Restore hardware context (packet filters, multicast addresses, MAC address, etc.)
+ - Enable interrupts and the NIC's DMA engine.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP (("[TAP] PowerState: Fully powered\n"));
+
+ // Start data path...
+
+ return status;
+}
+
+NDIS_STATUS
+AdapterSetPowerLow(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in NDIS_DEVICE_POWER_STATE PowerState
+ )
+/*++
+Routine Description:
+
+ The NIC is about to be transitioned to a low power state.
+ Prepare the NIC for the sleeping state:
+ - Disable interrupts and the NIC's DMA engine, cancel timers.
+ - Save any hardware context that the NIC cannot preserve in
+ a sleeping state (packet filters, multicast addresses,
+ the current MAC address, etc.)
+ A miniport driver cannot access the NIC hardware after
+ the NIC has been set to the D3 state by the bus driver.
+
+ Miniport drivers NDIS v6.30 and above
+ Do NOT wait for NDIS to return the ownership of all
+ NBLs from outstanding receive indications
+ Retain ownership of all the receive descriptors and
+ packet buffers previously owned by the hardware.
+
+Arguments:
+
+ Adapter - Pointer to adapter block
+ PowerState - New power state
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ DEBUGP (("[TAP] PowerState: Low-power\n"));
+
+ //
+ // Miniport drivers NDIS v6.20 and below are
+ // paused prior the low power transition
+ //
+
+ // Check for paused state...
+ // Verify data path stopped...
+
+ return status;
+}
+
+NDIS_STATUS
+tapSetInformation(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNDIS_OID_REQUEST OidRequest
+ )
+/*++
+
+Routine Description:
+
+ Helper function to perform a set OID request
+
+Arguments:
+
+ Adapter -
+ NdisSetRequest - The OID to set
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+
+ DBG_PRINT_OID_NAME(OidRequest->DATA.SET_INFORMATION.Oid);
+
+ switch(OidRequest->DATA.SET_INFORMATION.Oid)
+ {
+ case OID_802_3_MULTICAST_LIST:
+ //
+ // Set the multicast address list on the NIC for packet reception.
+ // The NIC driver can set a limit on the number of multicast
+ // addresses bound protocol drivers can enable simultaneously.
+ // NDIS returns NDIS_STATUS_MULTICAST_FULL if a protocol driver
+ // exceeds this limit or if it specifies an invalid multicast
+ // address.
+ //
+ status = tapSetMulticastList(Adapter,OidRequest);
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ //
+ // A protocol driver can set a suggested value for the number
+ // of bytes to be used in its binding; however, the underlying
+ // NIC driver is never required to limit its indications to
+ // the value set.
+ //
+ if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG))
+ {
+ OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG);
+ status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ Adapter->ulLookahead = *(PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
+
+ OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(ULONG);
+ status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ //
+ // Program the hardware to indicate the packets
+ // of certain filter types.
+ //
+ if(OidRequest->DATA.SET_INFORMATION.InformationBufferLength != sizeof(ULONG))
+ {
+ OidRequest->DATA.SET_INFORMATION.BytesNeeded = sizeof(ULONG);
+ status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ OidRequest->DATA.SET_INFORMATION.BytesRead
+ = OidRequest->DATA.SET_INFORMATION.InformationBufferLength;
+
+ status = tapSetPacketFilter(
+ Adapter,
+ *((PULONG)OidRequest->DATA.SET_INFORMATION.InformationBuffer)
+ );
+
+ break;
+
+ case OID_PNP_SET_POWER:
+ {
+ // Sanity check.
+ if (OidRequest->DATA.SET_INFORMATION.InformationBufferLength
+ < sizeof(NDIS_DEVICE_POWER_STATE)
+ )
+ {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ }
+ else
+ {
+ NDIS_DEVICE_POWER_STATE PowerState;
+
+ PowerState = *(PNDIS_DEVICE_POWER_STATE UNALIGNED)OidRequest->DATA.SET_INFORMATION.InformationBuffer;
+ OidRequest->DATA.SET_INFORMATION.BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
+
+ if(PowerState < NdisDeviceStateD0 ||
+ PowerState > NdisDeviceStateD3)
+ {
+ status = NDIS_STATUS_INVALID_DATA;
+ }
+ else
+ {
+ Adapter->CurrentPowerState = PowerState;
+
+ if (PowerState == NdisDeviceStateD0)
+ {
+ status = AdapterSetPowerD0(Adapter);
+ }
+ else
+ {
+ status = AdapterSetPowerLow(Adapter, PowerState);
+ }
+ }
+ }
+ }
+ break;
+
+#if (NDIS_SUPPORT_NDIS61)
+ case OID_PNP_ADD_WAKE_UP_PATTERN:
+ case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+ case OID_PNP_ENABLE_WAKE_UP:
+#endif
+ ASSERT(!"NIC does not support wake on LAN OIDs");
+ default:
+ //
+ // The entry point may by used by other requests
+ //
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return status;
+}
+
+NDIS_STATUS
+tapQueryInformation(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNDIS_OID_REQUEST OidRequest
+ )
+/*++
+
+Routine Description:
+
+ Helper function to perform a query OID request
+
+Arguments:
+
+ Adapter -
+ OidRequest - The OID request that is being queried
+
+Return Value:
+
+ NDIS_STATUS
+
+--*/
+{
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
+ NDIS_MEDIUM Medium = TAP_MEDIUM_TYPE;
+ NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
+ UCHAR VendorDesc[] = TAP_VENDOR_DESC;
+ ULONG ulInfo;
+ USHORT usInfo;
+ ULONG64 ulInfo64;
+
+ // Default to returning the ULONG value
+ PVOID pInfo=NULL;
+ ULONG ulInfoLen = sizeof(ulInfo);
+
+ // ATTENTION!!! Ignore OIDs to noisy to print...
+ if((OidRequest->DATA.QUERY_INFORMATION.Oid != OID_GEN_STATISTICS)
+ && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP4_OFFLOAD_STATS)
+ && (OidRequest->DATA.QUERY_INFORMATION.Oid != OID_IP6_OFFLOAD_STATS)
+ )
+ {
+ DBG_PRINT_OID_NAME(OidRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+
+ // Dispatch based on object identifier (OID).
+ switch(OidRequest->DATA.QUERY_INFORMATION.Oid)
+ {
+ case OID_GEN_HARDWARE_STATUS:
+ //
+ // Specify the current hardware status of the underlying NIC as
+ // one of the following NDIS_HARDWARE_STATUS-type values.
+ //
+ pInfo = (PVOID) &HardwareStatus;
+ ulInfoLen = sizeof(NDIS_HARDWARE_STATUS);
+ break;
+
+ case OID_802_3_PERMANENT_ADDRESS:
+ //
+ // Return the MAC address of the NIC burnt in the hardware.
+ //
+ pInfo = Adapter->PermanentAddress;
+ ulInfoLen = MACADDR_SIZE;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+ //
+ // Return the MAC address the NIC is currently programmed to
+ // use. Note that this address could be different from the
+ // permananent address as the user can override using
+ // registry. Read NdisReadNetworkAddress doc for more info.
+ //
+ pInfo = Adapter->CurrentAddress;
+ ulInfoLen = MACADDR_SIZE;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+ //
+ // Return an array of media that are supported by the miniport.
+ // This miniport only supports one medium (Ethernet), so the OID
+ // returns identical results to OID_GEN_MEDIA_IN_USE.
+ //
+
+ __fallthrough;
+
+ case OID_GEN_MEDIA_IN_USE:
+ //
+ // Return an array of media that are currently in use by the
+ // miniport. This array should be a subset of the array returned
+ // by OID_GEN_MEDIA_SUPPORTED.
+ //
+ pInfo = &Medium;
+ ulInfoLen = sizeof(Medium);
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ //
+ // Specify the maximum total packet length, in bytes, the NIC
+ // supports including the header. A protocol driver might use
+ // this returned length as a gauge to determine the maximum
+ // size packet that a NIC driver could forward to the
+ // protocol driver. The miniport driver must never indicate
+ // up to the bound protocol driver packets received over the
+ // network that are longer than the packet size specified by
+ // OID_GEN_MAXIMUM_TOTAL_SIZE.
+ //
+
+ __fallthrough;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ //
+ // The OID_GEN_TRANSMIT_BLOCK_SIZE OID specifies the minimum
+ // number of bytes that a single net packet occupies in the
+ // transmit buffer space of the NIC. In our case, the transmit
+ // block size is identical to its maximum packet size.
+ __fallthrough;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ //
+ // The OID_GEN_RECEIVE_BLOCK_SIZE OID specifies the amount of
+ // storage, in bytes, that a single packet occupies in the receive
+ // buffer space of the NIC.
+ //
+ ulInfo = (ULONG) TAP_MAX_FRAME_SIZE;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_INTERRUPT_MODERATION:
+ {
+ PNDIS_INTERRUPT_MODERATION_PARAMETERS moderationParams
+ = (PNDIS_INTERRUPT_MODERATION_PARAMETERS)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+
+ moderationParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ moderationParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ moderationParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ moderationParams->Flags = 0;
+ moderationParams->InterruptModeration = NdisInterruptModerationNotSupported;
+ ulInfoLen = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ }
+ break;
+
+ case OID_PNP_QUERY_POWER:
+ // Simply succeed this.
+ break;
+
+ case OID_GEN_VENDOR_ID:
+ //
+ // Specify a three-byte IEEE-registered vendor code, followed
+ // by a single byte that the vendor assigns to identify a
+ // particular NIC. The IEEE code uniquely identifies the vendor
+ // and is the same as the three bytes appearing at the beginning
+ // of the NIC hardware address. Vendors without an IEEE-registered
+ // code should use the value 0xFFFFFF.
+ //
+
+ ulInfo = TAP_VENDOR_ID;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+ //
+ // Specify a zero-terminated string describing the NIC vendor.
+ //
+ pInfo = VendorDesc;
+ ulInfoLen = sizeof(VendorDesc);
+ break;
+
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ //
+ // Specify the vendor-assigned version number of the NIC driver.
+ // The low-order half of the return value specifies the minor
+ // version; the high-order half specifies the major version.
+ //
+
+ ulInfo = TAP_DRIVER_VENDOR_VERSION;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+ //
+ // Specify the NDIS version in use by the NIC driver. The high
+ // byte is the major version number; the low byte is the minor
+ // version number.
+ //
+ usInfo = (USHORT) (TAP_NDIS_MAJOR_VERSION<<8) + TAP_NDIS_MINOR_VERSION;
+ pInfo = (PVOID) &usInfo;
+ ulInfoLen = sizeof(USHORT);
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ //
+ // The maximum number of multicast addresses the NIC driver
+ // can manage. This list is global for all protocols bound
+ // to (or above) the NIC. Consequently, a protocol can receive
+ // NDIS_STATUS_MULTICAST_FULL from the NIC driver when
+ // attempting to set the multicast address list, even if
+ // the number of elements in the given list is less than
+ // the number originally returned for this query.
+ //
+
+ ulInfo = TAP_MAX_MCAST_LIST;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_XMIT_ERROR:
+ ulInfo = (ULONG)
+ (Adapter->TxAbortExcessCollisions +
+ Adapter->TxDmaUnderrun +
+ Adapter->TxLostCRS +
+ Adapter->TxLateCollisions+
+ Adapter->TransmitFailuresOther);
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_RCV_ERROR:
+ ulInfo = (ULONG)
+ (Adapter->RxCrcErrors +
+ Adapter->RxAlignmentErrors +
+ Adapter->RxDmaOverrunErrors +
+ Adapter->RxRuntErrors);
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_RCV_DISCARDS:
+ ulInfo = (ULONG)Adapter->RxResourceErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_RCV_NO_BUFFER:
+ ulInfo = (ULONG)Adapter->RxResourceErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_XMIT_OK:
+ ulInfo64 = Adapter->FramesTxBroadcast
+ + Adapter->FramesTxMulticast
+ + Adapter->FramesTxDirected;
+ pInfo = &ulInfo64;
+ if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) ||
+ OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0)
+ {
+ ulInfoLen = sizeof(ULONG64);
+ }
+ else
+ {
+ ulInfoLen = sizeof(ULONG);
+ }
+
+ // We should always report that only 8 bytes are required to keep ndistest happy
+ OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64);
+ break;
+
+ case OID_GEN_RCV_OK:
+ ulInfo64 = Adapter->FramesRxBroadcast
+ + Adapter->FramesRxMulticast
+ + Adapter->FramesRxDirected;
+
+ pInfo = &ulInfo64;
+
+ if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(ULONG64) ||
+ OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength == 0)
+ {
+ ulInfoLen = sizeof(ULONG64);
+ }
+ else
+ {
+ ulInfoLen = sizeof(ULONG);
+ }
+
+ // We should always report that only 8 bytes are required to keep ndistest happy
+ OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(ULONG64);
+ break;
+
+ case OID_802_3_RCV_ERROR_ALIGNMENT:
+
+ ulInfo = Adapter->RxAlignmentErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_ONE_COLLISION:
+
+ ulInfo = Adapter->OneRetry;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_MORE_COLLISIONS:
+
+ ulInfo = Adapter->MoreThanOneRetry;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_DEFERRED:
+
+ ulInfo = Adapter->TxOKButDeferred;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_MAX_COLLISIONS:
+
+ ulInfo = Adapter->TxAbortExcessCollisions;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_RCV_OVERRUN:
+
+ ulInfo = Adapter->RxDmaOverrunErrors;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_802_3_XMIT_UNDERRUN:
+
+ ulInfo = Adapter->TxDmaUnderrun;
+ pInfo = &ulInfo;
+ break;
+
+ case OID_GEN_STATISTICS:
+
+ if (OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength < sizeof(NDIS_STATISTICS_INFO))
+ {
+ status = NDIS_STATUS_INVALID_LENGTH;
+ OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = sizeof(NDIS_STATISTICS_INFO);
+ break;
+ }
+ else
+ {
+ PNDIS_STATISTICS_INFO Statistics
+ = (PNDIS_STATISTICS_INFO)OidRequest->DATA.QUERY_INFORMATION.InformationBuffer;
+
+ {C_ASSERT(sizeof(NDIS_STATISTICS_INFO) >= NDIS_SIZEOF_STATISTICS_INFO_REVISION_1);}
+ Statistics->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ Statistics->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ Statistics->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
+
+ Statistics->SupportedStatistics = TAP_SUPPORTED_STATISTICS;
+
+ /* Bytes in */
+ Statistics->ifHCInOctets =
+ Adapter->BytesRxDirected +
+ Adapter->BytesRxMulticast +
+ Adapter->BytesRxBroadcast;
+
+ Statistics->ifHCInUcastOctets =
+ Adapter->BytesRxDirected;
+
+ Statistics->ifHCInMulticastOctets =
+ Adapter->BytesRxMulticast;
+
+ Statistics->ifHCInBroadcastOctets =
+ Adapter->BytesRxBroadcast;
+
+ /* Packets in */
+ Statistics->ifHCInUcastPkts =
+ Adapter->FramesRxDirected;
+
+ Statistics->ifHCInMulticastPkts =
+ Adapter->FramesRxMulticast;
+
+ Statistics->ifHCInBroadcastPkts =
+ Adapter->FramesRxBroadcast;
+
+ /* Errors in */
+ Statistics->ifInErrors =
+ Adapter->RxCrcErrors +
+ Adapter->RxAlignmentErrors +
+ Adapter->RxDmaOverrunErrors +
+ Adapter->RxRuntErrors;
+
+ Statistics->ifInDiscards =
+ Adapter->RxResourceErrors;
+
+
+ /* Bytes out */
+ Statistics->ifHCOutOctets =
+ Adapter->BytesTxDirected +
+ Adapter->BytesTxMulticast +
+ Adapter->BytesTxBroadcast;
+
+ Statistics->ifHCOutUcastOctets =
+ Adapter->BytesTxDirected;
+
+ Statistics->ifHCOutMulticastOctets =
+ Adapter->BytesTxMulticast;
+
+ Statistics->ifHCOutBroadcastOctets =
+ Adapter->BytesTxBroadcast;
+
+ /* Packets out */
+ Statistics->ifHCOutUcastPkts =
+ Adapter->FramesTxDirected;
+
+ Statistics->ifHCOutMulticastPkts =
+ Adapter->FramesTxMulticast;
+
+ Statistics->ifHCOutBroadcastPkts =
+ Adapter->FramesTxBroadcast;
+
+ /* Errors out */
+ Statistics->ifOutErrors =
+ Adapter->TxAbortExcessCollisions +
+ Adapter->TxDmaUnderrun +
+ Adapter->TxLostCRS +
+ Adapter->TxLateCollisions+
+ Adapter->TransmitFailuresOther;
+
+ Statistics->ifOutDiscards = 0ULL;
+
+ ulInfoLen = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ }
+
+ break;
+
+ // TODO: Inplement these query information requests.
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_MAXIMUM_SEND_PACKETS:
+ case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+ case OID_802_3_XMIT_HEARTBEAT_FAILURE:
+ case OID_802_3_XMIT_TIMES_CRS_LOST:
+ case OID_802_3_XMIT_LATE_COLLISIONS:
+
+ default:
+ //
+ // The entry point may by used by other requests
+ //
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (status == NDIS_STATUS_SUCCESS)
+ {
+ ASSERT(ulInfoLen > 0);
+
+ if (ulInfoLen <= OidRequest->DATA.QUERY_INFORMATION.InformationBufferLength)
+ {
+ if(pInfo)
+ {
+ // Copy result into InformationBuffer
+ NdisMoveMemory(
+ OidRequest->DATA.QUERY_INFORMATION.InformationBuffer,
+ pInfo,
+ ulInfoLen
+ );
+ }
+
+ OidRequest->DATA.QUERY_INFORMATION.BytesWritten = ulInfoLen;
+ }
+ else
+ {
+ // too short
+ OidRequest->DATA.QUERY_INFORMATION.BytesNeeded = ulInfoLen;
+ status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ }
+
+ return status;
+}
+
+NDIS_STATUS
+AdapterOidRequest(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PNDIS_OID_REQUEST OidRequest
+ )
+/*++
+
+Routine Description:
+
+ Entry point called by NDIS to get or set the value of a specified OID.
+
+Arguments:
+
+ MiniportAdapterContext - Our adapter handle
+ NdisRequest - The OID request to handle
+
+Return Value:
+
+ Return code from the NdisRequest below.
+
+--*/
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+ NDIS_STATUS status;
+
+ // Dispatch based on request type.
+ switch (OidRequest->RequestType)
+ {
+ case NdisRequestSetInformation:
+ status = tapSetInformation(adapter,OidRequest);
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ status = tapQueryInformation(adapter,OidRequest);
+ break;
+
+ case NdisRequestMethod: // TAP doesn't need to respond to this request type.
+ default:
+ //
+ // The entry point may by used by other requests
+ //
+ status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return status;
+}
+
+VOID
+AdapterCancelOidRequest(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PVOID RequestId
+ )
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+ UNREFERENCED_PARAMETER(RequestId);
+
+ //
+ // This miniport sample does not pend any OID requests, so we don't have
+ // to worry about cancelling them.
+ //
+}
+
diff --git a/windows/TapDriver6/proto.h b/windows/TapDriver6/proto.h
new file mode 100644
index 00000000..cc23de6d
--- /dev/null
+++ b/windows/TapDriver6/proto.h
@@ -0,0 +1,224 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//============================================================
+// MAC address, Ethernet header, and ARP
+//============================================================
+
+#pragma pack(1)
+
+#define IP_HEADER_SIZE 20
+#define IPV6_HEADER_SIZE 40
+
+#define MACADDR_SIZE 6
+typedef unsigned char MACADDR[MACADDR_SIZE];
+
+typedef unsigned long IPADDR;
+typedef unsigned char IPV6ADDR[16];
+
+//-----------------
+// Ethernet address
+//-----------------
+
+typedef struct {
+ MACADDR addr;
+} ETH_ADDR;
+
+typedef struct {
+ ETH_ADDR list[TAP_MAX_MCAST_LIST];
+} MC_LIST;
+
+
+// BUGBUG!!! Consider using ststem defines in netiodef.h!!!
+
+//----------------
+// Ethernet header
+//----------------
+typedef struct
+{
+ MACADDR dest; /* destination eth addr */
+ MACADDR src; /* source ether addr */
+ USHORT proto; /* packet type ID field */
+} ETH_HEADER, *PETH_HEADER;
+
+//----------------
+// ARP packet
+//----------------
+
+typedef struct
+ {
+ MACADDR m_MAC_Destination; // Reverse these two
+ MACADDR m_MAC_Source; // to answer ARP requests
+ USHORT m_Proto; // 0x0806
+
+# define MAC_ADDR_TYPE 0x0001
+ USHORT m_MAC_AddressType; // 0x0001
+
+ USHORT m_PROTO_AddressType; // 0x0800
+ UCHAR m_MAC_AddressSize; // 0x06
+ UCHAR m_PROTO_AddressSize; // 0x04
+
+# define ARP_REQUEST 0x0001
+# define ARP_REPLY 0x0002
+ USHORT m_ARP_Operation; // 0x0001 for ARP request, 0x0002 for ARP reply
+
+ MACADDR m_ARP_MAC_Source;
+ IPADDR m_ARP_IP_Source;
+ MACADDR m_ARP_MAC_Destination;
+ IPADDR m_ARP_IP_Destination;
+ }
+ARP_PACKET, *PARP_PACKET;
+
+//----------
+// IP Header
+//----------
+
+typedef struct {
+# define IPH_GET_VER(v) (((v) >> 4) & 0x0F)
+# define IPH_GET_LEN(v) (((v) & 0x0F) << 2)
+ UCHAR version_len;
+
+ UCHAR tos;
+ USHORT tot_len;
+ USHORT id;
+
+# define IP_OFFMASK 0x1fff
+ USHORT frag_off;
+
+ UCHAR ttl;
+
+# define IPPROTO_UDP 17 /* UDP protocol */
+# define IPPROTO_TCP 6 /* TCP protocol */
+# define IPPROTO_ICMP 1 /* ICMP protocol */
+# define IPPROTO_IGMP 2 /* IGMP protocol */
+ UCHAR protocol;
+
+ USHORT check;
+ ULONG saddr;
+ ULONG daddr;
+ /* The options start here. */
+} IPHDR;
+
+//-----------
+// UDP header
+//-----------
+
+typedef struct {
+ USHORT source;
+ USHORT dest;
+ USHORT len;
+ USHORT check;
+} UDPHDR;
+
+//--------------------------
+// TCP header, per RFC 793.
+//--------------------------
+
+typedef struct {
+ USHORT source; /* source port */
+ USHORT dest; /* destination port */
+ ULONG seq; /* sequence number */
+ ULONG ack_seq; /* acknowledgement number */
+
+# define TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2)
+ UCHAR doff_res;
+
+# define TCPH_FIN_MASK (1<<0)
+# define TCPH_SYN_MASK (1<<1)
+# define TCPH_RST_MASK (1<<2)
+# define TCPH_PSH_MASK (1<<3)
+# define TCPH_ACK_MASK (1<<4)
+# define TCPH_URG_MASK (1<<5)
+# define TCPH_ECE_MASK (1<<6)
+# define TCPH_CWR_MASK (1<<7)
+ UCHAR flags;
+
+ USHORT window;
+ USHORT check;
+ USHORT urg_ptr;
+} TCPHDR;
+
+#define TCPOPT_EOL 0
+#define TCPOPT_NOP 1
+#define TCPOPT_MAXSEG 2
+#define TCPOLEN_MAXSEG 4
+
+//------------
+// IPv6 Header
+//------------
+
+typedef struct {
+ UCHAR version_prio;
+ UCHAR flow_lbl[3];
+ USHORT payload_len;
+# define IPPROTO_ICMPV6 0x3a /* ICMP protocol v6 */
+ UCHAR nexthdr;
+ UCHAR hop_limit;
+ IPV6ADDR saddr;
+ IPV6ADDR daddr;
+} IPV6HDR;
+
+//--------------------------------------------
+// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861)
+//--------------------------------------------
+
+// Neighbor Solictiation - RFC 4861, 4.3
+// (this is just the ICMPv6 part of the packet)
+typedef struct {
+ UCHAR type;
+# define ICMPV6_TYPE_NS 135 // neighbour solicitation
+ UCHAR code;
+# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA
+ USHORT checksum;
+ ULONG reserved;
+ IPV6ADDR target_addr;
+} ICMPV6_NS;
+
+// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1
+// (this is just the ICMPv6 payload)
+typedef struct {
+ UCHAR type;
+# define ICMPV6_TYPE_NA 136 // neighbour advertisement
+ UCHAR code;
+# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA
+ USHORT checksum;
+ UCHAR rso_bits; // Router(0), Solicited(2), Ovrrd(4)
+ UCHAR reserved[3];
+ IPV6ADDR target_addr;
+// always include "Target Link-layer Address" option (RFC 4861 4.6.1)
+ UCHAR opt_type;
+#define ICMPV6_OPTION_TLLA 2
+ UCHAR opt_length;
+#define ICMPV6_LENGTH_TLLA 1 // multiplied by 8 -> 1 = 8 bytes
+ MACADDR target_macaddr;
+} ICMPV6_NA;
+
+// this is the complete packet with Ethernet and IPv6 headers
+typedef struct {
+ ETH_HEADER eth;
+ IPV6HDR ipv6;
+ ICMPV6_NA icmpv6;
+} ICMPV6_NA_PKT;
+
+#pragma pack()
diff --git a/windows/TapDriver6/prototypes.h b/windows/TapDriver6/prototypes.h
new file mode 100644
index 00000000..a48d35e7
--- /dev/null
+++ b/windows/TapDriver6/prototypes.h
@@ -0,0 +1,91 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TAP_PROTOTYPES_DEFINED
+#define TAP_PROTOTYPES_DEFINED
+
+DRIVER_INITIALIZE DriverEntry;
+
+//VOID AdapterFreeResources
+// (
+// TapAdapterPointer p_Adapter
+// );
+//
+
+//
+//NTSTATUS TapDeviceHook
+// (
+// IN PDEVICE_OBJECT p_DeviceObject,
+// IN PIRP p_IRP
+// );
+//
+
+NDIS_STATUS
+CreateTapDevice(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ );
+
+VOID
+DestroyTapDevice(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ );
+
+// Flush the pending send TAP packet queue.
+VOID
+tapFlushSendPacketQueue(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ );
+
+VOID
+IndicateReceivePacket(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PUCHAR packetData,
+ __in const unsigned int packetLength
+ );
+
+/*
+BOOLEAN
+ProcessDHCP(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in const ETH_HEADER *eth,
+ __in const IPHDR *ip,
+ __in const UDPHDR *udp,
+ __in const DHCP *dhcp,
+ __in int optlen
+ );
+*/
+
+/*
+BOOLEAN
+ProcessARP(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in const PARP_PACKET src,
+ __in const IPADDR adapter_ip,
+ __in const IPADDR ip_network,
+ __in const IPADDR ip_netmask,
+ __in const MACADDR mac
+ );
+*/
+
+#endif
diff --git a/windows/TapDriver6/resource.h b/windows/TapDriver6/resource.h
new file mode 100644
index 00000000..d609f17c
--- /dev/null
+++ b/windows/TapDriver6/resource.h
@@ -0,0 +1,1573 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resource.rc
+//
+#define SW_HIDE 0
+#define HIDE_WINDOW 0
+#define WM_NULL 0x0000
+#define WA_INACTIVE 0
+#define HTNOWHERE 0
+#define SMTO_NORMAL 0x0000
+#define ICON_SMALL 0
+#define SIZE_RESTORED 0
+#define BN_CLICKED 0
+#define BST_UNCHECKED 0x0000
+#define HDS_HORZ 0x0000
+#define TBSTYLE_BUTTON 0x0000
+#define TBS_HORZ 0x0000
+#define TBS_BOTTOM 0x0000
+#define TBS_RIGHT 0x0000
+#define LVS_ICON 0x0000
+#define LVS_ALIGNTOP 0x0000
+#define TCS_TABS 0x0000
+#define TCS_SINGLELINE 0x0000
+#define TCS_RIGHTJUSTIFY 0x0000
+#define DTS_SHORTDATEFORMAT 0x0000
+#define PGS_VERT 0x00000000
+#define LANG_NEUTRAL 0x00
+#define SUBLANG_NEUTRAL 0x00
+#define SORT_DEFAULT 0x0
+#define SORT_JAPANESE_XJIS 0x0
+#define SORT_CHINESE_BIG5 0x0
+#define SORT_CHINESE_PRCP 0x0
+#define SORT_KOREAN_KSC 0x0
+#define SORT_HUNGARIAN_DEFAULT 0x0
+#define SORT_GEORGIAN_TRADITIONAL 0x0
+#define _USE_DECLSPECS_FOR_SAL 0
+#define _USE_ATTRIBUTES_FOR_SAL 0
+#define __drv_typeConst 0
+#define VER_DEBUG 0
+#define VER_PRERELEASE 0
+#define PRODUCT_TAP_WIN_MINOR 0
+#define WINAPI_PARTITION_DESKTOP 0x00000001
+#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
+#define MINIMUM_RESERVED_MANIFEST_RESOURCE_ID 1
+#define SW_SHOWNORMAL 1
+#define SW_NORMAL 1
+#define SHOW_OPENWINDOW 1
+#define SW_PARENTCLOSING 1
+#define VK_LBUTTON 0x01
+#define WM_CREATE 0x0001
+#define WA_ACTIVE 1
+#define PWR_OK 1
+#define PWR_SUSPENDREQUEST 1
+#define NFR_ANSI 1
+#define UIS_SET 1
+#define UISF_HIDEFOCUS 0x1
+#define XBUTTON1 0x0001
+#define WMSZ_LEFT 1
+#define HTCLIENT 1
+#define SMTO_BLOCK 0x0001
+#define MA_ACTIVATE 1
+#define ICON_BIG 1
+#define SIZE_MINIMIZED 1
+#define MK_LBUTTON 0x0001
+#define TME_HOVER 0x00000001
+#define CS_VREDRAW 0x0001
+#define CF_TEXT 1
+#define SCF_ISSECURE 0x00000001
+#define IDOK 1
+#define BN_PAINT 1
+#define BST_CHECKED 0x0001
+#define TBSTYLE_SEP 0x0001
+#define TTS_ALWAYSTIP 0x01
+#define TBS_AUTOTICKS 0x0001
+#define UDS_WRAP 0x0001
+#define PBS_SMOOTH 0x01
+#define LWS_TRANSPARENT 0x0001
+#define LVS_REPORT 0x0001
+#define TVS_HASBUTTONS 0x0001
+#define TVS_EX_NOSINGLECOLLAPSE 0x0001
+#define TCS_SCROLLOPPOSITE 0x0001
+#define ACS_CENTER 0x0001
+#define MCS_DAYSTATE 0x0001
+#define DTS_UPDOWN 0x0001
+#define PGS_HORZ 0x00000001
+#define NFS_EDIT 0x0001
+#define BCSIF_GLYPH 0x0001
+#define BCSS_NOSPLIT 0x0001
+#define LANG_ARABIC 0x01
+#define SUBLANG_DEFAULT 0x01
+#define SUBLANG_AFRIKAANS_SOUTH_AFRICA 0x01
+#define SUBLANG_ALBANIAN_ALBANIA 0x01
+#define SUBLANG_ALSATIAN_FRANCE 0x01
+#define SUBLANG_AMHARIC_ETHIOPIA 0x01
+#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
+#define SUBLANG_ARMENIAN_ARMENIA 0x01
+#define SUBLANG_ASSAMESE_INDIA 0x01
+#define SUBLANG_AZERI_LATIN 0x01
+#define SUBLANG_AZERBAIJANI_AZERBAIJAN_LATIN 0x01
+#define SUBLANG_BANGLA_INDIA 0x01
+#define SUBLANG_BASHKIR_RUSSIA 0x01
+#define SUBLANG_BASQUE_BASQUE 0x01
+#define SUBLANG_BELARUSIAN_BELARUS 0x01
+#define SUBLANG_BENGALI_INDIA 0x01
+#define SUBLANG_BRETON_FRANCE 0x01
+#define SUBLANG_BULGARIAN_BULGARIA 0x01
+#define SUBLANG_CATALAN_CATALAN 0x01
+#define SUBLANG_CENTRAL_KURDISH_IRAQ 0x01
+#define SUBLANG_CHEROKEE_CHEROKEE 0x01
+#define SUBLANG_CHINESE_TRADITIONAL 0x01
+#define SUBLANG_CORSICAN_FRANCE 0x01
+#define SUBLANG_CZECH_CZECH_REPUBLIC 0x01
+#define SUBLANG_CROATIAN_CROATIA 0x01
+#define SUBLANG_DANISH_DENMARK 0x01
+#define SUBLANG_DARI_AFGHANISTAN 0x01
+#define SUBLANG_DIVEHI_MALDIVES 0x01
+#define SUBLANG_DUTCH 0x01
+#define SUBLANG_ENGLISH_US 0x01
+#define SUBLANG_ESTONIAN_ESTONIA 0x01
+#define SUBLANG_FAEROESE_FAROE_ISLANDS 0x01
+#define SUBLANG_FILIPINO_PHILIPPINES 0x01
+#define SUBLANG_FINNISH_FINLAND 0x01
+#define SUBLANG_FRENCH 0x01
+#define SUBLANG_FRISIAN_NETHERLANDS 0x01
+#define SUBLANG_GALICIAN_GALICIAN 0x01
+#define SUBLANG_GEORGIAN_GEORGIA 0x01
+#define SUBLANG_GERMAN 0x01
+#define SUBLANG_GREEK_GREECE 0x01
+#define SUBLANG_GREENLANDIC_GREENLAND 0x01
+#define SUBLANG_GUJARATI_INDIA 0x01
+#define SUBLANG_HAUSA_NIGERIA_LATIN 0x01
+#define SUBLANG_HAWAIIAN_US 0x01
+#define SUBLANG_HEBREW_ISRAEL 0x01
+#define SUBLANG_HINDI_INDIA 0x01
+#define SUBLANG_HUNGARIAN_HUNGARY 0x01
+#define SUBLANG_ICELANDIC_ICELAND 0x01
+#define SUBLANG_IGBO_NIGERIA 0x01
+#define SUBLANG_INDONESIAN_INDONESIA 0x01
+#define SUBLANG_INUKTITUT_CANADA 0x01
+#define SUBLANG_ITALIAN 0x01
+#define SUBLANG_JAPANESE_JAPAN 0x01
+#define SUBLANG_KANNADA_INDIA 0x01
+#define SUBLANG_KAZAK_KAZAKHSTAN 0x01
+#define SUBLANG_KHMER_CAMBODIA 0x01
+#define SUBLANG_KICHE_GUATEMALA 0x01
+#define SUBLANG_KINYARWANDA_RWANDA 0x01
+#define SUBLANG_KONKANI_INDIA 0x01
+#define SUBLANG_KOREAN 0x01
+#define SUBLANG_KYRGYZ_KYRGYZSTAN 0x01
+#define SUBLANG_LAO_LAO 0x01
+#define SUBLANG_LATVIAN_LATVIA 0x01
+#define SUBLANG_LITHUANIAN 0x01
+#define SUBLANG_LUXEMBOURGISH_LUXEMBOURG 0x01
+#define SUBLANG_MACEDONIAN_MACEDONIA 0x01
+#define SUBLANG_MALAY_MALAYSIA 0x01
+#define SUBLANG_MALAYALAM_INDIA 0x01
+#define SUBLANG_MALTESE_MALTA 0x01
+#define SUBLANG_MAORI_NEW_ZEALAND 0x01
+#define SUBLANG_MAPUDUNGUN_CHILE 0x01
+#define SUBLANG_MARATHI_INDIA 0x01
+#define SUBLANG_MOHAWK_MOHAWK 0x01
+#define SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA 0x01
+#define SUBLANG_NEPALI_NEPAL 0x01
+#define SUBLANG_NORWEGIAN_BOKMAL 0x01
+#define SUBLANG_OCCITAN_FRANCE 0x01
+#define SUBLANG_ODIA_INDIA 0x01
+#define SUBLANG_ORIYA_INDIA 0x01
+#define SUBLANG_PASHTO_AFGHANISTAN 0x01
+#define SUBLANG_PERSIAN_IRAN 0x01
+#define SUBLANG_POLISH_POLAND 0x01
+#define SUBLANG_PORTUGUESE_BRAZILIAN 0x01
+#define SUBLANG_PUNJABI_INDIA 0x01
+#define SUBLANG_QUECHUA_BOLIVIA 0x01
+#define SUBLANG_ROMANIAN_ROMANIA 0x01
+#define SUBLANG_ROMANSH_SWITZERLAND 0x01
+#define SUBLANG_RUSSIAN_RUSSIA 0x01
+#define SUBLANG_SAKHA_RUSSIA 0x01
+#define SUBLANG_SAMI_NORTHERN_NORWAY 0x01
+#define SUBLANG_SANSKRIT_INDIA 0x01
+#define SUBLANG_SCOTTISH_GAELIC 0x01
+#define SUBLANG_SERBIAN_CROATIA 0x01
+#define SUBLANG_SINDHI_INDIA 0x01
+#define SUBLANG_SINHALESE_SRI_LANKA 0x01
+#define SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA 0x01
+#define SUBLANG_SLOVAK_SLOVAKIA 0x01
+#define SUBLANG_SLOVENIAN_SLOVENIA 0x01
+#define SUBLANG_SPANISH 0x01
+#define SUBLANG_SWAHILI_KENYA 0x01
+#define SUBLANG_SWEDISH 0x01
+#define SUBLANG_SYRIAC_SYRIA 0x01
+#define SUBLANG_TAJIK_TAJIKISTAN 0x01
+#define SUBLANG_TAMIL_INDIA 0x01
+#define SUBLANG_TATAR_RUSSIA 0x01
+#define SUBLANG_TELUGU_INDIA 0x01
+#define SUBLANG_THAI_THAILAND 0x01
+#define SUBLANG_TIBETAN_PRC 0x01
+#define SUBLANG_TIGRINYA_ETHIOPIA 0x01
+#define SUBLANG_TSWANA_SOUTH_AFRICA 0x01
+#define SUBLANG_TURKISH_TURKEY 0x01
+#define SUBLANG_TURKMEN_TURKMENISTAN 0x01
+#define SUBLANG_UIGHUR_PRC 0x01
+#define SUBLANG_UKRAINIAN_UKRAINE 0x01
+#define SUBLANG_UPPER_SORBIAN_GERMANY 0x01
+#define SUBLANG_URDU_PAKISTAN 0x01
+#define SUBLANG_UZBEK_LATIN 0x01
+#define SUBLANG_VIETNAMESE_VIETNAM 0x01
+#define SUBLANG_WELSH_UNITED_KINGDOM 0x01
+#define SUBLANG_WOLOF_SENEGAL 0x01
+#define SUBLANG_XHOSA_SOUTH_AFRICA 0x01
+#define SUBLANG_YAKUT_RUSSIA 0x01
+#define SUBLANG_YI_PRC 0x01
+#define SUBLANG_YORUBA_NIGERIA 0x01
+#define SUBLANG_ZULU_SOUTH_AFRICA 0x01
+#define SORT_INVARIANT_MATH 0x1
+#define SORT_JAPANESE_UNICODE 0x1
+#define SORT_CHINESE_UNICODE 0x1
+#define SORT_KOREAN_UNICODE 0x1
+#define SORT_GERMAN_PHONE_BOOK 0x1
+#define SORT_HUNGARIAN_TECHNICAL 0x1
+#define SORT_GEORGIAN_MODERN 0x1
+#define __drv_typeCond 1
+#define VS_VERSION_INFO 1
+#define VFFF_ISSHAREDFILE 0x0001
+#define VFF_CURNEDEST 0x0001
+#define VIFF_FORCEINSTALL 0x0001
+#define WINAPI_PARTITION_APP 0x00000002
+#define ISOLATIONAWARE_MANIFEST_RESOURCE_ID 2
+#define SW_SHOWMINIMIZED 2
+#define SHOW_ICONWINDOW 2
+#define SW_OTHERZOOM 2
+#define VK_RBUTTON 0x02
+#define WM_DESTROY 0x0002
+#define WA_CLICKACTIVE 2
+#define PWR_SUSPENDRESUME 2
+#define NFR_UNICODE 2
+#define UIS_CLEAR 2
+#define UISF_HIDEACCEL 0x2
+#define XBUTTON2 0x0002
+#define WMSZ_RIGHT 2
+#define HTCAPTION 2
+#define SMTO_ABORTIFHUNG 0x0002
+#define MA_ACTIVATEANDEAT 2
+#define ICON_SMALL2 2
+#define SIZE_MAXIMIZED 2
+#define MK_RBUTTON 0x0002
+#define TME_LEAVE 0x00000002
+#define CS_HREDRAW 0x0002
+#define CF_BITMAP 2
+#define IDCANCEL 2
+#define BN_HILITE 2
+#define BST_INDETERMINATE 0x0002
+#define HDS_BUTTONS 0x0002
+#define TBSTYLE_CHECK 0x0002
+#define TTS_NOPREFIX 0x02
+#define TBS_VERT 0x0002
+#define UDS_SETBUDDYINT 0x0002
+#define LWS_IGNORERETURN 0x0002
+#define LVS_SMALLICON 0x0002
+#define TVS_HASLINES 0x0002
+#define TVS_EX_MULTISELECT 0x0002
+#define TCS_BOTTOM 0x0002
+#define TCS_RIGHT 0x0002
+#define ACS_TRANSPARENT 0x0002
+#define MCS_MULTISELECT 0x0002
+#define DTS_SHOWNONE 0x0002
+#define PGS_AUTOSCROLL 0x00000002
+#define NFS_STATIC 0x0002
+#define BCSIF_IMAGE 0x0002
+#define BCSS_STRETCH 0x0002
+#define LANG_BULGARIAN 0x02
+#define SUBLANG_SYS_DEFAULT 0x02
+#define SUBLANG_ARABIC_IRAQ 0x02
+#define SUBLANG_AZERI_CYRILLIC 0x02
+#define SUBLANG_AZERBAIJANI_AZERBAIJAN_CYRILLIC 0x02
+#define SUBLANG_BANGLA_BANGLADESH 0x02
+#define SUBLANG_BENGALI_BANGLADESH 0x02
+#define SUBLANG_CHINESE_SIMPLIFIED 0x02
+#define SUBLANG_DUTCH_BELGIAN 0x02
+#define SUBLANG_ENGLISH_UK 0x02
+#define SUBLANG_FRENCH_BELGIAN 0x02
+#define SUBLANG_FULAH_SENEGAL 0x02
+#define SUBLANG_GERMAN_SWISS 0x02
+#define SUBLANG_INUKTITUT_CANADA_LATIN 0x02
+#define SUBLANG_IRISH_IRELAND 0x02
+#define SUBLANG_ITALIAN_SWISS 0x02
+#define SUBLANG_KASHMIRI_SASIA 0x02
+#define SUBLANG_KASHMIRI_INDIA 0x02
+#define SUBLANG_LOWER_SORBIAN_GERMANY 0x02
+#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
+#define SUBLANG_MONGOLIAN_PRC 0x02
+#define SUBLANG_NEPALI_INDIA 0x02
+#define SUBLANG_NORWEGIAN_NYNORSK 0x02
+#define SUBLANG_PORTUGUESE 0x02
+#define SUBLANG_PULAR_SENEGAL 0x02
+#define SUBLANG_PUNJABI_PAKISTAN 0x02
+#define SUBLANG_QUECHUA_ECUADOR 0x02
+#define SUBLANG_SAMI_NORTHERN_SWEDEN 0x02
+#define SUBLANG_SERBIAN_LATIN 0x02
+#define SUBLANG_SINDHI_PAKISTAN 0x02
+#define SUBLANG_SINDHI_AFGHANISTAN 0x02
+#define SUBLANG_SPANISH_MEXICAN 0x02
+#define SUBLANG_SWEDISH_FINLAND 0x02
+#define SUBLANG_TAMAZIGHT_ALGERIA_LATIN 0x02
+#define SUBLANG_TAMIL_SRI_LANKA 0x02
+#define SUBLANG_TIGRIGNA_ERITREA 0x02
+#define SUBLANG_TIGRINYA_ERITREA 0x02
+#define SUBLANG_TSWANA_BOTSWANA 0x02
+#define SUBLANG_URDU_INDIA 0x02
+#define SUBLANG_UZBEK_CYRILLIC 0x02
+#define SUBLANG_VALENCIAN_VALENCIA 0x02
+#define SORT_CHINESE_PRC 0x2
+#define __drv_typeBitset 2
+#define VFF_FILEINUSE 0x0002
+#define VIFF_DONTDELETEOLD 0x0002
+#define VER_PRODUCTMINORVERSION 2
+#define ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID 3
+#define SW_SHOWMAXIMIZED 3
+#define SW_MAXIMIZE 3
+#define SHOW_FULLSCREEN 3
+#define SW_PARENTOPENING 3
+#define VK_CANCEL 0x03
+#define WM_MOVE 0x0003
+#define PWR_CRITICALRESUME 3
+#define NF_QUERY 3
+#define UIS_INITIALIZE 3
+#define WMSZ_TOP 3
+#define HTSYSMENU 3
+#define MA_NOACTIVATE 3
+#define SIZE_MAXSHOW 3
+#define CF_METAFILEPICT 3
+#define IDABORT 3
+#define BN_UNHILITE 3
+#define LVS_LIST 0x0003
+#define LVS_TYPEMASK 0x0003
+#define LANG_CATALAN 0x03
+#define LANG_VALENCIAN 0x03
+#define SUBLANG_CUSTOM_DEFAULT 0x03
+#define SUBLANG_ARABIC_EGYPT 0x03
+#define SUBLANG_CHINESE_HONGKONG 0x03
+#define SUBLANG_ENGLISH_AUS 0x03
+#define SUBLANG_FRENCH_CANADIAN 0x03
+#define SUBLANG_GERMAN_AUSTRIAN 0x03
+#define SUBLANG_QUECHUA_PERU 0x03
+#define SUBLANG_SAMI_NORTHERN_FINLAND 0x03
+#define SUBLANG_SERBIAN_CYRILLIC 0x03
+#define SUBLANG_SPANISH_MODERN 0x03
+#define SORT_CHINESE_BOPOMOFO 0x3
+#define __drv_typeExpr 3
+#define PRODUCT_TAP_WIN_MAJOR 3
+#define SW_SHOWNOACTIVATE 4
+#define SHOW_OPENNOACTIVATE 4
+#define SW_OTHERUNZOOM 4
+#define VK_MBUTTON 0x04
+#define NF_REQUERY 4
+#define UISF_ACTIVE 0x4
+#define WMSZ_TOPLEFT 4
+#define HTGROWBOX 4
+#define MA_NOACTIVATEANDEAT 4
+#define SIZE_MAXHIDE 4
+#define MK_SHIFT 0x0004
+#define CF_SYLK 4
+#define IDRETRY 4
+#define BN_DISABLE 4
+#define BST_PUSHED 0x0004
+#define HDS_HOTTRACK 0x0004
+#define TBSTYLE_GROUP 0x0004
+#define TBS_TOP 0x0004
+#define TBS_LEFT 0x0004
+#define UDS_ALIGNRIGHT 0x0004
+#define PBS_VERTICAL 0x04
+#define LWS_NOPREFIX 0x0004
+#define LVS_SINGLESEL 0x0004
+#define TVS_LINESATROOT 0x0004
+#define TVS_EX_DOUBLEBUFFER 0x0004
+#define TCS_MULTISELECT 0x0004
+#define ACS_AUTOPLAY 0x0004
+#define MCS_WEEKNUMBERS 0x0004
+#define DTS_LONGDATEFORMAT 0x0004
+#define PGS_DRAGNDROP 0x00000004
+#define NFS_LISTCOMBO 0x0004
+#define BCSIF_STYLE 0x0004
+#define BCSS_ALIGNLEFT 0x0004
+#define LANG_CHINESE 0x04
+#define LANG_CHINESE_SIMPLIFIED 0x04
+#define SUBLANG_CUSTOM_UNSPECIFIED 0x04
+#define SUBLANG_ARABIC_LIBYA 0x04
+#define SUBLANG_CHINESE_SINGAPORE 0x04
+#define SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN 0x04
+#define SUBLANG_ENGLISH_CAN 0x04
+#define SUBLANG_FRENCH_SWISS 0x04
+#define SUBLANG_GERMAN_LUXEMBOURG 0x04
+#define SUBLANG_SAMI_LULE_NORWAY 0x04
+#define SUBLANG_SPANISH_GUATEMALA 0x04
+#define SUBLANG_TAMAZIGHT_MOROCCO_TIFINAGH 0x04
+#define SORT_JAPANESE_RADICALSTROKE 0x4
+#define SORT_CHINESE_RADICALSTROKE 0x4
+#define VFF_BUFFTOOSMALL 0x0004
+#define SW_SHOW 5
+#define VK_XBUTTON1 0x05
+#define WM_SIZE 0x0005
+#define WMSZ_TOPRIGHT 5
+#define HTMENU 5
+#define CF_DIF 5
+#define IDIGNORE 5
+#define BN_DOUBLECLICKED 5
+#define LANG_CZECH 0x05
+#define SUBLANG_UI_CUSTOM_DEFAULT 0x05
+#define SUBLANG_ARABIC_ALGERIA 0x05
+#define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN 0x05
+#define SUBLANG_CHINESE_MACAU 0x05
+#define SUBLANG_ENGLISH_NZ 0x05
+#define SUBLANG_FRENCH_LUXEMBOURG 0x05
+#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
+#define SUBLANG_SAMI_LULE_SWEDEN 0x05
+#define SUBLANG_SPANISH_COSTA_RICA 0x05
+#define SW_MINIMIZE 6
+#define VK_XBUTTON2 0x06
+#define WM_ACTIVATE 0x0006
+#define WMSZ_BOTTOM 6
+#define HTHSCROLL 6
+#define CF_TIFF 6
+#define IDYES 6
+#define BN_SETFOCUS 6
+#define LANG_DANISH 0x06
+#define SUBLANG_ARABIC_MOROCCO 0x06
+#define SUBLANG_ENGLISH_EIRE 0x06
+#define SUBLANG_FRENCH_MONACO 0x06
+#define SUBLANG_SAMI_SOUTHERN_NORWAY 0x06
+#define SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN 0x06
+#define SUBLANG_SPANISH_PANAMA 0x06
+#define VER_PRODUCTMAJORVERSION 6
+#define SW_SHOWMINNOACTIVE 7
+#define WM_SETFOCUS 0x0007
+#define WMSZ_BOTTOMLEFT 7
+#define HTVSCROLL 7
+#define CF_OEMTEXT 7
+#define IDNO 7
+#define BN_KILLFOCUS 7
+#define LANG_GERMAN 0x07
+#define SUBLANG_ARABIC_TUNISIA 0x07
+#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
+#define SUBLANG_SAMI_SOUTHERN_SWEDEN 0x07
+#define SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC 0x07
+#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
+#define SW_SHOWNA 8
+#define VK_BACK 0x08
+#define WM_KILLFOCUS 0x0008
+#define WMSZ_BOTTOMRIGHT 8
+#define HTMINBUTTON 8
+#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008
+#define MK_CONTROL 0x0008
+#define CS_DBLCLKS 0x0008
+#define CF_DIB 8
+#define IDCLOSE 8
+#define BST_FOCUS 0x0008
+#define HDS_HIDDEN 0x0008
+#define TBSTYLE_DROPDOWN 0x0008
+#define TBS_BOTH 0x0008
+#define UDS_ALIGNLEFT 0x0008
+#define PBS_MARQUEE 0x08
+#define LWS_USEVISUALSTYLE 0x0008
+#define LVS_SHOWSELALWAYS 0x0008
+#define TVS_EDITLABELS 0x0008
+#define TVS_EX_NOINDENTSTATE 0x0008
+#define TCS_FLATBUTTONS 0x0008
+#define ACS_TIMER 0x0008
+#define MCS_NOTODAYCIRCLE 0x0008
+#define NFS_BUTTON 0x0008
+#define BCSIF_SIZE 0x0008
+#define BCSS_IMAGE 0x0008
+#define LANG_GREEK 0x08
+#define SUBLANG_ARABIC_OMAN 0x08
+#define SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC 0x08
+#define SUBLANG_ENGLISH_JAMAICA 0x08
+#define SUBLANG_SAMI_SKOLT_FINLAND 0x08
+#define SUBLANG_SPANISH_VENEZUELA 0x08
+#define SW_RESTORE 9
+#define VK_TAB 0x09
+#define HTMAXBUTTON 9
+#define CF_PALETTE 9
+#define IDHELP 9
+#define DTS_TIMEFORMAT 0x0009
+#define LANG_ENGLISH 0x09
+#define SUBLANG_ARABIC_YEMEN 0x09
+#define SUBLANG_ENGLISH_CARIBBEAN 0x09
+#define SUBLANG_SAMI_INARI_FINLAND 0x09
+#define SUBLANG_SERBIAN_SERBIA_LATIN 0x09
+#define SUBLANG_SPANISH_COLOMBIA 0x09
+#define SW_SHOWDEFAULT 10
+#define WM_ENABLE 0x000A
+#define HTLEFT 10
+#define CF_PENDATA 10
+#define IDTRYAGAIN 10
+#define HELP_CONTEXTMENU 0x000a
+#define LANG_SPANISH 0x0a
+#define SUBLANG_ARABIC_SYRIA 0x0a
+#define SUBLANG_ENGLISH_BELIZE 0x0a
+#define SUBLANG_SERBIAN_SERBIA_CYRILLIC 0x0a
+#define SUBLANG_SPANISH_PERU 0x0a
+#define SW_FORCEMINIMIZE 11
+#define SW_MAX 11
+#define WM_SETREDRAW 0x000B
+#define HTRIGHT 11
+#define CF_RIFF 11
+#define IDCONTINUE 11
+#define HELP_FINDER 0x000b
+#define LANG_FINNISH 0x0b
+#define SUBLANG_ARABIC_JORDAN 0x0b
+#define SUBLANG_ENGLISH_TRINIDAD 0x0b
+#define SUBLANG_SERBIAN_MONTENEGRO_LATIN 0x0b
+#define SUBLANG_SPANISH_ARGENTINA 0x0b
+#define VK_CLEAR 0x0C
+#define WM_SETTEXT 0x000C
+#define HTTOP 12
+#define CF_WAVE 12
+#define HELP_WM_HELP 0x000c
+#define DTS_SHORTDATECENTURYFORMAT 0x000C
+#define LANG_FRENCH 0x0c
+#define SUBLANG_ARABIC_LEBANON 0x0c
+#define SUBLANG_ENGLISH_ZIMBABWE 0x0c
+#define SUBLANG_SERBIAN_MONTENEGRO_CYRILLIC 0x0c
+#define SUBLANG_SPANISH_ECUADOR 0x0c
+#define VK_RETURN 0x0D
+#define WM_GETTEXT 0x000D
+#define HTTOPLEFT 13
+#define CF_UNICODETEXT 13
+#define HELP_SETPOPUP_POS 0x000d
+#define LANG_HEBREW 0x0d
+#define SUBLANG_ARABIC_KUWAIT 0x0d
+#define SUBLANG_ENGLISH_PHILIPPINES 0x0d
+#define SUBLANG_SPANISH_CHILE 0x0d
+#define WM_GETTEXTLENGTH 0x000E
+#define HTTOPRIGHT 14
+#define CF_ENHMETAFILE 14
+#define LANG_HUNGARIAN 0x0e
+#define SUBLANG_ARABIC_UAE 0x0e
+#define SUBLANG_SPANISH_URUGUAY 0x0e
+#define WM_PAINT 0x000F
+#define HTBOTTOM 15
+#define CF_HDROP 15
+#define LANG_ICELANDIC 0x0f
+#define SUBLANG_ARABIC_BAHRAIN 0x0f
+#define SUBLANG_SPANISH_PARAGUAY 0x0f
+#define MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID 16
+#define VK_SHIFT 0x10
+#define WM_CLOSE 0x0010
+#define HTBOTTOMLEFT 16
+#define WVR_ALIGNTOP 0x0010
+#define MK_MBUTTON 0x0010
+#define TME_NONCLIENT 0x00000010
+#define CF_LOCALE 16
+#define HELP_TCARD_DATA 0x0010
+#define TBSTYLE_AUTOSIZE 0x0010
+#define TTS_NOANIMATE 0x10
+#define TBS_NOTICKS 0x0010
+#define UDS_AUTOBUDDY 0x0010
+#define PBS_SMOOTHREVERSE 0x10
+#define LWS_USECUSTOMTEXT 0x0010
+#define LVS_SORTASCENDING 0x0010
+#define TVS_DISABLEDRAGDROP 0x0010
+#define TVS_EX_RICHTOOLTIP 0x0010
+#define TCS_FORCEICONLEFT 0x0010
+#define MCS_NOTODAY 0x0010
+#define DTS_APPCANPARSE 0x0010
+#define NFS_ALL 0x0010
+#define LANG_ITALIAN 0x10
+#define SUBLANG_ARABIC_QATAR 0x10
+#define SUBLANG_ENGLISH_INDIA 0x10
+#define SUBLANG_SPANISH_BOLIVIA 0x10
+#define VK_CONTROL 0x11
+#define WM_QUERYENDSESSION 0x0011
+#define HTBOTTOMRIGHT 17
+#define CF_DIBV5 17
+#define HELP_TCARD_OTHER_CALLER 0x0011
+#define LANG_JAPANESE 0x11
+#define SUBLANG_ENGLISH_MALAYSIA 0x11
+#define SUBLANG_SPANISH_EL_SALVADOR 0x11
+#define VK_MENU 0x12
+#define WM_QUIT 0x0012
+#define HTBORDER 18
+#define CF_MAX 18
+#define LANG_KOREAN 0x12
+#define SUBLANG_ENGLISH_SINGAPORE 0x12
+#define SUBLANG_SPANISH_HONDURAS 0x12
+#define VK_PAUSE 0x13
+#define WM_QUERYOPEN 0x0013
+#define HTOBJECT 19
+#define LANG_DUTCH 0x13
+#define SUBLANG_SPANISH_NICARAGUA 0x13
+#define VK_CAPITAL 0x14
+#define WM_ERASEBKGND 0x0014
+#define HTCLOSE 20
+#define LANG_NORWEGIAN 0x14
+#define SUBLANG_SPANISH_PUERTO_RICO 0x14
+#define _SAL_VERSION 20
+#define VK_KANA 0x15
+#define VK_HANGEUL 0x15
+#define VK_HANGUL 0x15
+#define WM_SYSCOLORCHANGE 0x0015
+#define HTHELP 21
+#define LANG_POLISH 0x15
+#define SUBLANG_SPANISH_US 0x15
+#define WM_ENDSESSION 0x0016
+#define LANG_PORTUGUESE 0x16
+#define VK_JUNJA 0x17
+#define LANG_ROMANSH 0x17
+#define RT_MANIFEST 24
+#define VK_FINAL 0x18
+#define WM_SHOWWINDOW 0x0018
+#define LANG_ROMANIAN 0x18
+#define VK_HANJA 0x19
+#define VK_KANJI 0x19
+#define LANG_RUSSIAN 0x19
+#define WM_WININICHANGE 0x001A
+#define LANG_BOSNIAN 0x1a
+#define LANG_CROATIAN 0x1a
+#define LANG_SERBIAN 0x1a
+#define VK_ESCAPE 0x1B
+#define WM_DEVMODECHANGE 0x001B
+#define LANG_SLOVAK 0x1b
+#define VK_CONVERT 0x1C
+#define WM_ACTIVATEAPP 0x001C
+#define LANG_ALBANIAN 0x1c
+#define VK_NONCONVERT 0x1D
+#define WM_FONTCHANGE 0x001D
+#define LANG_SWEDISH 0x1d
+#define VK_ACCEPT 0x1E
+#define WM_TIMECHANGE 0x001E
+#define LANG_THAI 0x1e
+#define VK_MODECHANGE 0x1F
+#define WM_CANCELMODE 0x001F
+#define LANG_TURKISH 0x1f
+#define VK_SPACE 0x20
+#define WM_SETCURSOR 0x0020
+#define SMTO_ERRORONEXIT 0x0020
+#define WVR_ALIGNLEFT 0x0020
+#define MK_XBUTTON1 0x0020
+#define CS_OWNDC 0x0020
+#define TBSTYLE_NOPREFIX 0x0020
+#define TTS_NOFADE 0x20
+#define TBS_ENABLESELRANGE 0x0020
+#define UDS_ARROWKEYS 0x0020
+#define LWS_RIGHT 0x0020
+#define LVS_SORTDESCENDING 0x0020
+#define TVS_SHOWSELALWAYS 0x0020
+#define TVS_EX_AUTOHSCROLL 0x0020
+#define TCS_FORCELABELLEFT 0x0020
+#define DTS_RIGHTALIGN 0x0020
+#define NFS_USEFONTASSOC 0x0020
+#define LANG_URDU 0x20
+#define VK_PRIOR 0x21
+#define WM_MOUSEACTIVATE 0x0021
+#define LANG_INDONESIAN 0x21
+#define VK_NEXT 0x22
+#define WM_CHILDACTIVATE 0x0022
+#define LANG_UKRAINIAN 0x22
+#define VK_END 0x23
+#define WM_QUEUESYNC 0x0023
+#define LANG_BELARUSIAN 0x23
+#define VK_HOME 0x24
+#define WM_GETMINMAXINFO 0x0024
+#define LANG_SLOVENIAN 0x24
+#define VK_LEFT 0x25
+#define LANG_ESTONIAN 0x25
+#define VK_UP 0x26
+#define WM_PAINTICON 0x0026
+#define LANG_LATVIAN 0x26
+#define VK_RIGHT 0x27
+#define WM_ICONERASEBKGND 0x0027
+#define LANG_LITHUANIAN 0x27
+#define VK_DOWN 0x28
+#define WM_NEXTDLGCTL 0x0028
+#define LANG_TAJIK 0x28
+#define VK_SELECT 0x29
+#define LANG_FARSI 0x29
+#define LANG_PERSIAN 0x29
+#define VK_PRINT 0x2A
+#define WM_SPOOLERSTATUS 0x002A
+#define LANG_VIETNAMESE 0x2a
+#define VK_EXECUTE 0x2B
+#define WM_DRAWITEM 0x002B
+#define LANG_ARMENIAN 0x2b
+#define VK_SNAPSHOT 0x2C
+#define WM_MEASUREITEM 0x002C
+#define LANG_AZERI 0x2c
+#define LANG_AZERBAIJANI 0x2c
+#define VK_INSERT 0x2D
+#define WM_DELETEITEM 0x002D
+#define LANG_BASQUE 0x2d
+#define VK_DELETE 0x2E
+#define WM_VKEYTOITEM 0x002E
+#define LANG_LOWER_SORBIAN 0x2e
+#define LANG_UPPER_SORBIAN 0x2e
+#define VK_HELP 0x2F
+#define WM_CHARTOITEM 0x002F
+#define LANG_MACEDONIAN 0x2f
+#define WM_SETFONT 0x0030
+#define WM_GETFONT 0x0031
+#define WM_SETHOTKEY 0x0032
+#define LANG_TSWANA 0x32
+#define WM_GETHOTKEY 0x0033
+#define LANG_XHOSA 0x34
+#define LANG_ZULU 0x35
+#define LANG_AFRIKAANS 0x36
+#define WM_QUERYDRAGICON 0x0037
+#define LANG_GEORGIAN 0x37
+#define LANG_FAEROESE 0x38
+#define WM_COMPAREITEM 0x0039
+#define LANG_HINDI 0x39
+#define LANG_MALTESE 0x3a
+#define LANG_SAMI 0x3b
+#define LANG_IRISH 0x3c
+#define WM_GETOBJECT 0x003D
+#define LANG_MALAY 0x3e
+#define LANG_KAZAK 0x3f
+#define WVR_ALIGNBOTTOM 0x0040
+#define MK_XBUTTON2 0x0040
+#define CS_CLASSDC 0x0040
+#define HDS_DRAGDROP 0x0040
+#define BTNS_SHOWTEXT 0x0040
+#define TTS_BALLOON 0x40
+#define TBS_FIXEDLENGTH 0x0040
+#define UDS_HORZ 0x0040
+#define LVS_SHAREIMAGELISTS 0x0040
+#define TVS_RTLREADING 0x0040
+#define TVS_EX_FADEINOUTEXPANDOS 0x0040
+#define TCS_HOTTRACK 0x0040
+#define MCS_NOTRAILINGDATES 0x0040
+#define LANG_KYRGYZ 0x40
+#define WM_COMPACTING 0x0041
+#define LANG_SWAHILI 0x41
+#define LANG_TURKMEN 0x42
+#define LANG_UZBEK 0x43
+#define WM_COMMNOTIFY 0x0044
+#define LANG_TATAR 0x44
+#define LANG_BANGLA 0x45
+#define LANG_BENGALI 0x45
+#define WM_WINDOWPOSCHANGING 0x0046
+#define LANG_PUNJABI 0x46
+#define WM_WINDOWPOSCHANGED 0x0047
+#define LANG_GUJARATI 0x47
+#define WM_POWER 0x0048
+#define LANG_ODIA 0x48
+#define LANG_ORIYA 0x48
+#define LANG_TAMIL 0x49
+#define WM_COPYDATA 0x004A
+#define LANG_TELUGU 0x4a
+#define WM_CANCELJOURNAL 0x004B
+#define LANG_KANNADA 0x4b
+#define LANG_MALAYALAM 0x4c
+#define LANG_ASSAMESE 0x4d
+#define WM_NOTIFY 0x004E
+#define LANG_MARATHI 0x4e
+#define LANG_SANSKRIT 0x4f
+#define WM_INPUTLANGCHANGEREQUEST 0x0050
+#define LANG_MONGOLIAN 0x50
+#define WM_INPUTLANGCHANGE 0x0051
+#define LANG_TIBETAN 0x51
+#define WM_TCARD 0x0052
+#define LANG_WELSH 0x52
+#define WM_HELP 0x0053
+#define LANG_KHMER 0x53
+#define WM_USERCHANGED 0x0054
+#define LANG_LAO 0x54
+#define WM_NOTIFYFORMAT 0x0055
+#define LANG_GALICIAN 0x56
+#define LANG_KONKANI 0x57
+#define LANG_MANIPURI 0x58
+#define LANG_SINDHI 0x59
+#define LANG_SYRIAC 0x5a
+#define VK_LWIN 0x5B
+#define LANG_SINHALESE 0x5b
+#define VK_RWIN 0x5C
+#define LANG_CHEROKEE 0x5c
+#define VK_APPS 0x5D
+#define LANG_INUKTITUT 0x5d
+#define LANG_AMHARIC 0x5e
+#define VK_SLEEP 0x5F
+#define LANG_TAMAZIGHT 0x5f
+#define VK_NUMPAD0 0x60
+#define LANG_KASHMIRI 0x60
+#define VK_NUMPAD1 0x61
+#define LANG_NEPALI 0x61
+#define VK_NUMPAD2 0x62
+#define LANG_FRISIAN 0x62
+#define VK_NUMPAD3 0x63
+#define LANG_PASHTO 0x63
+#define VK_NUMPAD4 0x64
+#define LANG_FILIPINO 0x64
+#define VS_USER_DEFINED 100
+#define VK_NUMPAD5 0x65
+#define LANG_DIVEHI 0x65
+#define VK_NUMPAD6 0x66
+#define VK_NUMPAD7 0x67
+#define LANG_FULAH 0x67
+#define LANG_PULAR 0x67
+#define VK_NUMPAD8 0x68
+#define LANG_HAUSA 0x68
+#define VK_NUMPAD9 0x69
+#define VK_MULTIPLY 0x6A
+#define LANG_YORUBA 0x6a
+#define VK_ADD 0x6B
+#define LANG_QUECHUA 0x6b
+#define VK_SEPARATOR 0x6C
+#define LANG_SOTHO 0x6c
+#define VK_SUBTRACT 0x6D
+#define LANG_BASHKIR 0x6d
+#define VK_DECIMAL 0x6E
+#define LANG_LUXEMBOURGISH 0x6e
+#define VK_DIVIDE 0x6F
+#define LANG_GREENLANDIC 0x6f
+#define VK_F1 0x70
+#define LANG_IGBO 0x70
+#define VK_F2 0x71
+#define VK_F3 0x72
+#define VK_F4 0x73
+#define LANG_TIGRIGNA 0x73
+#define LANG_TIGRINYA 0x73
+#define VK_F5 0x74
+#define VK_F6 0x75
+#define LANG_HAWAIIAN 0x75
+#define VK_F7 0x76
+#define VK_F8 0x77
+#define VK_F9 0x78
+#define WHEEL_DELTA 120
+#define LANG_YI 0x78
+#define VK_F10 0x79
+#define VK_F11 0x7A
+#define LANG_MAPUDUNGUN 0x7a
+#define VK_F12 0x7B
+#define WM_CONTEXTMENU 0x007B
+#define VK_F13 0x7C
+#define WM_STYLECHANGING 0x007C
+#define LANG_MOHAWK 0x7c
+#define VK_F14 0x7D
+#define WM_STYLECHANGED 0x007D
+#define VK_F15 0x7E
+#define WM_DISPLAYCHANGE 0x007E
+#define LANG_BRETON 0x7e
+#define VK_F16 0x7F
+#define WM_GETICON 0x007F
+#define LANG_INVARIANT 0x7f
+#define VK_F17 0x80
+#define WM_SETICON 0x0080
+#define WVR_ALIGNRIGHT 0x0080
+#define CS_PARENTDC 0x0080
+#define CF_OWNERDISPLAY 0x0080
+#define HDS_FULLDRAG 0x0080
+#define BTNS_WHOLEDROPDOWN 0x0080
+#define TTS_CLOSE 0x80
+#define TBS_NOTHUMB 0x0080
+#define UDS_NOTHOUSANDS 0x0080
+#define LVS_NOLABELWRAP 0x0080
+#define TVS_NOTOOLTIPS 0x0080
+#define TVS_EX_PARTIALCHECKBOXES 0x0080
+#define TCS_VERTICAL 0x0080
+#define MCS_SHORTDAYSOFWEEK 0x0080
+#define LANG_UIGHUR 0x80
+#define VK_F18 0x81
+#define WM_NCCREATE 0x0081
+#define CF_DSPTEXT 0x0081
+#define LANG_MAORI 0x81
+#define VK_F19 0x82
+#define WM_NCDESTROY 0x0082
+#define CF_DSPBITMAP 0x0082
+#define LANG_OCCITAN 0x82
+#define VK_F20 0x83
+#define WM_NCCALCSIZE 0x0083
+#define CF_DSPMETAFILEPICT 0x0083
+#define LANG_CORSICAN 0x83
+#define VK_F21 0x84
+#define WM_NCHITTEST 0x0084
+#define LANG_ALSATIAN 0x84
+#define VK_F22 0x85
+#define WM_NCPAINT 0x0085
+#define LANG_SAKHA 0x85
+#define LANG_YAKUT 0x85
+#define VK_F23 0x86
+#define WM_NCACTIVATE 0x0086
+#define LANG_KICHE 0x86
+#define VK_F24 0x87
+#define WM_GETDLGCODE 0x0087
+#define LANG_KINYARWANDA 0x87
+#define WM_SYNCPAINT 0x0088
+#define LANG_WOLOF 0x88
+#define LANG_DARI 0x8c
+#define CF_DSPENHMETAFILE 0x008E
+#define VK_NUMLOCK 0x90
+#define VK_SCROLL 0x91
+#define LANG_SCOTTISH_GAELIC 0x91
+#define VK_OEM_NEC_EQUAL 0x92
+#define VK_OEM_FJ_JISHO 0x92
+#define LANG_CENTRAL_KURDISH 0x92
+#define VK_OEM_FJ_MASSHOU 0x93
+#define VK_OEM_FJ_TOUROKU 0x94
+#define VK_OEM_FJ_LOYA 0x95
+#define VK_OEM_FJ_ROYA 0x96
+#define VK_LSHIFT 0xA0
+#define WM_NCMOUSEMOVE 0x00A0
+#define VK_RSHIFT 0xA1
+#define WM_NCLBUTTONDOWN 0x00A1
+#define VK_LCONTROL 0xA2
+#define WM_NCLBUTTONUP 0x00A2
+#define VK_RCONTROL 0xA3
+#define WM_NCLBUTTONDBLCLK 0x00A3
+#define VK_LMENU 0xA4
+#define WM_NCRBUTTONDOWN 0x00A4
+#define VK_RMENU 0xA5
+#define WM_NCRBUTTONUP 0x00A5
+#define VK_BROWSER_BACK 0xA6
+#define WM_NCRBUTTONDBLCLK 0x00A6
+#define VK_BROWSER_FORWARD 0xA7
+#define WM_NCMBUTTONDOWN 0x00A7
+#define VK_BROWSER_REFRESH 0xA8
+#define WM_NCMBUTTONUP 0x00A8
+#define VK_BROWSER_STOP 0xA9
+#define WM_NCMBUTTONDBLCLK 0x00A9
+#define VK_BROWSER_SEARCH 0xAA
+#define VK_BROWSER_FAVORITES 0xAB
+#define WM_NCXBUTTONDOWN 0x00AB
+#define VK_BROWSER_HOME 0xAC
+#define WM_NCXBUTTONUP 0x00AC
+#define VK_VOLUME_MUTE 0xAD
+#define WM_NCXBUTTONDBLCLK 0x00AD
+#define VK_VOLUME_DOWN 0xAE
+#define VK_VOLUME_UP 0xAF
+#define VK_MEDIA_NEXT_TRACK 0xB0
+#define EM_GETSEL 0x00B0
+#define VK_MEDIA_PREV_TRACK 0xB1
+#define EM_SETSEL 0x00B1
+#define VK_MEDIA_STOP 0xB2
+#define EM_GETRECT 0x00B2
+#define VK_MEDIA_PLAY_PAUSE 0xB3
+#define EM_SETRECT 0x00B3
+#define VK_LAUNCH_MAIL 0xB4
+#define EM_SETRECTNP 0x00B4
+#define VK_LAUNCH_MEDIA_SELECT 0xB5
+#define EM_SCROLL 0x00B5
+#define VK_LAUNCH_APP1 0xB6
+#define EM_LINESCROLL 0x00B6
+#define VK_LAUNCH_APP2 0xB7
+#define EM_SCROLLCARET 0x00B7
+#define EM_GETMODIFY 0x00B8
+#define EM_SETMODIFY 0x00B9
+#define VK_OEM_1 0xBA
+#define EM_GETLINECOUNT 0x00BA
+#define VK_OEM_PLUS 0xBB
+#define EM_LINEINDEX 0x00BB
+#define VK_OEM_COMMA 0xBC
+#define EM_SETHANDLE 0x00BC
+#define VK_OEM_MINUS 0xBD
+#define EM_GETHANDLE 0x00BD
+#define VK_OEM_PERIOD 0xBE
+#define EM_GETTHUMB 0x00BE
+#define VK_OEM_2 0xBF
+#define VK_OEM_3 0xC0
+#define EM_LINELENGTH 0x00C1
+#define EM_REPLACESEL 0x00C2
+#define EM_GETLINE 0x00C4
+#define EM_LIMITTEXT 0x00C5
+#define EM_CANUNDO 0x00C6
+#define EM_UNDO 0x00C7
+#define EM_FMTLINES 0x00C8
+#define EM_LINEFROMCHAR 0x00C9
+#define EM_SETTABSTOPS 0x00CB
+#define EM_SETPASSWORDCHAR 0x00CC
+#define EM_EMPTYUNDOBUFFER 0x00CD
+#define EM_GETFIRSTVISIBLELINE 0x00CE
+#define EM_SETREADONLY 0x00CF
+#define EM_SETWORDBREAKPROC 0x00D0
+#define EM_GETWORDBREAKPROC 0x00D1
+#define EM_GETPASSWORDCHAR 0x00D2
+#define EM_SETMARGINS 0x00D3
+#define EM_GETMARGINS 0x00D4
+#define EM_GETLIMITTEXT 0x00D5
+#define EM_POSFROMCHAR 0x00D6
+#define EM_CHARFROMPOS 0x00D7
+#define EM_SETIMESTATUS 0x00D8
+#define EM_GETIMESTATUS 0x00D9
+#define VK_OEM_4 0xDB
+#define VK_OEM_5 0xDC
+#define VK_OEM_6 0xDD
+#define VK_OEM_7 0xDE
+#define VK_OEM_8 0xDF
+#define VK_OEM_AX 0xE1
+#define VK_OEM_102 0xE2
+#define VK_ICO_HELP 0xE3
+#define VK_ICO_00 0xE4
+#define VK_PROCESSKEY 0xE5
+#define VK_ICO_CLEAR 0xE6
+#define VK_PACKET 0xE7
+#define VK_OEM_RESET 0xE9
+#define VK_OEM_JUMP 0xEA
+#define VK_OEM_PA1 0xEB
+#define VK_OEM_PA2 0xEC
+#define VK_OEM_PA3 0xED
+#define VK_OEM_WSCTRL 0xEE
+#define VK_OEM_CUSEL 0xEF
+#define VK_OEM_ATTN 0xF0
+#define BM_GETCHECK 0x00F0
+#define VK_OEM_FINISH 0xF1
+#define BM_SETCHECK 0x00F1
+#define VK_OEM_COPY 0xF2
+#define BM_GETSTATE 0x00F2
+#define VK_OEM_AUTO 0xF3
+#define BM_SETSTATE 0x00F3
+#define VK_OEM_ENLW 0xF4
+#define BM_SETSTYLE 0x00F4
+#define VK_OEM_BACKTAB 0xF5
+#define BM_CLICK 0x00F5
+#define VK_ATTN 0xF6
+#define BM_GETIMAGE 0x00F6
+#define VK_CRSEL 0xF7
+#define BM_SETIMAGE 0x00F7
+#define VK_EXSEL 0xF8
+#define BM_SETDONTCLICK 0x00F8
+#define VK_EREOF 0xF9
+#define VK_PLAY 0xFA
+#define VK_ZOOM 0xFB
+#define VK_NONAME 0xFC
+#define VK_PA1 0xFD
+#define VK_OEM_CLEAR 0xFE
+#define WM_INPUT_DEVICE_CHANGE 0x00FE
+#define SUBVERSION_MASK 0x000000FF
+#define WM_INPUT 0x00FF
+#define WM_KEYFIRST 0x0100
+#define WM_KEYDOWN 0x0100
+#define WVR_HREDRAW 0x0100
+#define HDS_FILTERBAR 0x0100
+#define TBSTYLE_TOOLTIPS 0x0100
+#define RBS_TOOLTIPS 0x00000100
+#define TTS_USEVISUALSTYLE 0x100
+#define SBARS_SIZEGRIP 0x0100
+#define TBS_TOOLTIPS 0x0100
+#define UDS_HOTTRACK 0x0100
+#define LVS_AUTOARRANGE 0x0100
+#define TVS_CHECKBOXES 0x0100
+#define TVS_EX_EXCLUSIONCHECKBOXES 0x0100
+#define TCS_BUTTONS 0x0100
+#define MCS_NOSELCHANGEONNAV 0x0100
+#define WM_KEYUP 0x0101
+#define WM_CHAR 0x0102
+#define WM_DEADCHAR 0x0103
+#define WM_SYSKEYDOWN 0x0104
+#define WM_SYSKEYUP 0x0105
+#define WM_SYSCHAR 0x0106
+#define WM_SYSDEADCHAR 0x0107
+#define WM_UNICHAR 0x0109
+#define WM_KEYLAST 0x0109
+#define WM_IME_STARTCOMPOSITION 0x010D
+#define WM_IME_ENDCOMPOSITION 0x010E
+#define WM_IME_COMPOSITION 0x010F
+#define WM_IME_KEYLAST 0x010F
+#define WM_INITDIALOG 0x0110
+#define WM_COMMAND 0x0111
+#define WM_SYSCOMMAND 0x0112
+#define WM_TIMER 0x0113
+#define WM_HSCROLL 0x0114
+#define WM_VSCROLL 0x0115
+#define WM_INITMENU 0x0116
+#define WM_INITMENUPOPUP 0x0117
+#define WM_GESTURE 0x0119
+#define WM_GESTURENOTIFY 0x011A
+#define WM_MENUSELECT 0x011F
+#define WM_MENUCHAR 0x0120
+#define WM_ENTERIDLE 0x0121
+#define WM_MENURBUTTONUP 0x0122
+#define WM_MENUDRAG 0x0123
+#define WM_MENUGETOBJECT 0x0124
+#define WM_UNINITMENUPOPUP 0x0125
+#define WM_MENUCOMMAND 0x0126
+#define WM_CHANGEUISTATE 0x0127
+#define WM_UPDATEUISTATE 0x0128
+#define WM_QUERYUISTATE 0x0129
+#define WM_CTLCOLORMSGBOX 0x0132
+#define WM_CTLCOLOREDIT 0x0133
+#define WM_CTLCOLORLISTBOX 0x0134
+#define WM_CTLCOLORBTN 0x0135
+#define WM_CTLCOLORDLG 0x0136
+#define WM_CTLCOLORSCROLLBAR 0x0137
+#define WM_CTLCOLORSTATIC 0x0138
+#define MN_GETHMENU 0x01E1
+#define _WIN32_IE_IE20 0x0200
+#define WM_MOUSEFIRST 0x0200
+#define WM_MOUSEMOVE 0x0200
+#define WVR_VREDRAW 0x0200
+#define CS_NOCLOSE 0x0200
+#define CF_PRIVATEFIRST 0x0200
+#define HDS_FLAT 0x0200
+#define TBSTYLE_WRAPABLE 0x0200
+#define RBS_VARHEIGHT 0x00000200
+#define TBS_REVERSED 0x0200
+#define LVS_EDITLABELS 0x0200
+#define TVS_TRACKSELECT 0x0200
+#define TVS_EX_DIMMEDCHECKBOXES 0x0200
+#define TCS_MULTILINE 0x0200
+#define WM_LBUTTONDOWN 0x0201
+#define WM_LBUTTONUP 0x0202
+#define WM_LBUTTONDBLCLK 0x0203
+#define WM_RBUTTONDOWN 0x0204
+#define WM_RBUTTONUP 0x0205
+#define WM_RBUTTONDBLCLK 0x0206
+#define WM_MBUTTONDOWN 0x0207
+#define WM_MBUTTONUP 0x0208
+#define WM_MBUTTONDBLCLK 0x0209
+#define WM_MOUSEWHEEL 0x020A
+#define WM_XBUTTONDOWN 0x020B
+#define WM_XBUTTONUP 0x020C
+#define WM_XBUTTONDBLCLK 0x020D
+#define WM_MOUSEHWHEEL 0x020E
+#define WM_MOUSELAST 0x020E
+#define WM_PARENTNOTIFY 0x0210
+#define WM_ENTERMENULOOP 0x0211
+#define WM_EXITMENULOOP 0x0212
+#define WM_NEXTMENU 0x0213
+#define WM_SIZING 0x0214
+#define WM_CAPTURECHANGED 0x0215
+#define WM_MOVING 0x0216
+#define WM_POWERBROADCAST 0x0218
+#define WM_DEVICECHANGE 0x0219
+#define WM_MDICREATE 0x0220
+#define WM_MDIDESTROY 0x0221
+#define WM_MDIACTIVATE 0x0222
+#define WM_MDIRESTORE 0x0223
+#define WM_MDINEXT 0x0224
+#define WM_MDIMAXIMIZE 0x0225
+#define WM_MDITILE 0x0226
+#define WM_MDICASCADE 0x0227
+#define WM_MDIICONARRANGE 0x0228
+#define WM_MDIGETACTIVE 0x0229
+#define WM_MDISETMENU 0x0230
+#define WM_ENTERSIZEMOVE 0x0231
+#define WM_EXITSIZEMOVE 0x0232
+#define WM_DROPFILES 0x0233
+#define WM_MDIREFRESHMENU 0x0234
+#define WM_POINTERDEVICECHANGE 0x238
+#define WM_POINTERDEVICEINRANGE 0x239
+#define WM_POINTERDEVICEOUTOFRANGE 0x23A
+#define WM_TOUCH 0x0240
+#define WM_NCPOINTERUPDATE 0x0241
+#define WM_NCPOINTERDOWN 0x0242
+#define WM_NCPOINTERUP 0x0243
+#define WM_POINTERUPDATE 0x0245
+#define WM_POINTERDOWN 0x0246
+#define WM_POINTERUP 0x0247
+#define WM_POINTERENTER 0x0249
+#define WM_POINTERLEAVE 0x024A
+#define WM_POINTERACTIVATE 0x024B
+#define WM_POINTERCAPTURECHANGED 0x024C
+#define WM_TOUCHHITTESTING 0x024D
+#define WM_POINTERWHEEL 0x024E
+#define WM_POINTERHWHEEL 0x024F
+#define WM_IME_SETCONTEXT 0x0281
+#define WM_IME_NOTIFY 0x0282
+#define WM_IME_CONTROL 0x0283
+#define WM_IME_COMPOSITIONFULL 0x0284
+#define WM_IME_SELECT 0x0285
+#define WM_IME_CHAR 0x0286
+#define WM_IME_REQUEST 0x0288
+#define WM_IME_KEYDOWN 0x0290
+#define WM_IME_KEYUP 0x0291
+#define WM_NCMOUSEHOVER 0x02A0
+#define WM_MOUSEHOVER 0x02A1
+#define WM_NCMOUSELEAVE 0x02A2
+#define WM_MOUSELEAVE 0x02A3
+#define WM_WTSSESSION_CHANGE 0x02B1
+#define WM_TABLET_FIRST 0x02c0
+#define WM_TABLET_LAST 0x02df
+#define CF_PRIVATELAST 0x02FF
+#define _WIN32_IE_IE30 0x0300
+#define WM_CUT 0x0300
+#define CF_GDIOBJFIRST 0x0300
+#define WM_COPY 0x0301
+#define _WIN32_IE_IE302 0x0302
+#define WM_PASTE 0x0302
+#define WM_CLEAR 0x0303
+#define WM_UNDO 0x0304
+#define WM_RENDERFORMAT 0x0305
+#define WM_RENDERALLFORMATS 0x0306
+#define WM_DESTROYCLIPBOARD 0x0307
+#define WM_DRAWCLIPBOARD 0x0308
+#define WM_PAINTCLIPBOARD 0x0309
+#define WM_VSCROLLCLIPBOARD 0x030A
+#define WM_SIZECLIPBOARD 0x030B
+#define WM_ASKCBFORMATNAME 0x030C
+#define WM_CHANGECBCHAIN 0x030D
+#define WM_HSCROLLCLIPBOARD 0x030E
+#define WM_QUERYNEWPALETTE 0x030F
+#define WM_PALETTEISCHANGING 0x0310
+#define WM_PALETTECHANGED 0x0311
+#define WM_HOTKEY 0x0312
+#define WM_PRINT 0x0317
+#define WM_PRINTCLIENT 0x0318
+#define WM_APPCOMMAND 0x0319
+#define WM_THEMECHANGED 0x031A
+#define WM_CLIPBOARDUPDATE 0x031D
+#define WM_DWMCOMPOSITIONCHANGED 0x031E
+#define WM_DWMNCRENDERINGCHANGED 0x031F
+#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
+#define WM_DWMWINDOWMAXIMIZEDCHANGE 0x0321
+#define WM_DWMSENDICONICTHUMBNAIL 0x0323
+#define WM_DWMSENDICONICLIVEPREVIEWBITMAP 0x0326
+#define WM_GETTITLEBARINFOEX 0x033F
+#define WM_HANDHELDFIRST 0x0358
+#define WM_HANDHELDLAST 0x035F
+#define WM_AFXFIRST 0x0360
+#define WM_AFXLAST 0x037F
+#define WM_PENWINFIRST 0x0380
+#define WM_PENWINLAST 0x038F
+#define WM_DDE_FIRST 0x03E0
+#define CF_GDIOBJLAST 0x03FF
+#define _WIN32_WINNT_NT4 0x0400
+#define _WIN32_IE_IE40 0x0400
+#define WM_USER 0x0400
+#define WVR_VALIDRECTS 0x0400
+#define HDS_CHECKBOXES 0x0400
+#define TBSTYLE_ALTDRAG 0x0400
+#define RBS_BANDBORDERS 0x00000400
+#define TBS_DOWNISLEFT 0x0400
+#define LVS_OWNERDRAWFIXED 0x0400
+#define TVS_SINGLEEXPAND 0x0400
+#define TVS_EX_DRAWIMAGEASYNC 0x0400
+#define TCS_FIXEDWIDTH 0x0400
+#define ctlFirst 0x0400
+#define psh1 0x0400
+#define _WIN32_IE_IE401 0x0401
+#define psh2 0x0401
+#define psh3 0x0402
+#define psh4 0x0403
+#define psh5 0x0404
+#define psh6 0x0405
+#define psh7 0x0406
+#define psh8 0x0407
+#define psh9 0x0408
+#define psh10 0x0409
+#define psh11 0x040a
+#define psh12 0x040b
+#define psh13 0x040c
+#define psh14 0x040d
+#define psh15 0x040e
+#define psh16 0x040f
+#define _WIN32_WINDOWS 0x0410
+#define chx1 0x0410
+#define chx2 0x0411
+#define chx3 0x0412
+#define chx4 0x0413
+#define chx5 0x0414
+#define chx6 0x0415
+#define chx7 0x0416
+#define chx8 0x0417
+#define chx9 0x0418
+#define chx10 0x0419
+#define chx11 0x041a
+#define chx12 0x041b
+#define chx13 0x041c
+#define chx14 0x041d
+#define chx15 0x041e
+#define chx16 0x041f
+#define rad1 0x0420
+#define rad2 0x0421
+#define rad3 0x0422
+#define rad4 0x0423
+#define rad5 0x0424
+#define rad6 0x0425
+#define rad7 0x0426
+#define rad8 0x0427
+#define rad9 0x0428
+#define rad10 0x0429
+#define rad11 0x042a
+#define rad12 0x042b
+#define rad13 0x042c
+#define rad14 0x042d
+#define rad15 0x042e
+#define rad16 0x042f
+#define grp1 0x0430
+#define grp2 0x0431
+#define grp3 0x0432
+#define grp4 0x0433
+#define frm1 0x0434
+#define frm2 0x0435
+#define frm3 0x0436
+#define frm4 0x0437
+#define rct1 0x0438
+#define rct2 0x0439
+#define rct3 0x043a
+#define rct4 0x043b
+#define ico1 0x043c
+#define ico2 0x043d
+#define ico3 0x043e
+#define ico4 0x043f
+#define stc1 0x0440
+#define stc2 0x0441
+#define stc3 0x0442
+#define stc4 0x0443
+#define stc5 0x0444
+#define stc6 0x0445
+#define stc7 0x0446
+#define stc8 0x0447
+#define stc9 0x0448
+#define stc10 0x0449
+#define stc11 0x044a
+#define stc12 0x044b
+#define stc13 0x044c
+#define stc14 0x044d
+#define stc15 0x044e
+#define stc16 0x044f
+#define stc17 0x0450
+#define stc18 0x0451
+#define stc19 0x0452
+#define stc20 0x0453
+#define stc21 0x0454
+#define stc22 0x0455
+#define stc23 0x0456
+#define stc24 0x0457
+#define stc25 0x0458
+#define stc26 0x0459
+#define stc27 0x045a
+#define stc28 0x045b
+#define stc29 0x045c
+#define stc30 0x045d
+#define stc31 0x045e
+#define stc32 0x045f
+#define lst1 0x0460
+#define lst2 0x0461
+#define lst3 0x0462
+#define lst4 0x0463
+#define lst5 0x0464
+#define lst6 0x0465
+#define lst7 0x0466
+#define lst8 0x0467
+#define lst9 0x0468
+#define lst10 0x0469
+#define lst11 0x046a
+#define lst12 0x046b
+#define lst13 0x046c
+#define lst14 0x046d
+#define lst15 0x046e
+#define lst16 0x046f
+#define cmb1 0x0470
+#define cmb2 0x0471
+#define cmb3 0x0472
+#define cmb4 0x0473
+#define cmb5 0x0474
+#define cmb6 0x0475
+#define cmb7 0x0476
+#define cmb8 0x0477
+#define cmb9 0x0478
+#define cmb10 0x0479
+#define cmb11 0x047a
+#define cmb12 0x047b
+#define cmb13 0x047c
+#define cmb14 0x047d
+#define cmb15 0x047e
+#define cmb16 0x047f
+#define edt1 0x0480
+#define edt2 0x0481
+#define edt3 0x0482
+#define edt4 0x0483
+#define edt5 0x0484
+#define edt6 0x0485
+#define edt7 0x0486
+#define edt8 0x0487
+#define edt9 0x0488
+#define edt10 0x0489
+#define edt11 0x048a
+#define edt12 0x048b
+#define edt13 0x048c
+#define edt14 0x048d
+#define edt15 0x048e
+#define edt16 0x048f
+#define scr1 0x0490
+#define scr2 0x0491
+#define scr3 0x0492
+#define scr4 0x0493
+#define scr5 0x0494
+#define scr6 0x0495
+#define scr7 0x0496
+#define scr8 0x0497
+#define ctl1 0x04A0
+#define ctlLast 0x04ff
+#define _WIN32_WINNT_WIN2K 0x0500
+#define _WIN32_IE_IE50 0x0500
+#define _WIN32_WINNT_WINXP 0x0501
+#define _WIN32_IE_IE501 0x0501
+#define _WIN32_WINNT_WS03 0x0502
+#define _WIN32_IE_IE55 0x0550
+#define _WIN32_WINNT_WIN6 0x0600
+#define _WIN32_WINNT_VISTA 0x0600
+#define _WIN32_WINNT_WS08 0x0600
+#define _WIN32_WINNT_LONGHORN 0x0600
+#define _WIN32_IE_IE60 0x0600
+#define FILEOPENORD 1536
+#define _WIN32_WINNT_WIN7 0x0601
+#define _WIN32_IE_IE60SP1 0x0601
+#define MULTIFILEOPENORD 1537
+#define _WIN32_WINNT_WIN8 0x0602
+#define _WIN32_IE_WS03 0x0602
+#define _WIN32_WINNT 0x0602
+#define PRINTDLGORD 1538
+#define VER_PRODUCTVERSION_W 0x0602
+#define _WIN32_IE_IE60SP2 0x0603
+#define PRNSETUPDLGORD 1539
+#define FINDDLGORD 1540
+#define REPLACEDLGORD 1541
+#define FONTDLGORD 1542
+#define FORMATDLGORD31 1543
+#define FORMATDLGORD30 1544
+#define RUNDLGORD 1545
+#define PAGESETUPDLGORD 1546
+#define NEWFILEOPENORD 1547
+#define PRINTDLGEXORD 1549
+#define PAGESETUPDLGORDMOTIF 1550
+#define COLORMGMTDLGORD 1551
+#define NEWFILEOPENV2ORD 1552
+#define NEWFILEOPENV3ORD 1553
+#define NEWFORMATDLGWITHLINK 1591
+#define IDC_MANAGE_LINK 1592
+#define _WIN32_IE_IE70 0x0700
+#define _WIN32_IE_IE80 0x0800
+#define CS_SAVEBITS 0x0800
+#define HDS_NOSIZING 0x0800
+#define TBSTYLE_FLAT 0x0800
+#define RBS_FIXEDORDER 0x00000800
+#define SBARS_TOOLTIPS 0x0800
+#define SBT_TOOLTIPS 0x0800
+#define TBS_NOTIFYBEFOREMOVE 0x0800
+#define LVS_ALIGNLEFT 0x0800
+#define TVS_INFOTIP 0x0800
+#define TCS_RAGGEDRIGHT 0x0800
+#define _WIN32_IE_IE90 0x0900
+#define _WIN32_IE_IE100 0x0A00
+#define LVS_ALIGNMASK 0x0c00
+#define CS_BYTEALIGNCLIENT 0x1000
+#define HDS_OVERFLOW 0x1000
+#define TBSTYLE_LIST 0x1000
+#define RBS_REGISTERDROP 0x00001000
+#define TBS_TRANSPARENTBKGND 0x1000
+#define LVS_OWNERDATA 0x1000
+#define TVS_FULLROWSELECT 0x1000
+#define TCS_FOCUSONBUTTONDOWN 0x1000
+#define CS_BYTEALIGNWINDOW 0x2000
+#define TBSTYLE_CUSTOMERASE 0x2000
+#define RBS_AUTOSIZE 0x00002000
+#define LVS_NOSCROLL 0x2000
+#define TVS_NOSCROLL 0x2000
+#define TCS_OWNERDRAWFIXED 0x2000
+#define VER_PRODUCTBUILD 9200
+#define CS_GLOBALCLASS 0x4000
+#define TBSTYLE_REGISTERDROP 0x4000
+#define RBS_VERTICALGRIPPER 0x00004000
+#define LVS_NOCOLUMNHEADER 0x4000
+#define TVS_NONEVENHEIGHT 0x4000
+#define TCS_TOOLTIPS 0x4000
+#define VER_PRODUCTBUILD_QFE 20557
+#define VER_PACKAGEBUILD_QFE 20557
+#define IDH_NO_HELP 28440
+#define IDH_MISSING_CONTEXT 28441
+#define IDH_GENERIC_HELP_BUTTON 28442
+#define IDH_OK 28443
+#define IDH_CANCEL 28444
+#define IDH_HELP 28445
+#define LANG_BOSNIAN_NEUTRAL 0x781a
+#define LANG_CHINESE_TRADITIONAL 0x7c04
+#define LANG_SERBIAN_NEUTRAL 0x7c1a
+#define IDTIMEOUT 32000
+#define OCR_NORMAL 32512
+#define OIC_SAMPLE 32512
+#define IDI_APPLICATION 32512
+#define OCR_IBEAM 32513
+#define OIC_HAND 32513
+#define IDI_HAND 32513
+#define OCR_WAIT 32514
+#define OIC_QUES 32514
+#define IDI_QUESTION 32514
+#define OCR_CROSS 32515
+#define OIC_BANG 32515
+#define IDI_EXCLAMATION 32515
+#define OCR_UP 32516
+#define OIC_NOTE 32516
+#define IDI_ASTERISK 32516
+#define OIC_WINLOGO 32517
+#define IDI_WINLOGO 32517
+#define OIC_SHIELD 32518
+#define IDI_SHIELD 32518
+#define OCR_SIZE 32640
+#define OCR_ICON 32641
+#define OCR_SIZENWSE 32642
+#define OCR_SIZENESW 32643
+#define OCR_SIZEWE 32644
+#define OCR_SIZENS 32645
+#define OCR_SIZEALL 32646
+#define OCR_ICOCUR 32647
+#define OCR_NO 32648
+#define OCR_HAND 32649
+#define OCR_APPSTARTING 32650
+#define OBM_LFARROWI 32734
+#define OBM_RGARROWI 32735
+#define OBM_DNARROWI 32736
+#define OBM_UPARROWI 32737
+#define OBM_COMBO 32738
+#define OBM_MNARROW 32739
+#define OBM_LFARROWD 32740
+#define OBM_RGARROWD 32741
+#define OBM_DNARROWD 32742
+#define OBM_UPARROWD 32743
+#define OBM_RESTORED 32744
+#define OBM_ZOOMD 32745
+#define OBM_REDUCED 32746
+#define OBM_RESTORE 32747
+#define OBM_ZOOM 32748
+#define OBM_REDUCE 32749
+#define OBM_LFARROW 32750
+#define OBM_RGARROW 32751
+#define OBM_DNARROW 32752
+#define OBM_UPARROW 32753
+#define OBM_CLOSE 32754
+#define OBM_OLD_RESTORE 32755
+#define OBM_OLD_ZOOM 32756
+#define OBM_OLD_REDUCE 32757
+#define OBM_BTNCORNERS 32758
+#define OBM_CHECKBOXES 32759
+#define OBM_CHECK 32760
+#define OBM_BTSIZE 32761
+#define OBM_OLD_LFARROW 32762
+#define OBM_OLD_RGARROW 32763
+#define OBM_OLD_DNARROW 32764
+#define OBM_OLD_UPARROW 32765
+#define OBM_SIZE 32766
+#define OBM_OLD_CLOSE 32767
+#define WM_APP 0x8000
+#define HELP_TCARD 0x8000
+#define TBSTYLE_TRANSPARENT 0x8000
+#define RBS_DBLCLKTOGGLE 0x00008000
+#define LVS_NOSORTHEADER 0x8000
+#define TVS_NOHSCROLL 0x8000
+#define TCS_FOCUSNEVER 0x8000
+#define SC_SIZE 0xF000
+#define SC_SEPARATOR 0xF00F
+#define SC_MOVE 0xF010
+#define SC_MINIMIZE 0xF020
+#define SC_MAXIMIZE 0xF030
+#define SC_NEXTWINDOW 0xF040
+#define SC_PREVWINDOW 0xF050
+#define SC_CLOSE 0xF060
+#define SC_VSCROLL 0xF070
+#define SC_HSCROLL 0xF080
+#define SC_MOUSEMENU 0xF090
+#define SC_KEYMENU 0xF100
+#define SC_ARRANGE 0xF110
+#define SC_RESTORE 0xF120
+#define SC_TASKLIST 0xF130
+#define SC_SCREENSAVE 0xF140
+#define SC_HOTKEY 0xF150
+#define SC_DEFAULT 0xF160
+#define SC_MONITORPOWER 0xF170
+#define SC_CONTEXTHELP 0xF180
+#define LVS_TYPESTYLEMASK 0xfc00
+#define SPVERSION_MASK 0x0000FF00
+#define HTERROR -2
+#define PWR_FAIL -1
+#define UNICODE_NOCHAR 0xFFFF
+#define HTTRANSPARENT -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/windows/TapDriver6/resource.rc b/windows/TapDriver6/resource.rc
new file mode 100644
index 00000000..2b65e2bb
--- /dev/null
+++ b/windows/TapDriver6/resource.rc
@@ -0,0 +1,88 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 3,0,0,0
+ PRODUCTVERSION 3,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x9L
+#else
+ FILEFLAGS 0x8L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x3L
+ FILESUBTYPE 0x6L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "ZeroTier Networks LLC"
+ VALUE "FileDescription", "ZeroTier One Virtual Network Port"
+ VALUE "FileVersion", "3.0.0 3/0"
+ VALUE "InternalName", "zttap300.sys"
+ VALUE "LegalCopyright", "ZeroTier, Inc., OpenVPN Technologies, Inc."
+ VALUE "OriginalFilename", "zttap300.sys"
+ VALUE "ProductName", "ZeroTier One Virtual Network Port"
+ VALUE "ProductVersion", "3.0.0 3/0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/windows/TapDriver6/rxpath.c b/windows/TapDriver6/rxpath.c
new file mode 100644
index 00000000..318bc56a
--- /dev/null
+++ b/windows/TapDriver6/rxpath.c
@@ -0,0 +1,669 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+//======================================================================
+// TAP Receive Path Support
+//======================================================================
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, TapDeviceWrite)
+#endif // ALLOC_PRAGMA
+
+//===============================================================
+// Used in cases where internally generated packets such as
+// ARP or DHCP replies must be returned to the kernel, to be
+// seen as an incoming packet "arriving" on the interface.
+//===============================================================
+
+VOID
+IndicateReceivePacket(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PUCHAR packetData,
+ __in const unsigned int packetLength
+ )
+{
+ PUCHAR injectBuffer;
+
+ //
+ // Handle miniport Pause
+ // ---------------------
+ // NDIS 6 miniports implement a temporary "Pause" state normally followed
+ // by the Restart. While in the Pause state it is forbidden for the miniport
+ // to indicate receive NBLs.
+ //
+ // That is: The device interface may be "up", but the NDIS miniport send/receive
+ // interface may be temporarily "down".
+ //
+ // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas inject path
+ // the code below will simply ignore inject packets passed to the driver while
+ // the miniport is in the Paused state.
+ //
+ // The correct implementation is to go ahead and build the NBLs corresponding
+ // to the inject packet - but queue them. When Restart is entered the
+ // queued NBLs would be dequeued and indicated to the host.
+ //
+ if(tapAdapterSendAndReceiveReady(Adapter) != NDIS_STATUS_SUCCESS)
+ {
+ DEBUGP (("[%s] Lying send in IndicateReceivePacket while adapter paused\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+
+ return;
+ }
+
+ // Allocate flat buffer for packet data.
+ injectBuffer = (PUCHAR )NdisAllocateMemoryWithTagPriority(
+ Adapter->MiniportAdapterHandle,
+ packetLength,
+ TAP_RX_INJECT_BUFFER_TAG,
+ NormalPoolPriority
+ );
+
+ if( injectBuffer)
+ {
+ PMDL mdl;
+
+ // Copy packet data to flat buffer.
+ NdisMoveMemory (injectBuffer, packetData, packetLength);
+
+ // Allocate MDL for flat buffer.
+ mdl = NdisAllocateMdl(
+ Adapter->MiniportAdapterHandle,
+ injectBuffer,
+ packetLength
+ );
+
+ if( mdl )
+ {
+ PNET_BUFFER_LIST netBufferList;
+
+ mdl->Next = NULL; // No next MDL
+
+ // Allocate the NBL and NB. Link MDL chain to NB.
+ netBufferList = NdisAllocateNetBufferAndNetBufferList(
+ Adapter->ReceiveNblPool,
+ 0, // ContextSize
+ 0, // ContextBackFill
+ mdl, // MDL chain
+ 0,
+ packetLength
+ );
+
+ if(netBufferList != NULL)
+ {
+ ULONG receiveFlags = 0;
+ LONG nblCount;
+
+ NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+ if(KeGetCurrentIrql() == DISPATCH_LEVEL)
+ {
+ receiveFlags |= NDIS_RECEIVE_FLAGS_DISPATCH_LEVEL;
+ }
+
+ // Set flag indicating that this is an injected packet
+ TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+ TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED);
+
+ netBufferList->MiniportReserved[0] = NULL;
+ netBufferList->MiniportReserved[1] = NULL;
+
+ // Increment in-flight receive NBL count.
+ nblCount = NdisInterlockedIncrement(&Adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount > 0 );
+
+ netBufferList->SourceHandle = Adapter->MiniportAdapterHandle;
+
+ //
+ // Indicate the packet
+ // -------------------
+ // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+ // contains the complete packet including Ethernet header and payload.
+ //
+ NdisMIndicateReceiveNetBufferLists(
+ Adapter->MiniportAdapterHandle,
+ netBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 1, // NumberOfNetBufferLists
+ receiveFlags
+ );
+
+ return;
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateNetBufferAndNetBufferList failed in IndicateReceivePacket\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+ NOTE_ERROR ();
+
+ NdisFreeMdl(mdl);
+ NdisFreeMemory(injectBuffer,0,0);
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateMdl failed in IndicateReceivePacket\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+ NOTE_ERROR ();
+
+ NdisFreeMemory(injectBuffer,0,0);
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateMemoryWithTagPriority failed in IndicateReceivePacket\n",
+ MINIPORT_INSTANCE_ID (Adapter)));
+ NOTE_ERROR ();
+ }
+}
+
+VOID
+tapCompleteIrpAndFreeReceiveNetBufferList(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNET_BUFFER_LIST NetBufferList, // Only one NB here...
+ __in NTSTATUS IoCompletionStatus
+ )
+{
+ PIRP irp;
+ ULONG frameType, netBufferCount, byteCount;
+ LONG nblCount;
+
+ // Fetch NB frame type.
+ frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(NetBufferList));
+
+ // Fetch statistics for all NBs linked to the NB.
+ netBufferCount = tapGetNetBufferCountsFromNetBufferList(
+ NetBufferList,
+ &byteCount
+ );
+
+ // Update statistics by frame type
+ if(IoCompletionStatus == STATUS_SUCCESS)
+ {
+ switch(frameType)
+ {
+ case NDIS_PACKET_TYPE_DIRECTED:
+ Adapter->FramesRxDirected += netBufferCount;
+ Adapter->BytesRxDirected += byteCount;
+ break;
+
+ case NDIS_PACKET_TYPE_BROADCAST:
+ Adapter->FramesRxBroadcast += netBufferCount;
+ Adapter->BytesRxBroadcast += byteCount;
+ break;
+
+ case NDIS_PACKET_TYPE_MULTICAST:
+ Adapter->FramesRxMulticast += netBufferCount;
+ Adapter->BytesRxMulticast += byteCount;
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ //
+ // Handle P2P Packet
+ // -----------------
+ // Free MDL allocated for P2P Ethernet header.
+ //
+ if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_P2P))
+ {
+ PNET_BUFFER netBuffer;
+ PMDL mdl;
+
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ mdl = NET_BUFFER_FIRST_MDL(netBuffer);
+ mdl->Next = NULL;
+
+ NdisFreeMdl(mdl);
+ }
+
+ //
+ // Handle Injected Packet
+ // -----------------------
+ // Free MDL and data buffer allocated for injected packet.
+ //
+ if(TAP_RX_NBL_FLAG_TEST(NetBufferList,TAP_RX_NBL_FLAGS_IS_INJECTED))
+ {
+ PNET_BUFFER netBuffer;
+ PMDL mdl;
+ PUCHAR injectBuffer;
+
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
+ mdl = NET_BUFFER_FIRST_MDL(netBuffer);
+
+ injectBuffer = (PUCHAR )MmGetSystemAddressForMdlSafe(mdl,NormalPagePriority);
+
+ if(injectBuffer)
+ {
+ NdisFreeMemory(injectBuffer,0,0);
+ }
+
+ NdisFreeMdl(mdl);
+ }
+
+ //
+ // Complete the IRP
+ //
+ irp = (PIRP )NetBufferList->MiniportReserved[0];
+
+ if(irp)
+ {
+ irp->IoStatus.Status = IoCompletionStatus;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ }
+
+ // Decrement in-flight receive NBL count.
+ nblCount = NdisInterlockedDecrement(&Adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount >= 0 );
+ if (0 == nblCount)
+ {
+ NdisSetEvent(&Adapter->ReceiveNblInFlightCountZeroEvent);
+ }
+
+ // Free the NBL
+ NdisFreeNetBufferList(NetBufferList);
+}
+
+VOID
+AdapterReturnNetBufferLists(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PNET_BUFFER_LIST NetBufferLists,
+ __in ULONG ReturnFlags
+ )
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+ PNET_BUFFER_LIST currentNbl, nextNbl;
+
+ UNREFERENCED_PARAMETER(ReturnFlags);
+
+ //
+ // Process each NBL individually
+ //
+ currentNbl = NetBufferLists;
+ while (currentNbl)
+ {
+ PNET_BUFFER_LIST nextNbl;
+
+ nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+ NET_BUFFER_LIST_NEXT_NBL(currentNbl) = NULL;
+
+ // Complete write IRP and free NBL and associated resources.
+ tapCompleteIrpAndFreeReceiveNetBufferList(
+ adapter,
+ currentNbl,
+ STATUS_SUCCESS
+ );
+
+ // Move to next NBL
+ currentNbl = nextNbl;
+ }
+}
+
+// IRP_MJ_WRITE callback.
+NTSTATUS
+TapDeviceWrite(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success
+ PIO_STACK_LOCATION irpSp;// Pointer to current stack location
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+ ULONG dataLength;
+
+ PAGED_CODE();
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Fetch adapter context for this device.
+ // --------------------------------------
+ // Adapter pointer was stashed in FsContext when handle was opened.
+ //
+ adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+ ASSERT(adapter);
+
+ //
+ // Sanity checks on state variables
+ //
+ if (!tapAdapterReadAndWriteReady(adapter))
+ {
+ //DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n",
+ // MINIPORT_INSTANCE_ID (adapter)));
+ //NOTE_ERROR();
+
+ Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ // Save IRP-accessible copy of buffer length
+ Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
+
+ if (Irp->MdlAddress == NULL)
+ {
+ DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ //
+ // Try to get a virtual address for the MDL.
+ //
+ NdisQueryMdl(
+ Irp->MdlAddress,
+ &Irp->AssociatedIrp.SystemBuffer,
+ &dataLength,
+ NormalPagePriority
+ );
+
+ if (Irp->AssociatedIrp.SystemBuffer == NULL)
+ {
+ DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ ASSERT(dataLength == irpSp->Parameters.Write.Length);
+
+ Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
+
+ //
+ // Handle miniport Pause
+ // ---------------------
+ // NDIS 6 miniports implement a temporary "Pause" state normally followed
+ // by the Restart. While in the Pause state it is forbidden for the miniport
+ // to indicate receive NBLs.
+ //
+ // That is: The device interface may be "up", but the NDIS miniport send/receive
+ // interface may be temporarily "down".
+ //
+ // BUGBUG!!! In the initial implementation of the NDIS 6 TapOas receive path
+ // the code below will perform a "lying send" for write IRPs passed to the
+ // driver while the miniport is in the Paused state.
+ //
+ // The correct implementation is to go ahead and build the NBLs corresponding
+ // to the user-mode write - but queue them. When Restart is entered the
+ // queued NBLs would be dequeued and indicated to the host.
+ //
+ if(tapAdapterSendAndReceiveReady(adapter) == NDIS_STATUS_SUCCESS)
+ {
+ if (/*!adapter->m_tun &&*/ ((irpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
+ {
+ PNET_BUFFER_LIST netBufferList;
+
+ DUMP_PACKET ("IRP_MJ_WRITE ETH",
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify (
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length,
+ FALSE,
+ "RX",
+ &adapter->m_RxTrunc
+ );
+#endif
+ (Irp->MdlAddress)->Next = NULL; // No next MDL
+
+ // Allocate the NBL and NB. Link MDL chain to NB.
+ netBufferList = NdisAllocateNetBufferAndNetBufferList(
+ adapter->ReceiveNblPool,
+ 0, // ContextSize
+ 0, // ContextBackFill
+ Irp->MdlAddress, // MDL chain
+ 0,
+ dataLength
+ );
+
+ if(netBufferList != NULL)
+ {
+ LONG nblCount;
+
+ NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+ // Stash IRP pointer in NBL MiniportReserved[0] field.
+ netBufferList->MiniportReserved[0] = Irp;
+ netBufferList->MiniportReserved[1] = NULL;
+
+ // This IRP is pended.
+ IoMarkIrpPending(Irp);
+
+ // This IRP cannot be cancelled while in-flight.
+ IoSetCancelRoutine(Irp,NULL);
+
+ TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+
+ // Increment in-flight receive NBL count.
+ nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount > 0 );
+
+ //
+ // Indicate the packet
+ // -------------------
+ // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+ // contains the complete packet including Ethernet header and payload.
+ //
+ NdisMIndicateReceiveNetBufferLists(
+ adapter->MiniportAdapterHandle,
+ netBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 1, // NumberOfNetBufferLists
+ 0 // ReceiveFlags
+ );
+
+ ntStatus = STATUS_PENDING;
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+ NOTE_ERROR ();
+
+ // Fail the IRP
+ Irp->IoStatus.Information = 0;
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ /*
+ else if (adapter->m_tun && ((irpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
+ {
+ PETH_HEADER p_UserToTap = &adapter->m_UserToTap;
+ PMDL mdl; // Head of MDL chain.
+
+ // For IPv6, need to use Ethernet header with IPv6 proto
+ if ( IPH_GET_VER( ((IPHDR*) Irp->AssociatedIrp.SystemBuffer)->version_len) == 6 )
+ {
+ p_UserToTap = &adapter->m_UserToTap_IPv6;
+ }
+
+ DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
+ p_UserToTap,
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify (
+ (unsigned char *) Irp->AssociatedIrp.SystemBuffer,
+ irpSp->Parameters.Write.Length,
+ TRUE,
+ "RX",
+ &adapter->m_RxTrunc
+ );
+#endif
+
+ //
+ // Allocate MDL for Ethernet header
+ // --------------------------------
+ // Irp->AssociatedIrp.SystemBuffer with length irpSp->Parameters.Write.Length
+ // contains the only the Ethernet payload. Prepend the user-mode provided
+ // payload with the Ethernet header pointed to by p_UserToTap.
+ //
+ mdl = NdisAllocateMdl(
+ adapter->MiniportAdapterHandle,
+ p_UserToTap,
+ sizeof(ETH_HEADER)
+ );
+
+ if(mdl != NULL)
+ {
+ PNET_BUFFER_LIST netBufferList;
+
+ // Chain user's Ethernet payload behind Ethernet header.
+ mdl->Next = Irp->MdlAddress;
+ (Irp->MdlAddress)->Next = NULL; // No next MDL
+
+ // Allocate the NBL and NB. Link MDL chain to NB.
+ netBufferList = NdisAllocateNetBufferAndNetBufferList(
+ adapter->ReceiveNblPool,
+ 0, // ContextSize
+ 0, // ContextBackFill
+ mdl, // MDL chain
+ 0,
+ sizeof(ETH_HEADER) + dataLength
+ );
+
+ if(netBufferList != NULL)
+ {
+ LONG nblCount;
+
+ NET_BUFFER_LIST_NEXT_NBL(netBufferList) = NULL; // Only one NBL
+
+ // This IRP is pended.
+ IoMarkIrpPending(Irp);
+
+ // This IRP cannot be cancelled while in-flight.
+ IoSetCancelRoutine(Irp,NULL);
+
+ // Stash IRP pointer in NBL MiniportReserved[0] field.
+ netBufferList->MiniportReserved[0] = Irp;
+ netBufferList->MiniportReserved[1] = NULL;
+
+ // Set flag indicating that this is P2P packet
+ TAP_RX_NBL_FLAGS_CLEAR_ALL(netBufferList);
+ TAP_RX_NBL_FLAG_SET(netBufferList,TAP_RX_NBL_FLAGS_IS_P2P);
+
+ // Increment in-flight receive NBL count.
+ nblCount = NdisInterlockedIncrement(&adapter->ReceiveNblInFlightCount);
+ ASSERT(nblCount > 0 );
+
+ //
+ // Indicate the packet
+ //
+ NdisMIndicateReceiveNetBufferLists(
+ adapter->MiniportAdapterHandle,
+ netBufferList,
+ NDIS_DEFAULT_PORT_NUMBER,
+ 1, // NumberOfNetBufferLists
+ 0 // ReceiveFlags
+ );
+
+ ntStatus = STATUS_PENDING;
+ }
+ else
+ {
+ mdl->Next = NULL;
+ NdisFreeMdl(mdl);
+
+ DEBUGP (("[%s] NdisMIndicateReceiveNetBufferLists failed in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+ NOTE_ERROR ();
+
+ // Fail the IRP
+ Irp->IoStatus.Information = 0;
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] NdisAllocateMdl failed in IRP_MJ_WRITE\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+ NOTE_ERROR ();
+
+ // Fail the IRP
+ Irp->IoStatus.Information = 0;
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ */
+ else
+ {
+ DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n",
+ MINIPORT_INSTANCE_ID (adapter),
+ irpSp->Parameters.Write.Length));
+ NOTE_ERROR ();
+
+ Irp->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE;
+ Irp->IoStatus.Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ else
+ {
+ DEBUGP (("[%s] Lying send in IRP_MJ_WRITE while adapter paused\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ ntStatus = STATUS_SUCCESS;
+ }
+
+ if (ntStatus != STATUS_PENDING)
+ {
+ Irp->IoStatus.Status = ntStatus;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+
+ return ntStatus;
+}
+
diff --git a/windows/TapDriver6/tap-windows.h b/windows/TapDriver6/tap-windows.h
new file mode 100644
index 00000000..7e01846d
--- /dev/null
+++ b/windows/TapDriver6/tap-windows.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
+ */
+#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)
+
+// Used by ZT1 to get multicast memberships at the L2 level -- Windows provides no native way to do this that I know of
+#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS TAP_WIN_CONTROL_CODE (11, METHOD_BUFFERED)
+// Must be the same as NIC_MAX_MCAST_LIST in constants.h
+#define TAP_MAX_MCAST_LIST 128
+// Amount of memory that must be provided to ioctl TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS
+#define TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE (TAP_MAX_MCAST_LIST * 6)
+
+/*
+ * =================
+ * Registry keys
+ * =================
+ */
+
+#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+/*
+ * ======================
+ * Filesystem prefixes
+ * ======================
+ */
+
+#define USERMODEDEVICEDIR "\\\\.\\Global\\"
+#define SYSDEVICEDIR "\\Device\\"
+#define USERDEVICEDIR "\\DosDevices\\Global\\"
+#define TAP_WIN_SUFFIX ".tap"
+
+#endif // __TAP_WIN_H
diff --git a/windows/TapDriver6/tap.h b/windows/TapDriver6/tap.h
new file mode 100644
index 00000000..079b279f
--- /dev/null
+++ b/windows/TapDriver6/tap.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_H
+#define __TAP_H
+
+#ifndef NDIS_SUPPORT_NDIS6
+#define NDIS_SUPPORT_NDIS6 1
+#define NDIS_SUPPORT_NDIS61 1
+#define NDIS_WDM1 1
+#define NDIS61_MINIPORT 1
+#endif
+
+#include <ntifs.h>
+#include <ndis.h>
+#include <ntstrsafe.h>
+#include <netioapi.h>
+
+#include "config.h"
+#include "lock.h"
+#include "constants.h"
+#include "proto.h"
+#include "mem.h"
+#include "macinfo.h"
+#include "error.h"
+#include "endian.h"
+#include "types.h"
+#include "adapter.h"
+#include "device.h"
+#include "prototypes.h"
+#include "tap-windows.h"
+
+//========================================================
+// Check for truncated IPv4 packets, log errors if found.
+//========================================================
+#define PACKET_TRUNCATION_CHECK 0
+
+//========================================================
+// EXPERIMENTAL -- Configure TAP device object to be
+// accessible from non-administrative accounts, based
+// on an advanced properties setting.
+//
+// Duplicates the functionality of OpenVPN's
+// --allow-nonadmin directive.
+//========================================================
+#define ENABLE_NONADMIN 1
+
+//
+// The driver has exactly one instance of the TAP_GLOBAL structure. NDIS keeps
+// an opaque handle to this data, (it doesn't attempt to read or interpret this
+// data), and it passes the handle back to the miniport in MiniportSetOptions
+// and MiniportInitializeEx.
+//
+typedef struct _TAP_GLOBAL
+{
+ LIST_ENTRY AdapterList;
+
+ NDIS_RW_LOCK Lock;
+
+ NDIS_HANDLE NdisDriverHandle; // From NdisMRegisterMiniportDriver
+
+} TAP_GLOBAL, *PTAP_GLOBAL;
+
+
+// Global data
+extern TAP_GLOBAL GlobalData;
+
+#endif // __TAP_H
diff --git a/windows/TapDriver6/tapdrvr.c b/windows/TapDriver6/tapdrvr.c
new file mode 100644
index 00000000..6c537f1d
--- /dev/null
+++ b/windows/TapDriver6/tapdrvr.c
@@ -0,0 +1,232 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//======================================================
+// This driver is designed to work on Windows Vista or higher
+// versions of Windows.
+//
+// It is SMP-safe and handles power management.
+//
+// By default we operate as a "tap" virtual ethernet
+// 802.3 interface, but we can emulate a "tun"
+// interface (point-to-point IPv4) through the
+// TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT or
+// TAP_WIN_IOCTL_CONFIG_TUN ioctl.
+//======================================================
+
+//
+// Include files.
+//
+
+#include <string.h>
+
+#include "tap.h"
+
+
+// Global data
+TAP_GLOBAL GlobalData;
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( INIT, DriverEntry )
+#pragma alloc_text( PAGE, TapDriverUnload)
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+DriverEntry(
+ __in PDRIVER_OBJECT DriverObject,
+ __in PUNICODE_STRING RegistryPath
+ )
+/*++
+Routine Description:
+
+ In the context of its DriverEntry function, a miniport driver associates
+ itself with NDIS, specifies the NDIS version that it is using, and
+ registers its entry points.
+
+
+Arguments:
+ PVOID DriverObject - pointer to the driver object.
+ PVOID RegistryPath - pointer to the driver registry path.
+
+ Return Value:
+
+ NTSTATUS code
+
+--*/
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ DEBUGP (("[TAP] --> DriverEntry; version [%d.%d] %s %s\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__));
+
+ DEBUGP (("[TAP] Registry Path: '%wZ'\n", RegistryPath));
+
+ //
+ // Initialize any driver-global variables here.
+ //
+ NdisZeroMemory(&GlobalData, sizeof(GlobalData));
+
+ //
+ // The ApaterList in the GlobalData structure is used to track multiple
+ // adapters controlled by this miniport.
+ //
+ NdisInitializeListHead(&GlobalData.AdapterList);
+
+ //
+ // This lock protects the AdapterList.
+ //
+ NdisInitializeReadWriteLock(&GlobalData.Lock);
+
+ do
+ {
+ NDIS_MINIPORT_DRIVER_CHARACTERISTICS miniportCharacteristics;
+
+ NdisZeroMemory(&miniportCharacteristics, sizeof(miniportCharacteristics));
+
+ {C_ASSERT(sizeof(miniportCharacteristics) >= NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2);}
+ miniportCharacteristics.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
+ miniportCharacteristics.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
+ miniportCharacteristics.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
+
+ miniportCharacteristics.MajorNdisVersion = TAP_NDIS_MAJOR_VERSION;
+ miniportCharacteristics.MinorNdisVersion = TAP_NDIS_MINOR_VERSION;
+
+ miniportCharacteristics.MajorDriverVersion = TAP_DRIVER_MAJOR_VERSION;
+ miniportCharacteristics.MinorDriverVersion = TAP_DRIVER_MINOR_VERSION;
+
+ miniportCharacteristics.Flags = 0;
+
+ //miniportCharacteristics.SetOptionsHandler = MPSetOptions; // Optional
+ miniportCharacteristics.InitializeHandlerEx = AdapterCreate;
+ miniportCharacteristics.HaltHandlerEx = AdapterHalt;
+ miniportCharacteristics.UnloadHandler = TapDriverUnload;
+ miniportCharacteristics.PauseHandler = AdapterPause;
+ miniportCharacteristics.RestartHandler = AdapterRestart;
+ miniportCharacteristics.OidRequestHandler = AdapterOidRequest;
+ miniportCharacteristics.SendNetBufferListsHandler = AdapterSendNetBufferLists;
+ miniportCharacteristics.ReturnNetBufferListsHandler = AdapterReturnNetBufferLists;
+ miniportCharacteristics.CancelSendHandler = AdapterCancelSend;
+ miniportCharacteristics.CheckForHangHandlerEx = AdapterCheckForHangEx;
+ miniportCharacteristics.ResetHandlerEx = AdapterReset;
+ miniportCharacteristics.DevicePnPEventNotifyHandler = AdapterDevicePnpEventNotify;
+ miniportCharacteristics.ShutdownHandlerEx = AdapterShutdownEx;
+ miniportCharacteristics.CancelOidRequestHandler = AdapterCancelOidRequest;
+
+ //
+ // Associate the miniport driver with NDIS by calling the
+ // NdisMRegisterMiniportDriver. This function returns an NdisDriverHandle.
+ // The miniport driver must retain this handle but it should never attempt
+ // to access or interpret this handle.
+ //
+ // By calling NdisMRegisterMiniportDriver, the driver indicates that it
+ // is ready for NDIS to call the driver's MiniportSetOptions and
+ // MiniportInitializeEx handlers.
+ //
+ DEBUGP (("[TAP] Calling NdisMRegisterMiniportDriver...\n"));
+ //NDIS_DECLARE_MINIPORT_DRIVER_CONTEXT(TAP_GLOBAL);
+ status = NdisMRegisterMiniportDriver(
+ DriverObject,
+ RegistryPath,
+ &GlobalData,
+ &miniportCharacteristics,
+ &GlobalData.NdisDriverHandle
+ );
+
+ if (NDIS_STATUS_SUCCESS == status)
+ {
+ DEBUGP (("[TAP] Registered miniport successfully\n"));
+ }
+ else
+ {
+ DEBUGP(("[TAP] NdisMRegisterMiniportDriver failed: %8.8X\n", status));
+ TapDriverUnload(DriverObject);
+ status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ } while(FALSE);
+
+ DEBUGP (("[TAP] <-- DriverEntry; status = %8.8X\n",status));
+
+ return status;
+}
+
+VOID
+TapDriverUnload(
+ __in PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ The unload handler is called during driver unload to free up resources
+ acquired in DriverEntry. This handler is registered in DriverEntry through
+ NdisMRegisterMiniportDriver. Note that an unload handler differs from
+ a MiniportHalt function in that this unload handler releases resources that
+ are global to the driver, while the halt handler releases resource for a
+ particular adapter.
+
+ Runs at IRQL = PASSIVE_LEVEL.
+
+Arguments:
+
+ DriverObject Not used
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
+ UNICODE_STRING uniWin32NameString;
+
+ DEBUGP (("[TAP] --> TapDriverUnload; version [%d.%d] %s %s unloaded\n",
+ TAP_DRIVER_MAJOR_VERSION,
+ TAP_DRIVER_MINOR_VERSION,
+ __DATE__,
+ __TIME__
+ ));
+
+ PAGED_CODE();
+
+ //
+ // Clean up all globals that were allocated in DriverEntry
+ //
+
+ ASSERT(IsListEmpty(&GlobalData.AdapterList));
+
+ if(GlobalData.NdisDriverHandle != NULL )
+ {
+ NdisMDeregisterMiniportDriver(GlobalData.NdisDriverHandle);
+ }
+
+ DEBUGP (("[TAP] <-- TapDriverUnload\n"));
+}
+
diff --git a/windows/TapDriver6/txpath.c b/windows/TapDriver6/txpath.c
new file mode 100644
index 00000000..7993ca40
--- /dev/null
+++ b/windows/TapDriver6/txpath.c
@@ -0,0 +1,1175 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+//
+// Include files.
+//
+
+#include "tap.h"
+
+//======================================================================
+// TAP Send Path Support
+//======================================================================
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, TapDeviceRead)
+#endif // ALLOC_PRAGMA
+
+// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum
+// see RFC 4443, 2.3, and RFC 2460, 8.1
+USHORT
+icmpv6_checksum(
+ __in const UCHAR *buf,
+ __in const int len_icmpv6,
+ __in const UCHAR *saddr6,
+ __in const UCHAR *daddr6
+ )
+{
+ USHORT word16;
+ ULONG sum = 0;
+ int i;
+
+ // make 16 bit words out of every two adjacent 8 bit words and
+ // calculate the sum of all 16 bit words
+ for (i = 0; i < len_icmpv6; i += 2)
+ {
+ word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i+1] & 0xFF) : 0);
+ sum += word16;
+ }
+
+ // add the IPv6 pseudo header which contains the IP source and destination addresses
+ for (i = 0; i < 16; i += 2)
+ {
+ word16 =((saddr6[i] << 8) & 0xFF00) + (saddr6[i+1] & 0xFF);
+ sum += word16;
+ }
+
+ for (i = 0; i < 16; i += 2)
+ {
+ word16 =((daddr6[i] << 8) & 0xFF00) + (daddr6[i+1] & 0xFF);
+ sum += word16;
+ }
+
+ // the next-header number and the length of the ICMPv6 packet
+ sum += (USHORT) IPPROTO_ICMPV6 + (USHORT) len_icmpv6;
+
+ // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ // Take the one's complement of sum
+ return ((USHORT) ~sum);
+}
+
+/*
+
+// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that
+// the tap driver needs to answer?"
+// see RFC 4861 4.3 for the different cases
+static IPV6ADDR IPV6_NS_TARGET_MCAST =
+ { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08 };
+static IPV6ADDR IPV6_NS_TARGET_UNICAST =
+ { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };
+
+BOOLEAN
+HandleIPv6NeighborDiscovery(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in UCHAR * m_Data
+ )
+{
+ const ETH_HEADER * e = (ETH_HEADER *) m_Data;
+ const IPV6HDR *ipv6 = (IPV6HDR *) (m_Data + sizeof (ETH_HEADER));
+ const ICMPV6_NS * icmpv6_ns = (ICMPV6_NS *) (m_Data + sizeof (ETH_HEADER) + sizeof (IPV6HDR));
+ ICMPV6_NA_PKT *na;
+ USHORT icmpv6_len, icmpv6_csum;
+
+ // we don't really care about the destination MAC address here
+ // - it's either a multicast MAC, or the userland destination MAC
+ // but since the TAP driver is point-to-point, all packets are "for us"
+
+ // IPv6 target address must be ff02::1::ff00:8 (multicast for
+ // initial NS) or fe80::1 (unicast for recurrent NUD)
+ if ( memcmp( ipv6->daddr, IPV6_NS_TARGET_MCAST,
+ sizeof(IPV6ADDR) ) != 0 &&
+ memcmp( ipv6->daddr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) ) != 0 )
+ {
+ return FALSE; // wrong target address
+ }
+
+ // IPv6 Next-Header must be ICMPv6
+ if ( ipv6->nexthdr != IPPROTO_ICMPV6 )
+ {
+ return FALSE; // wrong next-header
+ }
+
+ // ICMPv6 type+code must be 135/0 for NS
+ if ( icmpv6_ns->type != ICMPV6_TYPE_NS ||
+ icmpv6_ns->code != ICMPV6_CODE_0 )
+ {
+ return FALSE; // wrong ICMPv6 type
+ }
+
+ // ICMPv6 target address must be fe80::8 (magic)
+ if ( memcmp( icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) ) != 0 )
+ {
+ return FALSE; // not for us
+ }
+
+ // packet identified, build magic response packet
+
+ na = (ICMPV6_NA_PKT *) MemAlloc (sizeof (ICMPV6_NA_PKT), TRUE);
+ if ( !na ) return FALSE;
+
+ //------------------------------------------------
+ // Initialize Neighbour Advertisement reply packet
+ //------------------------------------------------
+
+ // ethernet header
+ na->eth.proto = htons(NDIS_ETH_TYPE_IPV6);
+ ETH_COPY_NETWORK_ADDRESS(na->eth.dest, Adapter->PermanentAddress);
+ ETH_COPY_NETWORK_ADDRESS(na->eth.src, Adapter->m_TapToUser.dest);
+
+ // IPv6 header
+ na->ipv6.version_prio = ipv6->version_prio;
+ NdisMoveMemory( na->ipv6.flow_lbl, ipv6->flow_lbl,
+ sizeof(na->ipv6.flow_lbl) );
+ icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR);
+ na->ipv6.payload_len = htons(icmpv6_len);
+ na->ipv6.nexthdr = IPPROTO_ICMPV6;
+ na->ipv6.hop_limit = 255;
+ NdisMoveMemory( na->ipv6.saddr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) );
+ NdisMoveMemory( na->ipv6.daddr, ipv6->saddr,
+ sizeof(IPV6ADDR) );
+
+ // ICMPv6
+ na->icmpv6.type = ICMPV6_TYPE_NA;
+ na->icmpv6.code = ICMPV6_CODE_0;
+ na->icmpv6.checksum = 0;
+ na->icmpv6.rso_bits = 0x60; // Solicited + Override
+ NdisZeroMemory( na->icmpv6.reserved, sizeof(na->icmpv6.reserved) );
+ NdisMoveMemory( na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) );
+
+ // ICMPv6 option "Target Link Layer Address"
+ na->icmpv6.opt_type = ICMPV6_OPTION_TLLA;
+ na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA;
+ ETH_COPY_NETWORK_ADDRESS( na->icmpv6.target_macaddr, Adapter->m_TapToUser.dest );
+
+ // calculate and set checksum
+ icmpv6_csum = icmpv6_checksum (
+ (UCHAR*) &(na->icmpv6),
+ icmpv6_len,
+ na->ipv6.saddr,
+ na->ipv6.daddr
+ );
+
+ na->icmpv6.checksum = htons( icmpv6_csum );
+
+ DUMP_PACKET ("HandleIPv6NeighborDiscovery",
+ (unsigned char *) na,
+ sizeof (ICMPV6_NA_PKT));
+
+ IndicateReceivePacket (Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT));
+
+ MemFree (na, sizeof (ICMPV6_NA_PKT));
+
+ return TRUE; // all fine
+}
+
+//===================================================
+// Generate an ARP reply message for specific kinds
+// ARP queries.
+//===================================================
+BOOLEAN
+ProcessARP(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in const PARP_PACKET src,
+ __in const IPADDR adapter_ip,
+ __in const IPADDR ip_network,
+ __in const IPADDR ip_netmask,
+ __in const MACADDR mac
+ )
+{
+ //-----------------------------------------------
+ // Is this the kind of packet we are looking for?
+ //-----------------------------------------------
+ if (src->m_Proto == htons (NDIS_ETH_TYPE_ARP)
+ && MAC_EQUAL (src->m_MAC_Source, Adapter->PermanentAddress)
+ && MAC_EQUAL (src->m_ARP_MAC_Source, Adapter->PermanentAddress)
+ && ETH_IS_BROADCAST(src->m_MAC_Destination)
+ && src->m_ARP_Operation == htons (ARP_REQUEST)
+ && src->m_MAC_AddressType == htons (MAC_ADDR_TYPE)
+ && src->m_MAC_AddressSize == sizeof (MACADDR)
+ && src->m_PROTO_AddressType == htons (NDIS_ETH_TYPE_IPV4)
+ && src->m_PROTO_AddressSize == sizeof (IPADDR)
+ && src->m_ARP_IP_Source == adapter_ip
+ && (src->m_ARP_IP_Destination & ip_netmask) == ip_network
+ && src->m_ARP_IP_Destination != adapter_ip)
+ {
+ ARP_PACKET *arp = (ARP_PACKET *) MemAlloc (sizeof (ARP_PACKET), TRUE);
+ if (arp)
+ {
+ //----------------------------------------------
+ // Initialize ARP reply fields
+ //----------------------------------------------
+ arp->m_Proto = htons (NDIS_ETH_TYPE_ARP);
+ arp->m_MAC_AddressType = htons (MAC_ADDR_TYPE);
+ arp->m_PROTO_AddressType = htons (NDIS_ETH_TYPE_IPV4);
+ arp->m_MAC_AddressSize = sizeof (MACADDR);
+ arp->m_PROTO_AddressSize = sizeof (IPADDR);
+ arp->m_ARP_Operation = htons (ARP_REPLY);
+
+ //----------------------------------------------
+ // ARP addresses
+ //----------------------------------------------
+ ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Source, mac);
+ ETH_COPY_NETWORK_ADDRESS (arp->m_MAC_Destination, Adapter->PermanentAddress);
+ ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Source, mac);
+ ETH_COPY_NETWORK_ADDRESS (arp->m_ARP_MAC_Destination, Adapter->PermanentAddress);
+ arp->m_ARP_IP_Source = src->m_ARP_IP_Destination;
+ arp->m_ARP_IP_Destination = adapter_ip;
+
+ DUMP_PACKET ("ProcessARP",
+ (unsigned char *) arp,
+ sizeof (ARP_PACKET));
+
+ IndicateReceivePacket (Adapter, (UCHAR *) arp, sizeof (ARP_PACKET));
+
+ MemFree (arp, sizeof (ARP_PACKET));
+ }
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+*/
+
+//=============================================================
+// CompleteIRP is normally called with an adapter -> userspace
+// network packet and an IRP (Pending I/O request) from userspace.
+//
+// The IRP will normally represent a queued overlapped read
+// operation from userspace that is in a wait state.
+//
+// Use the ethernet packet to satisfy the IRP.
+//=============================================================
+
+VOID
+tapCompletePendingReadIrp(
+ __in PIRP Irp,
+ __in PTAP_PACKET TapPacket
+ )
+{
+ int offset;
+ int len;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+
+ ASSERT(Irp);
+ ASSERT(TapPacket);
+
+ //-------------------------------------------
+ // While TapPacket always contains a
+ // full ethernet packet, including the
+ // ethernet header, in point-to-point mode,
+ // we only want to return the IPv4
+ // component.
+ //-------------------------------------------
+
+ if (TapPacket->m_SizeFlags & TP_TUN)
+ {
+ offset = ETHERNET_HEADER_SIZE;
+ len = (int) (TapPacket->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE;
+ }
+ else
+ {
+ offset = 0;
+ len = (TapPacket->m_SizeFlags & TP_SIZE_MASK);
+ }
+
+ if (len < 0 || (int) Irp->IoStatus.Information < len)
+ {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = status = STATUS_BUFFER_OVERFLOW;
+ NOTE_ERROR ();
+ }
+ else
+ {
+ Irp->IoStatus.Information = len;
+ Irp->IoStatus.Status = status = STATUS_SUCCESS;
+
+ // Copy packet data
+ NdisMoveMemory(
+ Irp->AssociatedIrp.SystemBuffer,
+ TapPacket->m_Data + offset,
+ len
+ );
+ }
+
+ // Free the TAP packet
+ NdisFreeMemory(TapPacket,0,0);
+
+ // Complete the IRP
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+}
+
+VOID
+tapProcessSendPacketQueue(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ KIRQL irql;
+
+ // Process the send packet queue
+ KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql);
+
+ while(Adapter->SendPacketQueue.Count > 0 )
+ {
+ PIRP irp;
+ PTAP_PACKET tapPacket;
+
+ // Fetch a read IRP
+ irp = IoCsqRemoveNextIrp(
+ &Adapter->PendingReadIrpQueue.CsqQueue,
+ NULL
+ );
+
+ if( irp == NULL )
+ {
+ // No IRP to satisfy
+ break;
+ }
+
+ // Fetch a queued TAP send packet
+ tapPacket = tapPacketRemoveHeadLocked(
+ &Adapter->SendPacketQueue
+ );
+
+ ASSERT(tapPacket);
+
+ // BUGBUG!!! Investigate whether release/reacquire can cause
+ // out-of-order IRP completion. Also, whether user-mode can
+ // tolerate out-of-order packets.
+
+ // Release packet queue lock while completing the IRP
+ //KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql);
+
+ // Complete the read IRP from queued TAP send packet.
+ tapCompletePendingReadIrp(irp,tapPacket);
+
+ // Reqcquire packet queue lock after completing the IRP
+ //KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql);
+ }
+
+ KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql);
+}
+
+// Flush the pending send TAP packet queue.
+VOID
+tapFlushSendPacketQueue(
+ __in PTAP_ADAPTER_CONTEXT Adapter
+ )
+{
+ KIRQL irql;
+
+ // Process the send packet queue
+ KeAcquireSpinLock(&Adapter->SendPacketQueue.QueueLock,&irql);
+
+ DEBUGP (("[TAP] tapFlushSendPacketQueue: Flushing %d TAP packets\n",
+ Adapter->SendPacketQueue.Count));
+
+ while(Adapter->SendPacketQueue.Count > 0 )
+ {
+ PTAP_PACKET tapPacket;
+
+ // Fetch a queued TAP send packet
+ tapPacket = tapPacketRemoveHeadLocked(
+ &Adapter->SendPacketQueue
+ );
+
+ ASSERT(tapPacket);
+
+ // Free the TAP packet
+ NdisFreeMemory(tapPacket,0,0);
+ }
+
+ KeReleaseSpinLock(&Adapter->SendPacketQueue.QueueLock,irql);
+}
+
+VOID
+tapAdapterTransmit(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNET_BUFFER NetBuffer,
+ __in BOOLEAN DispatchLevel
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to transmit an individual net buffer using a
+ style similar to the previous NDIS 5 AdapterTransmit function.
+
+ In this implementation adapter state and NB length checks have already
+ been done before this function has been called.
+
+ The net buffer will be completed by the calling routine after this
+ routine exits. So, under this design it is necessary to make a deep
+ copy of frame data in the net buffer.
+
+ This routine creates a flat buffer copy of NB frame data. This is an
+ unnecessary performance bottleneck. However, the bottleneck is probably
+ not significant or measurable except for adapters running at 1Gbps or
+ greater speeds. Since this adapter is currently running at 100Mbps this
+ defect can be ignored.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ Adapter Pointer to our adapter context
+ NetBuffer Pointer to the net buffer to transmit
+ DispatchLevel TRUE if called at IRQL == DISPATCH_LEVEL
+
+Return Value:
+
+ None.
+
+ In the Microsoft NDIS 6 architecture there is no per-packet status.
+
+--*/
+{
+ NDIS_STATUS status;
+ ULONG packetLength;
+ PTAP_PACKET tapPacket;
+ PVOID packetData;
+
+ packetLength = NET_BUFFER_DATA_LENGTH(NetBuffer);
+
+ // Allocate TAP packet memory
+ tapPacket = (PTAP_PACKET )NdisAllocateMemoryWithTagPriority(
+ Adapter->MiniportAdapterHandle,
+ TAP_PACKET_SIZE (packetLength),
+ TAP_PACKET_TAG,
+ NormalPoolPriority
+ );
+
+ if(tapPacket == NULL)
+ {
+ DEBUGP (("[TAP] tapAdapterTransmit: TAP packet allocation failed\n"));
+ return;
+ }
+
+ tapPacket->m_SizeFlags = (packetLength & TP_SIZE_MASK);
+
+ //
+ // Reassemble packet contents
+ // --------------------------
+ // NdisGetDataBuffer does most of the work. There are two cases:
+ //
+ // 1.) If the NB data was not contiguous it will copy the entire
+ // NB's data to m_data and return pointer to m_data.
+ // 2.) If the NB data was contiguous it returns a pointer to the
+ // first byte of the contiguous data instead of a pointer to m_Data.
+ // In this case the data will not have been copied to m_Data. Copy
+ // to m_Data will need to be done in an extra step.
+ //
+ // Case 1.) is the most likely in normal operation.
+ //
+ packetData = NdisGetDataBuffer(NetBuffer,packetLength,tapPacket->m_Data,1,0);
+
+ if(packetData == NULL)
+ {
+ DEBUGP (("[TAP] tapAdapterTransmit: Could not get packet data\n"));
+
+ NdisFreeMemory(tapPacket,0,0);
+
+ return;
+ }
+
+ if(packetData != tapPacket->m_Data)
+ {
+ // Packet data was contiguous and not yet copied to m_Data.
+ NdisMoveMemory(tapPacket->m_Data,packetData,packetLength);
+ }
+
+ DUMP_PACKET ("AdapterTransmit", tapPacket->m_Data, packetLength);
+
+ //=====================================================
+ // If IPv4 packet, check whether or not packet
+ // was truncated.
+ //=====================================================
+#if PACKET_TRUNCATION_CHECK
+ IPv4PacketSizeVerify(
+ tapPacket->m_Data,
+ packetLength,
+ FALSE,
+ "TX",
+ &Adapter->m_TxTrunc
+ );
+#endif
+
+ //=====================================================
+ // Are we running in DHCP server masquerade mode?
+ //
+ // If so, catch both DHCP requests and ARP queries
+ // to resolve the address of our virtual DHCP server.
+ //=====================================================
+#if 0
+ 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;
+ }
+ }
+ }
+#endif
+
+ //===============================================
+ // 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 0
+ if (Adapter->m_tun)
+ {
+ ETH_HEADER *e;
+
+ e = (ETH_HEADER *) tapPacket->m_Data;
+
+ switch (ntohs (e->proto))
+ {
+ case NDIS_ETH_TYPE_ARP:
+
+ // Make sure that packet is the right size for ARP.
+ if (packetLength != sizeof (ARP_PACKET))
+ {
+ goto no_queue;
+ }
+
+ ProcessARP (
+ Adapter,
+ (PARP_PACKET) tapPacket->m_Data,
+ Adapter->m_localIP,
+ Adapter->m_remoteNetwork,
+ Adapter->m_remoteNetmask,
+ Adapter->m_TapToUser.dest
+ );
+
+ default:
+ goto no_queue;
+
+ case NDIS_ETH_TYPE_IPV4:
+
+ // Make sure that packet is large enough to be IPv4.
+ if (packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE))
+ {
+ goto no_queue;
+ }
+
+ // Only accept directed packets, not broadcasts.
+ if (memcmp (e, &Adapter->m_TapToUser, ETHERNET_HEADER_SIZE))
+ {
+ goto no_queue;
+ }
+
+ // Packet looks like IPv4, queue it. :-)
+ tapPacket->m_SizeFlags |= TP_TUN;
+ break;
+
+ case NDIS_ETH_TYPE_IPV6:
+ // Make sure that packet is large enough to be IPv6.
+ if (packetLength < (ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE))
+ {
+ goto no_queue;
+ }
+
+ // Broadcasts and multicasts are handled specially
+ // (to be implemented)
+
+ // Neighbor discovery packets to fe80::8 are special
+ // OpenVPN sets this next-hop to signal "handled by tapdrv"
+ if ( HandleIPv6NeighborDiscovery(Adapter,tapPacket->m_Data) )
+ {
+ goto no_queue;
+ }
+
+ // Packet looks like IPv6, queue it. :-)
+ tapPacket->m_SizeFlags |= TP_TUN;
+ }
+ }
+#endif
+
+ //===============================================
+ // Push packet onto queue to wait for read from
+ // userspace.
+ //===============================================
+ if(tapAdapterReadAndWriteReady(Adapter))
+ {
+ tapPacketQueueInsertTail(&Adapter->SendPacketQueue,tapPacket);
+ }
+ else
+ {
+ //
+ // Tragedy. All this work and the packet is of no use...
+ //
+ NdisFreeMemory(tapPacket,0,0);
+ }
+
+ // Return after queuing or freeing TAP packet.
+ return;
+
+ // Free TAP packet without queuing.
+no_queue:
+ if(tapPacket != NULL )
+ {
+ NdisFreeMemory(tapPacket,0,0);
+ }
+
+exit_success:
+ return;
+}
+
+VOID
+tapSendNetBufferListsComplete(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNET_BUFFER_LIST NetBufferLists,
+ __in NDIS_STATUS SendCompletionStatus,
+ __in BOOLEAN DispatchLevel
+ )
+{
+ PNET_BUFFER_LIST currentNbl;
+ PNET_BUFFER_LIST nextNbl = NULL;
+ ULONG sendCompleteFlags = 0;
+
+ for (
+ currentNbl = NetBufferLists;
+ currentNbl != NULL;
+ currentNbl = nextNbl
+ )
+ {
+ ULONG frameType;
+ ULONG netBufferCount;
+ ULONG byteCount;
+
+ nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+
+ // Set NBL completion status.
+ NET_BUFFER_LIST_STATUS(currentNbl) = SendCompletionStatus;
+
+ // Fetch first NBs frame type. All linked NBs will have same type.
+ frameType = tapGetNetBufferFrameType(NET_BUFFER_LIST_FIRST_NB(currentNbl));
+
+ // Fetch statistics for all NBs linked to the NB.
+ netBufferCount = tapGetNetBufferCountsFromNetBufferList(
+ currentNbl,
+ &byteCount
+ );
+
+ // Update statistics by frame type
+ if(SendCompletionStatus == NDIS_STATUS_SUCCESS)
+ {
+ switch(frameType)
+ {
+ case NDIS_PACKET_TYPE_DIRECTED:
+ Adapter->FramesTxDirected += netBufferCount;
+ Adapter->BytesTxDirected += byteCount;
+ break;
+
+ case NDIS_PACKET_TYPE_BROADCAST:
+ Adapter->FramesTxBroadcast += netBufferCount;
+ Adapter->BytesTxBroadcast += byteCount;
+ break;
+
+ case NDIS_PACKET_TYPE_MULTICAST:
+ Adapter->FramesTxMulticast += netBufferCount;
+ Adapter->BytesTxMulticast += byteCount;
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+ else
+ {
+ // Transmit error.
+ Adapter->TransmitFailuresOther += netBufferCount;
+ }
+
+ currentNbl = nextNbl;
+ }
+
+ if(DispatchLevel)
+ {
+ sendCompleteFlags |= NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL;
+ }
+
+ // Complete the NBLs
+ NdisMSendNetBufferListsComplete(
+ Adapter->MiniportAdapterHandle,
+ NetBufferLists,
+ sendCompleteFlags
+ );
+}
+
+BOOLEAN
+tapNetBufferListNetBufferLengthsValid(
+ __in PTAP_ADAPTER_CONTEXT Adapter,
+ __in PNET_BUFFER_LIST NetBufferLists
+ )
+/*++
+
+Routine Description:
+
+ Scan all NBLs and their linked NBs for valid lengths.
+
+ Fairly absurd to find and packets with bogus lengths, but wise
+ to check anyway. If ANY packet has a bogus length, then abort the
+ entire send.
+
+ The only time that one might see this check fail might be during
+ HCK driver testing. The HKC test might send oversize packets to
+ determine if the miniport can gracefully deal with them.
+
+ This check is fairly fast. Unlike NDIS 5 packets, fetching NDIS 6
+ packets lengths do not require any computation.
+
+Arguments:
+
+ Adapter Pointer to our adapter context
+ NetBufferLists Head of a list of NBLs to examine
+
+Return Value:
+
+ Returns TRUE if all NBs have reasonable lengths.
+ Otherwise, returns FALSE.
+
+--*/
+{
+ PNET_BUFFER_LIST currentNbl;
+
+ currentNbl = NetBufferLists;
+
+ while (currentNbl)
+ {
+ PNET_BUFFER_LIST nextNbl;
+ PNET_BUFFER currentNb;
+
+ // Locate next NBL
+ nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+
+ // Locate first NB (aka "packet")
+ currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl);
+
+ //
+ // Process all NBs linked to this NBL
+ //
+ while(currentNb)
+ {
+ PNET_BUFFER nextNb;
+ ULONG packetLength;
+
+ // Locate next NB
+ nextNb = NET_BUFFER_NEXT_NB(currentNb);
+
+ packetLength = NET_BUFFER_DATA_LENGTH(currentNb);
+
+ // Minimum packet size is size of Ethernet plus IPv4 headers.
+ ASSERT(packetLength >= (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE));
+
+ if(packetLength < (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE))
+ {
+ return FALSE;
+ }
+
+ // Maximum size should be Ethernet header size plus MTU plus modest pad for
+ // VLAN tag.
+ ASSERT( packetLength <= (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize));
+
+ if(packetLength > (ETHERNET_HEADER_SIZE + VLAN_TAG_SIZE + Adapter->MtuSize))
+ {
+ return FALSE;
+ }
+
+ // Move to next NB
+ currentNb = nextNb;
+ }
+
+ // Move to next NBL
+ currentNbl = nextNbl;
+ }
+
+ return TRUE;
+}
+
+VOID
+AdapterSendNetBufferLists(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PNET_BUFFER_LIST NetBufferLists,
+ __in NDIS_PORT_NUMBER PortNumber,
+ __in ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+
+ Send Packet Array handler. Called by NDIS whenever a protocol
+ bound to our miniport sends one or more packets.
+
+ The input packet descriptor pointers have been ordered according
+ to the order in which the packets should be sent over the network
+ by the protocol driver that set up the packet array. The NDIS
+ library preserves the protocol-determined ordering when it submits
+ each packet array to MiniportSendPackets
+
+ As a deserialized driver, we are responsible for holding incoming send
+ packets in our internal queue until they can be transmitted over the
+ network and for preserving the protocol-determined ordering of packet
+ descriptors incoming to its MiniportSendPackets function.
+ A deserialized miniport driver must complete each incoming send packet
+ with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable.
+
+ Runs at IRQL <= DISPATCH_LEVEL
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ NetBufferLists Head of a list of NBLs to send
+ PortNumber A miniport adapter port. Default is 0.
+ SendFlags Additional flags for the send operation
+
+Return Value:
+
+ None. Write status directly into each NBL with the NET_BUFFER_LIST_STATUS
+ macro.
+
+--*/
+{
+ NDIS_STATUS status;
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+ BOOLEAN DispatchLevel = (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL);
+ PNET_BUFFER_LIST currentNbl;
+ BOOLEAN validNbLengths;
+
+ UNREFERENCED_PARAMETER(NetBufferLists);
+ UNREFERENCED_PARAMETER(PortNumber);
+ UNREFERENCED_PARAMETER(SendFlags);
+
+ ASSERT(PortNumber == 0); // Only the default port is supported
+
+ //
+ // Can't process sends if TAP device is not open.
+ // ----------------------------------------------
+ // Just perform a "lying send" and return packets as if they
+ // were successfully sent.
+ //
+ if(adapter->TapFileObject == NULL)
+ {
+ //
+ // Complete all NBLs and return if adapter not ready.
+ //
+ tapSendNetBufferListsComplete(
+ adapter,
+ NetBufferLists,
+ NDIS_STATUS_SUCCESS,
+ DispatchLevel
+ );
+
+ return;
+ }
+
+ //
+ // Check Adapter send/receive ready state.
+ //
+ status = tapAdapterSendAndReceiveReady(adapter);
+
+ if(status != NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Complete all NBLs and return if adapter not ready.
+ //
+ tapSendNetBufferListsComplete(
+ adapter,
+ NetBufferLists,
+ status,
+ DispatchLevel
+ );
+
+ return;
+ }
+
+ //
+ // Scan all NBLs and linked packets for valid lengths.
+ // ---------------------------------------------------
+ // If _ANY_ NB length is invalid, then fail the entire send operation.
+ //
+ // BUGBUG!!! Perhaps this should be less agressive. Fail only individual
+ // NBLs...
+ //
+ // If length check is valid, then TAP_PACKETS can be safely allocated
+ // and processed for all NBs being sent.
+ //
+ validNbLengths = tapNetBufferListNetBufferLengthsValid(
+ adapter,
+ NetBufferLists
+ );
+
+ if(!validNbLengths)
+ {
+ //
+ // Complete all NBLs and return if and NB length is invalid.
+ //
+ tapSendNetBufferListsComplete(
+ adapter,
+ NetBufferLists,
+ NDIS_STATUS_INVALID_LENGTH,
+ DispatchLevel
+ );
+
+ return;
+ }
+
+ //
+ // Process each NBL individually
+ //
+ currentNbl = NetBufferLists;
+
+ while (currentNbl)
+ {
+ PNET_BUFFER_LIST nextNbl;
+ PNET_BUFFER currentNb;
+
+ // Locate next NBL
+ nextNbl = NET_BUFFER_LIST_NEXT_NBL(currentNbl);
+
+ // Locate first NB (aka "packet")
+ currentNb = NET_BUFFER_LIST_FIRST_NB(currentNbl);
+
+ // Transmit all NBs linked to this NBL
+ while(currentNb)
+ {
+ PNET_BUFFER nextNb;
+
+ // Locate next NB
+ nextNb = NET_BUFFER_NEXT_NB(currentNb);
+
+ // Transmit the NB
+ tapAdapterTransmit(adapter,currentNb,DispatchLevel);
+
+ // Move to next NB
+ currentNb = nextNb;
+ }
+
+ // Move to next NBL
+ currentNbl = nextNbl;
+ }
+
+ // Complete all NBLs
+ tapSendNetBufferListsComplete(
+ adapter,
+ NetBufferLists,
+ NDIS_STATUS_SUCCESS,
+ DispatchLevel
+ );
+
+ // Attempt to complete pending read IRPs from pending TAP
+ // send packet queue.
+ tapProcessSendPacketQueue(adapter);
+}
+
+VOID
+AdapterCancelSend(
+ __in NDIS_HANDLE MiniportAdapterContext,
+ __in PVOID CancelId
+ )
+{
+ PTAP_ADAPTER_CONTEXT adapter = (PTAP_ADAPTER_CONTEXT )MiniportAdapterContext;
+
+ //
+ // This miniport completes its sends quickly, so it isn't strictly
+ // neccessary to implement MiniportCancelSend.
+ //
+ // If we did implement it, we'd have to walk the Adapter->SendWaitList
+ // and look for any NB that points to a NBL where the CancelId matches
+ // NDIS_GET_NET_BUFFER_LIST_CANCEL_ID(Nbl). For any NB that so matches,
+ // we'd remove the NB from the SendWaitList and set the NBL's status to
+ // NDIS_STATUS_SEND_ABORTED, then complete the NBL.
+ //
+}
+
+// IRP_MJ_READ callback.
+NTSTATUS
+TapDeviceRead(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success
+ PIO_STACK_LOCATION irpSp;// Pointer to current stack location
+ PTAP_ADAPTER_CONTEXT adapter = NULL;
+
+ PAGED_CODE();
+
+ irpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Fetch adapter context for this device.
+ // --------------------------------------
+ // Adapter pointer was stashed in FsContext when handle was opened.
+ //
+ adapter = (PTAP_ADAPTER_CONTEXT )(irpSp->FileObject)->FsContext;
+
+ ASSERT(adapter);
+
+ //
+ // Sanity checks on state variables
+ //
+ if (!tapAdapterReadAndWriteReady(adapter))
+ {
+ //DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n",
+ // MINIPORT_INSTANCE_ID (adapter)));
+ //NOTE_ERROR();
+
+ Irp->IoStatus.Status = ntStatus = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ // Save IRP-accessible copy of buffer length
+ Irp->IoStatus.Information = irpSp->Parameters.Read.Length;
+
+ if (Irp->MdlAddress == NULL)
+ {
+ DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_INVALID_PARAMETER;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ if ((Irp->AssociatedIrp.SystemBuffer
+ = MmGetSystemAddressForMdlSafe(
+ Irp->MdlAddress,
+ NormalPagePriority
+ ) ) == NULL
+ )
+ {
+ DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n",
+ MINIPORT_INSTANCE_ID (adapter)));
+
+ NOTE_ERROR();
+ Irp->IoStatus.Status = ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+
+ return ntStatus;
+ }
+
+ // BUGBUG!!! Use RemoveLock???
+
+ //
+ // Queue the IRP and return STATUS_PENDING.
+ // ----------------------------------------
+ // Note: IoCsqInsertIrp marks the IRP pending.
+ //
+
+ // BUGBUG!!! NDIS 5 implementation has IRP_QUEUE_SIZE of 16 and
+ // does not queue IRP if this capacity is exceeded.
+ //
+ // Is this needed???
+ //
+ IoCsqInsertIrp(&adapter->PendingReadIrpQueue.CsqQueue, Irp, NULL);
+
+ // Attempt to complete pending read IRPs from pending TAP
+ // send packet queue.
+ tapProcessSendPacketQueue(adapter);
+
+ ntStatus = STATUS_PENDING;
+
+ return ntStatus;
+}
+
diff --git a/windows/TapDriver6/types.h b/windows/TapDriver6/types.h
new file mode 100644
index 00000000..acea175c
--- /dev/null
+++ b/windows/TapDriver6/types.h
@@ -0,0 +1,90 @@
+/*
+ * TAP-Windows -- A kernel driver to provide virtual tap
+ * device functionality on Windows.
+ *
+ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
+ *
+ * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc.,
+ * and is released under the GPL version 2 (see below).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef TAP_TYPES_DEFINED
+#define TAP_TYPES_DEFINED
+
+//typedef
+//struct _Queue
+//{
+// ULONG base;
+// ULONG size;
+// ULONG capacity;
+// ULONG max_size;
+// PVOID data[];
+//} Queue;
+
+//typedef struct _TAP_PACKET;
+
+//typedef struct _TapExtension
+//{
+// // TAP device object and packet queues
+// Queue *m_PacketQueue, *m_IrpQueue;
+// PDEVICE_OBJECT m_TapDevice;
+// NDIS_HANDLE m_TapDeviceHandle;
+// ULONG TapFileIsOpen;
+//
+// // Used to lock packet queues
+// NDIS_SPIN_LOCK m_QueueLock;
+// BOOLEAN m_AllocatedSpinlocks;
+//
+// // Used to bracket open/close
+// // state changes.
+// MUTEX m_OpenCloseMutex;
+//
+// // True if device has been permanently halted
+// BOOLEAN m_Halt;
+//
+// // TAP device name
+// unsigned char *m_TapName;
+// UNICODE_STRING m_UnicodeLinkName;
+// BOOLEAN m_CreatedUnicodeLinkName;
+//
+// // Used for device status ioctl only
+// const char *m_LastErrorFilename;
+// int m_LastErrorLineNumber;
+// LONG TapFileOpenCount;
+//
+// // Flags
+// BOOLEAN TapDeviceCreated;
+// BOOLEAN m_CalledTapDeviceFreeResources;
+//
+// // DPC queue for deferred packet injection
+// BOOLEAN m_InjectDpcInitialized;
+// KDPC m_InjectDpc;
+// NDIS_SPIN_LOCK m_InjectLock;
+// Queue *m_InjectQueue;
+//}
+//TapExtension, *TapExtensionPointer;
+
+typedef struct _InjectPacket
+ {
+# define INJECT_PACKET_SIZE(data_size) (sizeof (InjectPacket) + (data_size))
+# define INJECT_PACKET_FREE(ib) NdisFreeMemory ((ib), INJECT_PACKET_SIZE ((ib)->m_Size), 0)
+ ULONG m_Size;
+ UCHAR m_Data []; // m_Data must be the last struct member
+ }
+InjectPacket, *InjectPacketPointer;
+
+#endif
diff --git a/windows/TapDriver6/zttap300.inf b/windows/TapDriver6/zttap300.inf
new file mode 100644
index 00000000..f901b130
--- /dev/null
+++ b/windows/TapDriver6/zttap300.inf
@@ -0,0 +1,143 @@
+;
+; ZeroTier One Virtual Network Port NDIS6 Driver
+;
+; Based on the OpenVPN tap-windows6 driver version 9.21.1 git
+; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3.
+; See: https://github.com/OpenVPN/tap-windows6
+;
+; Modified by ZeroTier, Inc. - https://www.zerotier.com/
+;
+; (1) Comment out 'tun' functionality and related features such as DHCP
+; emulation, since we don't use any of that. Just want straight 'tap'.
+; (2) Added custom IOCTL to enumerate L2 multicast memberships.
+; (3) Increase maximum number of multicast memberships to 128.
+; (4) Set default and max device MTU to 2800.
+; (5) Rename/rebrand driver as ZeroTier network port driver.
+;
+; Original copyright below. Modifications released under GPLv2 as well.
+;
+; ****************************************************************************
+; * 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. *
+; ****************************************************************************
+;
+
+[Version]
+Signature = "$Windows NT$"
+CatalogFile = zttap300.cat
+ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
+Provider = %Provider%
+Class = Net
+DriverVer=04/25/2015,3.00.00.0
+
+[Strings]
+DeviceDescription = "ZeroTier One Virtual Port"
+Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat.
+
+; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
+[Manufacturer]
+%Provider%=zttap300,NTamd64
+
+[zttap300]
+%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
+%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
+
+[zttap300.NTamd64]
+%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
+%DeviceDescription% = zttap300.ndi, zttap300 ; Legacy
+
+;----------------- Characteristics ------------
+; NCF_PHYSICAL = 0x04
+; NCF_VIRTUAL = 0x01
+; NCF_SOFTWARE_ENUMERATED = 0x02
+; NCF_HIDDEN = 0x08
+; NCF_NO_SERVICE = 0x10
+; NCF_HAS_UI = 0x80
+;----------------- Characteristics ------------
+[zttap300.ndi]
+CopyFiles = zttap300.driver, zttap300.files
+AddReg = zttap300.reg
+AddReg = zttap300.params.reg
+Characteristics = 0x81
+*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD
+*MediaType = 0x0 ; NdisMedium802_3
+*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3
+
+[zttap300.ndi.Services]
+AddService = zttap300, 2, zttap300.service
+
+[zttap300.reg]
+HKR, Ndi, Service, 0, "zttap300"
+HKR, Ndi\Interfaces, UpperRange, 0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows.
+HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
+HKR, , Manufacturer, 0, "%Provider%"
+HKR, , ProductName, 0, "%DeviceDescription%"
+
+[zttap300.params.reg]
+HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
+HKR, Ndi\params\MTU, Type, 0, "int"
+HKR, Ndi\params\MTU, Default, 0, "2800"
+HKR, Ndi\params\MTU, Optional, 0, "0"
+HKR, Ndi\params\MTU, Min, 0, "100"
+HKR, Ndi\params\MTU, Max, 0, "2800"
+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, "0"
+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 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 ---------------
+
+[zttap300.service]
+DisplayName = %DeviceDescription%
+ServiceType = 1
+StartType = 3
+ErrorControl = 1
+LoadOrderGroup = NDIS
+ServiceBinary = %12%\zttap300.sys
+
+;----------------- Copy Flags ------------
+; COPYFLG_NOSKIP = 0x02
+; COPYFLG_NOVERSIONCHECK = 0x04
+;----------------- Copy Flags ------------
+
+[SourceDisksNames]
+1 = %DeviceDescription%, zttap300.sys
+
+[SourceDisksFiles]
+zttap300.sys = 1
+
+[DestinationDirs]
+zttap300.files = 11
+zttap300.driver = 12
+
+[zttap300.files]
+;
+
+[zttap300.driver]
+zttap300.sys,,,6 ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
+
diff --git a/windows/ZeroTierOne.sln b/windows/ZeroTierOne.sln
index 09a0874b..3aebacb5 100644
--- a/windows/ZeroTierOne.sln
+++ b/windows/ZeroTierOne.sln
@@ -5,6 +5,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver", "TapDriver\TapD
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZeroTierOne", "ZeroTierOne\ZeroTierOne.vcxproj", "{B00A4957-5977-4AC1-9EF4-571DC27EADA2}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver6", "TapDriver6\TapDriver6.vcxproj", "{43BA7584-D4DB-4F7C-90FC-E2B18A68A213}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CD_ROM|Any CPU = CD_ROM|Any CPU
@@ -295,6 +297,149 @@ Global
{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.ActiveCfg = Release|Win32
{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.Build.0 = Release|Win32
{B00A4957-5977-4AC1-9EF4-571DC27EADA2}.Win8 Release|x86.Deploy.0 = Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Any CPU.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|Win32.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.ActiveCfg = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.Build.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x64.Deploy.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.CD_ROM|x86.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Any CPU.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.Build.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Mixed Platforms.Deploy.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.Build.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|Win32.Deploy.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.ActiveCfg = Win7 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.Build.0 = Win7 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x64.Deploy.0 = Win7 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.Build.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Debug|x86.Deploy.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Any CPU.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|Win32.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.ActiveCfg = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.Build.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x64.Deploy.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.DVD-5|x86.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Any CPU.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|Win32.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.ActiveCfg = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.Build.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x64.Deploy.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Release|x86.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Any CPU.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|Win32.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.ActiveCfg = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.Build.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x64.Deploy.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.SingleImage|x86.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Any CPU.ActiveCfg = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.ActiveCfg = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.Build.0 = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Mixed Platforms.Deploy.0 = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.ActiveCfg = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.Build.0 = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|Win32.Deploy.0 = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.ActiveCfg = Vista Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.Build.0 = Vista Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x64.Deploy.0 = Vista Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.ActiveCfg = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.Build.0 = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Debug|x86.Deploy.0 = Vista Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Any CPU.ActiveCfg = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.ActiveCfg = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.Build.0 = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Mixed Platforms.Deploy.0 = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.ActiveCfg = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.Build.0 = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|Win32.Deploy.0 = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.ActiveCfg = Vista Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.Build.0 = Vista Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x64.Deploy.0 = Vista Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.ActiveCfg = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.Build.0 = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Vista Release|x86.Deploy.0 = Vista Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Any CPU.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.Build.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Mixed Platforms.Deploy.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.Build.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|Win32.Deploy.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.ActiveCfg = Win7 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.Build.0 = Win7 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x64.Deploy.0 = Win7 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.ActiveCfg = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.Build.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Debug|x86.Deploy.0 = Win7 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Any CPU.ActiveCfg = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.ActiveCfg = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.Build.0 = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Mixed Platforms.Deploy.0 = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.ActiveCfg = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.Build.0 = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|Win32.Deploy.0 = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.ActiveCfg = Win7 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.Build.0 = Win7 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x64.Deploy.0 = Win7 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.ActiveCfg = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.Build.0 = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win7 Release|x86.Deploy.0 = Win7 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Any CPU.ActiveCfg = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.ActiveCfg = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.Build.0 = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Mixed Platforms.Deploy.0 = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.ActiveCfg = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.Build.0 = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|Win32.Deploy.0 = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.ActiveCfg = Win8 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.Build.0 = Win8 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x64.Deploy.0 = Win8 Debug|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.ActiveCfg = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.Build.0 = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Debug|x86.Deploy.0 = Win8 Debug|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Any CPU.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Mixed Platforms.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|Win32.Deploy.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.ActiveCfg = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.Build.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x64.Deploy.0 = Win8 Release|x64
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.ActiveCfg = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Build.0 = Win8 Release|Win32
+ {43BA7584-D4DB-4F7C-90FC-E2B18A68A213}.Win8 Release|x86.Deploy.0 = Win8 Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE