Browse Source

Merge branch 'adamierymenko-dev' into android-jni

Grant Limberg 10 years ago
parent
commit
ec45aeb42a
52 changed files with 11356 additions and 2340 deletions
  1. 0 949
      attic/Node.cpp
  2. 0 245
      attic/Node.hpp
  3. 0 162
      attic/WindowsEthernetTapFactory.cpp
  4. 0 90
      attic/WindowsEthernetTapFactory.hpp
  5. 0 887
      attic/main.cpp
  6. 0 0
      ext/bin/tap-windows-ndis5/x64/WdfCoinstaller01011.dll
  7. 0 0
      ext/bin/tap-windows-ndis5/x64/zttap200.cat
  8. 0 0
      ext/bin/tap-windows-ndis5/x64/zttap200.inf
  9. 0 0
      ext/bin/tap-windows-ndis5/x64/zttap200.sys
  10. 0 0
      ext/bin/tap-windows-ndis5/x86/WdfCoinstaller01011.dll
  11. 0 0
      ext/bin/tap-windows-ndis5/x86/zttap200.cat
  12. 0 0
      ext/bin/tap-windows-ndis5/x86/zttap200.inf
  13. 0 0
      ext/bin/tap-windows-ndis5/x86/zttap200.sys
  14. BIN
      ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll
  15. BIN
      ext/bin/tap-windows-ndis6/x64/zttap300.cat
  16. 143 0
      ext/bin/tap-windows-ndis6/x64/zttap300.inf
  17. BIN
      ext/bin/tap-windows-ndis6/x64/zttap300.sys
  18. BIN
      ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll
  19. BIN
      ext/bin/tap-windows-ndis6/x86/zttap300.cat
  20. 139 0
      ext/bin/tap-windows-ndis6/x86/zttap300.inf
  21. BIN
      ext/bin/tap-windows-ndis6/x86/zttap300.sys
  22. 18 7
      osdep/WindowsEthernetTap.cpp
  23. 371 0
      windows/TapDriver6/TapDriver6.vcxproj
  24. 110 0
      windows/TapDriver6/TapDriver6.vcxproj.filters
  25. 1716 0
      windows/TapDriver6/adapter.c
  26. 352 0
      windows/TapDriver6/adapter.h
  27. 9 0
      windows/TapDriver6/config.h
  28. 196 0
      windows/TapDriver6/constants.h
  29. 1209 0
      windows/TapDriver6/device.c
  30. 50 0
      windows/TapDriver6/device.h
  31. 35 0
      windows/TapDriver6/endian.h
  32. 398 0
      windows/TapDriver6/error.c
  33. 114 0
      windows/TapDriver6/error.h
  34. 63 0
      windows/TapDriver6/hexdump.h
  35. 75 0
      windows/TapDriver6/lock.h
  36. 164 0
      windows/TapDriver6/macinfo.c
  37. 53 0
      windows/TapDriver6/macinfo.h
  38. 401 0
      windows/TapDriver6/mem.c
  39. 113 0
      windows/TapDriver6/mem.h
  40. 1028 0
      windows/TapDriver6/oidrequest.c
  41. 224 0
      windows/TapDriver6/proto.h
  42. 91 0
      windows/TapDriver6/prototypes.h
  43. 1573 0
      windows/TapDriver6/resource.h
  44. 88 0
      windows/TapDriver6/resource.rc
  45. 669 0
      windows/TapDriver6/rxpath.c
  46. 81 0
      windows/TapDriver6/tap-windows.h
  47. 88 0
      windows/TapDriver6/tap.h
  48. 232 0
      windows/TapDriver6/tapdrvr.c
  49. 1175 0
      windows/TapDriver6/txpath.c
  50. 90 0
      windows/TapDriver6/types.h
  51. 143 0
      windows/TapDriver6/zttap300.inf
  52. 145 0
      windows/ZeroTierOne.sln

+ 0 - 949
attic/Node.cpp

@@ -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

+ 0 - 245
attic/Node.hpp

@@ -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

+ 0 - 162
attic/WindowsEthernetTapFactory.cpp

@@ -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

+ 0 - 90
attic/WindowsEthernetTapFactory.hpp

@@ -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

+ 0 - 887
attic/main.cpp

@@ -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;
-}

+ 0 - 0
ext/bin/tap-windows/x64/WdfCoinstaller01011.dll → ext/bin/tap-windows-ndis5/x64/WdfCoinstaller01011.dll


+ 0 - 0
ext/bin/tap-windows/x64/zttap200.cat → ext/bin/tap-windows-ndis5/x64/zttap200.cat


+ 0 - 0
ext/bin/tap-windows/x64/zttap200.inf → ext/bin/tap-windows-ndis5/x64/zttap200.inf


+ 0 - 0
ext/bin/tap-windows/x64/zttap200.sys → ext/bin/tap-windows-ndis5/x64/zttap200.sys


+ 0 - 0
ext/bin/tap-windows/x86/WdfCoinstaller01011.dll → ext/bin/tap-windows-ndis5/x86/WdfCoinstaller01011.dll


+ 0 - 0
ext/bin/tap-windows/x86/zttap200.cat → ext/bin/tap-windows-ndis5/x86/zttap200.cat


+ 0 - 0
ext/bin/tap-windows/x86/zttap200.inf → ext/bin/tap-windows-ndis5/x86/zttap200.inf


+ 0 - 0
ext/bin/tap-windows/x86/zttap200.sys → ext/bin/tap-windows-ndis5/x86/zttap200.sys


BIN
ext/bin/tap-windows-ndis6/x64/WdfCoinstaller01011.dll


BIN
ext/bin/tap-windows-ndis6/x64/zttap300.cat


+ 143 - 0
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
+

BIN
ext/bin/tap-windows-ndis6/x64/zttap300.sys


BIN
ext/bin/tap-windows-ndis6/x86/WdfCoinstaller01011.dll


BIN
ext/bin/tap-windows-ndis6/x86/zttap300.cat


+ 139 - 0
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
+

BIN
ext/bin/tap-windows-ndis6/x86/zttap300.sys


+ 18 - 7
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);

+ 371 - 0
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>

+ 110 - 0
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>

+ 1716 - 0
windows/TapDriver6/adapter.c

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

+ 352 - 0
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_

+ 9 - 0
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"

+ 196 - 0
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

+ 1209 - 0
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"));
+}
+

+ 50 - 0
windows/TapDriver6/device.h

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

+ 35 - 0
windows/TapDriver6/endian.h

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

+ 398 - 0
windows/TapDriver6/error.c

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

+ 114 - 0
windows/TapDriver6/error.h

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

+ 63 - 0
windows/TapDriver6/hexdump.h

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

+ 75 - 0
windows/TapDriver6/lock.h

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

+ 164 - 0
windows/TapDriver6/macinfo.c

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

+ 53 - 0
windows/TapDriver6/macinfo.h

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

+ 401 - 0
windows/TapDriver6/mem.c

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

+ 113 - 0
windows/TapDriver6/mem.h

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

+ 1028 - 0
windows/TapDriver6/oidrequest.c

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

+ 224 - 0
windows/TapDriver6/proto.h

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

+ 91 - 0
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

+ 1573 - 0
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

+ 88 - 0
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
+

+ 669 - 0
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;
+}
+

+ 81 - 0
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

+ 88 - 0
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

+ 232 - 0
windows/TapDriver6/tapdrvr.c

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

+ 1175 - 0
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;
+}
+

+ 90 - 0
windows/TapDriver6/types.h

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

+ 143 - 0
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
+

+ 145 - 0
windows/ZeroTierOne.sln

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